/*******************************************************************************
* 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.core.ui.editor.image.dockable;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JColorChooser;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSpinner;
import javax.swing.JTable;
import javax.swing.JToggleButton;
import javax.swing.JViewport;
import javax.swing.SwingUtilities;
import javax.swing.border.TitledBorder;
import javax.swing.table.TableModel;
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.JMVUtils;
import org.weasis.core.api.gui.util.JToogleButtonGroup;
import org.weasis.core.api.gui.util.TableHeaderRenderer;
import org.weasis.core.api.gui.util.ToggleButtonListener;
import org.weasis.core.api.image.util.MeasurableLayer;
import org.weasis.core.api.image.util.Unit;
import org.weasis.core.api.media.data.ImageElement;
import org.weasis.core.api.util.FontTools;
import org.weasis.core.api.util.StringUtil;
import org.weasis.core.ui.Messages;
import org.weasis.core.ui.docking.PluginTool;
import org.weasis.core.ui.docking.UIManager;
import org.weasis.core.ui.editor.image.ImageViewerEventManager;
import org.weasis.core.ui.editor.image.ImageViewerPlugin;
import org.weasis.core.ui.editor.image.MeasureToolBar;
import org.weasis.core.ui.editor.image.MouseActions;
import org.weasis.core.ui.editor.image.ViewCanvas;
import org.weasis.core.ui.editor.image.ViewerPlugin;
import org.weasis.core.ui.editor.image.ViewerToolBar;
import org.weasis.core.ui.model.graphic.DragGraphic;
import org.weasis.core.ui.model.graphic.Graphic;
import org.weasis.core.ui.model.graphic.GraphicSelectionListener;
import org.weasis.core.ui.model.layer.LayerType;
import org.weasis.core.ui.model.utils.ImageStatistics;
import org.weasis.core.ui.model.utils.bean.MeasureItem;
import org.weasis.core.ui.model.utils.bean.Measurement;
import org.weasis.core.ui.pref.PreferenceDialog;
import org.weasis.core.ui.pref.ViewSetting;
import org.weasis.core.ui.util.ColorLayerUI;
import org.weasis.core.ui.util.SimpleTableModel;
import org.weasis.core.ui.util.TableColumnAdjuster;
import org.weasis.core.ui.util.TableNumberRenderer;
import bibliothek.gui.dock.common.CLocation;
public class MeasureTool extends PluginTool implements GraphicSelectionListener {
private static final long serialVersionUID = 1117961156637401550L;
public static final String BUTTON_NAME = ActionW.DRAW + " & " + ActionW.MEASURE; //$NON-NLS-1$
public static final String LABEL_PREF_NAME = Messages.getString("MeasureTool.lab_img"); //$NON-NLS-1$
public static final ViewSetting viewSetting = new ViewSetting();
protected final ImageViewerEventManager<? extends ImageElement> eventManager;
private final JScrollPane rootPane;
private JPanel tableContainer;
private JTable jtable;
private List<DragGraphic> selectedGraphic;
public MeasureTool(ImageViewerEventManager<? extends ImageElement> eventManager) {
super(BUTTON_NAME, BUTTON_NAME, PluginTool.Type.TOOL, 30);
this.eventManager = eventManager;
this.rootPane = new JScrollPane();
dockable.setTitleIcon(new ImageIcon(MeasureTool.class.getResource("/icon/16x16/measure.png"))); //$NON-NLS-1$
setDockableWidth(javax.swing.UIManager.getLookAndFeel() != null
? javax.swing.UIManager.getLookAndFeel().getClass().getName().startsWith("org.pushingpixels") ? 190 : 205 //$NON-NLS-1$
: 205);
jbInit();
}
private final void jbInit() {
setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
add(getIconsPanel());
add(getSelectedMeasurePanel());
}
public final JPanel getIconsPanel() {
final JPanel transform = new JPanel();
transform.setAlignmentX(Component.LEFT_ALIGNMENT);
transform.setAlignmentY(Component.TOP_ALIGNMENT);
transform.setLayout(new BoxLayout(transform, BoxLayout.Y_AXIS));
MeasureTool.buildIconPanel(transform, eventManager, ActionW.MEASURE, ActionW.DRAW_MEASURE, 4);
MeasureTool.buildIconPanel(transform, eventManager, ActionW.DRAW, ActionW.DRAW_GRAPHICS, 4);
transform.add(Box.createVerticalStrut(5));
JPanel panel = new JPanel(new FlowLayout(FlowLayout.LEFT, 3, 0));
transform.add(panel);
JLabel label = new JLabel(Messages.getString("MeasureToolBar.line") + StringUtil.COLON); //$NON-NLS-1$
panel.add(label);
JButton button = new JButton(Messages.getString("MeasureTool.pick")); //$NON-NLS-1$
button.setBackground(viewSetting.getLineColor());
button.addActionListener(e -> {
JButton btn = (JButton) e.getSource();
Color newColor = JColorChooser.showDialog(SwingUtilities.getWindowAncestor(MeasureTool.this),
Messages.getString("MeasureTool.pick_color"), //$NON-NLS-1$
btn.getBackground());
if (newColor != null) {
btn.setBackground(newColor);
viewSetting.setLineColor(newColor);
updateMeasureProperties(viewSetting);
}
});
panel.add(button);
JSpinner spinner = new JSpinner();
JMVUtils.setNumberModel(spinner, viewSetting.getLineWidth(), 1, 8, 1);
spinner.addChangeListener(e -> {
Object val = ((JSpinner) e.getSource()).getValue();
if (val instanceof Integer) {
viewSetting.setLineWidth((Integer) val);
updateMeasureProperties(viewSetting);
}
});
panel.add(spinner);
ActionState drawOnceAction = eventManager.getAction(ActionW.DRAW_ONLY_ONCE);
if (drawOnceAction instanceof ToggleButtonListener) {
transform.add(Box.createVerticalStrut(5));
JPanel panel1 = new JPanel(new FlowLayout(FlowLayout.LEFT, 0, 0));
transform.add(panel1);
JCheckBox checkDraw =
((ToggleButtonListener) drawOnceAction).createCheckBox(ActionW.DRAW_ONLY_ONCE.getTitle());
checkDraw.setSelected(viewSetting.isDrawOnlyOnce());
checkDraw.setAlignmentX(Component.LEFT_ALIGNMENT);
panel1.add(checkDraw);
}
JPanel panel1 = new JPanel(new FlowLayout(FlowLayout.LEFT, 0, 0));
transform.add(panel1);
JCheckBox chckbxBasicImageStatistics =
new JCheckBox(Messages.getString("MeasureTool.pix_stats"), viewSetting.isBasicStatistics()); //$NON-NLS-1$
chckbxBasicImageStatistics.setAlignmentX(Component.LEFT_ALIGNMENT);
panel1.add(chckbxBasicImageStatistics);
chckbxBasicImageStatistics.addActionListener(e -> {
JCheckBox box = (JCheckBox) e.getSource();
boolean sel = box.isSelected();
viewSetting.setBasicStatistics(sel);
// Force also advanced statistics
viewSetting.setMoreStatistics(sel);
for (Measurement m : ImageStatistics.ALL_MEASUREMENTS) {
m.setComputed(sel);
}
synchronized (UIManager.VIEWER_PLUGINS) {
for (int i = UIManager.VIEWER_PLUGINS.size() - 1; i >= 0; i--) {
ViewerPlugin<?> p = UIManager.VIEWER_PLUGINS.get(i);
if (p instanceof ImageViewerPlugin) {
for (Object v : ((ImageViewerPlugin<?>) p).getImagePanels()) {
if (v instanceof ViewCanvas) {
ViewCanvas<?> view = (ViewCanvas<?>) v;
view.getGraphicManager().updateLabels(true, view);
}
}
}
}
}
});
panel1.add(chckbxBasicImageStatistics);
ActionState spUnitAction = eventManager.getAction(ActionW.SPATIAL_UNIT);
if (spUnitAction instanceof ComboItemListener) {
final JPanel panel4 = new JPanel(new FlowLayout(FlowLayout.LEADING, 2, 3));
final JLabel lutLabel = new JLabel();
lutLabel.setText(Messages.getString("MeasureTool.unit") + StringUtil.COLON); //$NON-NLS-1$
panel4.add(lutLabel);
final JComboBox unitComboBox = ((ComboItemListener) spUnitAction).createCombo(120);
unitComboBox.setSelectedItem(Unit.PIXEL);
panel4.add(unitComboBox);
transform.add(panel4);
}
transform.add(Box.createVerticalStrut(5));
JPanel panel2 = new JPanel(new FlowLayout(FlowLayout.LEFT, 0, 0));
transform.add(panel2);
final JButton btnGerenralOptions = new JButton(Messages.getString("MeasureTool.more_options")); //$NON-NLS-1$
btnGerenralOptions.setAlignmentX(Component.LEFT_ALIGNMENT);
panel2.add(btnGerenralOptions);
btnGerenralOptions.addActionListener(e -> {
ColorLayerUI layer = ColorLayerUI.createTransparentLayerUI(MeasureTool.this);
PreferenceDialog dialog = new PreferenceDialog(SwingUtilities.getWindowAncestor(MeasureTool.this));
dialog.showPage(LABEL_PREF_NAME);
ColorLayerUI.showCenterScreen(dialog, layer);
});
transform.add(panel2);
transform.add(Box.createVerticalStrut(5));
return transform;
}
private static void updateMeasureProperties(final ViewSetting setting) {
if (setting != null) {
MeasureToolBar.measureGraphicList.forEach(g -> MeasureToolBar.applyDefaultSetting(setting, g));
MeasureToolBar.drawGraphicList.forEach(g -> MeasureToolBar.applyDefaultSetting(setting, g));
}
}
public JPanel getSelectedMeasurePanel() {
final JPanel transform = new JPanel();
transform.setAlignmentY(Component.TOP_ALIGNMENT);
transform.setAlignmentX(Component.LEFT_ALIGNMENT);
transform.setLayout(new BoxLayout(transform, BoxLayout.Y_AXIS));
transform.setBorder(BorderFactory.createCompoundBorder(BorderFactory.createEmptyBorder(10, 3, 0, 3),
new TitledBorder(null, Messages.getString("MeasureTool.sel"), //$NON-NLS-1$
TitledBorder.DEFAULT_JUSTIFICATION, TitledBorder.DEFAULT_POSITION, FontTools.getFont12Bold(),
Color.GRAY)));
JPanel panel1 = new JPanel(new FlowLayout(FlowLayout.LEFT, 0, 0));
transform.add(panel1);
transform.add(Box.createVerticalStrut(5));
jtable = createMultipleRenderingTable(new SimpleTableModel(new String[] {}, new Object[][] {}));
jtable.setFont(FontTools.getFont10());
jtable.getTableHeader().setReorderingAllowed(false);
tableContainer = new JPanel();
tableContainer.setBorder(BorderFactory.createEtchedBorder());
tableContainer.setPreferredSize(new Dimension(50, 80));
tableContainer.setLayout(new BorderLayout());
transform.add(tableContainer);
return transform;
}
@Override
public Component getToolComponent() {
JViewport viewPort = rootPane.getViewport();
if (viewPort == null) {
viewPort = new JViewport();
rootPane.setViewport(viewPort);
}
if (viewPort.getView() != this) {
viewPort.setView(this);
}
return rootPane;
}
@Override
protected void changeToolWindowAnchor(CLocation clocation) {
// Do nothing
}
public static JTable createMultipleRenderingTable(TableModel model) {
JTable table = new JTable(model);
table.getColumnModel().setColumnMargin(3);
return table;
}
public static void createTableHeaders(JTable table) {
table.getColumnModel().getColumn(0).setHeaderRenderer(new TableHeaderRenderer());
table.getColumnModel().getColumn(1).setHeaderRenderer(new TableHeaderRenderer());
}
public void setSelectedGraphic(Graphic graph, MeasurableLayer layer) {
List<MeasureItem> measList = null;
if (graph != null && layer != null && graph.getLayerType() == LayerType.MEASURE) {
Unit unit = null;
ActionState spUnitAction = eventManager.getAction(ActionW.SPATIAL_UNIT);
if (spUnitAction instanceof ComboItemListener) {
unit = (Unit) ((ComboItemListener) spUnitAction).getSelectedItem();
}
measList = graph.computeMeasurements(layer, true, unit);
}
updateMeasuredItems(measList);
}
@Override
public void updateMeasuredItems(List<MeasureItem> measList) {
tableContainer.removeAll();
// just clear tableContainer if measList is null
if (measList != null) {
Object[][] labels = new Object[measList.size()][];
for (int i = 0; i < labels.length; i++) {
MeasureItem m = measList.get(i);
Object[] row = new Object[2];
StringBuilder buffer = new StringBuilder(m.getMeasurement().getName());
if (m.getLabelExtension() != null) {
buffer.append(m.getLabelExtension());
}
if (m.getUnit() != null) {
buffer.append(" ["); //$NON-NLS-1$
buffer.append(m.getUnit());
buffer.append("]"); //$NON-NLS-1$
}
row[0] = buffer.toString();
row[1] = m.getValue();
labels[i] = row;
}
String[] headers = { Messages.getString("MeasureTool.param"), Messages.getString("MeasureTool.val") }; //$NON-NLS-1$ //$NON-NLS-2$
jtable.setModel(new SimpleTableModel(headers, labels));
jtable.getColumnModel().getColumn(1).setCellRenderer(new TableNumberRenderer());
createTableHeaders(jtable);
int height = (jtable.getRowHeight() + jtable.getRowMargin()) * jtable.getRowCount()
+ jtable.getTableHeader().getHeight() + 5;
tableContainer.setPreferredSize(new Dimension(jtable.getColumnModel().getTotalColumnWidth(), height));
tableContainer.add(jtable.getTableHeader(), BorderLayout.PAGE_START);
tableContainer.add(jtable, BorderLayout.CENTER);
TableColumnAdjuster.pack(jtable);
} else {
tableContainer.setPreferredSize(new Dimension(50, 50));
}
tableContainer.revalidate();
tableContainer.repaint();
}
public static int getNumberOfMeasures(boolean[] select) {
int k = 0;
for (int i = 0; i < select.length; i++) {
if (select[i]) {
k++;
}
}
return k;
}
@Override
public void handle(List<Graphic> selectedGraphicList, MeasurableLayer layer) {
Graphic g = null;
List<DragGraphic> list = null;
if (selectedGraphicList != null) {
if (selectedGraphicList.size() == 1) {
g = selectedGraphicList.get(0);
}
list = new ArrayList<>();
for (Graphic graphic : selectedGraphicList) {
if (graphic instanceof DragGraphic) {
list.add((DragGraphic) graphic);
}
}
}
boolean computeAllMeasures = true;
if (selectedGraphic != null) {
if (g != null && selectedGraphic.size() == 1) {
// Warning only comparing if it is the same instance, cannot compare handle points.
// Update of the list of measures is performed in the drag sequence (move, complete). Here only the
// change of selection will compute the measurements
if (g == selectedGraphic.get(0)) {
computeAllMeasures = false;
}
}
selectedGraphic.clear();
}
this.selectedGraphic = list;
if (computeAllMeasures) {
// if g equals null means graphic is not single or no graphic is selected
setSelectedGraphic(g, layer);
}
}
public static void buildIconPanel(JPanel rootPanel, ImageViewerEventManager<?> eventManager, ActionW action,
ActionW graphicAction, int lineLength) {
Optional<ComboItemListener> actionState = eventManager.getAction(graphicAction, ComboItemListener.class);
if (!actionState.isPresent()) {
return;
}
final JPanel pIcons = new JPanel();
pIcons.setBorder(BorderFactory.createCompoundBorder(BorderFactory.createEmptyBorder(10, 3, 0, 3),
new TitledBorder(null, graphicAction.getTitle(), TitledBorder.DEFAULT_JUSTIFICATION,
TitledBorder.DEFAULT_POSITION, FontTools.getFont12Bold(), Color.GRAY)));
JToogleButtonGroup measures = actionState.get().createButtonGroup();
JToggleButton[] items = measures.getJToggleButtonList();
pIcons.setLayout(new GridBagLayout());
for (int i = 0; i < items.length; i++) {
items[i].addActionListener(e -> {
ImageViewerPlugin<? extends ImageElement> view = eventManager.getSelectedView2dContainer();
if (view != null) {
final ViewerToolBar toolBar = view.getViewerToolBar();
if (toolBar != null) {
String cmd = action.cmd();
if (!toolBar.isCommandActive(cmd)) {
MouseActions mouseActions = eventManager.getMouseActions();
mouseActions.setAction(MouseActions.LEFT, cmd);
view.setMouseActions(mouseActions);
toolBar.changeButtonState(MouseActions.LEFT, cmd);
}
}
}
});
GridBagConstraints constraints = new GridBagConstraints();
constraints.insets = new Insets(0, 0, 5, 5);
constraints.gridx = i % lineLength;
constraints.gridy = i / lineLength;
Dimension size = items[i].getPreferredSize();
if (size != null && size.width > size.height) {
items[i].setPreferredSize(new Dimension(size.height + 2, size.height));
}
pIcons.add(items[i], constraints);
}
JPanel panelLeft = new JPanel(new FlowLayout(FlowLayout.LEFT, 0, 0));
panelLeft.add(pIcons);
rootPanel.add(panelLeft);
}
}