/** * * 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; import org.jdesktop.application.Action; import org.jdesktop.application.ApplicationAction; import org.jdesktop.application.ProxyActions; import org.jdesktop.application.SingleFrameApplication; import org.jdesktop.application.TaskService; import org.jdesktop.swingx.JXErrorPane; import org.jdesktop.swingx.error.ErrorInfo; import org.jdesktop.swingx.util.WindowUtils; 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.io.Inputs; import org.qi4j.api.io.Outputs; import org.qi4j.api.io.Receiver; import org.qi4j.bootstrap.Energy4Java; import org.qi4j.spi.property.ValueType; import org.qi4j.spi.structure.ApplicationSPI; import org.qi4j.spi.structure.ModuleSPI; import org.restlet.Client; import org.restlet.Request; import org.restlet.Response; import org.restlet.Restlet; import org.restlet.data.Protocol; import org.restlet.routing.Filter; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import se.streamsource.dci.value.link.LinkValue; import se.streamsource.streamflow.api.workspace.cases.CaseDTO; import se.streamsource.streamflow.client.assembler.StreamflowClientAssembler; import se.streamsource.streamflow.client.ui.DebugWindow; import se.streamsource.streamflow.client.ui.account.AccountResources; import se.streamsource.streamflow.client.ui.account.AccountSelector; import se.streamsource.streamflow.client.ui.account.AccountsDialog; import se.streamsource.streamflow.client.ui.account.AccountsModel; import se.streamsource.streamflow.client.ui.account.ProfileView; import se.streamsource.streamflow.client.ui.administration.AdministrationWindow; import se.streamsource.streamflow.client.ui.overview.OverviewWindow; import se.streamsource.streamflow.client.ui.workspace.WorkspaceWindow; import se.streamsource.streamflow.client.util.JavaHelp; import se.streamsource.streamflow.client.util.dialog.DialogService; import se.streamsource.streamflow.client.util.i18n; import se.streamsource.streamflow.infrastructure.event.domain.DomainEvent; import se.streamsource.streamflow.infrastructure.event.domain.TransactionDomainEvents; import se.streamsource.streamflow.infrastructure.event.domain.source.EventStream; import se.streamsource.streamflow.infrastructure.event.domain.source.TransactionListener; import javax.jnlp.ServiceManager; import javax.jnlp.SingleInstanceListener; import javax.jnlp.SingleInstanceService; import javax.jnlp.UnavailableServiceException; import javax.swing.JComponent; import javax.swing.SwingUtilities; import javax.swing.ToolTipManager; import javax.swing.UnsupportedLookAndFeelException; import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionListener; import java.awt.Component; import java.awt.Container; import java.awt.Cursor; import java.awt.Frame; import java.awt.Window; import java.awt.event.ActionEvent; import java.io.File; import java.io.IOException; import java.util.Arrays; import java.util.Collections; import java.util.EventObject; import java.util.concurrent.Executors; import static se.streamsource.streamflow.client.util.i18n.*; /** * Controller for the application */ @ProxyActions({"cut", "copy", "paste", "createDraft", "complete", "assign", "drop", "forward", // Case related proxy actions "find", "selectTree", "selectTable", "selectDetails"}) public class StreamflowApplication extends SingleFrameApplication implements TransactionListener, SingleInstanceListener { public static ValueType DOMAIN_EVENT_TYPE; final Logger logger = LoggerFactory.getLogger(getClass().getName()); final Logger streamflowLogger = LoggerFactory.getLogger(LoggerCategories.STREAMFLOW); @Structure ModuleSPI module; @Service DialogService dialogs; @Service EventStream stream; @Service JavaHelp javaHelp; AccountsModel accountsModel; private AccountSelector accountSelector; WorkspaceWindow workspaceWindow; OverviewWindow overviewWindow; AdministrationWindow administrationWindow; DebugWindow debugWindow; public ApplicationSPI app; private String openCaseJson; public StreamflowApplication() { super(); // We have to ensure that calls to the server are done in the order they were executed, // so make it single threaded getContext().removeTaskService(getContext().getTaskService()); getContext().addTaskService(new TaskService("default", Executors.newSingleThreadExecutor())); getContext().getResourceManager().setApplicationBundleNames(Arrays.asList("se.streamsource.streamflow.client.resources.StreamflowApplication")); } @Override protected void initialize(String[] args) { // Check if we are supposed to open a particular case final File[] openFile = new File[1]; if (args.length > 0) { if (args[0].equals("-open")) { openFile(new File(args[1])); } } try { SingleInstanceService singleInstanceService = (SingleInstanceService) ServiceManager.lookup(SingleInstanceService.class.getName()); singleInstanceService.addSingleInstanceListener(this); } catch (UnavailableServiceException e) { // Ignore } } public void newActivation(String[] args) { System.out.println("New args:" + Arrays.asList(args)); if (args.length > 0) { initialize(args); CaseDTO caseDTO = module.valueBuilderFactory().newValueFromJSON(CaseDTO.class, openCaseJson); openCaseJson = null; workspaceWindow.getCurrentWorkspace().openCase(caseDTO.caseId().get()); } } public void openFile(File file) { System.out.println("Opening: " + file); try { final StringBuffer buf = new StringBuffer(); Inputs.text(file.getAbsoluteFile()).transferTo(Outputs.withReceiver(new Receiver<String, RuntimeException>() { public void receive(String item) throws RuntimeException { buf.append(item); } })); openCaseJson = buf.toString(); System.out.println(buf); } catch (IOException e) { e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates. } } public void init(@Uses final AccountsModel accountsModel, @Uses final AccountSelector accountSelector, @Service EventStream stream ) throws IllegalAccessException, UnsupportedLookAndFeelException, InstantiationException, ClassNotFoundException { DOMAIN_EVENT_TYPE = module.valueDescriptor(DomainEvent.class.getName()).valueType(); this.stream = stream; // NotificationGlassPane.install(); try { //Check for Mac OS - and load if we are on Mac getClass().getClassLoader().loadClass("com.apple.eawt.Application"); MacOsUIExtension osUIExtension = new MacOsUIExtension(this); osUIExtension.attachMacUIExtension(); osUIExtension.attachMacOpenFileExtension(); osUIExtension.convertAccelerators(); } catch (Throwable e) { //Do nothing } // General UI settings String toolTipDismissDelay = i18n.text(StreamflowResources.tooltip_delay_dismiss); String toolTipInitialDelay = i18n.text(StreamflowResources.tooltip_delay_initial); String toolTipReshowDelay = i18n.text(StreamflowResources.tooltip_delay_reshow); if (toolTipInitialDelay != null && !toolTipInitialDelay.trim().equals("")) { ToolTipManager.sharedInstance().setInitialDelay(Integer.parseInt(toolTipInitialDelay)); } if (toolTipDismissDelay != null && !toolTipDismissDelay.trim().equals("")) { ToolTipManager.sharedInstance().setDismissDelay(Integer.parseInt(toolTipDismissDelay)); } if (toolTipReshowDelay != null && !toolTipReshowDelay.trim().equals("")) { ToolTipManager.sharedInstance().setReshowDelay(Integer.parseInt(toolTipReshowDelay)); } getContext().getActionMap().get("myProfile").setEnabled(false); this.accountSelector = accountSelector; this.workspaceWindow = module.objectBuilderFactory().newObjectBuilder(WorkspaceWindow.class).use(accountSelector).newInstance(); this.overviewWindow = module.objectBuilderFactory().newObjectBuilder(OverviewWindow.class).use(accountSelector).newInstance(); this.administrationWindow = module.objectBuilderFactory().newObjectBuilder(AdministrationWindow.class).use(accountSelector).newInstance(); this.debugWindow = module.objectBuilderFactory().newObjectBuilder(DebugWindow.class).newInstance(); setMainFrame(workspaceWindow.getFrame()); this.accountsModel = accountsModel; showWorkspaceWindow(); // Auto-select first account if only one available SwingUtilities.invokeLater(new Runnable() { public void run() { if (accountsModel.getAccounts().size() == 1) { accountSelector.setSelectedIndex(0); if (openCaseJson != null) { CaseDTO caseDTO = module.valueBuilderFactory().newValueFromJSON(CaseDTO.class, openCaseJson); openCaseJson = null; workspaceWindow.getCurrentWorkspace().openCase(caseDTO.caseId().get()); } } } }); accountSelector.getSelectionModel().addListSelectionListener(new ListSelectionListener() { public void valueChanged(ListSelectionEvent e) { StreamflowApplication.this.getContext().getActionMap().get("myProfile").setEnabled(!accountSelector.getSelectionModel().isSelectionEmpty()); } }); getContext().getActionMap().get("savePerspective").setEnabled(false); getContext().getActionMap().get("managePerspectives").setEnabled(false); } @Override protected void startup() { try { Client client = new Client(Protocol.HTTP); client.start(); // Make it slower to get it more realistic Restlet restlet = new Filter(client.getContext(), client) { @Override protected int beforeHandle(Request request, Response response) { workspaceWindow.getFrame().setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); return super.beforeHandle(request, response); } @Override protected void afterHandle(Request request, Response response) { workspaceWindow.getFrame().setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); super.afterHandle(request, response); } }; Energy4Java is = new Energy4Java(); app = is.newApplication(new StreamflowClientAssembler(this, org.jdesktop.application.Application.getInstance().getContext(), restlet)); logger.info("Starting in " + app.mode() + " mode"); app.activate(); } catch (Throwable e) { JXErrorPane.showDialog(getMainFrame(), new ErrorInfo(i18n.text(StreamflowResources.startup_error), e.getMessage(), null, "#error", e, java.util.logging.Level.SEVERE, Collections.<String, String>emptyMap())); shutdown(); } streamflowLogger.info("Startup done"); } // Menu actions @Action public void manageAccounts() { LinkValue selectedValue = (LinkValue) accountSelector.getSelectedValue(); AccountsDialog dialog = module.objectBuilderFactory().newObjectBuilder(AccountsDialog.class).use(accountsModel).newInstance(); dialog.setSelectedAccount(selectedValue); dialogs.showOkDialog(getMainFrame(), dialog, text(AccountResources.account_title)); } @Action public void selectAccount() { accountSelector.clearSelection(); if (administrationWindow.getFrame().isVisible()) { administrationWindow.getFrame().setVisible(false); overviewWindow.getFrame().setVisible(false); } } @Action public void myProfile() { ProfileView profile = module.objectBuilderFactory().newObjectBuilder(ProfileView.class).use(accountSelector.getSelectedAccount().getProfileModel()).newInstance(); dialogs.showOkDialog(getMainFrame(), profile, text(AccountResources.profile_title)); } // Proxy actions for perspective @Action public void savePerspective(ActionEvent e) { ((ApplicationAction) getContext().getActionMap().get("savePerspective").getValue("proxy")).actionPerformed( e ); } @Action public void managePerspectives(ActionEvent e) { ((ApplicationAction) getContext().getActionMap().get("managePerspectives").getValue("proxy")).actionPerformed( e ); } // Proxy actions for message view @Action public void closeMessageDetails(ActionEvent e) { ((ApplicationAction) getContext().getActionMap().get("closeMessageDetails").getValue("proxy")).actionPerformed( e ); } @Action public void createMessage(ActionEvent e) { ((ApplicationAction) getContext().getActionMap().get("createMessage").getValue("proxy")).actionPerformed(e); } @Action public void cancelNewMessage(ActionEvent e) { ((ApplicationAction) getContext().getActionMap().get("cancelNewMessage").getValue("proxy")).actionPerformed(e); } public EventStream getSource() { return stream; } public void notifyTransactions(Iterable<TransactionDomainEvents> transactions) { for (Window window : Frame.getWindows()) { dispatchTransactions(window, transactions); } } private void dispatchTransactions(Component component, Iterable<TransactionDomainEvents> transactionEventsIterable) { if (!component.isShowing()) return; if (component instanceof TransactionListener) ((TransactionListener) component).notifyTransactions(transactionEventsIterable); if (component instanceof Container) { Container container = (Container) component; for (Component childComponent : container.getComponents()) { // Only dispatch to visible components - they will refresh once visible anyway dispatchTransactions(childComponent, transactionEventsIterable); } } } // Controller actions ------------------------------------------- // Menu actions // Account menu @Action public void showWorkspaceWindow() { if (!workspaceWindow.getFrame().isVisible()) { show(workspaceWindow); } workspaceWindow.getFrame().toFront(); } @Action public void showOverviewWindow() throws Exception { if (!overviewWindow.getFrame().isVisible()) { show(overviewWindow); } overviewWindow.getFrame().toFront(); } @Action public void showAdministrationWindow() throws Exception { if (!administrationWindow.getFrame().isVisible()) show(administrationWindow); administrationWindow.getFrame().toFront(); } @Action public void showDebugWindow() throws Exception { if (!debugWindow.getFrame().isVisible()) show(debugWindow); debugWindow.getFrame().toFront(); } @Action public void close(ActionEvent e) { WindowUtils.findWindow( (Component) e.getSource() ).dispose(); } @Action public void cancel(ActionEvent e) { WindowUtils.findWindow((Component) e.getSource()).dispose(); } @Action public void showAbout() { dialogs.showOkDialog( getMainFrame(), new AboutDialog( getContext() ) ); } @Action public void showHelp(ActionEvent event) { // Turn off java help for 1.0 release // javaHelp.init(); } @Override public void exit(EventObject eventObject) { super.exit(eventObject); } @Override protected void shutdown() { try { SingleInstanceService singleInstanceService = (SingleInstanceService) ServiceManager.lookup(SingleInstanceService.class.getName()); singleInstanceService.removeSingleInstanceListener(this); } catch (UnavailableServiceException e) { // Ignore } try { if (app != null) app.passivate(); } catch (Exception e) { e.printStackTrace(); } } @Override protected void show(JComponent jComponent) { super.show(jComponent); } public String currentUserId() { return accountSelector.getSelectedAccount().settings().userName().get(); } public long markReadTimeout() { return accountSelector.getSelectedAccount().getProfileModel().getIndex().markReadTimeout().get() * 1000; } public void callRefresh() { if( workspaceWindow.getCurrentWorkspace().isVisible() && workspaceWindow.getCurrentWorkspace().isShowing() ) { workspaceWindow.getCurrentWorkspace().refresh(); } } }