001/*
002 * Copyright 2010-2015 Institut Pasteur.
003 * 
004 * This file is part of Icy.
005 * 
006 * Icy is free software: you can redistribute it and/or modify
007 * it under the terms of the GNU General Public License as published by
008 * the Free Software Foundation, either version 3 of the License, or
009 * (at your option) any later version.
010 * 
011 * Icy is distributed in the hope that it will be useful,
012 * but WITHOUT ANY WARRANTY; without even the implied warranty of
013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
014 * GNU General Public License for more details.
015 * 
016 * You should have received a copy of the GNU General Public License
017 * along with Icy. If not, see <http://www.gnu.org/licenses/>.
018 */
019package icy.gui.sequence;
020
021import icy.file.FileUtil;
022import icy.gui.component.button.IcyButton;
023import icy.gui.frame.GenericFrame;
024import icy.gui.main.ActiveSequenceListener;
025import icy.main.Icy;
026import icy.math.UnitUtil;
027import icy.math.UnitUtil.UnitPrefix;
028import icy.resource.ResourceUtil;
029import icy.resource.icon.IcyIcon;
030import icy.sequence.Sequence;
031import icy.sequence.SequenceEvent;
032import icy.system.IcyExceptionHandler;
033import icy.system.SystemUtil;
034import icy.system.thread.ThreadUtil;
035import icy.util.EventUtil;
036import icy.util.StringUtil;
037
038import java.awt.Dimension;
039import java.awt.GridBagConstraints;
040import java.awt.GridBagLayout;
041import java.awt.Insets;
042import java.awt.event.ActionEvent;
043import java.awt.event.ActionListener;
044import java.awt.event.MouseAdapter;
045import java.awt.event.MouseEvent;
046import java.io.IOException;
047
048import javax.swing.JLabel;
049import javax.swing.JPanel;
050import javax.swing.JTextField;
051
052/**
053 * @author Stephane
054 */
055public class SequenceInfosPanel extends JPanel implements ActiveSequenceListener
056{
057    /**
058     * 
059     */
060    private static final long serialVersionUID = -6123324347914804260L;
061
062    // GUI
063    private JLabel dimensionLabel;
064    private JLabel resXLabel;
065    private JLabel resYLabel;
066    private JLabel resZLabel;
067    private JLabel resTLabel;
068    private JLabel sizeLabel;
069    private JLabel channelLabel;
070
071    private IcyButton editBtn;
072    private IcyButton detailBtn;
073
074    private JLabel pathLabel;
075    JTextField pathField;
076    private JTextField nameField;
077
078    // internals
079    private final Runnable infosRefresher;
080
081    public SequenceInfosPanel()
082    {
083        super();
084
085        initialize();
086
087        editBtn.addActionListener(new ActionListener()
088        {
089            @Override
090            public void actionPerformed(ActionEvent e)
091            {
092                // it should be the current focused sequence
093                final Sequence seq = Icy.getMainInterface().getActiveSequence();
094
095                if (seq != null)
096                    new SequencePropertiesDialog(seq);
097            }
098        });
099
100        detailBtn.addActionListener(new ActionListener()
101        {
102            @Override
103            public void actionPerformed(ActionEvent e)
104            {
105                // it should be the current focused sequence
106                final Sequence seq = Icy.getMainInterface().getActiveSequence();
107
108                if (seq != null)
109                {
110                    final GenericFrame g = new GenericFrame(seq.getName() + " - Metadata", new SequenceMetadataPanel(
111                            seq));
112
113                    g.addToDesktopPane();
114                    g.center();
115                    g.requestFocus();
116                }
117            }
118        });
119
120        infosRefresher = new Runnable()
121        {
122            @Override
123            public void run()
124            {
125                ThreadUtil.invokeNow(new Runnable()
126                {
127                    @Override
128                    public void run()
129                    {
130                        updateInfosInternal(Icy.getMainInterface().getActiveSequence());
131                    }
132                });
133            }
134        };
135
136        updateInfosInternal(null);
137    }
138
139    public void initialize()
140    {
141        GridBagLayout gridBagLayout = new GridBagLayout();
142        gridBagLayout.columnWidths = new int[] {0, 40, 40, 40, 0};
143        gridBagLayout.rowHeights = new int[] {18, 0, 18, 18, 18, 18, 18, 18, 0};
144        gridBagLayout.columnWeights = new double[] {0.0, 1.0, 1.0, 1.0, Double.MIN_VALUE};
145        gridBagLayout.rowWeights = new double[] {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, Double.MIN_VALUE};
146        setLayout(gridBagLayout);
147
148        JLabel lbl_name = new JLabel("Name");
149        lbl_name.setToolTipText("Sequence name");
150        GridBagConstraints gbc_lbl_name = new GridBagConstraints();
151        gbc_lbl_name.anchor = GridBagConstraints.WEST;
152        gbc_lbl_name.fill = GridBagConstraints.VERTICAL;
153        gbc_lbl_name.insets = new Insets(0, 0, 5, 5);
154        gbc_lbl_name.gridx = 0;
155        gbc_lbl_name.gridy = 0;
156        add(lbl_name, gbc_lbl_name);
157
158        nameField = new JTextField()
159        {
160            @Override
161            public Dimension getPreferredSize()
162            {
163                final Dimension result = super.getPreferredSize();
164                // prevent enlarging panel
165                result.width = 100;
166                return result;
167            }
168        };
169        nameField.setOpaque(false);
170        nameField.setBorder(null);
171        nameField.setEditable(false);
172
173        GridBagConstraints gbc_scrollPane = new GridBagConstraints();
174        gbc_scrollPane.fill = GridBagConstraints.BOTH;
175        gbc_scrollPane.gridwidth = 3;
176        gbc_scrollPane.insets = new Insets(0, 0, 5, 0);
177        gbc_scrollPane.gridx = 1;
178        gbc_scrollPane.gridy = 0;
179        add(nameField, gbc_scrollPane);
180
181        pathLabel = new JLabel("Path");
182        pathLabel.setToolTipText("Sequence file path");
183        GridBagConstraints gbc_pathLabel = new GridBagConstraints();
184        gbc_pathLabel.fill = GridBagConstraints.VERTICAL;
185        gbc_pathLabel.anchor = GridBagConstraints.WEST;
186        gbc_pathLabel.insets = new Insets(0, 0, 5, 5);
187        gbc_pathLabel.gridx = 0;
188        gbc_pathLabel.gridy = 1;
189        add(pathLabel, gbc_pathLabel);
190
191        pathField = new JTextField()
192        {
193            @Override
194            public Dimension getPreferredSize()
195            {
196                final Dimension result = super.getPreferredSize();
197                // prevent enlarging panel
198                result.width = 100;
199                return result;
200            }
201        };
202        pathField.setOpaque(false);
203        pathField.setBorder(null);
204        pathField.setEditable(false);
205        pathField.addMouseListener(new MouseAdapter()
206        {
207            @Override
208            public void mouseClicked(MouseEvent e)
209            {
210                if (e.isConsumed())
211                    return;
212
213                if (EventUtil.isLeftMouseButton(e) && (e.getClickCount() == 2))
214                {
215                    try
216                    {
217                        SystemUtil.openFolder(FileUtil.getDirectory(pathField.getText()));
218                    }
219                    catch (IOException e1)
220                    {
221                        IcyExceptionHandler.showErrorMessage(e1, false, false);
222                    }
223
224                    e.consume();
225                }
226            }
227        });
228
229        GridBagConstraints gbc_scrollPane_1 = new GridBagConstraints();
230        gbc_scrollPane_1.fill = GridBagConstraints.BOTH;
231        gbc_scrollPane_1.gridwidth = 3;
232        gbc_scrollPane_1.insets = new Insets(0, 0, 5, 5);
233        gbc_scrollPane_1.gridx = 1;
234        gbc_scrollPane_1.gridy = 1;
235        add(pathField, gbc_scrollPane_1);
236
237        JLabel lbl_dim = new JLabel("Dimension");
238        lbl_dim.setToolTipText("Size of X, Y, Z and T dimension");
239        GridBagConstraints gbc_lbl_dim = new GridBagConstraints();
240        gbc_lbl_dim.anchor = GridBagConstraints.WEST;
241        gbc_lbl_dim.fill = GridBagConstraints.VERTICAL;
242        gbc_lbl_dim.insets = new Insets(0, 0, 5, 5);
243        gbc_lbl_dim.gridx = 0;
244        gbc_lbl_dim.gridy = 2;
245        add(lbl_dim, gbc_lbl_dim);
246
247        dimensionLabel = new JLabel();
248        dimensionLabel.setText("---");
249        GridBagConstraints gbc_dimensionLabel = new GridBagConstraints();
250        gbc_dimensionLabel.anchor = GridBagConstraints.WEST;
251        gbc_dimensionLabel.gridwidth = 3;
252        gbc_dimensionLabel.fill = GridBagConstraints.VERTICAL;
253        gbc_dimensionLabel.insets = new Insets(0, 0, 5, 0);
254        gbc_dimensionLabel.gridx = 1;
255        gbc_dimensionLabel.gridy = 2;
256        add(dimensionLabel, gbc_dimensionLabel);
257
258        JLabel lbl_channel = new JLabel("Channel");
259        lbl_channel.setToolTipText("Number of channel - data type");
260        GridBagConstraints gbc_lbl_channel = new GridBagConstraints();
261        gbc_lbl_channel.anchor = GridBagConstraints.WEST;
262        gbc_lbl_channel.fill = GridBagConstraints.VERTICAL;
263        gbc_lbl_channel.insets = new Insets(0, 0, 5, 5);
264        gbc_lbl_channel.gridx = 0;
265        gbc_lbl_channel.gridy = 3;
266        add(lbl_channel, gbc_lbl_channel);
267
268        channelLabel = new JLabel();
269        channelLabel.setText("---");
270        GridBagConstraints gbc_channelLabel = new GridBagConstraints();
271        gbc_channelLabel.anchor = GridBagConstraints.WEST;
272        gbc_channelLabel.gridwidth = 3;
273        gbc_channelLabel.fill = GridBagConstraints.VERTICAL;
274        gbc_channelLabel.insets = new Insets(0, 0, 5, 0);
275        gbc_channelLabel.gridx = 1;
276        gbc_channelLabel.gridy = 3;
277        add(channelLabel, gbc_channelLabel);
278
279        JLabel lbl_size = new JLabel("Size");
280        lbl_size.setToolTipText("Size");
281        GridBagConstraints gbc_lbl_size = new GridBagConstraints();
282        gbc_lbl_size.anchor = GridBagConstraints.WEST;
283        gbc_lbl_size.fill = GridBagConstraints.VERTICAL;
284        gbc_lbl_size.insets = new Insets(0, 0, 5, 5);
285        gbc_lbl_size.gridx = 0;
286        gbc_lbl_size.gridy = 4;
287        add(lbl_size, gbc_lbl_size);
288
289        sizeLabel = new JLabel();
290        sizeLabel.setText("---");
291        GridBagConstraints gbc_sizeLabel = new GridBagConstraints();
292        gbc_sizeLabel.anchor = GridBagConstraints.WEST;
293        gbc_sizeLabel.gridwidth = 3;
294        gbc_sizeLabel.fill = GridBagConstraints.VERTICAL;
295        gbc_sizeLabel.insets = new Insets(0, 0, 5, 0);
296        gbc_sizeLabel.gridx = 1;
297        gbc_sizeLabel.gridy = 4;
298        add(sizeLabel, gbc_sizeLabel);
299
300        JLabel lbl_psx = new JLabel("Pixel size");
301        lbl_psx.setToolTipText("Pixel size for X, Y, Z dimension");
302        GridBagConstraints gbc_lbl_psx = new GridBagConstraints();
303        gbc_lbl_psx.anchor = GridBagConstraints.WEST;
304        gbc_lbl_psx.fill = GridBagConstraints.VERTICAL;
305        gbc_lbl_psx.insets = new Insets(0, 0, 5, 5);
306        gbc_lbl_psx.gridx = 0;
307        gbc_lbl_psx.gridy = 5;
308        add(lbl_psx, gbc_lbl_psx);
309
310        resXLabel = new JLabel();
311        resXLabel.setText("---");
312        GridBagConstraints gbc_resXLabel = new GridBagConstraints();
313        gbc_resXLabel.anchor = GridBagConstraints.WEST;
314        gbc_resXLabel.fill = GridBagConstraints.VERTICAL;
315        gbc_resXLabel.insets = new Insets(0, 0, 5, 5);
316        gbc_resXLabel.gridx = 1;
317        gbc_resXLabel.gridy = 5;
318        add(resXLabel, gbc_resXLabel);
319
320        resYLabel = new JLabel();
321        resYLabel.setText("---");
322        GridBagConstraints gbc_resYLabel = new GridBagConstraints();
323        gbc_resYLabel.anchor = GridBagConstraints.WEST;
324        gbc_resYLabel.fill = GridBagConstraints.VERTICAL;
325        gbc_resYLabel.insets = new Insets(0, 0, 5, 5);
326        gbc_resYLabel.gridx = 2;
327        gbc_resYLabel.gridy = 5;
328        add(resYLabel, gbc_resYLabel);
329
330        resZLabel = new JLabel();
331        resZLabel.setText("---");
332        GridBagConstraints gbc_resZLabel = new GridBagConstraints();
333        gbc_resZLabel.anchor = GridBagConstraints.WEST;
334        gbc_resZLabel.fill = GridBagConstraints.VERTICAL;
335        gbc_resZLabel.insets = new Insets(0, 0, 5, 0);
336        gbc_resZLabel.gridx = 3;
337        gbc_resZLabel.gridy = 5;
338        add(resZLabel, gbc_resZLabel);
339
340        JLabel lbl_time = new JLabel("Time interval");
341        lbl_time.setToolTipText("Time Interval");
342        GridBagConstraints gbc_lbl_time = new GridBagConstraints();
343        gbc_lbl_time.anchor = GridBagConstraints.WEST;
344        gbc_lbl_time.fill = GridBagConstraints.VERTICAL;
345        gbc_lbl_time.insets = new Insets(0, 0, 5, 5);
346        gbc_lbl_time.gridx = 0;
347        gbc_lbl_time.gridy = 6;
348        add(lbl_time, gbc_lbl_time);
349
350        resTLabel = new JLabel();
351        resTLabel.setText("---");
352        GridBagConstraints gbc_resTLabel = new GridBagConstraints();
353        gbc_resTLabel.anchor = GridBagConstraints.WEST;
354        gbc_resTLabel.gridwidth = 3;
355        gbc_resTLabel.fill = GridBagConstraints.VERTICAL;
356        gbc_resTLabel.insets = new Insets(0, 0, 5, 0);
357        gbc_resTLabel.gridx = 1;
358        gbc_resTLabel.gridy = 6;
359        add(resTLabel, gbc_resTLabel);
360
361        editBtn = new IcyButton("Edit", new IcyIcon(ResourceUtil.ICON_DOCEDIT));
362        editBtn.setToolTipText("Edit sequence properties");
363
364        GridBagConstraints gbc_editBtn = new GridBagConstraints();
365        gbc_editBtn.gridwidth = 2;
366        gbc_editBtn.fill = GridBagConstraints.BOTH;
367        gbc_editBtn.insets = new Insets(0, 0, 0, 5);
368        gbc_editBtn.gridx = 0;
369        gbc_editBtn.gridy = 7;
370        add(editBtn, gbc_editBtn);
371
372        detailBtn = new IcyButton("Show metadata", new IcyIcon(ResourceUtil.ICON_PROPERTIES));
373        detailBtn.setText("Metadata");
374        detailBtn.setToolTipText("Show all associated metadata informations");
375
376        GridBagConstraints gbc_detailBtn = new GridBagConstraints();
377        gbc_detailBtn.gridwidth = 2;
378        gbc_detailBtn.fill = GridBagConstraints.BOTH;
379        gbc_detailBtn.gridx = 2;
380        gbc_detailBtn.gridy = 7;
381        add(detailBtn, gbc_detailBtn);
382    }
383
384    public void updateInfos()
385    {
386        ThreadUtil.runSingle(infosRefresher);
387    }
388
389    public void updateInfosInternal(Sequence sequence)
390    {
391        if (sequence != null)
392        {
393            final int sizeX = sequence.getSizeX();
394            final int sizeY = sequence.getSizeY();
395            final int sizeZ = sequence.getSizeZ();
396            final int sizeT = sequence.getSizeT();
397            final int sizeC = sequence.getSizeC();
398
399            final double pxSizeX = sequence.getPixelSizeX();
400            final double pxSizeY = sequence.getPixelSizeY();
401            final double pxSizeZ = sequence.getPixelSizeZ();
402
403            final String path = sequence.getFilename();
404
405            nameField.setText(sequence.getName());
406            // path
407            if (StringUtil.isEmpty(path))
408            {
409                pathLabel.setVisible(false);
410                pathField.setVisible(false);
411            }
412            else
413            {
414                pathLabel.setVisible(true);
415                pathField.setVisible(true);
416                pathField.setText(path);
417            }
418            dimensionLabel.setText(sizeX + " x " + sizeY + " x " + sizeZ + " x " + sizeT);
419            channelLabel.setText(sizeC + " - " + sequence.getDataType_().toLongString());
420            sizeLabel.setText(UnitUtil.getBytesString((double) sizeX * (double) sizeY * sizeZ * sizeT * sizeC
421                    * sequence.getDataType_().getSize()));
422            resXLabel.setText(UnitUtil.getBestUnitInMeters(pxSizeX, 2, UnitPrefix.MICRO));
423            resYLabel.setText(UnitUtil.getBestUnitInMeters(pxSizeY, 2, UnitPrefix.MICRO));
424            resZLabel.setText(UnitUtil.getBestUnitInMeters(pxSizeZ, 2, UnitPrefix.MICRO));
425            resTLabel.setText(UnitUtil.displayTimeAsStringWithUnits(sequence.getTimeInterval() * 1000d, false));
426
427            nameField.setToolTipText(sequence.getName());
428            pathField.setToolTipText(path + "    (double click to see file location)");
429            dimensionLabel.setToolTipText("Size X : " + sizeX + "   Size Y : " + sizeY + "   Size Z : " + sizeZ
430                    + "   Size T : " + sizeT);
431            if (sizeC > 1)
432                channelLabel.setToolTipText(sizeC + " channels - " + sequence.getDataType_());
433            else
434                channelLabel.setToolTipText(sizeC + " channel - " + sequence.getDataType_());
435            sizeLabel.setToolTipText(sizeLabel.getText());
436
437            resXLabel.setToolTipText("X pixel resolution: " + resXLabel.getText());
438            resYLabel.setToolTipText("Y pixel resolution: " + resYLabel.getText());
439            resZLabel.setToolTipText("Z pixel resolution: " + resZLabel.getText());
440            resTLabel.setToolTipText("T time resolution: " + resTLabel.getText());
441
442            editBtn.setEnabled(true);
443            detailBtn.setEnabled(true);
444        }
445        else
446        {
447            pathLabel.setVisible(false);
448            pathField.setVisible(false);
449
450            nameField.setText("-");
451            dimensionLabel.setText("-");
452            channelLabel.setText("-");
453            sizeLabel.setText("-");
454            resXLabel.setText("-");
455            resYLabel.setText("-");
456            resZLabel.setText("-");
457            resTLabel.setText("-");
458
459            nameField.setToolTipText("");
460            dimensionLabel.setToolTipText("");
461            channelLabel.setToolTipText("");
462            sizeLabel.setToolTipText("");
463            resXLabel.setToolTipText("X pixel resolution");
464            resYLabel.setToolTipText("Y pixel resolution");
465            resZLabel.setToolTipText("Z pixel resolution");
466            resTLabel.setToolTipText("T time resolution");
467
468            editBtn.setEnabled(false);
469            detailBtn.setEnabled(false);
470        }
471
472        revalidate();
473    }
474
475    @Override
476    public void sequenceActivated(Sequence sequence)
477    {
478        updateInfos();
479    }
480
481    @Override
482    public void sequenceDeactivated(Sequence sequence)
483    {
484        // nothing to do here
485    }
486
487    @Override
488    public void activeSequenceChanged(SequenceEvent event)
489    {
490        switch (event.getSourceType())
491        {
492            case SEQUENCE_DATA:
493            case SEQUENCE_TYPE:
494            case SEQUENCE_META:
495                updateInfos();
496                break;
497        }
498    }
499}