package open.dolphin.client;
import java.awt.Color;
import java.awt.Desktop;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Image;
import java.awt.event.ActionEvent;
import java.awt.event.MouseEvent;
import java.beans.PropertyChangeEvent;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Iterator;
import javax.swing.AbstractAction;
import javax.swing.BorderFactory;
import javax.swing.ImageIcon;
import javax.swing.JPopupMenu;
import javax.swing.text.Position;
import open.dolphin.infomodel.SchemaModel;
import open.dolphin.plugin.PluginLoader;
import open.dolphin.project.Project;
/**
* スタンプのデータを保持するコンポーネントで TextPane に挿入される。
*
* @author Kazushi Minagawa, Digital Globe, Inc.
*/
public final class SchemaHolder extends AbstractComponentHolder implements ComponentHolder {
private SchemaModel schema;
//XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
// Junzo SATO
// to restrict the size of the component,
// setBounds and setSize are overridden.
private final int fixedSize = 192;//160;/////////////////////////////////////////
private final int fixedWidth = fixedSize;
private final int fixedHeight = fixedSize;
//XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
private boolean selected;
private Position start;
private Position end;
private final KartePane kartePane;
public SchemaHolder(KartePane kartePane, SchemaModel schema) {
this.kartePane = kartePane;
//XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
// Junzo SATO
// for simplicity, the acpect ratio of the fixed rect is set to 1.
this.setDoubleBuffered(false);
this.setOpaque(true);
this.setBackground(Color.white);
//XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
this.schema = schema;
//this.setImageIcon(schema.getIcon());
setIcon(adjustImageSize(schema.getIcon(), new Dimension(fixedWidth, fixedHeight)));
}
@Override
public int getContentType() {
return ComponentHolder.TT_IMAGE;
}
@Override
public KartePane getKartePane() {
return kartePane;
}
public SchemaModel getSchema() {
return schema;
}
@Override
public boolean isSelected() {
return selected;
}
@Override
public void mabeShowPopup(MouseEvent e) {
if (e.isPopupTrigger()) {
JPopupMenu popup = new JPopupMenu();
popup.setFocusable(false);
ChartMediator mediator = kartePane.getMediator();
popup.add(mediator.getAction(GUIConst.ACTION_CUT));
popup.add(mediator.getAction(GUIConst.ACTION_COPY));
popup.add(mediator.getAction(GUIConst.ACTION_PASTE));
popup.addSeparator();
// 右クリックで編集
String actionText = ClientContext.getMyBundle(SchemaHolder.class).getString("actionText.edit");
AbstractAction action = new AbstractAction(actionText) {
@Override
public void actionPerformed(ActionEvent ae) {
edit();
}
};
popup.add(action);
popup.show(e.getComponent(), e.getX(), e.getY());
}
}
@Override
public void setSelected(boolean selected) {
boolean old = this.selected;
this.selected = selected;
if (old != this.selected) {
if (this.selected) {
this.setBorder(BorderFactory.createLineBorder(GUIConst.STAMP_HOLDER_SELECTED_BORDER));
} else {
this.setBorder(BorderFactory.createLineBorder(kartePane.getTextPane().getBackground()));
}
}
}
@Override
public void edit() {
try {
PluginLoader<SchemaEditor> loader = PluginLoader.load(SchemaEditor.class);
Iterator<SchemaEditor> iter = loader.iterator();
if (iter.hasNext()) {
final SchemaEditor editor = iter.next();
editor.setSchema(schema);
editor.setEditable(kartePane.getTextPane().isEditable());
editor.addPropertyChangeListener(SchemaHolder.this);
Runnable awt = () -> {
editor.start();
};
EventQueue.invokeLater(awt);
}
} catch (Exception e) {
e.printStackTrace(System.err);
}
}
@Override
public void propertyChange(PropertyChangeEvent e) {
SchemaModel newSchema = (SchemaModel)e.getNewValue();
if (newSchema == null) {
return;
}
schema = newSchema;
setIcon(adjustImageSize(schema.getIcon(), new Dimension(fixedWidth, fixedHeight)));
this.kartePane.setDirty(true);
}
@Override
public void setEntry(Position start, Position end) {
this.start = start;
this.end = end;
}
@Override
public int getStartPos() {
return start.getOffset();
}
@Override
public int getEndPos() {
return end.getOffset();
}
/**
* アスペクト比を保って画像とラベルのサイズを変更する。
* @param icon
* @param dim
* @return
*/
protected ImageIcon adjustImageSize(ImageIcon icon, Dimension dim) {
int newWidth = icon.getIconWidth();
int newHeight = icon.getIconHeight();
float width = (float)icon.getIconWidth();
float height = (float)icon.getIconHeight();
float dimW = (float)dim.width;
float dimH = (float)dim.height;
boolean needResize = false;
// 縦長画像の時
if (height>width) {
// 画像の高さがラベルより大きい時、画像の高さを dim.height にする
if (height>dimH) {
newHeight = (int)dimH;
float ratio = dimH/height;
newWidth = (int)(ratio*width);
needResize = true;
}
} // 横長画像の時
else {
// 画像の幅がラベルより大きい時、画像の幅を dim.width にする
if (width>dimW) {
newWidth = (int)dimW;
float ratio = dimW/width;
newHeight = (int)(ratio*height);
needResize = true;
}
}
// ラベルのサイズ変更
this.setSize(newWidth, newHeight);
this.setMaximumSize(new Dimension(newWidth, newHeight));
this.setMinimumSize(new Dimension(newWidth, newHeight));
this.setPreferredSize(new Dimension(newWidth, newHeight));
if (needResize) {
Image img = icon.getImage();
img = img.getScaledInstance(newWidth, newHeight, Image.SCALE_SMOOTH);
return new ImageIcon(img);
} else {
return icon;
}
}
}