--- src/org/netbeans/modules/search/Bundle.properties +++ src/org/netbeans/modules/search/Bundle.properties @@ -71,6 +71,10 @@ TEXT_BUTTON_FILL=Show A&ll Details ACS_TEXT_BUTTON_FILL=Displays links to all found occurences of the pattern to the Output Window TEXT_ACTION_SEARCH_RESULTS=&Search Results +TEXT_BUTTON_SORT=\ Sort b&y Name +ACS_TEXT_BUTTON_SORT=Sorts found files by name +TEXT_BUTTON_UNSORT=\ Do &Not Sort +ACS_TEXT_BUTTON_UNSORT=Displays found files in a random order ACSN_Tabs=Each tab contains different search criterion ACSD_Tabs=N/A --- src/org/netbeans/modules/search/ResultTreeModel.java +++ src/org/netbeans/modules/search/ResultTreeModel.java @@ -43,6 +43,8 @@ import java.awt.EventQueue; import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; import java.util.List; import javax.swing.event.TreeModelEvent; import javax.swing.event.TreeModelListener; @@ -71,6 +73,10 @@ private int selectedObjectsCount; /** */ private List treeModelListeners; + /** */ + private boolean sorted; + /** */ + private List sortedMatchingObjects = new ArrayList(); /** * @@ -103,7 +109,7 @@ } else { try { //PENDING - threading: - ret = resultModel.matchingObjects.get(index); + ret = getSortedMatchingObjects().get(index); } catch (ArrayIndexOutOfBoundsException ex) { assert false; ret = null; @@ -190,7 +196,7 @@ int ret; if (parent == getRoot()) { ret = (child.getClass() == MatchingObject.class) - ? resultModel.matchingObjects.indexOf(child) + ? getSortedMatchingObjects().indexOf(child) : -1; } else { ret = -1; @@ -273,6 +279,25 @@ UPDATE_NAME_TASK.run(); //fireRootNodeChanged(); } + void setSorted(boolean sorted) { + this.sorted = sorted; + final List matchingObjects = resultModel.matchingObjects; + if (sorted && !sortedMatchingObjects.containsAll(matchingObjects)) { + sortedMatchingObjects.clear(); + sortedMatchingObjects.addAll(matchingObjects); + Collections.sort(sortedMatchingObjects, new Comparator() { + public int compare(MatchingObject o1, MatchingObject o2) { + return o1.getName().compareToIgnoreCase(o2.getName()); + } + }); + } + UPDATE_SORTED_CHILDREN_TASK.run(); + } + + private List getSortedMatchingObjects() { + return sorted ? sortedMatchingObjects : resultModel.matchingObjects; + } + /** */ boolean isSelected() { @@ -293,24 +318,35 @@ } private final Task UPDATE_NAME_TASK = new Task(); + private final Task UPDATE_SORTED_CHILDREN_TASK = new Task(true); + /** * Single class for sending various asynchronous tasks to the event queue. */ private final class Task implements Runnable { private final MatchingObject foundObject; private final int foundObjectIndex; + private final boolean refreshChildren; private Task() { this.foundObject = null; this.foundObjectIndex = -1; + this.refreshChildren = false; } + private Task(final boolean refreshChildren) { + this.foundObject = null; + this.foundObjectIndex = -1; + this.refreshChildren = refreshChildren; + } private Task(MatchingObject object) { this.foundObject = object; this.foundObjectIndex = -1; + this.refreshChildren = false; } private Task(MatchingObject foundObject, int foundObjectIndex) { assert (foundObject != null) && (foundObjectIndex >= 0); this.foundObject = foundObject; this.foundObjectIndex = foundObjectIndex; + this.refreshChildren = false; } public void run() { if (!EventQueue.isDispatchThread()) { @@ -334,6 +370,8 @@ updateRootNodeSelection(false); } } + } else if (refreshChildren) { + fireNodesChanged(); } else { fireRootNodeChanged(); } @@ -420,6 +458,21 @@ /** */ + private void fireNodesChanged() { + assert EventQueue.isDispatchThread(); + + if ((treeModelListeners == null) || treeModelListeners.isEmpty()) { + return; + } + + TreeModelEvent event = new TreeModelEvent(this, rootPath); + for (TreeModelListener l : treeModelListeners) { + l.treeStructureChanged(event); + } + } + + /** + */ void fireRootNodeChanged() { assert EventQueue.isDispatchThread(); @@ -475,7 +528,7 @@ return; } - final int index = resultModel.matchingObjects.indexOf(matchingObj); + final int index = getSortedMatchingObjects().indexOf(matchingObj); /* Notify that the file node itself has changed... */ TreeModelEvent event = new TreeModelEvent(this, --- src/org/netbeans/modules/search/ResultViewPanel.java +++ src/org/netbeans/modules/search/ResultViewPanel.java @@ -39,7 +39,6 @@ package org.netbeans.modules.search; -import java.awt.BorderLayout; import java.awt.CardLayout; import java.awt.Color; import java.awt.EventQueue; @@ -64,8 +63,10 @@ import javax.swing.BorderFactory; import javax.swing.Box; import javax.swing.BoxLayout; +import javax.swing.ButtonGroup; import javax.swing.JButton; import javax.swing.JPanel; +import javax.swing.JRadioButton; import javax.swing.JScrollPane; import javax.swing.JSeparator; import javax.swing.JSplitPane; @@ -152,6 +153,9 @@ private JButton btnReplace = new JButton(); private JButton btnPrev; private JButton btnNext; + private ButtonGroup sortButtonGroup = new ButtonGroup(); + private JRadioButton sortButton = new JRadioButton(); + private JRadioButton unsortButton = new JRadioButton(); private JToggleButton btnDisplayContext = new JToggleButton(); private Separator sepDisplayContext; @@ -257,6 +261,18 @@ } }); + //Search sort buttons + final ActionListener listener = new ActionListener() { + public void actionPerformed(ActionEvent e) { + treeModel.setSorted(e.getSource() == sortButton); + } + }; + unsortButton.setSelected(true); + sortButtonGroup.add(sortButton); + sortButtonGroup.add(unsortButton); + sortButton.addActionListener(listener); + unsortButton.addActionListener(listener); + Mnemonics.setLocalizedText( btnStop, NbBundle.getMessage(ResultView.class, "TEXT_BUTTON_STOP")); //NOI18N @@ -269,7 +285,16 @@ Mnemonics.setLocalizedText( btnModifySearch, NbBundle.getMessage(ResultView.class, "TEXT_BUTTON_CUSTOMIZE")); //NOI18N + Mnemonics.setLocalizedText( + sortButton, + NbBundle.getMessage(ResultView.class, "TEXT_BUTTON_SORT")); //NOI18N + Mnemonics.setLocalizedText( + unsortButton, + NbBundle.getMessage(ResultView.class, "TEXT_BUTTON_UNSORT")); //NOI18N + sortButton.setEnabled(false); + unsortButton.setEnabled(false); + btnStop.setEnabled(false); btnShowDetails.setEnabled(false); @@ -277,6 +302,8 @@ JPanel buttonsPanel = new JPanel(); buttonsPanel.setLayout(new BoxLayout(buttonsPanel, BoxLayout.X_AXIS)); + buttonsPanel.add(sortButton); + buttonsPanel.add(unsortButton); buttonsPanel.add(btnReplace); buttonsPanel.add(Box.createHorizontalGlue()); buttonsPanel.add(btnShowDetails); @@ -371,6 +398,8 @@ accessCtx.setAccessibleName(bundle.getString("ACSN_ResultTree")); //NOI18N accessCtx.setAccessibleDescription(bundle.getString("ACSD_ResultTree")); //NOI18N + sortButton.getAccessibleContext().setAccessibleDescription(bundle.getString("ACS_TEXT_BUTTON_SORT")); //NOI18N + unsortButton.getAccessibleContext().setAccessibleDescription(bundle.getString("ACS_TEXT_BUTTON_UNSORT")); //NOI18N btnReplace.getAccessibleContext().setAccessibleDescription(bundle.getString("ACS_TEXT_BUTTON_REPLACE")); //NOI18N btnModifySearch.getAccessibleContext().setAccessibleDescription(bundle.getString("ACS_TEXT_BUTTON_CUSTOMIZE")); //NOI18N btnShowDetails.getAccessibleContext().setAccessibleDescription(bundle.getString("ACS_TEXT_BUTTON_FILL")); //NOI18N @@ -603,6 +632,17 @@ /** */ + void updateSortButtons() { + assert EventQueue.isDispatchThread(); + + if (searchInProgress) { + unsortButton.setSelected(true); + } + setSortButtonsEnabled(hasResults && !searchInProgress); + } + + /** + */ void updateShowAllDetailsBtn() { assert EventQueue.isDispatchThread(); @@ -624,6 +664,7 @@ "TXT_RootSearchedNodesFulltext")); //NOI18N searchInProgress = true; + updateSortButtons(); updateShowAllDetailsBtn(); setBtnModifyEnabled(true); setBtnStopEnabled(true); @@ -638,6 +679,7 @@ searchInProgress = false; hasDetails = (resultModel != null) ? resultModel.hasDetails() : false; + updateSortButtons(); updateShowAllDetailsBtn(); setBtnStopEnabled(false); setBtnReplaceEnabled(true); @@ -655,6 +697,7 @@ void searchCancelled() { setRootDisplayName(NbBundle.getMessage(ResultView.class, "TEXT_TASK_CANCELLED"));//NOI18N searchInProgress = true; + updateSortButtons(); updateShowAllDetailsBtn(); setBtnStopEnabled(false); setBtnReplaceEnabled(true); @@ -1136,6 +1179,11 @@ Manager.getInstance().scheduleReplaceTask(taskReplace); } + void setSortButtonsEnabled(boolean enabled) { + sortButton.setEnabled(enabled); + unsortButton.setEnabled(enabled); + } + void setBtnModifyEnabled(boolean enabled){ btnModifySearch.setEnabled(enabled); }