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.action;
020
021import java.awt.Rectangle;
022import java.awt.event.ActionEvent;
023import java.awt.event.KeyEvent;
024import java.io.File;
025import java.lang.reflect.Field;
026import java.util.ArrayList;
027import java.util.Arrays;
028import java.util.List;
029
030import icy.file.Saver;
031import icy.gui.dialog.LoaderDialog;
032import icy.gui.dialog.MessageDialog;
033import icy.gui.dialog.SaverDialog;
034import icy.gui.menu.ApplicationMenu;
035import icy.gui.viewer.Viewer;
036import icy.image.IcyBufferedImage;
037import icy.main.Icy;
038import icy.preferences.GeneralPreferences;
039import icy.resource.ResourceUtil;
040import icy.resource.icon.IcyIcon;
041import icy.roi.ROI;
042import icy.sequence.Sequence;
043import icy.sequence.SequenceUtil;
044import icy.system.SystemUtil;
045import icy.system.thread.ThreadUtil;
046import icy.type.DataType;
047import icy.util.ClassUtil;
048import icy.util.StringUtil;
049
050/**
051 * File actions (open / save / close...)
052 * 
053 * @author Stephane
054 */
055public class FileActions
056{
057    // public static class OpenSequenceRegionAction extends IcyAbstractAction
058    // {
059    // final int resolution;
060    //
061    // public OpenSequenceRegionAction(int resolution)
062    // {
063    // super("Open at resolution 1/" + ((int) Math.pow(2, resolution)), null,
064    // "Open image region at resolution 1/" + ((int) Math.pow(2, resolution)),
065    // "Open the selected region from the original image at resolution 1/"
066    // + ((int) Math.pow(2, resolution)),
067    // true, null);
068    //
069    // this.resolution = resolution;
070    // }
071    //
072    // @Override
073    // public boolean doAction(ActionEvent e)
074    // {
075    // final Sequence sequence = Icy.getMainInterface().getActiveSequence();
076    //
077    // if (sequence != null)
078    // {
079    // final String path = sequence.getFilename();
080    //
081    // if (!StringUtil.isEmpty(path))
082    // {
083    // List<ROI> rois = sequence.getROIs();
084    // int size = rois.size();
085    //
086    // if (size == 0)
087    // {
088    // MessageDialog.showDialog(
089    // "There is no ROI in the current sequence.\nYou need a ROI to define the region to open.",
090    // MessageDialog.INFORMATION_MESSAGE);
091    // return false;
092    // }
093    // else if (size > 1)
094    // {
095    // rois = sequence.getSelectedROIs();
096    // size = rois.size();
097    //
098    // if (size == 0)
099    // {
100    // MessageDialog.showDialog("You need to select a ROI to do this operation.",
101    // MessageDialog.INFORMATION_MESSAGE);
102    // return false;
103    // }
104    // else if (size > 1)
105    // {
106    // MessageDialog.showDialog("You must have only one selected ROI to do this operation.",
107    // MessageDialog.INFORMATION_MESSAGE);
108    // return false;
109    // }
110    // }
111    //
112    // final ROI roi = rois.get(0);
113    // final Rectangle bounds = SequenceUtil
114    // .getOriginRectangle(roi.getBounds5D().toRectangle2D().getBounds(), sequence);
115    //
116    // if (!bounds.isEmpty())
117    // {
118    // final Sequence regionSequence = Loader.loadSequence(null, path, sequence.getSerieIndex(),
119    // resolution, bounds, -1, -1, -1, -1, -1, false, true);
120    //
121    // if (regionSequence != null)
122    // {
123    // Icy.getMainInterface().addSequence(regionSequence);
124    // return true;
125    // }
126    // }
127    // }
128    // }
129    //
130    // return false;
131    // }
132    //
133    // @Override
134    // public boolean isEnabled()
135    // {
136    // final Sequence seq = Icy.getMainInterface().getActiveSequence();
137    //
138    // return super.isEnabled() && (seq != null) && (!StringUtil.isEmpty(seq.getFilename()) &&
139    // seq.hasROI());
140    // }
141    // }
142
143    public static IcyAbstractAction clearRecentFilesAction = new IcyAbstractAction("Clear recent files",
144            new IcyIcon(ResourceUtil.ICON_DOC_COPY), "Clear recent files", "Clear the list of last opened files")
145    {
146        /**
147         * 
148         */
149        private static final long serialVersionUID = 4762494034660452392L;
150
151        @Override
152        public boolean doAction(ActionEvent e)
153        {
154            final ApplicationMenu appMenu = Icy.getMainInterface().getApplicationMenu();
155
156            if (appMenu != null)
157            {
158                appMenu.getRecentFileList().clear();
159                return true;
160            }
161
162            return false;
163        }
164    };
165
166    public static IcyAbstractAction newSequenceAction = new IcyAbstractAction("Create",
167            new IcyIcon(ResourceUtil.ICON_DOC_NEW), "Create an empty sequence")
168    {
169        /**
170         * 
171         */
172        private static final long serialVersionUID = -4799299843248624925L;
173
174        @Override
175        public boolean doAction(ActionEvent e)
176        {
177            Icy.getMainInterface().addSequence(
178                    new Sequence("Single channel sequence", new IcyBufferedImage(512, 512, 1, DataType.UBYTE)));
179            return true;
180        }
181    };
182
183    public static IcyAbstractAction newGraySequenceAction = new IcyAbstractAction("Create gray sequence",
184            new IcyIcon(ResourceUtil.ICON_DOC_NEW), "Create a new gray sequence",
185            "Create a new single channel (gray level) sequence.")
186    {
187        /**
188         * 
189         */
190        private static final long serialVersionUID = 797949281499261778L;
191
192        @Override
193        public boolean doAction(ActionEvent e)
194        {
195            ThreadUtil.bgRun(new Runnable()
196            {
197                @Override
198                public void run()
199                {
200                    Icy.getMainInterface().addSequence(
201                            new Sequence("Single channel sequence", new IcyBufferedImage(512, 512, 1, DataType.UBYTE)));
202                }
203            });
204
205            return true;
206        }
207    };
208
209    public static IcyAbstractAction newRGBSequenceAction = new IcyAbstractAction("Create RGB sequence",
210            new IcyIcon(ResourceUtil.ICON_DOC_NEW), "Create a new RGB color sequence",
211            "Create a 3 channels sequence (red, green, blue).")
212    {
213        /**
214         * 
215         */
216        private static final long serialVersionUID = 5755927058175369657L;
217
218        @Override
219        public boolean doAction(ActionEvent e)
220        {
221            ThreadUtil.bgRun(new Runnable()
222            {
223                @Override
224                public void run()
225                {
226                    Icy.getMainInterface().addSequence(
227                            new Sequence("RGB sequence", new IcyBufferedImage(512, 512, 3, DataType.UBYTE)));
228                }
229            });
230
231            return true;
232        }
233    };
234
235    public static IcyAbstractAction newARGBSequenceAction = new IcyAbstractAction("Create RGBA sequence",
236            new IcyIcon(ResourceUtil.ICON_DOC_NEW), "Create a new RGBA color sequence",
237            "Create a 4 channels sequence (red, green, blue, alpha).", true, "Creating RGBA sequence...")
238    {
239        /**
240         * 
241         */
242        private static final long serialVersionUID = -142873334899977341L;
243
244        @Override
245        public boolean doAction(ActionEvent e)
246        {
247            final IcyBufferedImage image = new IcyBufferedImage(512, 512, 4, DataType.UBYTE);
248            Arrays.fill(image.getDataXYAsByte(3), (byte) -1);
249            Icy.getMainInterface().addSequence(new Sequence("RGBA sequence", image));
250
251            return true;
252        }
253    };
254
255    public static IcyAbstractAction openSequenceAction = new IcyAbstractAction("Open...",
256            new IcyIcon(ResourceUtil.ICON_OPEN), "Open a file",
257            "Display a file selection dialog and choose the file to open", KeyEvent.VK_O, SystemUtil.getMenuCtrlMask())
258    {
259        /**
260         * 
261         */
262        private static final long serialVersionUID = 7399973037052771669L;
263
264        @Override
265        public boolean doAction(ActionEvent e)
266        {
267            new LoaderDialog();
268            return true;
269        }
270    };
271
272    public static IcyAbstractAction openSequenceRegionAction = new IcyAbstractAction("Open region...",
273            new IcyIcon(ResourceUtil.ICON_CROP), "Open selected region",
274            "Open the selected ROI region from the original image")
275    {
276
277        /**
278         * 
279         */
280        private static final long serialVersionUID = -2771137583765180575L;
281
282        @Override
283        public boolean doAction(ActionEvent e)
284        {
285            final Sequence sequence = Icy.getMainInterface().getActiveSequence();
286
287            if (sequence != null)
288            {
289                List<ROI> rois = sequence.getROIs();
290                int size = rois.size();
291
292                if (size == 0)
293                {
294                    MessageDialog.showDialog(
295                            "There is no ROI in the current sequence.\nYou need a ROI to define the region to open.",
296                            MessageDialog.INFORMATION_MESSAGE);
297                    return false;
298                }
299                else if (size > 1)
300                {
301                    rois = sequence.getSelectedROIs();
302                    size = rois.size();
303
304                    if (size == 0)
305                    {
306                        MessageDialog.showDialog("You need to select a ROI to do this operation.",
307                                MessageDialog.INFORMATION_MESSAGE);
308                        return false;
309                    }
310                    else if (size > 1)
311                    {
312                        MessageDialog.showDialog("You must have only one selected ROI to do this operation.",
313                                MessageDialog.INFORMATION_MESSAGE);
314                        return false;
315                    }
316                }
317
318                final ROI roi = rois.get(0);
319                Rectangle bounds = SequenceUtil.getOriginRectangle(roi.getBounds5D().toRectangle2D().getBounds(),
320                        sequence);
321                String path = sequence.getFilename();
322
323                if (!bounds.isEmpty())
324                    new LoaderDialog(path, bounds, sequence.getSeries(), true);
325                else
326                    new LoaderDialog(path, null, sequence.getSeries(), true);
327            }
328
329            return false;
330        }
331
332        @Override
333        public boolean isEnabled()
334        {
335            final Sequence seq = Icy.getMainInterface().getActiveSequence();
336
337            return super.isEnabled() && (seq != null) && (!StringUtil.isEmpty(seq.getFilename()) && seq.hasROI());
338        }
339    };
340
341    public static IcyAbstractAction saveSequenceAction = new IcyAbstractAction("Save",
342            new IcyIcon(ResourceUtil.ICON_SAVE), "Save active sequence",
343            "Save the active sequence with its default filename")
344    {
345        /**
346         * 
347         */
348        private static final long serialVersionUID = -8450533919443304021L;
349
350        @Override
351        public boolean doAction(ActionEvent e)
352        {
353            final Viewer viewer = Icy.getMainInterface().getActiveViewer();
354            final Sequence seq = viewer.getSequence();
355
356            if (seq != null)
357            {
358                final String filename = seq.getOutputFilename(true);
359
360                if (StringUtil.isEmpty(filename))
361                    new SaverDialog(seq, true);
362                else
363                {
364                    // background process
365                    ThreadUtil.bgRun(new Runnable()
366                    {
367                        @Override
368                        public void run()
369                        {
370                            final File file = new File(filename);
371
372                            Saver.save(seq, file, !file.exists() || file.isDirectory(), true);
373                        }
374                    });
375                }
376
377                return true;
378            }
379
380            return false;
381        }
382    };
383
384    public static IcyAbstractAction saveDefaultSequenceAction = new IcyAbstractAction("Save...",
385            new IcyIcon(ResourceUtil.ICON_SAVE), "Save active sequence",
386            "Save the active sequence under selected file name", KeyEvent.VK_S, SystemUtil.getMenuCtrlMask())
387    {
388        /**
389         * 
390         */
391        private static final long serialVersionUID = 3556923605878121275L;
392
393        @Override
394        public boolean doAction(ActionEvent e)
395        {
396            final Viewer viewer = Icy.getMainInterface().getActiveViewer();
397
398            if (viewer != null)
399            {
400                final Sequence seq = viewer.getSequence();
401
402                if (seq != null)
403                {
404                    new SaverDialog(seq);
405                    return true;
406                }
407            }
408
409            return false;
410        }
411    };
412
413    public static IcyAbstractAction saveAsSequenceAction = new IcyAbstractAction("Save as...",
414            new IcyIcon(ResourceUtil.ICON_SAVE), "Save active sequence",
415            "Save the active sequence under selected file name", KeyEvent.VK_S, SystemUtil.getMenuCtrlMask())
416    {
417        /**
418         * 
419         */
420        private static final long serialVersionUID = 3556923605878121275L;
421
422        @Override
423        public boolean doAction(ActionEvent e)
424        {
425            final Viewer viewer = Icy.getMainInterface().getActiveViewer();
426
427            if (viewer != null)
428            {
429                final Sequence seq = viewer.getSequence();
430
431                if (seq != null)
432                {
433                    new SaverDialog(seq);
434                    return true;
435                }
436            }
437
438            return false;
439        }
440    };
441
442    public static IcyAbstractAction saveMetaDataAction = new IcyAbstractAction("Save metadata",
443            new IcyIcon(ResourceUtil.ICON_SAVE), "Save active sequence metadata",
444            "Save the metadata of the active sequence now", true, "Saving metadata...")
445    {
446        /**
447         * 
448         */
449        private static final long serialVersionUID = 3556923605878121275L;
450
451        @Override
452        public boolean doAction(ActionEvent e)
453        {
454            // Sequence persistence enabled --> save XML metadata
455            if (GeneralPreferences.getSequencePersistence())
456            {
457                final Sequence seq = Icy.getMainInterface().getActiveSequence();
458                if (seq != null)
459                    return seq.saveXMLData();
460            }
461
462            return false;
463        }
464    };
465
466    public static IcyAbstractAction closeSequenceAction = new IcyAbstractAction("Close",
467            new IcyIcon(ResourceUtil.ICON_CLOSE), "Close active sequence", "Close the current active sequence")
468    {
469        /**
470         * 
471         */
472        private static final long serialVersionUID = 9023064791162525318L;
473
474        @Override
475        public boolean doAction(ActionEvent e)
476        {
477            final Viewer viewer = Icy.getMainInterface().getActiveViewer();
478
479            if (viewer != null)
480            {
481                viewer.close();
482                return true;
483            }
484
485            return false;
486        }
487    };
488
489    public static IcyAbstractAction closeCurrentSequenceAction = new IcyAbstractAction("Close sequence",
490            new IcyIcon(ResourceUtil.ICON_CLOSE), "Close active sequence", "Close the current active sequence")
491    {
492        /**
493         * 
494         */
495        private static final long serialVersionUID = -1127914432836889905L;
496
497        @Override
498        public boolean doAction(ActionEvent e)
499        {
500            final Viewer viewer = Icy.getMainInterface().getActiveViewer();
501
502            if (viewer != null)
503            {
504                viewer.close();
505                return true;
506            }
507
508            return false;
509        }
510    };
511
512    public static IcyAbstractAction closeOthersSequencesAction = new IcyAbstractAction("Close others",
513            new IcyIcon(ResourceUtil.ICON_CLOSE), "Close others sequences",
514            "Close all opened sequences except the active one.")
515    {
516        /**
517         * 
518         */
519        private static final long serialVersionUID = -8595244752658024122L;
520
521        @Override
522        public boolean doAction(ActionEvent e)
523        {
524            final Viewer focusedViewer = Icy.getMainInterface().getActiveViewer();
525
526            for (Viewer viewer : Icy.getMainInterface().getViewers())
527                if (viewer != focusedViewer)
528                    viewer.close();
529
530            return true;
531        }
532    };
533
534    public static IcyAbstractAction closeAllSequencesAction = new IcyAbstractAction("Close all",
535            new IcyIcon(ResourceUtil.ICON_CLOSE), "Close all sequences", "Close all opened sequences.")
536    {
537        /**
538         * 
539         */
540        private static final long serialVersionUID = -1343557201445697749L;
541
542        @Override
543        public boolean doAction(ActionEvent e)
544        {
545            Icy.getMainInterface().closeAllViewers();
546            return true;
547        }
548    };
549
550    /**
551     * Return all actions of this class
552     */
553    public static List<IcyAbstractAction> getAllActions()
554    {
555        final List<IcyAbstractAction> result = new ArrayList<IcyAbstractAction>();
556
557        for (Field field : FileActions.class.getFields())
558        {
559            final Class<?> type = field.getType();
560
561            try
562            {
563                if (ClassUtil.isSubClass(type, IcyAbstractAction[].class))
564                    result.addAll(Arrays.asList(((IcyAbstractAction[]) field.get(null))));
565                else if (ClassUtil.isSubClass(type, IcyAbstractAction.class))
566                    result.add((IcyAbstractAction) field.get(null));
567            }
568            catch (Exception e)
569            {
570                // ignore
571            }
572        }
573
574        return result;
575    }
576}