/******************************************************************************* * Copyright (c) 2016 Weasis Team and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Nicolas Roduit - initial API and implementation *******************************************************************************/ package org.weasis.base.ui.gui; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Component; import java.awt.Dialog; import java.awt.Frame; import java.awt.GraphicsConfiguration; import java.awt.GraphicsDevice; import java.awt.GraphicsEnvironment; import java.awt.Insets; import java.awt.Point; import java.awt.Rectangle; import java.awt.Toolkit; import java.awt.datatransfer.DataFlavor; import java.awt.datatransfer.Transferable; import java.awt.event.ActionEvent; import java.awt.event.InputEvent; import java.awt.event.KeyEvent; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.io.File; import java.lang.management.ManagementFactory; import java.net.MalformedURLException; import java.net.URL; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Optional; import java.util.function.Consumer; import javax.management.InstanceNotFoundException; import javax.management.JMException; import javax.management.MBeanServer; import javax.management.ObjectName; import javax.swing.Action; import javax.swing.Icon; import javax.swing.ImageIcon; import javax.swing.JCheckBoxMenuItem; import javax.swing.JComponent; import javax.swing.JFrame; import javax.swing.JMenu; import javax.swing.JMenuBar; import javax.swing.JMenuItem; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JPopupMenu; import javax.swing.JSeparator; import javax.swing.KeyStroke; import javax.swing.LookAndFeel; import javax.swing.RootPaneContainer; import javax.swing.SwingUtilities; import javax.swing.TransferHandler; import javax.swing.WindowConstants; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.weasis.base.ui.Messages; import org.weasis.core.api.explorer.DataExplorerView; import org.weasis.core.api.explorer.model.DataExplorerModel; import org.weasis.core.api.explorer.model.TreeModel; import org.weasis.core.api.explorer.model.TreeModelNode; import org.weasis.core.api.gui.Insertable; import org.weasis.core.api.gui.util.AppProperties; import org.weasis.core.api.gui.util.DynamicMenu; import org.weasis.core.api.gui.util.GuiExecutor; import org.weasis.core.api.gui.util.JMVUtils; import org.weasis.core.api.gui.util.WinUtil; import org.weasis.core.api.media.data.Codec; import org.weasis.core.api.media.data.MediaElement; import org.weasis.core.api.media.data.MediaReader; import org.weasis.core.api.media.data.MediaSeries; import org.weasis.core.api.media.data.MediaSeriesGroup; import org.weasis.core.api.media.data.Series; import org.weasis.core.api.media.data.TagW; import org.weasis.core.api.service.BundleTools; import org.weasis.core.api.util.ResourceUtil; import org.weasis.core.api.util.StringUtil; import org.weasis.core.api.util.StringUtil.Suffix; import org.weasis.core.ui.docking.DockableTool; import org.weasis.core.ui.docking.UIManager; import org.weasis.core.ui.editor.MimeSystemAppViewer; import org.weasis.core.ui.editor.SeriesViewer; import org.weasis.core.ui.editor.SeriesViewerFactory; import org.weasis.core.ui.editor.ViewerPluginBuilder; import org.weasis.core.ui.editor.image.ImageViewerPlugin; import org.weasis.core.ui.editor.image.ViewCanvas; import org.weasis.core.ui.editor.image.ViewerPlugin; import org.weasis.core.ui.pref.PreferenceDialog; import org.weasis.core.ui.util.ColorLayerUI; import org.weasis.core.ui.util.DefaultAction; import org.weasis.core.ui.util.ToolBarContainer; import org.weasis.core.ui.util.Toolbar; import org.weasis.core.ui.util.UriListFlavor; import bibliothek.extension.gui.dock.theme.EclipseTheme; import bibliothek.extension.gui.dock.theme.eclipse.EclipseTabDockActionLocation; import bibliothek.extension.gui.dock.theme.eclipse.EclipseTabStateInfo; import bibliothek.extension.gui.dock.theme.eclipse.rex.RexSystemColor; import bibliothek.gui.DockUI; import bibliothek.gui.dock.ScreenDockStation; import bibliothek.gui.dock.common.CControl; import bibliothek.gui.dock.common.CLocation; import bibliothek.gui.dock.common.DefaultSingleCDockable; import bibliothek.gui.dock.common.action.CAction; import bibliothek.gui.dock.common.action.predefined.CCloseAction; import bibliothek.gui.dock.common.event.CFocusListener; import bibliothek.gui.dock.common.intern.CDockable; import bibliothek.gui.dock.common.mode.ExtendedMode; import bibliothek.gui.dock.common.theme.ThemeMap; import bibliothek.gui.dock.common.theme.eclipse.CommonEclipseThemeConnector; import bibliothek.gui.dock.station.screen.BoundaryRestriction; import bibliothek.gui.dock.util.ConfiguredBackgroundPanel; import bibliothek.gui.dock.util.DirectWindowProvider; import bibliothek.gui.dock.util.DockUtilities; import bibliothek.gui.dock.util.Priority; import bibliothek.gui.dock.util.color.ColorManager; import bibliothek.gui.dock.util.laf.LookAndFeelColors; import bibliothek.util.Colors; public class WeasisWin { private static final Logger LOGGER = LoggerFactory.getLogger(WeasisWin.class); private static final JMenu menuFile = new JMenu(Messages.getString("WeasisWin.file")); //$NON-NLS-1$ private static final JMenu menuView = new JMenu(Messages.getString("WeasisWin.display")); //$NON-NLS-1$ private static final DynamicMenu menuSelectedPlugin = new DynamicMenu("") { //$NON-NLS-1$ @Override public void popupMenuWillBecomeVisible() { buildSelectedPluginMenu(this); } }; private static ViewerPlugin<?> selectedPlugin = null; private static final WeasisWin instance = new WeasisWin(); private final ToolBarContainer toolbarContainer; private volatile boolean busy = false; private final List<Runnable> runOnClose = new ArrayList<>(); private final Frame frame; private final RootPaneContainer rootPaneContainer; private CFocusListener selectionListener = new CFocusListener() { @Override public void focusGained(CDockable dockable) { if (dockable != null && dockable.getFocusComponent() instanceof ViewerPlugin) { setSelectedPlugin((ViewerPlugin) dockable.getFocusComponent()); } } @Override public void focusLost(CDockable dockable) { // Do nothing } }; private WeasisWin() { MBeanServer server = ManagementFactory.getPlatformMBeanServer(); RootPaneContainer container = null; try { ObjectName objectName = ObjectName.getInstance("weasis:name=MainWindow"); //$NON-NLS-1$ Object containerObj = server.getAttribute(objectName, "RootPaneContainer"); //$NON-NLS-1$ if (containerObj instanceof RootPaneContainer) { container = (RootPaneContainer) containerObj; container.getRootPane().updateUI(); if (container.getContentPane() instanceof JPanel) { ((JPanel) container.getContentPane()).updateUI(); } container.getContentPane().removeAll(); } } catch (InstanceNotFoundException ignored) { } catch (JMException e) { LOGGER.debug("Error while receiving main window", e); //$NON-NLS-1$ } if (container == null || container instanceof JFrame) { JFrame jFrame = container == null ? new JFrame() : (JFrame) container; frame = jFrame; jFrame.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE); frame.addWindowListener(new WindowAdapter() { @Override public void windowClosing(WindowEvent e) { closeWindow(); } }); rootPaneContainer = jFrame; } else { rootPaneContainer = container; // Get Frame of JApplet to pass a parent frame to JDialog. frame = (Frame) SwingUtilities.getAncestorOfClass(Frame.class, (Component) rootPaneContainer); } if (BundleTools.SYSTEM_PREFERENCES.getBooleanProperty("weasis.menu.menubar", true)) { //$NON-NLS-1$ rootPaneContainer.getRootPane().setJMenuBar(createMenuBar()); } toolbarContainer = new ToolBarContainer(); setSelectedPlugin(null); rootPaneContainer.getContentPane().add(toolbarContainer, BorderLayout.NORTH); rootPaneContainer.setGlassPane(AppProperties.glassPane); if (frame != null) { frame.setTitle(AppProperties.WEASIS_NAME + " v" + AppProperties.WEASIS_VERSION); //$NON-NLS-1$ ImageIcon icon = ResourceUtil.getIconLogo64(); if (icon != null) { frame.setIconImage(icon.getImage()); } } } public static WeasisWin getInstance() { return instance; } public Frame getFrame() { return frame; } public RootPaneContainer getRootPaneContainer() { return rootPaneContainer; } public boolean closeWindow() { if (busy) { // TODO add a message, Please wait or kill return false; } if (BundleTools.SYSTEM_PREFERENCES.getBooleanProperty("weasis.confirm.closing", false)) { //$NON-NLS-1$ int option = JOptionPane.showConfirmDialog(frame, Messages.getString("WeasisWin.exit_mes")); //$NON-NLS-1$ if (option == JOptionPane.YES_OPTION) { closeAllRunnable(); System.exit(0); return true; } } else { closeAllRunnable(); System.exit(0); return true; } return false; } private void closeAllRunnable() { for (Runnable onClose : runOnClose) { onClose.run(); } } public void runOnClose(Runnable run) { runOnClose.add(run); } public void destroyOnClose(final CControl control) { runOnClose(control::destroy); } public void createMainPanel() throws Exception { // Do not disable check when debugging if (System.getProperty("maven.localRepository") == null) { //$NON-NLS-1$ DockUtilities.disableCheckLayoutLocked(); } CControl control = UIManager.DOCKING_CONTROL; control.setRootWindow(new DirectWindowProvider(frame)); destroyOnClose(control); ThemeMap themes = control.getThemes(); themes.select(ThemeMap.KEY_ECLIPSE_THEME); control.getController().getProperties().set(EclipseTheme.PAINT_ICONS_WHEN_DESELECTED, true); control.putProperty(ScreenDockStation.BOUNDARY_RESTRICTION, BoundaryRestriction.HARD); control.putProperty(EclipseTheme.THEME_CONNECTOR, new HidingEclipseThemeConnector(control)); // control.setGroupBehavior(CGroupBehavior.TOPMOST); // control.setDefaultLocation(centerArea.getStationLocation()); // Fix substance LookAndFeel laf = javax.swing.UIManager.getLookAndFeel(); if (laf.getClass().getName().startsWith("org.pushingpixels")) { //$NON-NLS-1$ ColorManager colors = control.getController().getColors(); Color selection = javax.swing.UIManager.getColor("TextArea.selectionBackground"); //$NON-NLS-1$ Color inactiveColor = DockUI.getColor(LookAndFeelColors.TITLE_BACKGROUND).darker(); Color inactiveColorGradient = DockUI.getColor(LookAndFeelColors.PANEL_BACKGROUND); Color activeColor = selection.darker(); Color activeTextColor = javax.swing.UIManager.getColor("TextArea.selectionForeground"); //$NON-NLS-1$ colors.put(Priority.CLIENT, "stack.tab.border.selected", inactiveColorGradient); //$NON-NLS-1$ colors.put(Priority.CLIENT, "stack.tab.border.selected.focused", selection); //$NON-NLS-1$ colors.put(Priority.CLIENT, "stack.tab.border.selected.focuslost", inactiveColor); //$NON-NLS-1$ colors.put(Priority.CLIENT, "stack.tab.top.selected", inactiveColor); //$NON-NLS-1$ colors.put(Priority.CLIENT, "stack.tab.top.selected.focused", activeColor); //$NON-NLS-1$ colors.put(Priority.CLIENT, "stack.tab.top.selected.focuslost", inactiveColor); //$NON-NLS-1$ colors.put(Priority.CLIENT, "stack.tab.bottom.selected", inactiveColorGradient); //$NON-NLS-1$ colors.put(Priority.CLIENT, "stack.tab.bottom.selected.focused", selection); //$NON-NLS-1$ colors.put(Priority.CLIENT, "stack.tab.bottom.selected.focuslost", inactiveColor); //$NON-NLS-1$ colors.put(Priority.CLIENT, "stack.tab.text.selected", RexSystemColor.getInactiveTextColor()); //$NON-NLS-1$ colors.put(Priority.CLIENT, "stack.tab.text.selected.focused", activeTextColor); //$NON-NLS-1$ colors.put(Priority.CLIENT, "stack.tab.text.selected.focuslost", RexSystemColor.getInactiveTextColor()); //$NON-NLS-1$ colors.put(Priority.CLIENT, "title.flap.active", selection); //$NON-NLS-1$ colors.put(Priority.CLIENT, "title.flap.active.text", activeTextColor); //$NON-NLS-1$ colors.put(Priority.CLIENT, "title.flap.active.knob.highlight", Colors.brighter(selection)); //$NON-NLS-1$ colors.put(Priority.CLIENT, "title.flap.active.knob.shadow", Colors.darker(selection)); //$NON-NLS-1$ } control.addFocusListener(selectionListener); // control.setDefaultLocation(UIManager.BASE_AREA. // this.add(UIManager.EAST_AREA, BorderLayout.EAST); rootPaneContainer.getContentPane().add(UIManager.BASE_AREA, BorderLayout.CENTER); // Allow to drop series into the empty main area UIManager.MAIN_AREA.getComponent().setTransferHandler(new SequenceHandler()); UIManager.MAIN_AREA.setLocation(CLocation.base().normalRectangle(0, 0, 1, 1)); UIManager.MAIN_AREA.setVisible(true); } HashMap<MediaSeriesGroup, List<MediaSeries<?>>> getSeriesByEntry(TreeModel treeModel, List<? extends MediaSeries<?>> series, TreeModelNode entry) { HashMap<MediaSeriesGroup, List<MediaSeries<?>>> map = new HashMap<>(); if (series != null && treeModel != null && entry != null) { for (MediaSeries<?> s : series) { MediaSeriesGroup entry1 = treeModel.getParent(s, entry); List<MediaSeries<?>> seriesList = Optional.ofNullable(map.get(entry1)).orElseGet(ArrayList::new); seriesList.add(s); map.put(entry1, seriesList); } } return map; } void openSeriesInViewerPlugin(ViewerPluginBuilder builder, MediaSeriesGroup group) { if (builder == null) { return; } SeriesViewerFactory factory = builder.getFactory(); DataExplorerModel model = builder.getModel(); List<MediaSeries<MediaElement>> seriesList = builder.getSeries(); Map<String, Object> props = builder.getProperties(); Rectangle screenBound = (Rectangle) props.get(ViewerPluginBuilder.SCREEN_BOUND); boolean setInSelection = JMVUtils.getNULLtoFalse(props.get(ViewerPluginBuilder.OPEN_IN_SELECTION)); if (screenBound == null && factory != null && group != null) { boolean bestDefaultLayout = JMVUtils.getNULLtoTrue(props.get(ViewerPluginBuilder.BEST_DEF_LAYOUT)); synchronized (UIManager.VIEWER_PLUGINS) { for (int i = UIManager.VIEWER_PLUGINS.size() - 1; i >= 0; i--) { final ViewerPlugin p = UIManager.VIEWER_PLUGINS.get(i); // Remove the views not attached to any window (Fix bugs with external window) if (WinUtil.getParentWindow(p) == null) { UIManager.VIEWER_PLUGINS.remove(i); continue; } if (p instanceof ImageViewerPlugin && p.getName().equals(factory.getUIName()) && group.equals(p.getGroupID())) { ImageViewerPlugin viewer = (ImageViewerPlugin) p; if (setInSelection && seriesList.size() == 1) { viewer.addSeries(seriesList.get(0)); } else { viewer.addSeriesList(seriesList, bestDefaultLayout); } viewer.setSelectedAndGetFocus(); return; } } } } // Pass the DataExplorerModel to the viewer props.put(DataExplorerModel.class.getName(), model); if (seriesList.size() > 1) { props.put(ViewCanvas.class.getName(), seriesList.size()); } SeriesViewer seriesViewer = factory.createSeriesViewer(props); if (seriesViewer instanceof MimeSystemAppViewer) { for (MediaSeries m : seriesList) { seriesViewer.addSeries(m); } } else if (seriesViewer instanceof ViewerPlugin) { ViewerPlugin viewer = (ViewerPlugin) seriesViewer; String title; if (factory.canExternalizeSeries()) { GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment(); GraphicsDevice[] gd = ge.getScreenDevices(); if (gd.length > 1) { viewer.getDockable().setExternalizable(true); setExternalPosition(viewer.getDockable()); // viewer.getDockable().addCDockableLocationListener(new CDockableLocationListener() { // // @Override // public void changed(CDockableLocationEvent event) { // // TODO not a good condition // if (event.getNewLocation() instanceof CExternalizedLocation // && !(event.getOldLocation() instanceof CExternalizedLocation)) { // CDockable dockable = event.getDockable(); // if (dockable instanceof DefaultSingleCDockable) { // setExternalPosition((DefaultSingleCDockable) dockable); // } // } // } // }); } } if (group == null && model instanceof TreeModel && !seriesList.isEmpty() && model.getTreeModelNodeForNewPlugin() != null) { TreeModel treeModel = (TreeModel) model; MediaSeries s = seriesList.get(0); group = treeModel.getParent(s, model.getTreeModelNodeForNewPlugin()); } if (group != null) { title = group.toString(); viewer.setGroupID(group); viewer.getDockable().setTitleToolTip(title); viewer.setPluginName(StringUtil.getTruncatedString(title, 25, Suffix.THREE_PTS)); } // Override default plugin icon Object val = props.get(ViewerPluginBuilder.ICON); if (val instanceof Icon) { viewer.getDockable().setTitleIcon((Icon) val); } boolean isregistered; if (screenBound != null) { isregistered = registerDetachWindow(viewer, screenBound); } else { isregistered = registerPlugin(viewer); } if (isregistered) { viewer.setSelectedAndGetFocus(); if (seriesViewer instanceof ImageViewerPlugin) { if (!setInSelection) { ((ImageViewerPlugin) viewer).selectLayoutPositionForAddingSeries(seriesList); } } for (MediaSeries m : seriesList) { viewer.addSeries(m); } viewer.setSelected(true); } else { viewer.close(); viewer.handleFocusAfterClosing(); } } } private void setExternalPosition(final DefaultSingleCDockable dockable) { // TODO should be set dynamically. Maximize button of external window does not support multi-screens. Toolkit toolkit = Toolkit.getDefaultToolkit(); GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment(); GraphicsDevice[] gd = ge.getScreenDevices(); if (gd.length > 1) { // dockable.setExternalizable(true); Rectangle bound = WinUtil.getClosedScreenBound(rootPaneContainer.getRootPane().getBounds()); // LocationHint hint = // new LocationHint(LocationHint.DOCKABLE, bibliothek.gui.dock.action.LocationHint.LEFT_OF_ALL); // DefaultDockActionSource source = new DefaultDockActionSource(hint); // source.add(setupDropDownMenu(viewer.getDockable())); // source.addSeparator(); for (int i = 0; i < gd.length; i++) { GraphicsConfiguration config = gd[i].getDefaultConfiguration(); final Rectangle b = config.getBounds(); if (!b.contains(bound)) { Insets inset = toolkit.getScreenInsets(config); b.x += inset.left; b.y += inset.top; b.width -= (inset.left + inset.right); b.height -= (inset.top + inset.bottom); dockable.setDefaultLocation(ExtendedMode.EXTERNALIZED, CLocation.external(b.x, b.y, b.width - 150, b.height - 150)); // GuiExecutor.instance().execute(new Runnable() { // // @Override // public void run() { // if (dockable.isVisible()) { // dockable.setLocation(CLocation.external(b.x, b.y, b.width - 150, b.height - 150)); // UIManager.DOCKING_CONTROL.addVetoFocusListener(UIManager.DOCKING_VETO_FOCUS); // dockable.setExtendedMode(ExtendedMode.MAXIMIZED); // UIManager.DOCKING_CONTROL.removeVetoFocusListener(UIManager.DOCKING_VETO_FOCUS); // } // } // }); // source.add(new CloseAction(UIManager.DOCKING_CONTROLLER)); break; } } } } private static boolean registerDetachWindow(final ViewerPlugin plugin, Rectangle screenBound) { if (plugin != null && screenBound != null) { ViewerPlugin oldWin = null; synchronized (UIManager.VIEWER_PLUGINS) { for (int i = UIManager.VIEWER_PLUGINS.size() - 1; i >= 0; i--) { ViewerPlugin p = UIManager.VIEWER_PLUGINS.get(i); if (p.getDockable().isExternalizable()) { Dialog dialog = WinUtil.getParentDialog(p); if (dialog != null && screenBound.equals(WinUtil.getClosedScreenBound(dialog.getBounds()))) { oldWin = p; break; } } } } final DefaultSingleCDockable dock = plugin.getDockable(); dock.setExternalizable(true); if (oldWin == null) { dock.setLocation(CLocation.external(screenBound.x, screenBound.y, screenBound.width - 150, screenBound.height - 150)); plugin.showDockable(); GuiExecutor.instance().execute(() -> { if (dock.isVisible()) { UIManager.DOCKING_CONTROL.addVetoFocusListener(UIManager.DOCKING_VETO_FOCUS); dock.setExtendedMode(ExtendedMode.MAXIMIZED); UIManager.DOCKING_CONTROL.removeVetoFocusListener(UIManager.DOCKING_VETO_FOCUS); } }); } else { ConfiguredBackgroundPanel parent = WinUtil.getParentOfClass(oldWin, ConfiguredBackgroundPanel.class); if (parent == null) { return false; } else { Rectangle b2 = parent.getBounds(); b2.setLocation(parent.getLocationOnScreen()); dock.setLocation(CLocation.external(b2.x, b2.y, b2.width, b2.height).stack()); plugin.showDockable(); } } return true; } return false; } public boolean registerPlugin(final ViewerPlugin plugin) { if (plugin == null || UIManager.VIEWER_PLUGINS.contains(plugin)) { return false; } plugin.showDockable(); return true; } public synchronized ViewerPlugin getSelectedPlugin() { return selectedPlugin; } public synchronized void setSelectedPlugin(ViewerPlugin plugin) { if (plugin == null) { toolbarContainer.registerToolBar(null); List<DockableTool> oldTool = selectedPlugin == null ? null : selectedPlugin.getToolPanel(); if (oldTool != null) { for (DockableTool p : oldTool) { p.closeDockable(); } } selectedPlugin = null; return; } if (selectedPlugin == plugin) { plugin.requestFocusInWindow(); return; } ViewerPlugin oldPlugin = selectedPlugin; if (selectedPlugin != null) { selectedPlugin.setSelected(false); } selectedPlugin = plugin; selectedPlugin.setSelected(true); menuSelectedPlugin.setText(selectedPlugin.getName()); List<DockableTool> tool = selectedPlugin.getToolPanel(); List<DockableTool> oldTool = oldPlugin == null ? null : oldPlugin.getToolPanel(); if (tool != oldTool) { if (oldTool != null) { for (DockableTool p : oldTool) { p.closeDockable(); } } if (tool != null) { for (int i = 0; i < tool.size(); i++) { DockableTool p = tool.get(i); if (p.isComponentEnabled()) { p.showDockable(); } } } } updateToolbars(oldPlugin == null ? null : oldPlugin.getToolBar(), selectedPlugin.getToolBar(), false); } void updateToolbars(List<Toolbar> oldToolBars, List<Toolbar> toolBars, boolean force) { if (force || toolBars != oldToolBars) { toolbarContainer.registerToolBar(toolBars); } } public void showWindow() throws Exception { GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment(); Toolkit kit = Toolkit.getDefaultToolkit(); Rectangle bound; GraphicsConfiguration config = ge.getDefaultScreenDevice().getDefaultConfiguration(); Rectangle b; if (config != null) { b = config.getBounds(); Insets inset = kit.getScreenInsets(config); b.x += inset.left; b.y += inset.top; b.width -= (inset.left + inset.right); b.height -= (inset.top + inset.bottom); } else { b = new Rectangle(new Point(0, 0), kit.getScreenSize()); } bound = b; LOGGER.debug("Max main screen bound: {}", bound.toString()); //$NON-NLS-1$ // setMaximizedBounds(bound); // Do not apply to JApplet if (frame == rootPaneContainer) { // set a valid size, insets of screen is often non consistent frame.setBounds(bound.x, bound.y, bound.width - 150, bound.height - 150); frame.setVisible(true); frame.setExtendedState((frame.getExtendedState() & Frame.MAXIMIZED_BOTH) == Frame.MAXIMIZED_BOTH ? Frame.NORMAL : Frame.MAXIMIZED_BOTH); } LOGGER.info("End of loading the GUI..."); //$NON-NLS-1$ } private JMenuBar createMenuBar() { JMenuBar menuBar = new JMenuBar(); buildMenuFile(); menuBar.add(menuFile); buildMenuView(); menuBar.add(menuView); menuBar.add(menuSelectedPlugin); menuSelectedPlugin.addPopupMenuListener(); final JMenu helpMenuItem = new JMenu(Messages.getString("WeasisWin.help")); //$NON-NLS-1$ final String helpURL = System.getProperty("weasis.help.url"); //$NON-NLS-1$ if (helpURL != null) { final JMenuItem helpContentMenuItem = new JMenuItem(Messages.getString("WeasisWin.guide")); //$NON-NLS-1$ helpContentMenuItem.addActionListener(e -> { try { JMVUtils.openInDefaultBrowser(helpContentMenuItem, new URL(helpURL)); } catch (MalformedURLException e1) { LOGGER.error("Open URL in default browser", e); //$NON-NLS-1$ } }); helpMenuItem.add(helpContentMenuItem); } final JMenuItem webMenuItem = new JMenuItem(Messages.getString("WeasisWin.shortcuts")); //$NON-NLS-1$ webMenuItem.addActionListener(e -> { try { URL url = new URL(BundleTools.SYSTEM_PREFERENCES.getProperty("weasis.help.shortcuts")); //$NON-NLS-1$ JMVUtils.openInDefaultBrowser(webMenuItem, url); } catch (MalformedURLException e1) { LOGGER.error("Open URL in default browser", e); //$NON-NLS-1$ } }); helpMenuItem.add(webMenuItem); final JMenuItem websiteMenuItem = new JMenuItem(Messages.getString("WeasisWin.online")); //$NON-NLS-1$ websiteMenuItem.addActionListener(e -> { try { URL url = new URL(BundleTools.SYSTEM_PREFERENCES.getProperty("weasis.help.online")); //$NON-NLS-1$ JMVUtils.openInDefaultBrowser(websiteMenuItem, url); } catch (MalformedURLException e1) { LOGGER.error("Open URL in default browser", e); //$NON-NLS-1$ } }); helpMenuItem.add(websiteMenuItem); final JMenuItem aboutMenuItem = new JMenuItem(String.format(Messages.getString("WeasisAboutBox.about"), AppProperties.WEASIS_NAME)); //$NON-NLS-1$ aboutMenuItem.addActionListener(e -> { ColorLayerUI layer = ColorLayerUI.createTransparentLayerUI(rootPaneContainer); WeasisAboutBox about = new WeasisAboutBox(); ColorLayerUI.showCenterScreen(about, layer); }); helpMenuItem.add(aboutMenuItem); menuBar.add(helpMenuItem); return menuBar; } private void buildToolBarSubMenu(final JMenu toolBarMenu) { List<Toolbar> bars = toolbarContainer.getRegisteredToolBars(); for (final Toolbar bar : bars) { if (!Insertable.Type.EMPTY.equals(bar.getType())) { JCheckBoxMenuItem item = new JCheckBoxMenuItem(bar.getComponentName(), bar.isComponentEnabled()); item.addActionListener(e -> { if (e.getSource() instanceof JCheckBoxMenuItem) { toolbarContainer.displayToolbar(bar.getComponent(), ((JCheckBoxMenuItem) e.getSource()).isSelected()); } }); toolBarMenu.add(item); } } } private static void buildToolSubMenu(final JMenu toolMenu) { List<DockableTool> tools = selectedPlugin == null ? null : selectedPlugin.getToolPanel(); if (tools != null) { for (final DockableTool t : tools) { if (!Insertable.Type.EMPTY.equals(t.getType())) { JCheckBoxMenuItem item = new JCheckBoxMenuItem(t.getComponentName(), t.isComponentEnabled()); item.addActionListener(e -> { if (e.getSource() instanceof JCheckBoxMenuItem) { t.setComponentEnabled(((JCheckBoxMenuItem) e.getSource()).isSelected()); if (t.isComponentEnabled()) { t.showDockable(); } else { t.closeDockable(); } } }); toolMenu.add(item); } } } } private static void buildEplorerSubMenu(final JMenu explorerMenu) { synchronized (UIManager.EXPLORER_PLUGINS) { List<DataExplorerView> explorers = UIManager.EXPLORER_PLUGINS; for (final DataExplorerView dataExplorerView : explorers) { if (dataExplorerView instanceof DockableTool) { final DockableTool t = (DockableTool) dataExplorerView; if (!Insertable.Type.EMPTY.equals(t.getType())) { JCheckBoxMenuItem item = new JCheckBoxMenuItem(t.getComponentName(), t.isComponentEnabled()); item.addActionListener(e -> { if (e.getSource() instanceof JCheckBoxMenuItem) { t.setComponentEnabled(((JCheckBoxMenuItem) e.getSource()).isSelected()); if (t.isComponentEnabled()) { t.showDockable(); } else { t.closeDockable(); } } }); explorerMenu.add(item); } } } } } private static void buildPrintSubMenu(final JMenu printMenu) { if (selectedPlugin != null) { fillMenu(printMenu, selectedPlugin.getPrintActions()); } } private static void buildOpenSubMenu(final JMenu importMenu) { UIManager.SERIES_VIEWER_FACTORIES.forEach(d -> fillMenu(importMenu, d.getOpenActions())); } private static void buildImportSubMenu(final JMenu importMenu) { UIManager.EXPLORER_PLUGINS.forEach(d -> fillMenu(importMenu, d.getOpenImportDialogAction())); } private static void buildExportSubMenu(final JMenu exportMenu) { if (selectedPlugin != null) { fillMenu(exportMenu, selectedPlugin.getExportActions()); } UIManager.EXPLORER_PLUGINS.forEach(d -> fillMenu(exportMenu, d.getOpenExportDialogAction())); } private static void fillMenu(final JMenu menu, List<Action> actions) { Optional.ofNullable(actions).ifPresent(l -> l.forEach(a -> menu.add(new JMenuItem(a)))); } private static void buildSelectedPluginMenu(final JMenu selectedPluginMenu) { if (selectedPlugin != null) { selectedPlugin.fillSelectedPluginMenu(selectedPluginMenu); } } private void buildMenuView() { menuView.removeAll(); DynamicMenu toolBarMenu = new DynamicMenu(Messages.getString("WeasisWin.toolbar")) {//$NON-NLS-1$ @Override public void popupMenuWillBecomeVisible() { buildToolBarSubMenu(this); } }; toolBarMenu.addPopupMenuListener(); menuView.add(toolBarMenu); DynamicMenu toolMenu = new DynamicMenu(Messages.getString("WeasisWin.tools")) { //$NON-NLS-1$ @Override public void popupMenuWillBecomeVisible() { buildToolSubMenu(this); } }; toolMenu.addPopupMenuListener(); menuView.add(toolMenu); DynamicMenu explorerMenu = new DynamicMenu("Explorer") { //$NON-NLS-1$ @Override public void popupMenuWillBecomeVisible() { buildEplorerSubMenu(this); } }; explorerMenu.addPopupMenuListener(); menuView.add(explorerMenu); // TODO add save workspace layout // final AbstractAction saveAction = new AbstractAction("Save workspace layout") { //$NON-NLS-1$ // // @Override // public void actionPerformed(ActionEvent e) { // // Handle workspace ui persistence // try { // UIManager.DOCKING_CONTROL.save("lastLayout", false); // final BundleContext context = FrameworkUtil.getBundle(WeasisWin.class).getBundleContext(); // File file = new File(BundlePreferences.getDataFolder(context), "lastLayout.xml"); // UIManager.DOCKING_CONTROL.writeXML(file); // } catch (IOException e1) { // e1.printStackTrace(); // } // } // }; // menuView.add(saveAction); // // final AbstractAction loadAction = new AbstractAction("Restore last workspace layout") { //$NON-NLS-1$ // // @Override // public void actionPerformed(ActionEvent e) { // try { // final BundleContext context = FrameworkUtil.getBundle(WeasisWin.class).getBundleContext(); // File file = new File(BundlePreferences.getDataFolder(context), "lastLayout.xml"); // if (file.canRead()) { // UIManager.DOCKING_CONTROL.readXML(file); // UIManager.DOCKING_CONTROL.load("lastLayout", false); // } // } catch (IOException e1) { // e1.printStackTrace(); // } // } // }; // menuView.add(loadAction); } private static void buildMenuFile() { menuFile.removeAll(); DynamicMenu openMenu = new DynamicMenu(Messages.getString("WeasisWin.open")) { //$NON-NLS-1$ @Override public void popupMenuWillBecomeVisible() { buildOpenSubMenu(this); } }; openMenu.addPopupMenuListener(); menuFile.add(openMenu); DynamicMenu importMenu = new DynamicMenu(Messages.getString("WeasisWin.import")) {//$NON-NLS-1$ @Override public void popupMenuWillBecomeVisible() { buildImportSubMenu(this); } }; importMenu.addPopupMenuListener(); menuFile.add(importMenu); DynamicMenu exportMenu = new DynamicMenu(Messages.getString("WeasisWin.export")) {//$NON-NLS-1$ @Override public void popupMenuWillBecomeVisible() { buildExportSubMenu(this); } }; exportMenu.addPopupMenuListener(); menuFile.add(exportMenu); menuFile.add(new JSeparator()); DynamicMenu printMenu = new DynamicMenu(Messages.getString("WeasisWin.print")) { //$NON-NLS-1$ @Override public void popupMenuWillBecomeVisible() { buildPrintSubMenu(this); } }; printMenu.addPopupMenuListener(); menuFile.add(printMenu); menuFile.add(new JSeparator()); Consumer<ActionEvent> prefAction = e -> { ColorLayerUI layer = ColorLayerUI.createTransparentLayerUI(WeasisWin.getInstance().getRootPaneContainer()); PreferenceDialog dialog = new PreferenceDialog(WeasisWin.getInstance().getFrame()); ColorLayerUI.showCenterScreen(dialog, layer); }; DefaultAction preferencesAction = new DefaultAction(org.weasis.core.ui.Messages.getString("OpenPreferencesAction.title"), //$NON-NLS-1$ prefAction); preferencesAction.putValue(Action.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_P, InputEvent.ALT_MASK)); menuFile.add(new JMenuItem(preferencesAction)); menuFile.add(new JSeparator()); DefaultAction exitAction = new DefaultAction(Messages.getString("ExitAction.title"), //$NON-NLS-1$ e -> WeasisWin.getInstance().closeWindow()); menuFile.add(new JMenuItem(exitAction)); } private class SequenceHandler extends TransferHandler { public SequenceHandler() { super("series"); //$NON-NLS-1$ } @Override public Transferable createTransferable(JComponent comp) { return null; } @Override public boolean canImport(TransferSupport support) { if (!support.isDrop()) { return false; } if (support.isDataFlavorSupported(Series.sequenceDataFlavor) || support.isDataFlavorSupported(DataFlavor.javaFileListFlavor) || support.isDataFlavorSupported(UriListFlavor.flavor)) { return true; } return false; } @Override public boolean importData(TransferSupport support) { if (!canImport(support)) { return false; } Transferable transferable = support.getTransferable(); List<File> files = null; // Not supported by some OS if (support.isDataFlavorSupported(DataFlavor.javaFileListFlavor)) { try { files = (List<File>) transferable.getTransferData(DataFlavor.javaFileListFlavor); } catch (Exception e) { LOGGER.error("Get dragable files", e); //$NON-NLS-1$ } return dropFiles(files, support.getDropLocation()); } // When dragging a file or group of files // http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4899516 else if (support.isDataFlavorSupported(UriListFlavor.flavor)) { try { // Files with spaces in the filename trigger an error // http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6936006 String val = (String) transferable.getTransferData(UriListFlavor.flavor); files = UriListFlavor.textURIListToFileList(val); } catch (Exception e) { LOGGER.error("Get dragable URIs", e); //$NON-NLS-1$ } return dropFiles(files, support.getDropLocation()); } Series seq; try { seq = (Series) transferable.getTransferData(Series.sequenceDataFlavor); if (seq == null) { return false; } synchronized (UIManager.SERIES_VIEWER_FACTORIES) { for (final SeriesViewerFactory factory : UIManager.SERIES_VIEWER_FACTORIES) { if (factory.canReadMimeType(seq.getMimeType())) { DataExplorerModel model = (DataExplorerModel) seq.getTagValue(TagW.ExplorerModel); if (model instanceof TreeModel) { ArrayList<MediaSeries<MediaElement>> list = new ArrayList<>(1); list.add(seq); ViewerPluginBuilder builder = new ViewerPluginBuilder(factory, list, model, null); openSeriesInViewerPlugin(builder, ((TreeModel) model).getParent(seq, model.getTreeModelNodeForNewPlugin())); } else { ViewerPluginBuilder.openSequenceInDefaultPlugin(seq, model == null ? ViewerPluginBuilder.DefaultDataModel : model, true, true); } break; } } } } catch (Exception e) { LOGGER.error("Open series", e); //$NON-NLS-1$ return false; } return true; } private boolean dropFiles(final List<File> files, DropLocation dropLocation) { if (files != null) { List<DataExplorerView> explorers = new ArrayList<>(UIManager.EXPLORER_PLUGINS); for (int i = explorers.size() - 1; i >= 0; i--) { if (!explorers.get(i).canImportFiles()) { explorers.remove(i); } } final List<File> dirs = new ArrayList<>(); Map<Codec, List<File>> codecs = new HashMap<>(); for (File file : files) { if (file.isDirectory()) { dirs.add(file); continue; } MediaReader reader = ViewerPluginBuilder.getMedia(file, false); if (reader != null) { Codec c = reader.getCodec(); if (c != null) { List<File> cFiles = codecs.get(c); if (cFiles == null) { cFiles = new ArrayList<>(); codecs.put(c, cFiles); } cFiles.add(file); } } } if (!dirs.isEmpty() && !explorers.isEmpty()) { importInExplorer(explorers, dirs, dropLocation); } for (Iterator<Entry<Codec, List<File>>> it = codecs.entrySet().iterator(); it.hasNext();) { Entry<Codec, List<File>> entry = it.next(); final List<File> vals = entry.getValue(); List<DataExplorerView> exps = new ArrayList<>(); for (final DataExplorerView dataExplorerView : explorers) { DataExplorerModel model = dataExplorerView.getDataExplorerModel(); if (model != null) { List<Codec> cList = model.getCodecPlugins(); if (cList != null && cList.contains(entry.getKey())) { exps.add(dataExplorerView); } } } if (exps.isEmpty()) { for (File file : vals) { ViewerPluginBuilder.openSequenceInDefaultPlugin(file, true, true); } } else { importInExplorer(exps, vals, dropLocation); } } return true; } return false; } private void importInExplorer(List<DataExplorerView> exps, final List<File> vals, DropLocation dropLocation) { if (exps.size() == 1) { exps.get(0).importFiles(vals.toArray(new File[vals.size()]), true); } else { Point p; if (dropLocation == null) { Rectangle b = WeasisWin.this.getFrame().getBounds(); p = new Point((int) b.getCenterX(), (int) b.getCenterY()); } else { p = dropLocation.getDropPoint(); } JPopupMenu popup = new JPopupMenu(); for (final DataExplorerView dataExplorerView : exps) { JMenuItem item = new JMenuItem(dataExplorerView.getUIName(), dataExplorerView.getIcon()); item.addActionListener( e -> dataExplorerView.importFiles(vals.toArray(new File[vals.size()]), true)); popup.add(item); } popup.show(WeasisWin.this.getFrame(), p.x, p.y); } } } public static class HidingEclipseThemeConnector extends CommonEclipseThemeConnector { public HidingEclipseThemeConnector(CControl control) { super(control); } @Override protected EclipseTabDockActionLocation getLocation(CAction action, EclipseTabStateInfo tab) { if (action instanceof CCloseAction) { /* * By redefining the behavior of the close-action, we can hide it if the tab is not selected */ if (tab.isSelected()) { return EclipseTabDockActionLocation.TAB; } else { return EclipseTabDockActionLocation.HIDDEN; } } return super.getLocation(action, tab); } } }