package jav.gui.image;
import jav.correctionBackend.Page;
import jav.correctionBackend.Token;
import jav.gui.cookies.ImageZoomCookie;
import jav.gui.events.MessageCenter;
import jav.gui.events.documentChanged.DocumentChangedEvent;
import jav.gui.events.documentChanged.DocumentChangedEventSlot;
import jav.gui.events.pageChanged.PageChangedEvent;
import jav.gui.events.pageChanged.PageChangedEventSlot;
import jav.gui.events.tokenDeselection.TokenDeselectionEvent;
import jav.gui.events.tokenDeselection.TokenDeselectionEventSlot;
import jav.gui.events.tokenSelection.TokenSelectionEvent;
import jav.gui.events.tokenSelection.TokenSelectionEventSlot;
import jav.gui.main.AbstractMyTopComponent;
import jav.gui.main.MainController;
import java.awt.EventQueue;
import java.awt.RenderingHints;
import java.util.logging.Logger;
import java.util.prefs.Preferences;
import javax.media.jai.JAI;
import javax.media.jai.ParameterBlockJAI;
import javax.media.jai.RenderedOp;
import javax.swing.BoxLayout;
import javax.swing.JScrollPane;
import javax.swing.SwingWorker;
import javax.swing.SwingWorker.StateValue;
import jpl.mipl.jade.JadeDisplay;
import jpl.mipl.jade.MouseScroller;
import org.netbeans.api.settings.ConvertAsProperties;
import org.openide.util.NbBundle;
import org.openide.util.NbPreferences;
import org.openide.util.lookup.AbstractLookup;
import org.openide.util.lookup.InstanceContent;
import org.openide.windows.TopComponent;
import org.openide.windows.WindowManager;
/**
*Copyright (c) 2012, IMPACT working group at the Centrum für Informations- und Sprachverarbeitung, University of Munich.
*All rights reserved.
*Redistribution and use in source and binary forms, with or without
*modification, are permitted provided that the following conditions are met:
*Redistributions of source code must retain the above copyright
*notice, this list of conditions and the following disclaimer.
*Redistributions in binary form must reproduce the above copyright
*notice, this list of conditions and the following disclaimer in the
*documentation and/or other materials provided with the distribution.
*THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
*IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
*TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
*PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
*HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
*SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
*LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
*DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
*THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
*(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
*OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This file is part of the ocr-postcorrection tool developed
* by the IMPACT working group at the Centrum für Informations- und Sprachverarbeitung, University of Munich.
* For further information and contacts visit http://ocr.cis.uni-muenchen.de/
*
* @author thorsten (thorsten.vobl@googlemail.com)
*
* topcomponent that uses the jadedisplay to show an image
*
*/
@ConvertAsProperties(dtd = "-//jav.gui.image//CompleteImage//EN",
autostore = false)
public final class CompleteImageTopComponent extends AbstractMyTopComponent implements TokenSelectionEventSlot, TokenDeselectionEventSlot, DocumentChangedEventSlot, PageChangedEventSlot, ImageZoomCookie {
private int currentTokenIndex;
private boolean hasImage = false;
private Preferences node;
private JScrollPane sp = null;
private double scale;
private String actualPageString;
private boolean imageOpened = false;
private JadeDisplay _jadeDisplay = null;
private ParameterBlockJAI _loadPB, _zoomPB;
private RenderedOp _loadImage, _zoomImage, _finalImage;
private TokenBoxPainter _tokenAnMaler = null;
private InstanceContent content = new InstanceContent();
private static CompleteImageTopComponent instance;
private SwingWorker worker = null;
/**
* path to the icon used by the component and its open action
*/
// static final String ICON_PATH = "SET/PATH/TO/ICON/HERE";
private static final String PREFERRED_ID = "CompleteImageTopComponent";
public CompleteImageTopComponent() {
associateLookup(new AbstractLookup(content));
node = NbPreferences.forModule(this.getClass());
init();
sp = new JScrollPane();
this.setDoubleBuffered(true);
sp.setDoubleBuffered(false);
this.add(sp);
setName(NbBundle.getMessage(CompleteImageTopComponent.class, "CTL_CompleteImageTopComponent"));
setToolTipText(NbBundle.getMessage(CompleteImageTopComponent.class, "HINT_CompleteImageTopComponent"));
// setIcon(ImageUtilities.loadImage(ICON_PATH, true));
}
/**
* This method is called from within the constructor to initialize the form.
* WARNING: Do NOT modify this code. The content of this method is always
* regenerated by the Form Editor.
*/
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
private void initComponents() {
setVerifyInputWhenFocusTarget(false);
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
this.setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 400, Short.MAX_VALUE)
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 300, Short.MAX_VALUE)
);
}// </editor-fold>//GEN-END:initComponents
// Variables declaration - do not modify//GEN-BEGIN:variables
// End of variables declaration//GEN-END:variables
/**
* Gets default instance. Do not use directly: reserved for *.settings files
* only, i.e. deserialization routines; otherwise you could get a
* non-deserialized instance. To obtain the singleton instance, use {@link #findInstance}.
*/
public static synchronized CompleteImageTopComponent getDefault() {
if (instance == null) {
instance = new CompleteImageTopComponent();
}
return instance;
}
/**
* Obtain the CompleteImageTopComponent instance. Never call {@link #getDefault}
* directly!
*/
public static synchronized CompleteImageTopComponent findInstance() {
TopComponent win = WindowManager.getDefault().findTopComponent(PREFERRED_ID);
if (win == null) {
Logger.getLogger(CompleteImageTopComponent.class.getName()).warning(
"Cannot find " + PREFERRED_ID + " component. It will not be located properly in the window system.");
return getDefault();
}
if (win instanceof CompleteImageTopComponent) {
return (CompleteImageTopComponent) win;
}
Logger.getLogger(CompleteImageTopComponent.class.getName()).warning(
"There seem to be multiple components with the '" + PREFERRED_ID
+ "' ID. That is a potential source of errors and unexpected behavior.");
return getDefault();
}
@Override
public void componentOpened() {
MessageCenter.getInstance().addPageChangedEventListener(this);
MessageCenter.getInstance().addTokenSelectionEventListener(this);
MessageCenter.getInstance().addTokenDeselectionEventListener(this);
MessageCenter.getInstance().addDocumentChangedEventListener(this);
}
@Override
public void componentClosed() {
MessageCenter.getInstance().removeDocumentChangedEventListener(this);
MessageCenter.getInstance().removePageChangedEventListener(this);
MessageCenter.getInstance().removeTokenSelectionEventListener(this);
MessageCenter.getInstance().removeTokenDeselectionEventListener(this);
}
void writeProperties(java.util.Properties p) {
// better to version settings since initial version as advocated at
// http://wiki.apidesign.org/wiki/PropertyFiles
p.setProperty("version", "1.0");
// TODO store your settings
}
Object readProperties(java.util.Properties p) {
if (instance == null) {
instance = this;
}
instance.readPropertiesImpl(p);
return instance;
}
private void readPropertiesImpl(java.util.Properties p) {
String version = p.getProperty("version");
// TODO read your settings according to their version
}
@Override
protected String preferredID() {
return PREFERRED_ID;
}
private void init() {
this.setDoubleBuffered(true);
this.setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
}
@Override
public void dispatchEvent(final PageChangedEvent e) {
final Page p = MainController.findInstance().getPage(e.getPageNum());
if (p != null && p.hasImage()) {
setName(java.util.ResourceBundle.getBundle("jav/gui/image/Bundle").getString("page") + (e.getPageNum()+1));
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
actualPageString = p.getImageCanonical();
if (p.hasImage()) {
hasImage = true;
loadImage(actualPageString, scale);
}
}
});
}
}
private void loadImage(String filename, double scalef) {
System.out.println("imageload" + filename);
if (sp != null) {
content.remove(this);
}
_loadPB = new ParameterBlockJAI("fileload");
_loadPB.setParameter("filename", filename);
_loadImage = JAI.create("fileload", _loadPB, new RenderingHints(JAI.KEY_TILE_CACHE, null));
// z00m the image
_zoomPB = new ParameterBlockJAI("scale");
_zoomPB.setSource(_loadImage, 0);
float s = (float) scalef;
_zoomPB.setParameter("xScale", s);
_zoomPB.setParameter("yScale", s);
// _zoomPB.setParameter("interpolation", javax.media.jai.Interpolation.getInstance(javax.media.jai.Interpolation.INTERP_BICUBIC));
_zoomImage = JAI.create("scale", _zoomPB);
_finalImage = _zoomImage;
_jadeDisplay = new JadeDisplay(_finalImage);
_jadeDisplay.setDisableDoubleBuffering(false);
_jadeDisplay.setDoubleBuffered(false);
_jadeDisplay.setRepaintPolicy(JadeDisplay.REPAINT_DEFERRED);
sp.getVerticalScrollBar().setUnitIncrement(60);
sp.getVerticalScrollBar().setBlockIncrement(180);
sp.setViewportView(_jadeDisplay);
new MouseScroller(sp.getViewport());
_tokenAnMaler = new TokenBoxPainter(_jadeDisplay, sp);
imageOpened = true;
content.add(this);
// content.set(Collections.singleton(this), null);
}
@Override
public boolean isReady() {
return this.imageOpened;
}
@Override
public void zoomImg(double s) {
this.scale = s;
this.loadImage(this.actualPageString, s);
Token temp = MainController.findInstance().getDocument().getTokenByID(currentTokenIndex);
if (temp != null) {
_tokenAnMaler.paintTokenBox(temp, s);
}
}
@Override
public double getMaxScale() {
return node.getDouble("maxScale", 1.5);
}
@Override
public double getMinScale() {
return node.getDouble("minScale", 0.2);
}
@Override
public double getScale() {
return this.scale;
}
@Override
public void dispatchEvent(final TokenSelectionEvent e) {
currentTokenIndex = e.getTokenID();
if (worker != null && worker.getState().equals(StateValue.STARTED)) {
worker.cancel(true);
}
if (this.hasImage) {
worker = new SwingWorker<Boolean, Object>() {
@Override
protected Boolean doInBackground() throws Exception {
Token temp = MainController.findInstance().getDocument().getTokenByID(currentTokenIndex);
if (!temp.getImageFilename().equals("")) {
if (actualPageString.equals(temp.getImageFilename())) {
_tokenAnMaler.paintTokenBox(temp, scale);
} else {
loadImage(temp.getImageFilename(), scale);
actualPageString = temp.getImageFilename();
_tokenAnMaler.paintTokenBox(temp, scale);
}
}
return true;
}
};
worker.execute();
setName(java.util.ResourceBundle.getBundle("jav/gui/image/Bundle").getString("page") + (MainController.findInstance().getDocument().getTokenByID(currentTokenIndex).getPageIndex()+1));
}
}
@Override
public void dispatchEvent(TokenDeselectionEvent e) {
if (worker != null && worker.getState().equals(StateValue.STARTED)) {
worker.cancel(true);
}
currentTokenIndex = -1;
if (this._jadeDisplay != null && this._tokenAnMaler != null) {
this._jadeDisplay.removeOverlayPainter(this._tokenAnMaler);
_tokenAnMaler.setHasPainter(false);
}
}
@Override
public boolean hasImage() {
return this.hasImage;
}
@Override
public boolean showImage() {
return hasImage();
}
@Override
public void dispatchEvent(DocumentChangedEvent e) {
scale = Double.parseDouble(MainController.findInstance().getDocumentProperties().getProperty("completeImageScale"));
}
}