001/*****************************************************************************
002 * Copyright by The HDF Group.                                               *
003 * Copyright by the Board of Trustees of the University of Illinois.         *
004 * All rights reserved.                                                      *
005 *                                                                           *
006 * This file is part of the HDF Java Products distribution.                  *
007 * The full copyright notice, including terms governing use, modification,   *
008 * and redistribution, is contained in the files COPYING and Copyright.html. *
009 * COPYING can be found at the root of the source code distribution tree.    *
010 * Or, see http://hdfgroup.org/products/hdf-java/doc/Copyright.html.         *
011 * If you do not have access to either file, you may request a copy from     *
012 * help@hdfgroup.org.                                                        *
013 ****************************************************************************/
014
015package hdf.view;
016
017import java.awt.BorderLayout;
018import java.awt.Dimension;
019import java.awt.GridLayout;
020import java.awt.Insets;
021import java.awt.Point;
022import java.awt.Toolkit;
023import java.awt.event.ActionEvent;
024import java.awt.event.ActionListener;
025import java.awt.event.ItemEvent;
026import java.awt.event.ItemListener;
027import java.awt.event.KeyEvent;
028import java.io.File;
029import java.util.Enumeration;
030import java.util.Iterator;
031import java.util.List;
032import java.util.Vector;
033
034import javax.swing.BorderFactory;
035import javax.swing.ButtonGroup;
036import javax.swing.JButton;
037import javax.swing.JCheckBox;
038import javax.swing.JComboBox;
039import javax.swing.JDialog;
040import javax.swing.JFileChooser;
041import javax.swing.JFrame;
042import javax.swing.JLabel;
043import javax.swing.JOptionPane;
044import javax.swing.JPanel;
045import javax.swing.JRadioButton;
046import javax.swing.JTextField;
047import javax.swing.border.TitledBorder;
048import javax.swing.event.DocumentEvent;
049import javax.swing.event.DocumentListener;
050import javax.swing.tree.DefaultMutableTreeNode;
051import javax.swing.tree.TreeNode;
052
053import hdf.object.DataFormat;
054import hdf.object.FileFormat;
055import hdf.object.Group;
056import hdf.object.HObject;
057
058/**
059 * NewLinkDialog shows a message dialog requesting user input for creating a
060 * new links.
061 * 
062 * @author Peter X. Cao
063 * @version 2.4 9/6/2007
064 */
065public class NewLinkDialog extends JDialog implements ActionListener,DocumentListener, ItemListener {
066    private static final long serialVersionUID = 7100424106041533918L;
067
068    private final static org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(NewLinkDialog.class);
069
070    private JTextField nameField;
071
072    @SuppressWarnings("rawtypes")
073    private JComboBox parentChoice, targetObject;
074    
075    private String currentDir;
076    
077    private JTextField targetFile;
078    
079    private JButton targetFileButton;
080    
081    private JRadioButton hardLink, softLink, externalLink;
082
083    private JCheckBox checkUnsigned;
084
085    /** a list of current groups */
086    private List<HObject> groupList;
087
088    /** a list of current objects */
089    private List<?> objList;
090    
091    private HObject newObject;
092
093    private FileFormat fileFormat;
094
095    private final Toolkit toolkit;
096    
097    private ViewManager viewer;
098    
099    private final List<?> fileList;
100      
101
102    /**
103     * Constructs NewLinkDialog with specified list of possible parent groups.
104     * 
105     * @param owner
106     *            the owner of the input
107     * @param pGroup
108     *            the parent group which the new group is added to.
109     * @param objs
110     *            the list of all objects.
111     */
112    @SuppressWarnings({ "rawtypes", "unchecked" })
113    public NewLinkDialog(JFrame owner, Group pGroup, List<?> objs) {
114        super(owner, "New Link...", true);
115
116        viewer = (ViewManager)owner;
117        fileList = viewer.getTreeView().getCurrentFiles();
118             
119        newObject = null;      
120        fileFormat = pGroup.getFileFormat();
121        toolkit = Toolkit.getDefaultToolkit();
122        objList = objs;
123        
124        currentDir = ViewProperties.getWorkDir();
125        
126        parentChoice = new JComboBox();
127        parentChoice.setName("linkparent");
128        targetObject = new JComboBox();
129        targetObject.setEditable(false);
130       
131        groupList = new Vector<HObject>(objs.size());
132        HObject obj = null;
133        Iterator<?> iterator = objs.iterator();
134        String full_name = null;
135        int idx_root = -1, idx = -1;
136        while (iterator.hasNext()) {
137            obj = (HObject) iterator.next();
138            idx++;
139
140            if (obj instanceof Group) {
141                Group g = (Group) obj;
142                groupList.add(obj);
143                if (g.isRoot()) {
144                    full_name = HObject.separator;
145                    idx_root = idx;
146                }
147                else {
148                    full_name = g.getPath() + g.getName() + HObject.separator;
149                }
150                parentChoice.addItem(full_name);
151            }
152            else {
153                full_name = obj.getPath() + obj.getName();
154            }
155
156           targetObject.addItem(full_name);
157        }
158
159        targetObject.removeItemAt(idx_root);
160       objList.remove(idx_root);
161
162        if (pGroup.isRoot()) {
163            parentChoice.setSelectedItem(HObject.separator);
164        }
165        else {
166            parentChoice.setSelectedItem(pGroup.getPath() + pGroup.getName()
167                    + HObject.separator);
168        }
169       
170
171        JPanel contentPane = (JPanel) getContentPane();
172        contentPane.setLayout(new BorderLayout(5, 5));
173        contentPane.setBorder(BorderFactory.createEmptyBorder(15, 5, 5, 5));
174        int w = 600 + (ViewProperties.getFontSize() - 12) * 15;
175        int h = 280 + (ViewProperties.getFontSize() - 12) * 10;
176        contentPane.setPreferredSize(new Dimension(w, h));
177
178        JButton okButton = new JButton("   Ok   ");
179        okButton.setActionCommand("Ok");
180        okButton.setName("makelink");
181        okButton.setMnemonic(KeyEvent.VK_O);
182        okButton.addActionListener(this);
183
184        JButton cancelButton = new JButton("Cancel");
185        cancelButton.setMnemonic(KeyEvent.VK_C);
186        cancelButton.setActionCommand("Cancel");
187        cancelButton.addActionListener(this);
188
189        // set OK and CANCEL buttons
190        JPanel buttonPanel = new JPanel();
191        buttonPanel.add(okButton);
192        buttonPanel.add(cancelButton);
193        contentPane.add(buttonPanel, BorderLayout.SOUTH);
194
195        // set NAME and PARENT GROUP panel
196        JPanel namePanel = new JPanel();
197        namePanel.setLayout(new BorderLayout(5, 5));
198        JPanel tmpP = new JPanel();
199        tmpP.setLayout(new GridLayout(5, 1,5, 5));
200        tmpP.add(new JLabel("Link name: "));
201        tmpP.add(new JLabel("Parent group: "));
202        
203        JPanel tmpLinkJPanel = new JPanel();
204        tmpLinkJPanel.setLayout(new GridLayout(2, 1));
205        tmpLinkJPanel.add(new JLabel("Type of Link: "));
206        JButton helpButton = new JButton(ViewProperties.getHelpIcon());
207        helpButton.setToolTipText("Help on Links");
208        helpButton.setMargin(new Insets(0, 0, 0, 0));
209        helpButton.addActionListener(this);
210        helpButton.setActionCommand("Help on Links");
211        tmpLinkJPanel.add(helpButton);
212        tmpP.add(tmpLinkJPanel);
213        tmpP.add(new JLabel("Target File: "));
214        tmpP.add(new JLabel("Target Object: "));
215        namePanel.add(tmpP, BorderLayout.WEST);
216        
217        tmpP = new JPanel();
218        tmpP.setLayout(new GridLayout(5, 1,5,5));
219        nameField = new JTextField();
220        nameField.setName("linkname");
221        tmpP.add(nameField);
222        tmpP.add(parentChoice);
223              
224        JPanel tmpP0 = new JPanel();
225        tmpP0.setLayout(new GridLayout(1, 3));
226        tmpP0.add(hardLink = new JRadioButton("Hard Link ", true));
227        tmpP0.add(softLink = new JRadioButton("Soft Link "));
228        tmpP0.add(externalLink = new JRadioButton("External Link "));
229        tmpP0.setBorder(new TitledBorder(""));
230        tmpP.add(tmpP0);   
231        ButtonGroup bgroup = new ButtonGroup();
232        bgroup.add(hardLink);
233        bgroup.add(softLink);
234        bgroup.add(externalLink);
235        hardLink.addItemListener(this);
236        hardLink.setName("hardlink");
237        softLink.addItemListener(this);
238        softLink.setName("softlink");
239        externalLink.addItemListener(this);
240        externalLink.setName("externallink");
241        
242        JPanel p0 = new JPanel();
243        p0.setLayout(new BorderLayout());
244        p0.add(targetFile = new JTextField(), BorderLayout.CENTER);
245        targetFile.getDocument().addDocumentListener(this);
246        targetFile.addActionListener(this);
247        targetFile.setActionCommand("Link to File");
248        JButton b = new JButton("Browse...");
249        targetFileButton = b;
250        b.setActionCommand("Browse File");
251        b.setName("targetfilebutton");
252        b.addActionListener(this);
253        p0.add(b, BorderLayout.EAST);
254        tmpP.add(p0);
255        targetFile.setEnabled(false);
256        targetFileButton.setEnabled(false);
257        
258        tmpP.add(targetObject);
259        targetObject.setName("linktarget");
260        namePanel.add(tmpP, BorderLayout.CENTER);
261        contentPane.add(namePanel, BorderLayout.CENTER);
262
263        // locate the H5Property dialog
264        Point l = owner.getLocation();
265        l.x += 250;
266        l.y += 100;
267        setLocation(l);
268        validate();
269        pack();
270    }
271
272    public void actionPerformed(ActionEvent e) {
273        Object source = e.getSource();
274        String cmd = e.getActionCommand();
275        
276        if (cmd.equals("Help on Links")) {
277            final String msg = "The Type of Link specifies which type of link the user wants to create. \n"
278                + "It could be hard, soft or external links. \n\n"
279                + "<html><b>Hard Link</b></html> \n"
280                + "Hard Link creates a hard link to a pre-existing object in an HDF5 file. \n"    
281                + "The target object must already exist in the file.\n" 
282                + "The HDF5 library keeps a count of all hard links pointing to an object. \n\n"
283                + "<html><b>Soft Link</b></html> \n"
284                + "Soft Link creates a new soft link to an object in an HDF5 file. \n" 
285                + "Soft links are only for use only if the target object is in the current file. \n"
286                + "Unlike hard links, a soft link in an HDF5 file is allowed to dangle, \n" 
287                + "meaning that the target object need not exist at the time that the link is created.\n"
288                + "The HDF5 library does not keep a count of soft links  \n\n"
289                + "<html><b>External Link</b></html> \n"
290                + "External Link creates a new soft link to an external object, which is an object\n" 
291                + "in a different HDF5 file from the location of the link. External links are \n"
292                + "allowed to dangle like soft links. \n\n"
293                + "Soft links and external links are also known as symbolic links as they use \n" 
294                + "a name to point to an object; hard links employ an object's address in the file.  \n\n\n";
295            JOptionPane.showMessageDialog(this, msg);
296        }
297   
298        if (cmd.equals("Browse File")) {        
299            String filename = null;
300            filename = openTargetFile();
301            
302             if (filename == null) {
303                 return;
304             }
305             targetFile.setText(filename);
306         }
307               
308        if (cmd.equals("Ok")) {
309            newObject = createLink();
310
311            if (newObject != null) {
312                dispose();
313            }
314        }
315        if (cmd.equals("Cancel")) {
316            newObject = null;
317            dispose();
318            ((Vector<HObject>) groupList).setSize(0);
319        }
320    }
321
322    private String openTargetFile()
323    {
324        JFileChooser fchooser = new JFileChooser(currentDir);
325        fchooser.setFileFilter(DefaultFileFilter.getFileFilter());
326
327        int returnVal = fchooser.showOpenDialog(this);
328        if(returnVal != JFileChooser.APPROVE_OPTION) {
329                return null;
330        }
331
332        File choosedFile = fchooser.getSelectedFile();
333
334        if (choosedFile == null) {
335                return null;
336        }
337
338        if (choosedFile.isDirectory()) {
339                currentDir = choosedFile.getPath();
340        } 
341        else {
342                currentDir = choosedFile.getParent();
343        }
344
345        return choosedFile.getAbsolutePath();
346    }
347   
348    private final List<Object> breadthFirstUserObjects(TreeNode node)
349    {
350        if (node == null) {
351            return null;
352        }
353
354        Vector<Object> list = new Vector<Object>();
355        DefaultMutableTreeNode theNode = null;
356        Enumeration<?> local_enum = ((DefaultMutableTreeNode)node).breadthFirstEnumeration();
357        while(local_enum.hasMoreElements()) {
358            theNode = (DefaultMutableTreeNode)local_enum.nextElement();
359            list.add(theNode.getUserObject());
360        }
361
362        return list;
363    }
364   
365    private HObject createLink() {
366        String name = null;
367        Group pgroup = null;
368        HObject obj = null;
369
370        name = nameField.getText().trim();
371        if ((name == null) || (name.length() < 1)) {
372            toolkit.beep();
373            JOptionPane.showMessageDialog(this,
374                    "Link name is not specified.", getTitle(),
375                    JOptionPane.ERROR_MESSAGE);
376            return null;
377        }
378
379        if (name.indexOf(HObject.separator) >= 0) {
380            toolkit.beep();
381            JOptionPane.showMessageDialog(this,
382                    "Link name cannot contain path.", getTitle(),
383                    JOptionPane.ERROR_MESSAGE);
384            return null;
385        }
386
387        pgroup = (Group) groupList.get(parentChoice.getSelectedIndex());
388
389        if (pgroup == null) {
390            toolkit.beep();
391            JOptionPane.showMessageDialog(this, "Parent group is null.",
392                    getTitle(), JOptionPane.ERROR_MESSAGE);
393            return null;
394        }    
395
396        if (hardLink.isSelected()) {
397            HObject targetObj = (HObject) objList.get(targetObject
398                    .getSelectedIndex());
399
400            if (targetObj == null) {
401                toolkit.beep();
402                JOptionPane.showMessageDialog(this, "Target object is null.",
403                        getTitle(), JOptionPane.ERROR_MESSAGE);
404                return null;
405            }
406
407            if ((targetObj instanceof Group) && ((Group) targetObj).isRoot()) {
408                toolkit.beep();
409                JOptionPane.showMessageDialog(this,
410                        "Cannot make a link to the root group.", getTitle(),
411                        JOptionPane.ERROR_MESSAGE);
412                return null;
413            }
414            
415            try {
416                obj = fileFormat.createLink(pgroup, name, targetObj);
417            }
418            catch (Exception ex) {
419                toolkit.beep();
420                JOptionPane.showMessageDialog(this, ex, getTitle(),
421                        JOptionPane.ERROR_MESSAGE);
422                return null;
423            }          
424        }
425        else if (softLink.isSelected()){            
426            String target_name = targetObject.getEditor().getItem().toString();
427            if (target_name.length() < 1)  {
428                toolkit.beep();
429                JOptionPane.showMessageDialog(this,
430                        "Target object name is not specified.", getTitle(),
431                        JOptionPane.ERROR_MESSAGE);
432                return null;
433            }
434
435            HObject targetObj = null;
436            try {
437                targetObj = fileFormat.get(targetObject.getEditor().getItem().toString());
438            } 
439            catch (Exception ex) {
440                log.debug("softlink:", ex);
441            }
442                   
443            String tObj = null;
444            if(targetObj==null){
445                tObj = targetObject.getEditor().getItem().toString();
446                
447                if (!tObj.startsWith(HObject.separator)) {
448                    tObj = HObject.separator + tObj;
449                }
450            }
451            
452            if ((targetObj instanceof Group) && ((Group) targetObj).isRoot()) {
453                toolkit.beep();
454                JOptionPane.showMessageDialog(this,
455                        "Cannot make a link to the root group.", getTitle(),
456                        JOptionPane.ERROR_MESSAGE);
457                return null;
458            }
459
460            try {
461                if(targetObj !=null)
462                    obj = fileFormat.createLink(pgroup, name, targetObj, Group.LINK_TYPE_SOFT);
463                else if(tObj!=null)
464                    obj = fileFormat.createLink(pgroup, name, tObj, Group.LINK_TYPE_SOFT);
465            }
466            catch (Exception ex) {
467                ex.printStackTrace();
468                toolkit.beep();
469                JOptionPane.showMessageDialog(this, ex, getTitle(),
470                        JOptionPane.ERROR_MESSAGE);
471                return null;
472            }
473        }
474        else if (externalLink.isSelected()){
475            String TargetFileName = targetFile.getText();
476            FileFormat TargetFileFormat = null;
477            int fileAccessID = FileFormat.FILE_CREATE_OPEN;
478
479            File TargetFile = new File(TargetFileName);
480
481            if (!TargetFile.exists()) {               
482                return null;
483            }
484            FileFormat h5format = FileFormat.getFileFormat(FileFormat.FILE_TYPE_HDF5);
485            try {
486                //h5format.close();
487                TargetFileFormat = h5format.createInstance(TargetFileName, fileAccessID);
488                TargetFileFormat.open(); //open the file
489            } 
490            catch (Exception ex) {
491                log.debug("external link:", ex);
492                return null;
493            } 
494            
495            HObject targetObj = null;
496            try{
497                targetObj = TargetFileFormat.get(targetObject.getEditor().getItem().toString());
498            }
499            catch (Exception ex) {
500                ex.printStackTrace();
501            } 
502            
503            try {                            
504                TargetFileFormat.close();
505            } 
506            catch (Exception ex) {
507                log.debug("external link:", ex);
508            }
509                 
510            String tFileObj = null;         
511            if(targetObj==null){
512                String tObj = null;
513                tObj = targetObject.getEditor().getItem().toString();
514                if (tObj.length() < 1)  {
515                    toolkit.beep();
516                    JOptionPane.showMessageDialog(this,
517                            "Target object name not specified.", getTitle(),
518                            JOptionPane.ERROR_MESSAGE);
519                    return null;
520                }
521                tFileObj = TargetFileName + FileFormat.FILE_OBJ_SEP + tObj;
522            }
523// should allow to link to the root of an external file            
524//            if ((targetObj instanceof Group) && ((Group) targetObj).isRoot()) {
525//                toolkit.beep();
526//                JOptionPane.showMessageDialog(this,
527//                        "Cannot make a link to the root group.", getTitle(),
528//                        JOptionPane.ERROR_MESSAGE);
529//                return null;
530//            }
531
532            try {
533                if(targetObj !=null)
534                        obj = fileFormat.createLink(pgroup, name, targetObj, Group.LINK_TYPE_EXTERNAL);
535                else if(tFileObj!=null)
536                    obj = fileFormat.createLink(pgroup, name, tFileObj, Group.LINK_TYPE_EXTERNAL);
537            }
538            catch (Exception ex) {
539                ex.printStackTrace();
540                toolkit.beep();
541                JOptionPane.showMessageDialog(this, ex, getTitle(),
542                        JOptionPane.ERROR_MESSAGE);
543                return null;
544            }
545        }
546        
547        return obj;
548    }
549
550    /**
551     * Returns the new dataset created.
552     * 
553     * @return The new Dataset created
554     */
555    public DataFormat getObject() {
556        return newObject;
557    }
558
559    /**
560     * Returns the parent group of the new dataset.
561     * 
562     * @return The parent group of the new Dataset
563     */
564    public Group getParentGroup() {
565        return (Group) groupList.get(parentChoice.getSelectedIndex());
566    }
567
568    public void changedUpdate(DocumentEvent arg0) {        
569    }
570
571    public void insertUpdate(DocumentEvent e) {
572        targetObject.setEnabled(true);
573        getTargetFileObjs();
574    }
575
576    public void removeUpdate(DocumentEvent arg0) {
577        targetObject.setEnabled(true);
578        getTargetFileObjs();
579    }
580    
581    //Retrieving objects from Target File.
582    private void getTargetFileObjs(){
583        FileFormat fileFormatC = null;
584        int fileAccessID = FileFormat.FILE_CREATE_OPEN;
585        String filename = null;
586        filename = targetFile.getText();
587
588        if (filename == null || filename.length()<1) {
589            return;
590        }
591
592        //Check if the target File is not the current file.
593        String CurrentFileName = fileFormat.getAbsolutePath();
594        if(CurrentFileName.equals(filename))
595            targetObject.setEnabled(false);
596
597        //Check if the target File is open in treeView
598        if (isFileOpen(filename)) {
599            return;
600        }
601
602        File choosedFile = new File(filename);
603
604        if (!choosedFile.exists()) {
605            targetObject.setEnabled(false);
606            return;
607        }
608        FileFormat h5format = FileFormat.getFileFormat(FileFormat.FILE_TYPE_HDF5);
609        try {
610            //h5format.close();
611            fileFormatC = h5format.createInstance(filename, fileAccessID);
612            fileFormatC.open(); //open the file
613
614        } 
615        catch (Exception ex) {
616            targetObject.setEnabled(false);
617            toolkit.beep();
618            JOptionPane.showMessageDialog(this,"Invalid File Format", getTitle(),
619                    JOptionPane.ERROR_MESSAGE);    
620            return;
621        } 
622
623        //getting the list of objects from the file:-
624        retriveObjects(fileFormatC);
625
626        try {             
627            fileFormatC.close();    
628        } 
629        catch (Exception ex) {
630                log.debug("FileFormat close:", ex);
631        }
632    }
633    
634    //Function to check if the target File is open in treeView
635    private boolean isFileOpen(String filename)
636    {
637        boolean isOpen = false;
638        FileFormat theFile = null;
639
640        Iterator<?> iterator = fileList.iterator();
641        while(iterator.hasNext()) {
642                theFile = (FileFormat)iterator.next();
643                if (theFile.getFilePath().equals(filename)) {
644                        isOpen = true;
645                        if(!theFile.isThisType(FileFormat.getFileFormat(FileFormat.FILE_TYPE_HDF5))){
646                                targetObject.setEnabled(false);       
647                        }
648                        retriveObjects(theFile);
649                        break;
650                }
651        } // while(iterator.hasNext())
652
653        return isOpen;
654    }
655
656    public void itemStateChanged(ItemEvent e) {
657        Object source = e.getSource();
658
659        if (source instanceof JRadioButton) {
660            if (source.equals(hardLink) || source.equals(softLink) || source.equals(externalLink)) {
661                if (hardLink.isSelected()) {
662                    targetFile.setEnabled(false);
663                    targetFileButton.setEnabled(false);
664                    targetObject.setEnabled(true);
665                    targetObject.setEditable(false);                    
666                    retriveObjects(fileFormat);
667                }
668                else if (softLink.isSelected()) {
669                    targetFile.setEnabled(false);
670                    targetFileButton.setEnabled(false);
671                    targetObject.setEnabled(true);
672                    targetObject.setEditable(true);
673                    retriveObjects(fileFormat);
674                }
675                else if (externalLink.isSelected()) {
676                    targetFile.setEnabled(true);
677                    targetFileButton.setEnabled(true);
678                    targetObject.setEnabled(true);
679                    targetObject.setEditable(true);
680                    targetObject.removeAllItems();
681                }
682            }
683        }
684    }
685    
686    //getting the list of objects from the file:-
687    private void retriveObjects(FileFormat file) {        
688        List<Object> objsFile =  breadthFirstUserObjects(file.getRootNode());
689        List<HObject> groupListFile = new Vector<HObject>(objsFile.size());
690        HObject obj = null;
691        Iterator<Object> iterator = objsFile.iterator();
692        List<Object> objListFile = objsFile;
693        String full_name = null;
694        int idx_root = -1, idx = -1;
695        targetObject.removeAllItems();
696        while (iterator.hasNext()) {
697            obj = (HObject) iterator.next();
698            idx++;
699
700            if (obj instanceof Group) {
701                Group g = (Group) obj;
702                groupListFile.add(obj);
703                if (g.isRoot()) {
704                    full_name = HObject.separator;
705                    idx_root = idx;
706                }
707                else {
708                    full_name = g.getPath() + g.getName() + HObject.separator;
709                }
710            }
711            else {
712                full_name = obj.getPath() + obj.getName();
713            }
714            targetObject.addItem(full_name);
715        }
716        targetObject.removeItemAt(idx_root);
717        objListFile.remove(idx_root);           
718    }
719    
720}
721