/*
* This file is part of ADDIS (Aggregate Data Drug Information System).
* ADDIS is distributed from http://drugis.org/.
* Copyright © 2009 Gert van Valkenhoef, Tommi Tervonen.
* Copyright © 2010 Gert van Valkenhoef, Tommi Tervonen, Tijs Zwinkels,
* Maarten Jacobs, Hanno Koeslag, Florin Schimbinschi, Ahmad Kamal, Daniel
* Reid.
* Copyright © 2011 Gert van Valkenhoef, Ahmad Kamal, Daniel Reid, Florin
* Schimbinschi.
* Copyright © 2012 Gert van Valkenhoef, Daniel Reid, Joël Kuiper, Wouter
* Reckman.
* Copyright © 2013 Gert van Valkenhoef, Joël Kuiper.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.drugis.addis.gui;
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Insets;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import javax.swing.AbstractAction;
import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.JTabbedPane;
import javax.swing.JTextArea;
import javax.swing.JToolBar;
import javax.swing.JTree;
import javax.swing.KeyStroke;
import javax.swing.SwingUtilities;
import javax.swing.WindowConstants;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;
import javax.swing.tree.TreePath;
import org.drugis.addis.AppInfo;
import org.drugis.addis.FileNames;
import org.drugis.addis.entities.DependentEntitiesException;
import org.drugis.addis.entities.Domain;
import org.drugis.addis.entities.Drug;
import org.drugis.addis.entities.Entity;
import org.drugis.addis.entities.EntityCategory;
import org.drugis.addis.entities.Study;
import org.drugis.addis.gui.components.AddisScrollPane;
import org.drugis.addis.gui.components.AddisTabbedPane;
import org.drugis.addis.gui.knowledge.StudiesKnowledge;
import org.drugis.addis.gui.renderer.DomainTreeCellRenderer;
import org.drugis.addis.presentation.PresentationModelFactory;
import org.drugis.addis.presentation.wizard.AddStudyWizardPresentation;
import org.drugis.common.gui.FileSaveDialog;
import org.drugis.common.gui.ViewBuilder;
import org.drugis.mtc.gui.MainWindow;
import cern.colt.Arrays;
import com.jgoodies.binding.adapter.Bindings;
import com.jgoodies.binding.value.ValueModel;
import com.jgoodies.forms.builder.ButtonBarBuilder2;
import com.jgoodies.forms.builder.PanelBuilder;
import com.jgoodies.forms.layout.CellConstraints;
import com.jgoodies.forms.layout.FormLayout;
@SuppressWarnings("serial")
public class AddisWindow extends JFrame {
private JComponent d_leftPanel;
private JPanel d_rightPanel;
private ViewBuilder d_rightPanelBuilder;
private DomainTreeModel d_domainTreeModel;
private JTree d_leftPanelTree;
private JMenuItem d_editMenuDeleteItem;
private JMenuItem d_editMenuEditItem;
private PresentationModelFactory d_pmf;
final public static String DEFAULT_TITLE = AppInfo.getAppName() + " v" + AppInfo.getAppVersion();
JMenuItem d_saveMenuItem;
private final Domain d_domain;
private Main d_main;
public AddisWindow(final Main main, final Domain domain) {
super(DEFAULT_TITLE);
d_domain = domain;
d_pmf = new PresentationModelFactory(d_domain);
d_main = main;
d_main.getDomainChangedModel().addValueChangeListener(new PropertyChangeListener() {
public void propertyChange(final PropertyChangeEvent evt) {
updateTitle();
}
});
d_main.addPropertyChangeListener(new PropertyChangeListener() {
public void propertyChange(final PropertyChangeEvent evt) {
if (evt.getPropertyName().equals(Main.PROPERTY_DISPLAY_NAME)) {
updateTitle();
}
}
});
setIconImage(Main.IMAGELOADER.getImage(FileNames.ICON_ADDIS_APP));
setPreferredSize(fitDimensionToScreen(960, 800));
setMinimumSize(new Dimension(750, 550)); // fit the screen for 800x600 resolution
addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(final WindowEvent evt) {
main.quitApplication();
}
});
setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
initComponents();
Main.bindPrintScreen(super.getContentPane());
updateTitle();
selectDefaultPath();
}
private void selectDefaultPath() {
d_leftPanelTree.getSelectionModel().setSelectionPath(d_domainTreeModel.getPathTo(d_domain.getCategory(Study.class)));
}
public static Dimension fitDimensionToScreen(final int width, final int height) {
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
return new Dimension(
Math.min(width, screenSize.width - 20),
Math.min(height, screenSize.height - 50));
}
public Domain getDomain() {
return d_domain;
}
public void initComponents() {
initMenu();
initPanel();
initToolbar();
initStatusBar();
}
private void initToolbar() {
JToolBar toolbar = new JToolBar();
toolbar.setFloatable(false);
toolbar.setLayout(new BorderLayout());
ButtonBarBuilder2 builder = new ButtonBarBuilder2();
for (EntityCategory cat : getDomain().getCategories()) {
CategoryKnowledge knowledge = CategoryKnowledgeFactory.getCategoryKnowledge(cat);
if (knowledge.isToolbarCategory()) {
builder.addButton(createToolbarButton(knowledge));
}
}
toolbar.add(builder.getPanel(), BorderLayout.CENTER);
toolbar.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
add(toolbar, BorderLayout.NORTH);
}
private void initStatusBar() {
StatusBar statusBar = new StatusBar();
statusBar.setFloatable(false);
add(statusBar, BorderLayout.SOUTH);
}
private JButton createToolbarButton(final CategoryKnowledge knowledge) {
String title = "New " + knowledge.getSingularCapitalized();
JButton topAddStudyButton = new JButton(title,
Main.IMAGELOADER.getIcon(knowledge.getNewIconName()));
topAddStudyButton.setToolTipText(title);
topAddStudyButton.addActionListener(new AbstractAction() {
public void actionPerformed(final ActionEvent e) {
showAddDialog(knowledge, null);
}
});
return topAddStudyButton;
}
private void initPanel() {
JSplitPane pane = new JSplitPane();
pane.setBorder(BorderFactory.createEmptyBorder());
pane.setEnabled(true);
pane.setOneTouchExpandable(true);
initLeftPanel();
pane.setLeftComponent(d_leftPanel);
d_leftPanel.setMinimumSize(new Dimension(200, d_leftPanel.getMinimumSize().height));
initRightPanel();
pane.setRightComponent(d_rightPanel);
d_rightPanel.setMinimumSize(new Dimension(770, d_rightPanel.getMinimumSize().height));
add(pane);
}
public JPanel getRightPanel() {
return d_rightPanel;
}
private void initLeftPanel() {
d_domainTreeModel = new DomainTreeModel(getDomain());
d_leftPanelTree = new JTree(d_domainTreeModel);
d_leftPanelTree.setCellRenderer(new DomainTreeCellRenderer(getDomain()));
d_leftPanelTree.setRootVisible(false);
d_leftPanelTree.expandPath(new TreePath(new Object[] {d_domainTreeModel.getRoot(), d_domain.getCategory(Drug.class)}));
d_leftPanelTree.addTreeSelectionListener(new DomainTreeSelectionListener());
d_leftPanel = new JScrollPane(d_leftPanelTree);
}
private void initMenu() {
JMenuBar menuBar = new JMenuBar();
menuBar.add(createFileMenu());
menuBar.add(createEditMenu());
menuBar.add(createAddMenu());
menuBar.add(Box.createHorizontalGlue());
menuBar.add(createHelpMenu());
setJMenuBar(menuBar);
}
private JMenu createHelpMenu() {
JMenu menu = new JMenu("Help");
menu.setMnemonic('h');
menu.add(createAboutItem());
return menu;
}
private JMenuItem createAboutItem() {
JMenuItem item = new JMenuItem("About");
item.setMnemonic('a');
item.addActionListener(new AbstractAction() {
public void actionPerformed(final ActionEvent arg0) {
showAboutDialog();
}
});
return item;
}
private void showAboutDialog() {
final AboutDialog dlg = new AboutDialog(this);
dlg.setVisible(true);
}
private JMenu createAddMenu() {
JMenu addMenu = new JMenu("Add");
addMenu.setMnemonic('a');
for (EntityCategory cat : getDomain().getCategories()) {
addMenu.add(createAddMenuItem(CategoryKnowledgeFactory.getCategoryKnowledge(cat)));
}
return addMenu;
}
private JMenu createFileMenu() {
JMenu fileMenu = new JMenu("File");
fileMenu.setMnemonic('f');
fileMenu.add(createNewItem());
fileMenu.add(createLoadItem());
fileMenu.add(createSaveItem());
fileMenu.add(createSaveAsItem());
fileMenu.add(createExportToAddis2Item());
fileMenu.add(createExitItem());
return fileMenu;
}
private JMenu createEditMenu() {
JMenu editMenu = new JMenu("Edit");
editMenu.setMnemonic('e');
d_editMenuEditItem = createEditItem();
d_editMenuEditItem.setEnabled(false);
editMenu.add(d_editMenuEditItem);
d_editMenuDeleteItem = createDeleteItem();
d_editMenuDeleteItem.setEnabled(false);
d_editMenuDeleteItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_DELETE, 0));
editMenu.add(d_editMenuDeleteItem);
if(AppInfo.getAppVersion().equals(AppInfo.APPVERSIONFALLBACK)) {
JMenuItem menuItem = new JMenuItem("Generate error");
editMenu.add(menuItem);
menuItem.addActionListener(new ActionListener() {
public void actionPerformed(final ActionEvent e) {
String longStr = Arrays.toString(new double[100]);
throw new RuntimeException("Test exception " + longStr);
}
});
}
return editMenu;
}
private JMenuItem createDeleteItem() {
final JMenuItem item = new JMenuItem("Delete", MainWindow.IMAGELOADER.getIcon(org.drugis.mtc.gui.FileNames.ICON_DELETE));
item.setMnemonic('d');
item.addActionListener(new AbstractAction() {
public void actionPerformed(final ActionEvent arg0) {
if(deleteMenuAction()) {
selectDefaultPath();
}
}
});
return item;
}
private JMenuItem createEditItem() {
JMenuItem item = new JMenuItem("Edit", Main.IMAGELOADER.getIcon(FileNames.ICON_EDIT));
item.setMnemonic('e');
item.addActionListener(new AbstractAction() {
public void actionPerformed(final ActionEvent arg0) {
editMenuAction();
}
});
return item;
}
protected boolean deleteMenuAction() {
Entity selected = getSelectedEntity();
if (selected != null) {
return deleteEntity(selected, true);
}
return false;
}
private Entity getSelectedEntity() {
Object obj = d_leftPanelTree.getSelectionPath().getLastPathComponent();
if (obj instanceof Entity) return (Entity) obj;
return null;
}
protected void editMenuAction() {
Entity selected = getSelectedEntity();
if (selected == null) {
} else if (selected instanceof Study) {
Study study = (Study) selected;
if (getDomain().hasDependents(study)) {
JOptionPane.showMessageDialog(this,
"The study \"" + study + "\" is used by analyses. You can't edit it.",
"Unable to edit",
JOptionPane.ERROR_MESSAGE);
} else {
showEditStudyWizard(study);
}
}
}
private JMenuItem createLoadItem() {
JMenuItem openItem = new JMenuItem("Load", Main.IMAGELOADER
.getIcon(FileNames.ICON_OPENFILE));
openItem.setMnemonic('l');
openItem.addActionListener(new AbstractAction() {
public void actionPerformed(final ActionEvent e) {
if(d_main.isDataChanged()) {
if(saveChangesDialog()) {
d_main.fileLoadActions();
}
} else {
d_main.fileLoadActions();
}
}
});
return openItem;
}
protected boolean saveChangesDialog(){
boolean yesNoClicked = false;
int action = JOptionPane.showConfirmDialog(AddisWindow.this, "Do you want to save changes?",
"File contents changed", JOptionPane.YES_NO_CANCEL_OPTION);
switch(action) {
case JOptionPane.YES_OPTION : {
try {
if (d_main.getCurFilename() == null) {
MainFileSaveDialog dialog = new MainFileSaveDialog(AddisWindow.this, "xml", "XML files");
dialog.saveActions();
yesNoClicked = true;
} else {
d_main.saveDomainToFile(d_main.getCurFilename());
yesNoClicked = true;
}
} catch (Exception e) {
JOptionPane.showMessageDialog(AddisWindow.this, "Error saving domain", "Error saving domain", JOptionPane.ERROR_MESSAGE);
e.printStackTrace();
}
} break;
case JOptionPane.NO_OPTION : {
yesNoClicked = true;
} break;
}
return yesNoClicked;
}
private final class MainFileSaveDialog extends FileSaveDialog {
private MainFileSaveDialog(final Component frame, final String extension,
final String description) {
super(frame, extension, description);
}
@Override
public void doAction(final String path, final String extension) {
d_main.saveDomainToFile(path);
}
}
private JMenuItem createSaveItem() {
d_saveMenuItem = new JMenuItem("Save", Main.IMAGELOADER.getIcon(org.drugis.mtc.gui.FileNames.ICON_SAVEFILE));
d_saveMenuItem.setMnemonic('s');
Bindings.bind(d_saveMenuItem, "enabled", d_main.getDomainChangedModel());
// Attach to ctrl-s
d_saveMenuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_S, KeyEvent.CTRL_DOWN_MASK));
d_saveMenuItem.addActionListener(new AbstractAction() {
public void actionPerformed(final ActionEvent e) {
if (d_main.getCurFilename() == null) {
MainFileSaveDialog dialog = new MainFileSaveDialog(AddisWindow.this, "addis", "ADDIS data files");
dialog.saveActions();
} else {
d_main.saveDomainToFile(d_main.getCurFilename());
}
}
});
return d_saveMenuItem;
}
private JMenuItem createSaveAsItem() {
JMenuItem saveItem = new JMenuItem("Save As", Main.IMAGELOADER.getIcon(org.drugis.mtc.gui.FileNames.ICON_SAVEFILE));
// attach to ctrl-shift-s
saveItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_S, KeyEvent.CTRL_DOWN_MASK | KeyEvent.SHIFT_DOWN_MASK));
//align "Ctrl+Shift+S" text in the menu to the right
saveItem.setAlignmentX(LEFT_ALIGNMENT);
saveItem.setMnemonic('a');
saveItem.addActionListener(new AbstractAction() {
public void actionPerformed(final ActionEvent e) {
MainFileSaveDialog dialog = new MainFileSaveDialog(AddisWindow.this, "addis", "ADDIS data files");
dialog.saveActions();
}
});
return saveItem;
}
private JMenuItem createExportToAddis2Item() {
JMenuItem saveItem = new JMenuItem("Export to ADDIS 2", Main.IMAGELOADER.getIcon(org.drugis.mtc.gui.FileNames.ICON_SAVEFILE));
saveItem.setMnemonic('e');
saveItem.addActionListener(new AbstractAction() {
public void actionPerformed(final ActionEvent e) {
Addis2ExportDialog dialog = new Addis2ExportDialog(AddisWindow.this, d_main.getDomainManager());
dialog.setVisible(true);
}
});
return saveItem;
}
private JMenuItem createExitItem() {
JMenuItem exitItem = new JMenuItem("Exit", Main.IMAGELOADER.getIcon(FileNames.ICON_STOP));
exitItem.setMnemonic('e');
exitItem.addActionListener(new AbstractAction() {
public void actionPerformed(final ActionEvent arg0) {
d_main.quitApplication();
}
});
return exitItem;
}
private class DomainTreeSelectionListener implements TreeSelectionListener {
public void valueChanged(final TreeSelectionEvent event) {
Object node = ((JTree) event.getSource()).getLastSelectedPathComponent();
if (node == null || !(node instanceof Entity)) {
nonEntitySelected();
}
if (node == null) {
noneSelected();
} else if (node instanceof Entity) {
entitySelected((Entity) node);
} else if (node instanceof EntityCategory) {
categorySelected((EntityCategory) node);
} else {
noneSelected();
}
}
};
private void categorySelected(final EntityCategory node) {
CategoryKnowledge knowledge = CategoryKnowledgeFactory.getCategoryKnowledge(node);
setRightPanelView(knowledge.getCategoryViewBuilder(this, getDomain()));
}
private void nonEntitySelected() {
d_editMenuDeleteItem.setEnabled(false);
d_editMenuEditItem.setEnabled(false);
}
private void entitySelected(final Entity entity) {
ViewBuilder view = getEntityKnowledge(entity).getEntityViewBuilder(this, getDomain(), entity);
setRightPanelView(view);
d_editMenuDeleteItem.setEnabled(true);
d_editMenuEditItem.setEnabled(entity instanceof Study);
}
private void initRightPanel() {
d_rightPanel = new JPanel(new BorderLayout());
d_rightPanel.setOpaque(true);
}
public void setRightPanelView(final ViewBuilder view) {
d_rightPanelBuilder = view;
reloadRightPanel();
}
public void reloadRightPanel() {
reloadRightPanel(null);
}
public void reloadRightPanel(final String activeTab) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
if (d_rightPanelBuilder != null) {
d_rightPanel.setVisible(false);
try {
JComponent panel = d_rightPanelBuilder.buildPanel();
setActiveTab(activeTab, panel);
setRightPanelContents(panel);
d_rightPanel.setVisible(true);
} catch (RuntimeException e) {
setRightPanelContents(buildErrorPanel());
d_rightPanel.setVisible(true);
throw e;
}
}
}
private void setActiveTab(final String activeTab, final JComponent panel) {
if(panel instanceof JTabbedPane && activeTab != null) {
JTabbedPane pane = ((JTabbedPane) panel);
pane.setSelectedIndex(pane.indexOfTab(activeTab));
}
}
});
}
private JPanel buildErrorPanel() {
FormLayout layout = new FormLayout("pref:grow:fill", "p");
PanelBuilder builder = new PanelBuilder(layout);
builder.setDefaultDialogBorder();
CellConstraints cc = new CellConstraints();
builder.add(new JLabel("Error building panel"), cc.xy(1, 1));
return builder.getPanel();
}
private void setRightPanelContents(final JComponent component) {
d_rightPanel.removeAll();
d_rightPanel.add(encapsulate(component), BorderLayout.CENTER);
}
private Component encapsulate(final JComponent component) {
if (!(component instanceof AddisTabbedPane)) {
return new AddisScrollPane(component);
}
return component;
}
public void leftTreeFocus(final Object node) {
TreePath path = d_domainTreeModel.getPathTo(node);
if (path != null) {
d_leftPanelTree.setSelectionPath(path);
}
}
private void noneSelected() {
setRightPanelView(new ViewBuilder() {
public JComponent buildPanel() {
return new JPanel();
}
});
}
private CategoryKnowledge getEntityKnowledge(final Entity entity) {
CategoryKnowledge knowledge = CategoryKnowledgeFactory.getCategoryKnowledge(
getDomain().getCategory(entity));
return knowledge;
}
public boolean deleteEntity(final Entity selected, final boolean confirmation) {
String selectedType = getEntityKnowledge(selected).getSingularCapitalized();
if (confirmation) {
int conf = JOptionPane.showConfirmDialog(this,
"Do you really want to delete " + selectedType + " " + selected
+ " ?", "Confirm deletion", JOptionPane.YES_NO_OPTION,
JOptionPane.QUESTION_MESSAGE, MainWindow.IMAGELOADER.getIcon(org.drugis.mtc.gui.FileNames.ICON_DELETE));
if (conf != JOptionPane.YES_OPTION) {
return false;
}
}
try {
getDomain().deleteEntity(selected);
} catch (DependentEntitiesException e) {
String str = new String(selected + " is used by: ");
for (Entity en : e.getDependents()) {
str += "\n\t" + en;
}
str += "\n - delete these first.";
JTextArea text = new JTextArea(str);
text.setWrapStyleWord(true);
text.setLineWrap(true);
text.setMargin(new Insets(5, 5, 5, 5));
JScrollPane sp = new JScrollPane(text);
sp.setPreferredSize(new Dimension(300, 200));
JOptionPane.showMessageDialog(this, sp, "Error deleting "
+ selected, JOptionPane.ERROR_MESSAGE);
}
return true;
}
private JMenuItem createAddMenuItem(final CategoryKnowledge knowledge) {
JMenuItem item = new JMenuItem(knowledge.getSingularCapitalized(), Main.IMAGELOADER.getIcon(knowledge.getNewIconName()));
item.setMnemonic(knowledge.getMnemonic());
item.addActionListener(new AbstractAction() {
public void actionPerformed(final ActionEvent arg0) {
showAddDialog(knowledge, null);
}
});
return item;
}
public void showAddDialog(final CategoryKnowledge knowledge, final ValueModel selectionModel) {
JDialog dialog = knowledge.getAddDialog(this, getDomain(), selectionModel);
dialog.setLocationByPlatform(true);
dialog.setVisible(true);
}
private void showEditStudyWizard(final Study study) {
AddStudyWizardPresentation pm = new AddStudyWizardPresentation(getDomain(), d_pmf, this, study);
JDialog dialog = StudiesKnowledge.buildStudyWizardDialog(this, "Edit Study", pm);
leftTreeFocus(d_domainTreeModel.getRoot());
dialog.setLocationByPlatform(true);
dialog.setVisible(true);
}
private JMenuItem createNewItem() {
JMenuItem newItem = new JMenuItem("New", Main.IMAGELOADER.getIcon(FileNames.ICON_FILE_NEW));
newItem.setMnemonic('n');
newItem.addActionListener(new AbstractAction() {
public void actionPerformed(final ActionEvent arg0) {
if(d_main.isDataChanged()) {
if(saveChangesDialog()){
d_main.newFileActions();
}
} else {
d_main.newFileActions();
}
}
});
return newItem;
}
public void updateTitle() {
setTitle(DEFAULT_TITLE + " - " + d_main.getDisplayName() + (d_main.getDomainChangedModel().getValue() ? "*" : ""));
}
public PresentationModelFactory getPresentationModelFactory() {
return d_pmf;
}
public Runnable getReloadRightPanelAction(final String activeTab) {
return new Runnable() {
public void run() {
reloadRightPanel(activeTab);
}
};
}
}