/* * Source: Adam Perer Major revision made by Yejun Wu in April, 2005 * * This version tries to remove duplicates in a thread */ package edu.umd.email; import java.awt.AWTEvent; import java.awt.BorderLayout; import java.awt.Dimension; import java.awt.FlowLayout; import java.awt.Toolkit; import java.awt.datatransfer.Clipboard; import java.awt.datatransfer.StringSelection; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.io.BufferedReader; import java.io.File; import java.io.FileReader; //import java.util.ArrayList; //import java.util.TreeSet; //import java.util.Comparator; import java.util.*; import javax.swing.BorderFactory; import javax.swing.Box; import javax.swing.BoxLayout; import javax.swing.JButton; import javax.swing.JCheckBox; import javax.swing.JComboBox; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JMenuItem; import javax.swing.JPanel; import javax.swing.JPopupMenu; import javax.swing.JRadioButton; import javax.swing.JScrollPane; import javax.swing.JSplitPane; import javax.swing.JTextArea; import javax.swing.JTextField; import javax.swing.JTree; import javax.swing.border.Border; import javax.swing.border.EtchedBorder; import javax.swing.border.TitledBorder; import javax.swing.event.TreeSelectionEvent; import javax.swing.event.TreeSelectionListener; import javax.swing.tree.DefaultMutableTreeNode; import javax.swing.tree.DefaultTreeModel; import javax.swing.tree.TreeSelectionModel; import org.apache.lucene.analysis.Analyzer; import org.apache.lucene.document.DateField; import org.apache.lucene.document.Document; import org.apache.lucene.index.Term; import org.apache.lucene.queryParser.QueryParser; import org.apache.lucene.search.BooleanQuery; import org.apache.lucene.search.Hits; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Query; import org.apache.lucene.search.TermQuery; import edu.umd.email.enron.EmailAnalyzer; public class SearchDeDup extends JFrame { private static final int MAXHITS = 100; private int defaultNumHits = MAXHITS; //getContentPane() has 2 panes with BorderLayout // topPane (consisting of: listPane, fromPaneParent, toPaneParent, // subjectPane, textPane); // bottomSplitPane(consisting of treePane and bodyTextPane). private JComboBox collectionBox; private JTextField hitsInput; private JTextField fromAddressInput, toAddressInput, fromNameInput, toNameInput, subjectInput; private JTextArea bodyInput, output, bodyTextArea; private JButton search, reset, search2; private JRadioButton enronButton, w3cButton; private JScrollPane treePane, bodyTextPane; private JScrollPane outputPane, inputPane, fromAddressInputPane; private JScrollPane toAddressInputPane, subjectInputPane, fromNameInputPane; private JScrollPane toNameInputPane, listScrollPane; private JPanel fromPaneParent, toPaneParent; private JPanel topPane, fromPane, textPane, toPane, subjectPane, listPane, fromToPane; private JSplitPane bottomSplitPane; //load treePane and bodyTextPane private JCheckBox threadCheckBox; private DefaultTreeModel model; private JTree tree; private DefaultMutableTreeNode root, group; private IndexSearcher searcher; private Analyzer analyzer, threadAnalyzer; private String answerText = ""; private static int lastHit = -1; private static int lastHit2 = -1; private static String lastSearch = ""; private static String lastSearch2 = ""; private Hits hits = null; private Hits hits2 = null; private int start, end, top; private String[] collectionWords = { "Enron", "W3C" }; private String mySelection = ""; //private Vector seen = new Vector(); JPopupMenu popup; public static void main(String args[]) { SearchDeDup search = new SearchDeDup(); //search.createPopupMenu(); search.show(); //new Search().show(); } private void exitForm(java.awt.event.WindowEvent evt) { System.exit(0); } public SearchDeDup() { getContentPane().setLayout(new BorderLayout(3, 3));//horizontal and // vertical gaps // between components setTitle("Email Archive Explorer"); addWindowListener(new java.awt.event.WindowAdapter() { public void windowClosing(java.awt.event.WindowEvent evt) { exitForm(evt); } }); topPane = new JPanel(); //topPane.setLayout(new GridLayout(5, 1));//rows, cols //There is no space between components in a BoxLayout topPane.setLayout(new BoxLayout(topPane, BoxLayout.Y_AXIS)); listPane = new JPanel(); listPane.setLayout(new FlowLayout(FlowLayout.LEFT)); //fromPaneParent: to hold fromPane with a titled border fromPaneParent = new JPanel(); fromPaneParent.setLayout(new FlowLayout(FlowLayout.LEFT)); //toPaneParent: to hold toPane with a titled border toPaneParent = new JPanel(); toPaneParent.setLayout(new FlowLayout(FlowLayout.LEFT)); fromPane = new JPanel(); fromPane.setLayout(new FlowLayout(FlowLayout.LEFT));//FlowLayout.LEFT //fromPane.setLayout(new BoxLayout(fromPane, BoxLayout.X_AXIS)); //fromPane.setAlignmentX(JPanel.LEFT_ALIGNMENT); toPane = new JPanel(); toPane.setLayout(new FlowLayout(FlowLayout.LEFT)); //toPane.setAlignmentX(JPanel.LEFT_ALIGNMENT); fromToPane = new JPanel(); fromToPane.setLayout(new FlowLayout(FlowLayout.LEFT)); textPane = new JPanel(); textPane.setLayout(new FlowLayout(FlowLayout.LEFT)); subjectPane = new JPanel(); subjectPane.setLayout(new FlowLayout(FlowLayout.LEFT)); listPane.add(new JLabel("Select Collection: ")); collectionBox = new JComboBox(collectionWords); MyComboListener comboListener = new MyComboListener(collectionBox); collectionBox.addActionListener(comboListener); listPane.add(collectionBox); listPane.add(Box.createRigidArea(new Dimension(20, 0))); //filler listPane.add(new JLabel("Show max number of hits: ")); hitsInput = new JTextField("100", 4); //default hits: 100, width = 5 listPane.add(hitsInput); listPane.add(Box.createRigidArea(new Dimension(20, 0))); //filler threadCheckBox = new JCheckBox("Retrieve threads"); listPane.add(threadCheckBox); listPane.add(new JLabel("(can be time-costly)")); Dimension size = new Dimension(420, 62);//width, height for fromPane // and toPane Dimension maxsize = new Dimension(420, 65); fromPane.setMaximumSize(maxsize); fromPane.setPreferredSize(size); fromPane.setMinimumSize(size); toPane.setMaximumSize(size); toPane.setPreferredSize(size); toPane.setMinimumSize(size); fromPane.add(new JLabel("Address:")); fromAddressInput = new JTextField(14); fromPane.add(fromAddressInput); //use invisible components as filler fromPane.add(Box.createRigidArea(new Dimension(2, 0))); fromPane.add(new JLabel("Name:")); fromNameInput = new JTextField(10); fromPane.add(fromNameInput); //see: http://java.sun.com/docs/books/tutorial/uiswing/misc/border.html Border loweredetched, blackline; loweredetched = BorderFactory.createEtchedBorder(EtchedBorder.LOWERED); TitledBorder fromTitledBorder = BorderFactory.createTitledBorder( loweredetched, "From"); fromPane.setBorder(BorderFactory.createTitledBorder(fromTitledBorder)); fromPaneParent.add(fromPane); fromToPane.add(fromPaneParent); toPane.add(new JLabel("Address:")); toAddressInput = new JTextField(14); toPane.add(toAddressInput); //use invisible components as filler toPane.add(Box.createRigidArea(new Dimension(2, 0))); toPane.add(new JLabel("Name:")); toNameInput = new JTextField(10); toPane.add(toNameInput); TitledBorder toTitledBorder = BorderFactory.createTitledBorder( loweredetched, "To"); toPane.setBorder(BorderFactory.createTitledBorder(toTitledBorder)); toPaneParent.add(toPane); fromToPane.add(toPaneParent); subjectPane.add(new JLabel("Subject:")); //use invisible components as filler subjectPane.add(Box.createRigidArea(new Dimension(10, 0))); subjectInput = new JTextField(20); subjectPane.add(subjectInput); subjectPane .add(new JLabel("(Note: A subject query is case sensitive)")); textPane.add(new JLabel("Body Text: ")); bodyInput = new JTextArea(2, 50); //2 rows, 50 cols bodyInput.setLineWrap(true); bodyInput.setWrapStyleWord(true); bodyInput.setEditable(true); inputPane = new JScrollPane(); inputPane.setViewportView(bodyInput); textPane.add(inputPane); search = new JButton(); search.setText("Search"); search.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { searchActionPerformed(evt); } }); textPane.add(search); reset = new JButton(); reset.setText("Reset"); reset.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { resetActionPerformed(evt); } }); textPane.add(reset); topPane.add(listPane); topPane.add(fromToPane); topPane.add(subjectPane); topPane.add(textPane); getContentPane().add(topPane, BorderLayout.NORTH); //construct tree root = new DefaultMutableTreeNode("Emails"); //root.setUserObject("test"); //changes root label group = new DefaultMutableTreeNode("Group"); //root.insert(group, 0); model = new DefaultTreeModel(root); tree = new JTree(model); //add scroll pane with tree to content pane treePane = new JScrollPane(tree); //getContentPane().add(treePane, BorderLayout.CENTER); bodyTextArea = new JTextArea(8, 80); bodyTextArea.setLineWrap(true); bodyTextArea.setWrapStyleWord(true); bodyTextArea.setEditable(false); bodyTextPane = new JScrollPane(); bodyTextPane.setViewportView(bodyTextArea); //textPane.add(bodyTextPane); //getContentPane().add(bodyTextPane, BorderLayout.SOUTH); JMenuItem menuItem; //Create the popup menu. popup = new JPopupMenu(); enableEvents(AWTEvent.MOUSE_EVENT_MASK); menuItem = new JMenuItem("Copy Message"); menuItem.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { String cmd = e.getActionCommand(); //The getActionCommand method of ActionEvent returns the label // of the MenuItem. System.out.println(e.getActionCommand()); System.out.println("plan to copy"); //JMenuItem source = (JMenuItem)(e.getSource()); Clipboard cb = Toolkit.getDefaultToolkit().getSystemClipboard(); String s = bodyTextArea.getText(); StringSelection contents = new StringSelection(s); cb.setContents(contents, null); } }); popup.add(menuItem); //Add a listener to bodyTextArea to display pop-up bodyTextArea.addMouseListener(new MouseAdapter() { public void mousePressed(MouseEvent evt) { if (evt.isPopupTrigger()) { popup.show(evt.getComponent(), evt.getX(), evt.getY()); } } public void mouseReleased(MouseEvent evt) { if (evt.isPopupTrigger()) { popup.show(evt.getComponent(), evt.getX(), evt.getY()); } } }); bottomSplitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT, treePane, bodyTextPane); //bottomSplitPane.setOneTouchExpandable(true);//completely expand bottomSplitPane.setDividerLocation(300); getContentPane().add(bottomSplitPane, BorderLayout.CENTER); pack(); int mode = TreeSelectionModel.SINGLE_TREE_SELECTION; tree.getSelectionModel().setSelectionMode(mode); //Listen for when the selection changes. tree.addTreeSelectionListener(new TreeSelectionListener() { public void valueChanged(TreeSelectionEvent e) { DefaultMutableTreeNode node = (DefaultMutableTreeNode) tree .getLastSelectedPathComponent(); if (node == null) return; Object nodeInfo = node.getUserObject(); //if (node.isLeaf()) { //System.out.println("inside addTreeSelectionListener"); String metadata = (String) nodeInfo; //if (metadata.startsWith("FOLDER: ")){ //xxx; int folderStart = metadata.indexOf("FOLDER: "); String fileName = metadata.substring(folderStart + 8, metadata .length() - 1); //String fileName = metadata.substring(8); String wholeDocument = ""; if (fileName.indexOf(";") == -1) {//semicolon does not occur System.out.println("reading =" + fileName + "="); try { File theFile = new File(fileName); FileReader fileReader = new FileReader(theFile); BufferedReader reader = new BufferedReader(fileReader); String line = null; while ((line = reader.readLine()) != null) { wholeDocument += line + "\n"; } reader.close(); } catch (Exception ex) { ex.printStackTrace(); } } else { StringTokenizer folderParser = new StringTokenizer(fileName, ";"); while (folderParser.hasMoreTokens()){ String aFileName = folderParser.nextToken(); try { File aFile = new File(aFileName); FileReader fReader = new FileReader(aFile); BufferedReader aReader = new BufferedReader(fReader); String aLine = null; while ((aLine = aReader.readLine()) != null){ wholeDocument += aLine + "\n"; } aReader.close(); wholeDocument += "----------------------------------------------------------\n"; }catch (Exception ex) { ex.printStackTrace(); }//end try }//end while }//end else bodyTextArea.setText(wholeDocument); //} else // bodyTextArea.setText(metadata); //} }//end public void... }); //SelectColl4Search();//this does not work. actionPerformed effect // delayed }//end Search() /** * Don't use a MouseListener, since in Win95/NT you have to check * isPopupTrigger in mouseReleased, but do it in mousePressed in Solaris * (boo!). * * This method is required to make the popup menu, if any, pop up. It uses * the low-level Java 1.1 event handling mechanism to test all mouse events * (except mouse motion events) to see if they are the platform- dependent * popup menu trigger. If so, it calls show() to pop the popup up. If not, * it passes the event to the superclass version of this method so that it * is dispatched as usual and can be passed to the listener object * registered by the init method for scribbling. */ public void processMouseEvent(MouseEvent event) { if (popup != null && event.isPopupTrigger()) { popup.show(event.getComponent(), event.getX(), event.getY()); System.out.println("show popup menu"); } super.processMouseEvent(event); } //select a collection to search public void SelectColl4Search() { try { if (mySelection.equals("Enron")) { searcher = new IndexSearcher("indexes/enron"); //searcher = new IndexSearcher("C:/Eclipse/umdex_v1.00/indexes/enron"); System.out.println("searching in enron"); } else if (mySelection.equals("W3C")) { searcher = new IndexSearcher("indexes/w3c"); System.out.println("searching in w3c"); } analyzer = new EmailAnalyzer(); //initialize analyzer threadAnalyzer = new EmailAnalyzer(); //initialize analyzer System.out.println("Index opened with " + searcher.maxDoc() + " documents."); } catch (Exception e) { System.out.println("when getting a searcher, caught a " + e.getClass() + "\n with message: " + e.getMessage()); } }//end Search() class MyComboListener implements ActionListener { JComboBox combo; Object currentItem; MyComboListener(JComboBox combo) { this.combo = combo; //combo.setSelectedIndex(0); //preselect "Enron" currentItem = combo.getSelectedItem(); mySelection = (String) currentItem; } public void actionPerformed(ActionEvent e) { Object tempItem = combo.getSelectedItem(); currentItem = tempItem; combo.setSelectedItem(currentItem); mySelection = (String) currentItem; //System.out.println("actionperformed! currentItem is "+ // (String)currentItem); } public Object getCurrentItem() { //System.out.println("returning currentItem: " + // (String)currentItem); return currentItem; } } //reset everything to its original state private void resetActionPerformed(java.awt.event.ActionEvent evt) { bodyInput.setText(""); fromAddressInput.setText(""); toAddressInput.setText(""); subjectInput.setText(""); fromNameInput.setText(""); toNameInput.setText(""); bodyTextArea.setText(""); //enronButton.setSelected(true); //w3cButton.setSelected(false); collectionBox.setSelectedIndex(0); hitsInput.setText("100"); threadCheckBox.setSelected(false); hits = null; root.setUserObject("Emails"); addHitsToTree(hits); treePane.remove(tree); tree.updateUI(); } //actions performed when the "Search" button is clicked private void searchActionPerformed(java.awt.event.ActionEvent evt) { System.out.println("SearchActionPerformed!"); SelectColl4Search(); if (!hitsInput.getText().equals("")) { defaultNumHits = Integer.parseInt(hitsInput.getText()); } //System.out.println("max num of hits to show = " + defaultNumHits); //Note: if nothing is input into a query box, input.getText() is an // empty string, //i.e., a "" string rather than a null. //query.toString() usually brings its field name with it, such as // "contents:" //If inputText()=="", QueryParse throws an exception bodyTextArea.setText("");//whenever "Search" is clicked, remove // anything in "bodyTextArea" boolean fromAddressQueryEmpty = true, fromNameQueryEmpty = true; boolean toAddressQueryEmpty = true, toNameQueryEmpty = true; boolean subjectQueryEmpty = true, bodyQueryEmpty = true; try { BooleanQuery boolQuery = new BooleanQuery(); Query fromAddressQuery = null, bodyQuery = null, finalQuery = null; Query fromNameQuery = null, toAddressQuery = null, toNameQuery = null; Query subjectQuery = null; if (!fromAddressInput.getText().equals("")) { fromAddressQueryEmpty = false; fromAddressQuery = new TermQuery(new Term("fromAddress", fromAddressInput.getText())); } if (!fromNameInput.getText().equals("")) { fromNameQueryEmpty = false; fromNameQuery = QueryParser.parse(fromNameInput.getText(), "fromName", analyzer); } if (!toAddressInput.getText().equals("")) { toAddressQueryEmpty = false; toAddressQuery = new TermQuery(new Term("toAddress", toAddressInput.getText())); } if (!toNameInput.getText().equals("")) { toNameQueryEmpty = false; toNameQuery = QueryParser.parse(toNameInput.getText(), "toName", analyzer); } //System.out.println("subjectInput.getText()= " + "=" + // subjectInput.getText()+"="); if (!subjectInput.getText().equals("")) { subjectQueryEmpty = false; subjectQuery = QueryParser.parse(subjectInput.getText(), "subject", analyzer); } //System.out.println("bodyInput.getText() = " + "=" + // bodyInput.getText() + "="); if (!bodyInput.getText().equals("")) { bodyQueryEmpty = false; bodyQuery = QueryParser.parse(bodyInput.getText(), "contents", analyzer); } if (fromAddressQueryEmpty && fromNameQueryEmpty && toAddressQueryEmpty && toNameQueryEmpty && subjectQueryEmpty && bodyQueryEmpty) { bodyTextArea.setText("Warning: empty queries!"); } else if (!fromAddressQueryEmpty && fromNameQueryEmpty && toAddressQueryEmpty && toNameQueryEmpty && subjectQueryEmpty && bodyQueryEmpty) { hits = searcher.search(fromAddressQuery); //System.out.println("executing fromAddressQuery: "+ // fromAddressQuery.toString()); //System.out.println("hits="+hits.length()); } else if (fromAddressQueryEmpty && !fromNameQueryEmpty && toAddressQueryEmpty && toNameQueryEmpty && subjectQueryEmpty && bodyQueryEmpty) { hits = searcher.search(fromNameQuery); //System.out.println("executing fromNameQuery: // "+fromNameQuery.toString()); //System.out.println("hits="+hits.length()); } else if (fromAddressQueryEmpty && fromNameQueryEmpty && !toAddressQueryEmpty && toNameQueryEmpty && subjectQueryEmpty && bodyQueryEmpty) { hits = searcher.search(toAddressQuery); //System.out.println("executing toAddressQuery: // "+toAddressQuery.toString()); //System.out.println("hits="+hits.length()); } else if (fromAddressQueryEmpty && fromNameQueryEmpty && toAddressQueryEmpty && !toNameQueryEmpty && subjectQueryEmpty && bodyQueryEmpty) { hits = searcher.search(toNameQuery); //System.out.println("executing toNameQuery: // "+toNameQuery.toString()); //System.out.println("hits="+hits.length()); } else if (fromAddressQueryEmpty && fromNameQueryEmpty && toAddressQueryEmpty && toNameQueryEmpty && !subjectQueryEmpty && bodyQueryEmpty) { hits = searcher.search(subjectQuery); //System.out.println("executing subjectQuery: // "+subjectQuery.toString()); //System.out.println("hits="+hits.length()); } else if (fromAddressQueryEmpty && fromNameQueryEmpty && toAddressQueryEmpty && toNameQueryEmpty && subjectQueryEmpty && !bodyQueryEmpty) { hits = searcher.search(bodyQuery); //System.out.println("executing bodyQuery: " + // bodyQuery.toString()); //System.out.println("hits="+hits.length()); } else {//compose a boolean query if (!fromAddressQueryEmpty) boolQuery.add(fromAddressQuery, true, false); if (!fromNameQueryEmpty) boolQuery.add(fromNameQuery, true, false); if (!toAddressQueryEmpty) boolQuery.add(toAddressQuery, true, false); if (!toNameQueryEmpty) boolQuery.add(toNameQuery, true, false); if (!subjectQueryEmpty) boolQuery.add(subjectQuery, true, false); if (!bodyQueryEmpty) boolQuery.add(bodyQuery, true, false); hits = searcher.search(boolQuery); //System.out.println("executing boolQuery: " + // boolQuery.toString()); //System.out.println("hits=" + hits.length()); } //change root label from "Emails" to number of "Emails Retrieved": root.setUserObject(hits.length() + " Emails Retrieved"); if (threadCheckBox.isSelected()) addHitsToTree(hits); else addHitsSimply(hits); } catch (Exception e) { System.out.println(" inside SearchActionPerformed: caught a " + e.getClass() + "\n with message: " + e.getMessage()); e.printStackTrace(); } } //present the hits in a JTree, but not in threads void addHitsSimply(Hits hits) { //clean the tree Hits h = null; addHitsToTree(h); treePane.remove(tree); tree.updateUI(); try { for (int i = 0; (i < hits.length()) && (i < defaultNumHits); i++) { org.apache.lucene.document.Document doc = hits.doc(i); //doc.get("date") is a strange String like 0bwma9ncg. //Lucene's DateField String date = DateField.stringToDate(doc.get("date")).toString(); //System.out.println("doc.getdate: " + doc.get("date")); String subject = doc.get("subject"); // Hack to remove any quotes that appear in the subject line subject = subject.replaceAll("\\\"", ""); subject = "\"" + subject + "\""; //plan to make a phrase query //System.out.println("Node: " + line + " subject: " + subject); // Hack to protect against a zero-length subject line if (subject.length() <= 2) { subject = "\"<>\""; } DefaultMutableTreeNode emailNode = new DefaultMutableTreeNode( (i + 1) + "--" + subject + " [FROM: " + "\n" + doc.get("fromAddress") + " (" + doc.get("fromName") + ")] ----" + date + " ----[FOLDER: " + doc.get("folder") + "]"); root.add(emailNode); }//end for tree.updateUI(); } catch (Exception e) { System.out.println("inside AddHitsSimply: caught a " + e.getClass() + "\n with message: " + e.getMessage()); //return "ERROR!\n"; e.printStackTrace(); } } //present the hits in a JTree and in threads void addHitsToTree(Hits hits) { try { String answer = ""; TreeSet threadDocDeDupSet; root.removeAllChildren(); //if (hits.length()==0) //bodyTextArea.setText(""); int line = 0; for (int i = 0; (i < hits.length()) && (i < defaultNumHits); i++) { DefaultMutableTreeNode emailNode, textNode; org.apache.lucene.document.Document doc = hits.doc(i); //doc.get("date") is a strange String like 0bwma9ncg. String date = DateField.stringToDate(doc.get("date")) .toString(); //added 6/6/05 for identifying the leading email for a thread //String fromAddr = doc.get("fromAddress"); String subject = doc.get("subject"); // Hack to remove any quotes that appear in the subject line subject = subject.replaceAll("\\\"", ""); subject = "\"" + subject + "\""; //plan to make a phrase query // Hack to protect against a zero-length subject line if (subject.length() <= 2) { subject = "\"<>\""; } Query subjectQuery = QueryParser.parse(subject, "subject", threadAnalyzer); Hits threadHits = searcher.search(subjectQuery); //for this doc, get a thread that does not include any duplicates threadDocDeDupSet = deDuplicate(doc, threadHits); //"threadHits.length() == 0" happens when no threads found, in the case //of empty subject line. if (threadHits.length() == 0 || threadDocDeDupSet.size() == 1) { //DefaultMutableTreeNode(Object userObject): //Creates a tree node with no parent, no children, but // which allows children, //and initializes it with the specified user object. emailNode = new DefaultMutableTreeNode((i + 1) + "--" + "(" + 1 + ") " + subject + " [FROM: " + "\n" + doc.get("fromAddress") + " (" + doc.get("fromName") + ")] ----" + date + " ----[FOLDER: " + doc.get("folder") + "]"); //syntax: insert(MutableTreeNode newChild, int childIndex). //Removes newChild from its present parent (if it has a // parent), sets the //child's parent to this node, and then adds the child to // this node's child //array at index childIndex. } else { emailNode = new DefaultMutableTreeNode((i + 1) + "--" + "(" + threadDocDeDupSet.size() + ") " + subject + " [FROM: " + doc.get("fromAddress") + " (" + doc.get("fromName") + ")] ----" + date + " ----[FOLDER: " + doc.get("folder") + "]"); /*** emailNode = new DefaultMutableTreeNode((i + 1) + "--" + "(" + threadHits.length() + ") " + subject + " [FROM: " + doc.get("fromAddress") + " (" + doc.get("fromName") + ")] ----" + date + " ----[FOLDER: " + doc.get("folder") + "]"); ***/ }//end else //if threadDocDeDupSet.size() > 1, do the following: if (threadDocDeDupSet.size() > 1){ int threadCount = 0; String threadFolderStr = ""; //iterate through the TreeSet Iterator iter = threadDocDeDupSet.iterator(); while (iter.hasNext()){ Document threadDoc = (Document)iter.next(); String threadDate = DateField.stringToDate( threadDoc.get("date")).toString(); threadFolderStr += threadDoc.get("folder") + ";" ; if (compare2Documents(threadDoc, doc) == false){ int k = ++threadCount; DefaultMutableTreeNode threadNode = new DefaultMutableTreeNode( k + ". " + threadDoc.get("subject") + " [FROM: " + threadDoc.get("fromAddress") + " (" + threadDoc.get("fromName") + ")] ----" + threadDate + " ----[FOLDER: " + threadDoc.get("folder") + "]"); emailNode.add(threadNode); } else ++threadCount; }//end while //add one more node for "printing thread" threadFolderStr = "Print Thread [FOLDER: " + threadFolderStr; //remove the final semicolon int indexOfLastSemiColon = threadFolderStr.lastIndexOf(";"); threadFolderStr = threadFolderStr.substring(0, indexOfLastSemiColon) + "]" ; DefaultMutableTreeNode printThreadNode = new DefaultMutableTreeNode( threadFolderStr); emailNode.add(printThreadNode); }//end if (threadDocDeDupSet.size() > 1 /****** // //if threadHits.length()>0, do the following: // int threadCount = 0; int indexOfEmailInThread = 0; //locate the email (in the threads) that has already been presented on // the top of thread for (int m = 0; m < threadHits.length(); m++) { org.apache.lucene.document.Document threadDoc = threadHits .doc(m); String threadDate = DateField.stringToDate( threadDoc.get("date")).toString(); if (date.equals(threadDate)) { //locate an email with the same date indexOfEmailInThread = m; break; }//end if }//end for for (int j = 0; j < threadHits.length(); j++) { org.apache.lucene.document.Document threadDoc = threadHits.doc(j); String threadDate = DateField.stringToDate( threadDoc.get("date")).toString(); if (j != indexOfEmailInThread) { int k = j + 1; DefaultMutableTreeNode threadNode = new DefaultMutableTreeNode( k + ". " + threadDoc.get("subject") + " [FROM: " + threadDoc.get("fromAddress") + " (" + threadDoc.get("fromName") + ")] ----" + threadDate + " ----[FOLDER: " + threadDoc.get("folder") + "]"); emailNode.add(threadNode); }//end else }//end for (int j=0; j " + doc.get("toAddress") + " (" + doc.get("toName") + ")\n" + "Subj: " + doc.get("subject") + "\n-----\n"; //+ doc.get("text"); }//end for return answer; } catch (Exception e) { System.out.println("inside RankEmailSearch: caught a " + e.getClass() + "\n with message: " + e.getMessage()); return "ERROR!\n"; }//end try }//end RankEmailSearch //get first dozens of words (about 100-ish chars) from a wholeString //This method is not used in this program. String getSurrogate(String wholeString) { int index = 100; if (wholeString.length() <= index + 1) return wholeString; else { char ch = wholeString.charAt(index); //while (ch != ' ' && ch != '\0'){ while (ch != ' ' && index > 1) { index--; ch = wholeString.charAt(index); } return wholeString.substring(0, index + 1) + "..."; } } }