001    /*
002     * The contents of this file are subject to the Mozilla Public
003     * License Version 1.1 (the "License"); you may not use this file
004     * except in compliance with the License. You may obtain a copy of
005     * the License at http://www.mozilla.org/MPL/
006     *
007     * Software distributed under the License is distributed on an "AS
008     * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
009     * implied. See the License for the specific language governing
010     * rights and limitations under the License.
011     *
012     * The Original Code is Knowtator.
013     *
014     * The Initial Developer of the Original Code is University of Colorado.  
015     * Copyright (C) 2005 - 2008.  All Rights Reserved.
016     *
017     * Knowtator was developed by the Center for Computational Pharmacology
018     * (http://compbio.uchcs.edu) at the University of Colorado Health 
019     *  Sciences Center School of Medicine with support from the National 
020     *  Library of Medicine.  
021     *
022     * Current information about Knowtator can be obtained at 
023     * http://knowtator.sourceforge.net/
024     *
025     * Contributor(s):
026     *   Philip V. Ogren <philip@ogren.info> (Original Author)
027     */
028    package edu.uchsc.ccp.knowtator.wizards;
029    
030    import java.awt.BorderLayout;
031    import java.awt.Dimension;
032    import java.awt.GridBagConstraints;
033    import java.awt.GridBagLayout;
034    import java.awt.Insets;
035    import java.awt.Point;
036    import java.awt.event.ActionEvent;
037    import java.awt.event.ActionListener;
038    import java.util.Collection;
039    import java.util.HashSet;
040    import java.util.Set;
041    import java.util.TreeSet;
042    
043    import javax.swing.JButton;
044    import javax.swing.JFrame;
045    import javax.swing.JLabel;
046    import javax.swing.JList;
047    import javax.swing.JOptionPane;
048    import javax.swing.JScrollPane;
049    import javax.swing.JTextArea;
050    import javax.swing.JTextField;
051    import javax.swing.event.CaretEvent;
052    import javax.swing.event.CaretListener;
053    
054    import edu.stanford.smi.protege.model.SimpleInstance;
055    import edu.stanford.smi.protege.ui.DisplayUtilities;
056    import edu.stanford.smi.protege.ui.FrameRenderer;
057    import edu.stanford.smi.protege.util.CollectionUtilities;
058    import edu.uchsc.ccp.knowtator.FilterUtil;
059    import edu.uchsc.ccp.knowtator.KnowtatorManager;
060    
061    public class CreateConsensusSetWizard implements ActionListener {
062    
063            public static final String WELCOME_MESSAGE = "This wizard allows you to create a consensus set from existing, merged annotations. "
064                            + "Typically, text sources will be individually annotated in separate projects and then "
065                            + "merged together into a single project at which point consensus mode is used.   "
066                            + "This action will not delete or modify existing annotations.  A consensus set "
067                            + "consists of annotations that have been copied from the set of annotations "
068                            + "defined by the filter that you will choose in this wizard.  Consensus mode will then act on these "
069                            + "copied annotations.  For more information about "
070                            + "how consensus mode works please consult the online documentation. http://knowtator.sourceforge.net//consensus.shtml";
071    
072            public static final String FILTER_INSTRUCTIONS = "Please select a filter that describes the set of annotations that you want to create a consensus "
073                            + "set for.  The selected filter must have either two annotators or two annotation sets specified. If you "
074                            + "have not yet defined an appropriate filter, then please exit out of this wizard and create one.  Please see"
075                            + "http://knowtator.sourceforge.net//filters.shtml for information about filters.";
076    
077            public static final String NAME_INSTRUCTIONS = "Please enter a descriptive name for your consensus set. If you plan to have "
078                            + "only one consensus set in your annotation project, then selecting " + "the default name should be fine.";
079    
080            public static final String TEXT_SOURCES_INSTRUCTIONS = "Please select the text sources that you want included in the consensus set creation.";
081    
082            public static final String TO_WELCOME_FRAME = "TO_WELCOME_FRAME";
083    
084            public static final String TO_NAME_FRAME = "TO_NAME_FRAME";
085    
086            public static final String TO_FILTER_FRAME = "TO_FILTER_FRAME";
087    
088            public static final String TO_TEXTSOURCES_FRAME = "TO_TEXTSOURCES_FRAME";
089    
090            public static final String CREATE_BUTTON_CLICKED = "CREATE_BUTTON_CLICKED";
091    
092            SimpleInstance filter;
093    
094            String consensusSetName = "consensus set";
095    
096            Set<SimpleInstance> textSources;
097    
098            boolean createClicked = false;
099    
100            WizardFrame welcomeFrame;
101    
102            JTextArea welcomeMessageTextArea;
103    
104            WizardFrame nameFrame;
105    
106            JTextArea nameInstructionsTextArea;
107    
108            JLabel nameLabel;
109    
110            JTextField nameTextField;
111    
112            WizardFrame filterFrame;
113    
114            JTextArea filterInstructionsTextArea;
115    
116            JLabel filterLabel;
117    
118            JTextField filterTextField;
119    
120            JButton filterButton;
121    
122            WizardFrame textSourcesFrame;
123    
124            JTextArea textSourcesInstructionsTextArea;
125    
126            JLabel textSourcesLabel;
127    
128            JList textSourcesList;
129    
130            JButton textSourcesRemoveButton;
131    
132            JButton textSourcesAddButton;
133    
134            WizardFrame visibleFrame; // one of the above frames
135    
136            JFrame parent;
137    
138            Dimension wizardSize;
139    
140            Point wizardLocation;
141    
142            KnowtatorManager manager;
143    
144            public CreateConsensusSetWizard(JFrame parent, KnowtatorManager manager) {
145                    this.parent = parent;
146                    this.manager = manager;
147    
148                    textSources = new TreeSet<SimpleInstance>();
149    
150                    createWelcomeFrame();
151                    createConsensusNameFrame();
152                    createFilterFrame();
153                    createTextSourcesFrame();
154            }
155    
156            private void createWelcomeFrame() {
157                    welcomeFrame = new WizardFrame(parent, "consensus set creation wizard", new Dimension(500, 400));
158                    welcomeFrame.setAlwaysOnTop(false);
159                    welcomeFrame.previousButton.setEnabled(false);
160                    welcomeFrame.nextButton.setActionCommand(TO_NAME_FRAME);
161                    welcomeFrame.nextButton.addActionListener(this);
162                    welcomeFrame.cancelButton.addActionListener(this);
163                    welcomeFrame.contentPane.setLayout(new BorderLayout());
164                    welcomeFrame.setLocation(WizardUtil.getCentralDialogLocation(parent, welcomeFrame));
165    
166                    welcomeMessageTextArea = new JTextArea();
167                    welcomeMessageTextArea.setEditable(false);
168                    welcomeMessageTextArea.setText(WELCOME_MESSAGE);
169                    welcomeMessageTextArea.setLineWrap(true);
170                    welcomeMessageTextArea.setWrapStyleWord(true);
171                    welcomeFrame.contentPane.add(welcomeMessageTextArea, BorderLayout.CENTER);
172            }
173    
174            private void createConsensusNameFrame() {
175                    nameFrame = new WizardFrame(parent, "enter a name");
176                    nameFrame.setAlwaysOnTop(false);
177                    nameFrame.previousButton.setActionCommand(TO_WELCOME_FRAME);
178                    nameFrame.previousButton.addActionListener(this);
179                    nameFrame.nextButton.setActionCommand(TO_FILTER_FRAME);
180                    nameFrame.nextButton.addActionListener(this);
181                    nameFrame.cancelButton.addActionListener(this);
182    
183                    nameInstructionsTextArea = new JTextArea();
184                    nameInstructionsTextArea.setEditable(false);
185                    nameInstructionsTextArea.setText(NAME_INSTRUCTIONS);
186                    nameInstructionsTextArea.setLineWrap(true);
187                    nameInstructionsTextArea.setWrapStyleWord(true);
188    
189                    nameLabel = new JLabel("consensus set name ");
190    
191                    nameTextField = new JTextField(consensusSetName);
192                    nameTextField.addCaretListener(new CaretListener() {
193                            public void caretUpdate(CaretEvent e) {
194                                    String name = nameTextField.getText();
195                                    if (name == null || name.trim().equals("")) {
196                                            nameFrame.nextButton.setEnabled(false);
197                                    } else
198                                            nameFrame.nextButton.setEnabled(true);
199                                    consensusSetName = name;
200                            }
201                    });
202    
203                    nameFrame.contentPane.setLayout(new GridBagLayout());
204                    nameFrame.contentPane.add(nameInstructionsTextArea, new GridBagConstraints(0, 0, 2, 1, 1.0d, 1.0d,
205                                    GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(3, 3, 3, 3), 2, 2));
206                    nameFrame.contentPane.add(nameLabel, new GridBagConstraints(0, 1, 1, 1, 0d, 0d, GridBagConstraints.EAST,
207                                    GridBagConstraints.NONE, new Insets(5, 5, 5, 5), 2, 2));
208                    nameFrame.contentPane.add(nameTextField, new GridBagConstraints(1, 1, 1, 1, 1.0d, 0d, GridBagConstraints.WEST,
209                                    GridBagConstraints.HORIZONTAL, new Insets(5, 5, 5, 5), 2, 2));
210            }
211    
212            private void createFilterFrame() {
213                    filterFrame = new WizardFrame(parent, "select annotation filter");
214                    filterFrame.setAlwaysOnTop(false);
215                    filterFrame.previousButton.setActionCommand(TO_NAME_FRAME);
216                    filterFrame.previousButton.addActionListener(this);
217                    filterFrame.nextButton.setActionCommand(TO_TEXTSOURCES_FRAME);
218                    filterFrame.nextButton.addActionListener(this);
219                    filterFrame.nextButton.setEnabled(false);
220                    filterFrame.cancelButton.addActionListener(this);
221    
222                    filterInstructionsTextArea = new JTextArea();
223                    filterInstructionsTextArea.setEditable(false);
224                    filterInstructionsTextArea.setText(FILTER_INSTRUCTIONS);
225                    filterInstructionsTextArea.setLineWrap(true);
226                    filterInstructionsTextArea.setWrapStyleWord(true);
227    
228                    filterLabel = new JLabel("selected filter");
229                    filterTextField = new JTextField();
230                    filterTextField.setEditable(false);
231                    filterButton = new JButton("select filter");
232                    filterButton.addActionListener(this);
233    
234                    filterFrame.contentPane.setLayout(new GridBagLayout());
235                    filterFrame.contentPane.add(filterInstructionsTextArea, new GridBagConstraints(0, 0, 3, 1, 1.0d, 1.0d,
236                                    GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(3, 3, 3, 3), 2, 2));
237                    filterFrame.contentPane.add(filterLabel, new GridBagConstraints(0, 1, 1, 1, 0d, 0d, GridBagConstraints.EAST,
238                                    GridBagConstraints.NONE, new Insets(3, 3, 3, 3), 2, 2));
239                    filterFrame.contentPane.add(filterTextField, new GridBagConstraints(1, 1, 1, 1, 1.0d, 0d,
240                                    GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(3, 3, 3, 3), 2, 2));
241                    filterFrame.contentPane.add(filterButton, new GridBagConstraints(2, 1, 1, 1, 0d, 0d, GridBagConstraints.WEST,
242                                    GridBagConstraints.NONE, new Insets(3, 3, 3, 3), 2, 2));
243            }
244    
245            private void createTextSourcesFrame() {
246                    textSourcesFrame = new WizardFrame(parent, "select text sources");
247                    textSourcesFrame.setAlwaysOnTop(false);
248                    textSourcesFrame.previousButton.setActionCommand(TO_FILTER_FRAME);
249                    textSourcesFrame.previousButton.addActionListener(this);
250                    textSourcesFrame.nextButton.setText("create");
251                    textSourcesFrame.nextButton.setActionCommand(CREATE_BUTTON_CLICKED);
252                    textSourcesFrame.nextButton.addActionListener(this);
253                    textSourcesFrame.nextButton.setEnabled(false);
254                    textSourcesFrame.cancelButton.addActionListener(this);
255    
256                    textSourcesInstructionsTextArea = new JTextArea();
257                    textSourcesInstructionsTextArea.setEditable(false);
258                    textSourcesInstructionsTextArea.setText(TEXT_SOURCES_INSTRUCTIONS);
259                    textSourcesInstructionsTextArea.setLineWrap(true);
260                    textSourcesInstructionsTextArea.setWrapStyleWord(true);
261    
262                    textSourcesLabel = new JLabel("Selected text sources");
263    
264                    textSourcesList = new JList();
265                    textSourcesList.setCellRenderer(new FrameRenderer());
266                    JScrollPane scrollPane = new JScrollPane(textSourcesList);
267    
268                    textSourcesAddButton = new JButton("Add");
269                    textSourcesAddButton.addActionListener(this);
270                    textSourcesRemoveButton = new JButton("Remove");
271                    textSourcesRemoveButton.addActionListener(this);
272    
273                    textSourcesFrame.contentPane.setLayout(new GridBagLayout());
274                    textSourcesFrame.contentPane.add(textSourcesInstructionsTextArea, new GridBagConstraints(0, 0, 2, 1, 0d, 0d,
275                                    GridBagConstraints.CENTER, GridBagConstraints.NONE, new Insets(3, 3, 3, 3), 2, 2));
276                    textSourcesFrame.contentPane.add(textSourcesLabel, new GridBagConstraints(0, 1, 2, 1, 0d, 0d,
277                                    GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(3, 3, 3, 3), 2, 2));
278                    textSourcesFrame.contentPane.add(scrollPane, new GridBagConstraints(0, 2, 2, 1, 1.0d, 1.0d,
279                                    GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(3, 3, 3, 3), 2, 2));
280                    textSourcesFrame.contentPane.add(textSourcesAddButton, new GridBagConstraints(0, 3, 1, 1, 0d, 0d,
281                                    GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(3, 3, 3, 3), 2, 2));
282                    textSourcesFrame.contentPane.add(textSourcesRemoveButton, new GridBagConstraints(1, 3, 1, 1, 0d, 0d,
283                                    GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(3, 3, 3, 3), 2, 2));
284            }
285    
286            private void chooseFilter() {
287                    SimpleInstance chosenFilter = (SimpleInstance) DisplayUtilities.pickInstance(filterFrame, CollectionUtilities
288                                    .createCollection(manager.getKnowtatorProjectUtil().getFilterCls()), "Select annotation filter");
289    
290                    if (chosenFilter == null)
291                            return;
292                    Set<SimpleInstance> annotators = new HashSet<SimpleInstance>(FilterUtil.getAnnotators(chosenFilter));
293                    Set<SimpleInstance> sets = FilterUtil.getSets(chosenFilter);
294                    if (annotators.size() < 2 && sets.size() < 2) {
295                            JOptionPane.showMessageDialog(filterFrame,
296                                            "The selected filter must have either two annotators or two annotation sets specified.",
297                                            "Incomplete annotation filter", JOptionPane.ERROR_MESSAGE);
298                            return;
299                    }
300    
301                    filter = chosenFilter;
302                    filterFrame.nextButton.setEnabled(true);
303                    filterTextField.setText(filter.getBrowserText());
304            }
305    
306            private void addTextSources(Collection addedTextSources) {
307                    if (addedTextSources != null && addedTextSources.size() > 0) {
308                            for (Object addedTextSource : addedTextSources) {
309                                    textSources.add((SimpleInstance) addedTextSource);
310                            }
311                            textSourcesList.setListData(textSources.toArray());
312                    }
313                    if (textSources.size() > 0)
314                            textSourcesFrame.nextButton.setEnabled(true);
315            }
316    
317            private void chooseTextSources() {
318                    Collection textSources = DisplayUtilities.pickInstances(textSourcesFrame, manager.getKnowledgeBase(),
319                                    CollectionUtilities.createCollection(manager.getKnowtatorProjectUtil().getTextSourceCls()),
320                                    "select text sources");
321                    addTextSources(textSources);
322            }
323    
324            private void removeTextSources() {
325                    Object[] selectedValues = textSourcesList.getSelectedValues();
326                    for (Object selectedValue : selectedValues) {
327                            textSources.remove(selectedValue);
328                    }
329                    textSourcesList.setListData(textSources.toArray());
330                    if (textSources.size() == 0)
331                            textSourcesFrame.nextButton.setEnabled(false);
332            }
333    
334            public void actionPerformed(ActionEvent actionEvent) {
335                    String command = actionEvent.getActionCommand();
336                    Object source = actionEvent.getSource();
337                    if (command.equals(TO_WELCOME_FRAME)) {
338                            showFrame(welcomeFrame);
339                    } else if (command.equals(TO_NAME_FRAME)) {
340                            showFrame(nameFrame);
341                    } else if (command.equals(TO_FILTER_FRAME)) {
342                            showFrame(filterFrame);
343                    } else if (command.equals(TO_TEXTSOURCES_FRAME)) {
344                            showFrame(textSourcesFrame);
345                    } else if (command.equals("CANCEL")) {
346                            setVisible(false);
347                    } else if (source == filterButton) {
348                            chooseFilter();
349                    } else if (source == textSourcesAddButton) {
350                            chooseTextSources();
351                    } else if (source == textSourcesRemoveButton) {
352                            removeTextSources();
353                    } else if (command.equals(CREATE_BUTTON_CLICKED)) {
354                            createClicked = true;
355                            setVisible(false);
356                    }
357            }
358    
359            public void setVisible(boolean visible) {
360                    if (visible) {
361                            createClicked = false;
362                            showFrame(welcomeFrame);
363                    } else {
364                            welcomeFrame.setVisible(false);
365                            nameFrame.setVisible(false);
366                            filterFrame.setVisible(false);
367                            textSourcesFrame.setVisible(false);
368                    }
369            }
370    
371            public void showFrame(WizardFrame wizardFrame) {
372                    if (visibleFrame != null) {
373                            wizardSize = visibleFrame.getSize();
374                            wizardLocation = visibleFrame.getLocation();
375                            wizardFrame.setSize(wizardSize);
376                            wizardFrame.setLocation(wizardLocation);
377                    }
378                    visibleFrame = wizardFrame;
379                    setVisible(false);
380                    visibleFrame.setVisible(true);
381            }
382    
383            public boolean createConsensusSet() {
384                    return createClicked;
385            }
386    
387            public SimpleInstance getFilter() {
388                    return filter;
389            }
390    
391            public Set<SimpleInstance> getTextSources() {
392                    return textSources;
393            }
394    
395            public String getConsensusSetName() {
396                    return consensusSetName;
397            }
398    }