Java tutorial
/******************************************************************************* * Copyright (C) 2005, 2017 Wolfgang Schramm and Contributors * * This program 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 version 2 of the License. * * 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, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA *******************************************************************************/ package net.tourbook.ui; import java.io.File; import java.io.IOException; import java.net.URL; import java.sql.SQLException; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.time.ZonedDateTime; import java.util.ArrayList; import java.util.Formatter; import java.util.HashMap; import java.util.Set; import net.tourbook.Messages; import net.tourbook.application.TourbookPlugin; import net.tourbook.chart.Chart; import net.tourbook.common.color.MapGraphId; import net.tourbook.common.util.StatusUtil; import net.tourbook.common.util.Util; import net.tourbook.data.TourData; import net.tourbook.data.TourTag; import net.tourbook.data.TourType; import net.tourbook.database.TourDatabase; import net.tourbook.preferences.ITourbookPreferences; import net.tourbook.tour.SelectionTourId; import net.tourbook.tour.SelectionTourIds; import net.tourbook.tour.TourEvent; import net.tourbook.tour.TourManager; import net.tourbook.tour.filter.TourFilterManager; import net.tourbook.tour.photo.TourPhotoLinkView; import net.tourbook.ui.views.tourDataEditor.TourDataEditorView; import net.tourbook.web.WEB; import org.eclipse.core.runtime.FileLocator; import org.eclipse.jface.dialogs.IDialogConstants; import org.eclipse.jface.dialogs.MessageDialog; import org.eclipse.jface.layout.GridDataFactory; import org.eclipse.jface.layout.GridLayoutFactory; import org.eclipse.jface.layout.PixelConverter; import org.eclipse.jface.preference.IPreferenceStore; import org.eclipse.jface.preference.PreferenceConverter; import org.eclipse.jface.resource.ColorRegistry; import org.eclipse.jface.resource.ImageDescriptor; import org.eclipse.jface.resource.ImageRegistry; import org.eclipse.jface.resource.JFaceResources; import org.eclipse.jface.viewers.ColumnPixelData; import org.eclipse.jface.viewers.StyledString; import org.eclipse.jface.viewers.StyledString.Styler; import org.eclipse.osgi.util.NLS; import org.eclipse.swt.SWT; import org.eclipse.swt.custom.CLabel; import org.eclipse.swt.graphics.Color; import org.eclipse.swt.graphics.GC; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.graphics.ImageData; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; 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.swt.widgets.Shell; import org.eclipse.swt.widgets.Text; import org.eclipse.ui.IWorkbenchWindow; import org.eclipse.ui.PlatformUI; import org.eclipse.ui.forms.widgets.FormToolkit; public class UI { // long startTime = System.currentTimeMillis(); // long endTime = System.currentTimeMillis(); // System.out.println("Execution time : " + (endTime - startTime) + " ms"); // SET_FORMATTING_OFF public static final boolean IS_LINUX = "gtk".equals(SWT.getPlatform()); //$NON-NLS-1$ public static final boolean IS_OSX = "carbon".equals(SWT.getPlatform()) || //$NON-NLS-1$ "cocoa".equals(SWT.getPlatform()); //$NON-NLS-1$ public static final boolean IS_WIN = "win32".equals(SWT.getPlatform()) || //$NON-NLS-1$ "wpf".equals(SWT.getPlatform()); //$NON-NLS-1$ // SET_FORMATTING_ON private static final String ICONS_PATH = "/icons/"; //$NON-NLS-1$ public static final String EMPTY_STRING = ""; //$NON-NLS-1$ public static final String SPACE = " "; //$NON-NLS-1$ public static final String SPACE2 = " "; //$NON-NLS-1$ public static final String SPACE4 = " "; //$NON-NLS-1$ public static final String COLON_SPACE = ": "; //$NON-NLS-1$ public static final String COMMA_SPACE = ", "; //$NON-NLS-1$ public static final String UNDERSCORE = "_"; //$NON-NLS-1$ public static final String DASH = "-"; //$NON-NLS-1$ public static final String DASH_WITH_SPACE = " - "; //$NON-NLS-1$ public static final String DASH_WITH_DOUBLE_SPACE = " - "; //$NON-NLS-1$ public static final String SLASH_WITH_SPACE = " / "; //$NON-NLS-1$ public static final String EMPTY_STRING_FORMAT = "%s"; //$NON-NLS-1$ public static final String MNEMONIC = "&"; //$NON-NLS-1$ public static final String BREAK_TIME_MARKER = "x"; //$NON-NLS-1$ /** * contains a new line */ public static final String NEW_LINE = "\n"; //$NON-NLS-1$ /** * contains 2 new lines */ public static final String NEW_LINE2 = "\n\n"; //$NON-NLS-1$ public static final String SYSTEM_NEW_LINE = System.getProperty("line.separator"); //$NON-NLS-1$ public static final String IS_NOT_INITIALIZED = "IS NOT INITIALIZED"; //$NON-NLS-1$ public static final String GRAPH_ALTIMETER = "GRAPH_ALTIMETER"; //$NON-NLS-1$ public static final String GRAPH_ALTITUDE = "GRAPH_ALTITUDE"; //$NON-NLS-1$ public static final String GRAPH_CADENCE = "GRAPH_CADENCE"; //$NON-NLS-1$ public static final String GRAPH_GRADIENT = "GRAPH_GRADIENT"; //$NON-NLS-1$ public static final String GRAPH_PACE = "GRAPH_PACE"; //$NON-NLS-1$ public static final String GRAPH_POWER = "GRAPH_POWER"; //$NON-NLS-1$ public static final String GRAPH_PULSE = "GRAPH_PULSE"; //$NON-NLS-1$ public static final String GRAPH_SPEED = "GRAPH_SPEED"; //$NON-NLS-1$ public static final String GRAPH_TEMPERATURE = "GRAPH_TEMPERATURE"; //$NON-NLS-1$ public static final String VIEW_COLOR_CATEGORY = "view.color.category"; //$NON-NLS-1$ public static final String VIEW_COLOR_TITLE = "view.color.title"; //$NON-NLS-1$ public static final String VIEW_COLOR_SUB = "view.color.sub"; //$NON-NLS-1$ public static final String VIEW_COLOR_SUB_SUB = "view.color.sub-sub"; //$NON-NLS-1$ public static final String VIEW_COLOR_TOUR = "view.color.tour"; //$NON-NLS-1$ public static final String VIEW_COLOR_BG_HISTORY_TOUR = "VIEW_COLOR_BG_HISTORY_TOUR"; //$NON-NLS-1$ public static final String SYMBOL_AVERAGE = "\u00f8"; //$NON-NLS-1$ public static final String SYMBOL_AVERAGE_WITH_SPACE = "\u00f8 "; //$NON-NLS-1$ public static final String SYMBOL_DASH = "-"; //$NON-NLS-1$ public static final String SYMBOL_DOUBLE_HORIZONTAL = "\u2550"; //$NON-NLS-1$ public static final String SYMBOL_DOUBLE_VERTICAL = "\u2551"; //$NON-NLS-1$ public static final String SYMBOL_DEGREE = "\u00B0"; //$NON-NLS-1$ public static final String SYMBOL_INFINITY = "\u221E"; //$NON-NLS-1$ public static final String SYMBOL_SUM_WITH_SPACE = "\u2211 "; //$NON-NLS-1$ public static final String SYMBOL_TAU = "\u03c4"; //$NON-NLS-1$ public static final String SYMBOL_BRACKET_LEFT = "("; //$NON-NLS-1$ public static final String SYMBOL_BRACKET_RIGHT = ")"; //$NON-NLS-1$ public static final String SYMBOL_COLON = ":"; //$NON-NLS-1$ public static final String SYMBOL_DOT = "."; //$NON-NLS-1$ public static final String SYMBOL_EQUAL = "="; //$NON-NLS-1$ public static final String SYMBOL_GREATER_THAN = ">"; //$NON-NLS-1$ public static final String SYMBOL_LESS_THAN = "<"; //$NON-NLS-1$ public static final String SYMBOL_PERCENTAGE = "%"; //$NON-NLS-1$ public static final String SYMBOL_WIND_WITH_SPACE = "W "; //$NON-NLS-1$ public static final String SYMBOL_EXCLAMATION_POINT = "!"; //$NON-NLS-1$ /** * Convert Joule in Calorie * <p> * 1 cal = 4.1868 J<br> * 1 J = 0.238846 cal */ public static final float UNIT_CALORIE_2_JOULE = 4.1868f; /** * Convert Calorie to Joule * <p> * 1 cal = 4.1868 J<br> * 1 J = 0.238846 cal */ public static final float UNIT_JOULE_2_CALORY = 1.0f / 4.1868f; /** * Imperial system for distance */ public static final float UNIT_MILE = 1.609344f; /** * Imperial system for small distance, 1 yard = 3 feet = 36 inches = 0,9144 Meter */ public static final float UNIT_YARD = 0.9144f; /** * Imperial system for height */ public static final float UNIT_FOOT = 0.3048f; /** * contains the system of measurement value for distances relative to the metric system, the * metric system is <code>1</code> */ public static float UNIT_VALUE_DISTANCE = 1; /** * contains the system of measurement value for small distances relative to the metric system, * the metric system is <code>1</code> */ public static float UNIT_VALUE_DISTANCE_SMALL = 1; /** * contains the system of measurement value for altitudes relative to the metric system, the * metric system is <code>1</code> */ public static float UNIT_VALUE_ALTITUDE = 1; /** * contains the system of measurement value for the temperature, is set to <code>1</code> for * the metric system */ public static float UNIT_VALUE_TEMPERATURE = 1; /** * Contains the system of measurement value for the power, is set to <code>1</code> for the * metric system Watt/Kg. */ public static float UNIT_VALUE_POWER; // (Celcius * 9/5) + 32 = Fahrenheit public static final float UNIT_FAHRENHEIT_MULTI = 1.8f; public static final float UNIT_FAHRENHEIT_ADD = 32; private static final String TOUR_TYPE_PREFIX = "tourType"; //$NON-NLS-1$ public final static ImageRegistry IMAGE_REGISTRY; private static final String PART_NAME_GRAPH_ID = "graphId-"; //$NON-NLS-1$ private static final String PART_NAME_DISABLED = "-disabled"; //$NON-NLS-1$ public static final String IMAGE_TOUR_TYPE_FILTER = "tourType-filter"; //$NON-NLS-1$ public static final String IMAGE_TOUR_TYPE_FILTER_SYSTEM = "tourType-filter-system"; //$NON-NLS-1$ private static UI instance; private static StringBuilder _formatterSB = new StringBuilder(); private static Formatter _formatter = new Formatter(_formatterSB); private static DateFormat _dateFormatterShort; private static DateFormat _timeFormatterShort; public static Styler TAG_STYLER; public static Styler TAG_CATEGORY_STYLER; public static Styler TAG_SUB_STYLER; private final static HashMap<String, Image> _imageCache = new HashMap<String, Image>(); private final static HashMap<String, ImageDescriptor> _imageCacheDescriptor = new HashMap<String, ImageDescriptor>(); private final static HashMap<String, Boolean> _dirtyImages = new HashMap<String, Boolean>(); static { updateUnits(); setViewColorsFromPrefStore(); /* * load often used images into the image registry */ IMAGE_REGISTRY = TourbookPlugin.getDefault().getImageRegistry(); /* * Chart and map graphs. */ createGraphImageInRegistry(MapGraphId.Altimeter, Messages.Image__graph_altimeter, Messages.Image__graph_altimeter_disabled); createGraphImageInRegistry(MapGraphId.Altitude, Messages.Image__graph_altitude, Messages.Image__graph_altitude_disabled); createGraphImageInRegistry(MapGraphId.Cadence, Messages.Image__graph_cadence, Messages.Image__graph_cadence_disabled); createGraphImageInRegistry(MapGraphId.Gradient, Messages.Image__graph_gradient, Messages.Image__graph_gradient_disabled); createGraphImageInRegistry(MapGraphId.HrZone, // Messages.Image__PulseZones, Messages.Image__PulseZones_Disabled); createGraphImageInRegistry(MapGraphId.Pace, // Messages.Image__graph_pace, Messages.Image__graph_pace_disabled); createGraphImageInRegistry(MapGraphId.Power, // Messages.Image__graph_power, Messages.Image__graph_power_disabled); createGraphImageInRegistry(MapGraphId.Pulse, Messages.Image__graph_heartbeat, Messages.Image__graph_heartbeat_disabled); createGraphImageInRegistry(MapGraphId.Speed, // Messages.Image__graph_speed, Messages.Image__graph_speed_disabled); createGraphImageInRegistry(MapGraphId.Temperature, Messages.Image__graph_temperature, Messages.Image__graph_temperature_disabled); // tour type images IMAGE_REGISTRY.put(IMAGE_TOUR_TYPE_FILTER, TourbookPlugin.getImageDescriptor(Messages.Image__undo_tour_type_filter)); IMAGE_REGISTRY.put(IMAGE_TOUR_TYPE_FILTER_SYSTEM, TourbookPlugin.getImageDescriptor(Messages.Image__undo_tour_type_filter_system)); // photo IMAGE_REGISTRY.put(TourPhotoLinkView.IMAGE_PIC_DIR_VIEW, TourbookPlugin.getImageDescriptor(Messages.Image__PhotoDirectoryView)); IMAGE_REGISTRY.put(TourPhotoLinkView.IMAGE_PHOTO_PHOTO, TourbookPlugin.getImageDescriptor(Messages.Image__PhotoPhotos)); /* * set tag styler */ TAG_CATEGORY_STYLER = StyledString.createColorRegistryStyler(VIEW_COLOR_CATEGORY, null); TAG_STYLER = StyledString.createColorRegistryStyler(VIEW_COLOR_TITLE, null); TAG_SUB_STYLER = StyledString.createColorRegistryStyler(VIEW_COLOR_SUB, null); } private UI() { } /** * Change the title for the application * * @param newTitle * new title for the application or <code>null</code> to set the original title */ public static void changeAppTitle(final String newTitle) { final Display display = Display.getDefault(); if (display != null) { // Look at all the shells and pick the first one that is a workbench window. final Shell shells[] = display.getShells(); for (final Shell shell : shells) { final Object data = shell.getData(); // Check whether this shell points to the Application main window's shell: if (data instanceof IWorkbenchWindow) { String title; if (newTitle == null) { title = Messages.App_Title; } else { title = newTitle; } shell.setText(title); break; } } } } /** * @param file * @return Returns <code>true</code> when the file should be overwritten, otherwise * <code>false</code> */ public static boolean confirmOverwrite(final File file) { final Shell shell = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell(); final MessageDialog dialog = new MessageDialog(// shell, Messages.app_dlg_confirmFileOverwrite_title, null, NLS.bind(Messages.app_dlg_confirmFileOverwrite_message, file.getPath()), MessageDialog.QUESTION, new String[] { IDialogConstants.YES_LABEL, IDialogConstants.CANCEL_LABEL }, 0); dialog.open(); return dialog.getReturnCode() == 0; } public static boolean confirmOverwrite(final FileCollisionBehavior fileCollision, final File file) { final boolean[] isOverwrite = { false }; final int fileCollisionValue = fileCollision.value; if (fileCollisionValue == FileCollisionBehavior.REPLACE_ALL) { // overwrite is already confirmed isOverwrite[0] = true; } else if (fileCollisionValue == FileCollisionBehavior.ASK || fileCollisionValue == FileCollisionBehavior.REPLACE || fileCollisionValue == FileCollisionBehavior.KEEP) { Display.getDefault().syncExec(new Runnable() { @Override public void run() { final Shell shell = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell(); final MessageDialog dialog = new MessageDialog(// shell, Messages.app_dlg_confirmFileOverwrite_title, null, NLS.bind(Messages.app_dlg_confirmFileOverwrite_message, file.getPath()), MessageDialog.QUESTION, new String[] { IDialogConstants.YES_LABEL, IDialogConstants.YES_TO_ALL_LABEL, IDialogConstants.NO_LABEL, IDialogConstants.NO_TO_ALL_LABEL, IDialogConstants.CANCEL_LABEL }, 0); dialog.open(); final int returnCode = dialog.getReturnCode(); switch (returnCode) { case -1: // dialog was canceled case 4: fileCollision.value = FileCollisionBehavior.DIALOG_IS_CANCELED; break; case 0: // YES fileCollision.value = FileCollisionBehavior.REPLACE; isOverwrite[0] = true; break; case 1: // YES_TO_ALL fileCollision.value = FileCollisionBehavior.REPLACE_ALL; isOverwrite[0] = true; break; case 2: // NO fileCollision.value = FileCollisionBehavior.KEEP; break; case 3: // NO_TO_ALL fileCollision.value = FileCollisionBehavior.KEEP_ALL; break; default: break; } } }); } return isOverwrite[0]; } /** * Checks if tour id is contained in the property data * * @param propertyData * @param checkedTourId * @return Returns the tour id when it is contained in the property data, otherwise it returns * <code>null</code> */ public static Long containsTourId(final Object propertyData, final long checkedTourId) { Long containedTourId = null; if (propertyData instanceof SelectionTourId) { final Long tourId = ((SelectionTourId) propertyData).getTourId(); if (checkedTourId == tourId) { containedTourId = tourId; } } else if (propertyData instanceof SelectionTourIds) { for (final Long tourId : ((SelectionTourIds) propertyData).getTourIds()) { if (checkedTourId == tourId) { containedTourId = tourId; break; } } } else if (propertyData instanceof TourEvent) { final TourEvent tourEvent = (TourEvent) propertyData; final ArrayList<TourData> modifiedTours = tourEvent.getModifiedTours(); if (modifiedTours != null) { for (final TourData tourData : modifiedTours) { if (tourData.getTourId().longValue() == checkedTourId) { containedTourId = checkedTourId; break; } } } } return containedTourId; } /** * Get text for the OK button. * * @param tourData * @return */ public static String convertOKtoSaveUpdateButton(final TourData tourData) { String okText = null; final TourDataEditorView tourDataEditor = TourManager.getTourDataEditor(); if ((tourDataEditor != null) && tourDataEditor.isDirty() && (tourDataEditor.getTourData() == tourData)) { okText = Messages.app_action_update; } else { okText = Messages.app_action_save; } return okText; } private static String createGraphImage_Name(final MapGraphId graphId) { return PART_NAME_GRAPH_ID + graphId.name(); } private static String createGraphImage_NameDisabled(final MapGraphId graphId) { return PART_NAME_GRAPH_ID + graphId.name() + PART_NAME_DISABLED; } private static void createGraphImageInRegistry(final MapGraphId graphId, final String graphImageName, final String graphImageNameDisabled) { // create enabled image IMAGE_REGISTRY.put(createGraphImage_Name(graphId), // TourbookPlugin.getImageDescriptor(graphImageName)); // create disabled image IMAGE_REGISTRY.put(createGraphImage_NameDisabled(graphId), TourbookPlugin.getImageDescriptor(graphImageNameDisabled)); } /** * Creates a page with a static text. * * @param formToolkit * @param parent * @param labelText * @return */ public static Composite createPage(final FormToolkit formToolkit, final Composite parent, final String labelText) { final Composite container = formToolkit.createComposite(parent); GridDataFactory.fillDefaults().grab(true, false).applyTo(container); GridLayoutFactory.swtDefaults().numColumns(1).applyTo(container); { final Label label = formToolkit.createLabel(container, labelText, SWT.WRAP); GridDataFactory.fillDefaults().grab(true, false).applyTo(label); } return container; } /** * Disables all controls and their children */ public static void disableAllControls(final Composite container) { disableAllControlsInternal(container); // !!! force controls (text,combo...) to be updated !!! container.update(); } /** * !!!!!!!!!!!!!!! RECURSIVE !!!!!!!!!!!!!!!!!! */ private static void disableAllControlsInternal(final Composite container) { for (final Control child : container.getChildren()) { if (child instanceof Composite) { disableAllControlsInternal((Composite) child); } child.setEnabled(false); } } public static String format_yyyymmdd_hhmmss(final TourData tourData) { if (tourData == null) { return UI.EMPTY_STRING; } _formatterSB.setLength(0); final ZonedDateTime dt = tourData.getTourStartTime(); return _formatter.format(// Messages.Format_yyyymmdd_hhmmss, dt.getYear(), dt.getMonthValue(), dt.getDayOfMonth(), dt.getHour(), dt.getMinute(), dt.getSecond())// .toString(); } public static ColumnPixelData getColumnPixelWidth(final PixelConverter pixelConverter, final int width) { return new ColumnPixelData(pixelConverter.convertWidthInCharsToPixels(width), false); } /****************************************************************************** * this method is copied from the following source and was adjusted * * <pre> * Product: Compiere ERP & CRM Smart Business Solution * * Copyright (C) 1999-2006 ComPiere, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * * under the terms version 2 of the GNU General Public License 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, write to the Free Software Foundation, Inc., * * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. * * For the text or an alternative of this public license, you may reach us * * ComPiere, Inc., 2620 Augustine Dr. #245, Santa Clara, CA 95054, USA * * or via info@compiere.org or http://www.compiere.org/license.html * * </pre> * * @return date formatter with leading zeros for month and day and 4-digit year */ public static DateFormat getFormatterDateShort() { if (_dateFormatterShort == null) { final DateFormat dateInstance = DateFormat.getDateInstance(DateFormat.SHORT); if (dateInstance instanceof SimpleDateFormat) { final SimpleDateFormat sdf = (SimpleDateFormat) (_dateFormatterShort = dateInstance); String oldPattern = sdf.toPattern(); // some short formats have only one M and d (e.g. ths US) if (oldPattern.indexOf("MM") == -1 && oldPattern.indexOf("dd") == -1) {//$NON-NLS-1$ //$NON-NLS-2$ String newPattern = UI.EMPTY_STRING; for (int i = 0; i < oldPattern.length(); i++) { if (oldPattern.charAt(i) == 'M') { newPattern += "MM"; //$NON-NLS-1$ } else if (oldPattern.charAt(i) == 'd') { newPattern += "dd"; //$NON-NLS-1$ } else { newPattern += oldPattern.charAt(i); } } sdf.applyPattern(newPattern); } // Unknown short format => use JDBC if (sdf.toPattern().length() != 8) { sdf.applyPattern("yyyy-MM-dd"); //$NON-NLS-1$ } // 4 digit year if (sdf.toPattern().indexOf("yyyy") == -1) { //$NON-NLS-1$ oldPattern = sdf.toPattern(); String newPattern = UI.EMPTY_STRING; for (int i = 0; i < oldPattern.length(); i++) { if (oldPattern.charAt(i) == 'y') { newPattern += "yy"; //$NON-NLS-1$ } else { newPattern += oldPattern.charAt(i); } } sdf.applyPattern(newPattern); } sdf.setLenient(true); } } return _dateFormatterShort; } /****************************************************************************** * this method is copied from the following source and was adjusted * * <pre> * Product: Compiere ERP & CRM Smart Business Solution * * Copyright (C) 1999-2006 ComPiere, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * * under the terms version 2 of the GNU General Public License 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, write to the Free Software Foundation, Inc., * * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. * * For the text or an alternative of this public license, you may reach us * * ComPiere, Inc., 2620 Augustine Dr. #245, Santa Clara, CA 95054, USA * * or via info@compiere.org or http://www.compiere.org/license.html * * </pre> * * @return date formatter with leading zeros for month and day and 4-digit year */ public static DateFormat getFormatterTimeShort() { if (_timeFormatterShort == null) { final DateFormat timeInstance = DateFormat.getTimeInstance(DateFormat.SHORT); if (timeInstance instanceof SimpleDateFormat) { final SimpleDateFormat sdf = (SimpleDateFormat) (_timeFormatterShort = timeInstance); final String oldPattern = sdf.toPattern(); // some short formats have only one h (e.g. ths US) if (oldPattern.indexOf("hh") == -1) {//$NON-NLS-1$ String newPattern = UI.EMPTY_STRING; for (int i = 0; i < oldPattern.length(); i++) { if (oldPattern.charAt(i) == 'h') { newPattern += "hh"; //$NON-NLS-1$ } else { newPattern += oldPattern.charAt(i); } } sdf.applyPattern(newPattern); } sdf.setLenient(true); } } return _timeFormatterShort; } /** * @param graphId * @return Returns a graph image, this image <b>MUST</b> not be disposed. */ public static Image getGraphImage(final MapGraphId graphId) { return IMAGE_REGISTRY.get(createGraphImage_Name(graphId)); } public static ImageDescriptor getGraphImageDescriptor(final MapGraphId graphId) { switch (graphId) { case Altitude: return TourbookPlugin.getImageDescriptor(Messages.Image__graph_altitude); case Gradient: return TourbookPlugin.getImageDescriptor(Messages.Image__graph_gradient); case Pace: return TourbookPlugin.getImageDescriptor(Messages.Image__graph_pace); case Pulse: return TourbookPlugin.getImageDescriptor(Messages.Image__graph_heartbeat); case Speed: return TourbookPlugin.getImageDescriptor(Messages.Image__graph_speed); case HrZone: return TourbookPlugin.getImageDescriptor(Messages.Image__PulseZones); default: return TourbookPlugin.getImageDescriptor(Messages.Image__graph_altitude); } } public static ImageDescriptor getGraphImageDescriptorDisabled(final MapGraphId graphId) { switch (graphId) { case Altitude: return TourbookPlugin.getImageDescriptor(Messages.Image__graph_altitude_disabled); case Gradient: return TourbookPlugin.getImageDescriptor(Messages.Image__graph_gradient_disabled); case Pace: return TourbookPlugin.getImageDescriptor(Messages.Image__graph_pace_disabled); case Pulse: return TourbookPlugin.getImageDescriptor(Messages.Image__graph_heartbeat_disabled); case Speed: return TourbookPlugin.getImageDescriptor(Messages.Image__graph_speed_disabled); case HrZone: return TourbookPlugin.getImageDescriptor(Messages.Image__PulseZones_Disabled); default: return TourbookPlugin.getImageDescriptor(Messages.Image__graph_altitude_disabled); } } /** * @param graphId * @return Returns a graph image, this image <b>MUST</b> not be disposed. */ public static Image getGraphImageDisabled(final MapGraphId graphId) { return IMAGE_REGISTRY.get(createGraphImage_NameDisabled(graphId)); } /** * @param imageName * @return Returns the url for an icon image in the {@link TourbookPlugin} bundle. * @throws IOException */ public static String getIconUrl(final String imageName) { try { final URL bundleUrl = TourbookPlugin.getDefault().getBundle().getEntry(ICONS_PATH + imageName); final URL fileUrl = FileLocator.toFileURL(bundleUrl); final String encodedFileUrl = WEB.encodeSpace(fileUrl.toExternalForm()); return encodedFileUrl; } catch (final IOException e) { StatusUtil.log(e); } return EMPTY_STRING; } public static UI getInstance() { if (instance == null) { instance = new UI(); } return instance; } /** * Checks if propertyData has the same tour as the oldTourData * * @param propertyData * @param oldTourData * @return Returns {@link TourData} from the propertyData or <code>null</code> when it's another * tour */ public static TourData getTourPropertyTourData(final TourEvent propertyData, final TourData oldTourData) { final ArrayList<TourData> modifiedTours = propertyData.getModifiedTours(); if (modifiedTours == null) { return null; } final long oldTourId = oldTourData.getTourId(); for (final TourData tourData : modifiedTours) { if (tourData.getTourId() == oldTourId) { // nothing more to do, only one tour is supported return tourData; } } return null; } /** * @param tourTypeId * @return Returns the {@link TourType} or <code>null</code>. */ public static TourType getTourType(final long tourTypeId) { for (final TourType tourType : TourDatabase.getAllTourTypes()) { if (tourType.getTypeId() == tourTypeId) { return tourType; } } return null; } /** * @param tourTypeId * @return Returns the name of a {@link TourType}. */ public static String getTourTypeLabel(final long tourTypeId) { for (final TourType tourType : TourDatabase.getAllTourTypes()) { if (tourType.getTypeId() == tourTypeId) { return tourType.getName(); } } return UI.EMPTY_STRING; } public static ImageData rotate(final ImageData srcData, final int direction) { final int bytesPerPixel = srcData.bytesPerLine / srcData.width; final int destBytesPerLine = (direction == SWT.DOWN) ? srcData.width * bytesPerPixel : srcData.height * bytesPerPixel; final byte[] newData = new byte[srcData.data.length]; int width = 0, height = 0; for (int srcY = 0; srcY < srcData.height; srcY++) { for (int srcX = 0; srcX < srcData.width; srcX++) { int destX = 0, destY = 0, destIndex = 0, srcIndex = 0; switch (direction) { case SWT.LEFT: // left 90 degrees destX = srcY; destY = srcData.width - srcX - 1; width = srcData.height; height = srcData.width; break; case SWT.RIGHT: // right 90 degrees destX = srcData.height - srcY - 1; destY = srcX; width = srcData.height; height = srcData.width; break; case SWT.DOWN: // 180 degrees destX = srcData.width - srcX - 1; destY = srcData.height - srcY - 1; width = srcData.width; height = srcData.height; break; } destIndex = (destY * destBytesPerLine) + (destX * bytesPerPixel); srcIndex = (srcY * srcData.bytesPerLine) + (srcX * bytesPerPixel); System.arraycopy(srcData.data, srcIndex, newData, destIndex, bytesPerPixel); } } // destBytesPerLine is used as scanlinePad to ensure that no padding is required return new ImageData(width, height, srcData.depth, srcData.palette, destBytesPerLine, newData); } /** * Set grid layout with no margins for a composite * * @param composite */ public static void set0GridLayout(final Composite composite) { final GridLayout gridLayout = new GridLayout(); gridLayout.marginHeight = 0; gridLayout.marginWidth = 0; gridLayout.verticalSpacing = 0; composite.setLayout(gridLayout); } public static void setDefaultColor(final Control control) { control.setForeground(Display.getCurrent().getSystemColor(SWT.COLOR_WIDGET_FOREGROUND)); control.setBackground(null); } public static void setErrorColor(final Text control) { control.setBackground(Display.getCurrent().getSystemColor(SWT.COLOR_RED)); control.setForeground(Display.getCurrent().getSystemColor(SWT.COLOR_WHITE)); } public static void setHorizontalSpacer(final Composite parent, final int columns) { final Label label = new Label(parent, SWT.NONE); final GridData gd = new GridData(); gd.horizontalSpan = columns; label.setLayoutData(gd); } /** * Set tag colors in the JFace color registry from the pref store */ public static void setViewColorsFromPrefStore() { // pref store var cannot be set from a static field because it can be null !!! final IPreferenceStore prefStore = TourbookPlugin.getDefault().getPreferenceStore(); final ColorRegistry colorRegistry = JFaceResources.getColorRegistry(); colorRegistry.put(VIEW_COLOR_CATEGORY, // PreferenceConverter.getColor(prefStore, ITourbookPreferences.VIEW_LAYOUT_COLOR_CATEGORY)); colorRegistry.put(VIEW_COLOR_TITLE, // PreferenceConverter.getColor(prefStore, ITourbookPreferences.VIEW_LAYOUT_COLOR_TITLE)); colorRegistry.put(VIEW_COLOR_SUB, // year PreferenceConverter.getColor(prefStore, ITourbookPreferences.VIEW_LAYOUT_COLOR_SUB)); colorRegistry.put(VIEW_COLOR_SUB_SUB, // month PreferenceConverter.getColor(prefStore, ITourbookPreferences.VIEW_LAYOUT_COLOR_SUB_SUB)); colorRegistry.put(VIEW_COLOR_TOUR, // PreferenceConverter.getColor(prefStore, ITourbookPreferences.VIEW_LAYOUT_COLOR_TOUR)); colorRegistry.put(VIEW_COLOR_BG_HISTORY_TOUR, // PreferenceConverter.getColor(prefStore, ITourbookPreferences.VIEW_LAYOUT_COLOR_BG_HISTORY_TOUR)); } public static GridData setWidth(final Control control, final int width) { final GridData gd = new GridData(); gd.widthHint = width; control.setLayoutData(gd); return gd; } public static void showMessageInfo(final String title, final String message) { Display.getDefault().asyncExec(new Runnable() { @Override public void run() { MessageDialog.openInformation(Display.getDefault().getActiveShell(), title, message); } }); } public static void showSQLException(final SQLException ex) { Display.getDefault().asyncExec(new Runnable() { @Override public void run() { SQLException e = ex; while (e != null) { final String sqlExceptionText = Util.getSQLExceptionText(e); // log also the stacktrace StatusUtil.log(sqlExceptionText + Util.getStackTrace(e)); MessageDialog.openError(Display.getDefault().getActiveShell(), // "SQL Error", //$NON-NLS-1$ sqlExceptionText); e = e.getNextException(); } } }); } /** * Update properties for the chart from the pref store. * * @param chart * @param gridPrefix * Pref store prefix for grid preferences. */ public static void updateChartProperties(final Chart chart, final String gridPrefix) { if (chart == null) { return; } final IPreferenceStore prefStore = TourbookPlugin.getPrefStore(); chart.updateProperties( Util.getPrefixPrefInt(prefStore, gridPrefix, ITourbookPreferences.CHART_GRID_HORIZONTAL_DISTANCE), Util.getPrefixPrefInt(prefStore, gridPrefix, ITourbookPreferences.CHART_GRID_VERTICAL_DISTANCE), Util.getPrefixPrefBoolean(prefStore, gridPrefix, ITourbookPreferences.CHART_GRID_IS_SHOW_HORIZONTAL_GRIDLINES), Util.getPrefixPrefBoolean(prefStore, gridPrefix, ITourbookPreferences.CHART_GRID_IS_SHOW_VERTICAL_GRIDLINES), prefStore.getBoolean(ITourbookPreferences.GRAPH_IS_SEGMENT_ALTERNATE_COLOR), PreferenceConverter.getColor(prefStore, ITourbookPreferences.GRAPH_SEGMENT_ALTERNATE_COLOR)); } public static void updateUI_Tags(final TourData tourData, final Label tourTagLabel) { // tour tags final Set<TourTag> tourTags = tourData.getTourTags(); if (tourTags == null || tourTags.size() == 0) { tourTagLabel.setText(UI.EMPTY_STRING); } else { final String tagLabels = TourDatabase.getTagNames(tourTags); tourTagLabel.setText(tagLabels); tourTagLabel.setToolTipText(tagLabels); } // tourTagLabel.pack(true); } /** * Sets the tour type image and text into a {@link CLabel} * * @param tourData * @param lblTourType * @param isTextDisplayed */ public static void updateUI_TourType(final TourData tourData, final CLabel lblTourType, final boolean isTextDisplayed) { final TourType tourType = tourData.getTourType(); // tour type if (tourType == null) { lblTourType.setText(UI.EMPTY_STRING); lblTourType.setImage(UI.getInstance().getTourTypeImage(TourDatabase.ENTITY_IS_NOT_SAVED)); } else { lblTourType.setImage(UI.getInstance().getTourTypeImage(tourType.getTypeId())); lblTourType.setText(isTextDisplayed ? tourType.getName() : UI.EMPTY_STRING); } lblTourType.pack(true); lblTourType.redraw(); // display changed tour image } /** * update units from the pref store into the application variables */ public static void updateUnits() { // pref store var cannot be set from a static field because it can be null !!! final IPreferenceStore prefStore = TourbookPlugin.getDefault().getPreferenceStore(); /* * distance */ if (prefStore.getString(ITourbookPreferences.MEASUREMENT_SYSTEM_DISTANCE).equals(// ITourbookPreferences.MEASUREMENT_SYSTEM_DISTANCE_MI)) { // set imperial measure system UNIT_VALUE_DISTANCE = UNIT_MILE; UNIT_VALUE_DISTANCE_SMALL = UNIT_YARD; net.tourbook.common.UI.UNIT_LABEL_DISTANCE = net.tourbook.common.UI.UNIT_DISTANCE_MI; net.tourbook.common.UI.UNIT_LABEL_DISTANCE_SMALL = net.tourbook.common.UI.UNIT_DISTANCE_YARD; net.tourbook.common.UI.UNIT_LABEL_SPEED = net.tourbook.common.UI.UNIT_SPEED_MPH; net.tourbook.common.UI.UNIT_LABEL_PACE = net.tourbook.common.UI.UNIT_PACE_MIN_P_MILE; } else { // default is the metric measure system UNIT_VALUE_DISTANCE = 1; UNIT_VALUE_DISTANCE_SMALL = 1; net.tourbook.common.UI.UNIT_LABEL_DISTANCE = net.tourbook.common.UI.UNIT_DISTANCE_KM; net.tourbook.common.UI.UNIT_LABEL_DISTANCE_SMALL = net.tourbook.common.UI.UNIT_METER; net.tourbook.common.UI.UNIT_LABEL_SPEED = net.tourbook.common.UI.UNIT_SPEED_KM_H; net.tourbook.common.UI.UNIT_LABEL_PACE = net.tourbook.common.UI.UNIT_PACE_MIN_P_KM; } /* * altitude */ if (prefStore.getString(ITourbookPreferences.MEASUREMENT_SYSTEM_ALTITUDE).equals(// ITourbookPreferences.MEASUREMENT_SYSTEM_ALTITUDE_FOOT)) { // set imperial measure system UNIT_VALUE_ALTITUDE = UNIT_FOOT; net.tourbook.common.UI.UNIT_LABEL_ALTITUDE = net.tourbook.common.UI.UNIT_ALTITUDE_FT; net.tourbook.common.UI.UNIT_LABEL_ALTIMETER = net.tourbook.common.UI.UNIT_ALTIMETER_FT_H; } else { // default is the metric measure system UNIT_VALUE_ALTITUDE = 1; net.tourbook.common.UI.UNIT_LABEL_ALTITUDE = net.tourbook.common.UI.UNIT_ALTITUDE_M; net.tourbook.common.UI.UNIT_LABEL_ALTIMETER = net.tourbook.common.UI.UNIT_ALTIMETER_M_H; } /* * temperature */ if (prefStore.getString(ITourbookPreferences.MEASUREMENT_SYSTEM_TEMPERATURE).equals(// ITourbookPreferences.MEASUREMENT_SYSTEM_TEMPTERATURE_F)) { // set imperial measure system UNIT_VALUE_TEMPERATURE = UNIT_FAHRENHEIT_ADD; net.tourbook.common.UI.UNIT_VALUE_TEMPERATURE = UNIT_VALUE_TEMPERATURE; net.tourbook.common.UI.UNIT_LABEL_TEMPERATURE = net.tourbook.common.UI.UNIT_TEMPERATURE_F; } else { // default is the metric measure system UNIT_VALUE_TEMPERATURE = 1; net.tourbook.common.UI.UNIT_VALUE_TEMPERATURE = 1; net.tourbook.common.UI.UNIT_LABEL_TEMPERATURE = net.tourbook.common.UI.UNIT_TEMPERATURE_C; } TourFilterManager.updateUnits(); } private ImageData createTourTypeImage(final long typeId) { final Image tourTypeImage = new Image(Display.getCurrent(), TourType.TOUR_TYPE_IMAGE_SIZE, TourType.TOUR_TYPE_IMAGE_SIZE); final GC gcImage = new GC(tourTypeImage); { drawTourTypeImage(typeId, gcImage); } gcImage.dispose(); /* * set transparency */ final ImageData imageData = tourTypeImage.getImageData(); tourTypeImage.dispose(); final int transparentPixel = imageData.getPixel(0, 0); imageData.transparentPixel = transparentPixel; return imageData; } /** * create image tour type image from scratch */ private Image createTourTypeImage_New(final long typeId, final String colorId) { final ImageData imageData = createTourTypeImage(typeId); final Image transparentImage = new Image(Display.getCurrent(), imageData); // keep image in cache _imageCache.put(colorId, transparentImage); return transparentImage; } /** * updates an existing tour type image * * @param existingImage */ private Image createTourTypeImage_Update(final Image existingImage, final long typeId, final String keyColorId) { final ImageData imageData = createTourTypeImage(typeId); /* * update existing image */ final Image transparentImage = new Image(Display.getCurrent(), imageData); final GC gc = new GC(existingImage); { gc.drawImage(transparentImage, 0, 0); } gc.dispose(); transparentImage.dispose(); _dirtyImages.remove(keyColorId); return existingImage; } /** * dispose resources */ public void dispose() { disposeImages(); } private void disposeImages() { // System.out.println("disposeImages:\t"); for (final Image image : _imageCache.values()) { image.dispose(); } _imageCache.clear(); _imageCacheDescriptor.clear(); } private void drawTourTypeImage(final long typeId, final GC gcImage) { if (typeId == TourType.IMAGE_KEY_DIALOG_SELECTION) { // create a default image } else if (typeId == TourDatabase.ENTITY_IS_NOT_SAVED) { // make the image invisible return; } final int imageSize = TourType.TOUR_TYPE_IMAGE_SIZE; final Display display = Display.getCurrent(); final DrawingColors drawingColors = getTourTypeColors(display, typeId); final Color colorBright = drawingColors.colorBright; final Color colorDark = drawingColors.colorDark; final Color colorLine = drawingColors.colorLine; final Color colorTransparent = new Color(display, TourType.TRANSPARENT_COLOR); { gcImage.setBackground(colorTransparent); gcImage.fillRectangle(0, 0, imageSize, imageSize); gcImage.setForeground(colorBright); gcImage.setBackground(colorDark); gcImage.fillGradientRectangle(4, 4, imageSize - 8, imageSize - 8, false); gcImage.setForeground(colorLine); gcImage.drawRectangle(3, 3, imageSize - 7, imageSize - 7); } drawingColors.dispose(); colorTransparent.dispose(); } /** * @param display * @param graphColor * @return return the color for the graph */ private DrawingColors getTourTypeColors(final Display display, final long tourTypeId) { final DrawingColors drawingColors = new DrawingColors(); final ArrayList<TourType> tourTypes = TourDatabase.getAllTourTypes(); TourType colorTourType = null; for (final TourType tourType : tourTypes) { if (tourType.getTypeId() == tourTypeId) { colorTourType = tourType; break; } } if (tourTypeId == TourType.IMAGE_KEY_DIALOG_SELECTION || colorTourType == null || colorTourType.getTypeId() == TourDatabase.ENTITY_IS_NOT_SAVED) { // tour type was not found use default color drawingColors.colorBright = display.getSystemColor(SWT.COLOR_YELLOW); drawingColors.colorDark = display.getSystemColor(SWT.COLOR_DARK_YELLOW); drawingColors.colorLine = display.getSystemColor(SWT.COLOR_BLACK); // prevent disposing the colors drawingColors.mustBeDisposed = false; } else { drawingColors.colorBright = new Color(display, colorTourType.getRGBBright()); drawingColors.colorDark = new Color(display, colorTourType.getRGBDark()); drawingColors.colorLine = new Color(display, colorTourType.getRGBLine()); } return drawingColors; } /** * @param typeId * @return Returns an image which represents the tour type. This image must not be disposed, * this is done when the app closes. */ public Image getTourTypeImage(final long typeId) { final String keyColorId = TOUR_TYPE_PREFIX + typeId; final Image existingImage = _imageCache.get(keyColorId); // check if image is available if (existingImage != null && existingImage.isDisposed() == false) { // check if the image is dirty if (_dirtyImages.size() == 0 || _dirtyImages.containsKey(keyColorId) == false) { // image is available and not dirty return existingImage; } } // create image for the tour type if (existingImage == null || existingImage.isDisposed()) { return createTourTypeImage_New(typeId, keyColorId); } else { // old tour type image is available and not disposed but needs to be updated return createTourTypeImage_Update(existingImage, typeId, keyColorId); } } /** * The image descriptor is cached because the creation takes system resources and it's called * very often * * @param tourTypeId * Tour type id * @return Returns image descriptor for the tour type id */ public ImageDescriptor getTourTypeImageDescriptor(final long tourTypeId) { final String keyColorId = TOUR_TYPE_PREFIX + tourTypeId; final ImageDescriptor existingDescriptor = _imageCacheDescriptor.get(keyColorId); if (existingDescriptor != null) { return existingDescriptor; } final Image tourTypeImage = getTourTypeImage(tourTypeId); final ImageDescriptor newImageDesc = ImageDescriptor.createFromImage(tourTypeImage); _imageCacheDescriptor.put(keyColorId, newImageDesc); return newImageDesc; } /** * set dirty state for all tour type images, images cannot be disposed because they are * displayed in the UI */ public void setTourTypeImagesDirty() { for (final String imageId : _imageCache.keySet()) { if (imageId.startsWith(TOUR_TYPE_PREFIX)) { _dirtyImages.put(imageId, true); } } _imageCacheDescriptor.clear(); } }