4e6d918a8ba2a787a2f7fd7fa81a486a3da80071
[debian/jabref.git] / src / java / net / sf / jabref / DuplicateSearch.java
1 /*
2 Copyright (C) 2003 Nizar N. Batada, Morten O. Alver
3
4 All programs in this directory and
5 subdirectories are published under the GNU General Public License as
6 described below.
7
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or (at
11 your option) any later version.
12
13 This program is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
21 USA
22
23 Further information about the GNU GPL is available at:
24 http://www.gnu.org/copyleft/gpl.ja.html
25
26 */
27
28 // created by : ?
29 //
30 // modified : r.nagel 2.09.2004
31 //            - new SearcherThread.setFinish() method
32 //            - replace thread.sleep in run() by wait() and notify() mechanism
33
34 package net.sf.jabref;
35
36 import net.sf.jabref.undo.NamedCompound;
37 import net.sf.jabref.undo.UndoableRemoveEntry;
38 import java.util.Vector;
39
40 public class DuplicateSearch extends Thread {
41
42   BasePanel panel;
43   BibtexEntry[] bes;
44   final Vector duplicates = new Vector();
45
46   public DuplicateSearch(BasePanel bp) {
47     panel = bp;
48   }
49
50 public void run() {
51   NamedCompound ce = null;
52   int duplicateCounter = 0;
53   panel.output(Globals.lang("Searching for duplicates..."));
54   Object[] keys = panel.database.getKeySet().toArray();
55   if ((keys == null) || (keys.length < 2))
56     return;
57   bes = new BibtexEntry[keys.length];
58   for (int i=0; i<keys.length; i++)
59     bes[i] = panel.database.getEntryById((String)keys[i]);
60
61   SearcherThread st = new SearcherThread();
62   st.setPriority(Thread.MIN_PRIORITY);
63   st.start();
64   int current = 0;
65   DuplicateResolverDialog drd = null;
66
67 /*
68   loop: while (!st.finished() || (current < duplicates.size()))
69   {
70     if ( current >= duplicates.size() )
71     {
72       // No more duplicates to resolve, but search is still in progress. Sleep a little.
73        try
74        {
75          sleep(10);
76        } catch (InterruptedException ex) {}
77        continue loop;
78     }
79   }
80 */
81
82   while (!st.finished() || (current < duplicates.size()))
83   {
84     if (current >= duplicates.size() )
85     {
86       // wait until the search thread puts something into duplicates vector
87       // or finish its work
88       synchronized(duplicates)
89       {
90          try
91          {
92            duplicates.wait();
93          }
94          catch (Exception e) {}
95       }
96     } else  // duplicates found
97     {
98       BibtexEntry[] be = ( BibtexEntry[] ) duplicates.get( current ) ;
99       current++ ;
100       if ( ( panel.database.getEntryById( be[0].getId() ) != null ) &&
101            ( panel.database.getEntryById( be[1].getId() ) != null ) )
102       {
103
104         drd = new DuplicateResolverDialog( panel.frame, be[0], be[1],
105                                            DuplicateResolverDialog.DUPLICATE_SEARCH) ;
106         drd.setVisible(true); // drd.show(); -> deprecated since 1.5
107
108         duplicateCounter++ ;
109         int answer = drd.getSelected() ;
110         if ( answer == DuplicateResolverDialog.KEEP_UPPER )
111         {
112           if ( ce == null ) ce = new NamedCompound(Globals.lang("duplicate removal")) ;
113           panel.database.removeEntry( be[1].getId() ) ;
114           panel.markBaseChanged() ;
115           ce.addEdit( new UndoableRemoveEntry( panel.database, be[1], panel ) ) ;
116         }
117         else if ( answer == DuplicateResolverDialog.KEEP_LOWER )
118         {
119           if ( ce == null ) ce = new NamedCompound(Globals.lang("duplicate removal")) ;
120           panel.database.removeEntry( be[0].getId() ) ;
121           panel.markBaseChanged() ;
122           ce.addEdit( new UndoableRemoveEntry( panel.database, be[0], panel ) ) ;
123         }
124         else if ( answer == DuplicateResolverDialog.BREAK )
125         {
126           st.setFinished() ; // thread killing
127           current = Integer.MAX_VALUE ;
128           duplicateCounter-- ; // correct counter
129         }
130         drd.dispose();
131       }
132     }
133   }
134
135   if (drd != null)
136     drd.dispose();
137
138   panel.output(Globals.lang("Duplicate pairs found") + ": " + duplicates.size()
139                +" " +Globals.lang("pairs processed") +": " +duplicateCounter );
140
141   if (ce != null)
142   {
143     ce.end();
144     //Util.pr("ox");
145     panel.undoManager.addEdit(ce);
146     //markBaseChanged();
147     //refreshTable();
148   }
149 }
150
151
152 class SearcherThread extends Thread {
153
154   private boolean finished = false;
155
156   public void run() {
157     for (int i = 0; (i < bes.length - 1) && !finished ; i++) {
158       for (int j = i + 1; (j < bes.length) && !finished ; j++) {
159         boolean eq = Util.isDuplicate(bes[i], bes[j],
160                                       Globals.duplicateThreshold);
161
162         // If (suspected) duplicates, add them to the duplicates vector.
163         if (eq)
164         {
165           synchronized (duplicates)
166           {
167             duplicates.add( new BibtexEntry[] {bes[i], bes[j]} ) ;
168             duplicates.notifyAll(); // send wake up all
169           }
170         }
171       }
172     }
173     finished = true;
174
175     // if no duplicates found, the graphical thread will never wake up
176     synchronized(duplicates)
177     {
178       duplicates.notifyAll();
179     }
180   }
181
182   public boolean finished() {
183     return finished;
184   }
185
186   // Thread cancel option
187   // no synchronized used because no "realy" critical situations expected
188   public void setFinished()
189   {
190     finished = true ;
191   }
192 }
193
194 }