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.tools;
020
021import icy.gui.component.sequence.SequencePreviewPanel;
022import icy.image.IcyBufferedImage;
023import icy.sequence.AbstractSequenceModel;
024import icy.sequence.Sequence;
025import icy.sequence.SequenceUtil;
026
027import java.awt.GridBagConstraints;
028import java.awt.GridBagLayout;
029import java.awt.Insets;
030import java.awt.event.ActionEvent;
031import java.awt.event.ActionListener;
032import java.awt.image.BufferedImage;
033
034import javax.swing.ButtonGroup;
035import javax.swing.DefaultBoundedRangeModel;
036import javax.swing.JLabel;
037import javax.swing.JPanel;
038import javax.swing.JRadioButton;
039import javax.swing.JSlider;
040import javax.swing.JSpinner;
041import javax.swing.SpinnerNumberModel;
042import javax.swing.SwingConstants;
043import javax.swing.border.TitledBorder;
044import javax.swing.event.ChangeEvent;
045import javax.swing.event.ChangeListener;
046
047/**
048 * @author Stephane
049 */
050public class SequenceDimensionConvertPanel extends JPanel
051{
052    private class SequenceDimensionConvertPanelModel extends AbstractSequenceModel
053    {
054        public SequenceDimensionConvertPanelModel()
055        {
056            super();
057        }
058
059        @Override
060        public BufferedImage getImage(int t, int z)
061        {
062            return SequenceUtil.AdjustZTHelper
063                    .getImage(sequence, t, z, getNewSizeZ(), getNewSizeT(), isOrderReversed());
064        }
065
066        @Override
067        public int getSizeX()
068        {
069            return sequence.getSizeX();
070        }
071
072        @Override
073        public int getSizeY()
074        {
075            return sequence.getSizeY();
076        }
077
078        @Override
079        public int getSizeZ()
080        {
081            return getNewSizeZ();
082        }
083
084        @Override
085        public int getSizeT()
086        {
087            return getNewSizeT();
088        }
089
090        @Override
091        public int getSizeC()
092        {
093            return sequence.getSizeC();
094        }
095
096        @Override
097        public BufferedImage getImage(int t, int z, int c)
098        {
099            return ((IcyBufferedImage) getImage(t, z)).getImage(c);
100        }
101    }
102
103    /**
104     * 
105     */
106    private static final long serialVersionUID = -6906749224563258829L;
107
108    // GUI
109    private JRadioButton ztRadioButton;
110    private JRadioButton tzRadioButton;
111    JSlider sizeZSlider;
112    JSlider sizeTSlider;
113    JSpinner sizeZSpinner;
114    JSpinner sizeTSpinner;
115    SequencePreviewPanel previewPane;
116    private ButtonGroup dimensionGroup;
117
118    // internals
119    final Sequence sequence;
120    boolean changingZ;
121    boolean changingT;
122
123    public SequenceDimensionConvertPanel(Sequence sequence)
124    {
125        super();
126
127        this.sequence = sequence;
128        changingZ = false;
129        changingT = false;
130
131        initialize();
132
133        dimensionGroup = new ButtonGroup();
134        dimensionGroup.add(tzRadioButton);
135        dimensionGroup.add(ztRadioButton);
136        dimensionGroup.setSelected(ztRadioButton.getModel(), true);
137
138        final int sizeZ = sequence.getSizeZ();
139        final int sizeT = sequence.getSizeT();
140        final int sizeZT = sizeZ * sizeT;
141
142        sizeZSlider.setModel(new DefaultBoundedRangeModel(sizeZ, 0, 1, sizeZT));
143        sizeZSpinner.setModel(new SpinnerNumberModel(sizeZ, 1, sizeZT, 1));
144        sizeTSlider.setModel(new DefaultBoundedRangeModel(sizeT, 0, 1, sizeZT));
145        sizeTSpinner.setModel(new SpinnerNumberModel(sizeT, 1, sizeZT, 1));
146
147        tzRadioButton.addActionListener(new ActionListener()
148        {
149            @Override
150            public void actionPerformed(ActionEvent e)
151            {
152                previewPane.imageChanged();
153            }
154        });
155
156        ztRadioButton.addActionListener(new ActionListener()
157        {
158            @Override
159            public void actionPerformed(ActionEvent e)
160            {
161                previewPane.imageChanged();
162            }
163        });
164
165        sizeZSlider.addChangeListener(new ChangeListener()
166        {
167            @Override
168            public void stateChanged(ChangeEvent e)
169            {
170                if (changingT)
171                    return;
172
173                final int newSize = sizeZSlider.getValue();
174
175                sizeZSpinner.setValue(Integer.valueOf(newSize));
176
177                sizeZChanged();
178            }
179        });
180        sizeZSpinner.addChangeListener(new ChangeListener()
181        {
182            @Override
183            public void stateChanged(ChangeEvent e)
184            {
185                if (changingT)
186                    return;
187
188                final int newSize = ((Integer) sizeZSpinner.getValue()).intValue();
189
190                sizeZSlider.setValue(newSize);
191
192                sizeZChanged();
193            }
194        });
195
196        sizeTSlider.addChangeListener(new ChangeListener()
197        {
198            @Override
199            public void stateChanged(ChangeEvent e)
200            {
201                if (changingZ)
202                    return;
203
204                final int newSize = sizeTSlider.getValue();
205
206                sizeTSpinner.setValue(Integer.valueOf(newSize));
207
208                sizeTChanged();
209            }
210        });
211        sizeTSpinner.addChangeListener(new ChangeListener()
212        {
213            @Override
214            public void stateChanged(ChangeEvent e)
215            {
216                if (changingZ)
217                    return;
218
219                final int newSize = ((Integer) sizeTSpinner.getValue()).intValue();
220
221                sizeTSlider.setValue(newSize);
222
223                sizeTChanged();
224            }
225        });
226
227        previewPane.setModel(new SequenceDimensionConvertPanelModel());
228    }
229
230    private void initialize()
231    {
232        GridBagLayout gridBagLayout = new GridBagLayout();
233        gridBagLayout.columnWidths = new int[] {20, 0, 20, 0, 0, 0, 80, 20, 0};
234        gridBagLayout.rowHeights = new int[] {0, 0, 0, 0, 0};
235        gridBagLayout.columnWeights = new double[] {1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, Double.MIN_VALUE};
236        gridBagLayout.rowWeights = new double[] {0.0, 0.0, 0.0, 1.0, Double.MIN_VALUE};
237        setLayout(gridBagLayout);
238
239        final JLabel lblNewLabel = new JLabel("Dimension order");
240        lblNewLabel.setHorizontalAlignment(SwingConstants.TRAILING);
241        GridBagConstraints gbc_lblNewLabel = new GridBagConstraints();
242        gbc_lblNewLabel.fill = GridBagConstraints.BOTH;
243        gbc_lblNewLabel.insets = new Insets(0, 0, 5, 5);
244        gbc_lblNewLabel.gridx = 1;
245        gbc_lblNewLabel.gridy = 0;
246        add(lblNewLabel, gbc_lblNewLabel);
247
248        ztRadioButton = new JRadioButton("Z - T");
249        GridBagConstraints gbc_ztRadioButton = new GridBagConstraints();
250        gbc_ztRadioButton.fill = GridBagConstraints.BOTH;
251        gbc_ztRadioButton.insets = new Insets(0, 0, 5, 5);
252        gbc_ztRadioButton.gridx = 3;
253        gbc_ztRadioButton.gridy = 0;
254        add(ztRadioButton, gbc_ztRadioButton);
255
256        tzRadioButton = new JRadioButton("T - Z");
257        GridBagConstraints gbc_tzRadioButton = new GridBagConstraints();
258        gbc_tzRadioButton.gridwidth = 2;
259        gbc_tzRadioButton.fill = GridBagConstraints.BOTH;
260        gbc_tzRadioButton.insets = new Insets(0, 0, 5, 5);
261        gbc_tzRadioButton.gridx = 4;
262        gbc_tzRadioButton.gridy = 0;
263        add(tzRadioButton, gbc_tzRadioButton);
264
265        final JLabel lblNewLabel_1 = new JLabel("Size Z");
266        lblNewLabel_1.setHorizontalAlignment(SwingConstants.TRAILING);
267        lblNewLabel_1.setToolTipText("Size of Z dimension");
268        GridBagConstraints gbc_lblNewLabel_1 = new GridBagConstraints();
269        gbc_lblNewLabel_1.fill = GridBagConstraints.BOTH;
270        gbc_lblNewLabel_1.insets = new Insets(0, 0, 5, 5);
271        gbc_lblNewLabel_1.gridx = 1;
272        gbc_lblNewLabel_1.gridy = 1;
273        add(lblNewLabel_1, gbc_lblNewLabel_1);
274
275        sizeZSpinner = new JSpinner();
276        sizeZSpinner.setToolTipText("Size of Z dimension");
277        GridBagConstraints gbc_zSpinner = new GridBagConstraints();
278        gbc_zSpinner.gridwidth = 2;
279        gbc_zSpinner.fill = GridBagConstraints.BOTH;
280        gbc_zSpinner.insets = new Insets(0, 0, 5, 5);
281        gbc_zSpinner.gridx = 3;
282        gbc_zSpinner.gridy = 1;
283        add(sizeZSpinner, gbc_zSpinner);
284
285        sizeZSlider = new JSlider();
286        GridBagConstraints gbc_zSlider = new GridBagConstraints();
287        gbc_zSlider.gridwidth = 2;
288        gbc_zSlider.fill = GridBagConstraints.BOTH;
289        gbc_zSlider.insets = new Insets(0, 0, 5, 5);
290        gbc_zSlider.gridx = 5;
291        gbc_zSlider.gridy = 1;
292        add(sizeZSlider, gbc_zSlider);
293
294        final JLabel lblNewLabel_2 = new JLabel("Size T");
295        lblNewLabel_2.setHorizontalAlignment(SwingConstants.TRAILING);
296        lblNewLabel_2.setToolTipText("Size of T dimension");
297        GridBagConstraints gbc_lblNewLabel_2 = new GridBagConstraints();
298        gbc_lblNewLabel_2.fill = GridBagConstraints.BOTH;
299        gbc_lblNewLabel_2.insets = new Insets(0, 0, 5, 5);
300        gbc_lblNewLabel_2.gridx = 1;
301        gbc_lblNewLabel_2.gridy = 2;
302        add(lblNewLabel_2, gbc_lblNewLabel_2);
303
304        sizeTSpinner = new JSpinner();
305        sizeTSpinner.setToolTipText("Size of T dimension");
306        GridBagConstraints gbc_tSpinner = new GridBagConstraints();
307        gbc_tSpinner.gridwidth = 2;
308        gbc_tSpinner.fill = GridBagConstraints.BOTH;
309        gbc_tSpinner.insets = new Insets(0, 0, 5, 5);
310        gbc_tSpinner.gridx = 3;
311        gbc_tSpinner.gridy = 2;
312        add(sizeTSpinner, gbc_tSpinner);
313
314        sizeTSlider = new JSlider();
315        GridBagConstraints gbc_tSlider = new GridBagConstraints();
316        gbc_tSlider.gridwidth = 2;
317        gbc_tSlider.insets = new Insets(0, 0, 5, 5);
318        gbc_tSlider.fill = GridBagConstraints.BOTH;
319        gbc_tSlider.gridx = 5;
320        gbc_tSlider.gridy = 2;
321        add(sizeTSlider, gbc_tSlider);
322
323        previewPane = new SequencePreviewPanel(true);
324        previewPane.setBorder(new TitledBorder(null, "Preview", TitledBorder.LEADING, TitledBorder.TOP, null, null));
325        GridBagConstraints gbc_previewPane = new GridBagConstraints();
326        gbc_previewPane.gridwidth = 8;
327        gbc_previewPane.insets = new Insets(0, 0, 0, 5);
328        gbc_previewPane.fill = GridBagConstraints.BOTH;
329        gbc_previewPane.gridx = 0;
330        gbc_previewPane.gridy = 3;
331        add(previewPane, gbc_previewPane);
332    }
333
334    void sizeZChanged()
335    {
336        final int sizeZT = sequence.getSizeZ() * sequence.getSizeT();
337        final int newSizeZ = getNewSizeZ();
338        int newSizeT = sizeZT / newSizeZ;
339
340        if ((sizeZT % newSizeZ) != 0)
341            newSizeT++;
342
343        changingZ = true;
344        try
345        {
346            sizeTSpinner.setValue(Integer.valueOf(newSizeT));
347            sizeTSlider.setValue(newSizeT);
348            previewPane.dimensionChanged();
349        }
350        finally
351        {
352            changingZ = false;
353        }
354    }
355
356    void sizeTChanged()
357    {
358        final int sizeZT = sequence.getSizeZ() * sequence.getSizeT();
359        final int newSizeT = getNewSizeT();
360        int newSizeZ = sizeZT / newSizeT;
361
362        if ((sizeZT % newSizeT) != 0)
363            newSizeZ++;
364
365        changingT = true;
366        try
367        {
368            sizeZSpinner.setValue(Integer.valueOf(newSizeZ));
369            sizeZSlider.setValue(newSizeZ);
370            previewPane.dimensionChanged();
371        }
372        finally
373        {
374            changingT = false;
375        }
376    }
377
378    public Sequence getSequence()
379    {
380        return sequence;
381    }
382
383    public boolean isOrderReversed()
384    {
385        return dimensionGroup.getSelection() == tzRadioButton.getModel();
386    }
387
388    public int getNewSizeZ()
389    {
390        return ((Integer) sizeZSpinner.getValue()).intValue();
391    }
392
393    public int getNewSizeT()
394    {
395        return ((Integer) sizeTSpinner.getValue()).intValue();
396    }
397
398}