[29] | 1 | /* |
---|
| 2 | * This program is free software; you can redistribute it and/or modify |
---|
| 3 | * it under the terms of the GNU General Public License as published by |
---|
| 4 | * the Free Software Foundation; either version 2 of the License, or |
---|
| 5 | * (at your option) any later version. |
---|
| 6 | * |
---|
| 7 | * This program is distributed in the hope that it will be useful, |
---|
| 8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
| 9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
---|
| 10 | * GNU General Public License for more details. |
---|
| 11 | * |
---|
| 12 | * You should have received a copy of the GNU General Public License |
---|
| 13 | * along with this program; if not, write to the Free Software |
---|
| 14 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
---|
| 15 | */ |
---|
| 16 | |
---|
| 17 | /* |
---|
| 18 | * SimpleCLIPanel.java |
---|
| 19 | * Copyright (C) 2009 University of Waikato, Hamilton, New Zealand |
---|
| 20 | */ |
---|
| 21 | |
---|
| 22 | package weka.gui; |
---|
| 23 | |
---|
| 24 | import weka.core.Capabilities; |
---|
| 25 | import weka.core.CapabilitiesHandler; |
---|
| 26 | import weka.core.ClassDiscovery; |
---|
| 27 | import weka.core.OptionHandler; |
---|
| 28 | import weka.core.Trie; |
---|
| 29 | import weka.core.Utils; |
---|
| 30 | import weka.gui.scripting.ScriptingPanel; |
---|
| 31 | |
---|
| 32 | import java.awt.BorderLayout; |
---|
| 33 | import java.awt.Container; |
---|
| 34 | import java.awt.Cursor; |
---|
| 35 | import java.awt.Font; |
---|
| 36 | import java.awt.Frame; |
---|
| 37 | import java.awt.Window; |
---|
| 38 | import java.awt.event.ActionEvent; |
---|
| 39 | import java.awt.event.ActionListener; |
---|
| 40 | import java.awt.event.KeyAdapter; |
---|
| 41 | import java.awt.event.KeyEvent; |
---|
| 42 | import java.awt.event.WindowEvent; |
---|
| 43 | import java.io.BufferedOutputStream; |
---|
| 44 | import java.io.File; |
---|
| 45 | import java.io.FileOutputStream; |
---|
| 46 | import java.io.PrintStream; |
---|
| 47 | import java.lang.reflect.Method; |
---|
| 48 | import java.lang.reflect.Modifier; |
---|
| 49 | import java.util.Collections; |
---|
| 50 | import java.util.HashSet; |
---|
| 51 | import java.util.Properties; |
---|
| 52 | import java.util.Vector; |
---|
| 53 | |
---|
| 54 | import javax.swing.ImageIcon; |
---|
| 55 | import javax.swing.JFrame; |
---|
| 56 | import javax.swing.JInternalFrame; |
---|
| 57 | import javax.swing.JMenuBar; |
---|
| 58 | import javax.swing.JOptionPane; |
---|
| 59 | import javax.swing.JScrollPane; |
---|
| 60 | import javax.swing.JTextField; |
---|
| 61 | import javax.swing.JTextPane; |
---|
| 62 | |
---|
| 63 | /** |
---|
| 64 | * Creates a very simple command line for invoking the main method of |
---|
| 65 | * classes. System.out and System.err are redirected to an output area. |
---|
| 66 | * Features a simple command history -- use up and down arrows to move |
---|
| 67 | * through previous commmands. This gui uses only AWT (i.e. no Swing). |
---|
| 68 | * |
---|
| 69 | * @author Len Trigg (trigg@cs.waikato.ac.nz) |
---|
| 70 | * @author FracPete (fracpete at waikato dot ac dot nz) |
---|
| 71 | */ |
---|
| 72 | public class SimpleCLIPanel |
---|
| 73 | extends ScriptingPanel |
---|
| 74 | implements ActionListener { |
---|
| 75 | |
---|
| 76 | /** for serialization. */ |
---|
| 77 | private static final long serialVersionUID = 1089039734615114942L; |
---|
| 78 | |
---|
| 79 | /** The filename of the properties file. */ |
---|
| 80 | protected static String FILENAME = "SimpleCLI.props"; |
---|
| 81 | |
---|
| 82 | /** The default location of the properties file. */ |
---|
| 83 | protected static String PROPERTY_FILE = "weka/gui/" + FILENAME; |
---|
| 84 | |
---|
| 85 | /** Contains the SimpleCLI properties. */ |
---|
| 86 | protected static Properties PROPERTIES; |
---|
| 87 | |
---|
| 88 | static { |
---|
| 89 | // Allow a properties file in the current directory to override |
---|
| 90 | try { |
---|
| 91 | PROPERTIES = Utils.readProperties(PROPERTY_FILE); |
---|
| 92 | java.util.Enumeration keys = |
---|
| 93 | (java.util.Enumeration) PROPERTIES.propertyNames(); |
---|
| 94 | if (!keys.hasMoreElements()) { |
---|
| 95 | throw new Exception( |
---|
| 96 | "Failed to read a property file for the SimpleCLI"); |
---|
| 97 | } |
---|
| 98 | } |
---|
| 99 | catch (Exception ex) { |
---|
| 100 | JOptionPane.showMessageDialog( |
---|
| 101 | null, |
---|
| 102 | "Could not read a configuration file for the SimpleCLI.\n" |
---|
| 103 | + "An example file is included with the Weka distribution.\n" |
---|
| 104 | + "This file should be named \"" + PROPERTY_FILE + "\" and\n" |
---|
| 105 | + "should be placed either in your user home (which is set\n" |
---|
| 106 | + "to \"" + System.getProperties().getProperty("user.home") + "\")\n" |
---|
| 107 | + "or the directory that java was started from\n", |
---|
| 108 | "SimpleCLI", |
---|
| 109 | JOptionPane.ERROR_MESSAGE); |
---|
| 110 | } |
---|
| 111 | } |
---|
| 112 | |
---|
| 113 | /** The output area canvas added to the frame. */ |
---|
| 114 | protected JTextPane m_OutputArea; |
---|
| 115 | |
---|
| 116 | /** The command input area. */ |
---|
| 117 | protected JTextField m_Input; |
---|
| 118 | |
---|
| 119 | /** The history of commands entered interactively. */ |
---|
| 120 | protected Vector m_CommandHistory; |
---|
| 121 | |
---|
| 122 | /** The current position in the command history. */ |
---|
| 123 | protected int m_HistoryPos; |
---|
| 124 | |
---|
| 125 | /** The thread currently running a class main method. */ |
---|
| 126 | protected Thread m_RunThread; |
---|
| 127 | |
---|
| 128 | /** The commandline completion. */ |
---|
| 129 | protected CommandlineCompletion m_Completion; |
---|
| 130 | |
---|
| 131 | /** |
---|
| 132 | * A class that handles running the main method of the class |
---|
| 133 | * in a separate thread. |
---|
| 134 | * |
---|
| 135 | * @author Len Trigg (trigg@cs.waikato.ac.nz) |
---|
| 136 | * @version $Revision: 5855 $ |
---|
| 137 | */ |
---|
| 138 | class ClassRunner extends Thread { |
---|
| 139 | |
---|
| 140 | /** Stores the main method to call. */ |
---|
| 141 | protected Method m_MainMethod; |
---|
| 142 | |
---|
| 143 | /** Stores the command line arguments to pass to the main method. */ |
---|
| 144 | String[] m_CommandArgs; |
---|
| 145 | |
---|
| 146 | /** |
---|
| 147 | * Sets up the class runner thread. |
---|
| 148 | * |
---|
| 149 | * @param theClass the Class to call the main method of |
---|
| 150 | * @param commandArgs an array of Strings to use as command line args |
---|
| 151 | * @throws Exception if an error occurs |
---|
| 152 | */ |
---|
| 153 | public ClassRunner(Class theClass, String [] commandArgs) |
---|
| 154 | throws Exception { |
---|
| 155 | |
---|
| 156 | setDaemon(true); |
---|
| 157 | Class[] argTemplate = {String[].class}; |
---|
| 158 | m_CommandArgs = commandArgs; |
---|
| 159 | m_MainMethod = theClass.getMethod("main", argTemplate); |
---|
| 160 | if (((m_MainMethod.getModifiers() & Modifier.STATIC) == 0) |
---|
| 161 | || (m_MainMethod.getModifiers() & Modifier.PUBLIC) == 0) { |
---|
| 162 | throw new NoSuchMethodException("main(String[]) method of " + |
---|
| 163 | theClass.getName() + |
---|
| 164 | " is not public and static."); |
---|
| 165 | } |
---|
| 166 | } |
---|
| 167 | |
---|
| 168 | /** |
---|
| 169 | * Starts running the main method. |
---|
| 170 | */ |
---|
| 171 | public void run() { |
---|
| 172 | PrintStream outOld = null; |
---|
| 173 | PrintStream outNew = null; |
---|
| 174 | String outFilename = null; |
---|
| 175 | |
---|
| 176 | // is the output redirected? |
---|
| 177 | if (m_CommandArgs.length > 2) { |
---|
| 178 | String action = m_CommandArgs[m_CommandArgs.length - 2]; |
---|
| 179 | if (action.equals(">")) { |
---|
| 180 | outOld = System.out; |
---|
| 181 | try { |
---|
| 182 | outFilename = m_CommandArgs[m_CommandArgs.length - 1]; |
---|
| 183 | // since file may not yet exist, command-line completion doesn't |
---|
| 184 | // work, hence replace "~" manually with home directory |
---|
| 185 | if (outFilename.startsWith("~")) |
---|
| 186 | outFilename = outFilename.replaceFirst("~", System.getProperty("user.home")); |
---|
| 187 | outNew = new PrintStream(new File(outFilename)); |
---|
| 188 | System.setOut(outNew); |
---|
| 189 | m_CommandArgs[m_CommandArgs.length - 2] = ""; |
---|
| 190 | m_CommandArgs[m_CommandArgs.length - 1] = ""; |
---|
| 191 | // some main methods check the length of the "args" array |
---|
| 192 | // -> removed the two empty elements at the end |
---|
| 193 | String[] newArgs = new String[m_CommandArgs.length - 2]; |
---|
| 194 | System.arraycopy(m_CommandArgs, 0, newArgs, 0, m_CommandArgs.length - 2); |
---|
| 195 | m_CommandArgs = newArgs; |
---|
| 196 | } |
---|
| 197 | catch (Exception e) { |
---|
| 198 | System.setOut(outOld); |
---|
| 199 | outOld = null; |
---|
| 200 | } |
---|
| 201 | } |
---|
| 202 | } |
---|
| 203 | |
---|
| 204 | try { |
---|
| 205 | Object[] args = {m_CommandArgs}; |
---|
| 206 | m_MainMethod.invoke(null, args); |
---|
| 207 | if (isInterrupted()) { |
---|
| 208 | System.err.println("[...Interrupted]"); |
---|
| 209 | } |
---|
| 210 | } catch (Exception ex) { |
---|
| 211 | if (ex.getMessage() == null) { |
---|
| 212 | System.err.println("[...Killed]"); |
---|
| 213 | } else { |
---|
| 214 | System.err.println("[Run exception] " + ex.getMessage()); |
---|
| 215 | } |
---|
| 216 | } finally { |
---|
| 217 | m_RunThread = null; |
---|
| 218 | } |
---|
| 219 | |
---|
| 220 | // restore old System.out stream |
---|
| 221 | if (outOld != null) { |
---|
| 222 | outNew.flush(); |
---|
| 223 | outNew.close(); |
---|
| 224 | System.setOut(outOld); |
---|
| 225 | System.out.println("Finished redirecting output to '" + outFilename + "'."); |
---|
| 226 | } |
---|
| 227 | } |
---|
| 228 | } |
---|
| 229 | |
---|
| 230 | /** |
---|
| 231 | * A class for commandline completion of classnames. |
---|
| 232 | * |
---|
| 233 | * @author FracPete (fracpete at waikato dot ac dot nz) |
---|
| 234 | * @version $Revision: 5855 $ |
---|
| 235 | */ |
---|
| 236 | public static class CommandlineCompletion { |
---|
| 237 | |
---|
| 238 | /** all the available packages. */ |
---|
| 239 | protected static Vector<String> m_Packages; |
---|
| 240 | |
---|
| 241 | /** a trie for storing the packages. */ |
---|
| 242 | protected static Trie m_Trie; |
---|
| 243 | |
---|
| 244 | /** debug mode on/off. */ |
---|
| 245 | protected boolean m_Debug = false; |
---|
| 246 | |
---|
| 247 | /** |
---|
| 248 | * default constructor. |
---|
| 249 | */ |
---|
| 250 | public CommandlineCompletion() { |
---|
| 251 | super(); |
---|
| 252 | |
---|
| 253 | // build incremental list of packages |
---|
| 254 | if (m_Packages == null) { |
---|
| 255 | // get all packages |
---|
| 256 | Vector list = ClassDiscovery.findPackages(); |
---|
| 257 | |
---|
| 258 | // create incremental list |
---|
| 259 | HashSet<String> set = new HashSet<String>(); |
---|
| 260 | for (int i = 0; i < list.size(); i++) { |
---|
| 261 | String[] parts = ((String) list.get(i)).split("\\."); |
---|
| 262 | for (int n = 1; n < parts.length; n++) { |
---|
| 263 | String pkg = ""; |
---|
| 264 | for (int m = 0; m <= n; m++) { |
---|
| 265 | if (m > 0) |
---|
| 266 | pkg += "."; |
---|
| 267 | pkg += parts[m]; |
---|
| 268 | } |
---|
| 269 | set.add(pkg); |
---|
| 270 | } |
---|
| 271 | } |
---|
| 272 | |
---|
| 273 | // init packages |
---|
| 274 | m_Packages = new Vector<String>(); |
---|
| 275 | m_Packages.addAll(set); |
---|
| 276 | Collections.sort(m_Packages); |
---|
| 277 | |
---|
| 278 | m_Trie = new Trie(); |
---|
| 279 | m_Trie.addAll(m_Packages); |
---|
| 280 | } |
---|
| 281 | } |
---|
| 282 | |
---|
| 283 | /** |
---|
| 284 | * returns whether debug mode is on. |
---|
| 285 | * |
---|
| 286 | * @return true if debug is on |
---|
| 287 | */ |
---|
| 288 | public boolean getDebug() { |
---|
| 289 | return m_Debug; |
---|
| 290 | } |
---|
| 291 | |
---|
| 292 | /** |
---|
| 293 | * sets debug mode on/off. |
---|
| 294 | * |
---|
| 295 | * @param value if true then debug mode is on |
---|
| 296 | */ |
---|
| 297 | public void setDebug(boolean value) { |
---|
| 298 | m_Debug = value; |
---|
| 299 | } |
---|
| 300 | |
---|
| 301 | /** |
---|
| 302 | * tests whether the given partial string is the name of a class with |
---|
| 303 | * classpath - it basically tests, whether the string consists only |
---|
| 304 | * of alphanumeric literals, underscores and dots. |
---|
| 305 | * |
---|
| 306 | * @param partial the string to test |
---|
| 307 | * @return true if it looks like a classname |
---|
| 308 | */ |
---|
| 309 | public boolean isClassname(String partial) { |
---|
| 310 | return (partial.replaceAll("[a-zA-Z0-9\\-\\.]*", "").length() == 0); |
---|
| 311 | } |
---|
| 312 | |
---|
| 313 | /** |
---|
| 314 | * returns the packages part of the partial classname. |
---|
| 315 | * |
---|
| 316 | * @param partial the partial classname |
---|
| 317 | * @return the package part of the partial classname |
---|
| 318 | */ |
---|
| 319 | public String getPackage(String partial) { |
---|
| 320 | String result; |
---|
| 321 | int i; |
---|
| 322 | boolean wasDot; |
---|
| 323 | char c; |
---|
| 324 | |
---|
| 325 | result = ""; |
---|
| 326 | wasDot = false; |
---|
| 327 | for (i = 0; i < partial.length(); i++) { |
---|
| 328 | c = partial.charAt(i); |
---|
| 329 | |
---|
| 330 | // start of classname? |
---|
| 331 | if (wasDot && ((c >= 'A') && (c <= 'Z'))) { |
---|
| 332 | break; |
---|
| 333 | } |
---|
| 334 | // package/class separator |
---|
| 335 | else if (c == '.') { |
---|
| 336 | wasDot = true; |
---|
| 337 | result += "" + c; |
---|
| 338 | } |
---|
| 339 | // regular char |
---|
| 340 | else { |
---|
| 341 | wasDot = false; |
---|
| 342 | result += "" + c; |
---|
| 343 | } |
---|
| 344 | } |
---|
| 345 | |
---|
| 346 | // remove trailing "." |
---|
| 347 | if (result.endsWith(".")) |
---|
| 348 | result = result.substring(0, result.length() - 1); |
---|
| 349 | |
---|
| 350 | return result; |
---|
| 351 | } |
---|
| 352 | |
---|
| 353 | /** |
---|
| 354 | * returns the classname part of the partial classname. |
---|
| 355 | * |
---|
| 356 | * @param partial the partial classname |
---|
| 357 | * @return the class part of the classname |
---|
| 358 | */ |
---|
| 359 | public String getClassname(String partial) { |
---|
| 360 | String result; |
---|
| 361 | String pkg; |
---|
| 362 | |
---|
| 363 | pkg = getPackage(partial); |
---|
| 364 | if (pkg.length() + 1 < partial.length()) |
---|
| 365 | result = partial.substring(pkg.length() + 1); |
---|
| 366 | else |
---|
| 367 | result = ""; |
---|
| 368 | |
---|
| 369 | return result; |
---|
| 370 | } |
---|
| 371 | |
---|
| 372 | /** |
---|
| 373 | * returns all the file/dir matches with the partial search string. |
---|
| 374 | * |
---|
| 375 | * @param partial the partial search string |
---|
| 376 | * @return all the matches |
---|
| 377 | */ |
---|
| 378 | public Vector<String> getFileMatches(String partial) { |
---|
| 379 | Vector<String> result; |
---|
| 380 | File file; |
---|
| 381 | File dir; |
---|
| 382 | File[] files; |
---|
| 383 | int i; |
---|
| 384 | String prefix; |
---|
| 385 | boolean caseSensitive; |
---|
| 386 | String name; |
---|
| 387 | boolean match; |
---|
| 388 | |
---|
| 389 | result = new Vector<String>(); |
---|
| 390 | |
---|
| 391 | // is the OS case-sensitive? |
---|
| 392 | caseSensitive = (File.separatorChar != '\\'); |
---|
| 393 | if (m_Debug) |
---|
| 394 | System.out.println("case-sensitive=" + caseSensitive); |
---|
| 395 | |
---|
| 396 | // is "~" used for home directory? -> replace with actual home directory |
---|
| 397 | if (partial.startsWith("~")) |
---|
| 398 | partial = System.getProperty("user.home") + partial.substring(1); |
---|
| 399 | |
---|
| 400 | // determine dir and possible prefix |
---|
| 401 | file = new File(partial); |
---|
| 402 | dir = null; |
---|
| 403 | prefix = null; |
---|
| 404 | if (file.exists()) { |
---|
| 405 | // determine dir to read |
---|
| 406 | if (file.isDirectory()) { |
---|
| 407 | dir = file; |
---|
| 408 | prefix = null; // retrieve all |
---|
| 409 | } |
---|
| 410 | else { |
---|
| 411 | dir = file.getParentFile(); |
---|
| 412 | prefix = file.getName(); |
---|
| 413 | } |
---|
| 414 | } |
---|
| 415 | else { |
---|
| 416 | dir = file.getParentFile(); |
---|
| 417 | prefix = file.getName(); |
---|
| 418 | } |
---|
| 419 | |
---|
| 420 | if (m_Debug) |
---|
| 421 | System.out.println("search in dir=" + dir + ", prefix=" + prefix); |
---|
| 422 | |
---|
| 423 | // list all files in dir |
---|
| 424 | if (dir != null) { |
---|
| 425 | files = dir.listFiles(); |
---|
| 426 | if (files != null) { |
---|
| 427 | for (i = 0; i < files.length; i++) { |
---|
| 428 | name = files[i].getName(); |
---|
| 429 | |
---|
| 430 | // does the name match? |
---|
| 431 | if ((prefix != null) && caseSensitive) |
---|
| 432 | match = name.startsWith(prefix); |
---|
| 433 | else if ((prefix != null) && !caseSensitive) |
---|
| 434 | match = name.toLowerCase().startsWith(prefix.toLowerCase()); |
---|
| 435 | else |
---|
| 436 | match = true; |
---|
| 437 | |
---|
| 438 | if (match) { |
---|
| 439 | if (prefix != null) { |
---|
| 440 | result.add(partial.substring(0, partial.length() - prefix.length()) + name); |
---|
| 441 | } |
---|
| 442 | else { |
---|
| 443 | if (partial.endsWith("\\") || partial.endsWith("/")) |
---|
| 444 | result.add(partial + name); |
---|
| 445 | else |
---|
| 446 | result.add(partial + File.separator + name); |
---|
| 447 | } |
---|
| 448 | } |
---|
| 449 | } |
---|
| 450 | } |
---|
| 451 | else { |
---|
| 452 | System.err.println("Invalid path: " + partial); |
---|
| 453 | } |
---|
| 454 | } |
---|
| 455 | |
---|
| 456 | // sort the result |
---|
| 457 | if (result.size() > 1) |
---|
| 458 | Collections.sort(result); |
---|
| 459 | |
---|
| 460 | // print results |
---|
| 461 | if (m_Debug) { |
---|
| 462 | System.out.println("file matches:"); |
---|
| 463 | for (i = 0; i < result.size(); i++) |
---|
| 464 | System.out.println(result.get(i)); |
---|
| 465 | } |
---|
| 466 | |
---|
| 467 | return result; |
---|
| 468 | } |
---|
| 469 | |
---|
| 470 | /** |
---|
| 471 | * returns all the class/package matches with the partial search string. |
---|
| 472 | * |
---|
| 473 | * @param partial the partial search string |
---|
| 474 | * @return all the matches |
---|
| 475 | */ |
---|
| 476 | public Vector<String> getClassMatches(String partial) { |
---|
| 477 | String pkg; |
---|
| 478 | String cls; |
---|
| 479 | Vector<String> result; |
---|
| 480 | Vector<String> list; |
---|
| 481 | int i; |
---|
| 482 | int index; |
---|
| 483 | Trie tmpTrie; |
---|
| 484 | HashSet set; |
---|
| 485 | String tmpStr; |
---|
| 486 | |
---|
| 487 | pkg = getPackage(partial); |
---|
| 488 | cls = getClassname(partial); |
---|
| 489 | |
---|
| 490 | if (getDebug()) |
---|
| 491 | System.out.println( |
---|
| 492 | "\nsearch for: '" + partial + "' => package=" + pkg + ", class=" + cls); |
---|
| 493 | |
---|
| 494 | result = new Vector<String>(); |
---|
| 495 | |
---|
| 496 | // find all packages that start with that string |
---|
| 497 | if (cls.length() == 0) { |
---|
| 498 | list = m_Trie.getWithPrefix(pkg); |
---|
| 499 | set = new HashSet(); |
---|
| 500 | for (i = 0; i < list.size(); i++) { |
---|
| 501 | tmpStr = list.get(i); |
---|
| 502 | if (tmpStr.length() < partial.length()) |
---|
| 503 | continue; |
---|
| 504 | if (tmpStr.equals(partial)) |
---|
| 505 | continue; |
---|
| 506 | |
---|
| 507 | index = tmpStr.indexOf('.', partial.length() + 1); |
---|
| 508 | if (index > -1) |
---|
| 509 | set.add(tmpStr.substring(0, index)); |
---|
| 510 | else |
---|
| 511 | set.add(tmpStr); |
---|
| 512 | } |
---|
| 513 | |
---|
| 514 | result.addAll(set); |
---|
| 515 | if (result.size() > 1) |
---|
| 516 | Collections.sort(result); |
---|
| 517 | } |
---|
| 518 | |
---|
| 519 | // find all classes that start with that string |
---|
| 520 | list = ClassDiscovery.find(Object.class, pkg); |
---|
| 521 | tmpTrie = new Trie(); |
---|
| 522 | tmpTrie.addAll(list); |
---|
| 523 | list = tmpTrie.getWithPrefix(partial); |
---|
| 524 | result.addAll(list); |
---|
| 525 | |
---|
| 526 | // sort the result |
---|
| 527 | if (result.size() > 1) |
---|
| 528 | Collections.sort(result); |
---|
| 529 | |
---|
| 530 | // print results |
---|
| 531 | if (m_Debug) { |
---|
| 532 | System.out.println("class/package matches:"); |
---|
| 533 | for (i = 0; i < result.size(); i++) |
---|
| 534 | System.out.println(result.get(i)); |
---|
| 535 | } |
---|
| 536 | |
---|
| 537 | return result; |
---|
| 538 | } |
---|
| 539 | |
---|
| 540 | /** |
---|
| 541 | * returns all the matches with the partial search string, files or |
---|
| 542 | * classes. |
---|
| 543 | * |
---|
| 544 | * @param partial the partial search string |
---|
| 545 | * @return all the matches |
---|
| 546 | */ |
---|
| 547 | public Vector<String> getMatches(String partial) { |
---|
| 548 | if (isClassname(partial)) |
---|
| 549 | return getClassMatches(partial); |
---|
| 550 | else |
---|
| 551 | return getFileMatches(partial); |
---|
| 552 | } |
---|
| 553 | |
---|
| 554 | /** |
---|
| 555 | * returns the common prefix for all the items in the list. |
---|
| 556 | * |
---|
| 557 | * @param list the list to return the common prefix for |
---|
| 558 | * @return the common prefix of all the items |
---|
| 559 | */ |
---|
| 560 | public String getCommonPrefix(Vector<String> list) { |
---|
| 561 | String result; |
---|
| 562 | Trie trie; |
---|
| 563 | |
---|
| 564 | trie = new Trie(); |
---|
| 565 | trie.addAll(list); |
---|
| 566 | result = trie.getCommonPrefix(); |
---|
| 567 | |
---|
| 568 | if (m_Debug) |
---|
| 569 | System.out.println(list + "\n --> common prefix: '" + result + "'"); |
---|
| 570 | |
---|
| 571 | return result; |
---|
| 572 | } |
---|
| 573 | } |
---|
| 574 | |
---|
| 575 | /** |
---|
| 576 | * For initializing member variables. |
---|
| 577 | */ |
---|
| 578 | protected void initialize() { |
---|
| 579 | super.initialize(); |
---|
| 580 | |
---|
| 581 | m_CommandHistory = new Vector(); |
---|
| 582 | m_HistoryPos = 0; |
---|
| 583 | m_Completion = new CommandlineCompletion(); |
---|
| 584 | } |
---|
| 585 | |
---|
| 586 | /** |
---|
| 587 | * Sets up the GUI after initializing the members. |
---|
| 588 | */ |
---|
| 589 | protected void initGUI() { |
---|
| 590 | super.initGUI(); |
---|
| 591 | |
---|
| 592 | setLayout(new BorderLayout()); |
---|
| 593 | |
---|
| 594 | m_OutputArea = new JTextPane(); |
---|
| 595 | m_OutputArea.setEditable(false); |
---|
| 596 | m_OutputArea.setFont(new Font("Monospaced", Font.PLAIN, 12)); |
---|
| 597 | add(new JScrollPane(m_OutputArea), "Center"); |
---|
| 598 | |
---|
| 599 | m_Input = new JTextField(); |
---|
| 600 | m_Input.setFont(new Font("Monospaced", Font.PLAIN, 12)); |
---|
| 601 | m_Input.addActionListener(this); |
---|
| 602 | m_Input.setFocusTraversalKeysEnabled(false); |
---|
| 603 | m_Input.addKeyListener(new KeyAdapter() { |
---|
| 604 | public void keyPressed(KeyEvent e) { |
---|
| 605 | doHistory(e); |
---|
| 606 | doCommandlineCompletion(e); |
---|
| 607 | } |
---|
| 608 | }); |
---|
| 609 | add(m_Input, "South"); |
---|
| 610 | } |
---|
| 611 | |
---|
| 612 | /** |
---|
| 613 | * Finishes up after initializing members and setting up the GUI. |
---|
| 614 | */ |
---|
| 615 | protected void initFinish() { |
---|
| 616 | super.initFinish(); |
---|
| 617 | |
---|
| 618 | System.out.println( |
---|
| 619 | "\nWelcome to the WEKA SimpleCLI\n\n" |
---|
| 620 | + "Enter commands in the textfield at the bottom of \n" |
---|
| 621 | + "the window. Use the up and down arrows to move \n" |
---|
| 622 | + "through previous commands.\n" |
---|
| 623 | + "Command completion for classnames and files is \n" |
---|
| 624 | + "initiated with <Tab>. In order to distinguish \n" |
---|
| 625 | + "between files and classnames, file names must \n" |
---|
| 626 | + "be either absolute or start with '." + File.separator + "' or '~/'\n" |
---|
| 627 | + "(the latter is a shortcut for the home directory).\n" |
---|
| 628 | + "<Alt+BackSpace> is used for deleting the text\n" |
---|
| 629 | + "in the commandline in chunks.\n"); |
---|
| 630 | try { |
---|
| 631 | runCommand("help"); |
---|
| 632 | } |
---|
| 633 | catch (Exception e) { |
---|
| 634 | // ignored |
---|
| 635 | } |
---|
| 636 | |
---|
| 637 | loadHistory(); |
---|
| 638 | } |
---|
| 639 | |
---|
| 640 | /** |
---|
| 641 | * Returns an icon to be used in a frame. |
---|
| 642 | * |
---|
| 643 | * @return the icon |
---|
| 644 | */ |
---|
| 645 | public ImageIcon getIcon() { |
---|
| 646 | return ComponentHelper.getImageIcon("weka_icon.gif"); |
---|
| 647 | } |
---|
| 648 | |
---|
| 649 | /** |
---|
| 650 | * Returns the current title for the frame/dialog. |
---|
| 651 | * |
---|
| 652 | * @return the title |
---|
| 653 | */ |
---|
| 654 | public String getTitle() { |
---|
| 655 | return "SimpleCLI"; |
---|
| 656 | } |
---|
| 657 | |
---|
| 658 | /** |
---|
| 659 | * Returns the text area that is used for displaying output on stdout |
---|
| 660 | * and stderr. |
---|
| 661 | * |
---|
| 662 | * @return the JTextArea |
---|
| 663 | */ |
---|
| 664 | public JTextPane getOutput() { |
---|
| 665 | return m_OutputArea; |
---|
| 666 | } |
---|
| 667 | |
---|
| 668 | /** |
---|
| 669 | * Not supported. |
---|
| 670 | * |
---|
| 671 | * @return always null |
---|
| 672 | */ |
---|
| 673 | public JMenuBar getMenuBar() { |
---|
| 674 | return null; |
---|
| 675 | } |
---|
| 676 | |
---|
| 677 | /** |
---|
| 678 | * Executes a simple cli command. |
---|
| 679 | * |
---|
| 680 | * @param commands the command string |
---|
| 681 | * @throws Exception if an error occurs |
---|
| 682 | */ |
---|
| 683 | public void runCommand(String commands) throws Exception { |
---|
| 684 | |
---|
| 685 | System.out.println("> " + commands + '\n'); |
---|
| 686 | System.out.flush(); |
---|
| 687 | String [] commandArgs = Utils.splitOptions(commands); |
---|
| 688 | if (commandArgs.length == 0) { |
---|
| 689 | return; |
---|
| 690 | } |
---|
| 691 | if (commandArgs[0].equals("java")) { |
---|
| 692 | // Execute the main method of a class |
---|
| 693 | commandArgs[0] = ""; |
---|
| 694 | try { |
---|
| 695 | if (commandArgs.length == 1) { |
---|
| 696 | throw new Exception("No class name given"); |
---|
| 697 | } |
---|
| 698 | String className = commandArgs[1]; |
---|
| 699 | commandArgs[1] = ""; |
---|
| 700 | if (m_RunThread != null) { |
---|
| 701 | throw new Exception("An object is already running, use \"break\"" |
---|
| 702 | + " to interrupt it."); |
---|
| 703 | } |
---|
| 704 | Class theClass = Class.forName(className); |
---|
| 705 | |
---|
| 706 | // some classes expect a fixed order of the args, i.e., they don't |
---|
| 707 | // use Utils.getOption(...) => create new array without first two |
---|
| 708 | // empty strings (former "java" and "<classname>") |
---|
| 709 | Vector argv = new Vector(); |
---|
| 710 | for (int i = 2; i < commandArgs.length; i++) |
---|
| 711 | argv.add(commandArgs[i]); |
---|
| 712 | |
---|
| 713 | m_RunThread = new ClassRunner(theClass, (String[]) argv.toArray(new String[argv.size()])); |
---|
| 714 | m_RunThread.setPriority(Thread.MIN_PRIORITY); // UI has most priority |
---|
| 715 | m_RunThread.start(); |
---|
| 716 | } catch (Exception ex) { |
---|
| 717 | System.err.println(ex.getMessage()); |
---|
| 718 | } |
---|
| 719 | |
---|
| 720 | } else if (commandArgs[0].equals("capabilities")) { |
---|
| 721 | try { |
---|
| 722 | Object obj = Class.forName(commandArgs[1]).newInstance(); |
---|
| 723 | if (obj instanceof CapabilitiesHandler) { |
---|
| 724 | if (obj instanceof OptionHandler) { |
---|
| 725 | Vector<String> args = new Vector<String>(); |
---|
| 726 | for (int i = 2; i < commandArgs.length; i++) |
---|
| 727 | args.add(commandArgs[i]); |
---|
| 728 | ((OptionHandler) obj).setOptions(args.toArray(new String[args.size()])); |
---|
| 729 | } |
---|
| 730 | Capabilities caps = ((CapabilitiesHandler) obj).getCapabilities(); |
---|
| 731 | System.out.println(caps.toString().replace("[", "\n").replace("]", "\n")); |
---|
| 732 | } |
---|
| 733 | else { |
---|
| 734 | System.out.println("'" + commandArgs[1] + "' is not a " + CapabilitiesHandler.class.getName() + "!"); |
---|
| 735 | } |
---|
| 736 | } |
---|
| 737 | catch (Exception e) { |
---|
| 738 | System.err.println(e.getMessage()); |
---|
| 739 | } |
---|
| 740 | } else if (commandArgs[0].equals("cls")) { |
---|
| 741 | // Clear the text area |
---|
| 742 | m_OutputArea.setText(""); |
---|
| 743 | } else if (commandArgs[0].equals("history")) { |
---|
| 744 | System.out.println("Command history:"); |
---|
| 745 | for (int i = 0; i < m_CommandHistory.size(); i++) |
---|
| 746 | System.out.println(m_CommandHistory.get(i)); |
---|
| 747 | System.out.println(); |
---|
| 748 | } else if (commandArgs[0].equals("break")) { |
---|
| 749 | if (m_RunThread == null) { |
---|
| 750 | System.err.println("Nothing is currently running."); |
---|
| 751 | } else { |
---|
| 752 | System.out.println("[Interrupt...]"); |
---|
| 753 | m_RunThread.interrupt(); |
---|
| 754 | } |
---|
| 755 | } else if (commandArgs[0].equals("kill")) { |
---|
| 756 | if (m_RunThread == null) { |
---|
| 757 | System.err.println("Nothing is currently running."); |
---|
| 758 | } else { |
---|
| 759 | System.out.println("[Kill...]"); |
---|
| 760 | m_RunThread.stop(); |
---|
| 761 | m_RunThread = null; |
---|
| 762 | } |
---|
| 763 | } else if (commandArgs[0].equals("exit")) { |
---|
| 764 | // Shut down |
---|
| 765 | // determine parent |
---|
| 766 | Container parent = getParent(); |
---|
| 767 | Container frame = null; |
---|
| 768 | boolean finished = false; |
---|
| 769 | while (!finished) { |
---|
| 770 | if ( (parent instanceof JFrame) |
---|
| 771 | || (parent instanceof Frame) |
---|
| 772 | || (parent instanceof JInternalFrame) ) { |
---|
| 773 | frame = parent; |
---|
| 774 | finished = true; |
---|
| 775 | } |
---|
| 776 | |
---|
| 777 | if (!finished) { |
---|
| 778 | parent = parent.getParent(); |
---|
| 779 | finished = (parent == null); |
---|
| 780 | } |
---|
| 781 | } |
---|
| 782 | // fire the frame close event |
---|
| 783 | if (frame != null) { |
---|
| 784 | if (frame instanceof JInternalFrame) |
---|
| 785 | ((JInternalFrame) frame).doDefaultCloseAction(); |
---|
| 786 | else |
---|
| 787 | ((Window) frame).dispatchEvent( |
---|
| 788 | new WindowEvent( |
---|
| 789 | (Window) frame, WindowEvent.WINDOW_CLOSING)); |
---|
| 790 | } |
---|
| 791 | |
---|
| 792 | } else { |
---|
| 793 | boolean help = ((commandArgs.length > 1) |
---|
| 794 | && commandArgs[0].equals("help")); |
---|
| 795 | if (help && commandArgs[1].equals("java")) { |
---|
| 796 | System.out.println( |
---|
| 797 | "java <classname> <args>\n\n" |
---|
| 798 | + "Starts the main method of <classname> with " |
---|
| 799 | + "the supplied command line arguments (if any).\n" |
---|
| 800 | + "The command is started in a separate thread, " |
---|
| 801 | + "and may be interrupted with the \"break\"\n" |
---|
| 802 | + "command (friendly), or killed with the \"kill\" " |
---|
| 803 | + "command (unfriendly).\n" |
---|
| 804 | + "Redirecting can be done with '>' followed by the " |
---|
| 805 | + "file to write to, e.g.:\n" |
---|
| 806 | + " java some.Class > ." + File.separator + "some.txt"); |
---|
| 807 | } else if (help && commandArgs[1].equals("break")) { |
---|
| 808 | System.out.println( |
---|
| 809 | "break\n\n" |
---|
| 810 | + "Attempts to nicely interrupt the running job, " |
---|
| 811 | + "if any. If this doesn't respond in an\n" |
---|
| 812 | + "acceptable time, use \"kill\".\n"); |
---|
| 813 | } else if (help && commandArgs[1].equals("kill")) { |
---|
| 814 | System.out.println( |
---|
| 815 | "kill\n\n" |
---|
| 816 | + "Kills the running job, if any. You should only " |
---|
| 817 | + "use this if the job doesn't respond to\n" |
---|
| 818 | + "\"break\".\n"); |
---|
| 819 | } else if (help && commandArgs[1].equals("capabilities")) { |
---|
| 820 | System.out.println( |
---|
| 821 | "capabilities <classname> <args>\n\n" |
---|
| 822 | + "Lists the capabilities of the specified class.\n" |
---|
| 823 | + "If the class is a " + OptionHandler.class.getName() + " then\n" |
---|
| 824 | + "trailing options after the classname will be\n" |
---|
| 825 | + "set as well.\n"); |
---|
| 826 | } else if (help && commandArgs[1].equals("cls")) { |
---|
| 827 | System.out.println( |
---|
| 828 | "cls\n\n" |
---|
| 829 | + "Clears the output area.\n"); |
---|
| 830 | } else if (help && commandArgs[1].equals("history")) { |
---|
| 831 | System.out.println( |
---|
| 832 | "history\n\n" |
---|
| 833 | + "Prints all issued commands.\n"); |
---|
| 834 | } else if (help && commandArgs[1].equals("exit")) { |
---|
| 835 | System.out.println( |
---|
| 836 | "exit\n\n" |
---|
| 837 | + "Exits the SimpleCLI program.\n"); |
---|
| 838 | } else { |
---|
| 839 | // Print a help message |
---|
| 840 | System.out.println( |
---|
| 841 | "Command must be one of:\n" |
---|
| 842 | + "\tjava <classname> <args> [ > file]\n" |
---|
| 843 | + "\tbreak\n" |
---|
| 844 | + "\tkill\n" |
---|
| 845 | + "\tcapabilities <classname> <args>\n" |
---|
| 846 | + "\tcls\n" |
---|
| 847 | + "\thistory\n" |
---|
| 848 | + "\texit\n" |
---|
| 849 | + "\thelp <command>\n"); |
---|
| 850 | } |
---|
| 851 | } |
---|
| 852 | } |
---|
| 853 | |
---|
| 854 | /** |
---|
| 855 | * Changes the currently displayed command line when certain keys |
---|
| 856 | * are pressed. The up arrow moves back through history entries |
---|
| 857 | * and the down arrow moves forward through history entries. |
---|
| 858 | * |
---|
| 859 | * @param e a value of type 'KeyEvent' |
---|
| 860 | */ |
---|
| 861 | public void doHistory(KeyEvent e) { |
---|
| 862 | |
---|
| 863 | if (e.getSource() == m_Input) { |
---|
| 864 | switch (e.getKeyCode()) { |
---|
| 865 | case KeyEvent.VK_UP: |
---|
| 866 | if (m_HistoryPos > 0) { |
---|
| 867 | m_HistoryPos--; |
---|
| 868 | String command = (String) m_CommandHistory.elementAt(m_HistoryPos); |
---|
| 869 | m_Input.setText(command); |
---|
| 870 | } |
---|
| 871 | break; |
---|
| 872 | case KeyEvent.VK_DOWN: |
---|
| 873 | if (m_HistoryPos < m_CommandHistory.size()) { |
---|
| 874 | m_HistoryPos++; |
---|
| 875 | String command = ""; |
---|
| 876 | if (m_HistoryPos < m_CommandHistory.size()) { |
---|
| 877 | command = (String) m_CommandHistory.elementAt(m_HistoryPos); |
---|
| 878 | } |
---|
| 879 | m_Input.setText(command); |
---|
| 880 | } |
---|
| 881 | break; |
---|
| 882 | default: |
---|
| 883 | break; |
---|
| 884 | } |
---|
| 885 | } |
---|
| 886 | } |
---|
| 887 | |
---|
| 888 | /** |
---|
| 889 | * performs commandline completion on packages and classnames. |
---|
| 890 | * |
---|
| 891 | * @param e a value of type 'KeyEvent' |
---|
| 892 | */ |
---|
| 893 | public void doCommandlineCompletion(KeyEvent e) { |
---|
| 894 | if (e.getSource() == m_Input) { |
---|
| 895 | switch (e.getKeyCode()) { |
---|
| 896 | // completion |
---|
| 897 | case KeyEvent.VK_TAB: |
---|
| 898 | if (e.getModifiers() == 0) { |
---|
| 899 | // it might take a while before we determined all of the possible |
---|
| 900 | // matches (Java doesn't have an application wide cursor handling??) |
---|
| 901 | m_Input.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); |
---|
| 902 | m_OutputArea.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); |
---|
| 903 | |
---|
| 904 | try { |
---|
| 905 | String txt = m_Input.getText(); |
---|
| 906 | |
---|
| 907 | // java call? |
---|
| 908 | if (txt.trim().startsWith("java ")) { |
---|
| 909 | int pos = m_Input.getCaretPosition(); |
---|
| 910 | int nonNameCharPos = -1; |
---|
| 911 | // find first character not part of a name, back from current position |
---|
| 912 | // i.e., " or blank |
---|
| 913 | for (int i = pos - 1; i >= 0; i--) { |
---|
| 914 | if ( (txt.charAt(i) == '"') |
---|
| 915 | || (txt.charAt(i) == ' ') ) { |
---|
| 916 | nonNameCharPos = i; |
---|
| 917 | break; |
---|
| 918 | } |
---|
| 919 | } |
---|
| 920 | |
---|
| 921 | if (nonNameCharPos > -1) { |
---|
| 922 | String search = txt.substring(nonNameCharPos + 1, pos); |
---|
| 923 | |
---|
| 924 | // find matches and common prefix |
---|
| 925 | Vector<String> list = m_Completion.getMatches(search); |
---|
| 926 | String common = m_Completion.getCommonPrefix(list); |
---|
| 927 | |
---|
| 928 | // just extending by separator is not a real extension |
---|
| 929 | if ((search.toLowerCase() + File.separator).equals(common.toLowerCase())) |
---|
| 930 | common = search; |
---|
| 931 | |
---|
| 932 | // can we complete the string? |
---|
| 933 | if (common.length() > search.length()) { |
---|
| 934 | try { |
---|
| 935 | m_Input.getDocument().remove(nonNameCharPos + 1, search.length()); |
---|
| 936 | m_Input.getDocument().insertString(nonNameCharPos + 1, common, null); |
---|
| 937 | } |
---|
| 938 | catch (Exception ex) { |
---|
| 939 | ex.printStackTrace(); |
---|
| 940 | } |
---|
| 941 | } |
---|
| 942 | // ambigiuous? -> print matches |
---|
| 943 | else if (list.size() > 1) { |
---|
| 944 | System.out.println("\nPossible matches:"); |
---|
| 945 | for (int i = 0; i < list.size(); i++) |
---|
| 946 | System.out.println(" " + list.get(i)); |
---|
| 947 | } |
---|
| 948 | else { |
---|
| 949 | // nothing found, don't do anything |
---|
| 950 | } |
---|
| 951 | } |
---|
| 952 | } |
---|
| 953 | } |
---|
| 954 | finally { |
---|
| 955 | // set cursor back to default |
---|
| 956 | m_Input.setCursor(null); |
---|
| 957 | m_OutputArea.setCursor(null); |
---|
| 958 | } |
---|
| 959 | } |
---|
| 960 | break; |
---|
| 961 | |
---|
| 962 | // delete last part up to next blank or dot |
---|
| 963 | case KeyEvent.VK_BACK_SPACE: |
---|
| 964 | if (e.getModifiers() == KeyEvent.ALT_MASK) { |
---|
| 965 | String txt = m_Input.getText(); |
---|
| 966 | int pos = m_Input.getCaretPosition(); |
---|
| 967 | |
---|
| 968 | // skip whitespaces |
---|
| 969 | int start = pos; |
---|
| 970 | start--; |
---|
| 971 | while (start >= 0) { |
---|
| 972 | if ( (txt.charAt(start) == '.') |
---|
| 973 | || (txt.charAt(start) == ' ') |
---|
| 974 | || (txt.charAt(start) == '\\') |
---|
| 975 | || (txt.charAt(start) == '/') ) |
---|
| 976 | start--; |
---|
| 977 | else |
---|
| 978 | break; |
---|
| 979 | } |
---|
| 980 | |
---|
| 981 | // find first blank or dot back from position |
---|
| 982 | int newPos = -1; |
---|
| 983 | for (int i = start; i >= 0; i--) { |
---|
| 984 | if ( (txt.charAt(i) == '.') |
---|
| 985 | || (txt.charAt(i) == ' ') |
---|
| 986 | || (txt.charAt(i) == '\\') |
---|
| 987 | || (txt.charAt(i) == '/') ) { |
---|
| 988 | newPos = i; |
---|
| 989 | break; |
---|
| 990 | } |
---|
| 991 | } |
---|
| 992 | |
---|
| 993 | // remove string |
---|
| 994 | try { |
---|
| 995 | m_Input.getDocument().remove(newPos + 1, pos - newPos - 1); |
---|
| 996 | } |
---|
| 997 | catch (Exception ex) { |
---|
| 998 | ex.printStackTrace(); |
---|
| 999 | } |
---|
| 1000 | } |
---|
| 1001 | break; |
---|
| 1002 | } |
---|
| 1003 | } |
---|
| 1004 | } |
---|
| 1005 | |
---|
| 1006 | /** |
---|
| 1007 | * Only gets called when return is pressed in the input area, which |
---|
| 1008 | * starts the command running. |
---|
| 1009 | * |
---|
| 1010 | * @param e a value of type 'ActionEvent' |
---|
| 1011 | */ |
---|
| 1012 | public void actionPerformed(ActionEvent e) { |
---|
| 1013 | |
---|
| 1014 | try { |
---|
| 1015 | if (e.getSource() == m_Input) { |
---|
| 1016 | String command = m_Input.getText(); |
---|
| 1017 | int last = m_CommandHistory.size() - 1; |
---|
| 1018 | if ((last < 0) |
---|
| 1019 | || !command.equals((String)m_CommandHistory.elementAt(last))) { |
---|
| 1020 | m_CommandHistory.addElement(command); |
---|
| 1021 | saveHistory(); |
---|
| 1022 | } |
---|
| 1023 | m_HistoryPos = m_CommandHistory.size(); |
---|
| 1024 | runCommand(command); |
---|
| 1025 | |
---|
| 1026 | m_Input.setText(""); |
---|
| 1027 | } |
---|
| 1028 | } catch (Exception ex) { |
---|
| 1029 | System.err.println(ex.getMessage()); |
---|
| 1030 | } |
---|
| 1031 | } |
---|
| 1032 | |
---|
| 1033 | /** |
---|
| 1034 | * loads the command history from the user's properties file. |
---|
| 1035 | */ |
---|
| 1036 | protected void loadHistory() { |
---|
| 1037 | int size; |
---|
| 1038 | int i; |
---|
| 1039 | String cmd; |
---|
| 1040 | |
---|
| 1041 | size = Integer.parseInt(PROPERTIES.getProperty("HistorySize", "50")); |
---|
| 1042 | |
---|
| 1043 | m_CommandHistory.clear(); |
---|
| 1044 | for (i = 0; i < size; i++) { |
---|
| 1045 | cmd = PROPERTIES.getProperty("Command" + i, ""); |
---|
| 1046 | if (cmd.length() != 0) |
---|
| 1047 | m_CommandHistory.add(cmd); |
---|
| 1048 | else |
---|
| 1049 | break; |
---|
| 1050 | } |
---|
| 1051 | |
---|
| 1052 | m_HistoryPos = m_CommandHistory.size(); |
---|
| 1053 | } |
---|
| 1054 | |
---|
| 1055 | /** |
---|
| 1056 | * saves the current command history in the user's home directory. |
---|
| 1057 | */ |
---|
| 1058 | protected void saveHistory() { |
---|
| 1059 | int size; |
---|
| 1060 | int from; |
---|
| 1061 | int i; |
---|
| 1062 | String filename; |
---|
| 1063 | BufferedOutputStream stream; |
---|
| 1064 | |
---|
| 1065 | size = Integer.parseInt(PROPERTIES.getProperty("HistorySize", "50")); |
---|
| 1066 | |
---|
| 1067 | // determine first command to save |
---|
| 1068 | from = m_CommandHistory.size() - size; |
---|
| 1069 | if (from < 0) |
---|
| 1070 | from = 0; |
---|
| 1071 | |
---|
| 1072 | // fill properties |
---|
| 1073 | PROPERTIES.setProperty("HistorySize", "" + size); |
---|
| 1074 | for (i = from; i < m_CommandHistory.size(); i++) |
---|
| 1075 | PROPERTIES.setProperty("Command" + (i-from), (String) m_CommandHistory.get(i)); |
---|
| 1076 | |
---|
| 1077 | try { |
---|
| 1078 | filename = System.getProperties().getProperty("user.home") + File.separatorChar + FILENAME; |
---|
| 1079 | stream = new BufferedOutputStream(new FileOutputStream(filename)); |
---|
| 1080 | PROPERTIES.store(stream, "SimpleCLI"); |
---|
| 1081 | stream.close(); |
---|
| 1082 | } |
---|
| 1083 | catch (Exception e) { |
---|
| 1084 | e.printStackTrace(); |
---|
| 1085 | } |
---|
| 1086 | } |
---|
| 1087 | |
---|
| 1088 | /** |
---|
| 1089 | * Displays the panel in a frame. |
---|
| 1090 | * |
---|
| 1091 | * @param args ignored |
---|
| 1092 | */ |
---|
| 1093 | public static void main(String[] args) { |
---|
| 1094 | showPanel(new SimpleCLIPanel(), args); |
---|
| 1095 | } |
---|
| 1096 | } |
---|