Java tutorial
/* * This file is part of the ZoRa project: http://www.photozora.org. * * ZoRa is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * ZoRa 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 ZoRa; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * (c) 2009 Berthold Daum */ package com.bdaum.zoom.ui.internal.views; import org.eclipse.jface.action.Action; import org.eclipse.jface.action.IAction; import org.eclipse.jface.action.IMenuManager; import org.eclipse.jface.action.IToolBarManager; import org.eclipse.jface.action.Separator; import org.eclipse.jface.viewers.ISelection; import org.eclipse.jface.viewers.StructuredSelection; import org.eclipse.swt.SWT; import org.eclipse.swt.events.MouseAdapter; import org.eclipse.swt.events.MouseEvent; import org.eclipse.swt.events.PaintEvent; import org.eclipse.swt.events.PaintListener; import org.eclipse.swt.graphics.Color; import org.eclipse.swt.graphics.GC; import org.eclipse.swt.graphics.ImageData; import org.eclipse.swt.graphics.PaletteData; import org.eclipse.swt.graphics.Point; import org.eclipse.swt.graphics.RGB; import org.eclipse.swt.graphics.Rectangle; import org.eclipse.swt.graphics.TextLayout; import org.eclipse.swt.graphics.Transform; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Canvas; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Label; import org.eclipse.ui.IActionBars; import org.eclipse.ui.IMemento; import org.eclipse.ui.IViewSite; import org.eclipse.ui.IWorkbenchActionConstants; import org.eclipse.ui.PartInitException; import org.eclipse.ui.PlatformUI; import com.bdaum.zoom.cat.model.asset.Asset; import com.bdaum.zoom.core.Constants; import com.bdaum.zoom.core.internal.Utilities; import com.bdaum.zoom.ui.AssetSelection; import com.bdaum.zoom.ui.internal.HelpContextIds; import com.bdaum.zoom.ui.internal.Icons; import com.bdaum.zoom.ui.internal.dialogs.ConfigureCaptionDialog; @SuppressWarnings("restriction") public class HistogramView extends BasicView implements PaintListener { public static final String ID = "com.bdaum.zoom.ui.views.HistogramView"; //$NON-NLS-1$ private static final int MINTHUMBNAILSIZE = 160 * 120; private static final String SHOW_RED = "showRed"; //$NON-NLS-1$ private static final String SHOW_GREEN = "showGreen"; //$NON-NLS-1$ private static final String SHOW_BLUE = "showBlue"; //$NON-NLS-1$ private static final String SHOW_GREY = "showGrey"; //$NON-NLS-1$ private static final String WEIGHTED = "weighted"; //$NON-NLS-1$ private Canvas canvas; private Asset currentItem; private int[] reds = new int[256]; private int[] greens = new int[256]; private int[] blues = new int[256]; private int[] greys = new int[256]; private int mxvalue; private Action redAction, greenAction, blueAction, greyAction, centerAction; protected boolean showRed = true; protected boolean showGrey = true; protected boolean showBlue = true; protected boolean showGreen = true; private boolean weighted; private int count; private Label caption; private String template; private Action configureAction; private int alignment; private Composite composite; private Label space; private Action trigger; @Override public void init(IViewSite site, IMemento memento) throws PartInitException { super.init(site, memento); if (memento != null) { Boolean bool = memento.getBoolean(SHOW_RED); showRed = bool != null && bool; bool = memento.getBoolean(SHOW_GREEN); showGreen = bool != null && bool; bool = memento.getBoolean(SHOW_BLUE); showBlue = bool != null && bool; bool = memento.getBoolean(SHOW_GREY); showGrey = bool != null && bool; bool = memento.getBoolean(WEIGHTED); weighted = bool != null && bool; template = memento.getString(TEMPLATE); Integer integer = memento.getInteger(ALIGNMENT); alignment = integer != null ? integer : SWT.LEFT; } if (template == null) template = DEFAULTTEMPLATE; } @Override public void saveState(IMemento memento) { if (memento != null) { memento.putBoolean(SHOW_RED, showRed); memento.putBoolean(SHOW_GREEN, showGreen); memento.putBoolean(SHOW_BLUE, showBlue); memento.putBoolean(SHOW_GREY, showGrey); memento.putBoolean(SHOW_GREY, weighted); memento.putString(TEMPLATE, template); memento.putInteger(ALIGNMENT, alignment); } super.saveState(memento); } @Override public void createPartControl(Composite parent) { composite = new Composite(parent, SWT.NONE); GridLayout layout = new GridLayout(); layout.marginHeight = layout.marginWidth = 0; layout.marginTop = 10; composite.setLayout(layout); canvas = new Canvas(composite, SWT.DOUBLE_BUFFERED); canvas.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); canvas.addPaintListener(this); PlatformUI.getWorkbench().getHelpSystem().setHelp(canvas, HelpContextIds.HISTOGRAM_VIEW); makeActions(); installListeners(); contributeToActionBars(); updateActions(true); canvas.redraw(); } private void contributeToActionBars() { IActionBars bars = getViewSite().getActionBars(); fillLocalPullDown(bars.getMenuManager()); fillLocalToolBar(bars.getToolBarManager()); } private void fillLocalPullDown(IMenuManager manager) { manager.add(centerAction); manager.add(redAction); manager.add(greenAction); manager.add(blueAction); manager.add(greyAction); manager.add(new Separator()); manager.add(configureAction); manager.add(new Separator(IWorkbenchActionConstants.MB_ADDITIONS)); } private void fillLocalToolBar(IToolBarManager manager) { manager.add(centerAction); manager.add(redAction); manager.add(greenAction); manager.add(blueAction); manager.add(greyAction); manager.add(new Separator(IWorkbenchActionConstants.MB_ADDITIONS)); } @Override protected void makeActions() { super.makeActions(); centerAction = new Action(Messages.getString("HistogramView.centric"), IAction.AS_CHECK_BOX) { //$NON-NLS-1$ @Override public void run() { weighted = !weighted; setImageDescriptor(weighted ? Icons.centric.getDescriptor() : Icons.integral.getDescriptor()); setToolTipText(weighted ? Messages.getString("HistogramView.centric_tooltip") //$NON-NLS-1$ : Messages.getString("HistogramView.integral")); //$NON-NLS-1$ recalculate(); refresh(); } }; centerAction.setImageDescriptor(weighted ? Icons.centric.getDescriptor() : Icons.integral.getDescriptor()); centerAction.setToolTipText(weighted ? Messages.getString("HistogramView.centric_tooltip") //$NON-NLS-1$ : Messages.getString("HistogramView.integral")); //$NON-NLS-1$ centerAction.setChecked(weighted); redAction = new Action(Messages.getString("HistogramView.Red"), IAction.AS_CHECK_BOX) { //$NON-NLS-1$ @Override public void run() { showRed = !showRed; setImageDescriptor(showRed ? Icons.redDot.getDescriptor() : Icons.paleRedDot.getDescriptor()); setToolTipText(showRed ? Messages.getString("HistogramView.red_tooltip") //$NON-NLS-1$ : Messages.getString("HistogramView.red_off")); //$NON-NLS-1$ trigger = this; refresh(); } }; redAction.setImageDescriptor(showRed ? Icons.redDot.getDescriptor() : Icons.paleRedDot.getDescriptor()); redAction.setToolTipText(showRed ? Messages.getString("HistogramView.red_tooltip") //$NON-NLS-1$ : Messages.getString("HistogramView.red_off")); //$NON-NLS-1$ redAction.setChecked(showRed); greenAction = new Action(Messages.getString("HistogramView.green"), IAction.AS_CHECK_BOX) { //$NON-NLS-1$ @Override public void run() { showGreen = !showGreen; setImageDescriptor(showGreen ? Icons.greenDot.getDescriptor() : Icons.paleGreenDot.getDescriptor()); setToolTipText(showGreen ? Messages.getString("HistogramView.green_tooltip") //$NON-NLS-1$ : Messages.getString("HistogramView.green_off")); //$NON-NLS-1$ trigger = this; refresh(); } }; greenAction.setImageDescriptor( showGreen ? Icons.greenDot.getDescriptor() : Icons.paleGreenDot.getDescriptor()); greenAction.setToolTipText(showGreen ? Messages.getString("HistogramView.green_tooltip") //$NON-NLS-1$ : Messages.getString("HistogramView.green_off")); //$NON-NLS-1$ greenAction.setChecked(showGreen); blueAction = new Action(Messages.getString("HistogramView.blue"), IAction.AS_CHECK_BOX) { //$NON-NLS-1$ @Override public void run() { showBlue = !showBlue; setImageDescriptor(showBlue ? Icons.blueDot.getDescriptor() : Icons.paleBlueDot.getDescriptor()); setToolTipText(showBlue ? Messages.getString("HistogramView.blue_tooltip") //$NON-NLS-1$ : Messages.getString("HistogramView.blue_off")); //$NON-NLS-1$ trigger = this; refresh(); } }; blueAction.setImageDescriptor(showBlue ? Icons.blueDot.getDescriptor() : Icons.paleBlueDot.getDescriptor()); blueAction.setToolTipText(showBlue ? Messages.getString("HistogramView.blue_tooltip") //$NON-NLS-1$ : Messages.getString("HistogramView.blue_off")); //$NON-NLS-1$ blueAction.setChecked(showBlue); greyAction = new Action(Messages.getString("HistogramView.brightness"), IAction.AS_CHECK_BOX) { //$NON-NLS-1$ @Override public void run() { showGrey = !showGrey; setImageDescriptor( showGrey ? Icons.grayscale.getDescriptor() : Icons.paleGrayscale.getDescriptor()); setToolTipText(showGrey ? Messages.getString("HistogramView.brightness_tooltip") //$NON-NLS-1$ : Messages.getString("HistogramView.grey_off")); //$NON-NLS-1$ trigger = this; refresh(); } }; greyAction.setImageDescriptor( showGrey ? Icons.grayscale.getDescriptor() : Icons.paleGrayscale.getDescriptor()); greyAction.setToolTipText(showGrey ? Messages.getString("HistogramView.brightness_tooltip") //$NON-NLS-1$ : Messages.getString("HistogramView.grey_off")); //$NON-NLS-1$ greyAction.setChecked(showGrey); configureAction = new Action(Messages.getString("HistogramView.config_caption")) { //$NON-NLS-1$ @Override public void run() { ConfigureCaptionDialog dialog = new ConfigureCaptionDialog(getSite().getShell(), template, alignment, currentItem); if (dialog.open() == ConfigureCaptionDialog.OK) { template = dialog.getTemplate(); alignment = dialog.getAlignment(); updateCaption(); } } }; configureAction.setToolTipText(Messages.getString("HistogramView.configure_caption_tooltip")); //$NON-NLS-1$ } @Override public void setFocus() { canvas.setFocus(); } public void paintControl(PaintEvent e) { Rectangle clientArea = canvas.getClientArea(); Display display = e.display; GC gc = e.gc; gc.setBackground(display.getSystemColor(SWT.COLOR_WHITE)); gc.fillRectangle(clientArea); int width = clientArea.width; int height = clientArea.height; if (mxvalue > 0) { int gmax = 0; int gavg = 0; int shadows = 0; int highlights = 0; for (int i = 0; i < 256; i++) { greys[i] = (reds[i] * 306 + greens[i] * 601 + blues[i] * 117) >> 10; // 0.299R+0.587G+0.114B gavg += greys[i]; if (i > 0) gmax = Math.max(gmax, greys[i - 1] + greys[i]); } gmax /= 2; gavg /= 256; for (int i = 0; i < 25; i++) shadows = Math.max(shadows, greys[i] + greys[i + 1]); shadows /= 2; for (int i = 230; i < 255; i++) highlights = Math.max(highlights, greys[i] + greys[i + 1]); highlights /= 2; String message = null; if (shadows <= gavg * 0.05) { if (highlights > gavg) message = Messages.getString("HistogramView.overexpose"); //$NON-NLS-1$ else if (highlights < gavg * 0.05) message = Messages.getString("HistogramView.enhance_contrast"); //$NON-NLS-1$ else message = Messages.getString("HistogramView.darken_shadows"); //$NON-NLS-1$ } else if (highlights <= gavg * 0.05) { if (shadows > gavg) message = Messages.getString("HistogramView.underexposed"); //$NON-NLS-1$ else message = Messages.getString("HistogramView.lighten_highlights"); //$NON-NLS-1$ } else if (highlights > gavg && shadows > gavg) message = Messages.getString("HistogramView.compress_contrast"); //$NON-NLS-1$ Transform transform = new Transform(display); transform.translate(0, height); transform.scale(width / 256f, -(float) height / mxvalue); gc.setTransform(transform); if (showGrey) drawCurve(gc, greys, display.getSystemColor( (showRed || showGreen || showBlue) ? SWT.COLOR_DARK_GRAY : SWT.COLOR_BLACK), true, false); if (showRed) drawCurve(gc, reds, display.getSystemColor(SWT.COLOR_RED), !showGrey, true); if (showGreen) drawCurve(gc, greens, display.getSystemColor(SWT.COLOR_GREEN), !showGrey, true); if (showBlue) drawCurve(gc, blues, display.getSystemColor(SWT.COLOR_BLUE), !showGrey, true); gc.setTransform(null); transform.dispose(); if (message != null) { gc.setForeground(gc.getDevice().getSystemColor(SWT.COLOR_DARK_CYAN)); TextLayout textLayout = new TextLayout(gc.getDevice()); textLayout.setText(message); textLayout.draw(gc, width - textLayout.getBounds().width - 10, 15); textLayout.dispose(); } } else { String text = count > 1 ? Messages.getString("HistogramView.multiple_images_selected") //$NON-NLS-1$ : Messages.getString("HistogramView.nothing_selected"); //$NON-NLS-1$ gc.setForeground(display.getSystemColor(SWT.COLOR_DARK_GRAY)); Point tx = gc.textExtent(text); gc.drawText(text, (width - tx.x) / 2, (height - tx.y) / 2, true); } gc.setAlpha(255); gc.setForeground(display.getSystemColor(SWT.COLOR_DARK_GRAY)); gc.drawLine(width / 3, 0, width / 3, height); gc.drawLine(2 * width / 3, 0, 2 * width / 3, height); } private static void drawCurve(GC gc, int[] values, Color color, boolean fill, boolean line) { int[] points = new int[516]; int p = 3; points[p++] = values[0] + values[1] >> 1; for (int i = 1; i < 255; i++) { points[p++] = i; points[p++] = values[i - 1] + (values[i] << 1) + values[i + 1] >> 2; } points[512] = 255; points[513] = values[254] + values[255] >> 1; if (fill) { points[514] = 255; gc.setAlpha(64); gc.setBackground(color); gc.fillPolygon(points); gc.setAlpha(255); } if (line) { gc.setForeground(color); int[] copy = new int[512]; System.arraycopy(points, 2, copy, 0, Math.min(points.length, 512)); gc.drawPolyline(copy); } } @Override public boolean collectionChanged() { return false; } @Override public boolean selectionChanged() { return false; } @Override public boolean assetsChanged() { Asset previous = currentItem; AssetSelection selectedAssets = getNavigationHistory().getSelectedAssets(); count = selectedAssets.size(); currentItem = (count == 1) ? selectedAssets.get(0) : null; if (previous != currentItem) { recalculate(); updateCaption(); return true; } return false; } protected void updateCaption() { if (template.isEmpty()) { if (caption != null) { space.dispose(); caption.dispose(); caption = null; composite.layout(true, true); } } else { if (caption == null) { space = new Label(composite, SWT.NONE); caption = new Label(composite, SWT.NONE); caption.setLayoutData(new GridData(SWT.FILL, SWT.END, true, false)); caption.addMouseListener(new MouseAdapter() { @Override public void mouseUp(MouseEvent e) { configureAction.run(); } }); composite.layout(true, true); } caption.setText(currentItem == null ? "" //$NON-NLS-1$ : Utilities.evaluateTemplate(template, Constants.TH_ALL, "", null, -1, -1, -1, null, //$NON-NLS-1$ currentItem, "", Integer.MAX_VALUE, false, true)); caption.setAlignment(alignment); } } protected void recalculate() { mxvalue = 0; if (currentItem != null) { for (int i = 0; i < 256; i++) reds[i] = greens[i] = blues[i] = 0; ImageData data = getImage(currentItem).getImageData(); PaletteData palette = data.palette; int yinc = 1; int xinc = 1; long size = (long) data.height * data.width; if (size > MINTHUMBNAILSIZE) { yinc = (int) (Math.sqrt(size / (double) MINTHUMBNAILSIZE) + 0.5d); xinc = (int) (size / ((double) MINTHUMBNAILSIZE * yinc)); } if (weighted) { int h1 = data.height * 12 / 100; int h2 = data.height * 30 / 100; int h3 = data.height * 70 / 100; int h4 = data.height * 88 / 100; int w1 = data.width * 12 / 100; int w2 = data.width * 30 / 100; int w3 = data.width * 70 / 100; int w4 = data.width * 88 / 100; for (int y = h1; y < h2; y += yinc) for (int x = w1; x < w4; x += xinc) { RGB rgb = palette.getRGB(data.getPixel(x, y)); ++reds[rgb.red]; ++greens[rgb.green]; ++blues[rgb.blue]; } for (int y = h2; y < h3; y += yinc) { for (int x = w1; x < w2; x += xinc) { RGB rgb = palette.getRGB(data.getPixel(x, y)); ++reds[rgb.red]; ++greens[rgb.green]; ++blues[rgb.blue]; } for (int x = w2; x < w3; x += xinc) { RGB rgb = palette.getRGB(data.getPixel(x, y)); reds[rgb.red] += 2; greens[rgb.green] += 2; blues[rgb.blue] += 2; } for (int x = w3; x < w4; x += xinc) { RGB rgb = palette.getRGB(data.getPixel(x, y)); ++reds[rgb.red]; ++greens[rgb.green]; ++blues[rgb.blue]; } } for (int y = h3; y < h4; y += yinc) for (int x = w1; x < w4; x += xinc) { RGB rgb = palette.getRGB(data.getPixel(x, y)); ++reds[rgb.red]; ++greens[rgb.green]; ++blues[rgb.blue]; } } else for (int y = 0; y < data.height; y += yinc) for (int x = 0; x < data.width; x += xinc) { RGB rgb = palette.getRGB(data.getPixel(x, y)); ++reds[rgb.red]; ++greens[rgb.green]; ++blues[rgb.blue]; } for (int i = 0; i < 255; i++) mxvalue = Math.max(mxvalue, Math.max(reds[i] + reds[i + 1], Math.max(greens[i] + greens[i + 1], blues[i] + blues[i + 1]))); mxvalue /= 2; } } public Control getControl() { return canvas; } @Override public void refresh() { canvas.redraw(); updateActions(false); } @Override public void updateActions(boolean force) { if (redAction != null && (isVisible() || force)) { boolean enabled = mxvalue > 0; redAction.setEnabled(enabled); greenAction.setEnabled(enabled); blueAction.setEnabled(enabled); greyAction.setEnabled(enabled); centerAction.setEnabled(enabled); if (enabled && !showBlue && !showGreen && !showRed && !showGrey) { if (trigger == null || trigger == greyAction) { redAction.run(); greenAction.run(); blueAction.run(); } else greyAction.run(); } updateActions(-1, -1); } } public ISelection getSelection() { return currentItem != null ? new StructuredSelection(currentItem) : StructuredSelection.EMPTY; } public void setSelection(ISelection selection) { // do nothing } @Override protected void updateStatusLine() { // do nothing } }