Computing duplicates incrementally, including incremental computation UI.
authorJan Lahoda <jlahoda@netbeans.org>
Mon, 14 Feb 2011 20:43:35 +0100
changeset 5460d9ded9efca1
parent 545 224ff3deee5d
child 547 bfeb3f3a510e
Computing duplicates incrementally, including incremental computation UI.
api/src/org/netbeans/modules/jackpot30/impl/duplicates/Bundle.properties
api/src/org/netbeans/modules/jackpot30/impl/duplicates/ComputeDuplicates.java
api/src/org/netbeans/modules/jackpot30/impl/duplicates/DuplicatesListPanel.form
api/src/org/netbeans/modules/jackpot30/impl/duplicates/DuplicatesListPanel.java
api/src/org/netbeans/modules/jackpot30/impl/duplicates/GlobalFindDuplicates.java
api/test/unit/src/org/netbeans/modules/jackpot30/impl/duplicates/ComputeDuplicatesTest.java
     1.1 --- a/api/src/org/netbeans/modules/jackpot30/impl/duplicates/Bundle.properties	Sat Feb 12 00:49:24 2011 +0100
     1.2 +++ b/api/src/org/netbeans/modules/jackpot30/impl/duplicates/Bundle.properties	Mon Feb 14 20:43:35 2011 +0100
     1.3 @@ -1,1 +1,3 @@
     1.4  CTL_GlobalFindDuplicates=Global Find Duplicates
     1.5 +DuplicatesListPanel.findMore.text=<html><body><a href="">Look for More</a>
     1.6 +DuplicatesListPanel.progressLabel.text=
     2.1 --- a/api/src/org/netbeans/modules/jackpot30/impl/duplicates/ComputeDuplicates.java	Sat Feb 12 00:49:24 2011 +0100
     2.2 +++ b/api/src/org/netbeans/modules/jackpot30/impl/duplicates/ComputeDuplicates.java	Mon Feb 14 20:43:35 2011 +0100
     2.3 @@ -44,7 +44,6 @@
     2.4  import java.util.ArrayList;
     2.5  import java.util.Arrays;
     2.6  import java.util.BitSet;
     2.7 -import java.util.Collection;
     2.8  import java.util.Collections;
     2.9  import java.util.Comparator;
    2.10  import java.util.HashSet;
    2.11 @@ -54,6 +53,7 @@
    2.12  import java.util.List;
    2.13  import java.util.Map;
    2.14  import java.util.Map.Entry;
    2.15 +import java.util.NoSuchElementException;
    2.16  import java.util.Set;
    2.17  import java.util.concurrent.atomic.AtomicBoolean;
    2.18  import org.apache.lucene.document.Document;
    2.19 @@ -86,7 +86,7 @@
    2.20   */
    2.21  public class ComputeDuplicates {
    2.22  
    2.23 -    public Collection<? extends DuplicateDescription> computeDuplicatesForAllOpenedProjects(ProgressHandle progress, AtomicBoolean cancel) throws IOException {
    2.24 +    public Iterator<? extends DuplicateDescription> computeDuplicatesForAllOpenedProjects(ProgressHandle progress, AtomicBoolean cancel) throws IOException {
    2.25          Set<URL> urls = new HashSet<URL>();
    2.26  
    2.27          for (ClassPath cp : GlobalPathRegistry.getDefault().getPaths(ClassPath.SOURCE)) {
    2.28 @@ -103,7 +103,7 @@
    2.29          }
    2.30      }
    2.31  
    2.32 -    public Collection<? extends DuplicateDescription> computeDuplicates(Set<URL> forURLs, ProgressHandle progress, AtomicBoolean cancel) throws IOException {
    2.33 +    public Iterator<? extends DuplicateDescription> computeDuplicates(Set<URL> forURLs, ProgressHandle progress, AtomicBoolean cancel) throws IOException {
    2.34          Map<IndexReader, FileObject> readers2Roots = new LinkedHashMap<IndexReader, FileObject>();
    2.35  
    2.36          progress.progress("Updating indices");
    2.37 @@ -142,19 +142,27 @@
    2.38          //TODO: only show valuable duplicates?:
    2.39  //        dd = dd.subList(0, dd.size() / 10 + 1);
    2.40  
    2.41 -        progress.switchToDeterminate(dd.size());
    2.42 -        
    2.43 -        List<DuplicateDescription> result = new LinkedList<DuplicateDescription>();
    2.44 -        int done = 0;
    2.45 +        return new DuplicatesIterator(readers2Roots, dd);
    2.46 +    }
    2.47  
    2.48 -        for (String longest : dd) {
    2.49 +    private static final class DuplicatesIterator implements Iterator<DuplicateDescription> {
    2.50 +        private final Map<IndexReader, FileObject> readers2Roots;
    2.51 +        private final Iterator<String> duplicateCandidates;
    2.52 +        private final List<DuplicateDescription> result = new LinkedList<DuplicateDescription>();
    2.53 +
    2.54 +        public DuplicatesIterator(Map<IndexReader, FileObject> readers2Roots, Iterable<String> duplicateCandidates) {
    2.55 +            this.readers2Roots = readers2Roots;
    2.56 +            this.duplicateCandidates = duplicateCandidates.iterator();
    2.57 +        }
    2.58 +
    2.59 +        private DuplicateDescription nextDescription() throws IOException {
    2.60 +        while (duplicateCandidates.hasNext()) {
    2.61 +            String longest = duplicateCandidates.next();
    2.62              List<Span> foundDuplicates = new LinkedList<Span>();
    2.63  
    2.64              Query query = new TermQuery(new Term("generalized", longest));
    2.65  
    2.66              for (Entry<IndexReader, FileObject> e : readers2Roots.entrySet()) {
    2.67 -                if (cancel.get()) return Collections.emptyList();
    2.68 -
    2.69                  Searcher s = new IndexSearcher(e.getKey());
    2.70                  BitSet matchingDocuments = new BitSet(e.getKey().maxDoc());
    2.71                  Collector c = new BitSetCollector(matchingDocuments);
    2.72 @@ -201,16 +209,45 @@
    2.73                      }
    2.74                  }
    2.75  
    2.76 -                if (add)
    2.77 +                if (add) {
    2.78                      result.add(current);
    2.79 +                    return current;
    2.80 +                }
    2.81              }
    2.82  
    2.83 -            progress.progress(++done);
    2.84 +        }
    2.85 +        return null;
    2.86          }
    2.87  
    2.88 -        progress.finish();
    2.89 +        private DuplicateDescription next;
    2.90  
    2.91 -        return result;
    2.92 +        public boolean hasNext() {
    2.93 +            if (next == null) {
    2.94 +                try {
    2.95 +                    next = nextDescription();
    2.96 +                } catch (IOException ex) {
    2.97 +                    Exceptions.printStackTrace(ex);
    2.98 +                }
    2.99 +            }
   2.100 +
   2.101 +            return next != null;
   2.102 +        }
   2.103 +
   2.104 +        public DuplicateDescription next() {
   2.105 +            if (!hasNext()) {
   2.106 +                throw new NoSuchElementException();
   2.107 +            }
   2.108 +
   2.109 +            DuplicateDescription r = next;
   2.110 +
   2.111 +            next = null;
   2.112 +            return r;
   2.113 +        }
   2.114 +
   2.115 +        public void remove() {
   2.116 +            throw new UnsupportedOperationException("Not supported.");
   2.117 +        }
   2.118 +
   2.119      }
   2.120  
   2.121      private static List<String> getDuplicatedValues(IndexReader ir, String field, AtomicBoolean cancel) throws IOException {
     3.1 --- a/api/src/org/netbeans/modules/jackpot30/impl/duplicates/DuplicatesListPanel.form	Sat Feb 12 00:49:24 2011 +0100
     3.2 +++ b/api/src/org/netbeans/modules/jackpot30/impl/duplicates/DuplicatesListPanel.form	Mon Feb 14 20:43:35 2011 +0100
     3.3 @@ -1,9 +1,6 @@
     3.4 -<?xml version="1.0" encoding="UTF-8" ?>
     3.5 +<?xml version="1.1" encoding="UTF-8" ?>
     3.6  
     3.7  <Form version="1.5" maxVersion="1.7" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
     3.8 -  <SyntheticProperties>
     3.9 -    <SyntheticProperty name="designerSize" type="java.awt.Dimension" value="-84,-19,0,5,115,114,0,18,106,97,118,97,46,97,119,116,46,68,105,109,101,110,115,105,111,110,65,-114,-39,-41,-84,95,68,20,2,0,2,73,0,6,104,101,105,103,104,116,73,0,5,119,105,100,116,104,120,112,0,0,1,56,0,0,1,-98"/>
    3.10 -  </SyntheticProperties>
    3.11    <AuxValues>
    3.12      <AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="1"/>
    3.13      <AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
    3.14 @@ -19,11 +16,12 @@
    3.15    <Layout>
    3.16      <DimensionLayout dim="0">
    3.17        <Group type="103" groupAlignment="0" attributes="0">
    3.18 -          <Group type="102" alignment="0" attributes="0">
    3.19 +          <Group type="102" alignment="1" attributes="0">
    3.20                <EmptySpace max="-2" attributes="0"/>
    3.21 -              <Group type="103" groupAlignment="0" attributes="0">
    3.22 -                  <Component id="jSplitPane1" alignment="1" pref="390" max="32767" attributes="0"/>
    3.23 -                  <Component id="jScrollPane4" alignment="1" pref="390" max="32767" attributes="0"/>
    3.24 +              <Group type="103" groupAlignment="1" attributes="0">
    3.25 +                  <Component id="mainSplit2" alignment="0" pref="906" max="32767" attributes="0"/>
    3.26 +                  <Component id="jScrollPane1" alignment="0" pref="906" max="32767" attributes="0"/>
    3.27 +                  <Component id="jPanel1" alignment="1" min="-2" max="-2" attributes="0"/>
    3.28                </Group>
    3.29                <EmptySpace max="-2" attributes="0"/>
    3.30            </Group>
    3.31 @@ -32,99 +30,118 @@
    3.32      <DimensionLayout dim="1">
    3.33        <Group type="103" groupAlignment="0" attributes="0">
    3.34            <Group type="102" attributes="0">
    3.35 -              <EmptySpace max="-2" attributes="0"/>
    3.36 -              <Component id="jScrollPane4" min="-2" pref="76" max="-2" attributes="0"/>
    3.37 -              <EmptySpace max="-2" attributes="0"/>
    3.38 -              <Component id="jSplitPane1" pref="206" max="32767" attributes="0"/>
    3.39 -              <EmptySpace max="-2" attributes="0"/>
    3.40 +              <EmptySpace min="-2" max="-2" attributes="0"/>
    3.41 +              <Component id="jScrollPane1" min="-2" pref="67" max="-2" attributes="0"/>
    3.42 +              <EmptySpace min="-2" max="-2" attributes="0"/>
    3.43 +              <Component id="mainSplit2" pref="467" max="32767" attributes="0"/>
    3.44 +              <EmptySpace type="unrelated" min="-2" max="-2" attributes="0"/>
    3.45 +              <Component id="jPanel1" min="-2" max="-2" attributes="0"/>
    3.46 +              <EmptySpace min="-2" max="-2" attributes="0"/>
    3.47            </Group>
    3.48        </Group>
    3.49      </DimensionLayout>
    3.50    </Layout>
    3.51    <SubComponents>
    3.52 -    <Container class="javax.swing.JSplitPane" name="jSplitPane1">
    3.53 +    <Container class="javax.swing.JScrollPane" name="jScrollPane1">
    3.54 +
    3.55 +      <Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
    3.56 +      <SubComponents>
    3.57 +        <Component class="javax.swing.JList" name="duplicatesList">
    3.58 +          <Properties>
    3.59 +            <Property name="model" type="javax.swing.ListModel" editor="org.netbeans.modules.form.editors2.ListModelEditor">
    3.60 +              <StringArray count="0"/>
    3.61 +            </Property>
    3.62 +            <Property name="prototypeCellValue" type="java.lang.Object" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
    3.63 +              <Connection code="&quot;9999999999999999999999999999999999999999999999999999999999999999999999&quot;" type="code"/>
    3.64 +            </Property>
    3.65 +            <Property name="visibleRowCount" type="int" value="4"/>
    3.66 +          </Properties>
    3.67 +        </Component>
    3.68 +      </SubComponents>
    3.69 +    </Container>
    3.70 +    <Container class="javax.swing.JSplitPane" name="mainSplit2">
    3.71 +      <Properties>
    3.72 +        <Property name="dividerLocation" type="int" value="400"/>
    3.73 +      </Properties>
    3.74        <AuxValues>
    3.75          <AuxValue name="JavaCodeGenerator_CreateCodeCustom" type="java.lang.String" value="new BalancedSplitPane()"/>
    3.76        </AuxValues>
    3.77  
    3.78        <Layout class="org.netbeans.modules.form.compat2.layouts.support.JSplitPaneSupportLayout"/>
    3.79        <SubComponents>
    3.80 -        <Container class="javax.swing.JScrollPane" name="jScrollPane2">
    3.81 -          <AuxValues>
    3.82 -            <AuxValue name="autoScrollPane" type="java.lang.Boolean" value="true"/>
    3.83 -          </AuxValues>
    3.84 +        <Container class="javax.swing.JPanel" name="rightPanel">
    3.85 +          <Constraints>
    3.86 +            <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.support.JSplitPaneSupportLayout" value="org.netbeans.modules.form.compat2.layouts.support.JSplitPaneSupportLayout$JSplitPaneConstraintsDescription">
    3.87 +              <JSplitPaneConstraints position="right"/>
    3.88 +            </Constraint>
    3.89 +          </Constraints>
    3.90 +
    3.91 +          <Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout"/>
    3.92 +          <SubComponents>
    3.93 +            <Component class="javax.swing.JComboBox" name="rightFileList">
    3.94 +              <Properties>
    3.95 +                <Property name="model" type="javax.swing.ComboBoxModel" editor="org.netbeans.modules.form.editors2.ComboBoxModelEditor">
    3.96 +                  <StringArray count="0"/>
    3.97 +                </Property>
    3.98 +              </Properties>
    3.99 +              <Constraints>
   3.100 +                <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
   3.101 +                  <GridBagConstraints gridX="0" gridY="0" gridWidth="1" gridHeight="1" fill="2" ipadX="324" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="18" weightX="1.0" weightY="0.0"/>
   3.102 +                </Constraint>
   3.103 +              </Constraints>
   3.104 +            </Component>
   3.105 +            <Container class="javax.swing.JScrollPane" name="jScrollPane3">
   3.106 +              <AuxValues>
   3.107 +                <AuxValue name="autoScrollPane" type="java.lang.Boolean" value="true"/>
   3.108 +              </AuxValues>
   3.109 +              <Constraints>
   3.110 +                <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
   3.111 +                  <GridBagConstraints gridX="0" gridY="1" gridWidth="1" gridHeight="1" fill="1" ipadX="0" ipadY="0" insetsTop="6" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="18" weightX="1.0" weightY="1.0"/>
   3.112 +                </Constraint>
   3.113 +              </Constraints>
   3.114 +
   3.115 +              <Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
   3.116 +              <SubComponents>
   3.117 +                <Component class="javax.swing.JEditorPane" name="right">
   3.118 +                </Component>
   3.119 +              </SubComponents>
   3.120 +            </Container>
   3.121 +          </SubComponents>
   3.122 +        </Container>
   3.123 +        <Container class="javax.swing.JPanel" name="leftPanel">
   3.124            <Constraints>
   3.125              <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.support.JSplitPaneSupportLayout" value="org.netbeans.modules.form.compat2.layouts.support.JSplitPaneSupportLayout$JSplitPaneConstraintsDescription">
   3.126                <JSplitPaneConstraints position="left"/>
   3.127              </Constraint>
   3.128            </Constraints>
   3.129  
   3.130 -          <Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
   3.131 +          <Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout"/>
   3.132            <SubComponents>
   3.133 -            <Component class="javax.swing.JEditorPane" name="left">
   3.134 -            </Component>
   3.135 -          </SubComponents>
   3.136 -        </Container>
   3.137 -        <Container class="javax.swing.JScrollPane" name="jScrollPane3">
   3.138 -          <AuxValues>
   3.139 -            <AuxValue name="autoScrollPane" type="java.lang.Boolean" value="true"/>
   3.140 -          </AuxValues>
   3.141 -          <Constraints>
   3.142 -            <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.support.JSplitPaneSupportLayout" value="org.netbeans.modules.form.compat2.layouts.support.JSplitPaneSupportLayout$JSplitPaneConstraintsDescription">
   3.143 -              <JSplitPaneConstraints position="right"/>
   3.144 -            </Constraint>
   3.145 -          </Constraints>
   3.146 +            <Container class="javax.swing.JScrollPane" name="jScrollPane2">
   3.147 +              <AuxValues>
   3.148 +                <AuxValue name="autoScrollPane" type="java.lang.Boolean" value="true"/>
   3.149 +              </AuxValues>
   3.150 +              <Constraints>
   3.151 +                <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
   3.152 +                  <GridBagConstraints gridX="0" gridY="1" gridWidth="1" gridHeight="1" fill="1" ipadX="0" ipadY="0" insetsTop="6" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="18" weightX="1.0" weightY="1.0"/>
   3.153 +                </Constraint>
   3.154 +              </Constraints>
   3.155  
   3.156 -          <Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
   3.157 -          <SubComponents>
   3.158 -            <Component class="javax.swing.JEditorPane" name="right">
   3.159 -            </Component>
   3.160 -          </SubComponents>
   3.161 -        </Container>
   3.162 -      </SubComponents>
   3.163 -    </Container>
   3.164 -    <Container class="javax.swing.JScrollPane" name="jScrollPane4">
   3.165 -
   3.166 -      <Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
   3.167 -      <SubComponents>
   3.168 -        <Container class="javax.swing.JSplitPane" name="jSplitPane2">
   3.169 -          <Properties>
   3.170 -            <Property name="dividerLocation" type="int" value="250"/>
   3.171 -            <Property name="dividerSize" type="int" value="1"/>
   3.172 -          </Properties>
   3.173 -          <AuxValues>
   3.174 -            <AuxValue name="JavaCodeGenerator_CreateCodeCustom" type="java.lang.String" value="new BalancedSplitPane()"/>
   3.175 -          </AuxValues>
   3.176 -
   3.177 -          <Layout class="org.netbeans.modules.form.compat2.layouts.support.JSplitPaneSupportLayout"/>
   3.178 -          <SubComponents>
   3.179 -            <Component class="javax.swing.JList" name="rightList">
   3.180 +              <Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
   3.181 +              <SubComponents>
   3.182 +                <Component class="javax.swing.JEditorPane" name="left">
   3.183 +                </Component>
   3.184 +              </SubComponents>
   3.185 +            </Container>
   3.186 +            <Component class="javax.swing.JComboBox" name="leftFileList">
   3.187                <Properties>
   3.188 -                <Property name="model" type="javax.swing.ListModel" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
   3.189 -                  <Connection code="createListModel()" type="code"/>
   3.190 -                </Property>
   3.191 -                <Property name="cellRenderer" type="javax.swing.ListCellRenderer" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
   3.192 -                  <Connection code="new RendererImpl(false)" type="code"/>
   3.193 +                <Property name="model" type="javax.swing.ComboBoxModel" editor="org.netbeans.modules.form.editors2.ComboBoxModelEditor">
   3.194 +                  <StringArray count="0"/>
   3.195                  </Property>
   3.196                </Properties>
   3.197                <Constraints>
   3.198 -                <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.support.JSplitPaneSupportLayout" value="org.netbeans.modules.form.compat2.layouts.support.JSplitPaneSupportLayout$JSplitPaneConstraintsDescription">
   3.199 -                  <JSplitPaneConstraints position="right"/>
   3.200 -                </Constraint>
   3.201 -              </Constraints>
   3.202 -            </Component>
   3.203 -            <Component class="javax.swing.JList" name="leftList">
   3.204 -              <Properties>
   3.205 -                <Property name="model" type="javax.swing.ListModel" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
   3.206 -                  <Connection code="createListModel()" type="code"/>
   3.207 -                </Property>
   3.208 -                <Property name="cellRenderer" type="javax.swing.ListCellRenderer" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
   3.209 -                  <Connection code="new RendererImpl(true)" type="code"/>
   3.210 -                </Property>
   3.211 -              </Properties>
   3.212 -              <Constraints>
   3.213 -                <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.support.JSplitPaneSupportLayout" value="org.netbeans.modules.form.compat2.layouts.support.JSplitPaneSupportLayout$JSplitPaneConstraintsDescription">
   3.214 -                  <JSplitPaneConstraints position="left"/>
   3.215 +                <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
   3.216 +                  <GridBagConstraints gridX="0" gridY="0" gridWidth="1" gridHeight="1" fill="2" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="18" weightX="1.0" weightY="0.0"/>
   3.217                  </Constraint>
   3.218                </Constraints>
   3.219              </Component>
   3.220 @@ -132,5 +149,41 @@
   3.221          </Container>
   3.222        </SubComponents>
   3.223      </Container>
   3.224 +    <Container class="javax.swing.JPanel" name="jPanel1">
   3.225 +
   3.226 +      <Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout"/>
   3.227 +      <SubComponents>
   3.228 +        <Component class="javax.swing.JLabel" name="progressLabel">
   3.229 +          <Properties>
   3.230 +            <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
   3.231 +              <ResourceString bundle="org/netbeans/modules/jackpot30/impl/duplicates/Bundle.properties" key="DuplicatesListPanel.progressLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
   3.232 +            </Property>
   3.233 +          </Properties>
   3.234 +          <Constraints>
   3.235 +            <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
   3.236 +              <GridBagConstraints gridX="0" gridY="0" gridWidth="1" gridHeight="1" fill="2" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="18" weightX="1.0" weightY="0.0"/>
   3.237 +            </Constraint>
   3.238 +          </Constraints>
   3.239 +        </Component>
   3.240 +        <Component class="javax.swing.JLabel" name="findMore">
   3.241 +          <Properties>
   3.242 +            <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
   3.243 +              <ResourceString bundle="org/netbeans/modules/jackpot30/impl/duplicates/Bundle.properties" key="DuplicatesListPanel.findMore.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
   3.244 +            </Property>
   3.245 +            <Property name="cursor" type="java.awt.Cursor" editor="org.netbeans.modules.form.editors2.CursorEditor">
   3.246 +              <Color id="Hand Cursor"/>
   3.247 +            </Property>
   3.248 +          </Properties>
   3.249 +          <Events>
   3.250 +            <EventHandler event="mouseClicked" listener="java.awt.event.MouseListener" parameters="java.awt.event.MouseEvent" handler="findMoreMouseClicked"/>
   3.251 +          </Events>
   3.252 +          <Constraints>
   3.253 +            <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
   3.254 +              <GridBagConstraints gridX="1" gridY="0" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="6" insetsBottom="0" insetsRight="0" anchor="18" weightX="0.0" weightY="0.0"/>
   3.255 +            </Constraint>
   3.256 +          </Constraints>
   3.257 +        </Component>
   3.258 +      </SubComponents>
   3.259 +    </Container>
   3.260    </SubComponents>
   3.261  </Form>
     4.1 --- a/api/src/org/netbeans/modules/jackpot30/impl/duplicates/DuplicatesListPanel.java	Sat Feb 12 00:49:24 2011 +0100
     4.2 +++ b/api/src/org/netbeans/modules/jackpot30/impl/duplicates/DuplicatesListPanel.java	Mon Feb 14 20:43:35 2011 +0100
     4.3 @@ -41,14 +41,19 @@
     4.4  import java.awt.Color;
     4.5  import java.awt.Component;
     4.6  import java.awt.Rectangle;
     4.7 +import java.awt.event.ActionEvent;
     4.8 +import java.awt.event.ActionListener;
     4.9  import java.io.IOException;
    4.10  import java.util.Collection;
    4.11 +import java.util.Iterator;
    4.12 +import java.util.LinkedHashSet;
    4.13 +import java.util.Set;
    4.14 +import javax.swing.DefaultComboBoxModel;
    4.15  import javax.swing.DefaultListCellRenderer;
    4.16  import javax.swing.DefaultListModel;
    4.17  import javax.swing.JEditorPane;
    4.18  import javax.swing.JList;
    4.19  import javax.swing.JSplitPane;
    4.20 -import javax.swing.ListModel;
    4.21  import javax.swing.SwingUtilities;
    4.22  import javax.swing.event.ListSelectionEvent;
    4.23  import javax.swing.event.ListSelectionListener;
    4.24 @@ -68,6 +73,8 @@
    4.25  import org.openide.filesystems.FileUtil;
    4.26  import org.openide.util.Exceptions;
    4.27  import org.openide.util.Lookup;
    4.28 +import org.openide.util.RequestProcessor;
    4.29 +import org.openide.util.RequestProcessor.Task;
    4.30  import org.openide.util.lookup.Lookups;
    4.31  import org.openide.util.lookup.ServiceProvider;
    4.32  
    4.33 @@ -76,12 +83,14 @@
    4.34   * @author lahvac
    4.35   */
    4.36  public class DuplicatesListPanel extends javax.swing.JPanel {
    4.37 -    private final Collection<? extends DuplicateDescription> dupes;
    4.38 -    private final int commonPrefixLength;
    4.39 +    private final Collection<String> sourceRoots;
    4.40 +    private final Iterator<? extends DuplicateDescription> dupes;
    4.41  
    4.42 -    public DuplicatesListPanel(Collection<? extends DuplicateDescription> dupes) {
    4.43 +    private int targetCount;
    4.44 +
    4.45 +    public DuplicatesListPanel(Collection<String> sourceRoots, final Iterator<? extends DuplicateDescription> dupes) {
    4.46 +        this.sourceRoots = sourceRoots;
    4.47          this.dupes = dupes;
    4.48 -        this.commonPrefixLength = computeCommonPrefixLen(dupes);
    4.49          
    4.50          initComponents();
    4.51  
    4.52 @@ -91,20 +100,44 @@
    4.53          right.setContentType("text/x-java");
    4.54          right.putClientProperty(DuplicatesListPanel.class, new OffsetsBag(right.getDocument()));
    4.55  
    4.56 -        leftList.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
    4.57 +        duplicatesList.setModel(new DefaultListModel());
    4.58 +        duplicatesList.setCellRenderer(new DuplicatesRendererImpl());
    4.59 +        duplicatesList.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
    4.60              public void valueChanged(ListSelectionEvent arg0) {
    4.61 -                setDiff((DuplicateDescription) leftList.getSelectedValue());
    4.62 -                rightList.setSelectedValue(leftList.getSelectedValue(), false);
    4.63 +                DuplicateDescription dd = (DuplicateDescription) duplicatesList.getSelectedValue();
    4.64 +                DefaultComboBoxModel l = new DefaultComboBoxModel();
    4.65 +                DefaultComboBoxModel r = new DefaultComboBoxModel();
    4.66 +
    4.67 +                for (Span s : dd.dupes) {
    4.68 +                    l.addElement(s);
    4.69 +                    r.addElement(s);
    4.70 +                }
    4.71 +
    4.72 +                leftFileList.setModel(l);
    4.73 +                rightFileList.setModel(r);
    4.74 +
    4.75 +                leftFileList.setSelectedIndex(0);
    4.76 +                rightFileList.setSelectedIndex(1);
    4.77              }
    4.78          });
    4.79  
    4.80 -        rightList.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
    4.81 -            public void valueChanged(ListSelectionEvent arg0) {
    4.82 -                leftList.setSelectedValue(rightList.getSelectedValue(), false);
    4.83 +        leftFileList.setRenderer(new SpanRendererImpl());
    4.84 +        leftFileList.addActionListener(new ActionListener() {
    4.85 +
    4.86 +            public void actionPerformed(ActionEvent e) {
    4.87 +                setSpan(left, (Span) leftFileList.getSelectedItem());
    4.88 +            }
    4.89 +        });
    4.90 +        rightFileList.setRenderer(new SpanRendererImpl());
    4.91 +        rightFileList.addActionListener(new ActionListener() {
    4.92 +            public void actionPerformed(ActionEvent e) {
    4.93 +                setSpan(right, (Span) rightFileList.getSelectedItem());
    4.94              }
    4.95          });
    4.96  
    4.97 -        leftList.setSelectedIndex(0);
    4.98 +        progressLabel.setText("Looking for duplicates...");
    4.99 +
   4.100 +        findMore();
   4.101      }
   4.102  
   4.103      /** This method is called from within the constructor to
   4.104 @@ -115,81 +148,136 @@
   4.105      @SuppressWarnings("unchecked")
   4.106      // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
   4.107      private void initComponents() {
   4.108 +        java.awt.GridBagConstraints gridBagConstraints;
   4.109  
   4.110 -        jSplitPane1 = new BalancedSplitPane();
   4.111 +        jScrollPane1 = new javax.swing.JScrollPane();
   4.112 +        duplicatesList = new javax.swing.JList();
   4.113 +        mainSplit2 = new BalancedSplitPane();
   4.114 +        rightPanel = new javax.swing.JPanel();
   4.115 +        rightFileList = new javax.swing.JComboBox();
   4.116 +        jScrollPane3 = new javax.swing.JScrollPane();
   4.117 +        right = new javax.swing.JEditorPane();
   4.118 +        leftPanel = new javax.swing.JPanel();
   4.119          jScrollPane2 = new javax.swing.JScrollPane();
   4.120          left = new javax.swing.JEditorPane();
   4.121 -        jScrollPane3 = new javax.swing.JScrollPane();
   4.122 -        right = new javax.swing.JEditorPane();
   4.123 -        jScrollPane4 = new javax.swing.JScrollPane();
   4.124 -        jSplitPane2 = new BalancedSplitPane();
   4.125 -        rightList = new javax.swing.JList();
   4.126 -        leftList = new javax.swing.JList();
   4.127 +        leftFileList = new javax.swing.JComboBox();
   4.128 +        jPanel1 = new javax.swing.JPanel();
   4.129 +        progressLabel = new javax.swing.JLabel();
   4.130 +        findMore = new javax.swing.JLabel();
   4.131 +
   4.132 +        duplicatesList.setPrototypeCellValue("9999999999999999999999999999999999999999999999999999999999999999999999");
   4.133 +        duplicatesList.setVisibleRowCount(4);
   4.134 +        jScrollPane1.setViewportView(duplicatesList);
   4.135 +
   4.136 +        mainSplit2.setDividerLocation(400);
   4.137 +
   4.138 +        rightPanel.setLayout(new java.awt.GridBagLayout());
   4.139 +
   4.140 +        gridBagConstraints = new java.awt.GridBagConstraints();
   4.141 +        gridBagConstraints.gridx = 0;
   4.142 +        gridBagConstraints.gridy = 0;
   4.143 +        gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
   4.144 +        gridBagConstraints.ipadx = 324;
   4.145 +        gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
   4.146 +        gridBagConstraints.weightx = 1.0;
   4.147 +        rightPanel.add(rightFileList, gridBagConstraints);
   4.148 +
   4.149 +        jScrollPane3.setViewportView(right);
   4.150 +
   4.151 +        gridBagConstraints = new java.awt.GridBagConstraints();
   4.152 +        gridBagConstraints.gridx = 0;
   4.153 +        gridBagConstraints.gridy = 1;
   4.154 +        gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
   4.155 +        gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
   4.156 +        gridBagConstraints.weightx = 1.0;
   4.157 +        gridBagConstraints.weighty = 1.0;
   4.158 +        gridBagConstraints.insets = new java.awt.Insets(6, 0, 0, 0);
   4.159 +        rightPanel.add(jScrollPane3, gridBagConstraints);
   4.160 +
   4.161 +        mainSplit2.setRightComponent(rightPanel);
   4.162 +
   4.163 +        leftPanel.setLayout(new java.awt.GridBagLayout());
   4.164  
   4.165          jScrollPane2.setViewportView(left);
   4.166  
   4.167 -        jSplitPane1.setLeftComponent(jScrollPane2);
   4.168 +        gridBagConstraints = new java.awt.GridBagConstraints();
   4.169 +        gridBagConstraints.gridx = 0;
   4.170 +        gridBagConstraints.gridy = 1;
   4.171 +        gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
   4.172 +        gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
   4.173 +        gridBagConstraints.weightx = 1.0;
   4.174 +        gridBagConstraints.weighty = 1.0;
   4.175 +        gridBagConstraints.insets = new java.awt.Insets(6, 0, 0, 0);
   4.176 +        leftPanel.add(jScrollPane2, gridBagConstraints);
   4.177  
   4.178 -        jScrollPane3.setViewportView(right);
   4.179 +        gridBagConstraints = new java.awt.GridBagConstraints();
   4.180 +        gridBagConstraints.gridx = 0;
   4.181 +        gridBagConstraints.gridy = 0;
   4.182 +        gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
   4.183 +        gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
   4.184 +        gridBagConstraints.weightx = 1.0;
   4.185 +        leftPanel.add(leftFileList, gridBagConstraints);
   4.186  
   4.187 -        jSplitPane1.setRightComponent(jScrollPane3);
   4.188 +        mainSplit2.setLeftComponent(leftPanel);
   4.189  
   4.190 -        jSplitPane2.setDividerLocation(250);
   4.191 -        jSplitPane2.setDividerSize(1);
   4.192 +        jPanel1.setLayout(new java.awt.GridBagLayout());
   4.193  
   4.194 -        rightList.setModel(createListModel());
   4.195 -        rightList.setCellRenderer(new RendererImpl(false));
   4.196 -        jSplitPane2.setRightComponent(rightList);
   4.197 +        progressLabel.setText(org.openide.util.NbBundle.getMessage(DuplicatesListPanel.class, "DuplicatesListPanel.progressLabel.text")); // NOI18N
   4.198 +        gridBagConstraints = new java.awt.GridBagConstraints();
   4.199 +        gridBagConstraints.gridx = 0;
   4.200 +        gridBagConstraints.gridy = 0;
   4.201 +        gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
   4.202 +        gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
   4.203 +        gridBagConstraints.weightx = 1.0;
   4.204 +        jPanel1.add(progressLabel, gridBagConstraints);
   4.205  
   4.206 -        leftList.setModel(createListModel());
   4.207 -        leftList.setCellRenderer(new RendererImpl(true));
   4.208 -        jSplitPane2.setLeftComponent(leftList);
   4.209 -
   4.210 -        jScrollPane4.setViewportView(jSplitPane2);
   4.211 +        findMore.setText(org.openide.util.NbBundle.getMessage(DuplicatesListPanel.class, "DuplicatesListPanel.findMore.text")); // NOI18N
   4.212 +        findMore.setCursor(new java.awt.Cursor(java.awt.Cursor.HAND_CURSOR));
   4.213 +        findMore.addMouseListener(new java.awt.event.MouseAdapter() {
   4.214 +            public void mouseClicked(java.awt.event.MouseEvent evt) {
   4.215 +                findMoreMouseClicked(evt);
   4.216 +            }
   4.217 +        });
   4.218 +        gridBagConstraints = new java.awt.GridBagConstraints();
   4.219 +        gridBagConstraints.gridx = 1;
   4.220 +        gridBagConstraints.gridy = 0;
   4.221 +        gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
   4.222 +        gridBagConstraints.insets = new java.awt.Insets(0, 6, 0, 0);
   4.223 +        jPanel1.add(findMore, gridBagConstraints);
   4.224  
   4.225          javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
   4.226          this.setLayout(layout);
   4.227          layout.setHorizontalGroup(
   4.228              layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
   4.229 -            .addGroup(layout.createSequentialGroup()
   4.230 +            .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
   4.231                  .addContainerGap()
   4.232 -                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
   4.233 -                    .addComponent(jSplitPane1, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, 390, Short.MAX_VALUE)
   4.234 -                    .addComponent(jScrollPane4, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, 390, Short.MAX_VALUE))
   4.235 +                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
   4.236 +                    .addComponent(mainSplit2, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, 906, Short.MAX_VALUE)
   4.237 +                    .addComponent(jScrollPane1, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, 906, Short.MAX_VALUE)
   4.238 +                    .addComponent(jPanel1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
   4.239                  .addContainerGap())
   4.240          );
   4.241          layout.setVerticalGroup(
   4.242              layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
   4.243              .addGroup(layout.createSequentialGroup()
   4.244                  .addContainerGap()
   4.245 -                .addComponent(jScrollPane4, javax.swing.GroupLayout.PREFERRED_SIZE, 76, javax.swing.GroupLayout.PREFERRED_SIZE)
   4.246 +                .addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 67, javax.swing.GroupLayout.PREFERRED_SIZE)
   4.247                  .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
   4.248 -                .addComponent(jSplitPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 206, Short.MAX_VALUE)
   4.249 +                .addComponent(mainSplit2, javax.swing.GroupLayout.DEFAULT_SIZE, 467, Short.MAX_VALUE)
   4.250 +                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
   4.251 +                .addComponent(jPanel1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
   4.252                  .addContainerGap())
   4.253          );
   4.254      }// </editor-fold>//GEN-END:initComponents
   4.255  
   4.256 +    private void findMoreMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_findMoreMouseClicked
   4.257 +        findMore();
   4.258 +    }//GEN-LAST:event_findMoreMouseClicked
   4.259  
   4.260 -    private ListModel createListModel() {
   4.261 -        DefaultListModel dlm = new DefaultListModel();
   4.262 -
   4.263 -        for (DuplicateDescription dd : dupes) {
   4.264 -            dlm.addElement(dd);
   4.265 -        }
   4.266 -
   4.267 -        return dlm;
   4.268 -    }
   4.269 -
   4.270 -    private static int computeCommonPrefixLen(Collection<? extends DuplicateDescription> dupes) {
   4.271 -        String commonPrefix = null;
   4.272 -
   4.273 -        for (DuplicateDescription dd : dupes) {
   4.274 -            for (Span s : dd.dupes) {
   4.275 -                commonPrefix = computeCommonPrefix(commonPrefix, s.file);
   4.276 -            }
   4.277 -        }
   4.278 -
   4.279 -        return commonPrefix != null ? commonPrefix.length() : 0;
   4.280 +    private void findMore() {
   4.281 +        targetCount = duplicatesList.getModel().getSize() + 100;
   4.282 +        findMore.setVisible(false);
   4.283 +        WORKER.schedule(0);
   4.284      }
   4.285  
   4.286      private static String computeCommonPrefix(String origCommonPrefix, FileObject file) {
   4.287 @@ -208,11 +296,6 @@
   4.288          return origCommonPrefix;
   4.289      }
   4.290      
   4.291 -    private void setDiff(DuplicateDescription dd) {
   4.292 -        setSpan(left, dd.dupes.get(0));
   4.293 -        setSpan(right, dd.dupes.get(1));
   4.294 -    }
   4.295 -
   4.296      private static void setSpan(JEditorPane pane, Span s) {
   4.297          try {
   4.298              pane.setText(s.file.asText());
   4.299 @@ -241,17 +324,49 @@
   4.300  
   4.301      private static final AttributeSet HIGHLIGHT = AttributesUtilities.createImmutable(StyleConstants.Background, new Color(0xDF, 0xDF, 0xDF, 0xff));
   4.302  
   4.303 -    private final class RendererImpl extends DefaultListCellRenderer {
   4.304 -        private final boolean left;
   4.305 -        public RendererImpl(boolean left) {
   4.306 -            this.left = left;
   4.307 -        }
   4.308 +    private final class DuplicatesRendererImpl extends DefaultListCellRenderer {
   4.309          @Override
   4.310          public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
   4.311 +            if (!(value instanceof DuplicateDescription)) return super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
   4.312              DuplicateDescription dd = (DuplicateDescription) value;
   4.313 -            String name = left ? FileUtil.getFileDisplayName(dd.dupes.get(0).file).substring(commonPrefixLength) : FileUtil.getFileDisplayName(dd.dupes.get(1).file).substring(commonPrefixLength);
   4.314 +            Set<FileObject> files = new LinkedHashSet<FileObject>();
   4.315 +            String commonPrefix = null;
   4.316  
   4.317 -            return super.getListCellRendererComponent(list, name, index, isSelected, cellHasFocus);
   4.318 +            for (Span s : dd.dupes) {
   4.319 +                commonPrefix = computeCommonPrefix(commonPrefix, s.file);
   4.320 +                files.add(s.file);
   4.321 +            }
   4.322 +
   4.323 +            StringBuilder cap = new StringBuilder();
   4.324 +
   4.325 +            OUTER: for (FileObject file : files) {
   4.326 +                String name = FileUtil.getFileDisplayName(file);
   4.327 +
   4.328 +                if (cap.length() > 0) {
   4.329 +                    cap.append("    ");
   4.330 +                }
   4.331 +                
   4.332 +                for (String sr : sourceRoots) {
   4.333 +                    if (name.startsWith(sr)) {
   4.334 +                        cap.append(name.substring(Math.max(0, sr.lastIndexOf('/') + 1)));
   4.335 +                        continue OUTER;
   4.336 +                    }
   4.337 +                }
   4.338 +            }
   4.339 +
   4.340 +            return super.getListCellRendererComponent(list, cap.toString(), index, isSelected, cellHasFocus);
   4.341 +        }
   4.342 +    }
   4.343 +
   4.344 +    private final class SpanRendererImpl extends DefaultListCellRenderer {
   4.345 +        @Override
   4.346 +        public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
   4.347 +            if (!(value instanceof Span)) {
   4.348 +                return super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
   4.349 +            }
   4.350 +            Span span = (Span) value;
   4.351 +
   4.352 +            return super.getListCellRendererComponent(list, FileUtil.getFileDisplayName(span.file), index, isSelected, cellHasFocus);
   4.353          }
   4.354      }
   4.355  
   4.356 @@ -287,6 +402,7 @@
   4.357      private static final class BalancedSplitPane extends JSplitPane {
   4.358  
   4.359          @Override
   4.360 +        @SuppressWarnings("deprecation")
   4.361          public void reshape(int x, int y, int w, int h) {
   4.362              super.reshape(x, y, w, h);
   4.363              SwingUtilities.invokeLater(new Runnable() {
   4.364 @@ -299,15 +415,50 @@
   4.365      }
   4.366  
   4.367      // Variables declaration - do not modify//GEN-BEGIN:variables
   4.368 +    private javax.swing.JList duplicatesList;
   4.369 +    private javax.swing.JLabel findMore;
   4.370 +    private javax.swing.JPanel jPanel1;
   4.371 +    private javax.swing.JScrollPane jScrollPane1;
   4.372      private javax.swing.JScrollPane jScrollPane2;
   4.373      private javax.swing.JScrollPane jScrollPane3;
   4.374 -    private javax.swing.JScrollPane jScrollPane4;
   4.375 -    private javax.swing.JSplitPane jSplitPane1;
   4.376 -    private javax.swing.JSplitPane jSplitPane2;
   4.377      private javax.swing.JEditorPane left;
   4.378 -    private javax.swing.JList leftList;
   4.379 +    private javax.swing.JComboBox leftFileList;
   4.380 +    private javax.swing.JPanel leftPanel;
   4.381 +    private javax.swing.JSplitPane mainSplit2;
   4.382 +    private javax.swing.JLabel progressLabel;
   4.383      private javax.swing.JEditorPane right;
   4.384 -    private javax.swing.JList rightList;
   4.385 +    private javax.swing.JComboBox rightFileList;
   4.386 +    private javax.swing.JPanel rightPanel;
   4.387      // End of variables declaration//GEN-END:variables
   4.388  
   4.389 +    private static final RequestProcessor DEFAULT_WORKER = new RequestProcessor(DuplicatesListPanel.class.getName(), 1, false, false);
   4.390 +    private final Task WORKER = DEFAULT_WORKER.create(new Runnable() {
   4.391 +        public void run() {
   4.392 +            if (dupes.hasNext()) {
   4.393 +                final DuplicateDescription dd = dupes.next();
   4.394 +
   4.395 +                SwingUtilities.invokeLater(new Runnable() {
   4.396 +
   4.397 +                    public void run() {
   4.398 +                        ((DefaultListModel)duplicatesList.getModel()).addElement(dd);
   4.399 +
   4.400 +                        int size = duplicatesList.getModel().getSize();
   4.401 +
   4.402 +                        if (size == 1) {
   4.403 +                            duplicatesList.setSelectedIndex(0);
   4.404 +                        }
   4.405 +                        
   4.406 +                        if (size >= targetCount) {
   4.407 +                            findMore.setVisible(true);
   4.408 +                            progressLabel.setText("Found " + size + " duplicated snippets.");
   4.409 +                        } else {
   4.410 +                            progressLabel.setText("Found " + size + " duplicated snippets and searching...");
   4.411 +                            WORKER.schedule(0);
   4.412 +                        }
   4.413 +                    }
   4.414 +                });
   4.415 +            }
   4.416 +        }
   4.417 +    });
   4.418 +
   4.419  }
     5.1 --- a/api/src/org/netbeans/modules/jackpot30/impl/duplicates/GlobalFindDuplicates.java	Sat Feb 12 00:49:24 2011 +0100
     5.2 +++ b/api/src/org/netbeans/modules/jackpot30/impl/duplicates/GlobalFindDuplicates.java	Mon Feb 14 20:43:35 2011 +0100
     5.3 @@ -46,18 +46,22 @@
     5.4  import java.awt.event.ActionListener;
     5.5  import java.io.IOException;
     5.6  import java.util.Collection;
     5.7 -import java.util.Collections;
     5.8 +import java.util.Iterator;
     5.9  import java.util.LinkedList;
    5.10  import java.util.concurrent.atomic.AtomicBoolean;
    5.11  import javax.swing.JLabel;
    5.12  import javax.swing.JPanel;
    5.13  import javax.swing.SwingUtilities;
    5.14 +import org.netbeans.api.java.classpath.ClassPath;
    5.15 +import org.netbeans.api.java.classpath.GlobalPathRegistry;
    5.16  import org.netbeans.api.progress.ProgressHandle;
    5.17  import org.netbeans.api.progress.ProgressHandleFactory;
    5.18  import org.netbeans.modules.jackpot30.impl.duplicates.ComputeDuplicates.DuplicateDescription;
    5.19  import org.openide.DialogDescriptor;
    5.20  import org.openide.DialogDisplayer;
    5.21  import org.openide.NotifyDescriptor;
    5.22 +import org.openide.filesystems.FileObject;
    5.23 +import org.openide.filesystems.FileUtil;
    5.24  import org.openide.util.Exceptions;
    5.25  import org.openide.util.HelpCtx;
    5.26  import org.openide.util.RequestProcessor;
    5.27 @@ -65,7 +69,7 @@
    5.28  public final class GlobalFindDuplicates implements ActionListener {
    5.29  
    5.30      public void actionPerformed(ActionEvent e) {
    5.31 -        final Collection<DuplicateDescription> dupes = Collections.synchronizedList(new LinkedList<DuplicateDescription>());
    5.32 +        final Iterator<? extends DuplicateDescription>[] dupes = new Iterator[1];
    5.33          final ProgressHandle handle = ProgressHandleFactory.createHandle("Compute Duplicates");
    5.34          JPanel panel = createPanel(handle);
    5.35          final AtomicBoolean cancel = new AtomicBoolean();
    5.36 @@ -79,11 +83,22 @@
    5.37  
    5.38          final Dialog d = DialogDisplayer.getDefault().createDialog(w);
    5.39          final AtomicBoolean done = new AtomicBoolean();
    5.40 +        final Collection<String> sourceRoots = new LinkedList<String>();
    5.41  
    5.42          WORKER.post(new Runnable() {
    5.43              public void run() {
    5.44                  try {
    5.45 -                    dupes.addAll(new ComputeDuplicates().computeDuplicatesForAllOpenedProjects(handle, cancel));
    5.46 +                    for (ClassPath cp : GlobalPathRegistry.getDefault().getPaths(ClassPath.SOURCE)) {
    5.47 +                        for (ClassPath.Entry e : cp.entries()) {
    5.48 +                            FileObject root = e.getRoot();
    5.49 +
    5.50 +                            if (root == null) continue;
    5.51 +
    5.52 +                            sourceRoots.add(FileUtil.getFileDisplayName(root));
    5.53 +                        }
    5.54 +                    }
    5.55 +
    5.56 +                    dupes[0] = new ComputeDuplicates().computeDuplicatesForAllOpenedProjects(handle, cancel);
    5.57                      done.set(true);
    5.58                  } catch (IOException ex) {
    5.59                      Exceptions.printStackTrace(ex);
    5.60 @@ -111,7 +126,7 @@
    5.61          
    5.62          if (cancel.get()) return;
    5.63  
    5.64 -        NotifyDescriptor nd = new NotifyDescriptor.Message(new DuplicatesListPanel(dupes));
    5.65 +        NotifyDescriptor nd = new NotifyDescriptor.Message(new DuplicatesListPanel(sourceRoots, dupes[0]));
    5.66  
    5.67          DialogDisplayer.getDefault().notifyLater(nd);
    5.68      }
     6.1 --- a/api/test/unit/src/org/netbeans/modules/jackpot30/impl/duplicates/ComputeDuplicatesTest.java	Sat Feb 12 00:49:24 2011 +0100
     6.2 +++ b/api/test/unit/src/org/netbeans/modules/jackpot30/impl/duplicates/ComputeDuplicatesTest.java	Mon Feb 14 20:43:35 2011 +0100
     6.3 @@ -42,6 +42,7 @@
     6.4  import org.netbeans.api.progress.ProgressHandle;
     6.5  import org.openide.filesystems.FileObject;
     6.6  import java.util.HashMap;
     6.7 +import java.util.LinkedList;
     6.8  import java.util.Map;
     6.9  import java.util.concurrent.atomic.AtomicBoolean;
    6.10  import org.netbeans.api.java.source.TestUtilities;
    6.11 @@ -51,6 +52,7 @@
    6.12  import org.netbeans.modules.jackpot30.impl.indexing.IndexTestBase;
    6.13  import org.netbeans.modules.jackpot30.impl.indexing.IndexingTestUtils.File;
    6.14  import org.openide.filesystems.FileUtil;
    6.15 +import org.openide.util.NbCollections;
    6.16  import static org.junit.Assert.*;
    6.17  
    6.18  import static org.netbeans.modules.jackpot30.impl.indexing.IndexingTestUtils.writeFilesAndWaitForScan;
    6.19 @@ -101,7 +103,7 @@
    6.20  
    6.21          handle.start();
    6.22          
    6.23 -        for (DuplicateDescription dd : new ComputeDuplicates().computeDuplicatesForAllOpenedProjects(handle, new AtomicBoolean())) {
    6.24 +        for (DuplicateDescription dd : NbCollections.iterable(new ComputeDuplicates().computeDuplicatesForAllOpenedProjects(handle, new AtomicBoolean()))) {
    6.25              for (Span s : dd.dupes) {
    6.26                  duplicatesReal.put(relativePath(s.file), TestUtilities.copyFileToString(FileUtil.toFile(s.file)).substring(s.startOff, s.endOff));
    6.27              }