/* * ------------------------------------------------------------------------ * * Copyright (C) 2003 - 2013 * University of Konstanz, Germany and * KNIME GmbH, Konstanz, Germany * Website: http://www.knime.org; Email: contact@knime.org * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License, Version 3, as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see <http://www.gnu.org/licenses>. * * Additional permission under GNU GPL version 3 section 7: * * KNIME interoperates with ECLIPSE solely via ECLIPSE's plug-in APIs. * Hence, KNIME and ECLIPSE are both independent programs and are not * derived from each other. Should, however, the interpretation of the * GNU GPL Version 3 ("License") under any applicable laws result in * KNIME and ECLIPSE being a combined program, KNIME GMBH herewith grants * you the additional permission to use and propagate KNIME together with * ECLIPSE with only the license terms in place for ECLIPSE applying to * ECLIPSE and the GNU GPL Version 3 applying for KNIME, provided the * license terms of ECLIPSE themselves allow for the respective use and * propagation of ECLIPSE together with KNIME. * * Additional permission relating to nodes for KNIME that extend the Node * Extension (and in particular that are based on subclasses of NodeModel, * NodeDialog, and NodeView) and that only interoperate with KNIME through * standard APIs ("Nodes"): * Nodes are deemed to be separate and independent programs and to not be * covered works. Notwithstanding anything to the contrary in the * License, the License does not apply to Nodes, you are not required to * license Nodes under the License, and you are granted a license to * prepare and propagate Nodes, in each case even if such Nodes are * propagated with or for interoperation with KNIME. The owner of a Node * may freely choose the license terms applicable to such Node, including * when such Node is propagated with or for interoperation with KNIME. * --------------------------------------------------------------------- * * */ package org.knime.knip.base.nodes.view.imgparadjust; import java.awt.BorderLayout; import java.awt.Dimension; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.Map; import java.util.Map.Entry; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.ThreadFactory; import java.util.concurrent.atomic.AtomicInteger; import javax.swing.BoxLayout; import javax.swing.JButton; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.ListSelectionModel; import javax.swing.SwingConstants; import javax.swing.border.BevelBorder; import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionListener; import org.knime.core.node.NodeView; import org.knime.core.node.tableview.TableContentModel; import org.knime.core.node.tableview.TableContentView; import org.knime.core.node.tableview.TableView; import org.knime.core.node.workflow.FlowVariable; import org.knime.knip.base.data.img.ImgPlusValue; import org.knime.knip.base.nodes.view.PlainCellView; import org.knime.knip.core.ui.event.EventListener; import org.knime.knip.core.ui.event.EventService; import org.knime.knip.core.ui.imgviewer.ExpandingPanel; import org.knime.knip.core.ui.imgviewer.ImgCanvas; import org.knime.knip.core.ui.imgviewer.ImgViewer; import org.knime.knip.core.ui.imgviewer.events.TablePositionEvent; import org.knime.knip.core.ui.imgviewer.panels.ImgNormalizationPanel; import org.knime.knip.core.ui.imgviewer.panels.MinimapAndPlaneSelectionPanel; import org.knime.knip.core.ui.imgviewer.panels.ViewerControlEvent; import org.knime.knip.core.ui.imgviewer.panels.ViewerScrollEvent; import org.knime.knip.core.ui.imgviewer.panels.ViewerScrollEvent.Direction; import org.knime.knip.core.ui.imgviewer.panels.infobars.ImgViewInfoPanel; import org.knime.knip.core.ui.imgviewer.panels.providers.AWTImageProvider; import org.knime.knip.core.ui.imgviewer.panels.providers.ThresholdRU; import net.imagej.ImgPlus; import net.imglib2.img.Img; import net.imglib2.type.numeric.RealType; /** * * @author <a href="mailto:dietzc85@googlemail.com">Christian Dietz</a> * @author <a href="mailto:horn_martin@gmx.de">Martin Horn</a> * @author <a href="mailto:michael.zinsmaier@googlemail.com">Michael Zinsmaier</a> */ public class ImgParAdjustNodeView<T extends RealType<T>> extends NodeView<ImgParAdjustNodeModel> { private static final ExecutorService UPDATE_EXECUTOR = Executors.newCachedThreadPool(new ThreadFactory() { private final AtomicInteger m_counter = new AtomicInteger(); @Override public Thread newThread(final Runnable r) { final Thread t = new Thread(r, "ImgParAdjusterView-Updater-" + m_counter.incrementAndGet()); t.setDaemon(true); return t; } }); /* the img viewer panel */ private ImgViewer m_imgViewer; private ParameterPanel m_parameterPanel; private TableContentView m_tableContentView; private PlainCellView m_cellView; private TableView m_tableView; private int m_col; private int m_row; private EventService m_eventService; private JPanel m_content; private JLabel m_statusLabel; private JPanel m_tableViewPanel; protected static final String m_defStatusBarText = "Click on a cell or drag and select multiple cells to continue ..."; /** * @param nodeModel */ protected ImgParAdjustNodeView(final ImgParAdjustNodeModel nodeModel) { super(nodeModel); // allows the node view to display something during/before the // actual // node execution setShowNODATALabel(false); } private void initViewComponents() { m_tableContentView = new TableContentView(new TableContentModel(getNodeModel().getImageTable())); m_tableContentView.getSelectionModel().setSelectionMode(ListSelectionModel.SINGLE_SELECTION); m_tableContentView.getSelectionModel().addListSelectionListener(new ListSelectionListener() { @Override public void valueChanged(final ListSelectionEvent e) { if (e.getValueIsAdjusting()) { return; } onCellSelectionChanged(); } }); m_tableContentView.getColumnModel().getSelectionModel().addListSelectionListener(new ListSelectionListener() { @Override public void valueChanged(final ListSelectionEvent e) { if (e.getValueIsAdjusting()) { return; } onCellSelectionChanged(); } }); m_eventService = new EventService(); m_eventService.subscribe(this); m_tableView = new TableView(m_tableContentView); // scale to thumbnail size, if desired final int TABLE_CELL_SIZE = 100; m_tableView.setColumnWidth(TABLE_CELL_SIZE); m_tableView.setRowHeight(TABLE_CELL_SIZE); // contructing the image viewer final int CACHE_SIZE = 50; m_imgViewer = new ImgViewer(); final AWTImageProvider realProvider = new AWTImageProvider(CACHE_SIZE, new ThresholdRU<T>()); realProvider.setEventService(m_imgViewer.getEventService()); m_imgViewer.addViewerComponent(realProvider); m_imgViewer.addViewerComponent(new ImgViewInfoPanel<T>()); m_imgViewer.addViewerComponent(new ImgCanvas<T, Img<T>>()); m_imgViewer.addViewerComponent(new MinimapAndPlaneSelectionPanel()); m_imgViewer.addViewerComponent(new ExpandingPanel("Normalization", new ImgNormalizationPanel<T, Img<T>>())); m_imgViewer.addViewerComponent(new ExpandingPanel("Threshold", new SetThresholdPanel<T, Img<T>>())); m_parameterPanel = new ParameterPanel(); m_imgViewer.addViewerComponent(new ExpandingPanel("Parameters", m_parameterPanel)); m_imgViewer.doneAdding(); m_cellView = new PlainCellView(m_tableView, m_imgViewer); m_content = new JPanel(new BorderLayout()); m_tableViewPanel = new JPanel(new BorderLayout()); m_tableViewPanel.add(m_tableView, BorderLayout.CENTER); JPanel statusBar = new JPanel(); statusBar.setBorder(new BevelBorder(BevelBorder.LOWERED)); m_tableViewPanel.add(statusBar, BorderLayout.SOUTH); statusBar.setPreferredSize(new Dimension(m_tableViewPanel.getWidth(), 16)); statusBar.setLayout(new BoxLayout(statusBar, BoxLayout.X_AXIS)); m_statusLabel = new JLabel(m_defStatusBarText); m_statusLabel.setHorizontalAlignment(SwingConstants.LEFT); statusBar.add(m_statusLabel); m_content.add(m_cellView, BorderLayout.CENTER); final JButton continueButton = new JButton("Set parameters and continue execution ..."); continueButton.addActionListener(new ActionListener() { @Override public void actionPerformed(final ActionEvent e) { onContinueExecution(); } }); m_parameterPanel.add(continueButton, BorderLayout.SOUTH); setComponent(m_tableViewPanel); // let this class listening to the imgViewer events (registers // the // onNormalization... method the the event service of the // imgviewer) m_cellView.setEventService(m_eventService); } private void loadPortContent() { UPDATE_EXECUTOR.execute(new Runnable() { private TableContentModel m_tableModel; @Override public void run() { m_tableModel = new TableContentModel(); m_tableModel.setDataTable(getNodeModel().getImageTable()); initViewComponents(); } }); } /** * {@inheritDoc} */ @Override protected void modelChanged() { if (getNodeModel().getImageTable() == null) { setNonExecutingView(); return; } else { loadPortContent(); } } private boolean cellExists(final int row, final int col) { return (col >= 0 && col < m_tableContentView.getColumnCount() && row >= 0 && row < m_tableContentView.getRowCount()); } /** * @param row * @param col */ protected void onCellSelectionChanged() { final int row = m_tableContentView.getSelectionModel().getLeadSelectionIndex(); final int col = m_tableContentView.getColumnModel().getSelectionModel().getLeadSelectionIndex(); onCellSelectionChanged(col, row); } protected void onCellSelectionChanged(final int col, final int row) { if (!cellExists(row, col)) { return; } m_col = col; m_row = row; if (m_tableContentView.getContentModel().getValueAt(row, col) instanceof ImgPlusValue) { final ImgPlus<T> imgPlus = ((ImgPlusValue<T>)m_tableContentView.getContentModel().getValueAt(row, col)).getImgPlus(); m_imgViewer.setImg(imgPlus); if (getComponent() != m_content) { setComponent(m_content); } m_eventService.publish(new TablePositionEvent(m_tableContentView.getColumnCount(), m_tableContentView.getRowCount(), col + 1, row + 1, m_tableContentView.getColumnName(col), m_tableContentView.getContentModel().getRowKey(row).toString())); } } /** * {@inheritDoc} */ @Override protected void onClose() { // nothing to do } public void onContinueExecution() { getNodeModel().pushFlowVariable("saturation", m_parameterPanel.getSaturation()); getNodeModel().pushFlowVariable("posX", m_parameterPanel.getMouseCoordX()); getNodeModel().pushFlowVariable("posY", m_parameterPanel.getMouseCoordY()); getNodeModel().pushFlowVariable("zoomFactor", m_parameterPanel.getZoomFact()); getNodeModel().pushFlowVariable("thresholdValue", m_parameterPanel.getThresholdVal()); Map<String, Long> planeSel = m_parameterPanel.getPlaneSelection(); for (Entry<String, Long> e : planeSel.entrySet()) { getNodeModel().pushFlowVariable("pos" + e.getKey(), e.getValue().intValue()); } setNonExecutingView(); m_imgViewer = null; } /** * {@inheritDoc} */ @Override protected void onOpen() { } private void setNonExecutingView() { final JPanel p = new JPanel(); p.setLayout(new BoxLayout(p, BoxLayout.Y_AXIS)); p.add(new JLabel("Availables variables are:")); final Map<String, FlowVariable> variables = getNodeModel().getAvailableFlowVariables(); for (final FlowVariable entry : variables.values()) { p.add(new JLabel(entry.toString())); } setComponent(p); } @EventListener public void onViewerScrollEvent(final ViewerScrollEvent e) { if (e.getDirection() == Direction.NORTH) { onCellSelectionChanged(m_row - 1, m_col); } if (e.getDirection() == Direction.EAST) { onCellSelectionChanged(m_row, m_col + 1); } if (e.getDirection() == Direction.WEST) { onCellSelectionChanged(m_row, m_col - 1); } if (e.getDirection() == Direction.SOUTH) { onCellSelectionChanged(m_row + 1, m_col); } } @EventListener public void onOverviewToggle(final ViewerControlEvent e) { if (getComponent() == m_content) { if (m_cellView.isTableViewVisible()) { m_cellView.hideTableView(); } m_tableContentView.clearSelection(); setComponent(m_tableViewPanel); } } }