/tags/3.1.0/src/org/getopt/luke/Luke.java

http://luke.googlecode.com/ · Java · 4726 lines · 4239 code · 178 blank · 309 comment · 988 complexity · ed6ce736556028291fd87ef78bffcd8e MD5 · raw file

Large files are truncated click here to view the full file

  1. /*
  2. * Licensed to the Apache Software Foundation (ASF) under one or more
  3. * contributor license agreements. See the NOTICE file distributed with
  4. * this work for additional information regarding copyright ownership.
  5. * The ASF licenses this file to You under the Apache License, Version 2.0
  6. * (the "License"); you may not use this file except in compliance with
  7. * the License. You may obtain a copy of the License at
  8. *
  9. * http://www.apache.org/licenses/LICENSE-2.0
  10. *
  11. * Unless required by applicable law or agreed to in writing, software
  12. * distributed under the License is distributed on an "AS IS" BASIS,
  13. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. * See the License for the specific language governing permissions and
  15. * limitations under the License.
  16. */
  17. package org.getopt.luke;
  18. import java.awt.Color;
  19. import java.awt.Font;
  20. import java.awt.GraphicsEnvironment;
  21. import java.awt.Toolkit;
  22. import java.awt.datatransfer.Clipboard;
  23. import java.awt.datatransfer.ClipboardOwner;
  24. import java.awt.datatransfer.StringSelection;
  25. import java.awt.datatransfer.Transferable;
  26. import java.io.*;
  27. import java.lang.reflect.Constructor;
  28. import java.lang.reflect.Method;
  29. import java.text.DecimalFormat;
  30. import java.text.NumberFormat;
  31. import java.util.*;
  32. import java.util.Map.Entry;
  33. import java.util.zip.GZIPOutputStream;
  34. import javax.swing.JFileChooser;
  35. import javax.swing.UIManager;
  36. import org.apache.lucene.LucenePackage;
  37. import org.apache.lucene.analysis.*;
  38. import org.apache.lucene.analysis.payloads.PayloadHelper;
  39. import org.apache.lucene.analysis.standard.StandardAnalyzer;
  40. import org.apache.lucene.document.DateTools;
  41. import org.apache.lucene.document.Document;
  42. import org.apache.lucene.document.Field;
  43. import org.apache.lucene.document.NumberTools;
  44. import org.apache.lucene.document.Field.Index;
  45. import org.apache.lucene.document.Field.Store;
  46. import org.apache.lucene.index.*;
  47. import org.apache.lucene.index.IndexReader.FieldOption;
  48. import org.apache.lucene.index.IndexWriter.MaxFieldLength;
  49. import org.apache.lucene.misc.SweetSpotSimilarity;
  50. import org.apache.lucene.queryParser.QueryParser;
  51. import org.apache.lucene.search.*;
  52. import org.apache.lucene.search.BooleanClause.Occur;
  53. import org.apache.lucene.search.payloads.PayloadNearQuery;
  54. import org.apache.lucene.search.payloads.PayloadTermQuery;
  55. import org.apache.lucene.search.similar.MoreLikeThis;
  56. import org.apache.lucene.search.spans.SpanFirstQuery;
  57. import org.apache.lucene.search.spans.SpanNearQuery;
  58. import org.apache.lucene.search.spans.SpanNotQuery;
  59. import org.apache.lucene.search.spans.SpanOrQuery;
  60. import org.apache.lucene.search.spans.SpanQuery;
  61. import org.apache.lucene.search.spans.SpanTermQuery;
  62. import org.apache.lucene.search.spans.Spans;
  63. import org.apache.lucene.store.*;
  64. import org.apache.lucene.util.NumericUtils;
  65. import org.apache.lucene.util.Version;
  66. import org.apache.lucene.xmlparser.CoreParser;
  67. import org.apache.lucene.xmlparser.CorePlusExtensionsParser;
  68. import org.getopt.luke.DocReconstructor.Reconstructed;
  69. import org.getopt.luke.decoders.BinaryDecoder;
  70. import org.getopt.luke.decoders.DateDecoder;
  71. import org.getopt.luke.decoders.Decoder;
  72. import org.getopt.luke.decoders.NumDoubleDecoder;
  73. import org.getopt.luke.decoders.NumFloatDecoder;
  74. import org.getopt.luke.decoders.NumIntDecoder;
  75. import org.getopt.luke.decoders.NumLongDecoder;
  76. import org.getopt.luke.decoders.OldDateFieldDecoder;
  77. import org.getopt.luke.decoders.OldNumberToolsDecoder;
  78. import org.getopt.luke.decoders.StringDecoder;
  79. import org.getopt.luke.plugins.ScriptingPlugin;
  80. import org.getopt.luke.xmlQuery.XmlQueryParserFactory;
  81. import org.getopt.luke.xmlQuery.CorePlusExtensionsParserFactory;
  82. import thinlet.FrameLauncher;
  83. import thinlet.Thinlet;
  84. /**
  85. * This class allows you to browse a <a href="jakarta.apache.org/lucene">Lucene
  86. * </a> index in several ways - by document, by term, by query, and by most
  87. * frequent terms.
  88. *
  89. * @author Andrzej Bialecki
  90. *
  91. */
  92. public class Luke extends Thinlet implements ClipboardOwner {
  93. private Directory dir = null;
  94. String pName = null;
  95. private IndexReader ir = null;
  96. private IndexSearcher is = null;
  97. private boolean slowAccess = false;
  98. private Collection<String> fn = null;
  99. private String[] idxFields = null;
  100. private HashMap<String, FieldTermCount> termCounts = new HashMap<String, FieldTermCount>();
  101. private List<LukePlugin> plugins = new ArrayList<LukePlugin>();
  102. private Object errorDlg = null;
  103. private Object infoDlg = null;
  104. private Object statmsg = null;
  105. private Object slowstatus = null;
  106. private Object slowmsg = null;
  107. private Analyzer stdAnalyzer = new StandardAnalyzer(Version.LUCENE_CURRENT);
  108. private Analyzer analyzer = null;
  109. //private QueryParser qp = null;
  110. private boolean readOnly = false;
  111. private boolean ram = false;
  112. private boolean keepCommits = false;
  113. private boolean multi = false;
  114. private int tiiDiv = 1;
  115. private IndexCommit currentCommit = null;
  116. private Similarity similarity = null;
  117. private Object lastST;
  118. private HashMap<String, Decoder> decoders = new HashMap<String, Decoder>();
  119. private Decoder defDecoder = new StringDecoder();
  120. /** Default salmon theme. */
  121. public static final int THEME_DEFAULT = 0;
  122. /** Gray theme. */
  123. public static final int THEME_GRAY = 1;
  124. /** Sandstone theme. */
  125. public static final int THEME_SANDSTONE = 2;
  126. /** Sky blue theme. */
  127. public static final int THEME_SKY = 3;
  128. /** Navy blue reverse theme. */
  129. public static final int THEME_NAVY = 4;
  130. /** Theme color contants. */
  131. public int[][] themes = {
  132. {0xece9d0, 0x000000, 0xf5f4f0, 0x919b9a, 0xb0b0b0, 0xeeeeee, 0xb9b9b9, 0xff8080, 0xc5c5dd}, // default
  133. {0xe6e6e6, 0x000000, 0xffffff, 0x909090, 0xb0b0b0, 0xededed, 0xb9b9b9, 0x89899a, 0xc5c5dd}, // gray
  134. {0xeeeecc, 0x000000, 0xffffff, 0x999966, 0xb0b096, 0xededcb, 0xcccc99, 0xcc6600, 0xffcc66}, // sandstone
  135. {0xf0f0ff, 0x0000a0, 0xffffff, 0x8080ff, 0xb0b0b0, 0xededed, 0xb0b0ff, 0xff0000, 0xfde0e0}, // sky
  136. {0x6375d6, 0xffffff, 0x7f8fdd, 0xd6dff5, 0x9caae5, 0x666666, 0x003399, 0xff3333, 0x666666} // navy
  137. };
  138. private int numTerms = 0;
  139. private static boolean exitOnDestroy = false;
  140. private Class[] analyzers = null;
  141. private String baseDir = null;
  142. private Class[] defaultAnalyzers = { SimpleAnalyzer.class, StandardAnalyzer.class, StopAnalyzer.class,
  143. WhitespaceAnalyzer.class };
  144. private static final String MSG_NOINDEX = "FAILED: No index, or index is closed. Reopen it.";
  145. private static final String MSG_READONLY = "FAILED: Read-Only index.";
  146. private static final String MSG_CONV_ERROR = "Some values could not be properly represented in this format. " +
  147. "They are marked in grey and presented as a hex dump.";
  148. /** Default constructor, loads preferences, initializes plugins and GUI. */
  149. public Luke() {
  150. super();
  151. Prefs.load();
  152. try {
  153. UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
  154. } catch (Exception e) {}
  155. setTheme(Prefs.getInteger(Prefs.P_THEME, THEME_DEFAULT));
  156. String fontName = Prefs.getProperty(Prefs.P_FONT_NAME, "SansSerif");
  157. String fontSize = Prefs.getProperty(Prefs.P_FONT_SIZE, "12.0");
  158. float fsize = 12.0f;
  159. try {
  160. fsize = Float.parseFloat(fontSize);
  161. } catch (Exception e) {};
  162. Font f = new Font(fontName, Font.PLAIN, (int)fsize);
  163. setFont(f);
  164. addComponent(this, "/xml/luke.xml", null, null);
  165. errorDlg = addComponent(null, "/xml/error.xml", null, null);
  166. infoDlg = addComponent(null, "/xml/info.xml", null, null);
  167. statmsg = find("statmsg");
  168. slowstatus = find("slowstat");
  169. slowmsg = find(slowstatus, "slowmsg");
  170. // populate analyzers
  171. try {
  172. Class[] an = ClassFinder.getInstantiableSubclasses(Analyzer.class);
  173. if (an == null || an.length == 0) {
  174. analyzers = defaultAnalyzers;
  175. } else {
  176. HashSet<Class> uniq = new HashSet<Class>(Arrays.asList(an));
  177. analyzers = (Class[])uniq.toArray(new Class[uniq.size()]);
  178. }
  179. Object cbType = find("cbType");
  180. populateAnalyzers(cbType);
  181. } catch (Exception e) {
  182. e.printStackTrace();
  183. }
  184. loadPlugins();
  185. }
  186. /**
  187. * Set color theme for the UI.
  188. * @param which one of the predefined themes. For custom themes use {@link Thinlet#setColors(int, int, int, int, int, int, int, int, int)}.
  189. */
  190. public void setTheme(int which) {
  191. if (which < 0 || which >= themes.length) which = THEME_DEFAULT;
  192. int[] t = themes[which];
  193. setColors(t[0], t[1], t[2], t[3], t[4], t[5], t[6], t[7], t[8]);
  194. Prefs.setProperty(Prefs.P_THEME, which + "");
  195. }
  196. /**
  197. * Action handler to select color theme.
  198. * @param menu
  199. */
  200. public void actionTheme(Object menu) {
  201. String which = (String)getProperty(menu, "t");
  202. int t = THEME_DEFAULT;
  203. try {
  204. t = Integer.parseInt(which);
  205. } catch (Exception e) {};
  206. setTheme(t);
  207. }
  208. /**
  209. * Populate a combobox with the current list of analyzers.
  210. * @param combo
  211. */
  212. public void populateAnalyzers(Object combo) {
  213. removeAll(combo);
  214. String[] aNames = new String[analyzers.length];
  215. for (int i = 0; i < analyzers.length; i++) {
  216. aNames[i] = analyzers[i].getName();
  217. }
  218. Arrays.sort(aNames);
  219. for (int i = 0; i < aNames.length; i++) {
  220. Object choice = create("choice");
  221. setString(choice, "text", aNames[i]);
  222. add(combo, choice);
  223. if (i == 0) {
  224. setString(combo, "text", aNames[i]);
  225. }
  226. }
  227. int lastAnalyzerIdx = 0;
  228. String lastAnalyzer = Prefs.getProperty(Prefs.P_ANALYZER);
  229. if (lastAnalyzer != null) lastAnalyzerIdx = getIndex(combo, lastAnalyzer);
  230. if (lastAnalyzerIdx < 0) lastAnalyzerIdx = 0;
  231. setInteger(combo, "selected", lastAnalyzerIdx);
  232. }
  233. /**
  234. * Return an array of available Analyzer implementations.
  235. * @return
  236. */
  237. public Class[] getAnalyzers() {
  238. return analyzers;
  239. }
  240. /**
  241. * Loads plugins. Plugins are first searched from the CLASSPATH, and then from a
  242. * plugin list contained in a resource file "/.plugins". The "/.plugins" resource file
  243. * has a simple format - one fully qualified class name per line. Blank lines and
  244. * lines starting with '#' are ignored.
  245. */
  246. private void loadPlugins() {
  247. List pluginClasses = new ArrayList();
  248. // try to find all plugins
  249. try {
  250. Class classes[] = ClassFinder.getInstantiableSubclasses(LukePlugin.class);
  251. if (classes != null && classes.length > 0) {
  252. pluginClasses.addAll(Arrays.asList(classes));
  253. }
  254. } catch (Exception e) {
  255. e.printStackTrace();
  256. }
  257. // load plugins declared in the ".plugins" file
  258. try {
  259. InputStream is = getClass().getResourceAsStream("/.plugins");
  260. if (is != null) {
  261. BufferedReader br = new BufferedReader(new InputStreamReader(is));
  262. String line = null;
  263. while ((line = br.readLine()) != null) {
  264. if (line.startsWith("#")) continue;
  265. if (line.trim().equals("")) continue;
  266. try {
  267. Class clazz = Class.forName(line.trim());
  268. if (clazz.getSuperclass().equals(LukePlugin.class) && !pluginClasses.contains(clazz)) {
  269. pluginClasses.add(clazz);
  270. }
  271. } catch (Throwable x) {
  272. //
  273. }
  274. }
  275. }
  276. } catch (Exception e) {
  277. e.printStackTrace();
  278. }
  279. try {
  280. StringBuffer errors = new StringBuffer("Unable to load some plugins:");
  281. boolean failures = false;
  282. for (int i = 0; i < pluginClasses.size(); i++) {
  283. try {
  284. LukePlugin plugin = (LukePlugin) ((Class) pluginClasses.get(i)).getConstructor(new Class[0]).newInstance(
  285. new Object[0]);
  286. String xul = plugin.getXULName();
  287. if (xul == null) continue;
  288. Object ui = parse(xul, plugin);
  289. plugin.setApplication(this);
  290. plugin.setMyUi(ui);
  291. plugins.add(plugin);
  292. } catch (Exception e) {
  293. failures = true;
  294. e.printStackTrace();
  295. errors.append("\n" + pluginClasses.get(i).toString());
  296. }
  297. }
  298. if (failures) {
  299. errorMsg(errors.toString());
  300. }
  301. } catch (Exception e) {
  302. e.printStackTrace();
  303. errorMsg(e.toString());
  304. }
  305. if (plugins.size() == 0) return;
  306. initPlugins();
  307. }
  308. /**
  309. * Create UI for a single plugin.
  310. * @param tabs parent tabbedpane
  311. * @param plugin plugin instance
  312. */
  313. private void addPluginTab(Object tabs, LukePlugin plugin) {
  314. Object tab = create("tab");
  315. setColor(tab, "foreground", new Color(0x006000));
  316. setString(tab, "text", plugin.getPluginName());
  317. setFont(tab, getFont().deriveFont(Font.BOLD));
  318. add(tabs, tab);
  319. Object panel = create("panel");
  320. setInteger(panel, "gap", 2);
  321. setInteger(panel, "weightx", 1);
  322. setInteger(panel, "weighty", 1);
  323. setChoice(panel, "halign", "fill");
  324. setChoice(panel, "valign", "fill");
  325. setInteger(panel, "columns", 1);
  326. add(tab, panel);
  327. Object infobar = create("panel");
  328. setInteger(infobar, "gap", 8);
  329. setInteger(infobar, "top", 2);
  330. setInteger(infobar, "bottom", 2);
  331. setInteger(infobar, "weightx", 1);
  332. setChoice(infobar, "halign", "fill");
  333. setColor(infobar, "background", new Color(0xc0f0c0));
  334. add(panel, infobar);
  335. Object label = create("label");
  336. setString(label, "text", plugin.getPluginInfo());
  337. add(infobar, label);
  338. Object link = create("button");
  339. setChoice(link, "type", "link");
  340. setString(link, "text", plugin.getPluginHome());
  341. putProperty(link, "url", plugin.getPluginHome());
  342. setMethod(link, "action", "goUrl(this)", infobar, this);
  343. add(infobar, link);
  344. add(panel, create("separator"));
  345. add(panel, plugin.getMyUi());
  346. }
  347. /**
  348. * Return the list of active plugin instances.
  349. * @return
  350. */
  351. public List getPlugins() {
  352. return Collections.unmodifiableList(plugins);
  353. }
  354. /**
  355. * Get an already instantiated plugin, or null if such plugin was
  356. * not loaded on startup.
  357. * @param className fully qualified plugin classname
  358. * @return
  359. */
  360. public LukePlugin getPlugin(String className) {
  361. for (int i = 0; i < plugins.size(); i++) {
  362. Object plugin = plugins.get(i);
  363. if (plugin.getClass().getName().equals(className))
  364. return (LukePlugin)plugin;
  365. }
  366. return null;
  367. }
  368. Thread statusThread = null;
  369. long lastUpdate = 0;
  370. long statusSleep = 0;
  371. /**
  372. * Display a message on the status bar for 5 seconds.
  373. * @param msg message to display. Too long messages will be truncated by the UI.
  374. */
  375. public void showStatus(final String msg) {
  376. if (statusThread != null && statusThread.isAlive()) {
  377. setString(statmsg, "text", msg);
  378. statusSleep = 5000;
  379. } else {
  380. statusThread = new Thread() {
  381. public void run() {
  382. statusSleep = 5000;
  383. setString(statmsg, "text", msg);
  384. while (statusSleep > 0) {
  385. try {
  386. sleep(500);
  387. } catch (Exception e) {};
  388. statusSleep -= 500;
  389. }
  390. setString(statmsg, "text", "");
  391. }
  392. };
  393. statusThread.start();
  394. }
  395. }
  396. /**
  397. * As {@link #showStatus(String)} but also sets the "Last search time" label.
  398. * @param msg
  399. */
  400. public void showSearchStatus(String msg) {
  401. setString(lastST, "text", msg);
  402. showStatus(msg);
  403. }
  404. long lastSlowUpdate = 0L;
  405. long lastSlowCounter = 0L;
  406. Thread slowThread = null;
  407. long slowSleep = 0;
  408. public void showSlowStatus(final String msg, final long counter) {
  409. if (slowThread != null && slowThread.isAlive()) {
  410. lastSlowCounter += counter;
  411. setString(slowmsg, "text", msg + " " + lastSlowCounter);
  412. slowSleep = 5000;
  413. } else {
  414. slowThread = new Thread() {
  415. public void run() {
  416. slowSleep = 5000;
  417. lastSlowCounter = counter;
  418. setBoolean(slowstatus, "visible", true);
  419. setString(slowmsg, "text", msg + " " + lastSlowCounter);
  420. while (slowSleep > 0) {
  421. try {
  422. sleep(500);
  423. } catch (Exception e) {};
  424. slowSleep -= 500;
  425. }
  426. setString(slowmsg, "text", "");
  427. setBoolean(slowstatus, "visible", false);
  428. }
  429. };
  430. slowThread.start();
  431. }
  432. }
  433. /**
  434. * Add a Thinlet component from XUL file.
  435. * @param parent add the new component to this parent
  436. * @param compView path to the XUL resource
  437. * @param handlerStr fully qualified classname of the handler to instantiate,
  438. * or null if the current class will become the handler
  439. * @param argv if not null, these arguments will be passed to the
  440. * appropriate constructor.
  441. * @return
  442. */
  443. public Object addComponent(Object parent, String compView, String handlerStr, Object[] argv) {
  444. Object res = null;
  445. Object handler = null;
  446. try {
  447. if (handlerStr != null) {
  448. if (argv == null) {
  449. handler = Class.forName(handlerStr).getConstructor(new Class[] { Thinlet.class }).newInstance(
  450. new Object[] { this });
  451. } else {
  452. handler = Class.forName(handlerStr).getConstructor(new Class[] { Thinlet.class, Object[].class })
  453. .newInstance(new Object[] { this, argv });
  454. }
  455. }
  456. if (handler != null) {
  457. res = parse(compView, handler);
  458. } else res = parse(compView);
  459. if (parent != null) {
  460. if (parent instanceof Thinlet)
  461. add(res);
  462. else add(parent, res);
  463. }
  464. return res;
  465. } catch (Exception exc) {
  466. exc.printStackTrace();
  467. errorMsg(exc.getMessage());
  468. return null;
  469. }
  470. }
  471. /**
  472. * Show a modal error dialog with OK button.
  473. * @param msg error message
  474. */
  475. public void errorMsg(String msg) {
  476. Object fMsg = find(errorDlg, "msg");
  477. setString(fMsg, "text", msg);
  478. add(errorDlg);
  479. }
  480. /**
  481. * Show a modal info dialog with OK button.
  482. * @param msg info message
  483. */
  484. public void infoMsg(String msg) {
  485. Object fMsg = find(infoDlg, "msg");
  486. setString(fMsg, "text", msg);
  487. add(infoDlg);
  488. }
  489. /**
  490. * Show an "Open Index" dialog.
  491. *
  492. */
  493. public void actionOpen() {
  494. Object dialog = addComponent(this, "/xml/lukeinit.xml", null, null);
  495. Object path = find(dialog, "path");
  496. if (this.baseDir != null)
  497. setString(path, "text", this.baseDir);
  498. else setString(path, "text", System.getProperty("user.dir"));
  499. }
  500. /**
  501. * Browse for a directory, and put the selection result in the
  502. * indicated widget.
  503. * @param path Thinlet widget to put the result
  504. */
  505. public void openBrowse(Object path) {
  506. JFileChooser fd = new JFileChooser();
  507. fd.setDialogType(JFileChooser.OPEN_DIALOG);
  508. fd.setDialogTitle("Select Index directory");
  509. fd.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES);
  510. fd.setFileHidingEnabled(false);
  511. String strPath = getString(path, "text");
  512. if (strPath != null) strPath.trim();
  513. if (strPath != null && strPath.length() > 0)
  514. fd.setCurrentDirectory(new File(strPath));
  515. else if (this.baseDir != null)
  516. fd.setCurrentDirectory(new File(this.baseDir));
  517. else fd.setCurrentDirectory(new File(System.getProperty("user.dir")));
  518. int res = fd.showOpenDialog(this);
  519. File iDir = null;
  520. if (res == JFileChooser.APPROVE_OPTION) iDir = fd.getSelectedFile();
  521. if (iDir != null && iDir.exists()) {
  522. if (!iDir.isDirectory()) iDir = iDir.getParentFile();
  523. setString(path, "text", iDir.toString());
  524. }
  525. }
  526. /**
  527. * Select an output file name, and put the selection result in the
  528. * indicated widget.
  529. * @param path Thinlet widget to put the result
  530. */
  531. public void saveBrowse(Object path, Object startButton) {
  532. JFileChooser fd = new JFileChooser();
  533. fd.setDialogType(JFileChooser.SAVE_DIALOG);
  534. fd.setDialogTitle("Select Output File");
  535. fd.setFileSelectionMode(JFileChooser.FILES_ONLY);
  536. fd.setFileHidingEnabled(false);
  537. String strPath = getString(path, "text");
  538. if (strPath != null) strPath.trim();
  539. if (strPath != null && strPath.length() > 0)
  540. fd.setCurrentDirectory(new File(strPath));
  541. else if (this.baseDir != null)
  542. fd.setCurrentDirectory(new File(this.baseDir));
  543. else fd.setCurrentDirectory(new File(System.getProperty("user.dir")));
  544. int res = fd.showSaveDialog(this);
  545. setBoolean(startButton, "enabled", false);
  546. File iFile = null;
  547. if (res == JFileChooser.APPROVE_OPTION) iFile = fd.getSelectedFile();
  548. if (iFile != null) {
  549. setString(path, "text", iFile.toString());
  550. setBoolean(startButton, "enabled", true);
  551. }
  552. }
  553. /**
  554. * Initialize MRU list of indexes in the open index dialog.
  555. * @param dialog
  556. */
  557. public void setupInit(Object dialog) {
  558. Object path = find(dialog, "path");
  559. syncMRU(path);
  560. }
  561. /**
  562. * Attempt to load the index with parameters specified in the dialog.
  563. * <p>NOTE: this method is invoked from the UI. If you need to open an index
  564. * programmatically, you should use {@link #openIndex(String, boolean, boolean, boolean)} instead.</p>
  565. * @param dialog UI dialog with parameters
  566. */
  567. public void openOk(Object dialog) {
  568. Object path = find(dialog, "path");
  569. pName = getString(path, "text").trim();
  570. boolean force = getBoolean(find(dialog, "force"), "selected");
  571. boolean noReader = getBoolean(find(dialog, "cbNoReader"), "selected");
  572. tiiDiv = 1;
  573. try {
  574. tiiDiv = Integer.parseInt(getString(find(dialog, "tiiDiv"), "text"));
  575. } catch (Exception e) {
  576. e.printStackTrace();
  577. }
  578. Object dirImpl = getSelectedItem(find(dialog, "dirImpl"));
  579. String dirClass = null;
  580. if (dirImpl == null) {
  581. dirClass = FSDirectory.class.getName();
  582. } else {
  583. String name = getString(dirImpl, "name");
  584. if (name == null) {
  585. dirClass = getString(dirImpl, "text");
  586. } else {
  587. if (name.equals("fs")) {
  588. dirClass = FSDirectory.class.getName();
  589. } else if (name.equals("mmap")) {
  590. dirClass = MMapDirectory.class.getName();
  591. } else if (name.equals("niofs")) {
  592. dirClass = NIOFSDirectory.class.getName();
  593. }
  594. }
  595. }
  596. if (pName == null || pName.trim().equals("")) {
  597. errorMsg("Invalid path.");
  598. return;
  599. }
  600. readOnly = getBoolean(find(dialog, "ro"), "selected");
  601. ram = getBoolean(find(dialog, "ram"), "selected");
  602. keepCommits = getBoolean(find(dialog, "cbKeepCommits"), "selected");
  603. slowAccess = getBoolean(find(dialog, "cbSlowIO"), "selected");
  604. decoders.clear();
  605. currentCommit = null;
  606. Prefs.addToMruList(pName);
  607. syncMRU(path);
  608. remove(dialog);
  609. if (noReader) {
  610. removeAll();
  611. addComponent(this, "/xml/luke.xml", null, null);
  612. try {
  613. Directory d = openDirectory(dirClass, pName, false);
  614. if (IndexReader.indexExists(d)) {
  615. throw new Exception("there is no valid Lucene index in this directory.");
  616. }
  617. dir = d;
  618. initOverview();
  619. infoMsg("There is no IndexReader - most actions are disabled. " +
  620. "You can open IndexReader from current Directory using 'Re-Open'");
  621. } catch (Exception e) {
  622. errorMsg("ERROR: " + e.toString());
  623. }
  624. } else {
  625. openIndex(pName, force, dirClass, readOnly, ram, keepCommits, null, tiiDiv);
  626. }
  627. }
  628. public void actionClose() {
  629. if (ir != null) {
  630. try {
  631. if (is != null) is.close();
  632. ir.close();
  633. if (dir != null) dir.close();
  634. } catch (Exception e) {
  635. e.printStackTrace();
  636. errorMsg("Close failed: " + e.getMessage());
  637. }
  638. }
  639. ir = null;
  640. dir = null;
  641. is = null;
  642. removeAll();
  643. addComponent(this, "/xml/luke.xml", null, null);
  644. initPlugins();
  645. }
  646. public void actionCommit() {
  647. if (ir == null) {
  648. showStatus(MSG_NOINDEX);
  649. return;
  650. }
  651. if (readOnly) {
  652. showStatus(MSG_READONLY);
  653. return;
  654. }
  655. if (!IndexGate.hasChanges(ir)) {
  656. showStatus("No changes - commit ignored.");
  657. return;
  658. }
  659. Object dialog = addComponent(this, "/xml/commit.xml", null, null);
  660. Map userData = ir.getCommitUserData();
  661. TreeMap ud = new TreeMap(userData);
  662. putProperty(dialog, "userData", ud);
  663. _showUserData(dialog);
  664. }
  665. private void _showUserData(Object dialog) {
  666. Object table = find(dialog, "data");
  667. removeAll(table);
  668. Map<Object,Object> ud = (Map)getProperty(dialog, "userData");
  669. for (Entry e : ud.entrySet()) {
  670. Object row = create("row");
  671. putProperty(row, "key", e.getKey());
  672. add(table, row);
  673. Object cell = create("cell");
  674. setString(cell, "text", e.getKey().toString());
  675. add(row, cell);
  676. cell = create("cell");
  677. setString(cell, "text", e.getValue().toString());
  678. add(row, cell);
  679. }
  680. }
  681. public void putUserData(Object dialog) {
  682. Object key = find(dialog, "key");
  683. Object value = find(dialog, "value");
  684. String k = getString(key, "text");
  685. String v = getString(value, "text");
  686. if (k.equals("")) {
  687. showStatus("Cannot add empty key.");
  688. return;
  689. }
  690. Map<Object,Object> ud = (Map)getProperty(dialog, "userData");
  691. ud.put(k, v);
  692. _showUserData(dialog);
  693. }
  694. public void deleteUserData(Object dialog) {
  695. Object table = find(dialog, "data");
  696. Map ud = (Map)getProperty(dialog, "userData");
  697. Object[] rows = getSelectedItems(table);
  698. if (rows == null || rows.length == 0) {
  699. return;
  700. }
  701. for (Object row : rows) {
  702. Object key = getProperty(row, "key");
  703. ud.remove(key);
  704. }
  705. _showUserData(dialog);
  706. }
  707. public void commitUserData(Object dialog) {
  708. Map userData = (Map)getProperty(dialog, "userData");
  709. remove(dialog);
  710. try {
  711. ir.flush(userData);
  712. initOverview();
  713. showFiles(dir, Collections.EMPTY_LIST);
  714. } catch (Exception e) {
  715. errorMsg("Error: " + e.toString());
  716. }
  717. }
  718. public void actionReopen() {
  719. if (dir == null) {
  720. return;
  721. }
  722. openIndex(pName, false, dir.getClass().getName(), readOnly, ram,
  723. keepCommits, currentCommit, tiiDiv);
  724. }
  725. /**
  726. * Open indicated index and re-initialize all GUI and plugins.
  727. * @param pName path to index
  728. * @param force if true, and the index is locked, unlock it first. If false, and
  729. * the index is locked, an error will be reported.
  730. * @param readOnly open in read-only mode, and disallow modifications.
  731. */
  732. public void openIndex(String name, boolean force, String dirImpl, boolean ro,
  733. boolean ramdir, boolean keepCommits, IndexCommit point, int tiiDivisor) {
  734. pName = name;
  735. readOnly = ro;
  736. removeAll();
  737. File baseFileDir = new File(name);
  738. this.baseDir = baseFileDir.toString();
  739. addComponent(this, "/xml/luke.xml", null, null);
  740. statmsg = find("statmsg");
  741. if (dir != null) {
  742. try {
  743. if (ir != null) ir.close();
  744. } catch (Exception e) {}
  745. ;
  746. try {
  747. if (dir != null) dir.close();
  748. } catch (Exception e) {}
  749. ;
  750. }
  751. ArrayList<Directory> dirs = new ArrayList<Directory>();
  752. try {
  753. Directory d = openDirectory(dirImpl, pName, false);
  754. if (IndexWriter.isLocked(d)) {
  755. if (ro) {
  756. errorMsg("Index is locked and Read-Only. Open for read-write and 'Force unlock'.");
  757. d.close();
  758. d = null;
  759. return;
  760. }
  761. if (force) {
  762. IndexWriter.unlock(d);
  763. } else {
  764. errorMsg("Index is locked. Try 'Force unlock' when opening.");
  765. d.close();
  766. d = null;
  767. return;
  768. }
  769. }
  770. boolean existsSingle = false;
  771. try {
  772. existsSingle = IndexReader.indexExists(d);
  773. } catch (Exception e) {
  774. //
  775. }
  776. if (!existsSingle) { // try multi
  777. File[] files = baseFileDir.listFiles();
  778. for (File f : files) {
  779. if (f.isFile()) {
  780. continue;
  781. }
  782. Directory d1 = openDirectory(dirImpl, f.toString(), false);
  783. if (IndexWriter.isLocked(d1)) {
  784. if (ro) {
  785. errorMsg("Index is locked and Read-Only. Open for read-write and 'Force unlock'.");
  786. d1.close();
  787. d1 = null;
  788. return;
  789. }
  790. if (force) {
  791. IndexWriter.unlock(d1);
  792. } else {
  793. errorMsg("Index is locked. Try 'Force unlock' when opening.");
  794. d1.close();
  795. d1 = null;
  796. return;
  797. }
  798. }
  799. existsSingle = false;
  800. try {
  801. existsSingle = IndexReader.indexExists(d1);
  802. } catch (Exception e) {};
  803. if (!existsSingle) {
  804. d1.close();
  805. continue;
  806. }
  807. dirs.add(d1);
  808. }
  809. } else {
  810. dirs.add(d);
  811. }
  812. if (dirs.size() == 0) {
  813. errorMsg("No valid directory at the location, try another location.");
  814. return;
  815. }
  816. if (ramdir) {
  817. showStatus("Loading index into RAMDirectory ...");
  818. Directory dir1 = new RAMDirectory();
  819. IndexWriter iw1 = new IndexWriter(dir1, new SimpleAnalyzer(), MaxFieldLength.UNLIMITED);
  820. iw1.addIndexesNoOptimize((Directory[])dirs.toArray(new Directory[dirs.size()]));
  821. iw1.close();
  822. showStatus("RAMDirectory loading done!");
  823. dir.close();
  824. dir = dir1;
  825. }
  826. IndexDeletionPolicy policy;
  827. if (keepCommits) {
  828. policy = new KeepAllIndexDeletionPolicy();
  829. } else {
  830. policy = new KeepLastIndexDeletionPolicy();
  831. }
  832. ArrayList<IndexReader> readers = new ArrayList<IndexReader>();
  833. for (Directory dd : dirs) {
  834. IndexReader reader;
  835. if (tiiDivisor > 1) {
  836. reader = IndexReader.open(dd, policy, ro, tiiDivisor);
  837. } else {
  838. reader = IndexReader.open(dd, policy, ro);
  839. }
  840. readers.add(reader);
  841. }
  842. if (readers.size() == 1) {
  843. ir = readers.get(0);
  844. dir = ir.directory();
  845. } else {
  846. ir = new MultiReader((IndexReader[])readers.toArray(new IndexReader[readers.size()]));
  847. }
  848. is = new IndexSearcher(ir);
  849. // XXX
  850. slowAccess = false;
  851. initOverview();
  852. initPlugins();
  853. showStatus("Index successfully open.");
  854. } catch (Exception e) {
  855. e.printStackTrace();
  856. errorMsg(e.getMessage());
  857. return;
  858. }
  859. }
  860. /**
  861. * Open a single directory.
  862. * @param dirImpl fully-qualified class name of Directory implementation,
  863. * or "FSDirectory" for {@link FSDirectory}
  864. * @param file index directory
  865. * @param create if true, create a new directory
  866. * @return directory implementation
  867. */
  868. Class defaultDirImpl = null;
  869. public Directory openDirectory(String dirImpl, String file, boolean create) throws Exception {
  870. File f = new File(file);
  871. if (!f.exists()) {
  872. throw new Exception("Index directory doesn't exist.");
  873. }
  874. Directory res = null;
  875. if (dirImpl == null || dirImpl.equals(FSDirectory.class.getName())) {
  876. return FSDirectory.open(f);
  877. }
  878. try {
  879. Class implClass = Class.forName(dirImpl);
  880. Constructor<Directory> constr = implClass.getConstructor(File.class);
  881. res = constr.newInstance(f);
  882. } catch (Throwable e) {
  883. errorMsg("Invalid directory implementation class: " + dirImpl + " " + e);
  884. return null;
  885. }
  886. if (res != null) return res;
  887. // fall-back to FSDirectory.
  888. if (res == null) return FSDirectory.open(f);
  889. return null;
  890. }
  891. /**
  892. * Indicates whether I/O access should be optimized because
  893. * the index is on a slow medium (e.g. remote).
  894. * @return true if I/O access is costly and should be minimized
  895. */
  896. public boolean isSlowAccess() {
  897. return slowAccess;
  898. }
  899. /**
  900. * Set whether the I/O access to this index is costly and
  901. * should be minimized.
  902. */
  903. public void setSlowAccess(boolean slowAccess) {
  904. this.slowAccess = slowAccess;
  905. if (slowAccess) {
  906. }
  907. }
  908. /**
  909. * Initialize plugins. This method should always be called when a new index is open.
  910. *
  911. */
  912. public void initPlugins() {
  913. Object pluginsTabs = find("pluginsTabs");
  914. removeAll(pluginsTabs);
  915. for (int i = 0; i < plugins.size(); i++) {
  916. LukePlugin plugin = (LukePlugin) plugins.get(i);
  917. addPluginTab(pluginsTabs, plugin);
  918. plugin.setDirectory(dir);
  919. plugin.setIndexReader(ir);
  920. try {
  921. plugin.init();
  922. } catch (Exception e) {
  923. e.printStackTrace();
  924. showStatus("PLUGIN ERROR: " + e.getMessage());
  925. }
  926. }
  927. }
  928. /**
  929. * Initialize index overview and other GUI elements. This method is called always
  930. * when a new index is open.
  931. *
  932. */
  933. private void initOverview() {
  934. try {
  935. courier = new Font("Courier", getFont().getStyle(), getFont().getSize());
  936. lastST = find("lastST");
  937. setBoolean(find("bReload"), "enabled", true);
  938. setBoolean(find("bClose"), "enabled", true);
  939. setBoolean(find("bCommit"), "enabled", true);
  940. Object cbType = find("cbType");
  941. populateAnalyzers(cbType);
  942. Object pOver = find("pOver");
  943. Object iName = find("idx");
  944. String idxName;
  945. if (pName.length() > 40) {
  946. idxName = pName.substring(0, 10) + "..." + pName.substring(pName.length() - 27);
  947. } else {
  948. idxName = pName;
  949. }
  950. setString(iName, "text", idxName + (readOnly ? " (R)" : ""));
  951. iName = find(pOver, "iName");
  952. setString(iName, "text", pName + (readOnly ? " (Read-Only)" : ""));
  953. Object dirImpl = find("dirImpl");
  954. String implName = "N/A";
  955. if (dir == null) {
  956. if (ir != null) {
  957. implName = "N/A (reader is " + ir.getClass().getName() + ")";
  958. }
  959. } else {
  960. implName = dir.getClass().getName();
  961. }
  962. setString(dirImpl, "text", implName);
  963. Object fileSize = find("iFileSize");
  964. long totalFileSize = Util.calcTotalFileSize(pName, dir);
  965. setString(fileSize, "text", Util.normalizeSize(totalFileSize) + Util.normalizeUnit(totalFileSize));
  966. if (ir == null) {
  967. return;
  968. }
  969. // we need IndexReader from now on
  970. Object iMod = find(pOver, "iMod");
  971. String modText = "N/A";
  972. if (dir != null) {
  973. modText = new Date(IndexReader.lastModified(dir)).toString();
  974. }
  975. setString(iMod, "text", modText);
  976. Object iDocs = find(pOver, "iDocs");
  977. String numdocs = String.valueOf(ir.numDocs());
  978. setString(iDocs, "text", numdocs);
  979. iDocs = find("iDocs1");
  980. setString(iDocs, "text", String.valueOf(ir.maxDoc() - 1));
  981. Object iFields = find(pOver, "iFields");
  982. fn = ir.getFieldNames(IndexReader.FieldOption.ALL);
  983. if (fn.size() == 0) {
  984. showStatus("Empty index.");
  985. }
  986. showFiles(dir, null);
  987. showCommits();
  988. final Object fList = find(pOver, "fList");
  989. final Object defFld = find("defFld");
  990. final Object fCombo = find("fCombo");
  991. TreeSet<String> fields = new TreeSet<String>(fn);
  992. idxFields = (String[])fields.toArray(new String[fields.size()]);
  993. setString(iFields, "text", String.valueOf(idxFields.length));
  994. final Object iTerms = find(pOver, "iTerms");
  995. if (!slowAccess) {
  996. Thread t = new Thread() {
  997. public void run() {
  998. Object r = create("row");
  999. Object cell = create("cell");
  1000. add(r, cell);
  1001. add(fList, r);
  1002. setBoolean(cell, "enabled", false);
  1003. setString(cell, "text", "..wait..");
  1004. termCounts.clear();
  1005. FieldTermCount ftc = null;
  1006. try {
  1007. TermEnum te = ir.terms();
  1008. numTerms = 0;
  1009. while (te.next()) {
  1010. Term currTerm = te.term();
  1011. if (ftc == null) {
  1012. // initialize
  1013. ftc = new FieldTermCount();
  1014. ftc.fieldname = currTerm.field();
  1015. termCounts.put(ftc.fieldname, ftc);
  1016. }
  1017. if (ftc.fieldname == currTerm.field()) {
  1018. ftc.termCount++;
  1019. } else {
  1020. ftc = new FieldTermCount();
  1021. ftc.fieldname = currTerm.field();
  1022. ftc.termCount++;
  1023. termCounts.put(ftc.fieldname, ftc);
  1024. }
  1025. numTerms++;
  1026. }
  1027. te.close();
  1028. setString(iTerms, "text", String.valueOf(numTerms));
  1029. initFieldList(fList, fCombo, defFld);
  1030. } catch (Exception e) {
  1031. showStatus("ERROR: can't count terms per field");
  1032. }
  1033. }
  1034. };
  1035. t.start();
  1036. } else {
  1037. setString(iTerms, "text", "N/A");
  1038. initFieldList(fList, fCombo, defFld);
  1039. }
  1040. Object iDel = find(pOver, "iDelOpt");
  1041. String sDel = ir.hasDeletions() ? "Yes (" + ir.numDeletedDocs() + ")" : "No";
  1042. String sDelOpt = sDel + " / " +
  1043. (ir.isOptimized() ? "Yes" : "No");
  1044. setString(iDel, "text", sDelOpt);
  1045. Object iVer = find(pOver, "iVer");
  1046. String verText = "N/A";
  1047. if (dir != null) {
  1048. verText = Long.toHexString(IndexReader.getCurrentVersion(dir));
  1049. }
  1050. setString(iVer, "text", verText);
  1051. Object iFormat = find(pOver, "iFormat");
  1052. Object iCaps = find(pOver, "iCaps");
  1053. String formatText = "N/A";
  1054. String formatCaps = "N/A";
  1055. if (dir != null) {
  1056. int format = IndexGate.getIndexFormat(dir);
  1057. IndexGate.FormatDetails formatDetails = IndexGate.getFormatDetails(format);
  1058. formatText = format + " (" + formatDetails.genericName + ")";
  1059. formatCaps = formatDetails.capabilities;
  1060. }
  1061. setString(iFormat, "text", formatText);
  1062. setString(iCaps, "text", formatCaps);
  1063. Object iTiiDiv = find(pOver, "iTiiDiv");
  1064. String divText = "N/A";
  1065. // not available in Lucene 3.0
  1066. // try {
  1067. // divText = String.valueOf(ir.getTermInfosIndexDivisor());
  1068. // } catch (UnsupportedOperationException uoe) {
  1069. // }
  1070. setString(iTiiDiv, "text", divText);
  1071. Object iCommit = find(pOver, "iCommit");
  1072. String commitText = "N/A";
  1073. try {
  1074. IndexCommit commit = ir.getIndexCommit();
  1075. commitText = commit.getSegmentsFileName() + " (" +
  1076. new Date(commit.getTimestamp()).toString() + ")";
  1077. } catch (UnsupportedOperationException uoe) {
  1078. }
  1079. setString(iCommit, "text", commitText);
  1080. Object iUser = find(pOver, "iUser");
  1081. String userData = null;
  1082. try {
  1083. Map userDataMap = ir.getCommitUserData();
  1084. if (userDataMap != null && !userDataMap.isEmpty()) {
  1085. userData = ir.getCommitUserData().toString();
  1086. } else {
  1087. userData = "--";
  1088. }
  1089. } catch (UnsupportedOperationException uoe) {
  1090. userData = "(not supported)";
  1091. }
  1092. setString(iUser, "text", userData);
  1093. final Object nTerms = find("nTerms");
  1094. if (!slowAccess) {
  1095. Thread t = new Thread() {
  1096. public void run() {
  1097. actionTopTerms(nTerms);
  1098. }
  1099. };
  1100. t.start();
  1101. }
  1102. } catch (Exception e) {
  1103. e.printStackTrace();
  1104. errorMsg(e.getMessage());
  1105. }
  1106. }
  1107. private void initFieldList(Object fList, Object fCombo, Object defFld) {
  1108. removeAll(fList);
  1109. removeAll(fCombo);
  1110. removeAll(defFld);
  1111. setString(fCombo, "text", idxFields[0]);
  1112. setString(defFld, "text", idxFields[0]);
  1113. NumberFormat intCountFormat = NumberFormat.getIntegerInstance();
  1114. NumberFormat percentFormat = NumberFormat.getNumberInstance();
  1115. intCountFormat.setGroupingUsed(true);
  1116. percentFormat.setMaximumFractionDigits(2);
  1117. // sort by names now
  1118. for (String s : idxFields) {
  1119. Object row = create("row");
  1120. putProperty(row, "fName", s);
  1121. add(fList, row);
  1122. Object cell = create("cell");
  1123. setString(cell, "text", s);
  1124. add(row, cell);
  1125. cell = create("cell");
  1126. FieldTermCount ftc = termCounts.get(s);
  1127. if (ftc != null) {
  1128. long cnt = ftc.termCount;
  1129. setString(cell, "text", intCountFormat.format(cnt));
  1130. setChoice(cell, "alignment", "right");
  1131. add(row, cell);
  1132. float pcent = (float)(cnt * 100) / (float)numTerms;
  1133. cell = create("cell");
  1134. setString(cell, "text", percentFormat.format(pcent) + " %");
  1135. setChoice(cell, "alignment", "right");
  1136. add(row, cell);
  1137. } else {
  1138. setString(cell, "text", "0");
  1139. setChoice(cell, "alignment", "right");
  1140. add(row, cell);
  1141. cell = create("cell");
  1142. setString(cell, "text", "0.00 %");
  1143. setChoice(cell, "alignment", "right");
  1144. add(row, cell);
  1145. }
  1146. cell = create("cell");
  1147. setChoice(cell, "alignment", "right");
  1148. Decoder dec = decoders.get(s);
  1149. if (dec == null) dec = defDecoder;
  1150. setString(cell, "text", dec.toString());
  1151. add(row, cell);
  1152. // populate combos
  1153. Object choice = create("choice");
  1154. add(fCombo, choice);
  1155. setString(choice, "text", s);
  1156. putProperty(choice, "fName", s);
  1157. choice = create("choice");
  1158. add(defFld, choice);
  1159. setString(choice, "text", s);
  1160. putProperty(choice, "fName", s);
  1161. }
  1162. setString(find("defFld"), "text", idxFields[0]);
  1163. // Remove columns
  1164. Object header = get(find("sTable"), "header");
  1165. removeAll(header);
  1166. Object c = create("column");
  1167. setString(c, "text", "#");
  1168. setInteger(c, "width", 40);
  1169. add(header, c);
  1170. c = create("column");
  1171. setString(c, "text", "Score");
  1172. setInteger(c, "width", 50);
  1173. add(header, c);
  1174. c = create("column");
  1175. setString(c, "text", "Doc. Id");
  1176. setInteger(c, "width", 60);
  1177. add(header, c);
  1178. for (int j = 0; j < idxFields.length; j++) {
  1179. c = create("column");
  1180. setString(c, "text", idxFields[j]);
  1181. add(header, c);
  1182. }
  1183. }
  1184. private void showCommits() throws Exception {
  1185. Object commitsTable = find("commitsTable");
  1186. removeAll(commitsTable);
  1187. if (dir == null) {
  1188. Object row = create("row");
  1189. Object cell = create("cell");
  1190. setString(cell, "text", "<not available>");
  1191. setBoolean(cell, "enabled", false);
  1192. add(row, cell);
  1193. add(commitsTable, row);
  1194. return;
  1195. }
  1196. Collection commits = IndexReader.listCommits(dir);
  1197. // commits are ordered from oldest to newest ?
  1198. Iterator it = commits.iterator();
  1199. int rowNum = 0;
  1200. while (it.hasNext()) {
  1201. IndexCommit commit = (IndexCommit)it.next();
  1202. // figure out the name of the segment files
  1203. Collection files = commit.getFileNames();
  1204. Iterator itf = files.iterator();
  1205. Object row = create("row");
  1206. boolean enabled = rowNum < commits.size() - 1;
  1207. Color color = null;
  1208. rowNum++;
  1209. add(commitsTable, row);
  1210. putProperty(row, "commit", commit);
  1211. if (enabled) {
  1212. putProperty(row, "commitDeletable", Boolean.TRUE);
  1213. }
  1214. Object cell = create("cell");
  1215. setString(cell, "text", String.valueOf(commit.getGeneration()));
  1216. add(row, cell);
  1217. cell = create("cell");
  1218. char[] flags = new char[]{'-', '-'};
  1219. if (commit.isDeleted()) flags[0] = 'D';
  1220. if (commit.isOptimized()) flags[1] = 'O';
  1221. setString(cell, "text", new String(flags));
  1222. setFont(cell, "font", courier);
  1223. setChoice(cell, "alignment", "center");
  1224. add(row, cell);
  1225. cell = create("cell");
  1226. setString(cell, "text", Long.toHexString(commit.getVersion()));
  1227. add(row, cell);
  1228. cell = create("cell");
  1229. setString(cell, "text", new Date(commit.getTimestamp()).toString());
  1230. add(row, cell);
  1231. cell = create("cell");
  1232. Map userData = commit.getUserData();
  1233. if (userData != null && !userData.isEmpty()) {
  1234. setString(cell, "text", userData.toString());
  1235. } else {
  1236. setString(cell, "text", "--");
  1237. }
  1238. add(row, cell);
  1239. }
  1240. }
  1241. public void showCommitFiles(Object commitTable) throws Exception {
  1242. List commits = new ArrayList();
  1243. Object[] rows = getSelectedItems(commitTable);
  1244. if (rows == null || rows.length == 0) {
  1245. showFiles(dir, commits);
  1246. return;
  1247. }
  1248. for (int i = 0; i < rows.length; i++) {
  1249. IndexCommit commit = (IndexCommit)getProperty(rows[i], "commit");
  1250. if (commit != null) {
  1251. commits.add(commit);
  1252. }
  1253. }
  1254. showFiles(dir, commits);
  1255. }
  1256. private void showFiles(Directory dir, List commits) throws Exception {
  1257. Object filesTable = find("filesTable");
  1258. if (dir == null) {
  1259. removeAll(filesTable);
  1260. Object row = create("row");
  1261. Object cell = create("cell");
  1262. setString(cell, "text", "<not available>");
  1263. setBoolean(cell, "enabled", false);
  1264. add(row, cell);
  1265. add(filesTable, row);
  1266. return;
  1267. }
  1268. String[] physFiles = dir.listAll();
  1269. List<String> files = new ArrayList();
  1270. if (commits != null && commits.size() > 0) {
  1271. for (int i = 0; i < commits.size(); i++) {
  1272. IndexCommit commit = (IndexCommit)commits.get(i);
  1273. files.addAll(commit.getFileNames());
  1274. }
  1275. } else {
  1276. files.addAll(Arrays.asList(physFiles));
  1277. }
  1278. Collections.sort(files);
  1279. List segs = getIndexFileNames(dir);
  1280. List dels = getIndexDeletableNames(dir);
  1281. removeAll(filesTable);
  1282. for (int i = 0; i < files.size(); i++) {
  1283. String fileName = files.get(i);
  1284. String pathName;
  1285. if (pName.endsWith(File.separator)) {
  1286. pathName = pName;
  1287. } else {
  1288. pathName = pName + File.separator;
  1289. }
  1290. File file = new File(pathName + fileName);
  1291. Object row = create("row");
  1292. Object nameCell = create("cell");
  1293. setString(nameCell, "text", fileName);
  1294. add(row, nameCell);
  1295. Object sizeCell = create("cell");
  1296. setString(sizeCell, "text", Util.normalizeSize(file.length()));
  1297. setChoice(sizeCell, "alignment", "right");
  1298. add(row, sizeCell);
  1299. Object unitCell = create("cell");
  1300. setString(unitCell, "text", Util.normalizeUnit(file.length()));
  1301. add(row, unitCell);
  1302. boolean deletable = dels.contains(fileName.intern());
  1303. String inuse = getFileFunction(fileName);
  1304. Object delCell = create("cell");
  1305. setString(delCell, "text", deletable ? "YES" : "-");
  1306. add(row, delCell);
  1307. Object inuseCell = create("cell");
  1308. setString(inuseCell, "text", inuse);
  1309. add(row, inuseCell);
  1310. add(filesTable, row);
  1311. }
  1312. }
  1313. private String getFileFunction(String file) {
  1314. String res = IndexGate.getFileFunction(file);
  1315. if (res == null) {
  1316. res = "YES";
  1317. }
  1318. return res;
  1319. }
  1320. private void syncMRU(Object path) {
  1321. removeAll(path);
  1322. for (Iterator iter = Prefs.getMruList().iterator(); iter.hasNext();) {
  1323. String element = (String) iter.next();
  1324. Object choice = create("choice");
  1325. setString(choice, "text", element);
  1326. add(path, choice);
  1327. }
  1328. }
  1329. /**
  1330. * Update the list of top terms.
  1331. * @param nTerms Thinlet widget containing the number of top terms to show
  1332. */
  1333. public void actionTopTerms(Object nTerms) {
  1334. if (ir == null) {
  1335. showStatus(MSG_NOINDEX);
  1336. return;
  1337. }
  1338. String sndoc = getString(nTerms, "text");
  1339. int nd = 50;
  1340. try {
  1341. nd = Integer.parseInt(sndoc);
  1342. } catch (Exception e) {}
  1343. final int ndoc = nd;
  1344. Object[] fields = getSelectedItems(find("fList"));
  1345. String[] flds = null;
  1346. if (fields == null || fields.length == 0) {
  1347. flds = idxFields;
  1348. } else {
  1349. flds = new String[fields.length];
  1350. for (int i = 0; i < fields.length; i++) {
  1351. flds[i] = (String) getProperty(fields[i], "fName");
  1352. }
  1353. }
  1354. final String[] fflds = flds;
  1355. SlowThread st = new SlowThread(this) {
  1356. public void execute() {
  1357. try {
  1358. TermInfo[] tis = HighFreqTerms.getHighFreqTerms(ir, null, ndoc + 1, fflds);
  1359. Object table = find("tTable");
  1360. removeAll(table);
  1361. if (tis == null || tis.length == 0) {
  1362. Object row = create("row");
  1363. Object cell = create("cell");
  1364. add(row, cell);
  1365. cell = create("cell");
  1366. add(row, cell);
  1367. cell = create("cell");
  1368. add(row, cell);
  1369. cell = create("cell");
  1370. setBoolean(cell, "enabled", false);
  1371. setString(cell, "text", "No Results");
  1372. add(row, cell);
  1373. add(table, row);
  1374. return;
  1375. }
  1376. for (int i = 0; i < tis.length; i++) {
  1377. Object row = create("row");
  1378. add(table, row);
  1379. putProperty(row, "term", tis[i].term);
  1380. putProperty(row, "ti", tis[i]);
  1381. Object cell = create("cell");
  1382. setChoice(cell, "alignment", "right");
  1383. setString(cell, "text", String.valueOf(i + 1));
  1384. add(row, cell);
  1385. cell = create("cell");
  1386. setChoice(cell, "alignment", "right");
  1387. setString(cell, "text", String.valueOf(tis[i].docFreq) + " ");
  1388. add(row, cell);
  1389. cell = create("cell");
  1390. setString(cell, "text", tis[i].term.field());
  1391. add(row, cell);
  1392. cell = create("cell");
  1393. Decoder dec = decoders.get(tis[i].term.field());
  1394. if (dec == null) dec = defDecoder;
  1395. String s;
  1396. try {
  1397. s = dec.decodeTerm(tis[i].term.field(), tis[i].term.text());
  1398. } catch (Throwable e) {
  1399. s = tis[i].term.text();
  1400. setColor(cell, "foreground", Color.RED);
  1401. }
  1402. setString(cell, "text", " " + s);
  1403. add(row, cell);
  1404. }
  1405. } catch (Exception e) {
  1406. e.printStackTrace();
  1407. errorMsg(e.getMessage());
  1408. }
  1409. }
  1410. };
  1411. if (slowAccess) {
  1412. st.start();
  1413. } else {
  1414. st.execute();
  1415. }
  1416. }
  1417. public void clipTopTerms(Object tTable) {
  1418. Object[] rows = getItems(tTable);
  1419. StringBuffer sb = new StringBuffer();
  1420. for (int i = 0; i < rows.length; i++) {
  1421. TermInfo ti = (Term