001/*
002 *                    BioJava development code
003 *
004 * This code may be freely distributed and modified under the
005 * terms of the GNU Lesser General Public Licence.  This should
006 * be distributed with the code.  If you do not have a copy,
007 * see:
008 *
009 *      http://www.gnu.org/copyleft/lesser.html
010 *
011 * Copyright for this code is held jointly by the individual
012 * authors.  These should be listed in @author doc comments.
013 *
014 * For more information on the BioJava project and its aims,
015 * or to join the biojava-l mailing list, visit the home page
016 * at:
017 *
018 *      http://www.biojava.org/
019 *
020 */
021package org.biojava.nbio.structure.symmetry.gui;
022
023import java.awt.Dimension;
024import java.awt.event.ActionEvent;
025import java.io.IOException;
026
027import javax.swing.AbstractAction;
028import javax.swing.Action;
029import javax.swing.Box;
030import javax.swing.JButton;
031import javax.swing.JComboBox;
032import javax.swing.JFrame;
033import javax.swing.JLabel;
034import javax.swing.JMenuBar;
035import javax.swing.JOptionPane;
036import javax.swing.JProgressBar;
037import javax.swing.JTabbedPane;
038
039import org.biojava.nbio.structure.PassthroughIdentifier;
040import org.biojava.nbio.structure.Structure;
041import org.biojava.nbio.structure.StructureException;
042import org.biojava.nbio.structure.StructureIdentifier;
043import org.biojava.nbio.structure.align.ce.AbstractUserArgumentProcessor;
044import org.biojava.nbio.structure.align.gui.AlignmentCalculationRunnable;
045import org.biojava.nbio.structure.align.gui.MenuCreator;
046import org.biojava.nbio.structure.align.gui.ParameterGUI;
047import org.biojava.nbio.structure.align.gui.SelectPDBPanel;
048import org.biojava.nbio.structure.align.util.ResourceManager;
049import org.biojava.nbio.structure.align.webstart.AligUIManager;
050import org.biojava.nbio.structure.gui.util.PDBUploadPanel;
051import org.biojava.nbio.structure.gui.util.ScopSelectPanel;
052import org.biojava.nbio.structure.gui.util.StructurePairSelector;
053import org.biojava.nbio.structure.symmetry.internal.CESymmParameters;
054import org.biojava.nbio.structure.symmetry.internal.CeSymm;
055
056/**
057 * A JFrame that allows to trigger a symmetry analysis, either from files
058 * in a directory or after manual upload
059 * Adapted from the AlignmentGui class in biojava.
060 * Only one structure is inputted and only the CeSymm algorihm can be chosen.
061 *
062 * @author Aleix Lafita
063 * @since 4.2.0
064 *
065 */
066public class SymmetryGui extends JFrame {
067
068        private final static long serialVersionUID = 0l;
069
070        private CESymmParameters params = new CESymmParameters();
071        private JButton abortB;
072
073        private SelectPDBPanel  tab1 ;
074        private PDBUploadPanel  tab2;
075        private ScopSelectPanel tab3;
076
077        private Thread thread;
078        private AlignmentCalculationRunnable alicalc;
079        private JTabbedPane masterPane;
080        private JTabbedPane tabPane;
081        private JProgressBar progress;
082
083        public static void main(String[] args){
084                SymmetryGui.getInstance();
085        }
086
087        static final ResourceManager resourceManager =
088                        ResourceManager.getResourceManager("ce");
089
090        private static final String MAIN_TITLE =
091                        "Symmetry Analysis Tool: CE-Symm - V.1.0";
092
093        private static final SymmetryGui me = new SymmetryGui();
094
095        public static SymmetryGui getInstance(){
096
097                AbstractUserArgumentProcessor.printAboutMe();
098
099                AligUIManager.setLookAndFeel();
100
101                if (!me.isVisible()) me.setVisible(true);
102                if (! me.isActive()) me.requestFocus();
103
104                return me;
105        }
106
107        public static SymmetryGui getInstanceNoVisibilityChange(){
108                return me;
109        }
110
111        private SymmetryGui() {
112                super();
113
114                thread = null;
115
116                JMenuBar menu = MenuCreator.initAlignmentGUIMenu(this);
117                this.setJMenuBar(menu);
118
119                this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
120                this.setTitle(MAIN_TITLE);
121
122                tab1 = new SelectPDBPanel(false);
123                tab2 = new PDBUploadPanel(false);
124                tab3 = new ScopSelectPanel(false);
125
126                //setup tabPane
127                tabPane = new JTabbedPane();
128
129                tabPane.addTab("Select PDB ID", null, tab1, "Select PDB ID to analyze");
130                tabPane.addTab("Domain",null, tab3,"Select domain to analyze.");
131                tabPane.addTab("Custom file",null, tab2,"Analyze your own file.");
132
133                Box hBoxAlgo = setupAlgorithm();
134                Box vBox = Box.createVerticalBox();
135
136                vBox.add(tabPane);
137                vBox.add(Box.createGlue());
138
139                masterPane = new JTabbedPane();
140                masterPane.addTab("Symmetry Analysis", vBox);
141
142                Box vBoxMain = Box.createVerticalBox();
143                vBoxMain.add(hBoxAlgo);
144
145                vBoxMain.add(masterPane);
146                vBoxMain.add(initButtons());
147
148                this.getContentPane().add(vBoxMain);
149                this.pack();
150                this.setVisible(true);
151        }
152
153        private Box setupAlgorithm() {
154
155                String[] algorithms = {"JCE-symmetry"};
156                JLabel algoLabel = new JLabel("Symmetry algorithm: ");
157
158                JComboBox algorithmList = new JComboBox(algorithms);
159                algorithmList.setSelectedIndex(0);
160
161                Action paramAction = new AbstractAction("Parameters") {
162                        public static final long serialVersionUID = 0l;
163                        // This method is called when the button is pressed
164                        @Override
165                        public void actionPerformed(ActionEvent evt) {
166                                // Perform action...
167                                configureParameters();
168                        }
169                };
170
171                JButton parameterButton = new JButton(paramAction);
172
173                Box hBoxAlgo = Box.createHorizontalBox();
174                hBoxAlgo.add(Box.createGlue());
175                hBoxAlgo.add(algoLabel);
176                hBoxAlgo.add(algorithmList);
177                hBoxAlgo.add(Box.createGlue());
178                hBoxAlgo.add(parameterButton);
179                hBoxAlgo.add(Box.createGlue());
180                return hBoxAlgo;
181        }
182
183        private Box initButtons(){
184
185                progress =new JProgressBar();
186                progress.setIndeterminate(false);
187                progress.setMaximumSize(new Dimension(10,100));
188                progress.setVisible(false);
189
190                Action action1 = new AbstractAction("Analyze") {
191                        public static final long serialVersionUID = 0l;
192                        // This method is called when the button is pressed
193                        @Override
194                        public void actionPerformed(ActionEvent evt) {
195                                // Perform action...
196                                //System.out.println("calc structure alignment");
197                                int selectedIndex = masterPane.getSelectedIndex();
198                                if (selectedIndex == 0)
199                                        calcAlignment();
200                                else {
201                                        System.err.println("Unknown TAB: " + selectedIndex);
202                                }
203                        }
204                };
205
206                JButton submitB = new JButton(action1);
207
208                Action action3 = new AbstractAction("Abort") {
209                        public static final long serialVersionUID = 0l;
210                        // This method is called when the button is pressed
211                        @Override
212                        public void actionPerformed(ActionEvent evt) {
213                                // Perform action...
214                                abortCalc();
215                        }
216                };
217
218                abortB = new JButton(action3);
219
220                abortB.setEnabled(false);
221
222                Action action2 = new AbstractAction("Exit") {
223                        public static final long serialVersionUID = 0l;
224                        // This method is called when the button is pressed
225                        @Override
226                        public void actionPerformed(ActionEvent evt) {
227                                // Perform action...
228                                abortCalc();
229                                dispose();
230                                System.exit(0);
231                        }
232                };
233
234                JButton closeB = new JButton(action2);
235                Box hBox = Box.createHorizontalBox();
236                hBox.add(closeB);
237                hBox.add(Box.createGlue());
238                hBox.add(progress);
239                hBox.add(abortB);
240                //hBox.add(Box.createGlue());
241                hBox.add(submitB);
242
243                return hBox;
244        }
245
246        protected void configureParameters() {
247                System.out.println("configure parameters for " +
248                                CeSymm.algorithmName);
249
250                // show a new config GUI
251                new ParameterGUI(params, CeSymm.algorithmName);
252        }
253
254        public void cleanUp() {
255
256                if ( alicalc != null) {
257                        alicalc.cleanup();
258                }
259        }
260
261        private void calcAlignment() {
262
263                int pos = tabPane.getSelectedIndex();
264                StructurePairSelector tab = null;
265
266                if (pos == 0 ){
267                        tab = tab1;
268
269                } else if (pos == 1){
270                        tab = tab3;
271
272                } else if (pos == 2){
273                        tab = tab2;
274                }
275
276
277                try {
278                        Structure s = tab.getStructure1();
279
280                        if ( s == null) {
281                                System.err.println("Please select structure");
282                                return ;
283                        }
284
285                        StructureIdentifier name = new PassthroughIdentifier("custom");
286
287                        if  ( pos == 0){
288                                name = tab1.getName1();
289                        } else {
290                                name = s.getStructureIdentifier();
291                        }
292
293                        System.out.println("Analyzing: " + name);
294
295
296                        alicalc = new SymmetryCalc(this, s);
297
298
299                        thread = new Thread(alicalc);
300                        thread.start();
301                        abortB.setEnabled(true);
302                        progress.setIndeterminate(true);
303                        ProgressThreadDrawer drawer = new ProgressThreadDrawer(progress);
304                        drawer.start();
305                } catch (StructureException e){
306                        JOptionPane.showMessageDialog(null,
307                                        "Could not align structures. Exception: " + e.getMessage());
308                } catch (IOException e) {
309                        JOptionPane.showMessageDialog(null,
310                                        "Could not align structures. Exception: " + e.getMessage());
311                }
312        }
313
314        public void notifyCalcFinished(){
315                abortB.setEnabled(false);
316                thread = null;
317                progress.setIndeterminate(false);
318                this.repaint();
319        }
320
321        private void abortCalc(){
322                System.err.println("Interrupting alignment ...");
323                if ( alicalc != null )
324                        alicalc.interrupt();
325                notifyCalcFinished();
326        }
327
328
329        public CESymmParameters getParameters() {
330                return params;
331        }
332
333}
334
335class ProgressThreadDrawer extends Thread {
336
337        JProgressBar progress;
338        static int interval = 300;
339
340        public ProgressThreadDrawer(JProgressBar progress) {
341                this.progress = progress;
342        }
343
344
345        @Override
346        public void run() {
347                progress.setVisible(true);
348                boolean finished = false;
349                while ( ! finished) {
350                        try {
351                                progress.repaint();
352                                if ( ! progress.isIndeterminate() ){
353                                        finished =false;
354                                        break;
355                                }
356
357                                sleep(interval);
358                        } catch (InterruptedException e){
359                        }
360                        progress.repaint();
361                }
362                progress.setVisible(false);
363                progress = null;
364        }
365}