/*
* ------------------------------------------------------------------------
*
* 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.segmentoverlay;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.util.HashSet;
import java.util.Set;
import net.imglib2.RandomAccess;
import net.imglib2.roi.labeling.LabelingType;
import net.imglib2.type.numeric.RealType;
import org.knime.core.data.RowKey;
import org.knime.core.node.property.hilite.DefaultHiLiteHandler;
import org.knime.core.node.property.hilite.HiLiteHandler;
import org.knime.core.node.property.hilite.HiLiteListener;
import org.knime.core.node.property.hilite.KeyEvent;
import org.knime.knip.core.ui.event.EventListener;
import org.knime.knip.core.ui.event.EventService;
import org.knime.knip.core.ui.imgviewer.events.HilitedLabelsChgEvent;
import org.knime.knip.core.ui.imgviewer.events.ImgAndLabelingChgEvent;
import org.knime.knip.core.ui.imgviewer.events.ImgRedrawEvent;
import org.knime.knip.core.ui.imgviewer.events.ImgViewerMousePressedEvent;
import org.knime.knip.core.ui.imgviewer.events.LabelPanelHiliteSelectionChgEvent;
import org.knime.knip.core.ui.imgviewer.events.PlaneSelectionEvent;
import org.knime.knip.core.ui.imgviewer.panels.HiddenViewerComponent;
/**
* TODO Auto-generated
*
* @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 LabelHiliteProvider<L extends Comparable<L>, T extends RealType<T>> extends HiddenViewerComponent
implements HiLiteListener {
/**
*
*/
private static final long serialVersionUID = 1L;
private EventService m_eventService;
private Set<String> m_hilitedLabels;
private HiLiteHandler m_hiliteHandler;
private RandomAccess<LabelingType<L>> m_labelingAccess;
private String m_rowKey;
private PlaneSelectionEvent m_sel;
public LabelHiliteProvider() {
m_hilitedLabels = new HashSet<String>();
m_hiliteHandler = new DefaultHiLiteHandler();
}
public void clearHiliteListener() {
m_hilitedLabels.clear();
m_hiliteHandler.removeHiLiteListener(this);
}
public void close() {
clearHiliteListener();
}
private void createHiliteFromHandler(final HiLiteHandler hiliteHandler) {
m_hilitedLabels.clear();
handleHiLiteEvent(hiliteHandler.getHiLitKeys());
}
private void handleHiLiteEvent(final Set<RowKey> rowKeys) {
for (final RowKey key : rowKeys) {
m_hilitedLabels.add(key.getString());
}
m_eventService.publish(new HilitedLabelsChgEvent(m_hilitedLabels));
}
private void handleUnHiLiteEvent(final Set<RowKey> rowKeys) {
for (final RowKey key : rowKeys) {
m_hilitedLabels.remove(key.getString());
}
m_eventService.publish(new HilitedLabelsChgEvent(m_hilitedLabels));
}
@Override
public void loadComponentConfiguration(final ObjectInput in) throws IOException, ClassNotFoundException {
m_hilitedLabels = (Set<String>)in.readObject();
m_rowKey = in.readUTF();
}
public void onClose() {
clearHiliteListener();
m_hilitedLabels = null;
m_labelingAccess = null;
}
/**
* @param img
* @param axes
*/
@EventListener
public void onLabelingUpdated(final ImgAndLabelingChgEvent<T, L> e) {
m_rowKey = e.getName().getName();
m_labelingAccess = e.getLabeling().randomAccess();
createHiliteFromHandler(m_hiliteHandler);
}
@EventListener
public void onLabelSelectionHilite(final LabelPanelHiliteSelectionChgEvent e) {
final Set<RowKey> keys = new HashSet<RowKey>();
for (final String s : e.getLabels()) {
if (!m_hilitedLabels.contains(s)) {
if (e.isHilite()) {
m_hilitedLabels.add(s);
keys.add(new RowKey(s));
}
} else if (!e.isHilite()) {
m_hilitedLabels.remove(s);
keys.add(new RowKey(s));
}
}
if (e.isHilite()) {
m_hiliteHandler.fireHiLiteEvent(keys);
} else {
m_hiliteHandler.fireUnHiLiteEvent(keys);
}
}
@EventListener
public void onMousePressed(final ImgViewerMousePressedEvent e) {
if (e.isInside()) {
if (m_sel == null) {
m_sel = new PlaneSelectionEvent(0, 1, new long[m_labelingAccess.numDimensions()]);
}
m_labelingAccess.setPosition(e.getPosX(), m_sel.getPlaneDimIndex1());
m_labelingAccess.setPosition(e.getPosY(), m_sel.getPlaneDimIndex2());
boolean hilite = false;
final Set<RowKey> keys = new HashSet<RowKey>();
for (final L label : m_labelingAccess.get()) {
final String l = label.toString();
if (!m_hilitedLabels.contains(l)) {
m_hilitedLabels.add(l);
hilite = true;
}
keys.add(new RowKey(l));
}
if (hilite) {
m_hiliteHandler.fireHiLiteEvent(keys);
} else {
m_hiliteHandler.fireUnHiLiteEvent(keys);
}
}
}
@EventListener
public void onUpdate(final PlaneSelectionEvent sel) {
m_sel = sel;
if (m_labelingAccess != null) {
m_labelingAccess.setPosition(sel.getPlanePos());
}
}
@Override
public void saveComponentConfiguration(final ObjectOutput out) throws IOException {
out.writeObject(m_hilitedLabels);
out.writeUTF(m_rowKey);
}
@Override
public void setEventService(final EventService eventService) {
m_eventService = eventService;
eventService.subscribe(this);
}
public void updateInHandler(final HiLiteHandler hiliteInHandler) {
// nothing has changed, we come away easy
if (hiliteInHandler == m_hiliteHandler) {
return;
}
m_hilitedLabels.clear();
m_hiliteHandler.removeHiLiteListener(this);
m_hiliteHandler = hiliteInHandler;
createHiliteFromHandler(m_hiliteHandler);
m_hiliteHandler.addHiLiteListener(this);
}
@Override
public void hiLite(final KeyEvent event) {
final Set<RowKey> rowKeys = event.keys();
handleHiLiteEvent(rowKeys);
m_eventService.publish(new ImgRedrawEvent());
}
@Override
public void unHiLite(final KeyEvent event) {
final Set<RowKey> rowKeys = event.keys();
handleUnHiLiteEvent(rowKeys);
m_eventService.publish(new ImgRedrawEvent());
}
@Override
public void unHiLiteAll(final KeyEvent event) {
m_hilitedLabels.clear();
m_eventService.publish(new HilitedLabelsChgEvent(m_hilitedLabels));
m_eventService.publish(new ImgRedrawEvent());
}
}