package logbook.util;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import javax.annotation.CheckForNull;
import org.eclipse.swt.SWT;
import org.eclipse.swt.dnd.DND;
import org.eclipse.swt.dnd.DragSource;
import org.eclipse.swt.dnd.DragSourceAdapter;
import org.eclipse.swt.dnd.DragSourceEvent;
import org.eclipse.swt.dnd.DropTarget;
import org.eclipse.swt.dnd.DropTargetAdapter;
import org.eclipse.swt.dnd.DropTargetEvent;
import org.eclipse.swt.dnd.TextTransfer;
import org.eclipse.swt.dnd.Transfer;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.graphics.FontData;
import org.eclipse.swt.graphics.FontMetrics;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.ImageData;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.layout.FormAttachment;
import org.eclipse.swt.layout.FormData;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.layout.RowLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Group;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.MessageBox;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableItem;
import org.eclipse.swt.widgets.TaskBar;
import org.eclipse.swt.widgets.TaskItem;
import org.eclipse.wb.swt.SWTResourceManager;
/**
* SWTのutilです
*
*/
public final class SwtUtils {
/**
* TaskItemを取得します
*
* @param shell
* @return
*/
@CheckForNull
public static TaskItem getTaskBarItem(Shell shell) {
TaskBar bar = Display.getDefault().getSystemTaskBar();
if (bar == null)
return null;
TaskItem item = bar.getItem(shell);
if (item == null)
item = bar.getItem(null);
return item;
}
/**
* Composite.layout()をすべての要素で呼び出します
* @param composite
*/
public static void layoutCompositeRecursively(Composite composite) {
for (org.eclipse.swt.widgets.Control control : composite.getChildren()) {
if (control instanceof Composite) {
layoutCompositeRecursively((Composite) control);
}
}
composite.layout();
}
private static class ButtonImagePainter implements Listener {
private final Button button;
private final Image image;
public ButtonImagePainter(Button button, Image image) {
this.button = button;
this.image = image;
}
@Override
public void handleEvent(Event event) {
Rectangle rect = this.button.getBounds();
Image scaled = SwtUtils.scaleToFit(this.image, rect.width, rect.height);
Image old = this.button.getImage();
this.button.setImage(scaled);
if (old != null) {
old.dispose();
}
}
}
public static void setButtonImage(Button button, Image image) {
button.addListener(SWT.Resize, new ButtonImagePainter(button, image));
}
public static FormData makeFormData(
FormAttachment left, FormAttachment right,
FormAttachment top, FormAttachment bottom)
{
FormData data = new FormData();
data.left = left;
data.right = right;
data.top = top;
data.bottom = bottom;
return data;
}
public static GridLayout makeGridLayout(
int numColumns,
int horizontalSpacing, int verticalSpacing,
int marginWidth, int marginHeight)
{
GridLayout gl = new GridLayout(numColumns, false);
gl.horizontalSpacing = horizontalSpacing;
gl.verticalSpacing = verticalSpacing;
gl.marginWidth = marginWidth;
gl.marginHeight = marginHeight;
return gl;
}
public static RowLayout makeRowLayout(boolean horizontal, int spacing, int margin, boolean wrap) {
RowLayout rl = new RowLayout(horizontal ? SWT.HORIZONTAL : SWT.VERTICAL);
rl.spacing = spacing;
rl.center = true;
rl.marginBottom = rl.marginLeft = rl.marginRight = rl.marginTop = margin;
rl.wrap = wrap;
return rl;
}
private final static int DPI_BASE = 96;
private static String defaultFontName = null;
private static int defaultFontSize = 0;
private static int defaultFontStyle = 0;
private static int defaultLineHeight = 0;
private static Point DPI = Display.getDefault().getDPI();
/**
* DPIを考慮したサイズを返す
* @param width
* @return
*/
public static int DPIAwareWidth(int width) {
return (width * DPI.x) / DPI_BASE;
}
/**
* DPIを考慮したサイズを返す
* @param height
* @return
*/
public static int DPIAwareHeight(int height) {
return (height * DPI.y) / DPI_BASE;
}
public static Point DPIAwareSize(Point size) {
return new Point(DPIAwareWidth(size.x), DPIAwareHeight(size.y));
}
private static void checkControl(Control control) {
if (defaultFontName == null) {
FontData fd = control.getFont().getFontData()[0];
defaultFontName = fd.getName();
defaultFontSize = fd.getHeight();
defaultFontStyle = fd.getStyle();
GC gc = new GC(control);
FontMetrics fm = gc.getFontMetrics();
defaultLineHeight = fm.getAscent() + fm.getLeading() + fm.getDescent();
gc.dispose();
}
}
public static int ComputeHeaderHeight(Group group, double lineHeight) {
checkControl(group);
return (int) (((defaultFontSize * DPI.y) / 72.0) * lineHeight);
}
public static int ComputeLineSpacing(double lineHeight) {
return (int) (((defaultFontSize * DPI.y) / 72.0) * lineHeight) - defaultLineHeight;
}
/**
* 行間はデフォルト値 120%
* @param lbl
* @param text
* @param gd
* @return
*/
public static GridData initLabel(Label lbl, String text, GridData gd) {
return initLabel(lbl, text, 0, 1.2, gd);
}
public static GridData initLabel(Label lbl, String text, int fontSizeDiff, GridData gd) {
return initLabel(lbl, text, fontSizeDiff, 1.2, gd);
}
public static GridData initLabel(Label lbl, String text, int fontSizeDiff, double lineHeight, GridData gd) {
checkControl(lbl);
int heightInPoint = defaultFontSize + fontSizeDiff;
Font font = SWTResourceManager.getFont(defaultFontName, heightInPoint, defaultFontStyle);
lbl.setFont(font);
lbl.setText(text);
if (!"cocoa".equals(SWT.getPlatform())) { // mac以外
gd.heightHint = (int) (((heightInPoint * DPI.y) / 72.0) * lineHeight);
}
lbl.setLayoutData(gd);
return gd;
}
public static Image makeImage(File file) throws IOException {
InputStream stream = new FileInputStream(file);
try {
Display display = Display.getCurrent();
ImageData data = new ImageData(stream);
if (data.transparentPixel > 0) {
return new Image(display, data, data.getTransparencyMask());
}
return new Image(display, data);
} finally {
stream.close();
}
}
public static Image scaleToFit(Image img, int width, int height) {
ImageData data = img.getImageData();
float factor = Math.min((float) width / data.width, (float) height / data.height);
if (factor <= 0) {
return null;
}
ImageData scaled = data.scaledTo((int) (data.width * factor), (int) (data.height * factor));
return new Image(Display.getDefault(), scaled);
}
public static void errorDialog(Exception e, Shell parent) {
MessageBox box1 = new MessageBox(parent, SWT.OK | SWT.ICON_ERROR);
box1.setMessage(e.getMessage());
box1.open();
}
public static void messageDialog(String mes, Shell parent) {
MessageBox box1 = new MessageBox(parent, SWT.OK | SWT.ICON_INFORMATION);
box1.setMessage(mes);
box1.open();
}
public static interface TableDragAndDropListener {
String tableItemToString(TableItem item);
boolean canDragSource(TableItem source);
TableItem create(Table table, TableItem source, int index);
void finished(TableItem newItem);
}
/**
* テーブルにドラッグ&ドロップによるアイテムの移動機能を追加
* @param table
* @param createListener 移動先のアイテムを作るハンドラ
*/
public static void addItemDragAndDropMoveSupport(final Table[] tables, final TableDragAndDropListener listener) {
// ドラッグ中のオブジェクトを保持(finalにする都合上配列になっているだけでオブジェクトは1つしか持たない)
final TableItem[] dragSourceItem = new TableItem[1];
Transfer[] types = new Transfer[] { TextTransfer.getInstance() };
for (final Table table : tables) {
DragSource source = new DragSource(table, DND.DROP_MOVE);
source.setTransfer(types);
source.addDragListener(new DragSourceAdapter() {
@Override
public void dragStart(DragSourceEvent event) {
TableItem[] selection = table.getSelection();
if ((selection.length > 0) && listener.canDragSource(selection[0])) {
event.doit = true;
dragSourceItem[0] = selection[0];
} else {
event.doit = false;
}
}
@Override
public void dragSetData(DragSourceEvent event) {
event.data = listener.tableItemToString(dragSourceItem[0]);
}
@Override
public void dragFinished(DragSourceEvent event) {
dragSourceItem[0] = null;
}
});
}
for (final Table table : tables) {
DropTarget target = new DropTarget(table, DND.DROP_MOVE);
target.setTransfer(types);
target.addDropListener(new DropTargetAdapter() {
@Override
public void dragEnter(DropTargetEvent event) {
if (dragSourceItem[0] == null) {
// 他のアプリからのドロップなどは一切サポートしない
event.detail = DND.DROP_NONE;
}
}
@Override
public void dragOver(DropTargetEvent event) {
event.feedback = DND.FEEDBACK_SCROLL;
// event.itemは現在のドロップ先にあるアイテム
if (dragSourceItem[0] != null) {
// 移動先インジケータを表示
TableItem item = (TableItem) event.item;
if (item != null) {
Point pt = table.getDisplay().map(null, table, event.x, event.y);
Rectangle bounds = item.getBounds();
if (pt.y < (bounds.y + (bounds.height / 2))) {
event.feedback |= DND.FEEDBACK_INSERT_BEFORE;
} else {
event.feedback |= DND.FEEDBACK_INSERT_AFTER;
}
}
}
}
@Override
public void drop(DropTargetEvent event) {
if (dragSourceItem[0] != null) {
TableItem sourceItem = dragSourceItem[0];
TableItem targetItem = (TableItem) event.item;
Point pt = table.getDisplay().map(null, table, event.x, event.y);
int index = table.getItemCount();
if (targetItem != null) {
Rectangle bounds = targetItem.getBounds();
TableItem[] items = table.getItems();
for (int i = 0; i < items.length; i++) {
if (items[i] == targetItem) {
index = i;
break;
}
}
if (pt.y < (bounds.y + (bounds.height / 2))) {
} else {
index++;
}
}
TableItem item = listener.create(table, sourceItem, index);
sourceItem.dispose();
table.redraw();
listener.finished(item);
}
}
});
}
}
}