/*******************************************************************************
* 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
*******************************************************************************/
// Placed in public domain by Dmitry Olshansky, 2006
package org.weasis.core.ui.editor.image;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Cursor;
import java.awt.Dialog;
import java.awt.Dialog.ModalityType;
import java.awt.Dimension;
import java.awt.Frame;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.InputEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JComponent;
import javax.swing.JDialog;
import javax.swing.JPanel;
import javax.swing.plaf.PanelUI;
import org.weasis.core.api.gui.util.ActionState;
import org.weasis.core.api.gui.util.ActionW;
import org.weasis.core.api.gui.util.ComboItemListener;
import org.weasis.core.api.gui.util.Filter;
import org.weasis.core.api.gui.util.GuiExecutor;
import org.weasis.core.api.gui.util.WinUtil;
import org.weasis.core.api.image.GridBagLayoutModel;
import org.weasis.core.api.image.LayoutConstraints;
import org.weasis.core.api.media.data.ImageElement;
import org.weasis.core.api.media.data.MediaSeries;
import org.weasis.core.api.media.data.Series;
import org.weasis.core.ui.Messages;
import org.weasis.core.ui.editor.SeriesViewerEvent;
import org.weasis.core.ui.editor.SeriesViewerEvent.EVENT;
import org.weasis.core.ui.editor.SeriesViewerListener;
import org.weasis.core.ui.model.graphic.DragGraphic;
import org.weasis.core.ui.model.graphic.Graphic;
import org.weasis.core.ui.pref.Monitor;
import org.weasis.core.ui.util.MouseEventDouble;
public abstract class ImageViewerPlugin<E extends ImageElement> extends ViewerPlugin<E> {
private static final long serialVersionUID = -5804430771962614157L;
private static final String patterViews = Messages.getString("ImageViewerPlugin.2"); //$NON-NLS-1$
// A model must have at least one view that inherited of DefaultView2d
public static final Class<?> view2dClass = ViewCanvas.class;
public static final GridBagLayoutModel VIEWS_1x1 = new GridBagLayoutModel("1x1", //$NON-NLS-1$
String.format(Messages.getString("ImageViewerPlugin.1"), "1x1"), 1, 1, view2dClass.getName(), //$NON-NLS-1$ //$NON-NLS-2$
new ImageIcon(ImageViewerPlugin.class.getResource("/icon/22x22/layout1x1.png"))); //$NON-NLS-1$
public static final GridBagLayoutModel VIEWS_2x1 = new GridBagLayoutModel("2x1", //$NON-NLS-1$
String.format(patterViews, "2x1"), 2, 1, view2dClass.getName(), //$NON-NLS-1$
new ImageIcon(ImageViewerPlugin.class.getResource("/icon/22x22/layout2x1.png"))); //$NON-NLS-1$
public static final GridBagLayoutModel VIEWS_1x2 = new GridBagLayoutModel("1x2", //$NON-NLS-1$
String.format(patterViews, "1x2"), 1, 2, view2dClass.getName(), //$NON-NLS-1$
new ImageIcon(ImageViewerPlugin.class.getResource("/icon/22x22/layout1x2.png"))); //$NON-NLS-1$
public static final GridBagLayoutModel VIEWS_2x2_f2 =
new GridBagLayoutModel(ImageViewerPlugin.class.getResourceAsStream("/config/layoutModel2x2_f2.xml"), //$NON-NLS-1$
"layout_c2x1", Messages.getString("ImageViewerPlugin.layout_c2x1"), //$NON-NLS-1$ //$NON-NLS-2$
new ImageIcon(ImageViewerPlugin.class.getResource("/icon/22x22/layout2x2_f2.png"))); //$NON-NLS-1$
public static final GridBagLayoutModel VIEWS_2_f1x2 =
new GridBagLayoutModel(ImageViewerPlugin.class.getResourceAsStream("/config/layoutModel2_f1x2.xml"), //$NON-NLS-1$
"layout_c1x2", Messages.getString("ImageViewerPlugin.layout_c1x2"), //$NON-NLS-1$ //$NON-NLS-2$
new ImageIcon(ImageViewerPlugin.class.getResource("/icon/22x22/layout2_f1x2.png"))); //$NON-NLS-1$
public static final GridBagLayoutModel VIEWS_2x2 = new GridBagLayoutModel("2x2", //$NON-NLS-1$
String.format(patterViews, "2x2"), 2, 2, view2dClass.getName(), //$NON-NLS-1$
new ImageIcon(ImageViewerPlugin.class.getResource("/icon/22x22/layout2x2.png"))); //$NON-NLS-1$
public static final GridBagLayoutModel VIEWS_3x2 = new GridBagLayoutModel("3x2", //$NON-NLS-1$
String.format(patterViews, "3x2"), 3, 2, view2dClass.getName(), //$NON-NLS-1$
new ImageIcon(ImageViewerPlugin.class.getResource("/icon/22x22/layout3x2.png"))); //$NON-NLS-1$
public static final GridBagLayoutModel VIEWS_3x3 = new GridBagLayoutModel("3x3", //$NON-NLS-1$
String.format(patterViews, "3x3"), 3, 3, view2dClass.getName(), //$NON-NLS-1$
new ImageIcon(ImageViewerPlugin.class.getResource("/icon/22x22/layout3x3.png"))); //$NON-NLS-1$
public static final GridBagLayoutModel VIEWS_4x3 = new GridBagLayoutModel("4x3", //$NON-NLS-1$
String.format(patterViews, "4x3"), 4, 3, view2dClass.getName(), //$NON-NLS-1$
new ImageIcon(ImageViewerPlugin.class.getResource("/icon/22x22/layout4x3.png"))); //$NON-NLS-1$
public static final GridBagLayoutModel VIEWS_4x4 = new GridBagLayoutModel("4x4", //$NON-NLS-1$
String.format(patterViews, "4x4"), 4, 4, view2dClass.getName(), //$NON-NLS-1$
new ImageIcon(ImageViewerPlugin.class.getResource("/icon/22x22/layout4x4.png"))); //$NON-NLS-1$
/**
* The current focused <code>ImagePane</code>. The default is 0.
*/
protected ViewCanvas<E> selectedImagePane = null;
/**
* The array of display panes located in this image view panel.
*/
protected final ArrayList<ViewCanvas<E>> view2ds;
protected final ArrayList<Component> components;
protected SynchView synchView = SynchView.NONE;
protected final ImageViewerEventManager<E> eventManager;
protected final JPanel grid;
protected GridBagLayoutModel layoutModel;
private final MouseHandler mouseHandler;
public ImageViewerPlugin(ImageViewerEventManager<E> eventManager, String pluginName) {
this(eventManager, VIEWS_1x1, pluginName, null, null, null);
}
public ImageViewerPlugin(ImageViewerEventManager<E> eventManager, GridBagLayoutModel layoutModel, String uid,
String pluginName, Icon icon, String tooltips) {
super(uid, pluginName, icon, tooltips);
if (eventManager == null) {
throw new IllegalArgumentException("EventManager cannot be null"); //$NON-NLS-1$
}
this.eventManager = eventManager;
view2ds = new ArrayList<>();
components = new ArrayList<>();
grid = new JPanel();
// For having a black background with any Look and Feel
grid.setUI(new PanelUI() {
});
grid.setBackground(Color.BLACK);
grid.setFocusCycleRoot(true);
grid.setLayout(new GridBagLayout());
add(grid, BorderLayout.CENTER);
setLayoutModel(layoutModel);
this.mouseHandler = new MouseHandler();
grid.addMouseListener(mouseHandler);
grid.addMouseMotionListener(mouseHandler);
}
/**
* Returns true if type is instance of defaultClass. This operation is delegated in each bundle to be sure all
* classes are visible.
*
* @param defaultClass
* @param type
* @return
*/
public abstract boolean isViewType(Class<?> defaultClass, String type);
public abstract int getViewTypeNumber(GridBagLayoutModel layout, Class<?> defaultClass);
public abstract ViewCanvas<E> createDefaultView(String classType);
public abstract Component createUIcomponent(String clazz);
public ViewCanvas<E> getSelectedImagePane() {
return selectedImagePane;
}
@Override
public void close() {
super.close();
GuiExecutor.instance().execute(() -> {
removeComponents();
for (ViewCanvas v : view2ds) {
resetMaximizedSelectedImagePane(v);
v.disposeView();
}
});
}
/**
* Get the layout of this panel.
*
* @return the layoutModel
*/
public GridBagLayoutModel getLayoutModel() {
return layoutModel;
}
public GridBagLayoutModel getOriginalLayoutModel() {
// Get the non clone layout from the list
ActionState layout = eventManager.getAction(ActionW.LAYOUT);
if (layout instanceof ComboItemListener) {
for (Object element : ((ComboItemListener) layout).getAllItem()) {
if (element instanceof GridBagLayoutModel) {
GridBagLayoutModel gbm = (GridBagLayoutModel) element;
if ((layoutModel.getIcon() != null && gbm.getIcon() == layoutModel.getIcon())
|| layoutModel.toString().equals(gbm.toString())) {
return gbm;
}
}
}
}
return layoutModel;
}
@Override
public void addSeries(MediaSeries<E> sequence) {
if (sequence != null && selectedImagePane != null) {
if (SynchData.Mode.TILE.equals(synchView.getSynchData().getMode())) {
selectedImagePane.setSeries(sequence, null);
updateTileOffset();
return;
}
ViewCanvas<E> viewPane = getSelectedImagePane();
if (viewPane != null) {
viewPane.setSeries(sequence);
viewPane.getJComponent().repaint();
// Set selection to the next view
setSelectedImagePane(getNextSelectedImagePane());
}
}
}
@Override
public void removeSeries(MediaSeries<E> series) {
if (series != null) {
for (int i = 0; i < view2ds.size(); i++) {
ViewCanvas<E> v = view2ds.get(i);
if (v.getSeries() == series) {
v.setSeries(null, null);
}
}
}
}
@Override
public List<MediaSeries<E>> getOpenSeries() {
List<MediaSeries<E>> list = new ArrayList<>();
for (ViewCanvas<E> v : view2ds) {
MediaSeries<E> s = v.getSeries();
if (s != null) {
list.add(s);
}
}
return list;
}
public void changeLayoutModel(GridBagLayoutModel layoutModel) {
ActionState layout = eventManager.getAction(ActionW.LAYOUT);
if (layout instanceof ComboItemListener) {
((ComboItemListener) layout).setSelectedItem(layoutModel);
}
}
protected void removeComponents() {
for (Component c : components) {
if (c instanceof SeriesViewerListener) {
eventManager.removeSeriesViewerListener((SeriesViewerListener) c);
}
}
components.clear();
}
/**
* Set a layout to this view panel. The layout is defined by the provided number corresponding the layout definition
* in the property file.
*/
protected synchronized void setLayoutModel(GridBagLayoutModel layoutModel) {
this.layoutModel = layoutModel == null ? VIEWS_1x1.copy() : layoutModel.copy();
grid.removeAll();
// Keep views containing images
ArrayList<ViewCanvas<E>> oldViews = new ArrayList<>();
for (ViewCanvas<E> v : view2ds) {
if (v.getSeries() != null && v.getImage() != null) {
oldViews.add(v);
} else {
v.disposeView();
}
}
view2ds.clear();
int nbview = getViewTypeNumber(layoutModel, view2dClass);
if (oldViews.size() > nbview) {
for (int i = oldViews.size() - 1; i >= nbview; i--) {
oldViews.remove(i).disposeView();
}
}
removeComponents();
final Map<LayoutConstraints, Component> elements = this.layoutModel.getConstraints();
Iterator<LayoutConstraints> enumVal = elements.keySet().iterator();
while (enumVal.hasNext()) {
LayoutConstraints e = enumVal.next();
boolean typeView2d = isViewType(view2dClass, e.getType());
if (typeView2d) {
ViewCanvas<E> oldView;
if (oldViews.isEmpty()) {
oldView = createDefaultView(e.getType());
oldView.registerDefaultListeners();
} else {
oldView = oldViews.remove(0);
}
view2ds.add(oldView);
elements.put(e, oldView.getJComponent());
grid.add(oldView.getJComponent(), e);
if (oldView.getSeries() != null) {
oldView.getSeries().setOpen(true);
}
} else {
Component component = createUIcomponent(e.getType());
if (component != null) {
if (component instanceof JComponent) {
((JComponent) component).setOpaque(true);
}
components.add(component);
elements.put(e, component);
grid.add(component, e);
}
}
}
grid.revalidate();
if (!view2ds.isEmpty()) {
selectedImagePane = view2ds.get(0);
MouseActions mouseActions = eventManager.getMouseActions();
boolean tiledMode = SynchData.Mode.TILE.equals(synchView.getSynchData().getMode());
for (int i = 0; i < view2ds.size(); i++) {
ViewCanvas<E> v = view2ds.get(i);
// Close lens because update does not work
v.closeLens();
if (tiledMode) {
v.setTileOffset(i);
v.setSeries(selectedImagePane.getSeries(), null);
}
v.enableMouseAndKeyListener(mouseActions);
}
selectedImagePane.setSelected(true);
eventManager.updateComponentsListener(selectedImagePane);
if (selectedImagePane.getSeries() instanceof Series) {
eventManager.fireSeriesViewerListeners(new SeriesViewerEvent(this, selectedImagePane.getSeries(),
selectedImagePane.getImage(), EVENT.LAYOUT));
}
}
}
public void replaceView(ViewCanvas<E> oldView2d, ViewCanvas<E> newView2d) {
if (oldView2d != null && newView2d != null) {
grid.removeAll();
final Map<LayoutConstraints, Component> elements = this.layoutModel.getConstraints();
Iterator<Entry<LayoutConstraints, Component>> enumVal = elements.entrySet().iterator();
while (enumVal.hasNext()) {
Entry<LayoutConstraints, Component> element = enumVal.next();
if (element.getValue() == oldView2d.getJComponent()) {
if (selectedImagePane == oldView2d) {
selectedImagePane = newView2d;
}
oldView2d.disposeView();
int index = view2ds.indexOf(oldView2d);
if (index >= 0) {
view2ds.set(index, newView2d);
}
elements.put(element.getKey(), newView2d.getJComponent());
grid.add(newView2d.getJComponent(), element.getKey());
if (newView2d.getSeries() != null) {
newView2d.getSeries().setOpen(true);
}
} else {
grid.add(element.getValue(), element.getKey());
}
}
grid.revalidate();
if (!view2ds.isEmpty()) {
if (selectedImagePane == null) {
selectedImagePane = view2ds.get(0);
}
MouseActions mouseActions = eventManager.getMouseActions();
boolean tiledMode = SynchData.Mode.TILE.equals(synchView);
for (int i = 0; i < view2ds.size(); i++) {
ViewCanvas<E> v = view2ds.get(i);
// Close lens because update does not work
v.closeLens();
if (tiledMode) {
v.setTileOffset(i);
v.setSeries(selectedImagePane.getSeries(), null);
}
v.enableMouseAndKeyListener(mouseActions);
}
selectedImagePane.setSelected(true);
eventManager.updateComponentsListener(selectedImagePane);
}
}
}
public void setSelectedImagePaneFromFocus(ViewCanvas<E> viewCanvas) {
setSelectedImagePane(viewCanvas);
}
public void setSelectedImagePane(ViewCanvas<E> viewCanvas) {
if (this.selectedImagePane != null && this.selectedImagePane.getSeries() != null) {
this.selectedImagePane.getSeries().setSelected(false, null);
this.selectedImagePane.getSeries().setFocused(false);
}
if (viewCanvas != null && viewCanvas.getSeries() != null) {
viewCanvas.getSeries().setSelected(true, viewCanvas.getImage());
viewCanvas.getSeries().setFocused(eventManager.getSelectedView2dContainer() == this);
}
boolean newView = this.selectedImagePane != viewCanvas && viewCanvas != null;
if (newView) {
if (this.selectedImagePane != null) {
this.selectedImagePane.setSelected(false);
}
viewCanvas.setSelected(true);
this.selectedImagePane = viewCanvas;
eventManager.updateComponentsListener(viewCanvas);
}
if (newView && viewCanvas.getSeries() instanceof Series) {
eventManager.fireSeriesViewerListeners(
new SeriesViewerEvent(this, selectedImagePane.getSeries(), selectedImagePane.getImage(), EVENT.SELECT));
}
eventManager.fireSeriesViewerListeners(
new SeriesViewerEvent(this, viewCanvas == null ? null : viewCanvas.getSeries(), null, EVENT.SELECT_VIEW));
}
public void resetMaximizedSelectedImagePane(final ViewCanvas<E> viewCanvas) {
if (grid.getComponentCount() == 1) {
Dialog fullscreenDialog = WinUtil.getParentDialog(grid);
if (fullscreenDialog != null
&& fullscreenDialog.getTitle().equals(Messages.getString("ImageViewerPlugin.fullscreen"))) { //$NON-NLS-1$
maximizedSelectedImagePane(viewCanvas, null);
}
}
}
public void maximizedSelectedImagePane(final ViewCanvas<E> defaultView2d, MouseEvent evt) {
final Map<LayoutConstraints, Component> elements = layoutModel.getConstraints();
// Prevent conflict with double click for stopping to draw a graphic (like polyline)
List<DragGraphic> selGraphics = defaultView2d.getGraphicManager().getSelectedDragableGraphics();
// Check if there is at least one graphic not complete (numer of pts == UNDEFINED)
if (selGraphics.stream().filter(g -> Objects.equals(g.getPtsNumber(), Graphic.UNDEFINED)).findFirst()
.isPresent()) {
return;
}
if (evt != null) {
// Do not maximize when click hits a graphic
MouseEventDouble mouseEvt = new MouseEventDouble(evt);
mouseEvt.setImageCoordinates(defaultView2d.getImageCoordinatesFromMouse(evt.getX(), evt.getY()));
if (defaultView2d.getGraphicManager().getFirstGraphicIntersecting(mouseEvt).isPresent()) {
return;
}
}
for (ViewCanvas<E> v : view2ds) {
v.getJComponent().removeFocusListener(v);
}
String titleDialog = Messages.getString("ImageViewerPlugin.fullscreen"); //$NON-NLS-1$
Dialog fullscreenDialog = WinUtil.getParentDialog(grid);
// Handle the case when the dialog is a detached window and not the fullscreen window.
final boolean detachedWindow = fullscreenDialog != null && !titleDialog.equals(fullscreenDialog.getTitle());
grid.removeAll();
if (detachedWindow || fullscreenDialog == null) {
remove(grid);
Iterator<Entry<LayoutConstraints, Component>> enumVal = elements.entrySet().iterator();
while (enumVal.hasNext()) {
Entry<LayoutConstraints, Component> entry = enumVal.next();
if (entry.getValue().equals(defaultView2d)) {
GridBagConstraints c = entry.getKey().copy();
c.weightx = 1.0;
c.weighty = 1.0;
grid.add(defaultView2d.getJComponent(), c);
defaultView2d.getJComponent().addFocusListener(defaultView2d);
break;
}
}
Dialog oldDialog = fullscreenDialog;
Frame frame = WinUtil.getParentFrame(this);
fullscreenDialog =
new JDialog(detachedWindow ? oldDialog : frame, titleDialog, ModalityType.APPLICATION_MODAL);
fullscreenDialog.add(grid, BorderLayout.CENTER);
fullscreenDialog.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
maximizedSelectedImagePane(defaultView2d, null);
}
});
if (!detachedWindow && (frame.getExtendedState() & Frame.MAXIMIZED_BOTH) == Frame.MAXIMIZED_BOTH) {
fullscreenDialog.setBounds(frame.getBounds());
fullscreenDialog.setVisible(true);
} else {
Monitor monitor = Monitor.getMonitor(
detachedWindow ? oldDialog.getGraphicsConfiguration() : frame.getGraphicsConfiguration());
if (monitor != null) {
fullscreenDialog.setBounds(monitor.getFullscreenBounds());
fullscreenDialog.setVisible(true);
}
}
} else {
Iterator<Entry<LayoutConstraints, Component>> enumVal = elements.entrySet().iterator();
while (enumVal.hasNext()) {
Entry<LayoutConstraints, Component> entry = enumVal.next();
grid.add(entry.getValue(), entry.getKey());
}
for (ViewCanvas<E> v : view2ds) {
v.getJComponent().addFocusListener(v);
}
fullscreenDialog.removeAll();
fullscreenDialog.dispose();
add(grid, BorderLayout.CENTER);
}
defaultView2d.getJComponent().requestFocusInWindow();
}
/** Return the image in the image display panel. */
public E getImage(int i) {
if (i >= 0 && i < view2ds.size()) {
return view2ds.get(i).getImage();
}
return null;
}
/** Return all the <code>ImagePanel</code>s. */
public List<ViewCanvas<E>> getImagePanels() {
return getImagePanels(false);
}
public List<ViewCanvas<E>> getImagePanels(boolean selectedImagePaneLast) {
List<ViewCanvas<E>> viewList = new ArrayList<>(view2ds);
if (selectedImagePaneLast) {
ViewCanvas<E> selectedView = getSelectedImagePane();
if (selectedView != null && viewList.size() > 1) {
viewList.remove(selectedView);
viewList.add(selectedView);
}
return viewList;
}
return viewList;
}
public ViewCanvas<E> getNextSelectedImagePane() {
for (int i = 0; i < view2ds.size() - 1; i++) {
if (view2ds.get(i) == selectedImagePane) {
return view2ds.get(i + 1);
}
}
return selectedImagePane;
}
public abstract List<SynchView> getSynchList();
public abstract List<GridBagLayoutModel> getLayoutList();
public Boolean isContainingView(ViewCanvas<?> view2DPane) {
return view2ds.stream().filter(v -> Objects.equals(v, view2DPane)).findFirst().map(v -> Boolean.TRUE)
.orElse(Boolean.FALSE);
}
public SynchView getSynchView() {
return synchView;
}
public void setSynchView(SynchView synchView) {
Objects.requireNonNull(synchView);
this.synchView = synchView;
updateTileOffset();
eventManager.updateAllListeners(this, synchView);
}
@SuppressWarnings("unchecked")
public void updateTileOffset() {
if (SynchData.Mode.TILE.equals(synchView.getSynchData().getMode()) && selectedImagePane != null) {
MediaSeries<E> series = null;
ViewCanvas<E> selectedView = selectedImagePane;
if (selectedImagePane.getSeries() != null) {
series = selectedImagePane.getSeries();
} else {
for (ViewCanvas<E> v : view2ds) {
if (v.getSeries() != null) {
series = v.getSeries();
selectedView = v;
break;
}
}
}
if (series != null) {
int limit = series.size((Filter<E>) selectedView.getActionValue(ActionW.FILTERED_SERIES.cmd()));
for (int i = 0; i < view2ds.size(); i++) {
ViewCanvas<E> v = view2ds.get(i);
if (i < limit) {
v.setTileOffset(i);
v.setSeries(series, null);
} else {
v.setSeries(null, null);
}
}
}
} else {
for (ViewCanvas<E> v : view2ds) {
v.setTileOffset(0);
}
}
}
public synchronized void setMouseActions(MouseActions mouseActions) {
if (mouseActions == null) {
for (ViewCanvas<E> v : view2ds) {
v.disableMouseAndKeyListener();
// Let the possibility to get the focus
v.iniDefaultMouseListener();
}
} else {
for (ViewCanvas<E> v : view2ds) {
v.enableMouseAndKeyListener(mouseActions);
}
}
}
public GridBagLayoutModel getBestDefaultViewLayout(int size) {
if (size <= 1) {
return VIEWS_1x1;
}
ActionState layout = eventManager.getAction(ActionW.LAYOUT);
if (layout instanceof ComboItemListener) {
Object[] list = ((ComboItemListener) layout).getAllItem();
for (Object m : list) {
if (m instanceof GridBagLayoutModel) {
if (getViewTypeNumber((GridBagLayoutModel) m, view2dClass) >= size) {
return (GridBagLayoutModel) m;
}
}
}
}
return VIEWS_4x4;
}
public GridBagLayoutModel getViewLayout(String title) {
if (title != null) {
ActionState layout = eventManager.getAction(ActionW.LAYOUT);
if (layout instanceof ComboItemListener) {
Object[] list = ((ComboItemListener) layout).getAllItem();
for (Object m : list) {
if (m instanceof GridBagLayoutModel && title.equals(((GridBagLayoutModel) m).getId())) {
return (GridBagLayoutModel) m;
}
}
}
}
return VIEWS_1x1;
}
public void addSeriesList(List<MediaSeries<E>> seriesList, boolean bestDefaultLayout) {
if (seriesList != null && !seriesList.isEmpty()) {
if (SynchData.Mode.TILE.equals(synchView.getSynchData().getMode())) {
addSeries(seriesList.get(0));
return;
}
setSelectedAndGetFocus();
if (bestDefaultLayout) {
changeLayoutModel(getBestDefaultViewLayout(seriesList.size()));
// If the layout is larger than the list of series, clean other views.
if (view2ds.size() > seriesList.size()) {
setSelectedImagePane(view2ds.get(seriesList.size()));
for (int i = seriesList.size(); i < view2ds.size(); i++) {
ViewCanvas<E> viewPane = getSelectedImagePane();
if (viewPane != null) {
viewPane.setSeries(null, null);
}
getNextSelectedImagePane();
}
}
if (!view2ds.isEmpty()) {
setSelectedImagePane(view2ds.get(0));
}
for (MediaSeries mediaSeries : seriesList) {
addSeries(mediaSeries);
}
} else {
int emptyView = 0;
for (ViewCanvas<E> v : view2ds) {
if (v.getSeries() == null) {
emptyView++;
}
}
if (emptyView < seriesList.size()) {
changeLayoutModel(getBestDefaultViewLayout(view2ds.size() + seriesList.size()));
}
int index = 0;
for (ViewCanvas<E> v : view2ds) {
if (v.getSeries() == null && index < seriesList.size()) {
setSelectedImagePane(v);
addSeries(seriesList.get(index));
index++;
}
}
}
repaint();
}
}
class MouseHandler extends MouseAdapter {
private Point pickPoint = null;
private Point point = null;
private boolean splitVertical = false;
private final ArrayList<ImageViewerPlugin.DragLayoutElement> list = new ArrayList<>();
@Override
public void mousePressed(MouseEvent e) {
pickPoint = e.getPoint();
point = null;
list.clear();
Iterator<Entry<LayoutConstraints, Component>> enumVal =
ImageViewerPlugin.this.layoutModel.getConstraints().entrySet().iterator();
Entry<LayoutConstraints, Component> entry;
while (enumVal.hasNext()) {
entry = enumVal.next();
Component c = entry.getValue();
if (c != null) {
Rectangle rect = c.getBounds();
if (Math.abs(rect.x - pickPoint.x) <= LayoutConstraints.SPACE
&& (pickPoint.y >= rect.y && pickPoint.y <= rect.y + rect.height) && entry.getKey().gridx > 0) {
splitVertical = true;
point = new Point(entry.getKey().gridx, entry.getKey().gridy);
break;
}
else if (Math.abs(rect.y - pickPoint.y) <= LayoutConstraints.SPACE
&& (pickPoint.x >= rect.x && pickPoint.x <= rect.x + rect.width) && entry.getKey().gridy > 0) {
splitVertical = false;
point = new Point(entry.getKey().gridx, entry.getKey().gridy);
break;
}
}
}
if (point != null) {
enumVal = ImageViewerPlugin.this.layoutModel.getConstraints().entrySet().iterator();
while (enumVal.hasNext()) {
entry = enumVal.next();
Component c = entry.getValue();
if (c != null) {
list.add(new DragLayoutElement(entry.getKey(), c));
}
}
Rectangle b = grid.getBounds();
double totalWidth = b.getWidth();
double totalHeight = b.getHeight();
for (DragLayoutElement el : list) {
el.originalConstraints.weightx = el.originalBound.width / totalWidth;
el.originalConstraints.weighty = el.originalBound.height / totalHeight;
el.constraints.weightx = el.originalConstraints.weightx;
el.constraints.weighty = el.originalConstraints.weighty;
}
}
}
@Override
public void mouseReleased(MouseEvent mouseevent) {
pickPoint = null;
point = null;
list.clear();
}
@Override
public void mouseDragged(MouseEvent e) {
int mods = e.getModifiers();
if (pickPoint != null && point != null && list.size() > 1 && (mods & InputEvent.BUTTON1_MASK) != 0) {
Point p = e.getPoint();
if (splitVertical) {
int dx = p.x - pickPoint.x;
int limitdx = dx;
for (DragLayoutElement element : list) {
LayoutConstraints key = element.getConstraints();
if (key.gridx == point.x) {
int width = element.getOriginalBound().width - dx;
Dimension min = element.getComponent().getMinimumSize();
int minsize = min == null ? 50 : min.width;
if (width < minsize) {
limitdx = dx - (minsize - width);
}
} else if (key.gridx + key.gridwidth == point.x) {
int width = element.getOriginalBound().width + dx;
Dimension min = element.getComponent().getMinimumSize();
int minsize = min == null ? 50 : min.width;
if (width < minsize) {
limitdx = dx + (minsize - width);
}
}
}
for (DragLayoutElement element : list) {
LayoutConstraints key = element.getConstraints();
LayoutConstraints originkey = element.getOriginalConstraints();
if (key.gridx == point.x) {
key.weightx =
originkey.weightx - limitdx * originkey.weightx / element.getOriginalBound().width;
} else if (key.gridx + key.gridwidth == point.x) {
key.weightx =
originkey.weightx + limitdx * originkey.weightx / element.getOriginalBound().width;
}
}
} else {
int dy = p.y - pickPoint.y;
int limitdy = dy;
for (DragLayoutElement element : list) {
LayoutConstraints key = element.getConstraints();
if (key.gridy == point.y) {
int height = element.getOriginalBound().height - dy;
Dimension min = element.getComponent().getMinimumSize();
int minsize = min == null ? 50 : min.height;
if (height < minsize) {
limitdy = dy - (minsize - height);
}
} else if (key.gridy + key.gridheight == point.y) {
int height = element.getOriginalBound().height + dy;
Dimension min = element.getComponent().getMinimumSize();
int minsize = min == null ? 50 : min.height;
if (height < minsize) {
limitdy = dy + (minsize - height);
}
}
}
for (DragLayoutElement element : list) {
LayoutConstraints key = element.getConstraints();
LayoutConstraints originkey = element.getOriginalConstraints();
if (key.gridy == point.y) {
key.weighty =
originkey.weighty - limitdy * originkey.weighty / element.getOriginalBound().height;
} else if (key.gridy + key.gridheight == point.y) {
key.weighty =
originkey.weighty + limitdy * originkey.weighty / element.getOriginalBound().height;
}
}
}
Rectangle b = grid.getBounds();
double totalWidth = b.getWidth();
double totalHeight = b.getHeight();
grid.removeAll();
for (DragLayoutElement element : list) {
Component c = element.getComponent();
LayoutConstraints l = element.getConstraints();
c.setPreferredSize(new Dimension((int) Math.round(totalWidth * l.weightx),
(int) Math.round(totalHeight * l.weighty)));
grid.add(c, l);
}
setCursor(Cursor.getPredefinedCursor(splitVertical ? Cursor.E_RESIZE_CURSOR : Cursor.S_RESIZE_CURSOR));
grid.revalidate();
grid.repaint();
}
}
@Override
public void mouseMoved(MouseEvent me) {
setCursor(Cursor.getPredefinedCursor(getCursor(me)));
}
@Override
public void mouseExited(MouseEvent mouseEvent) {
setCursor(Cursor.getDefaultCursor());
}
private int getCursor(MouseEvent me) {
Point p = me.getPoint();
Iterator<Entry<LayoutConstraints, Component>> enumVal =
ImageViewerPlugin.this.layoutModel.getConstraints().entrySet().iterator();
while (enumVal.hasNext()) {
Entry<LayoutConstraints, Component> entry = enumVal.next();
Component c = entry.getValue();
if (c != null) {
Rectangle rect = c.getBounds();
if ((Math.abs(rect.x - p.x) <= LayoutConstraints.SPACE
|| Math.abs(rect.x + rect.width - p.x) <= LayoutConstraints.SPACE)
&& (p.y >= rect.y && p.y <= rect.y + rect.height)) {
return Cursor.E_RESIZE_CURSOR;
} else if ((Math.abs(rect.y - p.y) <= LayoutConstraints.SPACE
|| Math.abs(rect.y + rect.height - p.y) <= LayoutConstraints.SPACE)
&& (p.x >= rect.x && p.x <= rect.x + rect.width)) {
return Cursor.S_RESIZE_CURSOR;
}
}
}
return Cursor.DEFAULT_CURSOR;
}
}
static class DragLayoutElement {
private final LayoutConstraints originalConstraints;
private final Rectangle originalBound;
private final LayoutConstraints constraints;
private final Component component;
public DragLayoutElement(LayoutConstraints constraints, Component component) {
if (constraints == null || component == null) {
throw new IllegalArgumentException("Arguments cannot be null"); //$NON-NLS-1$
}
this.constraints = constraints;
this.originalConstraints = constraints.copy();
this.component = component;
this.originalBound = component.getBounds();
}
public LayoutConstraints getOriginalConstraints() {
return originalConstraints;
}
public Rectangle getOriginalBound() {
return originalBound;
}
public LayoutConstraints getConstraints() {
return constraints;
}
public Component getComponent() {
return component;
}
}
public void selectLayoutPositionForAddingSeries(List<MediaSeries<E>> seriesList) {
int nbSeriesToAdd = 1;
if (seriesList != null) {
nbSeriesToAdd = seriesList.size();
if (nbSeriesToAdd < 1) {
nbSeriesToAdd = 1;
}
}
int pos = view2ds.size() - nbSeriesToAdd;
if (pos < 0) {
pos = 0;
}
setSelectedImagePane(view2ds.get(pos));
}
}