Java tutorial
/******************************************************************************* * Copyright (C) 2005, 2016 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.views.rawData; import static java.nio.file.StandardWatchEventKinds.ENTRY_CREATE; import static java.nio.file.StandardWatchEventKinds.ENTRY_DELETE; import static net.tourbook.ui.UI.getIconUrl; import java.io.File; import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.net.URISyntaxException; import java.nio.file.ClosedWatchServiceException; import java.nio.file.FileSystems; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.nio.file.WatchEvent; import java.nio.file.WatchKey; import java.nio.file.WatchService; import java.text.NumberFormat; import java.time.ZonedDateTime; import java.util.ArrayList; import java.util.Base64; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Set; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.locks.ReentrantLock; import net.tourbook.Messages; import net.tourbook.application.TourbookPlugin; import net.tourbook.common.CommonActivator; import net.tourbook.common.UI; import net.tourbook.common.action.ActionOpenPrefDialog; import net.tourbook.common.formatter.FormatManager; import net.tourbook.common.preferences.ICommonPreferences; import net.tourbook.common.time.TimeTools; import net.tourbook.common.time.TourDateTime; import net.tourbook.common.util.ColumnDefinition; import net.tourbook.common.util.ColumnManager; import net.tourbook.common.util.ITourViewer3; import net.tourbook.common.util.PostSelectionProvider; import net.tourbook.common.util.StatusUtil; import net.tourbook.common.util.TableColumnDefinition; import net.tourbook.common.util.Util; import net.tourbook.data.TourData; import net.tourbook.data.TourMarker; import net.tourbook.data.TourPerson; import net.tourbook.data.TourTag; import net.tourbook.data.TourType; import net.tourbook.data.TourWayPoint; import net.tourbook.database.TourDatabase; import net.tourbook.extension.export.ActionExport; import net.tourbook.importdata.DeviceImportState; import net.tourbook.importdata.DialogEasyImportConfig; import net.tourbook.importdata.EasyConfig; import net.tourbook.importdata.EasyImportManager; import net.tourbook.importdata.ImportConfig; import net.tourbook.importdata.ImportDeviceState; import net.tourbook.importdata.ImportLauncher; import net.tourbook.importdata.OSFile; import net.tourbook.importdata.RawDataManager; import net.tourbook.importdata.SpeedTourType; import net.tourbook.importdata.TourTypeConfig; import net.tourbook.photo.ImageUtils; import net.tourbook.preferences.ITourbookPreferences; import net.tourbook.preferences.PrefPageImport; import net.tourbook.tag.TagMenuManager; import net.tourbook.tour.ActionOpenAdjustAltitudeDialog; import net.tourbook.tour.ActionOpenMarkerDialog; import net.tourbook.tour.ITourEventListener; import net.tourbook.tour.ITourItem; import net.tourbook.tour.SelectionDeletedTours; import net.tourbook.tour.SelectionTourData; import net.tourbook.tour.SelectionTourIds; import net.tourbook.tour.TourDoubleClickState; import net.tourbook.tour.TourEvent; import net.tourbook.tour.TourEventId; import net.tourbook.tour.TourLogManager; import net.tourbook.tour.TourLogState; import net.tourbook.tour.TourLogView; import net.tourbook.tour.TourManager; import net.tourbook.tour.TourTypeMenuManager; import net.tourbook.ui.ITourProviderAll; import net.tourbook.ui.TableColumnFactory; import net.tourbook.ui.action.ActionEditQuick; import net.tourbook.ui.action.ActionEditTour; import net.tourbook.ui.action.ActionJoinTours; import net.tourbook.ui.action.ActionModifyColumns; import net.tourbook.ui.action.ActionOpenTour; import net.tourbook.ui.action.ActionSetTourTypeMenu; import net.tourbook.ui.views.TableViewerTourInfoToolTip; import net.tourbook.ui.views.TourInfoToolTipCellLabelProvider; import net.tourbook.web.WEB; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.jface.action.GroupMarker; import org.eclipse.jface.action.IMenuListener; import org.eclipse.jface.action.IMenuManager; import org.eclipse.jface.action.IToolBarManager; import org.eclipse.jface.action.MenuManager; import org.eclipse.jface.action.Separator; import org.eclipse.jface.dialogs.IDialogSettings; import org.eclipse.jface.dialogs.MessageDialog; import org.eclipse.jface.dialogs.ProgressMonitorDialog; import org.eclipse.jface.layout.GridDataFactory; import org.eclipse.jface.layout.GridLayoutFactory; import org.eclipse.jface.layout.PixelConverter; import org.eclipse.jface.operation.IRunnableWithProgress; import org.eclipse.jface.preference.IPreferenceStore; import org.eclipse.jface.resource.ImageRegistry; import org.eclipse.jface.util.IPropertyChangeListener; import org.eclipse.jface.util.PropertyChangeEvent; import org.eclipse.jface.viewers.CellLabelProvider; import org.eclipse.jface.viewers.ColumnViewer; import org.eclipse.jface.viewers.DoubleClickEvent; import org.eclipse.jface.viewers.IDoubleClickListener; import org.eclipse.jface.viewers.ISelection; import org.eclipse.jface.viewers.ISelectionChangedListener; import org.eclipse.jface.viewers.IStructuredContentProvider; import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.jface.viewers.SelectionChangedEvent; import org.eclipse.jface.viewers.StructuredSelection; import org.eclipse.jface.viewers.TableViewer; import org.eclipse.jface.viewers.Viewer; import org.eclipse.jface.viewers.ViewerCell; import org.eclipse.jface.viewers.ViewerComparator; import org.eclipse.jface.window.Window; import org.eclipse.osgi.util.NLS; import org.eclipse.swt.SWT; import org.eclipse.swt.SWTError; import org.eclipse.swt.browser.Browser; import org.eclipse.swt.browser.BrowserFunction; import org.eclipse.swt.browser.LocationAdapter; import org.eclipse.swt.browser.LocationEvent; import org.eclipse.swt.browser.ProgressAdapter; import org.eclipse.swt.browser.ProgressEvent; import org.eclipse.swt.custom.CLabel; import org.eclipse.swt.events.MenuAdapter; import org.eclipse.swt.events.MenuEvent; import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.events.SelectionEvent; 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.widgets.Composite; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Link; import org.eclipse.swt.widgets.Menu; import org.eclipse.swt.widgets.Shell; import org.eclipse.swt.widgets.Table; import org.eclipse.swt.widgets.TableColumn; import org.eclipse.swt.widgets.Text; import org.eclipse.swt.widgets.Widget; import org.eclipse.ui.IPartListener2; import org.eclipse.ui.ISelectionListener; import org.eclipse.ui.IWorkbenchActionConstants; import org.eclipse.ui.IWorkbenchPart; import org.eclipse.ui.IWorkbenchPartReference; import org.eclipse.ui.part.PageBook; import org.eclipse.ui.part.ViewPart; import org.joda.time.Period; import org.joda.time.PeriodType; /** * */ public class RawDataView extends ViewPart implements ITourProviderAll, ITourViewer3 { public static final String ID = "net.tourbook.views.rawData.RawDataView"; //$NON-NLS-1$ private static final String COLUMN_FACTORY_TIME_ZONE_DIFF_TOOLTIP = net.tourbook.ui.Messages.ColumnFactory_TimeZoneDifference_Tooltip; // db state private static final String IMAGE_ASSIGN_MERGED_TOUR = "IMAGE_ASSIGN_MERGED_TOUR"; //$NON-NLS-1$ private static final String IMAGE_DATABASE = "IMAGE_DATABASE"; //$NON-NLS-1$ private static final String IMAGE_DATABASE_OTHER_PERSON = "IMAGE_DATABASE_OTHER_PERSON"; //$NON-NLS-1$ private static final String IMAGE_DELETE = "IMAGE_DELETE"; //$NON-NLS-1$ private static final String IMAGE_ICON_PLACEHOLDER = "IMAGE_ICON_PLACEHOLDER"; //$NON-NLS-1$ // import state private static final String IMAGE_STATE_DELETE = "IMAGE_STATE_DELETE"; //$NON-NLS-1$ private static final String IMAGE_STATE_MOVED = "IMAGE_STATE_MOVED"; //$NON-NLS-1$ // OLD UI private static final String IMAGE_DATA_TRANSFER = "IMAGE_DATA_TRANSFER"; //$NON-NLS-1$ private static final String IMAGE_DATA_TRANSFER_DIRECT = "IMAGE_DATA_TRANSFER_DIRECT"; //$NON-NLS-1$ private static final String IMAGE_IMPORT_FROM_FILES = "IMAGE_IMPORT_FROM_FILES"; //$NON-NLS-1$ private static final String IMAGE_NEW_UI = "IMAGE_NEW_UI"; //$NON-NLS-1$ // private static final String HTML_TD = "<td>"; //$NON-NLS-1$ private static final String HTML_TD_SPACE = "<td "; //$NON-NLS-1$ private static final String HTML_TD_END = "</td>"; //$NON-NLS-1$ private static final String HTML_TR = "<tr>"; //$NON-NLS-1$ private static final String HTML_TR_END = "</tr>"; //$NON-NLS-1$ // private static final String JS_FUNCTION_ON_SELECT_IMPORT_CONFIG = "onSelectImportConfig"; //$NON-NLS-1$ // private static final String WEB_RESOURCE_TITLE_FONT = "Nunito-Bold.ttf"; //$NON-NLS-1$ // private static final String WEB_RESOURCE_TITLE_FONT = "NothingYouCouldDo.ttf"; //$NON-NLS-1$ private static final String WEB_RESOURCE_TOUR_IMPORT_BG_IMAGE = "mytourbook-icon.svg"; //$NON-NLS-1$ private static final String WEB_RESOURCE_TOUR_IMPORT_CSS = "tour-import.css"; //$NON-NLS-1$ private static final String WEB_RESOURCE_TOUR_IMPORT_CSS3 = "tour-import-css3.css"; //$NON-NLS-1$ // private static final String CSS_IMPORT_BACKGROUND = "div.import-background"; //$NON-NLS-1$ private static final String CSS_IMPORT_TILE = "a.import-tile"; //$NON-NLS-1$ // static final int COLUMN_DATE = 0; static final int COLUMN_TITLE = 1; static final int COLUMN_DATA_FORMAT = 2; static final int COLUMN_FILE_NAME = 3; static final int COLUMN_TIME_ZONE = 4; // private static final String STATE_IMPORTED_FILENAMES = "importedFilenames"; //$NON-NLS-1$ private static final String STATE_SELECTED_TOUR_INDICES = "SelectedTourIndices"; //$NON-NLS-1$ // public static final String STATE_IS_CHECKSUM_VALIDATION = "isChecksumValidation"; //$NON-NLS-1$ public static final boolean STATE_IS_CHECKSUM_VALIDATION_DEFAULT = true; public static final String STATE_IS_CONVERT_WAYPOINTS = "STATE_IS_CONVERT_WAYPOINTS"; //$NON-NLS-1$ public static final boolean STATE_IS_CONVERT_WAYPOINTS_DEFAULT = true; public static final String STATE_IS_CREATE_TOUR_ID_WITH_TIME = "isCreateTourIdWithTime"; //$NON-NLS-1$ public static final boolean STATE_IS_CREATE_TOUR_ID_WITH_TIME_DEFAULT = false; public static final String STATE_IS_AUTO_OPEN_IMPORT_LOG_VIEW = "STATE_IS_AUTO_OPEN_IMPORT_LOG_VIEW"; //$NON-NLS-1$ public static final boolean STATE_IS_AUTO_OPEN_IMPORT_LOG_VIEW_DEFAULT = true; private static final String STATE_IS_REMOVE_TOURS_WHEN_VIEW_CLOSED = "STATE_IS_REMOVE_TOURS_WHEN_VIEW_CLOSED"; //$NON-NLS-1$ public static final String STATE_IS_MERGE_TRACKS = "isMergeTracks"; //$NON-NLS-1$ public static final boolean STATE_IS_MERGE_TRACKS_DEFAULT = false; // private static final String HREF_TOKEN = "#"; //$NON-NLS-1$ private static final String PAGE_ABOUT_BLANK = "about:blank"; //$NON-NLS-1$ /** * This is necessary otherwise XULrunner in Linux do not fire a location change event. */ private static final String HTTP_DUMMY = "http://dummy"; //$NON-NLS-1$ private static final String HTML_STYLE_TITLE_VERTICAL_PADDING = "style='padding-top:10px;'"; //$NON-NLS-1$ private static String ACTION_DEVICE_IMPORT = "DeviceImport"; //$NON-NLS-1$ private static String ACTION_DEVICE_WATCHING_ON_OFF = "DeviceOnOff"; //$NON-NLS-1$ private static final String ACTION_IMPORT_FROM_FILES = "ImportFromFiles"; //$NON-NLS-1$ private static final String ACTION_OLD_UI = "OldUI"; //$NON-NLS-1$ private static final String ACTION_SERIAL_PORT_CONFIGURED = "SerialPortConfigured"; //$NON-NLS-1$ private static final String ACTION_SERIAL_PORT_DIRECTLY = "SerialPortDirectly"; //$NON-NLS-1$ private static final String ACTION_SETUP_EASY_IMPORT = "SetupEasyImport"; //$NON-NLS-1$ // private static final String DOM_CLASS_DEVICE_ON = "deviceOn"; //$NON-NLS-1$ private static final String DOM_CLASS_DEVICE_OFF = "deviceOff"; //$NON-NLS-1$ private static final String DOM_CLASS_DEVICE_ON_ANIMATED = "deviceOnAnimated"; //$NON-NLS-1$ private static final String DOM_CLASS_DEVICE_OFF_ANIMATED = "deviceOffAnimated"; //$NON-NLS-1$ // private static final String DOM_ID_DEVICE_ON_OFF = "deviceOnOff"; //$NON-NLS-1$ private static final String DOM_ID_DEVICE_STATE = "deviceState"; //$NON-NLS-1$ private static final String DOM_ID_IMPORT_CONFIG = "importConfig"; //$NON-NLS-1$ private static final String DOM_ID_IMPORT_TILES = "importTiles"; //$NON-NLS-1$ // private static String HREF_ACTION_DEVICE_IMPORT; private static String HREF_ACTION_DEVICE_WATCHING_ON_OFF; private static String HREF_ACTION_IMPORT_FROM_FILES; private static String HREF_ACTION_OLD_UI; private static String HREF_ACTION_SERIAL_PORT_CONFIGURED; private static String HREF_ACTION_SERIAL_PORT_DIRECTLY; private static String HREF_ACTION_SETUP_EASY_IMPORT; static { HREF_ACTION_DEVICE_IMPORT = HREF_TOKEN + ACTION_DEVICE_IMPORT; HREF_ACTION_DEVICE_WATCHING_ON_OFF = HREF_TOKEN + ACTION_DEVICE_WATCHING_ON_OFF; HREF_ACTION_IMPORT_FROM_FILES = HREF_TOKEN + ACTION_IMPORT_FROM_FILES; HREF_ACTION_OLD_UI = HREF_TOKEN + ACTION_OLD_UI; HREF_ACTION_SERIAL_PORT_CONFIGURED = HREF_TOKEN + ACTION_SERIAL_PORT_CONFIGURED; HREF_ACTION_SERIAL_PORT_DIRECTLY = HREF_TOKEN + ACTION_SERIAL_PORT_DIRECTLY; HREF_ACTION_SETUP_EASY_IMPORT = HREF_TOKEN + ACTION_SETUP_EASY_IMPORT + HREF_TOKEN; } // private final IPreferenceStore _prefStore = TourbookPlugin.getPrefStore(); private final IPreferenceStore _prefStoreCommon = CommonActivator.getPrefStore(); private final IDialogSettings _state = TourbookPlugin.getState(ID); // private RawDataManager _rawDataMgr = RawDataManager.getInstance(); private TableViewer _tourViewer; private TableViewerTourInfoToolTip _tourInfoToolTip; private ColumnManager _columnManager; private SelectionAdapter _columnSortListener; private TableColumnDefinition _timeZoneOffsetColDef; private ImportComparator _importComparator; // private String _columnId_DeviceName; private String _columnId_ImportFileName; private String _columnId_TimeZone; private String _columnId_Title; private String _columnId_TourStartDate; // private PostSelectionProvider _postSelectionProvider; private IPartListener2 _partListener; private ISelectionListener _postSelectionListener; private IPropertyChangeListener _prefChangeListener; private IPropertyChangeListener _prefChangeListenerCommon; private ITourEventListener _tourEventListener; // // context menu actions private ActionClearView _actionClearView; private ActionOpenTourLogView _actionOpenTourLogView; private ActionDeleteTourFiles _actionDeleteTourFile; private ActionExport _actionExportTour; private ActionEditQuick _actionEditQuick; private ActionEditTour _actionEditTour; private ActionJoinTours _actionJoinTours; private ActionMergeIntoMenu _actionMergeIntoTour; private ActionMergeTour _actionMergeTour; private ActionModifyColumns _actionModifyColumns; private ActionOpenTour _actionOpenTour; private ActionOpenMarkerDialog _actionOpenMarkerDialog; private ActionOpenAdjustAltitudeDialog _actionOpenAdjustAltitudeDialog; private ActionOpenPrefDialog _actionEditImportPreferences; private ActionReimportSubMenu _actionReimportSubMenu; private ActionRemoveTour _actionRemoveTour; private ActionRemoveToursWhenClosed _actionRemoveToursWhenClosed; private ActionSaveTourInDatabase _actionSaveTour; private ActionSaveTourInDatabase _actionSaveTourWithPerson; private ActionSetupImport _actionSetupImport; private ActionSetTourTypeMenu _actionSetTourType; // protected TourPerson _activePerson; protected TourPerson _newActivePerson; // protected boolean _isPartVisible = false; protected boolean _isViewerPersonDataDirty = false; // // private final NumberFormat _nf1; private final NumberFormat _nf3; // private final PeriodType _durationTemplate; { _nf1 = NumberFormat.getNumberInstance(); _nf3 = NumberFormat.getNumberInstance(); _nf1.setMinimumFractionDigits(1); _nf1.setMaximumFractionDigits(1); _nf3.setMinimumFractionDigits(3); _nf3.setMaximumFractionDigits(3); _durationTemplate = PeriodType.yearMonthDayTime() // // hide these components .withMillisRemoved(); } // // private boolean _isToolTipInDate; private boolean _isToolTipInTime; private boolean _isToolTipInTitle; private boolean _isToolTipInTags; // private TagMenuManager _tagMenuMgr; private TourDoubleClickState _tourDoubleClickState = new TourDoubleClickState(); // private Thread _watchingStoresThread; private Thread _watchingFolderThread; private WatchService _folderWatcher; private boolean _isStopWatchingStoresThread; private AtomicBoolean _isWatchingStores = new AtomicBoolean(); private AtomicBoolean _isDeviceStateUpdateDelayed = new AtomicBoolean(); private ReentrantLock WATCH_LOCK = new ReentrantLock(); // private HashMap<Long, Image> _configImages = new HashMap<>(); private HashMap<Long, Integer> _configImageHash = new HashMap<>(); // private boolean _isBrowserCompleted; private boolean _isInUIStartup; private boolean _isInUpdate; private boolean _isNewUI; /** * When <code>false</code> then the background WatchStores task must set it valid. Only when it * is valid then the device state icon displays the state, otherwise it shows a waiting icon. */ private boolean _isDeviceStateValid; private boolean _isRunDashboardAnimation = true; private boolean _isShowWatcherAnimation; private boolean _isUpdateDeviceState = true; // private String _cssFonts; private String _cssFromFile; // private String _imageUrl_Device_TurnOff; private String _imageUrl_Device_TurnOn; private String _imageUrl_DeviceFolder_OK; private String _imageUrl_DeviceFolder_Disabled; private String _imageUrl_DeviceFolder_NotAvailable; private String _imageUrl_DeviceFolder_NotChecked; private String _imageUrl_DeviceFolder_NotSetup; private String _imageUrl_ImportFromFile; private String _imageUrl_SerialPort_Configured; private String _imageUrl_SerialPort_Directly; private String _imageUrl_State_AdjustTemperature; private String _imageUrl_State_Error; private String _imageUrl_State_OK; private String _imageUrl_State_MovedFiles; private String _imageUrl_State_SaveTour; private String _imageUrl_State_TourMarker; // private PixelConverter _pc; /* * resources */ private ImageRegistry _images; private DialogEasyImportConfig _dialogImportConfig; /* * UI controls */ private PageBook _topPageBook; private Composite _topPage_Dashboard; private Composite _topPage_ImportViewer; private Composite _topPage_OldUI; private Composite _topPage_Startup; private PageBook _dashboard_PageBook; private Composite _dashboardPage_NoBrowser; private Composite _dashboardPage_WithBrowser; private Composite _parent; private Composite _viewerContainer; private Text _txtNoBrowser; private Link _linkImport; private Browser _browser; private class ImportComparator extends ViewerComparator { static final int ASCENDING = 0; private static final int DESCENDING = 1; private String __sortColumnId; private int __sortDirection; @Override public int compare(final Viewer viewer, final Object obj1, final Object obj2) { final TourData tourData1 = ((TourData) obj1); final TourData tourData2 = ((TourData) obj2); int result = 0; if (__sortColumnId.equals(_columnId_TourStartDate)) { // date/time result = tourData1.getTourStartTimeMS() > tourData2.getTourStartTimeMS() ? 1 : -1; } else if (__sortColumnId.equals(_columnId_Title)) { // title result = tourData1.getTourTitle().compareTo(tourData2.getTourTitle()); } else if (__sortColumnId.equals(_columnId_ImportFileName)) { // file name final String importFilePath1 = tourData1.getImportFilePath(); final String importFilePath2 = tourData2.getImportFilePath(); if (importFilePath1 != null && importFilePath2 != null) { result = importFilePath1.compareTo(importFilePath2); } } else if (__sortColumnId.equals(_columnId_DeviceName)) { // device name result = tourData1.getDeviceName().compareTo(tourData2.getDeviceName()); } else if (__sortColumnId.equals(_columnId_TimeZone)) { // time zone final String timeZoneId1 = tourData1.getTimeZoneId(); final String timeZoneId2 = tourData2.getTimeZoneId(); if (timeZoneId1 != null && timeZoneId2 != null) { final int zoneCompareResult = timeZoneId1.compareTo(timeZoneId2); result = zoneCompareResult; } else if (timeZoneId1 != null) { result = 1; } else if (timeZoneId2 != null) { result = -1; } } // do a 2nd sorting by date/time if (result == 0) { result = tourData1.getTourStartTimeMS() > tourData2.getTourStartTimeMS() ? 1 : -1; } // if descending order, flip the direction if (__sortDirection == DESCENDING) { result = -result; } return result; } /** * Does the sort. If it's a different column from the previous sort, do an ascending sort. * If it's the same column as the last sort, toggle the sort direction. * * @param widget * Column widget */ private void setSortColumn(final Widget widget) { final ColumnDefinition columnDefinition = (ColumnDefinition) widget.getData(); final String columnId = columnDefinition.getColumnId(); if (columnId.equals(__sortColumnId)) { // Same column as last sort; toggle the direction __sortDirection = 1 - __sortDirection; } else { // New column; do an ascent sorting __sortColumnId = columnId; __sortDirection = ASCENDING; } updateUI_ShowSortDirection(__sortColumnId, __sortDirection); } } private class JS_OnSelectImportConfig extends BrowserFunction { JS_OnSelectImportConfig(final Browser browser, final String name) { super(browser, name); } @Override public Object function(final Object[] arguments) { final int selectedIndex = ((Number) arguments[0]).intValue(); Display.getCurrent().asyncExec(new Runnable() { @Override public void run() { onSelectImportConfig(selectedIndex); } }); //// this can be used to show created JS in the debugger // if (true) { // throw new RuntimeException(); // } return null; } } private class TourDataContentProvider implements IStructuredContentProvider { public TourDataContentProvider() { } @Override public void dispose() { } @Override public Object[] getElements(final Object parent) { return (Object[]) (parent); } @Override public void inputChanged(final Viewer v, final Object oldInput, final Object newInput) { } } private void action_Easy_SetDeviceWatching_OnOff() { _isShowWatcherAnimation = true; if (isWatchingOn()) { // stop watching setWatcher_Off(); } else { // start watching setWatcher_On(); } updateUI_DeviceState(); } /** * @param selectedTab * Tab which should be selected when config dialog is opened, -1 will select the * restored tab index. */ void action_Easy_SetupImport(final int selectedTab) { // prevent that the dialog is opened multiple times, this occured when testing if (_dialogImportConfig != null) { return; } final Shell shell = Display.getDefault().getActiveShell(); final EasyConfig easyConfig = getEasyConfig(); _dialogImportConfig = new DialogEasyImportConfig(shell, easyConfig, this, selectedTab); boolean isOK = false; if (_dialogImportConfig.open() == Window.OK) { isOK = true; } if (isOK) { // keep none live update values final EasyConfig modifiedEasyConfig = _dialogImportConfig.getModifiedConfig(); easyConfig.setActiveImportConfig(modifiedEasyConfig.getActiveImportConfig()); easyConfig.importConfigs.clear(); easyConfig.importConfigs.addAll(modifiedEasyConfig.importConfigs); easyConfig.importLaunchers.clear(); easyConfig.importLaunchers.addAll(modifiedEasyConfig.importLaunchers); updateModel_EasyConfig_Dashboard(_dialogImportConfig.getModifiedConfig()); _isDeviceStateValid = false; updateUI_2_Dashboard(); } _dialogImportConfig = null; } void actionClearView() { // force the state icon to be updated _isDeviceStateValid = false; thread_FolderWatcher_Activate(); // remove all tours _rawDataMgr.removeAllTours(); reloadViewer(); _postSelectionProvider.setSelection(new SelectionDeletedTours()); // don't throw the selection again _postSelectionProvider.clearSelection(); } /** * Delete selected tour files. */ void actionDeleteTourFiles() { final ArrayList<TourData> selectedTours = getAnySelectedTours(); runEasyImport_100_DeleteTourFiles(true, selectedTours, false); } void actionMergeTours(final TourData mergeFromTour, final TourData mergeIntoTour) { // check if the tour editor contains a modified tour if (TourManager.isTourEditorModified()) { return; } // backup data final Long backupMergeSourceTourId = mergeIntoTour.getMergeSourceTourId(); final Long backupMergeTargetTourId = mergeIntoTour.getMergeTargetTourId(); // set tour data and tour id from which the tour is merged mergeIntoTour.setMergeSourceTourId(mergeFromTour.getTourId()); mergeIntoTour.setMergeTargetTourId(null); // set temp data, this is required by the dialog because the merge from tour could not be saved mergeIntoTour.setMergeSourceTour(mergeFromTour); if (new DialogMergeTours(Display.getCurrent().getActiveShell(), mergeFromTour, mergeIntoTour) .open() != Window.OK) { // dialog is canceled, restore modified values mergeIntoTour.setMergeSourceTourId(backupMergeSourceTourId); mergeIntoTour.setMergeTargetTourId(backupMergeTargetTourId); } // reset temp tour data mergeIntoTour.setMergeSourceTour(null); } /** * Remove all tours from the raw data view which are selected */ void actionRemoveTour() { final IStructuredSelection selection = ((IStructuredSelection) _tourViewer.getSelection()); if (selection.size() == 0) { return; } /* * convert selection to array */ final Object[] selectedItems = selection.toArray(); final TourData[] selectedTours = new TourData[selection.size()]; for (int i = 0; i < selectedItems.length; i++) { selectedTours[i] = (TourData) selectedItems[i]; } _rawDataMgr.removeTours(selectedTours); _postSelectionProvider.clearSelection(); TourManager.fireEvent(TourEventId.CLEAR_DISPLAYED_TOUR, null, RawDataView.this); // update the table viewer reloadViewer(); } void actionSaveTour(final TourPerson person) { doSaveTour(person); } private void addPartListener() { _partListener = new IPartListener2() { @Override public void partActivated(final IWorkbenchPartReference partRef) { } @Override public void partBroughtToTop(final IWorkbenchPartReference partRef) { } @Override public void partClosed(final IWorkbenchPartReference partRef) { if (partRef.getPart(false) == RawDataView.this) { saveState(); // remove all tours _rawDataMgr.removeAllTours(); TourManager.fireEvent(TourEventId.CLEAR_DISPLAYED_TOUR, null, RawDataView.this); } } @Override public void partDeactivated(final IWorkbenchPartReference partRef) { } @Override public void partHidden(final IWorkbenchPartReference partRef) { if (RawDataView.this == partRef.getPart(false)) { _isPartVisible = false; } } @Override public void partInputChanged(final IWorkbenchPartReference partRef) { } @Override public void partOpened(final IWorkbenchPartReference partRef) { } @Override public void partVisible(final IWorkbenchPartReference partRef) { if (RawDataView.this == partRef.getPart(false)) { _isPartVisible = true; if (_isViewerPersonDataDirty || (_newActivePerson != _activePerson)) { reloadViewer(); updateViewerPersonData(); _newActivePerson = _activePerson; _isViewerPersonDataDirty = false; } } } }; getViewSite().getPage().addPartListener(_partListener); } private void addPrefListener() { _prefChangeListener = new IPropertyChangeListener() { @Override public void propertyChange(final PropertyChangeEvent event) { final String property = event.getProperty(); if (property.equals(ITourbookPreferences.APP_DATA_FILTER_IS_MODIFIED)) { if (_isPartVisible) { updateViewerPersonData(); } else { // keep new active person until the view is visible _newActivePerson = TourbookPlugin.getActivePerson(); } } else if (property.equals(ITourbookPreferences.TOUR_PERSON_LIST_IS_MODIFIED)) { _actionSaveTour.resetPeopleList(); } else if (property.equals(ITourbookPreferences.TOUR_TYPE_LIST_IS_MODIFIED)) { // tour type images can have been changed disposeConfigImages(); // update tour type in the raw data _rawDataMgr.updateTourData_InImportView_FromDb(null); _tourViewer.refresh(); } else if (property.equals(ITourbookPreferences.VIEW_TOOLTIP_IS_MODIFIED)) { updateToolTipState(); } else if (property.equals(ITourbookPreferences.MEASUREMENT_SYSTEM)) { // measurement system has changed recreateViewer(); } else if (property.equals(ITourbookPreferences.VIEW_LAYOUT_CHANGED)) { _tourViewer.getTable() .setLinesVisible(_prefStore.getBoolean(ITourbookPreferences.VIEW_LAYOUT_DISPLAY_LINES)); _tourViewer.refresh(); /* * the tree must be redrawn because the styled text does not show with the new * color */ _tourViewer.getTable().redraw(); } } }; _prefStore.addPropertyChangeListener(_prefChangeListener); /* * Common preferences */ _prefChangeListenerCommon = new IPropertyChangeListener() { @Override public void propertyChange(final PropertyChangeEvent event) { final String property = event.getProperty(); if (property.equals(ICommonPreferences.TIME_ZONE_LOCAL_ID)) { recreateViewer(); } } }; // register the listener _prefStoreCommon.addPropertyChangeListener(_prefChangeListenerCommon); } private void addSelectionListener() { _postSelectionListener = new ISelectionListener() { @Override public void selectionChanged(final IWorkbenchPart part, final ISelection selection) { if (part == RawDataView.this) { return; } onSelectionChanged(selection); } }; getSite().getPage().addPostSelectionListener(_postSelectionListener); } private void addTourEventListener() { _tourEventListener = new ITourEventListener() { @Override public void tourChanged(final IWorkbenchPart part, final TourEventId eventId, final Object eventData) { if (part == RawDataView.this) { return; } if (_isInUpdate) { return; } if ((eventId == TourEventId.TOUR_CHANGED) && (eventData instanceof TourEvent)) { // update modified tours final ArrayList<TourData> modifiedTours = ((TourEvent) eventData).getModifiedTours(); if (modifiedTours != null) { // update model _rawDataMgr.updateTourDataModel(modifiedTours); // update viewer _tourViewer.update(modifiedTours.toArray(), null); // remove old selection, old selection can have the same tour but with old data _postSelectionProvider.clearSelection(); } } else if (eventId == TourEventId.ALL_TOURS_ARE_MODIFIED) { // save imported file names final HashSet<String> importedFiles = _rawDataMgr.getImportedFiles(); _state.put(STATE_IMPORTED_FILENAMES, importedFiles.toArray(new String[importedFiles.size()])); reimportAllImportFiles(false); } else if (eventId == TourEventId.TAG_STRUCTURE_CHANGED) { _rawDataMgr.updateTourData_InImportView_FromDb(null); reloadViewer(); } } }; TourManager.getInstance().addTourEventListener(_tourEventListener); } private void createActions() { _actionEditImportPreferences = new ActionOpenPrefDialog(Messages.Import_Data_Action_EditImportPreferences, PrefPageImport.ID); _actionClearView = new ActionClearView(this); _actionDeleteTourFile = new ActionDeleteTourFiles(this); _actionEditTour = new ActionEditTour(this); _actionEditQuick = new ActionEditQuick(this); _actionExportTour = new ActionExport(this); _actionJoinTours = new ActionJoinTours(this); _actionMergeIntoTour = new ActionMergeIntoMenu(this); _actionMergeTour = new ActionMergeTour(this); _actionModifyColumns = new ActionModifyColumns(this); _actionOpenAdjustAltitudeDialog = new ActionOpenAdjustAltitudeDialog(this); _actionOpenTourLogView = new ActionOpenTourLogView(); _actionOpenMarkerDialog = new ActionOpenMarkerDialog(this, true); _actionOpenTour = new ActionOpenTour(this); _actionReimportSubMenu = new ActionReimportSubMenu(this); _actionRemoveTour = new ActionRemoveTour(this); _actionRemoveToursWhenClosed = new ActionRemoveToursWhenClosed(); _actionSaveTour = new ActionSaveTourInDatabase(this, false); _actionSaveTourWithPerson = new ActionSaveTourInDatabase(this, true); _actionSetupImport = new ActionSetupImport(this); _actionSetTourType = new ActionSetTourTypeMenu(this); _tagMenuMgr = new TagMenuManager(this, true); } /** * Create css from the import configurations. * * @return */ private String createCSS_Custom() { /* * Import background image */ final EasyConfig easyConfig = getEasyConfig(); final int itemSize = easyConfig.tileSize; final int opacity = easyConfig.backgroundOpacity; final int animationDuration = easyConfig.animationDuration; final int crazyFactor = easyConfig.animationCrazinessFactor; String bgImage = UI.EMPTY_STRING; if (opacity > 0) { /* * Show image only when it is visible, opacity > 0 */ File webFile; try { webFile = WEB.getResourceFile(WEB_RESOURCE_TOUR_IMPORT_BG_IMAGE); final String webContent = Util.readContentFromFile(webFile.getAbsolutePath()); final String base64Encoded = Base64.getEncoder().encodeToString(webContent.getBytes()); bgImage = (CSS_IMPORT_BACKGROUND + "\n")// //$NON-NLS-1$ + "{\n" //$NON-NLS-1$ + (" background: url('data:image/svg+xml;base64," + base64Encoded + "');\n") //$NON-NLS-1$ //$NON-NLS-2$ + (" background-repeat: no-repeat;\n") //$NON-NLS-1$ + (" background-size: contain;\n") //$NON-NLS-1$ + (" background-position: center center;\n") //$NON-NLS-1$ + (" opacity: " + (float) opacity / 100 + ";\n") //$NON-NLS-1$ //$NON-NLS-2$ + "}\n"; //$NON-NLS-1$ } catch (IOException | URISyntaxException e) { TourLogManager.logEx(e); } } String animation = UI.EMPTY_STRING; if (_isRunDashboardAnimation && animationDuration > 0 && UI.IS_WIN) { // run animation only once _isRunDashboardAnimation = false; final double rotateX = Math.random() * 10 * crazyFactor; final double rotateY = Math.random() * 10 * crazyFactor; animation = ""// //$NON-NLS-1$ + ("body\n") //$NON-NLS-1$ + ("{\n") //$NON-NLS-1$ + (" animation: fadeinBody;\n") //$NON-NLS-1$ + (" animation-duration: " + _nf1.format(animationDuration / 10.0) + "s;\n") //$NON-NLS-1$ //$NON-NLS-2$ + (" animation-timing-function: ease;\n") //$NON-NLS-1$ + ("}\n") //$NON-NLS-1$ + ("@keyframes fadeinBody \n") //$NON-NLS-1$ + ("{ \n") //$NON-NLS-1$ + (" from \n") //$NON-NLS-1$ + (" { \n") //$NON-NLS-1$ + (" opacity: 0; \n") //$NON-NLS-1$ + (" background-color: ButtonFace; \n") //$NON-NLS-1$ + (" transform: rotateX(" + (int) rotateX + "deg) rotateY(" + (int) rotateY //$NON-NLS-1$//$NON-NLS-2$ + "deg); \n") //$NON-NLS-1$ + (" } \n") //$NON-NLS-1$ // transform: rotateX(-80deg) rotateY(-80deg); // transform-origin: 50% 200%; + (" to \n") //$NON-NLS-1$ + (" { \n") //$NON-NLS-1$ + (" opacity: 1; \n") //$NON-NLS-1$ + (" } \n") //$NON-NLS-1$ + ("} \n"); //$NON-NLS-1$ } /* * Tile size */ final String tileSize = UI.EMPTY_STRING // + (CSS_IMPORT_TILE + "\n") //$NON-NLS-1$ + ("{\n") //$NON-NLS-1$ + (" min-height: " + itemSize + "px;\n") //$NON-NLS-1$ //$NON-NLS-2$ + (" max-height: " + itemSize + "px;\n") //$NON-NLS-1$ //$NON-NLS-2$ + (" min-width: " + itemSize + "px;\n") //$NON-NLS-1$ //$NON-NLS-2$ + (" max-width: " + itemSize + "px;\n") //$NON-NLS-1$ //$NON-NLS-2$ + ("}\n"); //$NON-NLS-1$ /* * State tooltip */ final String stateTooltip = UI.EMPTY_STRING // + (".stateTooltip\n") //$NON-NLS-1$ + ("{\n") //$NON-NLS-1$ + (" width:" + easyConfig.stateToolTipWidth + "px;\n") //$NON-NLS-1$ //$NON-NLS-2$ + ("}\n"); //$NON-NLS-1$ /* * CSS */ final String customCSS = "" // //$NON-NLS-1$ + "<style>\n" // //$NON-NLS-1$ + animation + bgImage + tileSize + stateTooltip + "</style>\n"; //$NON-NLS-1$ return customCSS; } private String createHTML() { // Force Internet Explorer to not use compatibility mode. Internet Explorer believes that websites under // several domains (including "ibm.com") require compatibility mode. You may see your web application run // normally under "localhost", but then fail when hosted under another domain (e.g.: "ibm.com"). // Setting "IE=Edge" will force the latest standards mode for the version of Internet Explorer being used. // This is supported for Internet Explorer 8 and later. You can also ease your testing efforts by forcing // specific versions of Internet Explorer to render using the standards mode of previous versions. This // prevents you from exploiting the latest features, but may offer you compatibility and stability. Lookup // the online documentation for the "X-UA-Compatible" META tag to find which value is right for you. final String html = "" // //$NON-NLS-1$ + "<!DOCTYPE html>\n" // ensure that IE is using the newest version and not the quirk mode //$NON-NLS-1$ + "<html style='height: 100%; width: 100%; margin: 0px; padding: 0px;'>\n" //$NON-NLS-1$ + ("<head>\n" + createHTML_10_Head() + "\n</head>\n") //$NON-NLS-1$ //$NON-NLS-2$ + ("<body>\n" + createHTML_20_Body() + "\n</body>\n") //$NON-NLS-1$ //$NON-NLS-2$ + "</html>"; //$NON-NLS-1$ return html; } private String createHTML_10_Head() { final String html = ""// //$NON-NLS-1$ + " <meta http-equiv='Content-Type' content='text/html; charset=UTF-8' />\n" //$NON-NLS-1$ + " <meta http-equiv='X-UA-Compatible' content='IE=edge' />\n" //$NON-NLS-1$ + _cssFonts + _cssFromFile + createCSS_Custom() + "\n"; //$NON-NLS-1$ return html; } private String createHTML_20_Body() { final StringBuilder sb = new StringBuilder(); sb.append("<div class='import-container'>\n"); //$NON-NLS-1$ { /* * Very tricky: When a parent has an opacity, a child cannot modify it. Therefore the * different divs with position relative/absolute. It took me some time to * find/implement this tricky but simple solution. */ sb.append("<div class='import-background'></div>\n"); //$NON-NLS-1$ sb.append("<div class='import-content'>\n"); //$NON-NLS-1$ { /* * Device Import */ createHTML_50_Easy_Header(sb); createHTML_80_Easy_Tiles(sb); /* * Get Tours */ sb.append("<div class='get-tours-title title'>\n"); //$NON-NLS-1$ sb.append(" " + Messages.Import_Data_HTML_GetTours + "\n"); //$NON-NLS-1$ //$NON-NLS-2$ sb.append("</div>\n"); //$NON-NLS-1$ createHTML_90_SimpleImport(sb); } sb.append("</div>\n"); //$NON-NLS-1$ } sb.append("</div>\n"); //$NON-NLS-1$ return sb.toString(); } private void createHTML_50_Easy_Header(final StringBuilder sb) { final String watchClass = isWatchingOn() ? DOM_CLASS_DEVICE_ON : DOM_CLASS_DEVICE_OFF; final String html = "" // //$NON-NLS-1$ + "<div class='auto-import-header'>\n" //$NON-NLS-1$ + (" <table border=0><tbody><tr>\n") //$NON-NLS-1$ // device state on/off + (" <td>\n") //$NON-NLS-1$ + (" <div id='" + DOM_ID_DEVICE_ON_OFF + "'>" + createHTML_52_DeviceState_OnOff() //$NON-NLS-1$//$NON-NLS-2$ + "</div>\n") //$NON-NLS-1$ + (" </td>\n") //$NON-NLS-1$ // title + (" <td><span class='title'>" + Messages.Import_Data_HTML_EasyImport + "</span></td>\n") //$NON-NLS-1$ //$NON-NLS-2$ // state icon + (" <td>\n") //$NON-NLS-1$ + (" <div id='" + DOM_ID_DEVICE_STATE + "' style='padding-left:25px;' class='" + watchClass //$NON-NLS-1$//$NON-NLS-2$ + "'>\n") //$NON-NLS-1$ + (createHTML_54_DeviceState()) + (" </div>\n") //$NON-NLS-1$ + (" </td>\n") //$NON-NLS-1$ // selected config + (" <td>") //$NON-NLS-1$ + (" <div id='" + DOM_ID_IMPORT_CONFIG + "' class='" + watchClass + "'>") //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + (createHTML_60_SelectImportConfig()) + (" </div>") //$NON-NLS-1$ + (" </td>") //$NON-NLS-1$ + " </tr></tbody></table>\n" // //$NON-NLS-1$ + "</div>\n"; //$NON-NLS-1$ sb.append(html); } private String createHTML_52_DeviceState_OnOff() { final boolean isWatchingOn = isWatchingOn(); String tooltip = isWatchingOn ? Messages.Import_Data_HTML_DeviceOff_Tooltip : Messages.Import_Data_HTML_DeviceOn_Tooltip; tooltip = UI.replaceHTML_NewLine(tooltip); // shwo red image when off final String imageUrl = isWatchingOn // ? _imageUrl_Device_TurnOn : _imageUrl_Device_TurnOff; final String hrefAction = HTTP_DUMMY + HREF_ACTION_DEVICE_WATCHING_ON_OFF; final String onOffImage = createHTML_BgImageStyle(imageUrl); final String html = ""// //$NON-NLS-1$ + "<a class='onOffIcon dash-action'" // //$NON-NLS-1$ + ("title='" + tooltip + "'") //$NON-NLS-1$ //$NON-NLS-2$ + (" href='" + hrefAction + "'") //$NON-NLS-1$ //$NON-NLS-2$ + ">" //$NON-NLS-1$ + ("<div class='stateIcon' " + onOffImage + "></div>") //$NON-NLS-1$ //$NON-NLS-2$ + "</a>"; //$NON-NLS-1$ return html; } private String createHTML_54_DeviceState() { final String hrefSetupAction = HTTP_DUMMY + HREF_ACTION_SETUP_EASY_IMPORT; final EasyConfig easyConfig = getEasyConfig(); final ImportConfig importConfig = easyConfig.getActiveImportConfig(); String html = null; final boolean isWatchAnything = importConfig.isWatchAnything(); if (!isWatchingOn()) { // watching is off final String stateImage = createHTML_BgImageStyle(_imageUrl_DeviceFolder_Disabled); final String htmlTooltip = Messages.Import_Data_HTML_WatchingIsOff; html = "\n"// //$NON-NLS-1$ + "<a class='importState dash-action'" // //$NON-NLS-1$ + (" href='" + HTTP_DUMMY + "'") //$NON-NLS-1$ //$NON-NLS-2$ + ">" //$NON-NLS-1$ + ("<div class='stateIcon' " + stateImage + ">\n") //$NON-NLS-1$ //$NON-NLS-2$ + (" <div class='stateIconValue'></div>\n") //$NON-NLS-1$ + ("</div>\n") //$NON-NLS-1$ + ("<div class='stateTooltip stateTooltipMessage'>" + htmlTooltip + "</div>\n") //$NON-NLS-1$ //$NON-NLS-2$ + "</a>\n"; //$NON-NLS-1$ } else if (isWatchAnything && _isDeviceStateValid) { html = createHTML_55_DeviceState_IsValid(easyConfig, hrefSetupAction); } else { /* * On startup, set the folder state without device info because this is retrieved in a * background thread, if not, it is blocking the UI !!! */ final String stateImage = createHTML_BgImageStyle( isWatchAnything ? _imageUrl_DeviceFolder_NotChecked : _imageUrl_DeviceFolder_NotSetup); final String htmlTooltip = isWatchAnything ? Messages.Import_Data_HTML_AcquireDeviceInfo : Messages.Import_Data_HTML_NothingIsWatched; html = "\n"// //$NON-NLS-1$ + "<a class='importState dash-action'" // //$NON-NLS-1$ + (" href='" + hrefSetupAction + "'") //$NON-NLS-1$ //$NON-NLS-2$ + ">\n" //$NON-NLS-1$ + ("<div class='stateIcon' " + stateImage + ">\n") //$NON-NLS-1$ //$NON-NLS-2$ + (" <div class='stateIconValue'></div>\n") //$NON-NLS-1$ + ("</div>\n") //$NON-NLS-1$ + ("<div class='stateTooltip stateTooltipMessage'>" + htmlTooltip + "</div>\n") //$NON-NLS-1$ //$NON-NLS-2$ + "</a>\n"; //$NON-NLS-1$ } return html; } private String createHTML_55_DeviceState_IsValid(final EasyConfig easyConfig, final String hrefAction) { final ImportConfig importConfig = easyConfig.getActiveImportConfig(); final String deviceOSFolder = importConfig.getDeviceOSFolder(); final ArrayList<OSFile> notImportedFiles = easyConfig.notImportedFiles; final int numDeviceFiles = easyConfig.numDeviceFiles; final int numMovedFiles = easyConfig.movedFiles.size(); final int numNotImportedFiles = notImportedFiles.size(); final int numAllFiles = numDeviceFiles + numMovedFiles; final boolean isDeviceFolderOK = isOSFolderValid(deviceOSFolder); boolean isFolderOK = true; final StringBuilder sb = new StringBuilder(); sb.append("<table border=0><tbody>"); //$NON-NLS-1$ /* * Title */ sb.append(HTML_TR); sb.append("<td colspan=2 class='importConfigTitle'>" + importConfig.name + HTML_TD_END); //$NON-NLS-1$ sb.append(HTML_TR_END); /* * Backup folder */ final boolean isCreateBackup = importConfig.isCreateBackup; if (isCreateBackup) { final String htmlBackupFolder = UI.replaceHTML_BackSlash(importConfig.getBackupFolder()); // check OS folder final String backupOSFolder = importConfig.getBackupOSFolder(); final boolean isBackupFolderOK = isOSFolderValid(backupOSFolder); isFolderOK &= isBackupFolderOK; final String folderTitle = Messages.Import_Data_HTML_Title_Backup; String folderInfo = null; /* * Show back folder info only when device folder is OK because they are related * together. */ if (isDeviceFolderOK) { final int numNotBackedUpFiles = easyConfig.notBackedUpFiles.size(); folderInfo = numNotBackedUpFiles == 0 // ? NLS.bind(Messages.Import_Data_HTML_AllFilesAreBackedUp, numDeviceFiles) : NLS.bind(Messages.Import_Data_HTML_NotBackedUpFiles, numNotBackedUpFiles, numDeviceFiles); } createHTML_56_FolderState(// sb, htmlBackupFolder, isBackupFolderOK, false, folderTitle, folderInfo); } /* * Device folder */ { final String htmlDeviceFolder = UI.replaceHTML_BackSlash(importConfig.getDeviceFolder()); final boolean isTopMargin = importConfig.isCreateBackup; final String folderTitle = Messages.Import_Data_HTML_Title_Device; final String folderInfo = numNotImportedFiles == 0 // ? NLS.bind(Messages.Import_Data_HTML_AllFilesAreImported, numAllFiles) : NLS.bind(Messages.Import_Data_HTML_NotImportedFiles, numNotImportedFiles, numAllFiles); createHTML_56_FolderState(// sb, htmlDeviceFolder, isDeviceFolderOK, isTopMargin, folderTitle, folderInfo); isFolderOK &= isDeviceFolderOK; } /* * Moved files */ if (numMovedFiles > 0) { sb.append(HTML_TR); sb.append(HTML_TD_SPACE + HTML_STYLE_TITLE_VERTICAL_PADDING + " class='folderTitle'>"); //$NON-NLS-1$ sb.append(Messages.Import_Data_HTML_Title_Moved); sb.append(HTML_TD_END); sb.append(HTML_TD_SPACE + HTML_STYLE_TITLE_VERTICAL_PADDING + " class='folderLocation'>"); //$NON-NLS-1$ sb.append(NLS.bind(Messages.Import_Data_HTML_MovedFiles, numMovedFiles)); sb.append(HTML_TD_END); sb.append(HTML_TR_END); } /* * Device files */ { final String deviceFiles = importConfig.fileGlobPattern.trim().length() == 0 ? ImportConfig.DEVICE_FILES_DEFAULT : importConfig.fileGlobPattern; sb.append(HTML_TR); sb.append(HTML_TD_SPACE + HTML_STYLE_TITLE_VERTICAL_PADDING + " class='folderTitle'>"); //$NON-NLS-1$ sb.append(Messages.Import_Data_HTML_Title_Files); sb.append(HTML_TD_END); sb.append(HTML_TD_SPACE + HTML_STYLE_TITLE_VERTICAL_PADDING + " class='folderLocation'>"); //$NON-NLS-1$ sb.append(deviceFiles); sb.append(HTML_TD_END); sb.append(HTML_TR_END); } /* * 100. Delete device files */ { final boolean isDeleteDeviceFiles = importConfig.isDeleteDeviceFiles; final String deleteFiles = isDeleteDeviceFiles ? Messages.Import_Data_HTML_DeleteFilesYES : Messages.Import_Data_HTML_DeleteFilesNO; sb.append(HTML_TR); sb.append(HTML_TD_SPACE + HTML_STYLE_TITLE_VERTICAL_PADDING + " class='folderTitle'>"); //$NON-NLS-1$ sb.append(Messages.Import_Data_HTML_Title_Delete); sb.append(HTML_TD_END); sb.append(HTML_TD_SPACE + HTML_STYLE_TITLE_VERTICAL_PADDING + " class='folderLocation'>"); //$NON-NLS-1$ sb.append(deleteFiles); sb.append(HTML_TD_END); sb.append(HTML_TR_END); } /* * 101. Turn off device watching */ { final boolean isWatchingOff = importConfig.isTurnOffWatching; final String watchingText = isWatchingOff ? Messages.Import_Data_HTML_WatchingOff : Messages.Import_Data_HTML_WatchingOn; // shwo red image when off final String imageUrl = isWatchingOff // ? _imageUrl_Device_TurnOff : _imageUrl_Device_TurnOn; final String onOffImage = createHTML_BgImage(imageUrl); sb.append(HTML_TR); sb.append(HTML_TD_SPACE + HTML_STYLE_TITLE_VERTICAL_PADDING + ">"); //$NON-NLS-1$ sb.append(" <div class='action-button-25' style='" + onOffImage + "'></div>"); //$NON-NLS-1$ //$NON-NLS-2$ sb.append(HTML_TD_END); sb.append("<td class='folderInfo' " + HTML_STYLE_TITLE_VERTICAL_PADDING + ">" + watchingText //$NON-NLS-1$//$NON-NLS-2$ + HTML_TD_END); sb.append(HTML_TR_END); } sb.append("</tbody></table>"); //$NON-NLS-1$ /* * Import files */ if (numNotImportedFiles > 0) { createHTML_58_NotImportedFiles(sb, notImportedFiles); } final String htmlTooltip = sb.toString(); /* * All states */ final String imageUrl = isFolderOK ? _imageUrl_DeviceFolder_OK : _imageUrl_DeviceFolder_NotAvailable; final String stateImage = createHTML_BgImageStyle(imageUrl); final String stateIconValue = isDeviceFolderOK ? Integer.toString(numNotImportedFiles) : UI.EMPTY_STRING; /* * Show overflow scrollbar ONLY when more than 10 entries are available because it looks * ugly. */ final String cssOverflow = numNotImportedFiles > 10 // ? "style='overflow-y: scroll;'" //$NON-NLS-1$ : UI.EMPTY_STRING; final String html = "\n"// //$NON-NLS-1$ + "<a class='importState dash-action'" // //$NON-NLS-1$ + (" href='" + hrefAction + "'") //$NON-NLS-1$ //$NON-NLS-2$ + ">" //$NON-NLS-1$ + (" <div class='stateIcon' " + stateImage + ">\n") //$NON-NLS-1$ //$NON-NLS-2$ + (" <div class='stateIconValue'>" + stateIconValue + "</div>\n") //$NON-NLS-1$ //$NON-NLS-2$ + (" </div>\n") //$NON-NLS-1$ + (" <div class='stateTooltip' " + cssOverflow + ">" + htmlTooltip + "</div>\n") //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + "</a>\n"; //$NON-NLS-1$ return html; } /** * @param sb * @param folderLocation * @param isOSFolderValid * @param isTopMargin * @param folderTitle * @param folderInfo */ private void createHTML_56_FolderState(final StringBuilder sb, final String folderLocation, final boolean isOSFolderValid, final boolean isTopMargin, final String folderTitle, final String folderInfo) { String htmlErrorState; String htmlFolderInfo; if (isOSFolderValid) { htmlErrorState = UI.EMPTY_STRING; htmlFolderInfo = folderInfo == null // ? UI.EMPTY_STRING : "<span class='folderInfo'>" + folderInfo + "</span>"; //$NON-NLS-1$ //$NON-NLS-2$ } else { htmlErrorState = "<div class='folderError'>" + Messages.Import_Data_HTML_FolderIsNotAvailable //$NON-NLS-1$ + "</div>"; //$NON-NLS-1$ htmlFolderInfo = UI.EMPTY_STRING; } final String paddingTop = isTopMargin // ? HTML_STYLE_TITLE_VERTICAL_PADDING : UI.EMPTY_STRING; final String imageUrl = isOSFolderValid // ? _imageUrl_State_OK : _imageUrl_State_Error; final String folderStateIcon = "<img src='" //$NON-NLS-1$ + imageUrl + "' style='padding-left:5px; vertical-align:text-bottom;'>"; //$NON-NLS-1$ sb.append(HTML_TR); sb.append(HTML_TD_SPACE + paddingTop + " class='folderTitle'>" + folderTitle + HTML_TD_END); //$NON-NLS-1$ sb.append(HTML_TD_SPACE + paddingTop + " class='folderLocation'>" + folderLocation + folderStateIcon); //$NON-NLS-1$ sb.append(htmlErrorState); sb.append(HTML_TD_END); sb.append(HTML_TR_END); sb.append(HTML_TR); sb.append("<td></td>"); //$NON-NLS-1$ sb.append(HTML_TD + htmlFolderInfo + HTML_TD_END); sb.append(HTML_TR_END); } private void createHTML_58_NotImportedFiles(final StringBuilder sb, final ArrayList<OSFile> notImportedFiles) { sb.append("<table border=0 class='deviceList'><tbody>"); //$NON-NLS-1$ for (final OSFile deviceFile : notImportedFiles) { final String fileMoveState = deviceFile.isBackupImportFile ? Messages.Import_Data_HTML_Title_Moved_State : UI.EMPTY_STRING; final String filePathName = UI.replaceHTML_BackSlash(deviceFile.getPath().getParent().toString()); final ZonedDateTime modifiedTime = TimeTools.getZonedDateTime(deviceFile.modifiedTime); sb.append(HTML_TR); sb.append("<td width=1 class='column'>"); //$NON-NLS-1$ sb.append(fileMoveState); sb.append(HTML_TD_END); sb.append("<td class='column content'>"); //$NON-NLS-1$ sb.append(deviceFile.getFileName()); sb.append(HTML_TD_END); // this is for debugging sb.append("<td class='column content'>"); //$NON-NLS-1$ sb.append(filePathName); sb.append(HTML_TD_END); sb.append("<td class='column right'>"); //$NON-NLS-1$ sb.append(modifiedTime.format(TimeTools.Formatter_Date_S)); sb.append(HTML_TD_END); sb.append("<td class='column right'>"); //$NON-NLS-1$ sb.append(modifiedTime.format(TimeTools.Formatter_Time_S)); sb.append(HTML_TD_END); sb.append("<td class='right'>"); //$NON-NLS-1$ sb.append(deviceFile.size); sb.append(HTML_TD_END); sb.append(HTML_TR_END); } sb.append("</tbody></table>"); //$NON-NLS-1$ } private String createHTML_60_SelectImportConfig() { final String onChange = "onchange='" + JS_FUNCTION_ON_SELECT_IMPORT_CONFIG + "(this.selectedIndex)'"; //$NON-NLS-1$ //$NON-NLS-2$ final EasyConfig easyConfig = getEasyConfig(); final ImportConfig selectedConfig = easyConfig.getActiveImportConfig(); final StringBuilder sb = new StringBuilder(); sb.append("<div class='selectConfigContainer'>"); //$NON-NLS-1$ sb.append(" <select class='selectConfig dash-action' " + onChange + ">"); //$NON-NLS-1$ //$NON-NLS-2$ for (final ImportConfig importConfig : easyConfig.importConfigs) { final String isSelected = importConfig.equals(selectedConfig)// ? "selected" //$NON-NLS-1$ : UI.EMPTY_STRING; sb.append(" <option class='selectOption' " + isSelected + ">" + importConfig.name + "</option>"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ } sb.append(" </select>"); //$NON-NLS-1$ sb.append("</div>"); //$NON-NLS-1$ return sb.toString(); } private void createHTML_80_Easy_Tiles(final StringBuilder sb) { final EasyConfig easyConfig = getEasyConfig(); final ArrayList<ImportLauncher> allImportLauncher = easyConfig.importLaunchers; final ArrayList<ImportConfig> allImportConfigs = easyConfig.importConfigs; if (allImportLauncher.size() == 0 || allImportConfigs.size() == 0) { // this case should not happen TourLogManager.logEx(new Exception("Import config/launcher are not setup correctly."));//$NON-NLS-1$ return; } // get available launcher int availableLauncher = 0; for (final ImportLauncher importLauncher : allImportLauncher) { if (importLauncher.isShowInDashboard) { availableLauncher++; } } int tileIndex = 0; int numHorizontalTiles = easyConfig.numHorizontalTiles; boolean isTrOpen = false; // reduce max tiles, otherwise there would be a BIG gap between tiles if (availableLauncher < numHorizontalTiles) { numHorizontalTiles = availableLauncher; } final String watchClass = isWatchingOn() // ? DOM_CLASS_DEVICE_ON : DOM_CLASS_DEVICE_OFF; sb.append("<table border=0" //$NON-NLS-1$ + (" id='" + DOM_ID_IMPORT_TILES + "'") //$NON-NLS-1$ //$NON-NLS-2$ + (" style='margin-top:5px;'") //$NON-NLS-1$ + (" class='" + watchClass + "'") //$NON-NLS-1$ //$NON-NLS-2$ + "><tbody>\n"); //$NON-NLS-1$ for (final ImportLauncher importLauncher : allImportLauncher) { if (importLauncher.isShowInDashboard) { if (tileIndex % numHorizontalTiles == 0) { sb.append("<tr>\n"); //$NON-NLS-1$ isTrOpen = true; } // enforce equal column width sb.append("<td style='width:" + 100 / numHorizontalTiles + "%' class='import-tile'>\n"); //$NON-NLS-1$ //$NON-NLS-2$ sb.append(createHTML_82_Easy_Tile(importLauncher)); sb.append("</td>\n"); //$NON-NLS-1$ if (tileIndex % numHorizontalTiles == numHorizontalTiles - 1) { sb.append("</tr>\n"); //$NON-NLS-1$ isTrOpen = false; } tileIndex++; } } if (isTrOpen) { sb.append("</tr>\n"); //$NON-NLS-1$ } sb.append("</tbody></table>\n"); //$NON-NLS-1$ } private String createHTML_82_Easy_Tile(final ImportLauncher importTile) { /* * Tooltip */ final String tooltip = createHTML_84_TileTooltip(importTile); /* * Tile image */ final Image tileImage = getImportConfigImage(importTile); String htmlImage = UI.EMPTY_STRING; if (tileImage != null) { final byte[] pngImageData = ImageUtils.formatImage(tileImage, SWT.IMAGE_PNG); final String base64Encoded = Base64.getEncoder().encodeToString(pngImageData); htmlImage = "<img src='data:image/png;base64," + base64Encoded + "'>"; //$NON-NLS-1$ //$NON-NLS-2$ } /* * Tile HTML */ final String href = HTTP_DUMMY + HREF_ACTION_DEVICE_IMPORT + HREF_TOKEN + importTile.getId(); final String htmlConfig = createHTML_86_Annotations(importTile); final String html = "" //$NON-NLS-1$ + ("<a href='" + href + "' title='" + tooltip + "' class='import-tile'>\n") //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + (" <div class='import-tile-image'>" + htmlImage + "</div>\n") //$NON-NLS-1$ //$NON-NLS-2$ + (" <div class='import-tile-config'>" + htmlConfig + "</div>\n") //$NON-NLS-1$ //$NON-NLS-2$ + ("</a>\n") //$NON-NLS-1$ ; return html; } private String createHTML_84_TileTooltip(final ImportLauncher importLauncher) { boolean isTextAdded = false; final StringBuilder sb = new StringBuilder(); final String tileName = importLauncher.name.trim(); final String tileDescription = importLauncher.description.trim(); final StringBuilder ttText = new StringBuilder(); final Enum<TourTypeConfig> ttConfig = importLauncher.tourTypeConfig; if (TourTypeConfig.TOUR_TYPE_CONFIG_BY_SPEED.equals(ttConfig)) { final ArrayList<SpeedTourType> speedTourTypes = importLauncher.speedTourTypes; boolean isSpeedAdded = false; for (final SpeedTourType speedTT : speedTourTypes) { if (isSpeedAdded) { ttText.append(UI.NEW_LINE); } final long tourTypeId = speedTT.tourTypeId; final double avgSpeed = (speedTT.avgSpeed / net.tourbook.ui.UI.UNIT_VALUE_DISTANCE) + 0.0001; ttText.append((int) avgSpeed); ttText.append(UI.SPACE); ttText.append(UI.UNIT_LABEL_SPEED); ttText.append(UI.DASH_WITH_DOUBLE_SPACE); ttText.append(net.tourbook.ui.UI.getTourTypeLabel(tourTypeId)); isSpeedAdded = true; } } else if (TourTypeConfig.TOUR_TYPE_CONFIG_ONE_FOR_ALL.equals(ttConfig)) { final TourType oneTourType = importLauncher.oneTourType; if (oneTourType != null) { final String ttName = oneTourType.getName(); // show this text only when the name is different if (!tileName.equals(ttName)) { ttText.append(ttName); } } } // tour type name if (tileName.length() > 0) { sb.append(tileName); isTextAdded = true; } // tour type description if (tileDescription.length() > 0) { if (isTextAdded) { sb.append(UI.NEW_LINE2); } sb.append(tileDescription); isTextAdded = true; } // tour type text if (ttText.length() > 0) { if (isTextAdded) { sb.append(UI.NEW_LINE2); } sb.append(ttText); isTextAdded = true; } sb.append(UI.NEW_LINE2); // last marker { final double distance = importLauncher.lastMarkerDistance / 1000.0 / net.tourbook.ui.UI.UNIT_VALUE_DISTANCE; final String distanceValue = _nf1.format(distance) + UI.SPACE1 + UI.UNIT_LABEL_DISTANCE; sb.append(importLauncher.isSetLastMarker // ? NLS.bind(Messages.Import_Data_HTML_LastMarker_Yes, distanceValue, importLauncher.lastMarkerText) : Messages.Import_Data_HTML_LastMarker_No); } // adjust temperature { sb.append(UI.NEW_LINE); if (importLauncher.isAdjustTemperature) { final float temperature = UI.convertTemperatureFromMetric(importLauncher.tourAvgTemperature); final String temperatureText = NLS.bind(Messages.Import_Data_HTML_AdjustTemperature_Yes, // new Object[] { getDurationText(importLauncher), _nf1.format(temperature), UI.UNIT_LABEL_TEMPERATURE }); sb.append(temperatureText); } else { sb.append(Messages.Import_Data_HTML_AdjustTemperature_No); } } // save tour { sb.append(UI.NEW_LINE); sb.append(importLauncher.isSaveTour ? Messages.Import_Data_HTML_SaveTour_Yes : Messages.Import_Data_HTML_SaveTour_No); } // delete device files { sb.append(UI.NEW_LINE); sb.append(getEasyConfig().getActiveImportConfig().isDeleteDeviceFiles ? Messages.Import_Data_HTML_DeleteDeviceFiles_Yes : Messages.Import_Data_HTML_DeleteDeviceFiles_No); } return sb.toString(); } private String createHTML_86_Annotations(final ImportLauncher importTile) { /* * Save tour */ String htmlSaveTour = UI.EMPTY_STRING; if (importTile.isSaveTour) { final String stateImage = createHTML_BgImage(_imageUrl_State_SaveTour); htmlSaveTour = createHTML_TileAnnotation(stateImage); } /* * AdjustTemperature */ String htmlAdjustTemperature = UI.EMPTY_STRING; if (importTile.isAdjustTemperature) { final String stateImage = createHTML_BgImage(_imageUrl_State_AdjustTemperature); htmlAdjustTemperature = createHTML_TileAnnotation(stateImage); } /* * Marker */ String htmlLastMarker = UI.EMPTY_STRING; if (importTile.isSetLastMarker) { final String stateImage = createHTML_BgImage(_imageUrl_State_TourMarker); htmlLastMarker = createHTML_TileAnnotation(stateImage); } /* * Delete device files */ String htmlDeleteFiles = UI.EMPTY_STRING; if (getEasyConfig().getActiveImportConfig().isDeleteDeviceFiles) { final String stateImage = createHTML_BgImage(_imageUrl_State_MovedFiles); htmlDeleteFiles = createHTML_TileAnnotation(stateImage); } final StringBuilder sb = new StringBuilder(); // order is reverted that it looks in the correct order sb.append(htmlDeleteFiles); sb.append(htmlSaveTour); sb.append(htmlAdjustTemperature); sb.append(htmlLastMarker); sb.append("<div style='float:left;'>" + importTile.name + "</div>"); //$NON-NLS-1$ //$NON-NLS-2$ return sb.toString(); } private void createHTML_90_SimpleImport(final StringBuilder sb) { sb.append("<div class='get-tours-items'>\n"); //$NON-NLS-1$ sb.append(" <table><tbody><tr>\n"); //$NON-NLS-1$ { createHTML_92_TileAction(sb, Messages.Import_Data_HTML_ImportFromFiles_Action, Messages.Import_Data_HTML_ImportFromFiles_ActionTooltip, (HTTP_DUMMY + HREF_ACTION_IMPORT_FROM_FILES), _imageUrl_ImportFromFile); createHTML_92_TileAction(sb, Messages.Import_Data_HTML_ReceiveFromSerialPort_ConfiguredAction, Messages.Import_Data_HTML_ReceiveFromSerialPort_ConfiguredLink, (HTTP_DUMMY + HREF_ACTION_SERIAL_PORT_CONFIGURED), _imageUrl_SerialPort_Configured); createHTML_92_TileAction(sb, Messages.Import_Data_HTML_ReceiveFromSerialPort_DirectlyAction, Messages.Import_Data_HTML_ReceiveFromSerialPort_DirectlyLink, (HTTP_DUMMY + HREF_ACTION_SERIAL_PORT_DIRECTLY), _imageUrl_SerialPort_Directly); createHTML_92_TileAction(sb, Messages.Import_Data_HTML_Action_OldUI, Messages.Import_Data_HTML_Action_OldUI_Tooltip, (HTTP_DUMMY + HREF_ACTION_OLD_UI), null); } sb.append(" </tr></tbody></table>\n"); // //$NON-NLS-1$ sb.append("</div>\n"); //$NON-NLS-1$ } private void createHTML_92_TileAction(final StringBuilder sb, final String name, final String tooltip, final String href, final String imageUrl) { String htmlImage = UI.EMPTY_STRING; if (imageUrl != null) { htmlImage = "style='" // //$NON-NLS-1$ + ("background-image: url(" + imageUrl + ");\n") //$NON-NLS-1$ //$NON-NLS-2$ // + "'"; //$NON-NLS-1$ } final String validTooltip = tooltip.replace("'", ""); //$NON-NLS-1$ //$NON-NLS-2$ final String html = "" //$NON-NLS-1$ + HTML_TD + ("<a href='" + href + "' title='" + validTooltip + "' class='import-tile'>\n") //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + (" <div class='import-tile-image action-button' " + htmlImage + "></div>\n") //$NON-NLS-1$ //$NON-NLS-2$ + (" <div class='import-tile-config'>" + name + "</div>\n") //$NON-NLS-1$ //$NON-NLS-2$ + ("</a>\n") //$NON-NLS-1$ + HTML_TD_END; sb.append(html); } private String createHTML_BgImage(final String imageUrl) { final String encodedImageUrl = WEB.encodeSpace(imageUrl); return "background-image: url(" + encodedImageUrl + ");"; //$NON-NLS-1$ //$NON-NLS-2$ } private String createHTML_BgImageStyle(final String imageUrl) { final String bgImage = createHTML_BgImage(imageUrl); return "style='" + bgImage + "'"; //$NON-NLS-1$ //$NON-NLS-2$ } private String createHTML_TileAnnotation(final String imageBgStyle) { return "<div style='float: right;" + imageBgStyle + "' class='action-button-16'></div>"; //$NON-NLS-1$ //$NON-NLS-2$ } @Override public void createPartControl(final Composite parent) { initUI(parent); // define all columns _columnManager = new ColumnManager(this, _state); _columnManager.setIsCategoryAvailable(true); defineAllColumns(); createUI(parent); createActions(); fillToolbar(); addPartListener(); addSelectionListener(); addPrefListener(); addTourEventListener(); // set this view part as selection provider getSite().setSelectionProvider(_postSelectionProvider = new PostSelectionProvider(ID)); _activePerson = TourbookPlugin.getActivePerson(); // prevent that the UI start is run twice, 2nd would be in the part listener _newActivePerson = _activePerson; enableActions(); restoreState(); // the part visible listener shows the top page also updateUI_1_TopPage(true); } private void createResources_Image() { _images = new ImageRegistry(); /* * Database */ _images.put(IMAGE_DATABASE, // TourbookPlugin.getImageDescriptor(Messages.Image__database)); _images.put(IMAGE_DATABASE_OTHER_PERSON, // TourbookPlugin.getImageDescriptor(Messages.Image__database_other_person)); _images.put(IMAGE_ASSIGN_MERGED_TOUR, // TourbookPlugin.getImageDescriptor(Messages.Image__assignMergedTour)); _images.put(IMAGE_ICON_PLACEHOLDER, // TourbookPlugin.getImageDescriptor(Messages.Image__icon_placeholder)); _images.put(IMAGE_DELETE, // TourbookPlugin.getImageDescriptor(Messages.Image__delete)); /* * Import state */ _images.put(IMAGE_STATE_DELETE, // TourbookPlugin.getImageDescriptor(Messages.Image__State_DeletedTour_View)); _images.put(IMAGE_STATE_MOVED, // TourbookPlugin.getImageDescriptor(Messages.Image__State_MovedTour_View)); /* * Data transfer */ _images.put(IMAGE_DATA_TRANSFER, // TourbookPlugin.getImageDescriptor(Messages.Image__RawData_Transfer)); _images.put(IMAGE_DATA_TRANSFER_DIRECT, // TourbookPlugin.getImageDescriptor(Messages.Image__RawData_TransferDirect)); _images.put(IMAGE_IMPORT_FROM_FILES, // TourbookPlugin.getImageDescriptor(Messages.Image__RawData_Import)); _images.put(IMAGE_NEW_UI, // TourbookPlugin.getImageDescriptor(Messages.Image__RawData_DashboardUI)); } private void createResources_Web() { try { /* * Font css must be on the top */ final File fontFile = WEB.getResourceFile(WEB_RESOURCE_TITLE_FONT); final Path path = Paths.get(fontFile.getAbsolutePath()); final byte[] data = Files.readAllBytes(path); final String base64Encoded = Base64.getEncoder().encodeToString(data); _cssFonts = "<style>\n" // //$NON-NLS-1$ + ("@font-face\n") //$NON-NLS-1$ + ("{\n") //$NON-NLS-1$ // + (" font-family: 'NothingYouCouldDo';\n") //$NON-NLS-1$ + (" font-family: 'Nunito-Bold';\n") //$NON-NLS-1$ + (" font-weight: 700;\n") //$NON-NLS-1$ + (" font-style: bold;\n") //$NON-NLS-1$ + (" src: url(data:font/truetype;charset=utf-8;base64," + base64Encoded //$NON-NLS-1$ + ") format('truetype');") //$NON-NLS-1$ + ("}\n") //$NON-NLS-1$ + "</style>\n"; //$NON-NLS-1$ /* * Webpage css */ File webFile = WEB.getResourceFile(WEB_RESOURCE_TOUR_IMPORT_CSS); final String css = Util.readContentFromFile(webFile.getAbsolutePath()); String css3 = UI.EMPTY_STRING; /* * Eclipse 3.8 with Linux has only a limited css3 support -> DISABLED */ if (UI.IS_WIN) { webFile = WEB.getResourceFile(WEB_RESOURCE_TOUR_IMPORT_CSS3); css3 = Util.readContentFromFile(webFile.getAbsolutePath()); } _cssFromFile = ""// //$NON-NLS-1$ + "<style>\n" //$NON-NLS-1$ + css + css3 + "</style>\n"; //$NON-NLS-1$ /* * Image urls */ _imageUrl_ImportFromFile = getIconUrl(Messages.Image__RawData_Import); _imageUrl_SerialPort_Configured = getIconUrl(Messages.Image__RawData_Transfer); _imageUrl_SerialPort_Directly = getIconUrl(Messages.Image__RawData_TransferDirect); _imageUrl_State_AdjustTemperature = getIconUrl(Messages.Image__State_AdjustTemperature); _imageUrl_State_Error = getIconUrl(Messages.Image__State_Error); _imageUrl_State_OK = getIconUrl(Messages.Image__State_OK); _imageUrl_State_MovedFiles = getIconUrl(Messages.Image__State_MovedTour); _imageUrl_State_SaveTour = getIconUrl(Messages.Image__State_SaveTour); _imageUrl_State_TourMarker = getIconUrl(Messages.Image__State_TourMarker); _imageUrl_Device_TurnOff = getIconUrl(Messages.Image__RawData_Device_TurnOff); _imageUrl_Device_TurnOn = getIconUrl(Messages.Image__RawData_Device_TurnOn); _imageUrl_DeviceFolder_OK = getIconUrl(Messages.Image__RawData_DeviceFolder); _imageUrl_DeviceFolder_Disabled = getIconUrl(Messages.Image__RawData_DeviceFolderDisabled); _imageUrl_DeviceFolder_NotAvailable = getIconUrl(Messages.Image__RawData_DeviceFolder_NotDefined); _imageUrl_DeviceFolder_NotChecked = getIconUrl(Messages.Image__RawData_DeviceFolder_NotChecked); _imageUrl_DeviceFolder_NotSetup = getIconUrl(Messages.Image__RawData_DeviceFolder_NotSetup); } catch (final IOException | URISyntaxException e) { TourLogManager.logEx(e); } } private void createUI(final Composite parent) { _topPageBook = new PageBook(parent, SWT.NONE); GridDataFactory.fillDefaults().grab(true, true).applyTo(_topPageBook); _topPage_OldUI = createUI_05_Page_OldUI(_topPageBook); _topPage_Startup = createUI_10_Page_Startup(_topPageBook); _topPage_ImportViewer = createUI_90_Page_TourViewer(_topPageBook); _topPageBook.showPage(_topPage_Startup); } private Composite createUI_05_Page_OldUI(final Composite parent) { final int defaultWidth = 300; final Composite container = new Composite(parent, SWT.NONE); GridDataFactory.fillDefaults().grab(true, true).applyTo(container); GridLayoutFactory.swtDefaults().numColumns(2).applyTo(container); // container.setBackground(Display.getCurrent().getSystemColor(SWT.COLOR_BLUE)); { { /* * Import info */ final Label label = new Label(container, SWT.WRAP); label.setText(Messages.Import_Data_OldUI_Label_Info); GridDataFactory.fillDefaults()// .hint(defaultWidth, SWT.DEFAULT).grab(true, false).span(2, 1).applyTo(label); } { /* * Import */ // icon final CLabel iconImport = new CLabel(container, SWT.NONE); iconImport.setImage(_images.get(IMAGE_IMPORT_FROM_FILES)); GridDataFactory.fillDefaults()// .indent(0, 10).align(SWT.CENTER, SWT.BEGINNING) // .grab(true, false) .applyTo(iconImport); // link _linkImport = new Link(container, SWT.NONE); _linkImport.setText(Messages.Import_Data_OldUI_Link_Import); _linkImport.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(final SelectionEvent e) { _rawDataMgr.actionImportFromFile(); } }); GridDataFactory.fillDefaults()// .hint(defaultWidth, SWT.DEFAULT).align(SWT.FILL, SWT.CENTER).grab(true, false).indent(0, 10) .applyTo(_linkImport); } { /* * Data transfer */ // icon final CLabel iconTransfer = new CLabel(container, SWT.NONE); iconTransfer.setImage(_images.get(IMAGE_DATA_TRANSFER)); GridDataFactory.fillDefaults()// .align(SWT.CENTER, SWT.BEGINNING) // .grab(true, false) .indent(0, 10).applyTo(iconTransfer); // link final Link linkTransfer = new Link(container, SWT.NONE); linkTransfer.setText(Messages.Import_Data_OldUI_Link_ReceiveFromSerialPort_Configured); linkTransfer.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(final SelectionEvent e) { _rawDataMgr.actionImportFromDevice(); } }); GridDataFactory.fillDefaults()// .hint(defaultWidth, SWT.DEFAULT).align(SWT.FILL, SWT.CENTER) // .grab(true, false) .indent(0, 10).applyTo(linkTransfer); } { /* * Direct data transfer */ // icon final CLabel iconDirectTransfer = new CLabel(container, SWT.NONE); iconDirectTransfer.setImage(_images.get(IMAGE_DATA_TRANSFER_DIRECT)); GridDataFactory.fillDefaults()// .align(SWT.CENTER, SWT.BEGINNING) // .grab(true, false) .indent(0, 10).applyTo(iconDirectTransfer); // link final Link linkTransferDirect = new Link(container, SWT.NONE); linkTransferDirect.setText(Messages.Import_Data_OldUI_Link_ReceiveFromSerialPort_Directly); linkTransferDirect.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(final SelectionEvent e) { _rawDataMgr.actionImportFromDeviceDirect(); } }); GridDataFactory.fillDefaults() // .hint(defaultWidth, SWT.DEFAULT).align(SWT.FILL, SWT.CENTER).grab(true, false).indent(0, 10) .applyTo(linkTransferDirect); } { /* * New UI */ // icon final CLabel icon = new CLabel(container, SWT.NONE); icon.setImage(_images.get(IMAGE_NEW_UI)); GridDataFactory.fillDefaults().indent(0, 10).applyTo(icon); // link final Link link = new Link(container, SWT.NONE); link.setText(Messages.Import_Data_OldUI_Link_ShowNewUI); link.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(final SelectionEvent e) { onSelectUI_New(); } }); GridDataFactory.fillDefaults()// .hint(defaultWidth, SWT.DEFAULT).align(SWT.FILL, SWT.CENTER).grab(true, false).indent(0, 10) .applyTo(link); } { /* * Hint */ final Label label = new Label(container, SWT.WRAP); label.setText(Messages.Import_Data_OldUI_Label_Hint); GridDataFactory.fillDefaults()// .hint(defaultWidth, SWT.DEFAULT).grab(true, false).indent(0, 20).span(2, 1).applyTo(label); } } return container; } /** * This page is displayed until the first page of the browser is loaded. * * @param parent * @return */ private Composite createUI_10_Page_Startup(final Composite parent) { final Composite container = new Composite(parent, SWT.NONE); GridDataFactory.fillDefaults().grab(true, true).applyTo(container); GridLayoutFactory.fillDefaults().numColumns(1).applyTo(container); // { // final Label label = new Label(container, SWT.NONE); // GridDataFactory.fillDefaults().grab(true, true).align(SWT.CENTER, SWT.CENTER).applyTo(label); // label.setText("TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST "); //$NON-NLS-1$ // } return container; } private Composite createUI_20_Page_Dashboard(final Composite parent) { final Color bgColor = Display.getCurrent().getSystemColor(SWT.COLOR_LIST_BACKGROUND); _dashboard_PageBook = new PageBook(parent, SWT.NONE); GridDataFactory.fillDefaults().grab(true, true).applyTo(_dashboard_PageBook); _dashboardPage_NoBrowser = new Composite(_dashboard_PageBook, SWT.NONE); _dashboardPage_NoBrowser.setBackground(bgColor); GridDataFactory.fillDefaults().grab(true, true).applyTo(_dashboardPage_NoBrowser); GridLayoutFactory.swtDefaults().numColumns(1).applyTo(_dashboardPage_NoBrowser); { _txtNoBrowser = new Text(_dashboardPage_NoBrowser, SWT.WRAP | SWT.READ_ONLY); _txtNoBrowser.setText(Messages.UI_Label_BrowserCannotBeCreated); _txtNoBrowser.setBackground(bgColor); GridDataFactory.fillDefaults()// .grab(true, true).align(SWT.FILL, SWT.BEGINNING).applyTo(_txtNoBrowser); } _dashboardPage_WithBrowser = new Composite(_dashboard_PageBook, SWT.NONE); GridLayoutFactory.fillDefaults().applyTo(_dashboardPage_WithBrowser); { createUI_22_Browser(_dashboardPage_WithBrowser); } return _dashboard_PageBook; } private void createUI_22_Browser(final Composite parent) { try { try { // use default browser _browser = new Browser(parent, SWT.NONE); // initial setup _browser.setRedraw(false); } catch (final Exception e) { // /* // * Use mozilla browser, this is necessary for Linux when default browser fails // * however the XULrunner needs to be installed. // */ // _browser = new Browser(parent, SWT.MOZILLA); } if (_browser != null) { GridDataFactory.fillDefaults().grab(true, true).applyTo(_browser); new JS_OnSelectImportConfig(_browser, JS_FUNCTION_ON_SELECT_IMPORT_CONFIG); _browser.addLocationListener(new LocationAdapter() { @Override public void changed(final LocationEvent event) { // _browser.removeLocationListener(this); // function.dispose(); } @Override public void changing(final LocationEvent event) { onBrowser_LocationChanging(event); } }); _browser.addProgressListener(new ProgressAdapter() { @Override public void completed(final ProgressEvent event) { onBrowser_Completed(event); } }); } } catch (final SWTError e) { _txtNoBrowser.setText(NLS.bind(Messages.UI_Label_BrowserCannotBeCreated_Error, e.getMessage())); } finally { showFailbackUI(); } } private Composite createUI_90_Page_TourViewer(final Composite parent) { _viewerContainer = new Composite(parent, SWT.NONE); GridLayoutFactory.fillDefaults().applyTo(_viewerContainer); { createUI_92_TourViewer(_viewerContainer); } return _viewerContainer; } /** * @param parent */ private void createUI_92_TourViewer(final Composite parent) { // table final Table table = new Table(parent, SWT.H_SCROLL | SWT.V_SCROLL | SWT.FULL_SELECTION | SWT.MULTI); table.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); table.setHeaderVisible(true); table.setLinesVisible(_prefStore.getBoolean(ITourbookPreferences.VIEW_LAYOUT_DISPLAY_LINES)); _tourViewer = new TableViewer(table); _columnManager.createColumns(_tourViewer); // table viewer _tourViewer.setContentProvider(new TourDataContentProvider()); _tourViewer.setComparator(_importComparator); _tourViewer.addDoubleClickListener(new IDoubleClickListener() { @Override public void doubleClick(final DoubleClickEvent event) { final Object firstElement = ((IStructuredSelection) _tourViewer.getSelection()).getFirstElement(); if ((firstElement != null) && (firstElement instanceof TourData)) { TourManager.getInstance().tourDoubleClickAction(RawDataView.this, _tourDoubleClickState); } } }); _tourViewer.addSelectionChangedListener(new ISelectionChangedListener() { @Override public void selectionChanged(final SelectionChangedEvent event) { if (_isInUpdate) { return; } fireSelectedTour(); } }); // set tour info tooltip provider _tourInfoToolTip = new TableViewerTourInfoToolTip(_tourViewer); /* * Setup tour comparator */ _importComparator.__sortColumnId = _columnId_TourStartDate; _importComparator.__sortDirection = ImportComparator.ASCENDING; // show the sorting indicator in the viewer updateUI_ShowSortDirection(// _importComparator.__sortColumnId, _importComparator.__sortDirection); createUI_94_ContextMenu(); } /** * create the views context menu */ private void createUI_94_ContextMenu() { final Table table = (Table) _tourViewer.getControl(); final MenuManager menuMgr = new MenuManager("#PopupMenu"); //$NON-NLS-1$ menuMgr.setRemoveAllWhenShown(true); menuMgr.addMenuListener(new IMenuListener() { @Override public void menuAboutToShow(final IMenuManager manager) { fillContextMenu(manager); } }); final Menu tableContextMenu = menuMgr.createContextMenu(table); tableContextMenu.addMenuListener(new MenuAdapter() { @Override public void menuHidden(final MenuEvent e) { _tagMenuMgr.onHideMenu(); } @Override public void menuShown(final MenuEvent menuEvent) { _tagMenuMgr.onShowMenu(menuEvent, table, Display.getCurrent().getCursorLocation(), _tourInfoToolTip); } }); getSite().registerContextMenu(menuMgr, _tourViewer); _columnManager.createHeaderContextMenu(table, tableContextMenu); } private void createUI_NewUI() { /* * Create new UI only when it is used to prevent that the app is crashing when the old UI is * used */ if (_topPage_Dashboard == null) { _topPage_Dashboard = createUI_20_Page_Dashboard(_topPageBook); } } /** * Defines all columns for the table viewer in the column manager, the sequenze defines the * default columns * * @param parent */ private void defineAllColumns() { defineColumn_State_Import(); defineColumn_State_Database(); defineColumn_Time_TourDate(); defineColumn_Time_TourStartTime(); defineColumn_Time_RecordingTime(); defineColumn_Time_DrivingTime(); defineColumn_Time_TimeZone(); defineColumn_Time_TimeZoneDifference(); defineColumn_Tour_Type(); defineColumn_Tour_TypeText(); defineColumn_Tour_Title(); defineColumn_Tour_Tags(); defineColumn_Tour_Marker(); defineColumn_Motion_Distance(); defineColumn_Motion_AvgSpeed(); defineColumn_Motion_AvgPace(); defineColumn_Altitude_Up(); defineColumn_Altitude_Down(); defineColumn_Weather_Clouds(); defineColumn_Body_Calories(); defineColumn_Device_Name(); defineColumn_Device_Profile(); defineColumn_Data_ImportFileName(); defineColumn_Data_ImportFilePath(); defineColumn_Date_TimeInterval(); // must be called before the columns are created but after they are defined updateUI_TourViewerColumns(); } /** * column: altitude down */ private void defineColumn_Altitude_Down() { final ColumnDefinition colDef = TableColumnFactory.ALTITUDE_SUMMARIZED_BORDER_DOWN .createColumn(_columnManager, _pc); colDef.setLabelProvider(new CellLabelProvider() { @Override public void update(final ViewerCell cell) { final double dbValue = ((TourData) cell.getElement()).getTourAltDown(); final double value = -dbValue / net.tourbook.ui.UI.UNIT_VALUE_ALTITUDE; colDef.printValue_0(cell, value); } }); } /** * column: altitude up */ private void defineColumn_Altitude_Up() { final ColumnDefinition colDef = TableColumnFactory.ALTITUDE_SUMMARIZED_BORDER_UP .createColumn(_columnManager, _pc); colDef.setIsDefaultColumn(); colDef.setLabelProvider(new CellLabelProvider() { @Override public void update(final ViewerCell cell) { final double dbValue = ((TourData) cell.getElement()).getTourAltUp(); final double value = dbValue / net.tourbook.ui.UI.UNIT_VALUE_ALTITUDE; colDef.printValue_0(cell, value); } }); } /** * column: calories (cal) */ private void defineColumn_Body_Calories() { final TableColumnDefinition colDef = TableColumnFactory.BODY_CALORIES.createColumn(_columnManager, _pc); colDef.setLabelProvider(new CellLabelProvider() { @Override public void update(final ViewerCell cell) { final TourData element = (TourData) cell.getElement(); final long value = element.getCalories(); cell.setText(FormatManager.formatNumber_0(value)); } }); } /** * column: import file name */ private void defineColumn_Data_ImportFileName() { final ColumnDefinition colDef = TableColumnFactory.DATA_IMPORT_FILE_NAME.createColumn(_columnManager, _pc); colDef.setColumnSelectionListener(_columnSortListener); colDef.setLabelProvider(new CellLabelProvider() { @Override public void update(final ViewerCell cell) { final TourData tourData = (TourData) cell.getElement(); final String importFileName = tourData.getImportFileName(); if (importFileName != null) { cell.setText(importFileName); } } }); _columnId_ImportFileName = colDef.getColumnId(); } /** * column: import file path */ private void defineColumn_Data_ImportFilePath() { final ColumnDefinition colDef = TableColumnFactory.DATA_IMPORT_FILE_PATH.createColumn(_columnManager, _pc); colDef.setLabelProvider(new CellLabelProvider() { @Override public void update(final ViewerCell cell) { final TourData tourData = (TourData) cell.getElement(); final String importFilePath = tourData.getImportFilePath(); if (importFilePath != null) { cell.setText(importFilePath); } } }); } /** * column: time interval */ private void defineColumn_Date_TimeInterval() { final ColumnDefinition colDef = TableColumnFactory.DATA_TIME_INTERVAL.createColumn(_columnManager, _pc); colDef.setLabelProvider(new CellLabelProvider() { @Override public void update(final ViewerCell cell) { cell.setText(Integer.toString(((TourData) cell.getElement()).getDeviceTimeInterval())); } }); } /** * column: device name */ private void defineColumn_Device_Name() { final ColumnDefinition colDef = TableColumnFactory.DEVICE_NAME.createColumn(_columnManager, _pc); colDef.setColumnSelectionListener(_columnSortListener); colDef.setLabelProvider(new CellLabelProvider() { @Override public void update(final ViewerCell cell) { final TourData tourData = (TourData) cell.getElement(); final String deviceName = tourData.getDeviceName(); final String firmwareVersion = tourData.getDeviceFirmwareVersion(); final String name = firmwareVersion.length() == 0// ? deviceName : deviceName + UI.SPACE + UI.SYMBOL_BRACKET_LEFT + firmwareVersion + UI.SYMBOL_BRACKET_RIGHT; cell.setText(name); } }); _columnId_DeviceName = colDef.getColumnId(); } /** * column: device profile */ private void defineColumn_Device_Profile() { final ColumnDefinition colDef = TableColumnFactory.DEVICE_PROFILE.createColumn(_columnManager, _pc); colDef.setLabelProvider(new CellLabelProvider() { @Override public void update(final ViewerCell cell) { cell.setText(((TourData) cell.getElement()).getDeviceModeName()); } }); } /** * column: average pace */ private void defineColumn_Motion_AvgPace() { final ColumnDefinition colDef = TableColumnFactory.MOTION_AVG_PACE.createColumn(_columnManager, _pc); colDef.setIsDefaultColumn(); colDef.setLabelProvider(new CellLabelProvider() { @Override public void update(final ViewerCell cell) { final TourData tourData = (TourData) cell.getElement(); final float tourDistance = tourData.getTourDistance(); final long drivingTime = tourData.getTourDrivingTime(); final float pace = tourDistance == 0 ? // 0 : drivingTime * 1000 / tourDistance * net.tourbook.ui.UI.UNIT_VALUE_DISTANCE; if (pace == 0) { cell.setText(UI.EMPTY_STRING); } else { cell.setText(UI.format_mm_ss((long) pace)); } } }); } /** * column: avg speed */ private void defineColumn_Motion_AvgSpeed() { final ColumnDefinition colDef = TableColumnFactory.MOTION_AVG_SPEED.createColumn(_columnManager, _pc); // show avg speed to verify the tour type by speed colDef.setIsDefaultColumn(); colDef.setLabelProvider(new CellLabelProvider() { @Override public void update(final ViewerCell cell) { final TourData tourData = ((TourData) cell.getElement()); final float tourDistance = tourData.getTourDistance(); final long drivingTime = tourData.getTourDrivingTime(); double value = 0; if (drivingTime != 0) { value = tourDistance / drivingTime * 3.6 / net.tourbook.ui.UI.UNIT_VALUE_DISTANCE; } colDef.printDetailValue(cell, value); } }); } /** * column: distance (km/mile) */ private void defineColumn_Motion_Distance() { final ColumnDefinition colDef = TableColumnFactory.MOTION_DISTANCE.createColumn(_columnManager, _pc); colDef.setIsDefaultColumn(); colDef.setLabelProvider(new CellLabelProvider() { @Override public void update(final ViewerCell cell) { final double tourDistance = ((TourData) cell.getElement()).getTourDistance(); final double value = tourDistance / 1000 / net.tourbook.ui.UI.UNIT_VALUE_DISTANCE; colDef.printDetailValue(cell, value); } }); } /** * Column: Database state */ private void defineColumn_State_Database() { final ColumnDefinition colDef = TableColumnFactory.STATE_DB_STATUS.createColumn(_columnManager, _pc); colDef.setIsDefaultColumn(); colDef.setCanModifyVisibility(false); colDef.setLabelProvider(new CellLabelProvider() { @Override public void update(final ViewerCell cell) { // show the database indicator for the person who owns the tour final TourData tourData = (TourData) cell.getElement(); cell.setImage(getStateImage_Db(tourData)); } }); } /** * Column: Import state */ private void defineColumn_State_Import() { final ColumnDefinition colDef = TableColumnFactory.STATE_IMPORT_STATE.createColumn(_columnManager, _pc); colDef.setIsDefaultColumn(); colDef.setCanModifyVisibility(false); colDef.setLabelProvider(new CellLabelProvider() { @Override public void update(final ViewerCell cell) { final TourData tourData = (TourData) cell.getElement(); final Image stateImage = getStateImage_Import(tourData); cell.setImage(stateImage); } }); } /** * column: driving time */ private void defineColumn_Time_DrivingTime() { final ColumnDefinition colDef = TableColumnFactory.TIME_DRIVING_TIME.createColumn(_columnManager, _pc); colDef.setLabelProvider(new CellLabelProvider() { @Override public void update(final ViewerCell cell) { final long value = ((TourData) cell.getElement()).getTourDrivingTime(); colDef.printDetailValue(cell, value); } }); } /** * column: recording time */ private void defineColumn_Time_RecordingTime() { final ColumnDefinition colDef = TableColumnFactory.TIME_RECORDING_TIME.createColumn(_columnManager, _pc); colDef.setIsDefaultColumn(); colDef.setLabelProvider(new CellLabelProvider() { @Override public void update(final ViewerCell cell) { final long value = ((TourData) cell.getElement()).getTourRecordingTime(); colDef.printDetailValue(cell, value); } }); } /** * column: Timezone */ private void defineColumn_Time_TimeZone() { final TableColumnDefinition colDef = TableColumnFactory.TIME_TIME_ZONE.createColumn(_columnManager, _pc); colDef.setColumnSelectionListener(_columnSortListener); colDef.setLabelProvider(new CellLabelProvider() { @Override public void update(final ViewerCell cell) { final TourData tourData = (TourData) cell.getElement(); final String timeZoneId = tourData.getTimeZoneId(); cell.setText(timeZoneId == null ? UI.EMPTY_STRING : timeZoneId); } }); _columnId_TimeZone = colDef.getColumnId(); } /** * column: Timezone difference */ private void defineColumn_Time_TimeZoneDifference() { _timeZoneOffsetColDef = TableColumnFactory.TIME_TIME_ZONE_DIFFERENCE.createColumn(_columnManager, _pc); _timeZoneOffsetColDef.setLabelProvider(new CellLabelProvider() { @Override public void update(final ViewerCell cell) { final TourData tourData = (TourData) cell.getElement(); final TourDateTime tourDateTime = tourData.getTourDateTime(); cell.setText(tourDateTime.timeZoneOffsetLabel); } }); } /** * column: date */ private void defineColumn_Time_TourDate() { final ColumnDefinition colDef = TableColumnFactory.TIME_TOUR_DATE.createColumn(_columnManager, _pc); colDef.setIsDefaultColumn(); colDef.setCanModifyVisibility(false); colDef.setColumnSelectionListener(_columnSortListener); colDef.setLabelProvider(new TourInfoToolTipCellLabelProvider() { @Override public Long getTourId(final ViewerCell cell) { if (_isToolTipInDate == false) { return null; } return ((TourData) cell.getElement()).getTourId(); } @Override public void update(final ViewerCell cell) { final TourData tourData = (TourData) cell.getElement(); cell.setText(tourData.getTourStartTime().format(TimeTools.Formatter_Date_S)); } }); _columnId_TourStartDate = colDef.getColumnId(); } /** * column: time */ private void defineColumn_Time_TourStartTime() { final ColumnDefinition colDef = TableColumnFactory.TIME_TOUR_START_TIME.createColumn(_columnManager, _pc); colDef.setIsDefaultColumn(); colDef.setCanModifyVisibility(false); colDef.setColumnSelectionListener(_columnSortListener); colDef.setLabelProvider(new TourInfoToolTipCellLabelProvider() { @Override public Long getTourId(final ViewerCell cell) { if (_isToolTipInTime == false) { return null; } return ((TourData) cell.getElement()).getTourId(); } @Override public void update(final ViewerCell cell) { final TourData tourData = (TourData) cell.getElement(); cell.setText(tourData.getTourStartTime().format(TimeTools.Formatter_Time_S)); } }); } /** * column: markers */ private void defineColumn_Tour_Marker() { final ColumnDefinition colDef = TableColumnFactory.TOUR_MARKERS.createColumn(_columnManager, _pc); colDef.setIsDefaultColumn(); colDef.setLabelProvider(new CellLabelProvider() { @Override public void update(final ViewerCell cell) { final TourData tourData = (TourData) cell.getElement(); final Set<TourMarker> tourMarker = tourData.getTourMarkers(); final Set<TourWayPoint> wayPoints = tourData.getTourWayPoints(); if (tourMarker == null && wayPoints == null) { cell.setText(UI.EMPTY_STRING); } else { int size = 0; if (tourMarker != null) { size = tourMarker.size(); } if (wayPoints != null) { size += wayPoints.size(); } cell.setText(size == 0 ? UI.EMPTY_STRING : Integer.toString(size)); } } }); } /** * column: tags */ private void defineColumn_Tour_Tags() { final ColumnDefinition colDef = TableColumnFactory.TOUR_TAGS.createColumn(_columnManager, _pc); colDef.setIsDefaultColumn(); colDef.setLabelProvider(new TourInfoToolTipCellLabelProvider() { @Override public Long getTourId(final ViewerCell cell) { if (_isToolTipInTags == false) { return null; } return ((TourData) cell.getElement()).getTourId(); } @Override public void update(final ViewerCell cell) { final Object element = cell.getElement(); final TourData tourData = (TourData) element; final Set<TourTag> tourTags = tourData.getTourTags(); if (tourTags.size() == 0) { // the tags could have been removed, set empty field cell.setText(UI.EMPTY_STRING); } else { // convert the tags into a list of tag ids cell.setText(TourDatabase.getTagNames(tourTags)); } } }); } /** * column: tour title */ private void defineColumn_Tour_Title() { final ColumnDefinition colDef = TableColumnFactory.TOUR_TITLE.createColumn(_columnManager, _pc); colDef.setIsDefaultColumn(); colDef.setColumnSelectionListener(_columnSortListener); colDef.setLabelProvider(new TourInfoToolTipCellLabelProvider() { @Override public Long getTourId(final ViewerCell cell) { if (_isToolTipInTitle == false) { return null; } return ((TourData) cell.getElement()).getTourId(); } @Override public void update(final ViewerCell cell) { final TourData tourData = (TourData) cell.getElement(); cell.setText(tourData.getTourTitle()); } }); _columnId_Title = colDef.getColumnId(); } /** * column: tour type image */ private void defineColumn_Tour_Type() { final ColumnDefinition colDef = TableColumnFactory.TOUR_TYPE.createColumn(_columnManager, _pc); colDef.setIsDefaultColumn(); colDef.setLabelProvider(new CellLabelProvider() { @Override public void update(final ViewerCell cell) { final net.tourbook.ui.UI ui = net.tourbook.ui.UI.getInstance(); final TourType tourType = ((TourData) cell.getElement()).getTourType(); if (tourType == null) { cell.setImage(ui.getTourTypeImage(TourDatabase.ENTITY_IS_NOT_SAVED)); } else { final long tourTypeId = tourType.getTypeId(); final Image tourTypeImage = ui.getTourTypeImage(tourTypeId); /* * when a tour type image is modified, it will keep the same image resource only * the content is modified but in the rawDataView the modified image is not * displayed compared with the tourBookView which displays the correct image */ cell.setImage(tourTypeImage); } } }); } /** * column: tour type text */ private void defineColumn_Tour_TypeText() { final ColumnDefinition colDef = TableColumnFactory.TOUR_TYPE_TEXT.createColumn(_columnManager, _pc); colDef.setLabelProvider(new CellLabelProvider() { @Override public void update(final ViewerCell cell) { final TourType tourType = ((TourData) cell.getElement()).getTourType(); if (tourType == null) { cell.setText(UI.EMPTY_STRING); } else { cell.setText(tourType.getName()); } } }); } /** * column: clouds */ private void defineColumn_Weather_Clouds() { final ColumnDefinition colDef = TableColumnFactory.WEATHER_CLOUDS.createColumn(_columnManager, _pc); colDef.setIsDefaultColumn(); colDef.setLabelProvider(new CellLabelProvider() { @Override public void update(final ViewerCell cell) { final String weatherCloudId = ((TourData) cell.getElement()).getWeatherClouds(); if (weatherCloudId == null) { cell.setText(UI.EMPTY_STRING); } else { final Image img = UI.IMAGE_REGISTRY.get(weatherCloudId); if (img != null) { cell.setImage(img); } else { cell.setText(weatherCloudId); } } } }); } private void deleteFile(final ArrayList<String> deletedFiles, final ArrayList<String> notDeletedFiles, final String fileFolder, final String fileName, final TourLogState importLogState) { if (fileFolder == null || fileFolder.trim().length() == 0) { // there is no folder return; } Path filePath = null; try { filePath = Paths.get(fileFolder, fileName); final String filePathName = filePath.toString(); Files.delete(filePath); deletedFiles.add(filePathName); TourLogManager.addSubLog(importLogState, filePathName); } catch (final Exception e) { // file can be invalid final String fileNamePath = '"' + fileFolder + '"' + UI.SPACE + '"' + fileName + '"'; notDeletedFiles.add(fileNamePath); TourLogManager.addSubLog(TourLogState.IMPORT_ERROR, fileNamePath); } return; } @Override public void dispose() { resetEasyImport(); _images.dispose(); // don't throw the selection again _postSelectionProvider.clearSelection(); getViewSite().getPage().removePartListener(_partListener); getSite().getPage().removeSelectionListener(_postSelectionListener); TourManager.getInstance().removeTourEventListener(_tourEventListener); _prefStore.removePropertyChangeListener(_prefChangeListener); _prefStoreCommon.removePropertyChangeListener(_prefChangeListenerCommon); disposeConfigImages(); super.dispose(); } private void disposeConfigImages() { for (final Image configImage : _configImages.values()) { if (configImage != null) { configImage.dispose(); } } _configImages.clear(); _configImageHash.clear(); } public void doLiveUpdate(final DialogEasyImportConfig dialogImportConfig) { updateModel_EasyConfig_Dashboard(dialogImportConfig.getModifiedConfig()); _isDeviceStateValid = false; updateUI_2_Dashboard(); } private void doSaveTour(final TourPerson person) { final ArrayList<TourData> selectedTours = getAnySelectedTours(); runEasyImport_099_SaveTour(person, selectedTours, false); } /** * @param tourData * {@link TourData} which is not yet saved. * @param person * Person for which the tour is being saved. * @param savedTours * The saved tour is added to this list. */ private void doSaveTour_OneTour(final TourData tourData, final TourPerson person, final ArrayList<TourData> savedTours) { // workaround for hibernate problems if (tourData.isTourDeleted) { return; } if (tourData.getTourPerson() != null) { /* * tour is already saved, resaving cannot be done in the import view it can be done in * the tour editor */ return; } // a saved tour needs a person tourData.setTourPerson(person); // set weight from person tourData.setBodyWeight(person.getWeight()); tourData.setTourBike(person.getTourBike()); final TourData savedTour = TourDatabase.saveTour(tourData, true); if (savedTour != null) { savedTours.add(savedTour); // update fields which are not saved but used in the UI and easy setup savedTour.isTourFileDeleted = tourData.isTourFileDeleted; savedTour.isTourFileMoved = tourData.isTourFileMoved; savedTour.isBackupImportFile = tourData.isBackupImportFile; savedTour.importFilePathOriginal = tourData.importFilePathOriginal; } } /** * After tours are saved, the internal structures and ui viewers must be updated * * @param savedTours * contains the saved {@link TourData} */ private void doSaveTour_PostActions(final ArrayList<TourData> savedTours) { // update viewer, fire selection event if (savedTours.size() == 0) { return; } final ArrayList<Long> savedToursIds = new ArrayList<Long>(); // update raw data map with the saved tour data final HashMap<Long, TourData> rawDataMap = _rawDataMgr.getImportedTours(); for (final TourData tourData : savedTours) { final Long tourId = tourData.getTourId(); rawDataMap.put(tourId, tourData); savedToursIds.add(tourId); } /* * the selection provider can contain old tour data which conflicts with the tour data in * the tour data editor */ _postSelectionProvider.clearSelection(); // update import viewer reloadViewer(); enableActions(); /* * notify all views, it is not checked if the tour data editor is dirty because newly saved * tours can not be modified in the tour data editor */ TourManager.fireEventWithCustomData(TourEventId.UPDATE_UI, new SelectionTourIds(savedToursIds), this); } private void enableActions() { final Object[] rawData = _rawDataMgr.getImportedTours().values().toArray(); final boolean isTourAvailable = rawData.length > 0; final StructuredSelection selection = (StructuredSelection) _tourViewer.getSelection(); int savedTours = 0; int unsavedTours = 0; int selectedTours = 0; // contains all tours which are selected and not deleted int selectedNotDeleteTours = 0; TourData firstSavedTour = null; TourData firstValidTour = null; for (final Iterator<?> iter = selection.iterator(); iter.hasNext();) { final Object treeItem = iter.next(); if (treeItem instanceof TourData) { selectedTours++; final TourData tourData = (TourData) treeItem; if (tourData.getTourPerson() == null) { // tour is not saved if (tourData.isTourDeleted == false) { // tour is not deleted, deleted tours are ignored unsavedTours++; selectedNotDeleteTours++; } } else { if (savedTours == 0) { firstSavedTour = tourData; } savedTours++; selectedNotDeleteTours++; } if (selectedNotDeleteTours == 1) { firstValidTour = tourData; } } } final boolean isSavedTourSelected = savedTours > 0; final boolean isOneSavedAndNotDeleteTour = (selectedNotDeleteTours == 1) && (savedTours == 1); final boolean isOneSelectedNotDeleteTour = selectedNotDeleteTours == 1; // action: save tour with person final TourPerson person = TourbookPlugin.getActivePerson(); if (person != null) { _actionSaveTourWithPerson .setText(NLS.bind(Messages.import_data_action_save_tour_with_person, person.getName())); _actionSaveTourWithPerson.setPerson(person); } _actionSaveTourWithPerson.setEnabled((person != null) && (unsavedTours > 0)); // action: save tour... if (selection.size() == 1) { _actionSaveTour.setText(Messages.import_data_action_save_tour_for_person); } else { _actionSaveTour.setText(Messages.import_data_action_save_tours_for_person); } _actionSaveTour.setEnabled(unsavedTours > 0); // action: merge tour ... into ... if (isOneSelectedNotDeleteTour) { final StringBuilder sb = new StringBuilder().append(UI.EMPTY_STRING)// .append(TourManager.getTourDateShort(firstValidTour)).append(UI.DASH_WITH_SPACE) .append(TourManager.getTourTimeShort(firstValidTour)).append(UI.DASH_WITH_SPACE) .append(firstValidTour.getDeviceName()); _actionMergeIntoTour.setText(NLS.bind(Messages.import_data_action_assignMergedTour, sb.toString())); } else { // tour cannot be merged, display default text _actionMergeIntoTour.setText(Messages.import_data_action_assignMergedTour_default); } _actionMergeIntoTour.setEnabled(isOneSelectedNotDeleteTour); _actionMergeTour.setEnabled(isOneSavedAndNotDeleteTour && (firstSavedTour.getMergeSourceTourId() != null)); _actionReimportSubMenu.setEnabled(selectedTours > 0); _actionRemoveTour.setEnabled(selectedTours > 0); _actionExportTour.setEnabled(selectedNotDeleteTours > 0); _actionJoinTours.setEnabled(selectedNotDeleteTours > 1); _actionEditTour.setEnabled(isOneSavedAndNotDeleteTour); _actionEditQuick.setEnabled(isOneSavedAndNotDeleteTour); _actionOpenTour.setEnabled(isOneSavedAndNotDeleteTour); _actionOpenMarkerDialog.setEnabled(isOneSavedAndNotDeleteTour); _actionOpenAdjustAltitudeDialog.setEnabled(isOneSavedAndNotDeleteTour); _actionDeleteTourFile.setEnabled(isTourAvailable); // set double click state _tourDoubleClickState.canEditTour = isOneSavedAndNotDeleteTour; _tourDoubleClickState.canQuickEditTour = isOneSavedAndNotDeleteTour; _tourDoubleClickState.canEditMarker = isOneSavedAndNotDeleteTour; _tourDoubleClickState.canAdjustAltitude = isOneSavedAndNotDeleteTour; _tourDoubleClickState.canOpenTour = isOneSelectedNotDeleteTour; final ArrayList<TourType> tourTypes = TourDatabase.getAllTourTypes(); _actionSetTourType.setEnabled(isSavedTourSelected && (tourTypes.size() > 0)); final ArrayList<Long> existingTagIds = new ArrayList<Long>(); long existingTourTypeId = TourDatabase.ENTITY_IS_NOT_SAVED; boolean isOneTour; if ((firstSavedTour != null) && (savedTours == 1)) { // one tour is selected isOneTour = true; final TourType tourType = firstSavedTour.getTourType(); existingTourTypeId = tourType == null ? TourDatabase.ENTITY_IS_NOT_SAVED : tourType.getTypeId(); final Set<TourTag> existingTags = firstSavedTour.getTourTags(); if ((existingTags != null) && (existingTags.size() > 0)) { // tour contains at least one tag for (final TourTag tourTag : existingTags) { existingTagIds.add(tourTag.getTagId()); } } } else { // multiple tours are selected isOneTour = false; } // enable/disable actions for tags/tour types _tagMenuMgr.enableTagActions(isSavedTourSelected, isOneTour, existingTagIds); TourTypeMenuManager.enableRecentTourTypeActions(isSavedTourSelected, existingTourTypeId); /* * Action: Setup import */ _actionSetupImport.setEnabled(!isTourAvailable); _actionClearView.setEnabled(isTourAvailable); } private void fillContextMenu(final IMenuManager menuMgr) { // hide tour info tooltip, this is displayed when the mouse context menu should be created _tourInfoToolTip.hide(); if (TourbookPlugin.getActivePerson() != null) { menuMgr.add(_actionSaveTourWithPerson); } menuMgr.add(_actionSaveTour); menuMgr.add(_actionMergeIntoTour); menuMgr.add(_actionJoinTours); menuMgr.add(new Separator()); menuMgr.add(_actionExportTour); menuMgr.add(_actionReimportSubMenu); menuMgr.add(_actionEditImportPreferences); menuMgr.add(_actionRemoveTour); menuMgr.add(_actionDeleteTourFile); menuMgr.add(new Separator()); menuMgr.add(_actionEditQuick); menuMgr.add(_actionEditTour); menuMgr.add(_actionOpenMarkerDialog); menuMgr.add(_actionOpenAdjustAltitudeDialog); menuMgr.add(_actionMergeTour); menuMgr.add(_actionOpenTour); // tour type actions menuMgr.add(new Separator()); menuMgr.add(_actionSetTourType); TourTypeMenuManager.fillMenuWithRecentTourTypes(menuMgr, this, true); // tour tag actions _tagMenuMgr.fillTagMenu(menuMgr); // add standard group which allows other plug-ins to contribute here menuMgr.add(new Separator(IWorkbenchActionConstants.MB_ADDITIONS)); enableActions(); } private void fillToolbar() { /* * fill view toolbar */ final IToolBarManager tbm = getViewSite().getActionBars().getToolBarManager(); tbm.add(_actionSaveTourWithPerson); tbm.add(_actionSaveTour); tbm.add(new Separator()); // place for import and transfer actions tbm.add(new GroupMarker("import")); //$NON-NLS-1$ tbm.add(new Separator()); tbm.add(_actionClearView); tbm.add(_actionOpenTourLogView); tbm.add(_actionSetupImport); /* * fill view menu */ final IMenuManager menuMgr = getViewSite().getActionBars().getMenuManager(); menuMgr.add(_actionRemoveToursWhenClosed); menuMgr.add(_actionEditImportPreferences); menuMgr.add(new Separator()); menuMgr.add(_actionModifyColumns); } private void fireSelectedTour() { final IStructuredSelection selection = (IStructuredSelection) _tourViewer.getSelection(); final TourData tourData = (TourData) selection.getFirstElement(); enableActions(); if (tourData != null) { _postSelectionProvider.setSelection(new SelectionTourData(null, tourData)); } } @Override public ArrayList<TourData> getAllSelectedTours() { final TourManager tourManager = TourManager.getInstance(); // get selected tours final IStructuredSelection selectedTours = ((IStructuredSelection) _tourViewer.getSelection()); final ArrayList<TourData> selectedTourData = new ArrayList<TourData>(); // loop: all selected tours for (final Iterator<?> iter = selectedTours.iterator(); iter.hasNext();) { final Object tourItem = iter.next(); if (tourItem instanceof TourData) { final TourData tourData = (TourData) tourItem; if (tourData.isTourDeleted) { // skip deleted tour continue; } if (tourData.getTourPerson() == null) { // tour is not saved selectedTourData.add(tourData); } else { /* * get the data from the database because the tag names could be changed and * this is not reflected in the tours which are displayed in the raw data view */ final TourData tourDataInDb = tourManager.getTourData(tourData.getTourId()); if (tourDataInDb != null) { selectedTourData.add(tourDataInDb); } } } } return selectedTourData; } private ArrayList<TourData> getAnySelectedTours() { final ArrayList<TourData> selectedTours = new ArrayList<TourData>(); // get selected tours, this must be outside of the runnable !!! final IStructuredSelection selection = ((IStructuredSelection) _tourViewer.getSelection()); for (final Iterator<?> iterator = selection.iterator(); iterator.hasNext();) { selectedTours.add((TourData) iterator.next()); } return selectedTours; } @Override public ColumnManager getColumnManager() { return _columnManager; } private String getDurationText(final ImportLauncher importLauncher) { final int duration = importLauncher.temperatureAdjustmentDuration; final Period durationPeriod = new Period(0, duration * 1000, _durationTemplate); return durationPeriod.toString(UI.DEFAULT_DURATION_FORMATTER); } private EasyConfig getEasyConfig() { return EasyImportManager.getInstance().getEasyConfig(); } public Image getImportConfigImage(final ImportLauncher importConfig) { final int imageWidth = importConfig.imageWidth; if (imageWidth == 0) { return null; } final long configId = importConfig.getId(); Image image = _configImages.get(configId); if (isConfigImageValid(image, importConfig)) { return image; } final Display display = _parent.getDisplay(); final Enum<TourTypeConfig> tourTypeConfig = importConfig.tourTypeConfig; final net.tourbook.ui.UI ui = net.tourbook.ui.UI.getInstance(); if (TourTypeConfig.TOUR_TYPE_CONFIG_BY_SPEED.equals(tourTypeConfig)) { final ArrayList<SpeedTourType> speedVertices = importConfig.speedTourTypes; final int imageSize = TourType.TOUR_TYPE_IMAGE_SIZE; final Image tempImage = new Image(display, imageWidth, imageSize); { final GC gcImage = new GC(tempImage); final Color colorTransparent = new Color(display, TourType.TRANSPARENT_COLOR); { // fill with transparent color gcImage.setBackground(colorTransparent); gcImage.fillRectangle(0, 0, imageWidth, imageSize); for (int imageIndex = 0; imageIndex < speedVertices.size(); imageIndex++) { final SpeedTourType vertex = speedVertices.get(imageIndex); final Image ttImage = ui.getTourTypeImage(vertex.tourTypeId); gcImage.drawImage(ttImage, // 0, 0, imageSize, imageSize, imageSize * imageIndex, 0, imageSize, imageSize); } } gcImage.dispose(); colorTransparent.dispose(); /* * set transparency */ final ImageData imageData = tempImage.getImageData(); imageData.transparentPixel = imageData.getPixel(0, 0); image = new Image(display, imageData); } tempImage.dispose(); } else if (TourTypeConfig.TOUR_TYPE_CONFIG_ONE_FOR_ALL.equals(tourTypeConfig)) { final TourType tourType = importConfig.oneTourType; if (tourType != null) { // create a copy because the copied image can be disposed final Image tempImage = new Image(display, TourType.TOUR_TYPE_IMAGE_SIZE, TourType.TOUR_TYPE_IMAGE_SIZE); { final GC gcImage = new GC(tempImage); final Color colorTransparent = new Color(display, TourType.TRANSPARENT_COLOR); { // fill with transparent color gcImage.setBackground(colorTransparent); gcImage.fillRectangle(0, 0, TourType.TOUR_TYPE_IMAGE_SIZE, TourType.TOUR_TYPE_IMAGE_SIZE); final Image ttImage = ui.getTourTypeImage(tourType.getTypeId()); gcImage.drawImage(ttImage, 0, 0); } gcImage.dispose(); colorTransparent.dispose(); /* * set transparency */ final ImageData imageData = tempImage.getImageData(); imageData.transparentPixel = imageData.getPixel(0, 0); image = new Image(display, imageData); } tempImage.dispose(); } } else { // this is the default or TourTypeConfig.TOUR_TYPE_CONFIG_NOT_USED } // keep image in the cache final Image oldImage = _configImages.put(configId, image); Util.disposeResource(oldImage); _configImageHash.put(configId, importConfig.imageHash); return image; } @Override public PostSelectionProvider getPostSelectionProvider() { return _postSelectionProvider; } @Override public ArrayList<TourData> getSelectedTours() { final TourManager tourManager = TourManager.getInstance(); // get selected tours final IStructuredSelection selectedTours = ((IStructuredSelection) _tourViewer.getSelection()); final ArrayList<TourData> selectedTourData = new ArrayList<TourData>(); // loop: all selected tours for (final Iterator<?> iter = selectedTours.iterator(); iter.hasNext();) { final Object tourItem = iter.next(); if (tourItem instanceof TourData) { final TourData tourData = (TourData) tourItem; /* * only tours are added which are saved in the database */ if (tourData.getTourPerson() != null) { /* * get the data from the database because the tag names could be changed and * this is not reflected in the tours which are displayed in the raw data view */ final TourData tourDataInDb = tourManager.getTourData(tourData.getTourId()); if (tourDataInDb != null) { selectedTourData.add(tourDataInDb); } } } } return selectedTourData; } /** * @param sortColumnId * @return Returns the column widget by it's column id, when column id is not found then the * first column is returned. */ private TableColumn getSortColumn(final String sortColumnId) { final TableColumn[] allColumns = _tourViewer.getTable().getColumns(); for (final TableColumn column : allColumns) { final String columnId = ((ColumnDefinition) column.getData()).getColumnId(); if (columnId.equals(sortColumnId)) { return column; } } return allColumns[0]; } Image getStateImage_Db(final TourData tourData) { final TourPerson tourPerson = tourData.getTourPerson(); final long activePersonId = _activePerson == null ? -1 : _activePerson.getPersonId(); if (tourData.isTourDeleted) { return _images.get(IMAGE_DELETE); } else if (tourData.getMergeTargetTourId() != null) { return _images.get(IMAGE_ASSIGN_MERGED_TOUR); } else if (tourPerson == null) { return _images.get(IMAGE_ICON_PLACEHOLDER); } else if (tourPerson.getPersonId() == activePersonId) { return _images.get(IMAGE_DATABASE); } else { return _images.get(IMAGE_DATABASE_OTHER_PERSON); } } private Image getStateImage_Import(final TourData tourData) { if (tourData.isTourFileDeleted) { return _images.get(IMAGE_STATE_DELETE); } else if (tourData.isTourFileMoved) { return _images.get(IMAGE_STATE_MOVED); } return null; } @Override public ColumnViewer getViewer() { return _tourViewer; } private void initUI(final Composite parent) { _parent = parent; _pc = new PixelConverter(parent); createResources_Image(); createResources_Web(); _importComparator = new ImportComparator(); _columnSortListener = new SelectionAdapter() { @Override public void widgetSelected(final SelectionEvent e) { onSelect_SortColumn(e); } }; } /** * @param image * @param importConfig * @return Returns <code>true</code> when the image is valid, returns <code>false</code> when * the profile image must be created, */ private boolean isConfigImageValid(final Image image, final ImportLauncher importConfig) { if (image == null || image.isDisposed()) { return false; } final Integer imageHash = _configImageHash.get(importConfig.getId()); if (imageHash == null || imageHash != importConfig.imageHash) { image.dispose(); return false; } return true; } private boolean isOSFolderValid(final String osFolder) { try { if (osFolder != null && osFolder.trim().length() > 0 && Files.exists(Paths.get(osFolder))) { // device folder exists return true; } } catch (final Exception e) { } return false; } /** * @return Returns <code>true</code> when the devices are watched. */ private boolean isWatchingOn() { return _watchingStoresThread != null; } private void onBrowser_Completed(final ProgressEvent event) { _isBrowserCompleted = true; if (_isInUIStartup) { _isInUIStartup = false; // a redraw MUST be done otherwise nothing is displayed _browser.setRedraw(true); // set focus that clicking on an action works the 1st and not the 2nd time _browser.setFocus(); // dashboard is visible, activate background task setWatcher_On(); // make the import tiles visible otherwise they are 'hidden' after the startup _isShowWatcherAnimation = true; updateUI_WatcherAnimation(isWatchingOn() // ? DOM_CLASS_DEVICE_ON_ANIMATED : DOM_CLASS_DEVICE_OFF_ANIMATED); } if (_isDeviceStateUpdateDelayed.getAndSet(false)) { updateUI_DeviceState_DOM(); } } private void onBrowser_LocationChanging(final LocationEvent event) { final String location = event.location; final String[] locationParts = location.split(HREF_TOKEN); if (locationParts.length > 1) { // finalize loading of the browser page and then start the action _browser.getDisplay().asyncExec(new Runnable() { @Override public void run() { onBrowser_LocationChanging_Runnable(locationParts); } }); } // prevent to load a new url if (location.equals(PAGE_ABOUT_BLANK) == false) { // about:blank is the initial page event.doit = false; } } private void onBrowser_LocationChanging_Runnable(final String[] locationParts) { final String hrefAction = locationParts[1]; if (ACTION_DEVICE_IMPORT.equals(hrefAction)) { final long tileId = Long.parseLong(locationParts[2]); runEasyImport(tileId); } else if (ACTION_SETUP_EASY_IMPORT.equals(hrefAction)) { action_Easy_SetupImport(-1); } else if (ACTION_DEVICE_WATCHING_ON_OFF.equals(hrefAction)) { action_Easy_SetDeviceWatching_OnOff(); } else if (ACTION_IMPORT_FROM_FILES.equals(hrefAction)) { _rawDataMgr.actionImportFromFile(); } else if (ACTION_SERIAL_PORT_CONFIGURED.equals(hrefAction)) { _rawDataMgr.actionImportFromDevice(); } else if (ACTION_SERIAL_PORT_DIRECTLY.equals(hrefAction)) { _rawDataMgr.actionImportFromDeviceDirect(); } else if (ACTION_OLD_UI.equals(hrefAction)) { onSelectUI_Old(); } } private void onSelect_SortColumn(final SelectionEvent e) { _viewerContainer.setRedraw(false); { // keep selection final ISelection selectionBackup = _tourViewer.getSelection(); // update viewer with new sorting _importComparator.setSortColumn(e.widget); _tourViewer.refresh(); // reselect _isInUpdate = true; { _tourViewer.setSelection(selectionBackup, true); final Table table = _tourViewer.getTable(); table.showSelection(); } _isInUpdate = false; } _viewerContainer.setRedraw(true); } /** * Import config is selected in the dashboard. * * @param selectedIndex */ private void onSelectImportConfig(final int selectedIndex) { final EasyConfig easyConfig = getEasyConfig(); final ImportConfig selectedConfig = easyConfig.importConfigs.get(selectedIndex); easyConfig.setActiveImportConfig(selectedConfig); _isDeviceStateValid = false; updateUI_2_Dashboard(); } private void onSelectionChanged(final ISelection selection) { if (selection instanceof SelectionDeletedTours) { // tours are deleted _postSelectionProvider.clearSelection(); final SelectionDeletedTours tourSelection = (SelectionDeletedTours) selection; final ArrayList<ITourItem> removedTours = tourSelection.removedTours; if (removedTours.size() == 0) { return; } removeTours(removedTours); if (_isPartVisible) { _rawDataMgr.updateTourData_InImportView_FromDb(null); // force the store watcher to update the device state _isDeviceStateValid = false; // thread_FolderWatcher_Activate(); // update the table viewer reloadViewer(); } else { _isViewerPersonDataDirty = true; } } } private void onSelectUI_New() { _isNewUI = true; _prefStore.setValue(ITourbookPreferences.IMPORT_IS_NEW_UI, _isNewUI); updateUI_1_TopPage(true); showFailbackUI(); } private void onSelectUI_Old() { resetEasyImport(); _isNewUI = false; _prefStore.setValue(ITourbookPreferences.IMPORT_IS_NEW_UI, _isNewUI); updateUI_1_TopPage(true); } private void recreateViewer() { _columnManager.saveState(_state); _columnManager.clearColumns(); defineAllColumns(); _tourViewer = (TableViewer) recreateViewer(_tourViewer); _isDeviceStateValid = false; updateUI_2_Dashboard(); } @Override public ColumnViewer recreateViewer(final ColumnViewer columnViewer) { _topPage_ImportViewer.setRedraw(false); { _tourViewer.getTable().dispose(); createUI_92_TourViewer(_topPage_ImportViewer); _topPage_ImportViewer.layout(); // update the viewer reloadViewer(); } _topPage_ImportViewer.setRedraw(true); return _tourViewer; } /** * Update {@link TourData} from the database for all imported tours, displays a progress dialog. * * @param canCancelable */ private void reimportAllImportFiles(final boolean canCancelable) { final String[] prevImportedFiles = _state.getArray(STATE_IMPORTED_FILENAMES); if ((prevImportedFiles == null) || (prevImportedFiles.length == 0)) { return; } // Log reimport TourLogManager.addLog(TourLogState.DEFAULT, RawDataManager.LOG_REIMPORT_PREVIOUS_FILES, TourLogView.CSS_LOG_TITLE); final long start = System.currentTimeMillis(); if (RawDataManager.isAutoOpenImportLog()) { TourLogManager.showLogView(); } try { new ProgressMonitorDialog(Display.getDefault().getActiveShell()).run(true, canCancelable, new IRunnableWithProgress() { @Override public void run(final IProgressMonitor monitor) throws InvocationTargetException, InterruptedException { reimportAllImportFiles_Runnable(monitor, prevImportedFiles, canCancelable); } }); } catch (final Exception e) { TourLogManager.logEx(e); } finally { final double time = (System.currentTimeMillis() - start) / 1000.0; TourLogManager.addLog(// TourLogState.DEFAULT, String.format(RawDataManager.LOG_REIMPORT_END, time)); } } /** * reimport previous imported tours * * @param monitor * @param importedFiles * @param canCancelable */ private void reimportAllImportFiles_Runnable(final IProgressMonitor monitor, final String[] importedFiles, final boolean canCancelable) { int workedDone = 0; final int workedAll = importedFiles.length; if (monitor != null) { monitor.beginTask(Messages.import_data_importTours_task, workedAll); } final ArrayList<String> notImportedFiles = new ArrayList<String>(); _rawDataMgr.getImportedTours().clear(); _rawDataMgr.setImportId(); int importedFileCounter = 0; // loop: import all files for (final String fileName : importedFiles) { if (monitor != null) { monitor.worked(1); monitor.subTask(NLS.bind(Messages.import_data_importTours_subTask, // new Object[] { workedDone++, workedAll, fileName })); } final File file = new File(fileName); if (file.exists()) { final boolean isImported = _rawDataMgr.importRawData(file, null, false, null, true); if (isImported) { TourLogManager.addSubLog(TourLogState.IMPORT_OK, fileName); importedFileCounter++; } else { TourLogManager.addSubLog(TourLogState.IMPORT_ERROR, fileName); notImportedFiles.add(fileName); } } if (canCancelable && monitor.isCanceled()) { // stop importing but process imported tours break; } } if (importedFileCounter > 0) { _rawDataMgr.updateTourData_InImportView_FromDb(monitor); Display.getDefault().asyncExec(new Runnable() { @Override public void run() { reloadViewer(); /* * restore selected tour */ final String[] viewerIndices = _state.getArray(STATE_SELECTED_TOUR_INDICES); if (viewerIndices != null) { final ArrayList<Object> viewerTourData = new ArrayList<Object>(); for (final String viewerIndex : viewerIndices) { Object tourData = null; try { final int index = Integer.parseInt(viewerIndex); tourData = _tourViewer.getElementAt(index); } catch (final NumberFormatException e) { // just ignore } if (tourData != null) { viewerTourData.add(tourData); } } if (viewerTourData.size() > 0) { _tourViewer.setSelection(new StructuredSelection(viewerTourData.toArray()), true); } } } }); } // show error log if (notImportedFiles.size() > 0) { TourLogManager.showLogView(); } } /** * This will also aktivate/deactivate the folder/store watcher. * * @see net.tourbook.common.util.ITourViewer#reloadViewer() */ @Override public void reloadViewer() { updateUI_1_TopPage(false); // update tour data viewer final Object[] rawData = _rawDataMgr.getImportedTours().values().toArray(); _tourViewer.setInput(rawData); enableActions(); } private void removeTours(final ArrayList<ITourItem> removedTours) { final HashMap<Long, TourData> tourMap = _rawDataMgr.getImportedTours(); for (final ITourItem tourItem : removedTours) { final TourData tourData = tourMap.get(tourItem.getTourId()); if (tourData != null) { // when a tour was deleted the person in the tour data must be removed tourData.setTourPerson(null); // remove tour properties tourData.setTourType(null); tourData.setTourTitle(UI.EMPTY_STRING); tourData.setTourTags(new HashSet<TourTag>()); /** * when a remove tour is saved again, this will cause the exception: <br> * detached entity passed to persist: net.tourbook.data.TourMarker<br> * I didn't find a workaround, so this tour cannot be saved again until it is * reloaded from the file */ tourData.isTourDeleted = true; } } } private void resetEasyImport() { setWatcher_Off(); EasyImportManager.getInstance().reset(); } private void restoreState() { _isNewUI = _prefStore.getBoolean(ITourbookPreferences.IMPORT_IS_NEW_UI); _actionRemoveToursWhenClosed .setChecked(Util.getStateBoolean(_state, STATE_IS_REMOVE_TOURS_WHEN_VIEW_CLOSED, true)); // restore: set merge tracks status before the tours are imported final boolean isMergeTracks = _state.getBoolean(STATE_IS_MERGE_TRACKS); _rawDataMgr.setMergeTracks(isMergeTracks); // restore: set merge tracks status before the tours are imported final boolean isCreateTourIdWithTime = _state.getBoolean(STATE_IS_CREATE_TOUR_ID_WITH_TIME); _rawDataMgr.setState_CreateTourIdWithTime(isCreateTourIdWithTime); // auto open import log view final boolean isAutoOpenLogView = Util.getStateBoolean(_state, // STATE_IS_AUTO_OPEN_IMPORT_LOG_VIEW, RawDataView.STATE_IS_AUTO_OPEN_IMPORT_LOG_VIEW_DEFAULT); _rawDataMgr.setState_IsOpenImportLogView(isAutoOpenLogView); // restore: is checksum validation final boolean isValidation = _state.getBoolean(STATE_IS_CHECKSUM_VALIDATION); _rawDataMgr.setIsChecksumValidation(isValidation); updateToolTipState(); Display.getCurrent().asyncExec(new Runnable() { @Override public void run() { reimportAllImportFiles(true); } }); } private void runEasyImport(final long tileId) { final long start = System.currentTimeMillis(); /* * Log import start */ TourLogManager.addLog(TourLogState.DEFAULT, EasyImportManager.LOG_EASY_IMPORT_000_IMPORT_START, TourLogView.CSS_LOG_TITLE); if (isWatchingOn() == false) { /* * It can be dangerous pressing an import tile and the UI is dimmed, so it's almost * invisible what is clicked. */ return; } final EasyConfig easyConfig = getEasyConfig(); final ImportConfig importConfig = easyConfig.getActiveImportConfig(); /* * Get import launcher */ ImportLauncher importLauncher = null; for (final ImportLauncher launcher : easyConfig.importLaunchers) { if (launcher.getId() == tileId) { importLauncher = launcher; break; } } if (importLauncher == null) { // this should not occure return; } /* * Check person */ TourPerson person = null; if (importLauncher.isSaveTour) { person = TourbookPlugin.getActivePerson(); if (person == null) { MessageDialog.openError(_parent.getShell(), Messages.Import_Data_Dialog_EasyImport_Title, Messages.Import_Data_Dialog_NoActivePersion_Message); return; } } /* * Run easy import */ ImportDeviceState importState = null; if (RawDataManager.isAutoOpenImportLog()) { TourLogManager.showLogView(); } try { // disable state update during import, this causes lots of problems !!! _isUpdateDeviceState = false; importState = EasyImportManager.getInstance().runImport(importLauncher); } finally { _isUpdateDeviceState = true; } /* * Update viewer with newly imported files */ final Collection<TourData> importedToursCollection = RawDataManager.getInstance().getImportedTours() .values(); final ArrayList<TourData> importedTours = new ArrayList<>(importedToursCollection); try { // stop all other actions when canceled if (importState.isImportCanceled) { return; } // open import config dialog to solve problems if (importState.isOpenSetup) { _parent.getDisplay().asyncExec(new Runnable() { @Override public void run() { action_Easy_SetupImport(0); } }); return; } /* * 4. Set last marker text */ if (importLauncher.isSetLastMarker) { runEasyImport_004_SetLastMarker(importLauncher, importedTours); } /* * 5. Adjust temperature */ if (importLauncher.isAdjustTemperature) { runEasyImport_005_AdjustTemperature(importLauncher, importedTours); } ArrayList<TourData> importedAndSavedTours; /* * 99. Save imported tours */ if (importLauncher.isSaveTour) { importedAndSavedTours = runEasyImport_099_SaveTour(person, importedTours, true); } else { importedAndSavedTours = _rawDataMgr.getImportedTourList(); } /* * 100. Delete device files */ if (importConfig.isDeleteDeviceFiles) { // use newly saved/not saved tours runEasyImport_100_DeleteTourFiles(false, importedAndSavedTours, true); } /* * 101. Turn watching off */ if (importConfig.isTurnOffWatching) { TourLogManager.addLog(TourLogState.DEFAULT, EasyImportManager.LOG_EASY_IMPORT_101_TURN_WATCHING_OFF); setWatcher_Off(); } /* * Log import end */ final double time = (System.currentTimeMillis() - start) / 1000.0; TourLogManager.addLog(TourLogState.DEFAULT, String.format(EasyImportManager.LOG_EASY_IMPORT_999_IMPORT_END, time)); } finally { // update viewer when required if (importState.isUpdateImportViewer) { _tourViewer.update(importedToursCollection.toArray(), null); selectFirstTour(); } } } private void runEasyImport_004_SetLastMarker(final ImportLauncher importLauncher, final ArrayList<TourData> importedTours) { final String lastMarkerText = importLauncher.lastMarkerText; if (lastMarkerText == null || lastMarkerText.trim().length() == 0) { // there is nothing to do return; } TourLogManager.addLog(TourLogState.DEFAULT, EasyImportManager.LOG_EASY_IMPORT_004_SET_LAST_MARKER); final int ilLastMarkerDistance = importLauncher.lastMarkerDistance; for (final TourData tourData : importedTours) { // check if distance is available final float[] distancSerie = tourData.distanceSerie; if (distancSerie == null || distancSerie.length == 0) { continue; } final ArrayList<TourMarker> tourMarkers = tourData.getTourMarkersSorted(); final int numMarkers = tourMarkers.size(); // check if markers are available if (numMarkers == 0) { continue; } // get last marker final TourMarker lastMarker = tourMarkers.get(numMarkers - 1); final int markerIndex = lastMarker.getSerieIndex(); final float lastMarkerDistance = distancSerie[markerIndex]; final float tourDistance = tourData.getTourDistance(); final float distanceDiff = tourDistance - lastMarkerDistance; if (distanceDiff <= ilLastMarkerDistance) { // this marker is in the range of the last marker distance -> set the tour marker text lastMarker.setLabel(lastMarkerText); TourLogManager.addSubLog(TourLogState.DEFAULT, TourManager.getTourDateTimeShort(tourData)); } } } private void runEasyImport_005_AdjustTemperature(final ImportLauncher importLauncher, final ArrayList<TourData> importedTours) { final float avgMinimumTemperature = importLauncher.tourAvgTemperature; final float temperature = UI.convertTemperatureFromMetric(avgMinimumTemperature); final int durationTime = importLauncher.temperatureAdjustmentDuration; TourLogManager.addLog(TourLogState.DEFAULT, NLS.bind(EasyImportManager.LOG_EASY_IMPORT_005_ADJUST_TEMPERATURE, new Object[] { getDurationText(importLauncher), _nf1.format(temperature), UI.UNIT_LABEL_TEMPERATURE })); for (final TourData tourData : importedTours) { final float oldTourAvgTemperature = tourData.getAvgTemperature(); // skip tours which avg temperature is above the minimum avg temperature if (oldTourAvgTemperature > avgMinimumTemperature) { TourLogManager.logSubError(String.format(TourManager.LOG_TEMP_ADJUST_006_IS_ABOVE_TEMPERATURE, TourManager.getTourDateTimeShort(tourData), oldTourAvgTemperature, avgMinimumTemperature)); continue; } TourManager.adjustTemperature(tourData, durationTime); } } /** * @param person * @param selectedTours * @param isEasyImport * @return Returns list with saved tours. */ private ArrayList<TourData> runEasyImport_099_SaveTour(final TourPerson person, final ArrayList<TourData> selectedTours, final boolean isEasyImport) { final String css = isEasyImport // ? UI.EMPTY_STRING : TourLogView.CSS_LOG_TITLE; final String message = isEasyImport // ? EasyImportManager.LOG_EASY_IMPORT_099_SAVE_TOUR : TourLogManager.LOG_TOUR_SAVE_TOURS; TourLogManager.addLog(TourLogState.DEFAULT, message, css); final ArrayList<TourData> savedTours = new ArrayList<TourData>(); final IRunnableWithProgress saveRunnable = new IRunnableWithProgress() { @Override public void run(final IProgressMonitor monitor) throws InvocationTargetException, InterruptedException { int saveCounter = 0; final int selectionSize = selectedTours.size(); monitor.beginTask(Messages.Tour_Data_SaveTour_Monitor, selectionSize); // loop: all selected tours, selected tours can already be saved for (final TourData tourData : selectedTours) { monitor.subTask( NLS.bind(Messages.Tour_Data_SaveTour_MonitorSubtask, ++saveCounter, selectionSize)); doSaveTour_OneTour(tourData, person, savedTours); TourLogManager.addSubLog(TourLogState.TOUR_SAVED, String.format(TourLogManager.LOG_TOUR_SAVE_TOURS_FILE, tourData.getTourStartTime().format(TimeTools.Formatter_DateTime_S), tourData.getImportFilePathNameText())); monitor.worked(1); } } }; try { new ProgressMonitorDialog(Display.getCurrent().getActiveShell()).run(true, false, saveRunnable); } catch (InvocationTargetException | InterruptedException e) { TourLogManager.logEx(e); } doSaveTour_PostActions(savedTours); return savedTours; } /** * @param isDeleteAllFiles * When <code>true</code> then all files (device and backup) will be deleted. * Otherwise only device files will be deleted without any confirmation dialog, the * backup files are not touched, this feature is used to move device files to the * backup folder. */ private void runEasyImport_100_DeleteTourFiles(final boolean isDeleteAllFiles, final ArrayList<TourData> allTourData, final boolean isEasyImport) { // open log view always then tour files are deleted TourLogManager.showLogView(); final String css = isEasyImport // ? UI.EMPTY_STRING : TourLogView.CSS_LOG_TITLE; final String message = isEasyImport ? EasyImportManager.LOG_EASY_IMPORT_100_DELETE_TOUR_FILES : RawDataManager.LOG_IMPORT_DELETE_TOUR_FILE; TourLogManager.addLog(TourLogState.DEFAULT, message, css); if (isDeleteAllFiles) { if (MessageDialog.openConfirm(_parent.getShell(), Messages.Import_Data_Dialog_DeleteTourFiles_Title, Messages.Import_Data_Dialog_DeleteTourFiles_Message) == false) { return; } if (MessageDialog.openConfirm(_parent.getShell(), Messages.Import_Data_Dialog_DeleteTourFiles_Title, Messages.Import_Data_Dialog_DeleteTourFiles_LastChance_Message) == false) { return; } } final ArrayList<String> deletedFiles = new ArrayList<>(); final ArrayList<String> notDeletedFiles = new ArrayList<>(); final IRunnableWithProgress saveRunnable = new IRunnableWithProgress() { @Override public void run(final IProgressMonitor monitor) throws InvocationTargetException, InterruptedException { int saveCounter = 0; final int selectionSize = allTourData.size(); monitor.beginTask(Messages.Import_Data_Monitor_DeleteTourFiles, selectionSize); // loop: all selected tours, selected tours can already be saved for (final TourData tourData : allTourData) { monitor.subTask(NLS.bind(Messages.Import_Data_Monitor_DeleteTourFiles_Subtask, ++saveCounter, selectionSize)); if (tourData.isBackupImportFile && isDeleteAllFiles == false) { /* * Do not delete files which are imported from the backup folder */ continue; } final String originalFilePath = tourData.importFilePathOriginal; // this is the backup folder when an backup is created final String importFilePath = tourData.getImportFilePath(); final String importFileName = tourData.getImportFileName(); // delete backup files if (isDeleteAllFiles) { deleteFile(deletedFiles, notDeletedFiles, importFilePath, importFileName, TourLogState.EASY_IMPORT_DELETE_BACKUP); } // delete device files deleteFile(deletedFiles, notDeletedFiles, originalFilePath, importFileName, TourLogState.EASY_IMPORT_DELETE_DEVICE); // set state if (isDeleteAllFiles) { tourData.isTourFileDeleted = true; } else { tourData.isTourFileMoved = true; } monitor.worked(1); } } }; try { new ProgressMonitorDialog(_parent.getShell()).run(true, false, saveRunnable); } catch (InvocationTargetException | InterruptedException e) { TourLogManager.logEx(e); } // show delete state in UI _tourViewer.update(allTourData.toArray(), null); /* * Log deleted files */ final String logText = String.format(RawDataManager.LOG_IMPORT_DELETE_TOUR_FILE_END, deletedFiles.size(), notDeletedFiles.size()); TourLogManager.addLog(TourLogState.DEFAULT, logText); } private void saveState() { // check if UI is disposed final Table table = _tourViewer.getTable(); if (table.isDisposed()) { return; } EasyImportManager.getInstance().saveEasyConfig(getEasyConfig()); /* * save imported file names */ final boolean isRemoveToursWhenClosed = _actionRemoveToursWhenClosed.isChecked(); String[] stateImportedFiles; if (isRemoveToursWhenClosed) { stateImportedFiles = new String[] {}; } else { final HashSet<String> importedFiles = _rawDataMgr.getImportedFiles(); stateImportedFiles = importedFiles.toArray(new String[importedFiles.size()]); } _state.put(STATE_IMPORTED_FILENAMES, stateImportedFiles); _state.put(STATE_IS_REMOVE_TOURS_WHEN_VIEW_CLOSED, isRemoveToursWhenClosed); // keep selected tours Util.setState(_state, STATE_SELECTED_TOUR_INDICES, table.getSelectionIndices()); _columnManager.saveState(_state); } /** * Select first tour in the import view. */ public void selectFirstTour() { final TourData firstTourData = (TourData) _tourViewer.getElementAt(0); if (firstTourData != null) { _tourViewer.setSelection(new StructuredSelection(firstTourData), true); } } void selectLastTour() { final Collection<TourData> tourDataCollection = _rawDataMgr.getImportedTours().values(); final TourData[] tourList = tourDataCollection.toArray(new TourData[tourDataCollection.size()]); // select the last tour in the viewer if (tourList.length > 0) { final TourData tourData = tourList[0]; _tourViewer.setSelection(new StructuredSelection(tourData), true); } } /** * Passing the focus request to the viewer's control. */ @Override public void setFocus() { /* * When imported tours are available then the import viewer page will ALLWAYS be displayed. */ final int numImportedTours = _rawDataMgr.getImportedTours().size(); if (numImportedTours > 0) { _tourViewer.getControl().setFocus(); } else { if (_isNewUI) { if (_browser != null) { _browser.setFocus(); } } else { _topPageBook.setFocus(); } } if (_postSelectionProvider.getSelection() == null) { // fire a selected tour when the selection provider was cleared sometime before Display.getCurrent().asyncExec(new Runnable() { @Override public void run() { fireSelectedTour(); } }); } } private void setWatcher_Off() { if (isWatchingOn()) { // !!! Store watching must be canceled before the watch folder thread because it could launch a new watch folder thread !!! thread_WatchStores_Cancel(); thread_WatchFolders(false); updateUI_WatcherAnimation(DOM_CLASS_DEVICE_OFF_ANIMATED); } } private void setWatcher_On() { if (isWatchingOn()) { // do not start twice return; } updateUI_WatcherAnimation(DOM_CLASS_DEVICE_ON_ANIMATED); thread_WatchStores_Start(); thread_FolderWatcher_Activate(); } private void showFailbackUI() { if (_browser == null || _browser.isDisposed()) { // show OLD UI after 5 seconds Display.getDefault().timerExec(5000, new Runnable() { @Override public void run() { if (_parent.isDisposed()) { return; } // check again because the browser could be set if (_browser == null || _browser.isDisposed()) { onSelectUI_Old(); } } }); } } private void thread_FolderWatcher_Activate() { // activate store watching _isWatchingStores.set(true); // activate folder watching thread_WatchFolders(true); } private void thread_FolderWatcher_Deactivate() { // deactivate background tasks _isWatchingStores.set(false); thread_WatchFolders(false); } /** * Retrieve files from the device folder and update the UI. */ private void thread_UpdateDeviceState() { final EasyConfig importConfig = getEasyConfig(); if (importConfig.getActiveImportConfig().isWatchAnything()) { EasyImportManager.getInstance().checkImportedFiles(true); updateUI_DeviceState(); } } /** * @param isStartWatching * When <code>true</code> a new watcher ist restarted, otherwise this thread is * canceled. */ private void thread_WatchFolders(final boolean isStartWatching) { WATCH_LOCK.lock(); try { // cancel previous watcher thread_WatchFolders_Cancel(); if (_watchingFolderThread != null) { throw new RuntimeException(); } if (isWatchingOn() == false) { // watching store is off -> do not watch folders return; } if (isStartWatching) { final Runnable runnable = thread_WatchFolders_Runnable(); _watchingFolderThread = new Thread(runnable, "WatchDeviceFolder - " + TimeTools.now()); //$NON-NLS-1$ _watchingFolderThread.setDaemon(true); _watchingFolderThread.start(); } } finally { WATCH_LOCK.unlock(); } } /** * <b>!!! This thread is not interrupted it could cause SQL exceptions !!!</b> */ private void thread_WatchFolders_Cancel() { if (_watchingFolderThread != null) { try { if (_folderWatcher != null) { try { _folderWatcher.close(); } catch (final IOException e) { TourLogManager.logEx(e); } finally { _folderWatcher = null; } } } catch (final Exception e) { TourLogManager.logEx(e); } finally { try { // it occured that the join never ended // _watchingFolderThread.join(); _watchingFolderThread.join(10000); // force interrupt _watchingFolderThread.interrupt(); } catch (final InterruptedException e) { TourLogManager.logEx(e); } finally { _watchingFolderThread = null; } } } } private Runnable thread_WatchFolders_Runnable() { return new Runnable() { @Override public void run() { WatchService folderWatcher = null; WatchKey watchKey = null; try { // keep watcher local because it could be set to null !!! folderWatcher = _folderWatcher = FileSystems.getDefault().newWatchService(); final EasyConfig easyConfig = getEasyConfig(); final ImportConfig importConfig = easyConfig.getActiveImportConfig(); /* * Check device folder */ boolean isDeviceFolderValid = false; final String deviceFolder = importConfig.getDeviceOSFolder(); if (deviceFolder != null) { try { final Path deviceFolderPath = Paths.get(deviceFolder); if (Files.exists(deviceFolderPath)) { isDeviceFolderValid = true; deviceFolderPath.register(folderWatcher, ENTRY_CREATE, ENTRY_DELETE); } } catch (final Exception e) { } } if (isDeviceFolderValid) { Thread.currentThread().setName(// "WatchingDeviceFolder: " + deviceFolder + " - " + TimeTools.now()); //$NON-NLS-1$ //$NON-NLS-2$ } else { // the device folder is not available, update the folder state updateUI_DeviceState(); return; } /* * Check backup folder */ final String backupFolder = importConfig.getBackupOSFolder(); if (backupFolder != null) { try { final Path watchBackupFolder = Paths.get(backupFolder); if (Files.exists(watchBackupFolder)) { watchBackupFolder.register(folderWatcher, ENTRY_CREATE, ENTRY_DELETE); } } catch (final Exception e) { } } // do not update the device state when the import is running otherwise the import file list can be wrong if (_isUpdateDeviceState) { thread_UpdateDeviceState(); } do { // wait for the next event watchKey = folderWatcher.take(); /* * Events MUST be polled otherwise this will stay in an endless loop. */ @SuppressWarnings("unused") final List<WatchEvent<?>> polledEvents = watchKey.pollEvents(); //// log events, they are not used // for (final WatchEvent<?> event : polledEvents) { // // final WatchEvent.Kind<?> kind = event.kind(); // // System.out.println((UI.timeStampNano() + " [" + getClass().getSimpleName() + "] ") // + (String.format("Event: %s\tFile: %s", kind, event.context()))); // // TODO remove SYSTEM.OUT.PRINTLN // } // do not update the device state when the import is running otherwise the import file list can be wrong if (_isUpdateDeviceState) { thread_UpdateDeviceState(); } } while (watchKey.reset()); } catch (final InterruptedException e) { // } catch (final ClosedWatchServiceException e) { // } catch (final Exception e) { TourLogManager.logEx(e); } finally { if (watchKey != null) { watchKey.cancel(); } if (folderWatcher != null) { try { folderWatcher.close(); } catch (final IOException e) { TourLogManager.logEx(e); } } } } }; } /** * Thread cannot be interrupted, it could cause SQL exceptions, so set flag and wait. */ private void thread_WatchStores_Cancel() { _isStopWatchingStoresThread = true; // run with progress, duration can be 0...5 seconds try { final IRunnableWithProgress runnable = new IRunnableWithProgress() { @Override public void run(final IProgressMonitor monitor) throws InvocationTargetException, InterruptedException { try { monitor.beginTask(Messages.Import_Data_Task_CloseDeviceInfo, IProgressMonitor.UNKNOWN); final int waitingTime = 10000; _watchingStoresThread.join(waitingTime); if (_watchingStoresThread.isAlive()) { // thread is still alive _watchingStoresThread.interrupt(); Display.getDefault().asyncExec(new Runnable() { @Override public void run() { StatusUtil.showInfo(NLS.bind(// Messages.Import_Data_Task_CloseDeviceInfo_CannotClose, waitingTime / 1000)); } }); } } catch (final InterruptedException e) { TourLogManager.logEx(e); } finally { _watchingStoresThread = null; } } }; new ProgressMonitorDialog(Display.getDefault().getActiveShell()).run(true, false, runnable); } catch (InvocationTargetException | InterruptedException e) { TourLogManager.logEx(e); } } private void thread_WatchStores_Start() { _watchingStoresThread = new Thread("WatchingStores") { //$NON-NLS-1$ @Override public void run() { while (!isInterrupted()) { try { Thread.sleep(1000); // check if this thread should be stopped if (_isStopWatchingStoresThread) { _isStopWatchingStoresThread = false; break; } // check if polling is currently enabled if (_isWatchingStores.get()) { final EasyConfig importConfig = getEasyConfig(); // check if anything should be watched if (importConfig.getActiveImportConfig().isWatchAnything()) { final boolean isCheckFiles = _isDeviceStateValid == false; final DeviceImportState importState = EasyImportManager.getInstance()// .checkImportedFiles(isCheckFiles); if (importState.areTheSameStores == false || isCheckFiles) { // stores have changed, update the folder watcher thread_WatchFolders(true); } if (importState.areFilesRetrieved || isCheckFiles) { // import files have been retrieved, update the UI updateUI_DeviceState(); } _isDeviceStateValid = true; } } } catch (final InterruptedException e) { interrupt(); } catch (final Exception e) { TourLogManager.logEx(e); } } } }; _watchingStoresThread.setDaemon(true); _watchingStoresThread.start(); } @Override public void updateColumnHeader(final ColumnDefinition colDef) { // TODO Auto-generated method stub } /** * Keep live update values, other values MUST already have been set. */ private void updateModel_EasyConfig_Dashboard(final EasyConfig modifiedConfig) { final EasyConfig easyConfig = getEasyConfig(); if (easyConfig.animationDuration != modifiedConfig.animationDuration || easyConfig.animationCrazinessFactor != modifiedConfig.animationCrazinessFactor) { // run animation only when it was modified _isRunDashboardAnimation = true; } easyConfig.animationCrazinessFactor = modifiedConfig.animationCrazinessFactor; easyConfig.animationDuration = modifiedConfig.animationDuration; easyConfig.backgroundOpacity = modifiedConfig.backgroundOpacity; easyConfig.isLiveUpdate = modifiedConfig.isLiveUpdate; easyConfig.numHorizontalTiles = modifiedConfig.numHorizontalTiles; easyConfig.stateToolTipWidth = modifiedConfig.stateToolTipWidth; easyConfig.tileSize = modifiedConfig.tileSize; EasyImportManager.getInstance().saveEasyConfig(easyConfig); } private void updateToolTipState() { _isToolTipInDate = _prefStore.getBoolean(ITourbookPreferences.VIEW_TOOLTIP_TOURIMPORT_DATE); _isToolTipInTime = _prefStore.getBoolean(ITourbookPreferences.VIEW_TOOLTIP_TOURIMPORT_TIME); _isToolTipInTitle = _prefStore.getBoolean(ITourbookPreferences.VIEW_TOOLTIP_TOURIMPORT_TITLE); _isToolTipInTags = _prefStore.getBoolean(ITourbookPreferences.VIEW_TOOLTIP_TOURIMPORT_TAGS); } /** * Set top page. */ private void updateUI_1_TopPage(final boolean isInStartUp) { /* * When imported tours are available then the import viewer page will ALLWAYS be displayed. */ final int numImportedTours = _rawDataMgr.getImportedTours().size(); if (numImportedTours > 0) { thread_FolderWatcher_Deactivate(); _topPageBook.showPage(_topPage_ImportViewer); } else { /* * !!! Run async that the first page in the top pagebook is visible and to prevent * flickering when the view toolbar is first drawn on the left side of the view !!! */ if (_isNewUI) { _parent.getDisplay().asyncExec(new Runnable() { @Override public void run() { _isInUIStartup = isInStartUp; createUI_NewUI(); _topPageBook.showPage(_topPage_Dashboard); // create dashboard UI updateUI_2_Dashboard(); if (_browser == null) { // deactivate background task setWatcher_Off(); } // the watcher is started in onBrowser_Completed } }); } else { _topPageBook.showPage(_topPage_OldUI); _linkImport.setFocus(); } } } /** * Set/create dashboard page. */ private void updateUI_2_Dashboard() { if (_dashboard_PageBook == null) { /* * This occures when the app is started the first time and the measurement selection * dialog which fires an event */ return; } final boolean isBrowserAvailable = _browser != null; // set dashboard page _dashboard_PageBook.showPage(isBrowserAvailable// ? _dashboardPage_WithBrowser : _dashboardPage_NoBrowser); if (!isBrowserAvailable) { return; } final String html = createHTML(); _isBrowserCompleted = false; _browser.setText(html); } private void updateUI_DeviceState() { Display.getDefault().asyncExec(new Runnable() { @Override public void run() { if (_browser.isDisposed()) { // this occured return; } if (_isBrowserCompleted) { updateUI_DeviceState_DOM(); } else { _isDeviceStateUpdateDelayed.set(true); } } }); } private void updateUI_DeviceState_DOM() { final String htmlDeviceOnOff = createHTML_52_DeviceState_OnOff(); String jsDeviceOnOff = UI.replaceJS_QuotaMark(htmlDeviceOnOff); jsDeviceOnOff = UI.replaceHTML_NewLine(jsDeviceOnOff); final String htmlDeviceState = createHTML_54_DeviceState(); String jsDeviceState = UI.replaceJS_QuotaMark(htmlDeviceState); jsDeviceState = UI.replaceHTML_NewLine(jsDeviceState); final String js = "\n" //$NON-NLS-1$ + ("var htmlDeviceOnOff=\"" + jsDeviceOnOff + "\";\n") //$NON-NLS-1$ //$NON-NLS-2$ + ("document.getElementById(\"" + DOM_ID_DEVICE_ON_OFF + "\").innerHTML = htmlDeviceOnOff;\n") //$NON-NLS-1$ //$NON-NLS-2$ + ("var htmlDeviceState =\"" + jsDeviceState + "\";\n") //$NON-NLS-1$ //$NON-NLS-2$ + ("document.getElementById(\"" + DOM_ID_DEVICE_STATE + "\").innerHTML = htmlDeviceState;\n") //$NON-NLS-1$ //$NON-NLS-2$ ; final boolean isSuccess = _browser.execute(js); if (!isSuccess) { System.out.println((UI.timeStampNano() + " [" + getClass().getSimpleName() + "] ") //$NON-NLS-1$ //$NON-NLS-2$ + ("\tupdateDOM_DeviceState: " + isSuccess + js)); //$NON-NLS-1$ // TODO remove SYSTEM.OUT.PRINTLN } } /** * Set the sort column direction indicator for a column. * * @param sortColumnId * @param isAscendingSort */ private void updateUI_ShowSortDirection(final String sortColumnId, final int sortDirection) { final Table table = _tourViewer.getTable(); final TableColumn tc = getSortColumn(sortColumnId); table.setSortColumn(tc); table.setSortDirection(sortDirection == ImportComparator.ASCENDING ? SWT.UP : SWT.DOWN); } private void updateUI_TourViewerColumns() { // set tooltip text final String timeZone = _prefStoreCommon.getString(ICommonPreferences.TIME_ZONE_LOCAL_ID); final String timeZoneTooltip = NLS.bind(COLUMN_FACTORY_TIME_ZONE_DIFF_TOOLTIP, timeZone); _timeZoneOffsetColDef.setColumnHeaderToolTipText(timeZoneTooltip); } private void updateUI_WatcherAnimation(final String domClassState) { if (_isShowWatcherAnimation && _browser != null && !_browser.isDisposed() && _isBrowserCompleted) { _isShowWatcherAnimation = false; final String js = UI.EMPTY_STRING// + ("document.getElementById(\"" + DOM_ID_IMPORT_TILES + "\").className ='" + domClassState //$NON-NLS-1$//$NON-NLS-2$ + "';\n") //$NON-NLS-1$ + ("document.getElementById(\"" + DOM_ID_DEVICE_STATE + "\").className ='" + domClassState //$NON-NLS-1$//$NON-NLS-2$ + "';\n") //$NON-NLS-1$ + ("document.getElementById(\"" + DOM_ID_IMPORT_CONFIG + "\").className ='" + domClassState //$NON-NLS-1$//$NON-NLS-2$ + "';\n") //$NON-NLS-1$ ; _browser.execute(js); } } /** * when the active person was modified, the view must be updated */ private void updateViewerPersonData() { _activePerson = TourbookPlugin.getActivePerson(); // update person in save action enableActions(); // update person in the raw data _rawDataMgr.updateTourData_InImportView_FromDb(null); _tourViewer.refresh(); } }