/** * * Copyright * 2009-2015 Jayway Products AB * 2016-2017 Föreningen Sambruk * * Licensed under AGPL, Version 3.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.gnu.org/licenses/agpl.txt * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package se.streamsource.streamflow.client.ui.workspace; import ca.odell.glazedlists.event.ListEvent; import ca.odell.glazedlists.event.ListEventListener; import ca.odell.glazedlists.gui.TableFormat; import com.jgoodies.forms.factories.Borders; import org.jdesktop.application.Action; import org.jdesktop.application.ApplicationAction; import org.jdesktop.application.ApplicationContext; import org.jdesktop.application.Task; import org.qi4j.api.injection.scope.Service; import org.qi4j.api.injection.scope.Structure; import org.qi4j.api.injection.scope.Uses; import org.qi4j.api.structure.Module; import se.streamsource.streamflow.api.workspace.PerspectiveDTO; import se.streamsource.streamflow.client.MacOsUIWrapper; import se.streamsource.streamflow.client.ui.ContextItem; import se.streamsource.streamflow.client.ui.workspace.search.ManagePerspectivesDialog; import se.streamsource.streamflow.client.ui.workspace.search.SearchResultTableModel; import se.streamsource.streamflow.client.ui.workspace.search.SearchView; import se.streamsource.streamflow.client.ui.workspace.table.CasesTableFormatter; import se.streamsource.streamflow.client.ui.workspace.table.CasesTableView; import se.streamsource.streamflow.client.ui.workspace.table.CasesView; import se.streamsource.streamflow.client.util.CommandTask; import se.streamsource.streamflow.client.util.RoundedBorder; import se.streamsource.streamflow.client.util.StreamflowButton; import se.streamsource.streamflow.client.util.dialog.DialogService; import se.streamsource.streamflow.client.util.dialog.NameDialog; import se.streamsource.streamflow.client.util.i18n; import se.streamsource.streamflow.infrastructure.event.domain.TransactionDomainEvents; import se.streamsource.streamflow.infrastructure.event.domain.source.TransactionListener; import se.streamsource.streamflow.util.Strings; import javax.swing.ActionMap; import javax.swing.BorderFactory; import javax.swing.JComponent; import javax.swing.JDialog; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JList; import javax.swing.JPanel; import javax.swing.KeyStroke; import javax.swing.SwingUtilities; import javax.swing.UIDefaults; import javax.swing.UIManager; import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionListener; import java.awt.BorderLayout; import java.awt.CardLayout; import java.awt.Dimension; import java.awt.FlowLayout; import java.awt.Font; import java.awt.FontMetrics; import java.awt.Insets; import java.awt.Point; import java.awt.Toolkit; import java.awt.event.ComponentAdapter; import java.awt.event.ComponentEvent; import java.awt.event.HierarchyEvent; import java.awt.event.HierarchyListener; import java.awt.event.KeyEvent; /** * JAVADOC */ public class WorkspaceView extends JPanel implements TransactionListener { @Service DialogService dialogs; Module module; SearchResultTableModel searchResultTableModel; private WorkspaceContextView contextView; private JLabel selectedContext; private StreamflowButton selectContextButton; private StreamflowButton createCaseButton; private JDialog popup; private JPanel contextToolbar; private JPanel contextPanel; private CardLayout topLayout = new CardLayout(); private CasesView casesView; private WorkspaceModel model; private SearchView searchView; private javax.swing.Action managePerspectives; private javax.swing.Action savePerspective; private CasesTableView casesTable; public WorkspaceView(final @Service ApplicationContext context, final @Structure Module module, final @Uses WorkspaceModel model) { this.module = module; this.model = model; setLayout(new BorderLayout()); this.setBorder(Borders.createEmptyBorder("2dlu, 2dlu, 2dlu, 2dlu")); getInputMap(WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, KeyEvent.ALT_DOWN_MASK + Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()), "selectTree"); getInputMap(WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_UP, KeyEvent.ALT_DOWN_MASK + Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()), "selectTable"); getInputMap(WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, KeyEvent.ALT_DOWN_MASK + Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()), "selectDetails"); setActionMap(context.getActionMap(this)); MacOsUIWrapper.convertAccelerators(context.getActionMap( WorkspaceView.class, this)); final ActionMap am = getActionMap(); // Proxy menu item actions manually ApplicationAction managePerspectivesAction = (ApplicationAction) getActionMap().get("managePerspectives"); managePerspectives = context.getActionMap().get("managePerspectives"); managePerspectives.putValue("proxy", managePerspectivesAction); // Proxy menu item actions manually ApplicationAction savePerspectiveAction = (ApplicationAction) getActionMap().get("savePerspective"); savePerspective = context.getActionMap().get("savePerspective"); savePerspective.putValue("proxy", savePerspectiveAction); savePerspectiveAction.setEnabled(false); searchResultTableModel = model.newSearchModel(); searchView = module.objectBuilderFactory().newObjectBuilder(SearchView.class).use(searchResultTableModel).newInstance(); casesView = module.objectBuilderFactory().newObjectBuilder(CasesView.class).use(model.newCasesModel(), searchView.getTextField()).newInstance(); // Create Case javax.swing.Action createCaseAction = am.get("createCase"); createCaseButton = new StreamflowButton(createCaseAction); createCaseButton.registerKeyboardAction(createCaseAction, (KeyStroke) createCaseAction .getValue(javax.swing.Action.ACCELERATOR_KEY), JComponent.WHEN_IN_FOCUSED_WINDOW); // Refresh case list javax.swing.Action refreshAction = am.get("refresh"); StreamflowButton refreshButton = new StreamflowButton(refreshAction); refreshButton.registerKeyboardAction(refreshAction, (KeyStroke) refreshAction .getValue(javax.swing.Action.ACCELERATOR_KEY), JComponent.WHEN_IN_FOCUSED_WINDOW); MacOsUIWrapper.convertAccelerators(getActionMap()); JPanel topPanel = new JPanel(new BorderLayout()); selectContextButton = new StreamflowButton(getActionMap().get("selectContext")); selectContextButton.setMargin( new Insets( 3,4,1,3 ) ); selectContextButton.setName("btnSelectContext"); JPanel contextSelectionPanel = new JPanel(new FlowLayout(FlowLayout.LEFT, 0, 0)); contextSelectionPanel.setBorder(BorderFactory.createEmptyBorder(5, 5, 0, 0)); contextSelectionPanel.add(selectContextButton); selectedContext = new JLabel(); selectedContext.setFont(selectedContext.getFont().deriveFont(Font.BOLD)); contextSelectionPanel.add(selectedContext); topPanel.add(contextSelectionPanel, BorderLayout.WEST); contextToolbar = new JPanel(); //contextToolbar.add( perspectiveButton ); contextToolbar.add(createCaseButton); contextToolbar.add(refreshButton); topPanel.add(contextToolbar, BorderLayout.EAST); contextToolbar.setVisible(false); topPanel.add(searchView, BorderLayout.CENTER); searchView.setVisible(false); add(topPanel, BorderLayout.NORTH); add(casesView, BorderLayout.CENTER); contextView = module.objectBuilderFactory().newObjectBuilder(WorkspaceContextView.class).use(model).newInstance(); JList workspaceContextList = contextView.getWorkspaceContextList(); workspaceContextList.addListSelectionListener(new ListSelectionListener() { public void valueChanged(ListSelectionEvent e) { if (!e.getValueIsAdjusting()) { JList list = (JList) e.getSource(); try { if (list.getSelectedValue() == null) { casesView.clearCase(); return; } if (!(list.getSelectedValue() instanceof ContextItem)) return; } catch (IndexOutOfBoundsException e1) { return; // Can get this if filtering with selection } ContextItem contextItem = (ContextItem) list.getSelectedValue(); if (contextItem != null) { boolean isSearch = contextItem.getRelation().equals("search"); boolean isPerspective = contextItem.getRelation().equals("perspective"); TableFormat tableFormat; tableFormat = new CasesTableFormatter(); if (isPerspective) { PerspectiveDTO perspectiveDTO = contextItem.getClient().query("index", PerspectiveDTO.class); String contextRel = perspectiveDTO.context().get(); for (ContextItem item : contextView.getModel().getItems()) { if (contextRel.equals(item.getClient().getReference().toString())) { contextItem = item; isSearch = contextItem.getRelation().equals("search"); break; } } casesTable = module.objectBuilderFactory().newObjectBuilder(CasesTableView.class) .use(isSearch ? searchResultTableModel : contextItem.getClient(), tableFormat, isSearch ? searchView.getTextField() : null) .newInstance(); casesTable.getModel().setFilter(perspectiveDTO); searchView.getTextField().setText(perspectiveDTO.query().get()); setContextString(contextItem, perspectiveDTO.name().get()); } else { casesTable = module.objectBuilderFactory().newObjectBuilder(CasesTableView.class) .use(isSearch ? searchResultTableModel : model.newCasesTableModel(contextItem.getClient()), tableFormat, isSearch ? searchView.getTextField() : null) .newInstance(); searchView.getTextField().setText( "" ); searchResultTableModel.clearSearchString(); casesTable.getModel().clearFilter(); setContextString(contextItem, null); } searchView.setVisible(isSearch); contextToolbar.setVisible(true); casesView.showTable(casesTable); createCaseButton.setVisible(casesTable.getModel().isCreateCaseEnabled()); } else { setContextString(contextItem, null); } killPopup(); } } }); addHierarchyListener(new HierarchyListener() { public void hierarchyChanged(HierarchyEvent e) { if ((e.getChangeFlags() & HierarchyEvent.SHOWING_CHANGED) > 0) { if (!WorkspaceView.this.isShowing()) { killPopup(); context.getActionMap().get("managePerspectives").setEnabled(false); context.getActionMap().get("savePerspective").setEnabled(false); } else { context.getActionMap().get("managePerspectives").setEnabled(true); } } } }); } public void openCase(String id) { contextView.refresh(); contextView.getWorkspaceContextList().setSelectedIndex(1); final ListEventListener listener = new ListEventListener() { boolean executed = false; public void listChanged(ListEvent listEvent) { if (!executed) { // Select first found case casesView.getCaseTableView().getCaseTable().getSelectionModel().setSelectionInterval(0, 0); executed = true; } } }; searchResultTableModel.getEventList().addListEventListener(listener); searchResultTableModel.search(id); } private void setContextString(ContextItem contextItem, String perspective) { if (contextItem != null) { selectedContext.setOpaque(true); UIDefaults uiDefaults = UIManager.getDefaults(); selectedContext.setBackground(uiDefaults.getColor("Menu.selectionBackground")); selectedContext.setForeground(uiDefaults.getColor("Menu.selectionForeground")); selectedContext.setBorder(new RoundedBorder()); String text = ""; if (contextItem.getGroup().equals("")) { text += contextItem.getName(); } else { text += contextItem.getGroup() + " : " + contextItem.getName(); } text = Strings.empty(perspective) ? text : text + " : " + perspective; selectedContext.setText(" " + text + " "); FontMetrics fm = selectedContext.getFontMetrics(selectedContext.getFont()); int width = fm.stringWidth(selectedContext.getText()) + 15; selectedContext.setPreferredSize(new Dimension(width, 22)); } else { selectedContext.setOpaque(false); selectedContext.setBackground(selectedContext.getParent().getBackground()); selectedContext.setForeground(selectedContext.getParent().getForeground()); selectedContext.setText(""); } } @Action public void selectContext() { if (popup == null) { final JFrame frame = (JFrame) SwingUtilities.getAncestorOfClass(JFrame.class, this); popup = new JDialog(frame); popup.setUndecorated(true); popup.setModal(false); popup.setLayout(new BorderLayout()); popup.add(contextView, BorderLayout.CENTER); Point location = selectContextButton.getLocationOnScreen(); popup.setBounds((int) location.getX(), (int) location.getY() + selectContextButton.getHeight(), contextView.getWidth(), contextView.getHeight()); popup.pack(); popup.setVisible(true); frame.addComponentListener(new ComponentAdapter() { @Override public void componentMoved(ComponentEvent e) { if (popup != null) { killPopup(); frame.removeComponentListener(this); } } }); } else { killPopup(); } } @Action public Task createCase() { return new CommandTask() { @Override public void command() throws Exception { casesTable.getModel().clearFilter(); casesTable.getModel().createCase(); } }; } @Action public void refresh() { casesView.refresh(); } @Action public void managePerspectives() { ManagePerspectivesDialog dialog = module.objectBuilderFactory().newObjectBuilder(ManagePerspectivesDialog.class).use(model.newPerspectivesModel()).newInstance(); dialogs.showButtonLessDialog(this, dialog, i18n.text(WorkspaceResources.manage_perspectives)); } @Action public Task savePerspective() { final NameDialog dialog = module.objectBuilderFactory().newObject(NameDialog.class); dialogs.showOkCancelHelpDialog(this, dialog, i18n.text(WorkspaceResources.save_perspective)); if (!Strings.empty(dialog.name())) { return new CommandTask() { @Override public void command() throws Exception { PerspectiveDTO perspective = casesView.getCaseTableView().getModel().getPerspective(dialog.name(), searchView.isVisible() ? searchView.getTextField().getText() : ""); model.newPerspectivesModel().savePerspective(perspective); } }; } else return null; } public void notifyTransactions(Iterable<TransactionDomainEvents> transactions) { } public void killPopup() { if (popup != null) { popup.setVisible(false); popup.dispose(); popup = null; } } public WorkspaceContextView getWorkspaceContext() { return contextView; } }