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