KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > modules > subversion > ui > diff > DiffMainPanel


1 /*
2  * The contents of this file are subject to the terms of the Common Development
3  * and Distribution License (the License). You may not use this file except in
4  * compliance with the License.
5  *
6  * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7  * or http://www.netbeans.org/cddl.txt.
8  *
9  * When distributing Covered Code, include this CDDL Header Notice in each file
10  * and include the License file at http://www.netbeans.org/cddl.txt.
11  * If applicable, add the following below the CDDL Header, with the fields
12  * enclosed by brackets [] replaced by your own identifying information:
13  * "Portions Copyrighted [year] [name of copyright owner]"
14  *
15  * The Original Software is NetBeans. The Initial Developer of the Original
16  * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
17  * Microsystems, Inc. All Rights Reserved.
18  */

19
20 package org.netbeans.modules.subversion.ui.diff;
21
22 import java.io.*;
23 import org.netbeans.api.diff.*;
24 import org.netbeans.api.diff.Diff;
25 import org.netbeans.api.diff.DiffView;
26 import org.netbeans.api.diff.StreamSource;
27 import org.netbeans.modules.subversion.*;
28 import org.netbeans.modules.subversion.client.*;
29 import org.netbeans.modules.subversion.ui.commit.*;
30 import org.netbeans.modules.subversion.util.*;
31 import org.netbeans.modules.versioning.util.VersioningListener;
32 import org.netbeans.modules.versioning.util.VersioningEvent;
33 import org.netbeans.modules.versioning.util.DelegatingUndoRedo;
34 import org.netbeans.spi.diff.*;
35 import org.openide.util.Lookup;
36 import org.openide.util.NbBundle;
37 import org.openide.util.RequestProcessor;
38 import org.openide.util.Task;
39 import org.openide.util.TaskListener;
40 import org.openide.util.lookup.Lookups;
41 import org.openide.ErrorManager;
42 import org.openide.LifecycleManager;
43 import org.openide.awt.UndoRedo;
44 import org.openide.nodes.Node;
45 import org.openide.nodes.AbstractNode;
46 import org.openide.nodes.Children;
47 import org.openide.windows.TopComponent;
48 import org.openide.windows.WindowManager;
49 import org.openide.filesystems.FileObject;
50 import org.openide.filesystems.FileUtil;
51
52 import javax.swing.*;
53 import javax.swing.plaf.basic.BasicComboBoxRenderer JavaDoc;
54 import javax.swing.border.CompoundBorder JavaDoc;
55 import java.io.IOException JavaDoc;
56 import java.io.File JavaDoc;
57 import java.util.*;
58 import java.util.List JavaDoc;
59 import java.awt.event.*;
60 import java.awt.*;
61 import java.awt.image.BufferedImage JavaDoc;
62 import org.netbeans.modules.subversion.ui.status.StatusAction;
63 import org.netbeans.modules.subversion.ui.update.UpdateAction;
64 import org.netbeans.modules.subversion.ui.actions.ContextAction;
65
66 /**
67  * Main DIFF GUI panel that includes the navidation toolbar and DIFF component.
68  *
69  * @author Maros Sandor
70  */

71 public class DiffMainPanel extends javax.swing.JPanel JavaDoc implements ActionListener, VersioningListener, DiffSetupSource {
72
73     /**
74      * Array of DIFF setups that we show in the DIFF view. Contents of this array is changed if
75      * the user switches DIFF types.
76      */

77     private Setup[] setups;
78
79     private final DelegatingUndoRedo delegatingUndoRedo = new DelegatingUndoRedo();
80     /**
81      * Context in which to DIFF.
82      */

83     private final Context context;
84
85     private int displayStatuses;
86
87     /**
88      * Display name of the context of this diff.
89      */

90     private final String JavaDoc contextName;
91     
92     private int currentType;
93     private int currentDifferenceIndex;
94     private int currentIndex = -1;
95     
96     private RequestProcessor.Task prepareTask;
97     private DiffPrepareTask dpt;
98
99     private AbstractAction nextAction;
100     private AbstractAction prevAction;
101     
102     // TODO: reuse this code ... the same pattern is in SynchronizePanel
103
private static final RequestProcessor rp = new RequestProcessor("SVN_DIFF", 1); // NOI18N
104

105     /**
106      * null for view that are not
107      */

108     private RequestProcessor.Task refreshTask;
109
110     private JComponent diffView;
111
112     private SvnProgressSupport executeStatusSupport;
113
114     /**
115      * Creates diff panel and immediatelly starts loading...
116      */

117     public DiffMainPanel(Context context, int initialType, String JavaDoc contextName) {
118         this.context = context;
119         this.contextName = contextName;
120         currentType = initialType;
121         initComponents();
122         setupComponents();
123         refreshSetups();
124         refreshComponents();
125         refreshTask = rp.create(new RefreshViewTask());
126     }
127
128     /**
129      * Construct diff component showing just one file.
130      * It hides All, Local, Remote toggles and file chooser combo.
131      */

132     public DiffMainPanel(File JavaDoc file, String JavaDoc rev1, String JavaDoc rev2) {
133         context = null;
134         contextName = file.getName();
135         initComponents();
136         setupComponents();
137         localToggle.setVisible(false);
138         remoteToggle.setVisible(false);
139         allToggle.setVisible(false);
140         navigationCombo.setVisible(false);
141         refreshButton.setVisible(false);
142         updateButton.setVisible(false);
143         commitButton.setVisible(false);
144
145         // mimics refreshSetups()
146
setups = new Setup[] {
147             new Setup(file, rev1, rev2)
148         };
149         setDiffIndex(0, 0);
150         dpt = new DiffPrepareTask(setups);
151         prepareTask = RequestProcessor.getDefault().post(dpt);
152     }
153     
154     /**
155      * Called by the enclosing TopComponent to interrupt the fetching task.
156      */

157     void componentClosed() {
158         setups = null;
159         if (prepareTask != null) {
160             prepareTask.cancel();
161         }
162         if(executeStatusSupport!=null) {
163             executeStatusSupport.cancel();
164         }
165     }
166
167     void requestActive() {
168         if (diffView != null) {
169             diffView.requestFocusInWindow();
170         }
171     }
172
173     public UndoRedo getUndoRedo() {
174         return delegatingUndoRedo;
175     }
176
177     private static class ColoredComboRenderer extends BasicComboBoxRenderer JavaDoc {
178
179         public Component getListCellRendererComponent(JList list, Object JavaDoc value, int index, boolean isSelected, boolean cellHasFocus) {
180             if (isSelected) {
181                 value = ((Setup) value).getBaseFile().getName();
182             }
183             return super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
184         }
185     }
186
187     private void setupComponents() {
188         controlsToolbar.putClientProperty("JToolBar.isRollover", Boolean.TRUE); // NOI18N
189
controlsToolbar.setLayout(new DiffMainPanel.ToolbarLayout());
190         
191         navigationCombo.addActionListener(this);
192         navigationCombo.setRenderer(new ColoredComboRenderer());
193         refreshButton.addActionListener(this);
194         updateButton.addActionListener(this);
195         commitButton.addActionListener(this);
196         localToggle.addActionListener(this);
197         remoteToggle.addActionListener(this);
198         allToggle.addActionListener(this);
199         
200         refreshButton.setToolTipText(NbBundle.getMessage(DiffMainPanel.class, "MSG_RefreshDiff_Tooltip")); // NOI18N
201
updateButton.setToolTipText(NbBundle.getMessage(DiffMainPanel.class, "MSG_UpdateDiff_Tooltip", contextName)); // NOI18N
202
commitButton.setToolTipText(NbBundle.getMessage(DiffMainPanel.class, "MSG_CommitDiff_Tooltip", contextName)); // NOI18N
203
ButtonGroup grp = new ButtonGroup();
204         grp.add(localToggle);
205         grp.add(remoteToggle);
206         grp.add(allToggle);
207         if (currentType == Setup.DIFFTYPE_LOCAL) localToggle.setSelected(true);
208         else if (currentType == Setup.DIFFTYPE_REMOTE) remoteToggle.setSelected(true);
209         else if (currentType == Setup.DIFFTYPE_ALL) allToggle.setSelected(true);
210         
211         nextAction = new AbstractAction(null, new javax.swing.ImageIcon JavaDoc(getClass().getResource("/org/netbeans/modules/subversion/resources/icons/diff-next.png"))) { // NOI18N
212
{
213                 putValue(Action.SHORT_DESCRIPTION, java.util.ResourceBundle.getBundle("org/netbeans/modules/subversion/ui/diff/Bundle"). // NOI18N
214
getString("CTL_DiffPanel_Next_Tooltip")); // NOI18N
215
}
216             public void actionPerformed(ActionEvent e) {
217                 onNextButton();
218             }
219         };
220         prevAction = new AbstractAction(null, new javax.swing.ImageIcon JavaDoc(getClass().getResource("/org/netbeans/modules/subversion/resources/icons/diff-prev.png"))) { // NOI18N
221
{
222                 putValue(Action.SHORT_DESCRIPTION, java.util.ResourceBundle.getBundle("org/netbeans/modules/subversion/ui/diff/Bundle"). // NOI18N
223
getString("CTL_DiffPanel_Prev_Tooltip")); // NOI18N
224
}
225             public void actionPerformed(ActionEvent e) {
226                 onPrevButton();
227             }
228         };
229         nextButton.setAction(nextAction);
230         prevButton.setAction(prevAction);
231     }
232     
233     private void refreshComponents() {
234         DiffView view = setups != null ? setups[currentIndex].getView() : null;
235         if (view != null) {
236             nextAction.setEnabled(currentIndex < setups.length - 1 || currentDifferenceIndex < view.getDifferenceCount() - 1);
237         } else {
238             nextAction.setEnabled(false);
239         }
240         prevAction.setEnabled(currentIndex > 0 || currentDifferenceIndex > 0);
241     }
242     
243     public void addNotify() {
244         super.addNotify();
245         if (refreshTask != null) {
246             Subversion.getInstance().getStatusCache().addVersioningListener(this);
247         }
248         JComponent parent = (JComponent) getParent();
249         parent.getActionMap().put("jumpNext", nextAction); // NOI18N
250
parent.getActionMap().put("jumpPrev", prevAction); // NOI18N
251
}
252
253     public void removeNotify() {
254         Subversion.getInstance().getStatusCache().removeVersioningListener(this);
255         super.removeNotify();
256     }
257     
258     // TODO: reuse this code ... the same pattern is in SynchronizePanel
259
public void versioningEvent(VersioningEvent event) {
260         if (event.getId() == FileStatusCache.EVENT_FILE_STATUS_CHANGED) {
261             if (!affectsView(event)) {
262                 return;
263             }
264             refreshTask.schedule(200);
265         }
266     }
267     
268     private boolean affectsView(VersioningEvent event) {
269         File JavaDoc file = (File JavaDoc) event.getParams()[0];
270         FileInformation oldInfo = (FileInformation) event.getParams()[1];
271         FileInformation newInfo = (FileInformation) event.getParams()[2];
272         if (oldInfo == null) {
273             if ((newInfo.getStatus() & displayStatuses) == 0) return false;
274         } else {
275             if ((oldInfo.getStatus() & displayStatuses) + (newInfo.getStatus() & displayStatuses) == 0) return false;
276         }
277         return context.contains(file);
278     }
279     
280     private void setDiffIndex(int idx, int location) {
281         currentIndex = idx;
282         DiffView view = setups[currentIndex].getView();
283
284         // enable Select in .. action
285
final TopComponent tc = (TopComponent) getClientProperty(TopComponent.class);
286         if (tc != null) {
287             Node node = Node.EMPTY;
288             File JavaDoc baseFile = setups[currentIndex].getBaseFile();
289             if (baseFile != null) {
290                 FileObject fo = FileUtil.toFileObject(baseFile);
291                 if (fo != null) {
292                     node = new AbstractNode(Children.LEAF, Lookups.singleton(fo));
293                 }
294             }
295             final Node[] nodes = new Node[] {node};
296             EventQueue.invokeLater(new Runnable JavaDoc() {
297                 public void run() {
298                     tc.setActivatedNodes(nodes);
299                 }
300             });
301         }
302
303         boolean focus = false;
304         boolean setDifference = false;
305         removeDiffComponent();
306         if (view != null) {
307             if (location == -1) {
308                 location = view.getDifferenceCount() - 1;
309             }
310             if (location >=0 && location < view.getDifferenceCount()) {
311                 setDifference = true;
312             }
313             diffView = (JComponent) view.getComponent();
314             diffView.getActionMap().put("jumpNext", nextAction); // NOI18N
315
diffView.getActionMap().put("jumpPrev", prevAction); // NOI18N
316
Component toc = WindowManager.getDefault().getRegistry().getActivated();
317             if (SwingUtilities.isDescendingFrom(this, toc)) {
318                 focus = true;
319             }
320         } else {
321             diffView = new SourcesUnavailableComponent(NbBundle.getMessage(DiffMainPanel.class, "MSG_DiffPanel_NoContent")); // NOI18N
322
}
323         add(diffView);
324         delegatingUndoRedo.setDiffView(diffView);
325
326         currentDifferenceIndex = location;
327         if (navigationCombo.isVisible()) {
328             navigationCombo.setSelectedIndex(currentIndex);
329         }
330         refreshComponents();
331         revalidate();
332         repaint();
333         if (focus) {
334             diffView.requestFocusInWindow();
335         }
336         // Workaround for Issue #76336. Seems that the MultiDiff component is not fully initialized until calling reXXX methods above
337
if (setDifference) {
338             final int finalLocation = location;
339             final DiffView finalView = view;
340             SwingUtilities.invokeLater(new Runnable JavaDoc() {
341                 public void run() {
342                     finalView.setCurrentDifference(finalLocation);
343                 }
344             });
345         }
346     }
347
348     private void removeDiffComponent() {
349         if (diffView != null) {
350             remove(diffView);
351             diffView = null;
352         }
353     }
354
355     public void actionPerformed(ActionEvent e) {
356         Object JavaDoc source = e.getSource();
357         if (source == navigationCombo) onNavigationCombo();
358         else if (source == refreshButton) onRefreshButton();
359         else if (source == updateButton) onUpdateButton();
360         else if (source == commitButton) onCommitButton();
361         else if (source == localToggle || source == remoteToggle || source == allToggle) onDiffTypeChanged();
362     }
363
364     private void onRefreshButton() {
365         if (context == null || context.getRoots().size() == 0) {
366             return;
367         }
368
369         if(executeStatusSupport!=null) {
370             executeStatusSupport.cancel();
371             executeStatusSupport = null;
372         }
373         
374         LifecycleManager.getDefault().saveAll();
375         RequestProcessor rp = Subversion.getInstance().getRequestProcessor();
376         executeStatusSupport = new SvnProgressSupport() {
377             public void perform() {
378                 StatusAction.executeStatus(context, this);
379             }
380         };
381         refreshSetups();
382     }
383
384     private void onUpdateButton() {
385         UpdateAction.performUpdate(context);
386     }
387
388     private void onCommitButton() {
389         CommitAction.commit(contextName, context);
390     }
391
392     /** Next that is driven by visibility. It continues to next not yet visible difference. */
393     private void onNextButton() {
394         if (navigationCombo.isVisible()) {
395             currentIndex = navigationCombo.getSelectedIndex();
396         }
397
398         DiffView view = setups[currentIndex].getView();
399         if (view != null) {
400             int visibleDiffernce = view.getCurrentDifference();
401             if (visibleDiffernce < view.getDifferenceCount() - 1) {
402                 currentDifferenceIndex = Math.max(currentDifferenceIndex, visibleDiffernce);
403             }
404             if (++currentDifferenceIndex >= view.getDifferenceCount()) {
405                 if (++currentIndex >= setups.length) {
406                     currentIndex--;
407                 } else {
408                     setDiffIndex(currentIndex, 0);
409                 }
410             } else {
411                 view.setCurrentDifference(currentDifferenceIndex);
412             }
413         } else {
414             if (++currentIndex >= setups.length) currentIndex = 0;
415             setDiffIndex(currentIndex, 0);
416         }
417         refreshComponents();
418     }
419
420     private void onPrevButton() {
421         DiffView view = setups[currentIndex].getView();
422         if (view != null) {
423             if (--currentDifferenceIndex < 0) {
424                 if (--currentIndex < 0) {
425                     currentIndex++;
426                 } else {
427                     setDiffIndex(currentIndex, -1);
428                 }
429             } else {
430                 view.setCurrentDifference(currentDifferenceIndex);
431             }
432         } else {
433             if (--currentIndex < 0) currentIndex = setups.length - 1;
434             setDiffIndex(currentIndex, -1);
435         }
436         refreshComponents();
437     }
438
439     private void onNavigationCombo() {
440         int idx = navigationCombo.getSelectedIndex();
441         if (idx != currentIndex) setDiffIndex(idx, 0);
442     }
443
444     /**
445      * @return setups, takes into account Local, Remote, All switch
446      */

447     public Collection getSetups() {
448         if (setups == null) {
449             return Collections.EMPTY_SET;
450         } else {
451             return Arrays.asList(setups);
452         }
453     }
454
455     public String JavaDoc getSetupDisplayName() {
456         return contextName;
457     }
458
459
460     private void refreshSetups() {
461         if (dpt != null) {
462             prepareTask.cancel();
463         }
464
465         File JavaDoc [] files;
466         switch (currentType) {
467         case Setup.DIFFTYPE_LOCAL:
468             displayStatuses = FileInformation.STATUS_LOCAL_CHANGE;
469             break;
470         case Setup.DIFFTYPE_REMOTE:
471             displayStatuses = FileInformation.STATUS_REMOTE_CHANGE;
472             break;
473         case Setup.DIFFTYPE_ALL:
474             displayStatuses = FileInformation.STATUS_LOCAL_CHANGE | FileInformation.STATUS_REMOTE_CHANGE;
475             break;
476         default:
477             throw new IllegalStateException JavaDoc("Unknown DIFF type:" + currentType); // NOI18N
478
}
479         files = SvnUtils.getModifiedFiles(context, displayStatuses);
480         
481         Setup [] newSetups = new Setup[files.length];
482         for (int i = 0; i < newSetups.length; i++) {
483             File JavaDoc file = files[i];
484             newSetups[i] = new Setup(file, currentType);
485         }
486         Arrays.sort(newSetups, new SetupsComparator());
487
488         setups = newSetups;
489         navigationCombo.setModel(new DefaultComboBoxModel(setups));
490
491         if (setups.length == 0) {
492             String JavaDoc noContentLabel;
493             switch (currentType) {
494             case Setup.DIFFTYPE_LOCAL:
495                 noContentLabel = NbBundle.getMessage(DiffMainPanel.class, "MSG_DiffPanel_NoLocalChanges"); // NOI18N
496
break;
497             case Setup.DIFFTYPE_REMOTE:
498                 noContentLabel = NbBundle.getMessage(DiffMainPanel.class, "MSG_DiffPanel_NoRemoteChanges"); // NOI18N
499
break;
500             case Setup.DIFFTYPE_ALL:
501                 noContentLabel = NbBundle.getMessage(DiffMainPanel.class, "MSG_DiffPanel_NoAllChanges"); // NOI18N
502
break;
503             default:
504                 throw new IllegalStateException JavaDoc("Unknown DIFF type:" + currentType); // NOI18N
505
}
506             setups = null;
507             navigationCombo.setModel(new DefaultComboBoxModel(new Object JavaDoc [] { noContentLabel }));
508             navigationCombo.setEnabled(false);
509             navigationCombo.setPreferredSize(null);
510             Dimension dim = navigationCombo.getPreferredSize();
511             navigationCombo.setPreferredSize(new Dimension(dim.width + 1, dim.height));
512             removeDiffComponent();
513             diffView = new SourcesUnavailableComponent(noContentLabel);
514             add(diffView);
515             nextAction.setEnabled(false);
516             prevAction.setEnabled(false);
517             revalidate();
518             repaint();
519         } else {
520             navigationCombo.setEnabled(true);
521             navigationCombo.setPreferredSize(null);
522             Dimension dim = navigationCombo.getPreferredSize();
523             navigationCombo.setPreferredSize(new Dimension(dim.width + 1, dim.height));
524             setDiffIndex(0, 0);
525             dpt = new DiffPrepareTask(setups);
526             prepareTask = RequestProcessor.getDefault().post(dpt);
527         }
528     }
529     
530     private void onDiffTypeChanged() {
531         if (localToggle.isSelected()) {
532             if (currentType == Setup.DIFFTYPE_LOCAL) return;
533             currentType = Setup.DIFFTYPE_LOCAL;
534         } else if (remoteToggle.isSelected()) {
535             if (currentType == Setup.DIFFTYPE_REMOTE) return;
536             currentType = Setup.DIFFTYPE_REMOTE;
537         } else if (allToggle.isSelected()) {
538             if (currentType == Setup.DIFFTYPE_ALL) return;
539             currentType = Setup.DIFFTYPE_ALL;
540         }
541         refreshSetups();
542     }
543
544     /** This method is called from within the constructor to
545      * initialize the form.
546      * WARNING: Do NOT modify this code. The content of this method is
547      * always regenerated by the Form Editor.
548      */

549     // <editor-fold defaultstate="collapsed" desc=" Generated Code ">//GEN-BEGIN:initComponents
550
private void initComponents() {
551         controlsToolbar = new javax.swing.JToolBar JavaDoc();
552         allToggle = new javax.swing.JToggleButton JavaDoc();
553         localToggle = new javax.swing.JToggleButton JavaDoc();
554         remoteToggle = new javax.swing.JToggleButton JavaDoc();
555         navigationCombo = new javax.swing.JComboBox JavaDoc();
556         nextButton = new javax.swing.JButton JavaDoc();
557         prevButton = new javax.swing.JButton JavaDoc();
558         jPanel1 = new javax.swing.JPanel JavaDoc();
559         refreshButton = new javax.swing.JButton JavaDoc();
560         updateButton = new javax.swing.JButton JavaDoc();
561         commitButton = new javax.swing.JButton JavaDoc();
562
563         setLayout(new java.awt.BorderLayout JavaDoc());
564
565         controlsToolbar.setFloatable(false);
566         org.openide.awt.Mnemonics.setLocalizedText(allToggle, org.openide.util.NbBundle.getBundle(DiffMainPanel.class).getString("CTL_DiffPanel_All")); // NOI18N
567
java.util.ResourceBundle JavaDoc bundle = java.util.ResourceBundle.getBundle("org/netbeans/modules/subversion/ui/diff/Bundle"); // NOI18N
568
allToggle.setToolTipText(bundle.getString("CTL_DiffPanel_All_Tooltip")); // NOI18N
569
controlsToolbar.add(allToggle);
570
571         org.openide.awt.Mnemonics.setLocalizedText(localToggle, org.openide.util.NbBundle.getBundle(DiffMainPanel.class).getString("CTL_DiffPanel_Local")); // NOI18N
572
localToggle.setToolTipText(bundle.getString("CTL_DiffPanel_Local_Tooltip")); // NOI18N
573
controlsToolbar.add(localToggle);
574
575         org.openide.awt.Mnemonics.setLocalizedText(remoteToggle, bundle.getString("CTL_DiffPanel_Remote")); // NOI18N
576
remoteToggle.setToolTipText(bundle.getString("CTL_DiffPanel_Remote_Tooltip")); // NOI18N
577
controlsToolbar.add(remoteToggle);
578
579         controlsToolbar.add(navigationCombo);
580         navigationCombo.getAccessibleContext().setAccessibleName("Navigation list");
581         navigationCombo.getAccessibleContext().setAccessibleDescription("Navigation list");
582
583         nextButton.setIcon(new javax.swing.ImageIcon JavaDoc(getClass().getResource("/org/netbeans/modules/subversion/resources/icons/diff-next.png")));
584         nextButton.setToolTipText(bundle.getString("CTL_DiffPanel_Next_Tooltip")); // NOI18N
585
nextButton.setEnabled(false);
586         controlsToolbar.add(nextButton);
587         nextButton.getAccessibleContext().setAccessibleName("Go to next");
588
589         prevButton.setIcon(new javax.swing.ImageIcon JavaDoc(getClass().getResource("/org/netbeans/modules/subversion/resources/icons/diff-prev.png")));
590         prevButton.setToolTipText(bundle.getString("CTL_DiffPanel_Prev_Tooltip")); // NOI18N
591
prevButton.setEnabled(false);
592         controlsToolbar.add(prevButton);
593         prevButton.getAccessibleContext().setAccessibleName("Go to previous");
594
595         jPanel1.setMaximumSize(new java.awt.Dimension JavaDoc(15, 1));
596         jPanel1.setPreferredSize(new java.awt.Dimension JavaDoc(15, 1));
597         controlsToolbar.add(jPanel1);
598
599         refreshButton.setIcon(new javax.swing.ImageIcon JavaDoc(getClass().getResource("/org/netbeans/modules/subversion/resources/icons/refresh.png")));
600         refreshButton.setToolTipText(bundle.getString("MSG_RefreshDiff_Tooltip")); // NOI18N
601
controlsToolbar.add(refreshButton);
602         refreshButton.getAccessibleContext().setAccessibleName("Refresh");
603
604         updateButton.setIcon(new javax.swing.ImageIcon JavaDoc(getClass().getResource("/org/netbeans/modules/subversion/resources/icons/update.png")));
605         updateButton.setToolTipText(bundle.getString("CTL_DiffPanel_Update_Tooltip")); // NOI18N
606
controlsToolbar.add(updateButton);
607         updateButton.getAccessibleContext().setAccessibleName("Update All");
608         updateButton.getAccessibleContext().setAccessibleDescription(org.openide.util.NbBundle.getBundle(DiffMainPanel.class).getString("CTL_Diff_DiffAll")); // NOI18N
609

610         commitButton.setIcon(new javax.swing.ImageIcon JavaDoc(getClass().getResource("/org/netbeans/modules/subversion/resources/icons/commit.png")));
611         commitButton.setToolTipText(bundle.getString("CTL_DiffPanel_Commit_Tooltip")); // NOI18N
612
controlsToolbar.add(commitButton);
613         commitButton.getAccessibleContext().setAccessibleName("Commit All");
614         commitButton.getAccessibleContext().setAccessibleDescription("Commit All Chnages");
615
616         add(controlsToolbar, java.awt.BorderLayout.NORTH);
617
618     }// </editor-fold>//GEN-END:initComponents
619

620     // Variables declaration - do not modify//GEN-BEGIN:variables
621
private javax.swing.JToggleButton JavaDoc allToggle;
622     private javax.swing.JButton JavaDoc commitButton;
623     private javax.swing.JToolBar JavaDoc controlsToolbar;
624     private javax.swing.JPanel JavaDoc jPanel1;
625     private javax.swing.JToggleButton JavaDoc localToggle;
626     private javax.swing.JComboBox JavaDoc navigationCombo;
627     private javax.swing.JButton JavaDoc nextButton;
628     private javax.swing.JButton JavaDoc prevButton;
629     private javax.swing.JButton JavaDoc refreshButton;
630     private javax.swing.JToggleButton JavaDoc remoteToggle;
631     private javax.swing.JButton JavaDoc updateButton;
632     // End of variables declaration//GEN-END:variables
633

634     
635     private class DiffPrepareTask implements Runnable JavaDoc {
636         
637         private final Setup[] prepareSetups;
638
639         public DiffPrepareTask(Setup [] prepareSetups) {
640             this.prepareSetups = prepareSetups;
641         }
642
643         public void run() {
644             final Diff diff = Diff.getDefault();
645             for (int i = 0; i < prepareSetups.length; i++) {
646                 if (prepareSetups != setups) return;
647                 final int fi = i;
648
649                 try {
650                     StreamSource ss1, ss2;
651                     prepareSetups[i].initSources(); // slow network I/O
652
ss1 = prepareSetups[fi].getFirstSource();
653                     ss2 = prepareSetups[fi].getSecondSource();
654                     DiffView view = diff.createDiff(ss1, ss2); // possibly executing slow external diff
655

656                     List JavaDoc propDiffViews = propertyDiffViews(prepareSetups[fi]);
657                     DiffView[] views = new DiffView[propDiffViews.size() +1];
658                     views[0] = view;
659                     for (int v=0; v<propDiffViews.size(); v++) {
660                         views[v+1] = (DiffView) propDiffViews.get(v);
661                     }
662                     view = new MultiDiffView(views, DiffMainPanel.this);
663
664                     final DiffView finalDiffView = view;
665                     SwingUtilities.invokeLater(new Runnable JavaDoc() {
666                         public void run() {
667                             prepareSetups[fi].setView(finalDiffView);
668                             if (prepareSetups != setups) {
669                                 return;
670                             }
671                             if (currentIndex == fi) {
672                                 setDiffIndex(fi, 0);
673                             }
674                         }
675                     });
676                 } catch (IOException JavaDoc e) {
677                     ErrorManager.getDefault().notify(e);
678                 }
679             }
680         }
681     }
682
683     /**
684      * Computes file property diffs.
685      *
686      * <p>FIXME shows local property value changes only, svnClientAdapter
687      * does not provide API to access remote property values.
688      */

689     private List JavaDoc<DiffView> propertyDiffViews(Setup setup) {
690         final Diff diff = Diff.getDefault();
691         List JavaDoc<DiffView> propDiffViews = getEmptyList();
692         if (currentType == Setup.DIFFTYPE_LOCAL ||
693             currentType == Setup.DIFFTYPE_ALL) {
694             DiffProvider diffAlgorithm = (DiffProvider) Lookup.getDefault().lookup(DiffProvider.class);
695             try {
696                 File JavaDoc base = setup.getBaseFile();
697                 PropertiesClient client = new PropertiesClient(base);
698                 Map<String JavaDoc, byte[]> baseProps = client.getBaseProperties();
699                 Map<String JavaDoc, byte[]> localProps = client.getProperties();
700
701                 // detect three changes locally modifiedm locally new and locally removed
702

703                 Set<String JavaDoc> allProps = new TreeSet<String JavaDoc>(localProps.keySet());
704                 allProps.addAll(baseProps.keySet());
705                 propDiffViews = new ArrayList<DiffView>(allProps.size());
706                 Iterator<String JavaDoc> it = allProps.iterator();
707                 while(it.hasNext()) {
708                     String JavaDoc key = it.next();
709                     boolean isBase = baseProps.containsKey(key);
710                     boolean isLocal = localProps.containsKey(key);
711                     if (isBase && isLocal) {
712                         Property p1 = new Property(baseProps.get(key));
713                         Property p2 = new Property(localProps.get(key));
714                         Difference[] diffs = diffAlgorithm.computeDiff(p1.toReader(), p2.toReader());
715                         if (diff != null && diffs.length != 0) {
716                             StreamSource ps1 = StreamSource.createSource(key, NbBundle.getMessage(DiffMainPanel.class, "LBL_Diff_PropertyBase", key), p1.getMIME(), p1.toReader()); // NOI18N
717
StreamSource ps2 = StreamSource.createSource(key, NbBundle.getMessage(DiffMainPanel.class, "LBL_Diff_PropertyLocallyModified", key), p2.getMIME(), p2.toReader()); // NOI18N
718
propDiffViews.add(diff.createDiff(ps1, ps2));
719                         }
720                     } else if (isBase) {
721                         // locally deleted
722
Property p1 = new Property(baseProps.get(key));
723                         Reader r2 = new StringReader(""); // NOI18N
724
StreamSource ps1 = StreamSource.createSource(key, NbBundle.getMessage(DiffMainPanel.class, "LBL_Diff_PropertyBase", key), p1.getMIME(), p1.toReader()); // NOI18N
725
StreamSource ps2 = StreamSource.createSource(key, NbBundle.getMessage(DiffMainPanel.class, "LBL_Diff_PropertyLocallyDeleted", key), "text/plain", r2); // NOI18N
726
propDiffViews.add(diff.createDiff(ps1, ps2));
727                     } else {
728                         Reader r1 = new StringReader(""); // NOI18N
729
Property p2 = new Property(localProps.get(key));
730                         StreamSource ps1 = StreamSource.createSource(key, NbBundle.getMessage(DiffMainPanel.class, "LBL_Diff_Property", key), "text/plain", r1); // NOI18N
731
StreamSource ps2 = StreamSource.createSource(key, NbBundle.getMessage(DiffMainPanel.class, "LBL_Diff_PropertyLocallyNew", key), p2.getMIME(), p2.toReader()); // NOI18N
732
propDiffViews.add(diff.createDiff(ps1, ps2));
733                     }
734                 }
735
736             } catch (IOException JavaDoc ex) {
737                 ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, ex);
738             }
739
740         } else {
741             ErrorManager.getDefault().log("subversion.DiffMainPanel does not support remote property retrievals"); // NOI18N
742
}
743         return propDiffViews;
744     }
745
746     private static final List JavaDoc<DiffView> getEmptyList() {
747         return Collections.emptyList();
748     }
749
750     /** Interprets property blob. */
751     static class Property {
752         final byte[] value;
753
754         Property(Object JavaDoc value) {
755             this.value = (byte[]) value;
756         }
757
758         String JavaDoc getMIME() {
759             return "text/plain"; // NOI18N
760
}
761
762         Reader toReader() {
763             if (SvnUtils.isBinary(value)) {
764                 return new StringReader(NbBundle.getMessage(DiffMainPanel.class, "LBL_Diff_NoBinaryDiff")); // hexa-flexa txt? // NOI18N
765
} else {
766                 try {
767                     return new InputStreamReader(new ByteArrayInputStream(value), "utf8"); // XXX what encoding is used for storing property values in the text file?, is it really UTF-8 // NOI18N
768
} catch (UnsupportedEncodingException ex) {
769                     ErrorManager.getDefault().notify(ex);
770                     return new StringReader("[ERROR: " + ex.getLocalizedMessage() + "]"); // NOI18N
771
}
772             }
773         }
774     }
775
776     private static class SourcesUnavailableComponent extends JComponent {
777         
778         public SourcesUnavailableComponent(String JavaDoc message) {
779             JLabel label = new JLabel(message);
780             setLayout(new BorderLayout());
781             label.setHorizontalAlignment(JLabel.CENTER);
782             add(label, BorderLayout.CENTER);
783         }
784     }
785     
786     /**
787      * Hardcoded toolbar layout. It eliminates need
788      * for nested panels their look is hardly maintanable
789      * accross several look and feels
790      * (e.g. strange layouting panel borders on GTK+).
791      *
792      * <p>It sets authoritatively component height and takes
793      * "prefered" width from components itself.
794      *
795      */

796     private class ToolbarLayout implements LayoutManager {
797
798         /** Expected border height */
799         private int TOOLBAR_HEIGHT_ADJUSTMENT = 10;
800
801         private int TOOLBAR_SEPARATOR_MIN_WIDTH = 12;
802
803         /** Cached toolbar height */
804         private int toolbarHeight = -1;
805
806         /** Guard for above cache. */
807         private Dimension parentSize;
808
809         private Set<JComponent> adjusted = new HashSet<JComponent>();
810
811         public void removeLayoutComponent(Component comp) {
812         }
813
814         public void layoutContainer(Container parent) {
815             Rectangle [] sizes = layout(parent);
816             for (int i = 0; i < sizes.length; i++) {
817                 JComponent comp = (JComponent) parent.getComponent(i);
818                 if (comp.isVisible()) {
819                     comp.setBounds(sizes[i]);
820                 }
821             }
822         }
823
824         private Rectangle [] layout(Container parent) {
825             Dimension dim = DiffMainPanel.this.getSize();
826             Dimension max = parent.getSize();
827             int rowOffset = 0;
828             int maxHeigth = 0;
829
830             List JavaDoc<Rectangle> sizes = new ArrayList<Rectangle>();
831             int components = parent.getComponentCount();
832             int horizont = 0;
833             for (int i = 0; i < components; i++) {
834                 Rectangle rect = new Rectangle();
835                 JComponent comp = (JComponent) parent.getComponent(i);
836                 if (comp.isVisible()) {
837                     rect.setLocation(horizont, rowOffset);
838                     if (comp instanceof AbstractButton) {
839                         adjustToobarButton((AbstractButton)comp);
840                     } else {
841                         adjustToolbarComponentSize(comp);
842                     }
843                     Dimension pref = comp.getPreferredSize();
844                     int width = pref.width;
845                     if (comp instanceof JSeparator && ((dim.height - dim.width) <= 0)) {
846                         width = Math.max(width, TOOLBAR_SEPARATOR_MIN_WIDTH);
847                     }
848     
849                     // in column layout use taller toolbar
850
int height = getToolbarHeight(dim) -1;
851                     maxHeigth = Math.max(maxHeigth, height);
852                     rect.setSize(width, height); // 1 verySoftBevel compensation
853
horizont += width;
854                     if (horizont > max.width) {
855                         rowOffset += maxHeigth + 2;
856                         horizont = 0;
857                         maxHeigth = 0;
858                     }
859                 }
860                 sizes.add(rect);
861             }
862             return sizes.toArray(new Rectangle[sizes.size()]);
863         }
864         
865         public void addLayoutComponent(String JavaDoc name, Component comp) {
866         }
867
868         public Dimension minimumLayoutSize(Container parent) {
869
870             // in column layout use taller toolbar
871
Dimension dim = DiffMainPanel.this.getSize();
872             int height = getToolbarHeight(dim);
873
874             int components = parent.getComponentCount();
875             int horizont = 0;
876             for (int i = 0; i<components; i++) {
877                 Component comp = parent.getComponent(i);
878                 if (comp.isVisible() == false) continue;
879                 if (comp instanceof AbstractButton) {
880                     adjustToobarButton((AbstractButton)comp);
881                 } else {
882                     adjustToolbarComponentSize((JComponent)comp);
883                 }
884                 Dimension pref = comp.getPreferredSize();
885                 int width = pref.width;
886                 if (comp instanceof JSeparator && ((dim.height - dim.width) <= 0)) {
887                     width = Math.max(width, TOOLBAR_SEPARATOR_MIN_WIDTH);
888                 }
889                 horizont += width;
890             }
891
892             return new Dimension(horizont, height);
893         }
894
895         public Dimension preferredLayoutSize(Container parent) {
896             Rectangle [] bounds = layout(parent);
897             Rectangle union = new Rectangle();
898             for (int i = 0; i < bounds.length; i++) {
899                 union.add(bounds[i]);
900             }
901             return new Dimension(union.width, union.height);
902         }
903
904         /**
905          * Computes vertical toolbar components height that can used for layout manager hinting.
906          * @return size based on font size and expected border.
907          */

908         private int getToolbarHeight(Dimension parent) {
909
910             if (parentSize == null || (parentSize.equals(parent) == false)) {
911                 parentSize = parent;
912                 toolbarHeight = -1;
913             }
914
915             if (toolbarHeight == -1) {
916                 BufferedImage JavaDoc image = new BufferedImage JavaDoc(1,1,BufferedImage.TYPE_BYTE_GRAY);
917                 Graphics2D g = image.createGraphics();
918                 UIDefaults def = UIManager.getLookAndFeelDefaults();
919
920                 int height = 0;
921                 String JavaDoc[] fonts = {"Label.font", "Button.font", "ToggleButton.font"}; // NOI18N
922
for (int i=0; i<fonts.length; i++) {
923                     Font f = def.getFont(fonts[i]);
924                     FontMetrics fm = g.getFontMetrics(f);
925                     height = Math.max(height, fm.getHeight());
926                 }
927                 toolbarHeight = height + TOOLBAR_HEIGHT_ADJUSTMENT;
928             }
929
930             return toolbarHeight;
931         }
932
933
934         /** Toolbar controls must be smaller and should be transparent*/
935         private void adjustToobarButton(final AbstractButton button) {
936
937             if (adjusted.contains(button)) return;
938
939             // workaround for Ocean L&F clutter - toolbars use gradient.
940
// To make the gradient visible under buttons the content area must not
941
// be filled. To support rollover it must be temporarily filled
942
if (button instanceof JToggleButton == false) {
943                 button.setContentAreaFilled(false);
944                 button.setMargin(new Insets(0, 3, 0, 3));
945                 button.setBorderPainted(false);
946                 button.addMouseListener(new MouseAdapter() {
947                     public void mouseEntered(MouseEvent e) {
948                         button.setContentAreaFilled(true);
949                         button.setBorderPainted(true);
950                     }
951
952                     public void mouseExited(MouseEvent e) {
953                         button.setContentAreaFilled(false);
954                         button.setBorderPainted(false);
955                     }
956                 });
957             }
958
959             adjustToolbarComponentSize(button);
960         }
961
962         private void adjustToolbarComponentSize(JComponent button) {
963
964             if (adjusted.contains(button)) return;
965
966             // as we cannot get the button small enough using the margin and border...
967
if (button.getBorder() instanceof CompoundBorder JavaDoc) { // from BasicLookAndFeel
968
Dimension pref = button.getPreferredSize();
969
970                 // XXX #41827 workaround w2k, that adds eclipsis (...) instead of actual text
971
if ("Windows".equals(UIManager.getLookAndFeel().getID())) { // NOI18N
972
pref.width += 9;
973                 }
974                 button.setPreferredSize(pref);
975             }
976
977             adjusted.add(button);
978         }
979     }
980
981     private static class SetupsComparator implements Comparator<Setup> {
982
983         private SvnUtils.ByImportanceComparator delegate = new SvnUtils.ByImportanceComparator();
984         private FileStatusCache cache;
985
986         public SetupsComparator() {
987             cache = Subversion.getInstance().getStatusCache();
988         }
989
990         public int compare(Setup setup1, Setup setup2) {
991             int cmp = delegate.compare(cache.getStatus(setup1.getBaseFile()), cache.getStatus(setup2.getBaseFile()));
992             if (cmp == 0) {
993                 return setup1.getBaseFile().getName().compareToIgnoreCase(setup2.getBaseFile().getName());
994             }
995             return cmp;
996         }
997     }
998
999     private class RefreshViewTask implements Runnable JavaDoc {
1000        public void run() {
1001            SwingUtilities.invokeLater(new Runnable JavaDoc() {
1002                public void run() {
1003                    refreshSetups();
1004                }
1005            });
1006        }
1007    }
1008}
1009
Popular Tags