~vcs-imports/xena/trunk

« back to all changes in this revision

Viewing changes to ext/src/javahelp/jhMaster/JavaHelp/src/new/javax/help/plaf/basic/.svn/text-base/BasicFavoritesNavigatorUI.java.svn-base

  • Committer: matthewoliver
  • Date: 2009-12-10 03:18:07 UTC
  • Revision ID: vcs-imports@canonical.com-20091210031807-l086qguzdlljtkl9
Merged Xena Testing into Xena Stable for the Xena 5 release.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * @(#)BasicFavoritesNavigatorUI.java   1.17 06/10/30
 
3
 * 
 
4
 * Copyright (c) 2006 Sun Microsystems, Inc.  All Rights Reserved.
 
5
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 
6
 * 
 
7
 * This code is free software; you can redistribute it and/or modify it
 
8
 * under the terms of the GNU General Public License version 2 only, as
 
9
 * published by the Free Software Foundation.  Sun designates this
 
10
 * particular file as subject to the "Classpath" exception as provided
 
11
 * by Sun in the LICENSE file that accompanied this code.
 
12
 * 
 
13
 * This code is distributed in the hope that it will be useful, but WITHOUT
 
14
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 
15
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 
16
 * version 2 for more details (a copy is included in the LICENSE file that
 
17
 * accompanied this code).
 
18
 * 
 
19
 * You should have received a copy of the GNU General Public License version
 
20
 * 2 along with this work; if not, write to the Free Software Foundation,
 
21
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 
22
 * 
 
23
 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
 
24
 * CA 95054 USA or visit www.sun.com if you need additional information or
 
25
 * have any questions.
 
26
 */
 
27
 
 
28
package javax.help.plaf.basic;
 
29
 
 
30
import javax.help.*;
 
31
import javax.help.plaf.HelpNavigatorUI;
 
32
import javax.help.plaf.HelpUI;
 
33
import javax.help.event.HelpModelListener;
 
34
import javax.help.event.HelpModelEvent;
 
35
import java.util.EventObject;
 
36
import java.util.Enumeration;
 
37
import java.util.Hashtable;
 
38
import java.util.Vector;
 
39
import java.util.Locale;
 
40
import java.util.HashMap;
 
41
import javax.swing.*;
 
42
import javax.swing.plaf.ComponentUI;
 
43
import javax.swing.tree.*;
 
44
import javax.swing.event.*;
 
45
import java.awt.*;
 
46
import java.awt.event.*;
 
47
import java.io.Reader;
 
48
import java.io.Serializable;
 
49
import java.net.URL;
 
50
import java.net.URLConnection;
 
51
import java.beans.PropertyChangeEvent;
 
52
import java.beans.PropertyChangeListener;
 
53
import java.awt.event.ComponentEvent;
 
54
import javax.help.Map.ID;
 
55
import java.text.Collator;
 
56
import java.text.RuleBasedCollator;
 
57
import java.net.MalformedURLException;
 
58
import java.util.HashSet;
 
59
import javax.help.event.HelpSetListener;
 
60
import javax.help.event.HelpSetEvent;
 
61
import java.awt.Cursor;
 
62
import java.awt.image.BufferedImage;
 
63
import java.awt.geom.Rectangle2D.Float;
 
64
import java.awt.geom.Rectangle2D;
 
65
import java.awt.geom.AffineTransform;
 
66
import java.awt.datatransfer.*;
 
67
import java.awt.dnd.*;
 
68
import java.awt.dnd.peer.*;
 
69
import java.io.IOException;
 
70
 
 
71
/**
 
72
 * The default UI for JHelpNavigator of type Favorites
 
73
 *
 
74
 * @author Richard Gregor
 
75
 * @version     1.17    10/30/06
 
76
 */
 
77
 
 
78
public class BasicFavoritesNavigatorUI extends HelpNavigatorUI
 
79
implements HelpModelListener, TreeSelectionListener, HelpSetListener,
 
80
PropertyChangeListener, TreeModelListener, Serializable {
 
81
    
 
82
    protected JHelpFavoritesNavigator favorites;
 
83
    protected JScrollPane sp;
 
84
    protected FavoritesNode topNode;
 
85
    protected JTree tree;
 
86
    private   String contentTitle;
 
87
    protected RuleBasedCollator rbc;
 
88
    protected String oldText;
 
89
    protected DefaultMutableTreeNode currentFindNode;
 
90
    protected Action addAction;
 
91
    protected Action removeAction;
 
92
    protected Action cutAction;
 
93
    protected Action pasteAction;
 
94
    protected Action copyAction;
 
95
    protected Action folderAction;
 
96
    protected JPopupMenu popup;
 
97
    
 
98
    private   HashMap dataMap = new HashMap();
 
99
    // node wich will contain parsed favorites data
 
100
    private   FavoritesNode favNode = null;
 
101
    // node which contents will be saved
 
102
    private   FavoritesNode rootNode = null;
 
103
    private   Locale locale = null;
 
104
    private   FavoritesNode selectedNode = null;
 
105
    private   FavoritesItem selectedItem = null;
 
106
    private   TreePath selectedTreePath = null;
 
107
    private   Map.ID selectedID = null;
 
108
    private   JMenuItem newFolderMI = null;
 
109
    private   JMenuItem addMI = null;
 
110
    private   JSeparator separatorMI = null;
 
111
    private   JMenuItem cutMI = null;
 
112
    private   JMenuItem copyMI = null;
 
113
    private   JMenuItem pasteMI = null;
 
114
    private   JMenuItem removeMI = null;
 
115
    private   HashMap hsMap = null;
 
116
    //HasMap with visible node from favNode as key and its related node from rootNode as a value
 
117
    private   HashMap connections = new HashMap();
 
118
    /**
 
119
     * Vector of nodes used in CutAction
 
120
     */
 
121
    private   Vector nodeClipboard = new Vector();
 
122
 
 
123
    static private boolean on1dot3 = false;
 
124
 
 
125
    static {
 
126
        try {
 
127
            // Test if method introduced in 1.3 or greater is available.
 
128
            Class klass = Class.forName("javax.swing.InputVerifier");
 
129
            on1dot3 = (klass != null);
 
130
        } catch (ClassNotFoundException e) {
 
131
            on1dot3 = false;
 
132
        }
 
133
    }
 
134
 
 
135
    
 
136
    public static ComponentUI createUI(JComponent x) {
 
137
        return new BasicFavoritesNavigatorUI((JHelpFavoritesNavigator) x);
 
138
    }
 
139
    /**
 
140
     * Creates BasicFavoritesUI for JHelpFavoritesNavigator
 
141
     */
 
142
    public BasicFavoritesNavigatorUI(JHelpFavoritesNavigator b) {
 
143
        ImageIcon icon = getImageIcon(b.getNavigatorView());
 
144
        if (icon != null) {
 
145
            setIcon(icon);
 
146
        } else {
 
147
            setIcon(UIManager.getIcon("FavoritesNav.icon")); 
 
148
        }
 
149
    }
 
150
    
 
151
    public void installUI(JComponent c) {
 
152
        debug("installUI");
 
153
        
 
154
        locale = HelpUtilities.getLocale(c);
 
155
        addAction = new AddAction();
 
156
        removeAction = new RemoveAction();
 
157
        folderAction = new FolderAction();
 
158
        favorites = (JHelpFavoritesNavigator)c;
 
159
        HelpModel model = favorites.getModel();
 
160
        
 
161
        favorites.setLayout(new BorderLayout());
 
162
        favorites.addPropertyChangeListener(this);
 
163
        if (model != null) {
 
164
            model.addHelpModelListener(this); // for our own changes
 
165
            model.addPropertyChangeListener(this); // for HelpSet change
 
166
            HelpSet helpSet = model.getHelpSet();
 
167
            if(helpSet != null)
 
168
                helpSet.addHelpSetListener(this);
 
169
        }
 
170
        
 
171
        topNode = new FavoritesNode(new FavoritesItem("Favorites"));
 
172
        if (on1dot3) {
 
173
            // Use drag and drop if available
 
174
            tree = new FavoritesTree(topNode);
 
175
        } else {
 
176
            tree = new JTree(topNode);
 
177
        }
 
178
        tree.setEditable(true);
 
179
        tree.addMouseListener(new PopupListener());
 
180
        
 
181
        cutAction = new CutAction();
 
182
        copyAction = new CopyAction();
 
183
        pasteAction = new PasteAction();
 
184
        
 
185
        popup = new JPopupMenu();
 
186
        
 
187
        newFolderMI = new JMenuItem((String)folderAction.getValue(folderAction.NAME));
 
188
        newFolderMI.addActionListener(folderAction);
 
189
        popup.add(newFolderMI);
 
190
        
 
191
        addMI = new JMenuItem((String)addAction.getValue(addAction.NAME));
 
192
        addMI.addActionListener(addAction);
 
193
        popup.add(addMI);
 
194
 
 
195
        separatorMI = new JSeparator();
 
196
        popup.add(separatorMI);
 
197
        
 
198
        cutMI = new JMenuItem((String)cutAction.getValue(cutAction.NAME));
 
199
        cutMI.addActionListener(cutAction);
 
200
        cutMI.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_X,java.awt.Event.CTRL_MASK));
 
201
        popup.add(cutMI);
 
202
        
 
203
        copyMI = new JMenuItem((String)copyAction.getValue(copyAction.NAME));
 
204
        copyMI.addActionListener(copyAction);
 
205
        copyMI.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_C,java.awt.Event.CTRL_MASK));
 
206
        popup.add(copyMI);
 
207
        
 
208
        pasteMI = new JMenuItem((String)pasteAction.getValue(pasteAction.NAME));
 
209
        pasteMI.addActionListener(pasteAction);
 
210
        pasteMI.setEnabled(false);
 
211
        pasteMI.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_V,java.awt.Event.CTRL_MASK));
 
212
        popup.add(pasteMI);
 
213
        
 
214
        removeMI = new JMenuItem((String) removeAction.getValue(removeAction.NAME));
 
215
        removeMI.addActionListener(removeAction);
 
216
        
 
217
        popup.add(removeMI);
 
218
        
 
219
        tree.getModel().addTreeModelListener(this);
 
220
        tree.addTreeSelectionListener(this);
 
221
        
 
222
        TreeSelectionModel tsm = tree.getSelectionModel();
 
223
        tsm.addTreeSelectionListener(this);
 
224
        
 
225
        tree.setShowsRootHandles(true);
 
226
        tree.setRootVisible(false);
 
227
        
 
228
        setCellRenderer(favorites.getNavigatorView(), tree);
 
229
 
 
230
        sp = new JScrollPane();
 
231
        sp.getViewport().add(tree);
 
232
        
 
233
        favorites.add("Center", sp);
 
234
        
 
235
        reloadData();
 
236
    }
 
237
    
 
238
    /**
 
239
     * Sets the desired cell renderer on this tree.  This is exposed for redefinition
 
240
     * by subclases.
 
241
     */
 
242
    protected void setCellRenderer(NavigatorView view, JTree tree) {
 
243
        tree.setCellRenderer(new BasicFavoritesCellRenderer());
 
244
    }
 
245
    
 
246
    public void uninstallUI(JComponent c) {
 
247
        debug("uninstallUI");
 
248
        HelpModel model = favorites.getModel();
 
249
        
 
250
        favorites.removePropertyChangeListener(this);
 
251
        TreeSelectionModel tsm = tree.getSelectionModel();
 
252
        tsm.removeTreeSelectionListener(this);
 
253
        favorites.setLayout(null);
 
254
        favorites.removeAll();
 
255
        
 
256
        if (model != null) {
 
257
            model.removeHelpModelListener(this);
 
258
        }
 
259
        
 
260
        favorites = null;
 
261
    }
 
262
    
 
263
    public Dimension getPreferredSize(JComponent c) {
 
264
        
 
265
        return new Dimension(200,100);
 
266
        
 
267
    }
 
268
    
 
269
    public Dimension getMinimumSize(JComponent c) {
 
270
        return new Dimension(100,100);
 
271
    }
 
272
    
 
273
    public Dimension getMaximumSize(JComponent c) {
 
274
        return new Dimension(Short.MAX_VALUE, Short.MAX_VALUE);
 
275
    }
 
276
    
 
277
    
 
278
    private void reloadData() {
 
279
        debug("reloadData");
 
280
        
 
281
        //needs refactoring - sholudn't parse each time!!! - only once
 
282
        
 
283
        if (favorites.getModel() == null) {
 
284
            return;
 
285
        }
 
286
        
 
287
        // remove all children
 
288
        topNode.removeAllChildren();
 
289
        
 
290
        FavoritesView view = (FavoritesView) favorites.getNavigatorView();
 
291
        
 
292
        if (view == null) {
 
293
            return;
 
294
        }
 
295
 
 
296
        favNode = view.getDataAsTree();
 
297
        rootNode = favNode.getDeepCopy();
 
298
 
 
299
        classifyNode(favNode);
 
300
        while (favNode.getChildCount() > 0) {
 
301
            // this looks strange but as you add a child to the top node
 
302
            // it removes the child from the favNode so the getFirstChild
 
303
            // will always get the first child
 
304
            topNode.add((DefaultMutableTreeNode)favNode.getFirstChild());
 
305
        }
 
306
        
 
307
        // reload the tree data
 
308
        ((DefaultTreeModel)tree.getModel()).reload();
 
309
        
 
310
        setVisibility(topNode);        
 
311
        
 
312
    }
 
313
    
 
314
    /**
 
315
     * Classifies the node. Determines wheter child will be visible or not according to node's HelpSet.
 
316
     * Hides node without children when its HelpSet is not loaded
 
317
     *
 
318
     * @param node The FavoritesNode
 
319
     */
 
320
    private void classifyNode(FavoritesNode node){
 
321
        debug("classifyNode");
 
322
        
 
323
        if(node == null)
 
324
            return;
 
325
        
 
326
        HelpModel model = favorites.getModel();
 
327
        if(model == null){
 
328
            node.removeAllChildren();
 
329
            return;
 
330
        }
 
331
        HelpSet masterHelpSet = model.getHelpSet();
 
332
        if(masterHelpSet == null){
 
333
            node.removeAllChildren();
 
334
            return;
 
335
        }
 
336
        hsMap = new HashMap();
 
337
        hsMap.put(masterHelpSet.getTitle(), masterHelpSet);
 
338
        
 
339
        fillHelpSetTitles(masterHelpSet);
 
340
        
 
341
        // tags node's children wheter they are visible or not
 
342
        classifyChildren(node);
 
343
        
 
344
    }
 
345
    
 
346
    /**
 
347
     * Fills HashMap with actual HelpSets and their titles
 
348
     *
 
349
     * @param masterHelpSet The master HelpSet
 
350
     */
 
351
    private void fillHelpSetTitles(HelpSet masterHelpSet){
 
352
        for(Enumeration helpSets = masterHelpSet.getHelpSets();helpSets.hasMoreElements();){
 
353
            HelpSet hs = (HelpSet) helpSets.nextElement();
 
354
            if(hs != null){
 
355
                hsMap.put(hs.getTitle(), hs);
 
356
                debug(" fill title: "+hs.getTitle());
 
357
                fillHelpSetTitles(hs);
 
358
            }
 
359
        }
 
360
    }
 
361
    
 
362
    /**
 
363
     * Classifies children of node
 
364
     *
 
365
     * @param node The FavoritesNode
 
366
     */
 
367
    private void classifyChildren(FavoritesNode node){
 
368
        debug("classifyChildren: "+node);
 
369
        
 
370
        if(node == null)
 
371
            return;
 
372
        
 
373
        boolean skipChild = true;
 
374
 
 
375
        for(Enumeration children = node.preorderEnumeration();children.hasMoreElements();){
 
376
            FavoritesNode chnode = (FavoritesNode)children.nextElement();
 
377
 
 
378
            // Skip the first entry because it is node and we don't need
 
379
            // to classify the node only it's children
 
380
            if (skipChild) {
 
381
                skipChild = false;
 
382
                continue;
 
383
            }
 
384
 
 
385
            // Add this child node to the root node. 
 
386
 
 
387
            // Make a copy of the child node for the rootNode 
 
388
            FavoritesNode copy = chnode.getDeepCopy();
 
389
 
 
390
            // establish the connection between the chnode and the copy
 
391
            connections.put(chnode, copy);
 
392
            // properly connect it to the childs corresponding parent in the 
 
393
            // rootnode. 
 
394
            FavoritesNode rootParent = (FavoritesNode)connections.get(chnode.getParent());
 
395
            if (rootParent == null) {
 
396
                rootParent = rootNode;
 
397
            }
 
398
            rootParent.add(copy);
 
399
 
 
400
            // Now on to seeing if the item
 
401
            FavoritesItem item = (FavoritesItem)chnode.getUserObject();
 
402
            debug("classify item: "+ item);
 
403
            //shouldn't happen
 
404
            if(item == null){
 
405
                debug("item is null : fillDataMap");
 
406
                continue;
 
407
            }
 
408
            String target = item.getTarget();
 
409
            String hsTitle = item.getHelpSetTitle();
 
410
            if(!hsMap.containsKey(hsTitle)){
 
411
                if(chnode.getVisibleChildCount() == 0){
 
412
                    if(item.emptyInitState() && item.isFolder()){
 
413
                        debug("empty init state");
 
414
                        continue;
 
415
                    }
 
416
                    //chnode.removeFromParent();
 
417
                    item.setVisible(false);
 
418
                    continue;
 
419
                }
 
420
            }
 
421
            
 
422
            if(target == null){
 
423
                debug("target is null:fillDataMap");
 
424
                continue;
 
425
            }
 
426
            
 
427
            Map.ID id = null;
 
428
            try{
 
429
                id = Map.ID.create(target, (HelpSet)hsMap.get(hsTitle));
 
430
            }catch(BadIDException ep){
 
431
                debug(ep.getMessage());
 
432
                continue;
 
433
            }
 
434
            
 
435
            debug("put to the dataMap: "+item);
 
436
            dataMap.put(item,id);
 
437
        }
 
438
        
 
439
        //clear node
 
440
        Vector toRemove = new Vector();
 
441
        Enumeration nodesToRem = node.breadthFirstEnumeration();
 
442
        while(nodesToRem.hasMoreElements()) {
 
443
            FavoritesNode fn = (FavoritesNode)nodesToRem.nextElement();
 
444
            if(!fn.isVisible()){
 
445
                debug ("remove node:" +(FavoritesItem)fn.getUserObject());
 
446
                toRemove.addElement(fn);
 
447
            }
 
448
        }
 
449
        for (int i=0; i < toRemove.size(); i++) {
 
450
            debug("removing " +  toRemove.elementAt(i));
 
451
            try {
 
452
                node.remove((DefaultMutableTreeNode) toRemove.elementAt(i));
 
453
            } catch (IllegalArgumentException iae) {
 
454
                // ignore - supernode is already removed
 
455
            }
 
456
        }
 
457
        
 
458
    }
 
459
    
 
460
    /**
 
461
     * Expands entry path and entry itself( when entry is not empty) for specific id
 
462
     *
 
463
     * @param target The target of entry
 
464
     */
 
465
    
 
466
    private void expand(String target){
 
467
        debug("expand called");
 
468
        //find all nodes with certain id
 
469
        Enumeration nodes = findNodes(target).elements();
 
470
        DefaultMutableTreeNode node = null;
 
471
        
 
472
        while(nodes.hasMoreElements()){
 
473
            node = (DefaultMutableTreeNode)nodes.nextElement();
 
474
            debug("expandPath :"+node);
 
475
            if(node.getChildCount() > 0){
 
476
                DefaultMutableTreeNode child =(DefaultMutableTreeNode) node.getFirstChild();
 
477
                TreePath path = new TreePath(child.getPath());
 
478
                tree.makeVisible(path);
 
479
            }
 
480
            else{
 
481
                TreeNode[] treeNode = node.getPath();
 
482
                TreePath path = new TreePath(treeNode);
 
483
                //tree.scrollPathToVisible(path);
 
484
                tree.makeVisible(path);
 
485
            }
 
486
        }
 
487
    }
 
488
    
 
489
    /**
 
490
     * Returns all nodes with certain id
 
491
     *
 
492
     * @param target The target of entry
 
493
     *
 
494
     */
 
495
    private Vector findNodes(String target){
 
496
        Enumeration nodes = topNode.preorderEnumeration();
 
497
        DefaultMutableTreeNode node = null;
 
498
        Vector nodeFound = new Vector();
 
499
        
 
500
        while(nodes.hasMoreElements()){
 
501
            node = (DefaultMutableTreeNode)nodes.nextElement();
 
502
            debug(" node :"+ node.toString());
 
503
            if(node != null){
 
504
                FavoritesItem favoritesItem = (FavoritesItem)node.getUserObject();
 
505
                if(favoritesItem == null)
 
506
                    debug("favoritesItem is null");
 
507
                else{
 
508
                    //Map.ID id = favoritesItem.getID();
 
509
                    Map.ID id = (Map.ID)dataMap.get(favoritesItem);
 
510
                    if(id != null){
 
511
                        debug("id name :"+id.id);
 
512
                        debug("target :"+target);
 
513
                        Map.ID itemID = null;
 
514
                        try{
 
515
                            itemID = Map.ID.create(target,favorites.getModel().getHelpSet());
 
516
                        }
 
517
                        catch(BadIDException exp){
 
518
                            System.err.println("Not valid ID :"+target );
 
519
                            break;
 
520
                        }
 
521
                        if(id.equals(itemID))
 
522
                            nodeFound.addElement(node);
 
523
                    }
 
524
                }
 
525
            }
 
526
        }
 
527
        
 
528
        return nodeFound;
 
529
    }
 
530
    
 
531
    /**
 
532
     * Collapses entry specified by id. If entry is empty collapses it's parent.
 
533
     *
 
534
     * @param target The target of entry
 
535
     */
 
536
    
 
537
    private void collapse(String target){
 
538
        Enumeration nodes = findNodes(target).elements();
 
539
        DefaultMutableTreeNode node = null;
 
540
        debug("collapse called");
 
541
        
 
542
        while(nodes.hasMoreElements()){
 
543
            node = (DefaultMutableTreeNode)nodes.nextElement();
 
544
            if(node.getChildCount() > 0){
 
545
                TreeNode[] treeNode = node.getPath();
 
546
                TreePath path = new TreePath(treeNode);
 
547
                tree.collapsePath(path);
 
548
                tree.collapseRow(tree.getRowForPath(path));
 
549
            }
 
550
            else{
 
551
                DefaultMutableTreeNode parent =(DefaultMutableTreeNode) node.getParent();
 
552
                TreePath path = new TreePath(parent.getPath());
 
553
                tree.collapseRow(tree.getRowForPath(path));
 
554
            }
 
555
        }
 
556
    }
 
557
    
 
558
    // Make all nodes visible
 
559
    
 
560
    private void setVisibility(DefaultMutableTreeNode node) {
 
561
        tree.expandPath(new TreePath(node.getPath()));
 
562
        if (! node.isLeaf()) {
 
563
            int max = node.getChildCount();
 
564
            for (int i=0; i<max; i++) {
 
565
                setVisibility((DefaultMutableTreeNode)node.getChildAt(i));
 
566
            }
 
567
        }
 
568
    }
 
569
    
 
570
    /**
 
571
     * Processes and idChanged event. In this navigator works with url too.
 
572
     *
 
573
     * @param e The HelpModelEvent
 
574
     */
 
575
    
 
576
    public void idChanged(HelpModelEvent e) {
 
577
        debug("idChanged("+e+")");
 
578
        
 
579
        //next values
 
580
        ID id = e.getID();
 
581
        contentTitle = e.getHistoryName();
 
582
        URL nurl = e.getURL();
 
583
        String nURL = null;
 
584
        if (nurl != null)
 
585
            nURL = nurl.toExternalForm();
 
586
        
 
587
        //current values
 
588
        ID currentID = null;
 
589
        String currentURL = null;
 
590
        String currentName = null;
 
591
        FavoritesItem item = null;
 
592
        
 
593
        HelpModel helpModel = favorites.getModel();
 
594
        
 
595
        
 
596
        if (e.getSource() != helpModel) {
 
597
            debug("Internal inconsistency!");
 
598
            debug("  "+e.getSource()+" != "+helpModel);
 
599
            throw new Error("Internal error");
 
600
        }
 
601
        
 
602
        TreePath s = tree.getSelectionPath();
 
603
        if (s != null) {
 
604
            Object o = s.getLastPathComponent();
 
605
            // should require only a TreeNode
 
606
            if (o instanceof DefaultMutableTreeNode) {
 
607
                DefaultMutableTreeNode tn = (DefaultMutableTreeNode) o;
 
608
                item = (FavoritesItem) tn.getUserObject();
 
609
                if (item != null){
 
610
                    currentID = (Map.ID) dataMap.get(item);
 
611
                    currentURL = item.getURLSpec();
 
612
                    currentName = item.getName();
 
613
                }
 
614
                if((currentName != null) && (currentName.equals(contentTitle))){
 
615
                    if(currentID != null)
 
616
                        if(currentID.equals(id))
 
617
                            return;
 
618
                    if(currentURL != null)
 
619
                        if(currentURL.equals(nURL))
 
620
                            return;
 
621
                }
 
622
            }
 
623
        }
 
624
        
 
625
        DefaultMutableTreeNode node = null;        
 
626
 
 
627
        node = findID(topNode, id);
 
628
        if(node == null) {
 
629
            node = findURL(topNode, nURL);
 
630
        }
 
631
 
 
632
        if (node == null) {
 
633
            // node doesn't exist. Need to clear the selection.
 
634
            tree.clearSelection();
 
635
            return;
 
636
        }
 
637
        TreePath path = new TreePath(node.getPath());
 
638
        tree.expandPath(path);
 
639
        tree.setSelectionPath(path);
 
640
        tree.scrollPathToVisible(path);
 
641
    }
 
642
    
 
643
    private DefaultMutableTreeNode findID(DefaultMutableTreeNode node, ID id) {
 
644
        debug("findID: ("+id+")");
 
645
        debug("  node: "+node);
 
646
        
 
647
        // check on the id
 
648
        if (id == null) {
 
649
            return null;
 
650
        }
 
651
        FavoritesItem item = (FavoritesItem) node.getUserObject();
 
652
        Map.ID  itemID = (Map.ID) dataMap.get(item);
 
653
        if (itemID != null) {
 
654
            ID testID = itemID;
 
655
            debug("  testID: "+testID);
 
656
            if (testID != null && testID.equals(id)) {
 
657
                return node;
 
658
            }
 
659
        }
 
660
        int size = node.getChildCount();
 
661
        for (int i=0; i<size ; i++) {
 
662
            DefaultMutableTreeNode tmp =
 
663
            (DefaultMutableTreeNode) node.getChildAt(i);
 
664
            DefaultMutableTreeNode test = findID(tmp, id);
 
665
            if (test != null) {
 
666
                return test;
 
667
            }
 
668
        }
 
669
        return null;
 
670
    }
 
671
    /**
 
672
     * Finds the subnode with certain url and name
 
673
     */
 
674
    private DefaultMutableTreeNode findURL(DefaultMutableTreeNode node, String urlSpec){
 
675
        debug(" findURL: "+ urlSpec);
 
676
        
 
677
        if(urlSpec == null)
 
678
            return null;
 
679
        
 
680
        for(Enumeration children = node.children(); children.hasMoreElements();){
 
681
            DefaultMutableTreeNode child = (DefaultMutableTreeNode)children.nextElement();
 
682
            FavoritesItem childItem = (FavoritesItem) child.getUserObject();
 
683
            String childName = childItem.getName();
 
684
            String childURL = childItem.getURLSpec();
 
685
            if(urlSpec.equals(childURL))
 
686
                return child;
 
687
            else
 
688
                findURL(child,urlSpec);
 
689
        }
 
690
        return null;
 
691
    }
 
692
    
 
693
    /**
 
694
     * Finds the subnode with certain id and name
 
695
     */
 
696
    
 
697
    public void valueChanged(TreeSelectionEvent e) {
 
698
        
 
699
        selectedTreePath = e.getNewLeadSelectionPath();
 
700
        if (selectedTreePath == null) {
 
701
            selectedNode = null;
 
702
            return;
 
703
        }
 
704
        selectedNode =
 
705
        (FavoritesNode)selectedTreePath.getLastPathComponent();
 
706
        if (selectedNode != null){
 
707
            selectedItem = (FavoritesItem)selectedNode.getUserObject();
 
708
            selectedID = (Map.ID)dataMap.get(selectedItem);
 
709
        }
 
710
        
 
711
        HelpModel helpModel = favorites.getModel();
 
712
        HelpSet hs = helpModel.getHelpSet();
 
713
        
 
714
        debug("ValueChanged: "+e);
 
715
        debug("  model: "+helpModel);
 
716
        if(helpModel == null)
 
717
            return;
 
718
        // send selected items into navigator
 
719
        TreeItem[] items = null;
 
720
        TreePath[] paths = tree.getSelectionPaths();
 
721
        if (paths != null) {
 
722
            removeAction.setEnabled(true);
 
723
            items = new TreeItem[paths.length];
 
724
            for (int i = 0; i < paths.length; i++) {
 
725
                if (paths[i] != null) {
 
726
                    DefaultMutableTreeNode node = (DefaultMutableTreeNode) paths[i].getLastPathComponent();
 
727
                    FavoritesItem favItem = (FavoritesItem) node.getUserObject();
 
728
                    // need to normalize this item so it looks like a real TreeItem
 
729
                    try {
 
730
                        String target = favItem.getTarget();
 
731
                        if (target != null) {
 
732
                            ID id = Map.ID.create(favItem.getTarget(), hs);
 
733
                            favItem.setID(id);
 
734
                        }
 
735
                    } catch (BadIDException ee) {
 
736
                    }
 
737
                    items[i] = (TreeItem) favItem;
 
738
                }
 
739
            }
 
740
        }else{
 
741
            removeAction.setEnabled(false);
 
742
            pasteAction.setEnabled(false);
 
743
            pasteMI.setEnabled(false);
 
744
            return;
 
745
        }
 
746
        favorites.setSelectedItems(items);
 
747
        
 
748
        // change current id only if one item is selected
 
749
        if (items != null && items.length == 1) {
 
750
            FavoritesItem item = (FavoritesItem) items[0];
 
751
            if (item != null) {
 
752
                Map.ID itemID = (Map.ID) dataMap.get(item);
 
753
                if(itemID != null){
 
754
                    debug("itemID: "+itemID);
 
755
                    try{
 
756
                        // helpmodel.setCurrentID(item.getID());
 
757
                        helpModel.setCurrentID(itemID, item.getName(), (JHelpNavigator)favorites);
 
758
                    } catch (InvalidHelpSetContextException ex) {
 
759
                        System.err.println("BadID: "+item.getID());
 
760
                        return;
 
761
                    }
 
762
                }else{
 
763
                    if(item.getURLSpec() != null){
 
764
                        try{
 
765
                            URL url = new URL(item.getURLSpec());
 
766
                            helpModel.setCurrentURL(url,item.getName(),(JHelpNavigator)favorites);
 
767
                        }catch(MalformedURLException ep){
 
768
                            System.err.println(ep);
 
769
                        }
 
770
                    }
 
771
                }
 
772
            }
 
773
        }
 
774
    }
 
775
    
 
776
    public void propertyChange(PropertyChangeEvent event) {
 
777
        debug("propertyChange: " + event.getSource() + " "  +
 
778
        event.getPropertyName());
 
779
        
 
780
        if (event.getSource() == favorites) {
 
781
            String changeName = event.getPropertyName();
 
782
            if (changeName.equals("helpModel")) {
 
783
                debug("model changed");
 
784
                reloadData();
 
785
                
 
786
            } else  if (changeName.equals("font")) {
 
787
                debug("Font change");
 
788
                Font newFont = (Font)event.getNewValue();
 
789
                tree.setFont(newFont);
 
790
                RepaintManager.currentManager(tree).markCompletelyDirty(tree);
 
791
            } else if(changeName.equals("expand")){
 
792
                debug("Expand change");
 
793
                expand((String)event.getNewValue());
 
794
            } else if(changeName.equals("collapse")){
 
795
                debug("Collapse change");
 
796
                collapse((String)event.getNewValue());
 
797
            } else if(changeName.equals("navigatorChange")){
 
798
                debug("Navigator change");
 
799
                tree.clearSelection();
 
800
            }
 
801
            
 
802
            // changes to UI property?
 
803
            
 
804
        }else if (favorites != null){
 
805
            if (event.getSource() == favorites.getModel()) {
 
806
                String changeName = event.getPropertyName();
 
807
                if( changeName.equals("helpSet")) {
 
808
                    reloadData();
 
809
                }
 
810
            }
 
811
        }
 
812
    }
 
813
    
 
814
    public void helpSetAdded(HelpSetEvent ev){
 
815
        debug("HelpSet added");
 
816
        reloadData();
 
817
    }
 
818
    
 
819
    public void helpSetRemoved(HelpSetEvent ev){
 
820
        debug("HelpSet removed");
 
821
        reloadData();
 
822
    }
 
823
    
 
824
    /**
 
825
     * Saves favorites to the file
 
826
     */
 
827
    public void saveFavorites(){
 
828
        FavoritesView view = (FavoritesView)favorites.getNavigatorView();
 
829
        view.saveFavorites(rootNode);
 
830
    }
 
831
    
 
832
    public void treeStructureChanged(javax.swing.event.TreeModelEvent treeModelEvent) {
 
833
        debug("tree structure changed");
 
834
    }
 
835
    
 
836
    public void treeNodesInserted(javax.swing.event.TreeModelEvent treeModelEvent) {
 
837
        debug("node inserted");
 
838
        int place = -1;
 
839
        FavoritesNode parent = (FavoritesNode) treeModelEvent.getTreePath().getLastPathComponent();
 
840
        Object nodes[] = treeModelEvent.getChildren();
 
841
        int[] indices = treeModelEvent.getChildIndices();
 
842
        int firstIndex = indices[0];
 
843
        debug("index first "+firstIndex);
 
844
        int lastIndex = (indices.length + firstIndex) - 1;
 
845
        FavoritesNode rootParent = (FavoritesNode)connections.get(parent);
 
846
        if(rootParent == null)
 
847
            rootParent = rootNode;
 
848
        
 
849
        debug("root parent "+rootParent);
 
850
        //nodes were inserted into first place in parent
 
851
        if(firstIndex == 0){
 
852
            if(rootParent.getChildCount() == 0)
 
853
                place = 0;
 
854
            else{
 
855
                for(Enumeration en = rootParent.children(); en.hasMoreElements();){
 
856
                    FavoritesNode node = (FavoritesNode)en.nextElement();
 
857
                    if(node.isVisible()){
 
858
                        debug("is visible : "+node);
 
859
                        place = rootParent.getIndex(node);
 
860
                        break;
 
861
                    }
 
862
                }
 
863
            }
 
864
            //insert nodes in node place
 
865
            if(place >= 0){
 
866
                for(int j = nodes.length - 1; j >= 0; j--){
 
867
                    FavoritesNode copy = ((FavoritesNode) nodes[j]).getDeepCopy();
 
868
                    rootParent.insert((DefaultMutableTreeNode)copy,place);
 
869
                    connections.put((FavoritesNode)nodes[j],copy);
 
870
                }
 
871
            }
 
872
            
 
873
        }else if (firstIndex > 0){
 
874
            //find what is before
 
875
            FavoritesNode nodeBefore = (FavoritesNode)parent.getChildAt(firstIndex - 1);
 
876
            FavoritesNode rootNode = (FavoritesNode)connections.get(nodeBefore);
 
877
            place = rootParent.getIndex(rootNode)+1;
 
878
            for(int k = nodes.length - 1; k >= 0; k--){
 
879
                FavoritesNode copyNode = ((FavoritesNode)nodes[k]).getDeepCopy();
 
880
                rootParent.insert((DefaultMutableTreeNode)copyNode,place);
 
881
                connections.put((FavoritesNode)nodes[k],copyNode);
 
882
            }
 
883
        }
 
884
    }
 
885
    
 
886
    public void treeNodesRemoved(javax.swing.event.TreeModelEvent treeModelEvent) {
 
887
        debug("nodes removed");
 
888
        Object nodes[] = treeModelEvent.getChildren();
 
889
        for(int i = 0; i < nodes.length; i++){
 
890
            FavoritesNode originalNode = (FavoritesNode)nodes[i];
 
891
            FavoritesNode remNode = (FavoritesNode)connections.get(originalNode);
 
892
            if(remNode != null)
 
893
                remNode.removeFromParent();
 
894
        }
 
895
    }
 
896
    
 
897
    public void treeNodesChanged(javax.swing.event.TreeModelEvent treeModelEvent) {
 
898
        debug("node changed");
 
899
        TreeCellEditor editor = tree.getCellEditor();
 
900
        Object newName = editor.getCellEditorValue();
 
901
        
 
902
        if((newName instanceof String) && selectedItem != null){
 
903
            debug("new name");
 
904
            //data of old item
 
905
            Map.ID itemID = (Map.ID)dataMap.get(selectedItem);
 
906
            //remove old data from dataMap
 
907
            dataMap.remove(selectedItem);
 
908
            FavoritesNode fromRootNode = (FavoritesNode)connections.get(getSelectedNode());
 
909
            //change name of old Item
 
910
            selectedItem.setName((String)newName);
 
911
            selectedNode.setUserObject(selectedItem);       
 
912
            if(fromRootNode != null){
 
913
                FavoritesItem fromRootItem = (FavoritesItem) fromRootNode.getUserObject();
 
914
                fromRootItem.setName((String)newName);
 
915
            }
 
916
            //put data to the dataMap
 
917
            dataMap.put(selectedItem,itemID);
 
918
            saveFavorites();
 
919
        }
 
920
    }
 
921
    
 
922
    /**
 
923
     * Returns the selected node
 
924
     *
 
925
     */
 
926
    public FavoritesNode getSelectedNode() {
 
927
        return selectedNode;
 
928
    }
 
929
    
 
930
    /**
 
931
     * AddAction class.
 
932
     *
 
933
     */
 
934
    public class AddAction extends AbstractAction{
 
935
        
 
936
        public AddAction(){
 
937
            super(HelpUtilities.getString(locale, "favorites.add"), SwingHelpUtilities.getImageIcon(BasicFavoritesNavigatorUI.class,"images/addToFav.gif"));
 
938
        }
 
939
        
 
940
        public void actionPerformed(ActionEvent ev){
 
941
            debug("add");
 
942
 
 
943
            String target = null;
 
944
            String hstitle = null;
 
945
            FavoritesItem favorite = null;
 
946
            HelpModel helpModel = favorites.getModel();
 
947
            HelpSet hs = helpModel.getHelpSet();
 
948
 
 
949
            Map.ID ID = helpModel.getCurrentID();
 
950
            URL url = helpModel.getCurrentURL();
 
951
            if(ID != null){
 
952
                target = ID.id;
 
953
                hstitle = ID.hs.getTitle();
 
954
            }
 
955
            if(hstitle == null){
 
956
                // need to determine the helpset title by looking at the
 
957
                // starting URL of the 
 
958
                hstitle = getHelpSetTitle(hs, url);
 
959
                if (hstitle == null) {
 
960
                    hstitle=  hs.getTitle();
 
961
                }
 
962
            }
 
963
            String urlSpec = null;
 
964
            if(target == null) {
 
965
                urlSpec = url.toExternalForm();
 
966
            }
 
967
            favorite = new FavoritesItem(contentTitle, target, urlSpec,
 
968
                                         hstitle, Locale.getDefault());
 
969
            dataMap.put(favorite,ID);
 
970
 
 
971
            FavoritesNode node = new FavoritesNode(favorite);
 
972
            DefaultTreeModel model = (DefaultTreeModel)tree.getModel();
 
973
            model.insertNodeInto(node, topNode, topNode.getChildCount());
 
974
            
 
975
            TreePath path = new TreePath(node.getPath());
 
976
            tree.expandPath(path);
 
977
            tree.setSelectionPath(path);
 
978
            tree.scrollPathToVisible(path);
 
979
 
 
980
            saveFavorites();
 
981
        }
 
982
 
 
983
        /**
 
984
         * retuns a helpset title for a given url
 
985
         */
 
986
        private String getHelpSetTitle(HelpSet hs, URL url) {
 
987
            URL baseURL = hs.getHelpSetURL();
 
988
            String urlExternal = url.toExternalForm();
 
989
            String baseURLExternal = baseURL.toExternalForm();
 
990
            if (urlExternal.startsWith(baseURLExternal)) {
 
991
                return hs.getTitle();
 
992
            }
 
993
            Enumeration helpsets = hs.getHelpSets();
 
994
            String title = null;
 
995
            while (helpsets.hasMoreElements()) {
 
996
                HelpSet testHS = (HelpSet) helpsets.nextElement();
 
997
                title = getHelpSetTitle(testHS, url);
 
998
                if (title != null) {
 
999
                    break;
 
1000
                }
 
1001
            }
 
1002
            return title;
 
1003
        }
 
1004
 
 
1005
    }
 
1006
    
 
1007
    /**
 
1008
     * Returns the Add action
 
1009
     *
 
1010
     */
 
1011
    public Action getAddAction(){
 
1012
        return addAction;
 
1013
    }
 
1014
    
 
1015
    /**
 
1016
     * RemoveAction class.
 
1017
     *
 
1018
     */
 
1019
    public class RemoveAction extends AbstractAction{
 
1020
        
 
1021
        public RemoveAction(){
 
1022
            super(HelpUtilities.getString(locale, "favorites.remove"), SwingHelpUtilities.getImageIcon(BasicFavoritesNavigatorUI.class,"images/remove.gif"));
 
1023
        }
 
1024
        
 
1025
        public void actionPerformed(ActionEvent ev){
 
1026
            debug("remove");
 
1027
            DefaultMutableTreeNode node = null;
 
1028
            DefaultTreeModel model = (DefaultTreeModel)tree.getModel();
 
1029
            TreePath[] paths = tree.getSelectionPaths();
 
1030
            for(int i = 0 ; i < paths.length; i++){
 
1031
                if(paths[i] != null){
 
1032
                    node = (DefaultMutableTreeNode)paths[i].getLastPathComponent();
 
1033
                    model.removeNodeFromParent(node);
 
1034
                    if(node != null){
 
1035
                        FavoritesItem item = (FavoritesItem)node.getUserObject();
 
1036
                        dataMap.remove(item);
 
1037
                    }
 
1038
                }
 
1039
                saveFavorites();
 
1040
            }
 
1041
        }
 
1042
    }
 
1043
    
 
1044
    /**
 
1045
     * Returns the RemoveAction object
 
1046
     */
 
1047
    public Action getRemoveAction(){
 
1048
        return removeAction;
 
1049
    }
 
1050
    
 
1051
    /**
 
1052
     * FolderAction class.
 
1053
     *
 
1054
     */
 
1055
    public class FolderAction extends AbstractAction{
 
1056
        
 
1057
        public FolderAction(){
 
1058
            super(HelpUtilities.getString(locale, "favorites.folder"), SwingHelpUtilities.getImageIcon(BasicFavoritesNavigatorUI.class,"images/folder.gif"));
 
1059
        }
 
1060
        
 
1061
        public void actionPerformed(ActionEvent ev){
 
1062
            FavoritesItem favoriteFolder = new FavoritesItem(HelpUtilities.getString(locale, "favorites.folder"));
 
1063
            favoriteFolder.setAsFolder();
 
1064
            FavoritesNode node = new FavoritesNode(favoriteFolder);
 
1065
            TreePath nodePath = tree.getSelectionPath();
 
1066
            TreeNode parent = null;
 
1067
            if(nodePath == null)
 
1068
                parent = topNode;
 
1069
            else{
 
1070
                FavoritesNode selNode = (FavoritesNode)nodePath.getLastPathComponent();
 
1071
                parent = selNode.getParent();
 
1072
            }
 
1073
            DefaultTreeModel model = (DefaultTreeModel)tree.getModel();
 
1074
            model.insertNodeInto(node,(DefaultMutableTreeNode)parent,parent.getChildCount());
 
1075
            TreePath path = new TreePath(node.getPath());
 
1076
            tree.expandPath(path);
 
1077
            tree.setSelectionPath(path);
 
1078
            tree.scrollPathToVisible(path);
 
1079
            saveFavorites();
 
1080
        }
 
1081
    }
 
1082
    
 
1083
    /**
 
1084
     * Returns the FolderAction object
 
1085
     */
 
1086
    public Action getFolderAction(){
 
1087
        return folderAction;
 
1088
    }
 
1089
    
 
1090
    /**
 
1091
     * CutAction class.
 
1092
     */
 
1093
    public class CutAction extends AbstractAction{
 
1094
        
 
1095
        public CutAction(){
 
1096
            super(HelpUtilities.getString(locale,"favorites.cut"));
 
1097
        }
 
1098
        
 
1099
        public void actionPerformed(ActionEvent ev){
 
1100
            debug("cut");
 
1101
            DefaultMutableTreeNode node = null;
 
1102
            nodeClipboard.removeAllElements();
 
1103
            DefaultTreeModel model = (DefaultTreeModel)tree.getModel();
 
1104
            TreePath[] paths = tree.getSelectionPaths();
 
1105
            for(int i = 0 ; i < paths.length; i++){
 
1106
                if(paths[i] != null){
 
1107
                    node = (DefaultMutableTreeNode)paths[i].getLastPathComponent();
 
1108
                    if(node != null){
 
1109
                        FavoritesItem item = (FavoritesItem)node.getUserObject();
 
1110
                        nodeClipboard.add(node);
 
1111
                    }
 
1112
                    model.removeNodeFromParent(node);
 
1113
                }
 
1114
            }
 
1115
            saveFavorites();
 
1116
            pasteMI.setEnabled(true);
 
1117
        }
 
1118
    }
 
1119
    
 
1120
    /**
 
1121
     * Returns the CutAction object
 
1122
     */
 
1123
    public Action getCutAction(){
 
1124
        return cutAction;
 
1125
    }
 
1126
    
 
1127
    /**
 
1128
     * PasteAction class.
 
1129
     */
 
1130
    public class PasteAction extends AbstractAction{
 
1131
        
 
1132
        public PasteAction(){
 
1133
            super(HelpUtilities.getString(locale,"favorites.paste"));
 
1134
        }
 
1135
        
 
1136
        public void actionPerformed(ActionEvent ev){
 
1137
            debug("paste");
 
1138
            
 
1139
            DefaultTreeModel model = (DefaultTreeModel)tree.getModel();
 
1140
            TreePath path = tree.getSelectionPath();
 
1141
            FavoritesNode node = (FavoritesNode)path.getLastPathComponent();
 
1142
            if(node != null){
 
1143
                if(node.getAllowsChildren()){
 
1144
                    for(Enumeration nodes = nodeClipboard.elements(); nodes.hasMoreElements();){
 
1145
                        model.insertNodeInto((DefaultMutableTreeNode)nodes.nextElement(),(DefaultMutableTreeNode)node,node.getChildCount());
 
1146
                    }
 
1147
                }
 
1148
                else{
 
1149
                    DefaultMutableTreeNode parent = (DefaultMutableTreeNode)node.getParent();
 
1150
                    if(parent == null)
 
1151
                        return;
 
1152
                    int index = parent.getIndex(node);
 
1153
                    for(Enumeration en = nodeClipboard.elements(); en.hasMoreElements();index++){
 
1154
                        model.insertNodeInto((DefaultMutableTreeNode)en.nextElement(),parent,index);
 
1155
                    }
 
1156
                }
 
1157
                saveFavorites();
 
1158
            }
 
1159
            
 
1160
        }
 
1161
    }
 
1162
    
 
1163
    /**
 
1164
     * Returns the PasteAction object
 
1165
     */
 
1166
    public Action getPasteAction(){
 
1167
        return pasteAction;
 
1168
    }
 
1169
    
 
1170
    /**
 
1171
     * CopyAction class.
 
1172
     */
 
1173
    public class CopyAction extends AbstractAction{
 
1174
        
 
1175
        public CopyAction(){
 
1176
            super(HelpUtilities.getString(locale,"favorites.copy"));
 
1177
        }
 
1178
        
 
1179
        public void actionPerformed(ActionEvent ev){
 
1180
            debug("paste");
 
1181
            
 
1182
            DefaultMutableTreeNode node = null;
 
1183
            nodeClipboard.removeAllElements();
 
1184
            DefaultTreeModel model = (DefaultTreeModel)tree.getModel();
 
1185
            TreePath[] paths = tree.getSelectionPaths();
 
1186
            for(int i = 0 ; i < paths.length; i++){
 
1187
                if(paths[i] != null){
 
1188
                    node = (DefaultMutableTreeNode)paths[i].getLastPathComponent();
 
1189
                    if(node != null){
 
1190
                        FavoritesItem item = (FavoritesItem)node.getUserObject();
 
1191
                        FavoritesNode copy = ((FavoritesNode)node).getDeepCopy();
 
1192
                        nodeClipboard.add(copy);
 
1193
                    }
 
1194
                }
 
1195
            }
 
1196
            saveFavorites();
 
1197
            pasteMI.setEnabled(true);
 
1198
        }
 
1199
    }
 
1200
    
 
1201
    /**
 
1202
     * Returns the CopyAction Object
 
1203
     */
 
1204
    public Action getCopyAction(){
 
1205
        return copyAction;
 
1206
    }
 
1207
    
 
1208
    /**
 
1209
     * PopupListener class
 
1210
     */
 
1211
    public class PopupListener extends MouseAdapter{
 
1212
        
 
1213
        public void mousePressed(MouseEvent e){
 
1214
            maybeShowPopup(e);
 
1215
        }
 
1216
 
 
1217
        public void mouseReleased(MouseEvent e){
 
1218
            maybeShowPopup(e);
 
1219
        }
 
1220
 
 
1221
        private void maybeShowPopup(MouseEvent e) {
 
1222
            TreePath path = tree.getSelectionPath();
 
1223
            TreePath clickPath = tree.getPathForLocation(e.getX(),e.getY());
 
1224
            if (e.isPopupTrigger()) { 
 
1225
                if (path != null && path.equals(clickPath)) {
 
1226
                    separatorMI.setVisible(true);
 
1227
                    cutMI.setVisible(true);
 
1228
                    copyMI.setVisible(true);
 
1229
                    pasteMI.setVisible(true);
 
1230
                    removeMI.setVisible(true);
 
1231
                } else {
 
1232
                    separatorMI.setVisible(false);
 
1233
                    cutMI.setVisible(false);
 
1234
                    copyMI.setVisible(false);
 
1235
                    pasteMI.setVisible(false);
 
1236
                    removeMI.setVisible(false);
 
1237
                }
 
1238
                popup.show(e.getComponent(), e.getX(), e.getY());
 
1239
            }
 
1240
        }
 
1241
    }
 
1242
    
 
1243
    /**
 
1244
     * Class for JTree supported D&D features.
 
1245
     */
 
1246
    public class FavoritesTree extends JTree implements DragGestureListener, DropTargetListener, DragSourceListener {
 
1247
        
 
1248
        protected Map.ID selectedID = null;
 
1249
        
 
1250
        private DragSource dragSource = null;
 
1251
        private DragSourceContext dragSourceContext = null;
 
1252
        private Point cursorLocation = null;
 
1253
        private TreePath pathSource;
 
1254
        private BufferedImage ghostImage;
 
1255
        private Point offset = new Point();
 
1256
        private Point ptLast = new Point();
 
1257
        private Rectangle2D ghostRect = new Rectangle2D.Float();
 
1258
        
 
1259
        /**
 
1260
         * Data object of selected FavoritesNode
 
1261
         */
 
1262
        private Map.ID hashCandidate;
 
1263
        /**
 
1264
         * Custom cursor
 
1265
         */
 
1266
        private Cursor dndCursor;
 
1267
        
 
1268
        /**
 
1269
         * Creates FavoritesTree
 
1270
         *
 
1271
         * @param root The root node of the tree
 
1272
         */
 
1273
        public FavoritesTree(FavoritesNode root) {
 
1274
            super(root);
 
1275
            
 
1276
            setEditable(true);
 
1277
            
 
1278
            dragSource = DragSource.getDefaultDragSource();
 
1279
            
 
1280
            DragGestureRecognizer dgr =
 
1281
            dragSource.createDefaultDragGestureRecognizer(this,DnDConstants.ACTION_COPY_OR_MOVE,this);
 
1282
            
 
1283
            dgr.setSourceActions((dgr.getSourceActions()) &~ (InputEvent.BUTTON3_MASK));
 
1284
            
 
1285
            DropTarget dropTarget = new DropTarget(this, this);
 
1286
            
 
1287
            Toolkit tk = this.getToolkit();
 
1288
            if(tk.getBestCursorSize(16,16).equals(new Dimension(64,64)))
 
1289
                dndCursor = (Cursor) UIManager.get("HelpDnDCursor");
 
1290
            if(dndCursor == null)
 
1291
                debug("cursor is null");
 
1292
            putClientProperty("JTree.lineStyle", "None");
 
1293
        }
 
1294
        
 
1295
        public void dragGestureRecognized(DragGestureEvent e) {
 
1296
            FavoritesNode dragNode = getSelectedNode();
 
1297
            if (dragNode != null) {
 
1298
                
 
1299
                ghostImage = createGhostImage(e);
 
1300
                Transferable transferable = (Transferable) dragNode.getUserObject();
 
1301
                hashCandidate = (Map.ID)dataMap.get((FavoritesItem)transferable);
 
1302
                
 
1303
                Cursor cursor = DragSource.DefaultCopyDrop;
 
1304
                int action = e.getDragAction();
 
1305
                if(action == DnDConstants.ACTION_MOVE){
 
1306
                    debug("action move");
 
1307
                    cursor = DragSource.DefaultMoveDrop;
 
1308
                }
 
1309
                
 
1310
                dragSource.startDrag(e,dndCursor,ghostImage,new Point(5,5), transferable,this);
 
1311
            }
 
1312
        }
 
1313
        
 
1314
        private BufferedImage createGhostImage(DragGestureEvent e){
 
1315
            debug("createGhostImage");
 
1316
            
 
1317
            BufferedImage ghostImage = null;
 
1318
            Point ptDragOrigin = e.getDragOrigin();
 
1319
            TreePath path = getPathForLocation(ptDragOrigin.x, ptDragOrigin.y);
 
1320
            if (path == null)
 
1321
                return ghostImage;
 
1322
            
 
1323
            Rectangle raPath = getPathBounds(path);
 
1324
            offset.setLocation(ptDragOrigin.x-raPath.x, ptDragOrigin.y-raPath.y);
 
1325
            
 
1326
            JLabel lbl = (JLabel) getCellRenderer().getTreeCellRendererComponent
 
1327
            (this,path.getLastPathComponent(),false, isExpanded(path),getModel().isLeaf(path.getLastPathComponent()),0,false);
 
1328
            lbl.setSize((int)raPath.getWidth(), (int)raPath.getHeight()); 
 
1329
            
 
1330
            ghostImage = new BufferedImage((int)raPath.getWidth(), (int)raPath.getHeight(), BufferedImage.TYPE_INT_ARGB_PRE);
 
1331
            Graphics2D g2 = ghostImage.createGraphics();
 
1332
            
 
1333
            g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC, 0.5f));
 
1334
            lbl.paint(g2);
 
1335
            
 
1336
            Icon icon = lbl.getIcon();
 
1337
            int nStartOfText = (icon == null) ? 0 : icon.getIconWidth()+lbl.getIconTextGap();
 
1338
            g2.setComposite(AlphaComposite.getInstance(AlphaComposite.DST_OVER, 0.5f));
 
1339
            g2.setPaint(new GradientPaint(nStartOfText, 0, SystemColor.controlShadow,
 
1340
            getWidth(), 0, new Color(255,255,255,0)));
 
1341
            g2.fillRect(nStartOfText, 0, getWidth(), ghostImage.getHeight());
 
1342
            
 
1343
            g2.dispose();
 
1344
            
 
1345
            return ghostImage;
 
1346
        }
 
1347
        
 
1348
        public void dragDropEnd(DragSourceDropEvent dsde) {
 
1349
            debug("dragDropEnd");
 
1350
        }
 
1351
        
 
1352
        public void dragEnter(DragSourceDragEvent dsde) {
 
1353
            debug("dragEnter");
 
1354
            setCursor(dsde);
 
1355
        }
 
1356
        
 
1357
        public void dragOver(DragSourceDragEvent dsde) {
 
1358
            debug("drag over");
 
1359
            setCursor(dsde);
 
1360
        }
 
1361
        
 
1362
        public void dropActionChanged(DragSourceDragEvent dsde) {
 
1363
            debug("dropActionChanged");
 
1364
            setCursor(dsde);
 
1365
        }
 
1366
        
 
1367
        public void dragExit(DragSourceEvent dsde) {
 
1368
            debug("dragExit");
 
1369
        }
 
1370
        
 
1371
        /**
 
1372
         * Sets appropriate cursor type according to event
 
1373
         *
 
1374
         * @param dsde DrageSourceDrageEvent
 
1375
         */
 
1376
        private void setCursor(DragSourceDragEvent dsde) {
 
1377
            
 
1378
            if (cursorLocation == null) return;
 
1379
            
 
1380
            TreePath destinationPath =
 
1381
            getPathForLocation(cursorLocation.x, cursorLocation.y);
 
1382
            
 
1383
            DragSourceContext dsc = dsde.getDragSourceContext();
 
1384
            
 
1385
            if (testDropTarget(destinationPath, selectedTreePath) == null){
 
1386
                dsc.setCursor(DragSource.DefaultCopyDrop);
 
1387
                
 
1388
            }
 
1389
            else {
 
1390
                dsc.setCursor(DragSource.DefaultCopyNoDrop);
 
1391
            }
 
1392
        }
 
1393
        
 
1394
        public void drop(DropTargetDropEvent e) {
 
1395
            debug("drop");
 
1396
            try {
 
1397
                Transferable tr = e.getTransferable();
 
1398
                
 
1399
                if (!tr.isDataFlavorSupported( FavoritesItem.FAVORITES_FLAVOR)){
 
1400
                    debug("drop rejected not data flavor");
 
1401
                    e.rejectDrop();
 
1402
                }
 
1403
                
 
1404
                FavoritesItem childInfo = (FavoritesItem) tr.getTransferData( FavoritesItem.FAVORITES_FLAVOR );
 
1405
                Point loc = e.getLocation();
 
1406
                TreePath destinationPath = getPathForLocation(loc.x, loc.y);
 
1407
                
 
1408
                final String msg = testDropTarget(destinationPath, selectedTreePath);
 
1409
                if (msg != null) {
 
1410
                    e.rejectDrop();
 
1411
                    debug("Error : "+msg);
 
1412
                    return;
 
1413
                }
 
1414
                
 
1415
                FavoritesNode newParent =
 
1416
                (FavoritesNode) destinationPath.getLastPathComponent();
 
1417
                
 
1418
                debug("new parent: "+newParent);
 
1419
                //get old parent node
 
1420
                FavoritesNode oldParent = (FavoritesNode) getSelectedNode().getParent();
 
1421
                
 
1422
                FavoritesNode selNode = (FavoritesNode) getSelectedNode();
 
1423
                FavoritesItem selItem = (FavoritesItem) selNode.getUserObject();
 
1424
                
 
1425
                FavoritesNode newNode = selNode.getDeepCopy();
 
1426
                
 
1427
                int action = e.getDropAction();
 
1428
                boolean copyAction = (action == DnDConstants.ACTION_COPY);
 
1429
                debug("copy action: "+ copyAction);
 
1430
                //make new child node
 
1431
                FavoritesNode newChild = new FavoritesNode(childInfo);
 
1432
                debug("new child: "+newChild);
 
1433
                try {
 
1434
                    if (!copyAction){
 
1435
                        FavoritesNode fromRootNode = (FavoritesNode)connections.get(getSelectedNode());
 
1436
                        if(fromRootNode != null)
 
1437
                            fromRootNode.removeFromParent();
 
1438
                        oldParent.remove(getSelectedNode());
 
1439
                    }
 
1440
                    DefaultTreeModel model = (DefaultTreeModel)getModel();
 
1441
                    
 
1442
                    if (!newParent.getAllowsChildren()){
 
1443
                        TreeNode parent = newParent.getParent();
 
1444
                        if(parent != null){
 
1445
                            int index = parent.getIndex(newParent);
 
1446
                            model.insertNodeInto(newNode,(DefaultMutableTreeNode)parent, index+1);
 
1447
                        }
 
1448
                    }else
 
1449
                        model.insertNodeInto(newNode,newParent,newParent.getChildCount());
 
1450
                    
 
1451
                    if (copyAction)
 
1452
                        e.acceptDrop(DnDConstants.ACTION_COPY);
 
1453
                    else e.acceptDrop(DnDConstants.ACTION_MOVE);
 
1454
                }
 
1455
                catch (java.lang.IllegalStateException ils) {
 
1456
                    debug("drop ejected");
 
1457
                    e.rejectDrop();
 
1458
                }
 
1459
                
 
1460
                e.getDropTargetContext().dropComplete(true);
 
1461
                
 
1462
                FavoritesItem newItem = (FavoritesItem) newNode.getUserObject();
 
1463
                dataMap.put(newItem, hashCandidate);
 
1464
                DefaultTreeModel model = (DefaultTreeModel) getModel();
 
1465
                model.reload(oldParent);
 
1466
                model.reload(newParent);
 
1467
                TreePath parentPath = new TreePath(newParent.getPath());
 
1468
                expandPath(parentPath);
 
1469
                saveFavorites();
 
1470
            }
 
1471
            catch (IOException io) {
 
1472
                e.rejectDrop();
 
1473
                debug("drop rejected" + io);
 
1474
            }
 
1475
            catch (UnsupportedFlavorException ufe) {
 
1476
                e.rejectDrop();
 
1477
                debug("drop rejected: "+ ufe);
 
1478
            }
 
1479
        }
 
1480
        
 
1481
        public void dragEnter(DropTargetDragEvent e) {
 
1482
        }
 
1483
        
 
1484
        public void dragExit(DropTargetEvent e) {
 
1485
            if (!DragSource.isDragImageSupported()) {
 
1486
                repaint(ghostRect.getBounds());
 
1487
            }
 
1488
        }
 
1489
        
 
1490
        public void dragOver(DropTargetDragEvent e) {
 
1491
            
 
1492
            Point pt = e.getLocation();
 
1493
            if (pt.equals(ptLast))
 
1494
                return;
 
1495
            
 
1496
            ptLast = pt;
 
1497
            
 
1498
            Point cursorLocationBis = e.getLocation();
 
1499
            TreePath destinationPath = getPathForLocation(cursorLocationBis.x, cursorLocationBis.y);
 
1500
            
 
1501
            Graphics2D g2 = (Graphics2D) getGraphics();
 
1502
            
 
1503
            if(testDropTarget(destinationPath, selectedTreePath) == null){
 
1504
                e.acceptDrag(DnDConstants.ACTION_COPY_OR_MOVE);
 
1505
                if (!DragSource.isDragImageSupported()) {
 
1506
                    paintImmediately(ghostRect.getBounds());
 
1507
                    ghostRect.setRect(pt.x - offset.x, pt.y - offset.y, ghostImage.getWidth(), ghostImage.getHeight());
 
1508
                    g2.drawImage(ghostImage, AffineTransform.getTranslateInstance(ghostRect.getX(), ghostRect.getY()), null);
 
1509
                }
 
1510
            }else
 
1511
                e.rejectDrag();
 
1512
        }
 
1513
        
 
1514
        public void dropActionChanged(DropTargetDragEvent e) {
 
1515
        }
 
1516
        
 
1517
        /**
 
1518
         * Tests whether drop location is valid or not
 
1519
         *
 
1520
         * @param destination The destination path
 
1521
         * @param dropper The path for the node to be dropped
 
1522
         * @return Null if no problems, otherwise an explanation
 
1523
         */
 
1524
        private String testDropTarget(TreePath destination, TreePath dropper) {
 
1525
            
 
1526
            boolean destinationPathIsNull = destination == null;
 
1527
            if (destinationPathIsNull){
 
1528
                return "Invalid drop location.";
 
1529
                //remove ghostLikeImage
 
1530
            }
 
1531
            
 
1532
            FavoritesNode node = (FavoritesNode) destination.getLastPathComponent();
 
1533
            
 
1534
            if (destination.equals(dropper))
 
1535
                return "Destination cannot be same as source";
 
1536
            
 
1537
            
 
1538
            if ( dropper.isDescendant(destination))
 
1539
                return "Destination node cannot be a descendant.";
 
1540
            
 
1541
            
 
1542
            if ( dropper.getParentPath().equals(destination))
 
1543
                return "Destination node cannot be a parent.";
 
1544
            
 
1545
            return null;
 
1546
        }
 
1547
    }
 
1548
    
 
1549
    /**
 
1550
     * For printf debugging.
 
1551
     */
 
1552
    private static boolean debug = false;
 
1553
    private static void debug(String str) {
 
1554
        if (debug) {
 
1555
            System.out.println("BasicFavoritesNavigatorUI: " + str);
 
1556
        }
 
1557
    }
 
1558
}