Java tutorial
/* * The MIT License (MIT) * * Copyright (c) 2015 Bogdan Rechi * * 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; either version 2 * of the License, or (at your option) any later version. * 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 Street, Fifth Floor, Boston, MA 02110-1301, USA. */ package bogdanrechi.lansator; import org.apache.commons.io.FilenameUtils; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.eclipse.swt.SWT; import org.eclipse.swt.events.ControlAdapter; import org.eclipse.swt.events.ControlEvent; import org.eclipse.swt.events.FocusAdapter; import org.eclipse.swt.events.FocusEvent; import org.eclipse.swt.events.KeyAdapter; import org.eclipse.swt.events.KeyEvent; import org.eclipse.swt.events.MenuDetectEvent; import org.eclipse.swt.events.MenuDetectListener; import org.eclipse.swt.events.MouseAdapter; import org.eclipse.swt.events.MouseEvent; import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.events.ShellAdapter; import org.eclipse.swt.events.ShellEvent; import org.eclipse.swt.events.TraverseEvent; import org.eclipse.swt.events.TraverseListener; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.graphics.Point; import org.eclipse.swt.graphics.Rectangle; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Menu; import org.eclipse.swt.widgets.MenuItem; import org.eclipse.swt.widgets.Shell; import org.eclipse.swt.widgets.TabFolder; import org.eclipse.swt.widgets.TabItem; import org.eclipse.swt.widgets.ToolBar; import org.eclipse.swt.widgets.ToolItem; import org.eclipse.swt.widgets.TrayItem; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.JsonSyntaxException; import bogdanrechi.commons.About; import bogdanrechi.commons.Exec; import bogdanrechi.commons.Localization; import bogdanrechi.commons.Platform; import bogdanrechi.commons.Property; import bogdanrechi.commons.Run; import bogdanrechi.commons.SingleInstance; import bogdanrechi.commons.exceptions.StringException; import bogdanrechi.commons.file.FileContent; import bogdanrechi.commons.file.Files; import bogdanrechi.commons.text.Text; import bogdanrechi.lansator.properties.Configuration; import bogdanrechi.lansator.properties.Item; import bogdanrechi.lansator.properties.ProgramItem; import bogdanrechi.lansator.properties.ProgramsGroupItem; import bogdanrechi.lansator.resources.LansatorResources; import bogdanrechi.swt.commons.SwtMessageBox; import bogdanrechi.swt.commons.SwtPlatform; import bogdanrechi.swt.commons.SwtPoints; import bogdanrechi.swt.commons.SwtResourceManager; import bogdanrechi.swt.commons.SwtShell; import bogdanrechi.swt.commons.dialogs.AboutBox; /** * Applications launcher * * @author Bogdan Rechi */ public final class MainWindow extends Shell { private static final String ERROR_CANNOT_CREATE_SINGLE_INSTANCE_OBJECT = "Cannot create single instance object"; /** * Single instance port */ private static final int SINGLE_INSTANCE_PORT = 50123; /** * Single instance handshake */ private static final String SINGLE_INSTANCE_HANDSHAKE = "6ad8a44a-0f48-4d75-9734-96f6a62e1ec7"; /** * Big ampersand, workaround for group names. The double & does not work */ private static final String BIG_AMPERSAND = ""; /** * Item images folder */ private static final String IMAGES_PATH = Platform.CURRENT_DIRECTORY + "images" + Platform.FILE_SEPARATOR; /** * Last path used for loading */ public String LastLoadingPath = IMAGES_PATH; public static int ImagesMaximumDimension = 32; // localizations private Localization _localizedControls; private Localization _localizedMessages; /** * Application language */ private String _language = Platform.SYSTEM_LANGUAGE; /** * Resource manager */ private SwtResourceManager _swtResourceManager; /** * Application log4j log */ private Logger _log; /** * Application main image */ private Image _mainImage; private Gson _gson; /** * Application configuration */ private Configuration _config; /** * Tray menu images */ private Image _showImage; private Image _aboutImage; private Image _terminalImage; private Image _centerOnScreenImage; private Image _saveConfigurationImage; private Image _exitImage; /** * Default image path */ private String _defaultImagePath = LansatorResources.RESOURCES_ICONS_PATH + "running big.png"; /** * Default image path */ private Image _defaultImage; /** * Allow explicit exit */ private boolean _doExit = false; /** * Signals an ongoing operation (against, for example, the hiding of the main window) */ private boolean _ongoingOperation = false; private int _lastSelectedGroup = -1; // region private Display _display; private static MainWindow _mainWindow; // region private TabFolder _tabFolder; /** * Tray menu */ private Menu menuTray; /** * @wbp.nonvisual location=73,509 */ private TrayItem _trayMain; /** * Launch the application * * @param args * Program arguments */ public static void main(String[] args) { Platform.validateCurrentJavaVersion("1.9"); SwtPlatform.validateCurrentSwtVersion(4763); Run.DEBUG_ACTIVE = System.getenv("LANSATOR_DEBUG") != null; SingleInstance.ReceiveMessageDelegate receiveMessageDelegate = new SingleInstance.ReceiveMessageDelegate() { @Override public void receiveMessage(String message) { _mainWindow.showMainWindow(); } }; SingleInstance singleInstance = null; try { singleInstance = SingleInstance.request(SINGLE_INSTANCE_PORT, SINGLE_INSTANCE_HANDSHAKE, receiveMessageDelegate); } catch (StringException e2) { _mainWindow._log.fatal(ERROR_CANNOT_CREATE_SINGLE_INSTANCE_OBJECT); SwtMessageBox.messageBoxError(_mainWindow._localizedMessages.get("CRITICAL_APPLICATION_ERROR")); return; } if (singleInstance == null) { return; } _mainWindow = new MainWindow(Display.getDefault()); _mainWindow._trayMain = new TrayItem(_mainWindow._display.getSystemTray(), SWT.NONE); try { _mainWindow._log = LogManager.getLogger(MainWindow.class); if (args.length == 1) { _mainWindow._language = args[0]; } _mainWindow .setLocalizedMessages(new Localization(_mainWindow._language, LansatorResources.MESSAGES_JSON)); _mainWindow .setLocalizedControls(new Localization(_mainWindow._language, LansatorResources.CONTROLS_JSON)); _mainWindow.loadConfiguration(); _mainWindow.setDefaultImage(_mainWindow._swtResourceManager.loadResourceImage(MainWindow.class, _mainWindow._defaultImagePath)); _mainWindow.createContents(); _mainWindow.setup(); _mainWindow.setVisible(false); _mainWindow.setInitialSize(); while (!_mainWindow.isDisposed()) { if (!_mainWindow._display.readAndDispatch()) { _mainWindow._display.sleep(); } } } catch (Throwable e) { _mainWindow._log.fatal(Run.getExceptionStackTrace(e)); _mainWindow.displayFatalErrorAndExit("CRITICAL_APPLICATION_ERROR"); } finally { _mainWindow._trayMain.dispose(); try { singleInstance.closeInstance(); } catch (StringException e) { _mainWindow._log.fatal(Run.getExceptionStackTrace(e)); } } } /** * Create the shell */ private MainWindow(Display display) { super(display, SWT.CLOSE | SWT.RESIZE | SWT.TITLE); _display = display; _swtResourceManager = SwtResourceManager.getDisplayManager(); SwtShell.CurrentApplicationShell = this; } /** * Create contents of the shell */ protected void createContents() { setMinimumSize(new Point(200, 100)); addKeyListener(new KeyAdapter() { @Override public void keyPressed(KeyEvent arg0) { if (arg0.keyCode == SWT.ESC) { _mainWindow.setVisible(false); } } }); addShellListener(new ShellAdapter() { @Override public void shellClosed(ShellEvent arg0) { if (!_doExit) { arg0.doit = false; _mainWindow.setVisible(false); } else { _mainWindow.saveLastBounds(); SwtResourceManager.disposeAll(); } } }); addTraverseListener(new TraverseListener() { @Override public void keyTraversed(TraverseEvent arg0) { if (arg0.keyCode == SWT.ESC) { _mainWindow.setVisible(false); } } }); this.setImages(new Image[] { _mainImage = _swtResourceManager.loadResourceImage(MainWindow.class, LansatorResources.RESOURCES_ICONS_PATH + "running.png"), _swtResourceManager.loadResourceImage(MainWindow.class, LansatorResources.RESOURCES_ICONS_PATH + "running big.png") }); setText(getLocalizedControls().get("AppTitle")); setSize(523, 373); _trayMain.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent arg0) { showMainWindow(); } }); _trayMain.addMenuDetectListener(new MenuDetectListener() { @Override public void menuDetected(MenuDetectEvent arg0) { menuTray.setVisible(true); } }); _trayMain.setText("Lansator"); _trayMain.setToolTipText("Lansator / " + About.getVersionText(LansatorResources.METADATA_JSON)); _trayMain.setImage(_mainImage); createTrayMenu(); addControlListener(new ControlAdapter() { @Override public void controlResized(ControlEvent arg0) { onResize(); } }); } /** * Set initial window size */ private void setInitialSize() { setSize(_config.width, _config.height); if (_config.left != -1 && _config.top != -1) { setLocation(_config.left, _config.top); } else { centerOnScreen(); } } /** * Save last window bounds */ private void saveLastBounds() { Point size = getSize(); _config.width = size.x; _config.height = size.y; Point location = getLocation(); _config.top = location.y; _config.left = location.x; saveConfiguration(); } /** * Create tray menu */ private void createTrayMenu() { _showImage = _swtResourceManager.loadResourceImage(MainWindow.class, LansatorResources.RESOURCES_ICONS_PATH + "show.png"); _terminalImage = _swtResourceManager.loadResourceImage(MainWindow.class, LansatorResources.RESOURCES_ICONS_PATH + "terminal.png"); _centerOnScreenImage = _swtResourceManager.loadResourceImage(MainWindow.class, LansatorResources.RESOURCES_ICONS_PATH + "center.png"); _saveConfigurationImage = _swtResourceManager.loadResourceImage(MainWindow.class, LansatorResources.RESOURCES_ICONS_PATH + "save.png"); _aboutImage = _swtResourceManager.loadResourceImage(MainWindow.class, LansatorResources.RESOURCES_ICONS_PATH + "about.png"); _exitImage = _swtResourceManager.loadResourceImage(MainWindow.class, LansatorResources.RESOURCES_ICONS_PATH + "exit.png"); menuTray = new Menu(this); setMenu(menuTray); MenuItem menuItem = new MenuItem(menuTray, SWT.NONE); menuItem.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { showMainWindow(); } }); menuItem.setText(getLocalizedControls().get("Show")); menuItem.setImage(_showImage); menuItem = new MenuItem(menuTray, SWT.SEPARATOR); menuItem = new MenuItem(menuTray, SWT.NONE); menuItem.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { _doExit = true; _mainWindow.close(); } }); menuItem.setText(getLocalizedControls().get("Exit")); menuItem.setImage(_exitImage); } /** * Get the current groups * * @return An array of the current group names */ protected String[] getGroupNames() { int count = _tabFolder.getItemCount(); String[] groups = new String[count]; for (int i = 0; i < count; i++) { groups[i] = ((ProgramsGroupItem) _tabFolder.getItem(i).getData()).name; } return groups; } /** * Setup application */ private void setup() { if (_tabFolder != null) { _tabFolder.dispose(); _tabFolder = null; } _tabFolder = new TabFolder(this, SWT.FLAT | SWT.WRAP | SWT.RIGHT); _tabFolder.setBounds(0, 0, 0, 0); _tabFolder.addMouseListener(new MouseAdapter() { @Override public void mouseDown(MouseEvent arg0) { switch (arg0.button) { case 3: setupGroupMenu(arg0); break; case 2: _mainWindow.setVisible(false); break; } } }); _tabFolder.addFocusListener(new FocusAdapter() { @Override public void focusLost(FocusEvent arg0) { if (Platform.SYSTEM_IS_WINDOWS) { if (!_ongoingOperation) { _mainWindow.setVisible(false); } } } }); for (ProgramsGroupItem groupItem : _config.programsGroups) { setupGroup(groupItem); } _tabFolder.forceFocus(); setupLastSelectedGroup(); } /** * Setup last selected group */ private void setupLastSelectedGroup() { if (_mainWindow != null) { onResize(); if (_lastSelectedGroup != -1) { if (_tabFolder.getItemCount() > 0) { if (_tabFolder.getItemCount() > _lastSelectedGroup) { _tabFolder.setSelection(_lastSelectedGroup); } else { _tabFolder.setSelection(_lastSelectedGroup = 0); } } else { _lastSelectedGroup = -1; } } } } /** * Setup group item * * @param groupItem * Group item to setup */ private void setupGroup(ProgramsGroupItem groupItem) { TabItem group = new TabItem(_tabFolder, SWT.NONE); setupGroupImageAndText(groupItem, group); final ToolBar groupToolbar = new ToolBar(_tabFolder, SWT.FLAT | SWT.WRAP | SWT.RIGHT); group.setControl(groupToolbar); groupToolbar.addMouseListener(new MouseAdapter() { @Override public void mouseDown(MouseEvent arg0) { switch (arg0.button) { case 3: setupGroupProgramsMenus(groupItem, groupToolbar, arg0); break; case 2: _mainWindow.setVisible(false); break; } } }); setupGroupProgramsTextAndOnClick(groupItem, groupToolbar); } /** * Setup group programs text and OnClick events * * @param groupItem * Selected group * @param groupToolbar * Selected group toolbar */ private void setupGroupProgramsTextAndOnClick(ProgramsGroupItem groupItem, final ToolBar groupToolbar) { for (ProgramItem itemData : groupItem.programs) { ToolItem item = setupProgramText(groupToolbar, itemData); item.setData(itemData); item.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent arg0) { _ongoingOperation = true; boolean executedOk = execute(itemData, false); _ongoingOperation = false; if (executedOk && (arg0.stateMask & SWT.CONTROL) == 0) { _mainWindow.setVisible(false); } } }); } } /** * Setup program text * * @param groupToolbar * Parent toolbar of program item * @param itemData * Config program data * * @return Toolbar item */ private ToolItem setupProgramText(final ToolBar groupToolbar, ProgramItem itemData) { ToolItem item; if (itemData.isSeparator) { item = new ToolItem(groupToolbar, SWT.SEPARATOR_FILL); item.setText(" | "); } else { boolean hasImage = itemData.imageFile.length() != 0; String itemName = itemData.name; if (itemData.asSuperuser) { itemName = "* " + itemName; } item = new ToolItem(groupToolbar, SWT.NONE); if (hasImage) { Image itemImage = _swtResourceManager.loadImageAtMaximumDimension(IMAGES_PATH + itemData.imageFile, ImagesMaximumDimension); if (itemImage != null && !itemImage.isDisposed()) { item.setImage(itemImage); } else { item.setImage(getDefaultImage()); } } if ((hasImage && itemData.isImageAndText) || !hasImage) { item.setText(itemName.replaceAll("&", "&&")); } else { item.setToolTipText(itemName); } } return item; } /** * Setup group programs menus * * @param groupItem * Selected group * @param groupToolbar * Group toolbar * @param arg0 * Mouse event */ private void setupGroupProgramsMenus(ProgramsGroupItem groupItem, final ToolBar groupToolbar, MouseEvent arg0) { boolean hasItemsAbove = false; Menu popMenu = new Menu(groupToolbar); ProgramItem currentItemData = null; for (int i = 0; i < groupToolbar.getItemCount(); i++) { ToolItem ti = groupToolbar.getItem(i); if (SwtPoints.pointInRectangle(arg0.x, arg0.y, ti.getBounds())) { final ProgramItem itemData = (ProgramItem) ti.getData(); currentItemData = itemData; _lastSelectedGroup = _tabFolder.getSelectionIndex(); addProgramUpdateMenuItem(popMenu, itemData); addProgramDuplicateMenuItem(groupItem, popMenu, itemData); addProgramRemoveMenuItem(groupItem, popMenu, itemData); addProgramExecAsSuperuserMenuItem(popMenu, itemData); hasItemsAbove = true; break; } } addCommonMenuItems(currentItemData, false, hasItemsAbove, popMenu); popMenu.setVisible(true); } /** * Add program "exec as superuser" menu item * * @param popMenu * Menu to add the item to * @param itemData * Config data of the program */ private void addProgramExecAsSuperuserMenuItem(Menu popMenu, final ProgramItem itemData) { if (Platform.SYSTEM_IS_LINUX) { if (!itemData.asSuperuser) { MenuItem popMenuItem = new MenuItem(popMenu, SWT.SEPARATOR); popMenuItem = new MenuItem(popMenu, SWT.NONE); popMenuItem.setText(getLocalizedControls().get("ExecuteAsSuperuser")); popMenuItem.setImage(_terminalImage); popMenuItem.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent arg0) { _ongoingOperation = true; boolean executedOk = execute(itemData, true); _ongoingOperation = false; if (executedOk && (arg0.stateMask & SWT.CONTROL) == 0) { _mainWindow.setVisible(false); } } }); } } } /** * Add program "remove" menu item * * @param groupItem * Group containing program * @param popMenu * Menu to add the item to * @param itemData * Config data of the program */ private void addProgramRemoveMenuItem(ProgramsGroupItem groupItem, Menu popMenu, final ProgramItem itemData) { MenuItem popMenuItem = new MenuItem(popMenu, SWT.NONE); popMenuItem.setText(getLocalizedControls().get("Remove")); popMenuItem.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent arg0) { _ongoingOperation = true; int response; if (itemData.isSeparator) { response = SwtMessageBox.messageBox(getLocalizedMessages().get("CONFIRM_REMOVE_SEPARATOR"), SWT.ICON_QUESTION | SWT.OK | SWT.CANCEL); } else { response = SwtMessageBox.messageBox( String.format(getLocalizedMessages().get("CONFIRM_REMOVE_ITEM"), itemData.name), SWT.ICON_QUESTION | SWT.OK | SWT.CANCEL); } if (response == SWT.OK) { removeItem(groupItem, itemData); _lastSelectedGroup = _tabFolder.getSelectionIndex(); setup(); } _ongoingOperation = false; } }); } /** * Add program "duplicate" menu item * * @param groupItem * Group containing program * @param popMenu * Menu to add the item to * @param itemData * Config data of the program */ private void addProgramDuplicateMenuItem(ProgramsGroupItem groupItem, Menu popMenu, final ProgramItem itemData) { MenuItem popMenuItem = new MenuItem(popMenu, SWT.NONE); popMenuItem.setText(getLocalizedControls().get("Duplicate")); popMenuItem.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent arg0) { _ongoingOperation = true; try { duplicateProgramItem(groupItem, itemData); } catch (StringException e) { _mainWindow.reportCriticalErrorAndTerminate(e); } _lastSelectedGroup = _tabFolder.getSelectionIndex(); setup(); _ongoingOperation = false; } }); } /** * Add program "update" menu item * * @param popMenu * Program menu * @param itemData * Config program data */ private void addProgramUpdateMenuItem(Menu popMenu, final ProgramItem itemData) { MenuItem popMenuItem = new MenuItem(popMenu, SWT.NONE); popMenuItem.setText(getLocalizedControls().get("Update")); popMenuItem.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent arg0) { _ongoingOperation = true; AddUpdateProgram itemDlg = new AddUpdateProgram(_mainWindow, true); itemDlg.setDetails(itemData); itemDlg.setGroupNames(getGroupNames()); itemDlg.setGroupIndex(_tabFolder.getSelectionIndex()); if (itemDlg.open() == SWT.OK) { updateItem(itemData, itemDlg.getDetails(), itemDlg.getGroupIndex()); _lastSelectedGroup = itemDlg.getGroupIndex(); setup(); } _ongoingOperation = false; } }); } /** * Setup group image and text * * @param configGroupItem * Config group item * @param group * Group tab */ private void setupGroupImageAndText(ProgramsGroupItem configGroupItem, TabItem group) { boolean hasImage = configGroupItem.imageFile.length() != 0; if (hasImage) { Image groupImage = _swtResourceManager .loadImageAtMaximumDimension(IMAGES_PATH + configGroupItem.imageFile, ImagesMaximumDimension); if (groupImage != null && !groupImage.isDisposed()) { group.setImage(groupImage); } else { group.setImage(getDefaultImage()); } } if ((hasImage && configGroupItem.isImageAndText) || !hasImage) { group.setText(configGroupItem.name.replaceAll("&", BIG_AMPERSAND)); } else { group.setToolTipText(configGroupItem.name); } group.setData(configGroupItem); } /** * Setup group menu * * @param arg0 * Right-click mouse event */ private void setupGroupMenu(MouseEvent arg0) { boolean hasItemsAbove = false; ProgramsGroupItem currentGroupData = null; Menu popMenu = new Menu(_tabFolder); for (int i = 0; i < _tabFolder.getItemCount(); i++) { final TabItem ti = _tabFolder.getItem(i); if (SwtPoints.pointInRectangle(arg0.x, arg0.y, ti.getBounds())) { final ProgramsGroupItem groupData = (ProgramsGroupItem) ti.getData(); currentGroupData = groupData; _tabFolder.setSelection(_lastSelectedGroup = i); addGroupUpdateMenuItem(popMenu, groupData); addGroupRemoveMenuItem(popMenu, groupData); hasItemsAbove = true; break; } } addCommonMenuItems(currentGroupData, true, hasItemsAbove, popMenu); popMenu.setVisible(true); } /** * Add common items to a popup menu * * @param programOrGroup * The current program or group * @param isGroup * true if a new group is added, otherwise false * @param hasItemsAbove * true if there are items above, otherwise false * @param popMenu * Popup menu to add the items to */ private void addCommonMenuItems(final Item programOrGroup, final boolean isGroup, boolean hasItemsAbove, Menu popMenu) { if (hasItemsAbove) { new MenuItem(popMenu, SWT.SEPARATOR); } if (programOrGroup != null) { boolean canMove = false; if (canMoveItemBefore(programOrGroup)) { canMove = true; addCommonMoveLeftMenuItems(programOrGroup, isGroup, popMenu); } if (canMove) { new MenuItem(popMenu, SWT.SEPARATOR); canMove = false; } if (canMoveItemAfter(programOrGroup)) { canMove = true; addCommonMoveRightMenuItems(programOrGroup, isGroup, popMenu); } if (canMove) { new MenuItem(popMenu, SWT.SEPARATOR); } } addCommonAddGroupOrProgramMenuItem(programOrGroup, isGroup, popMenu); MenuItem popMenuItem = new MenuItem(popMenu, SWT.SEPARATOR); popMenuItem = new MenuItem(popMenu, SWT.NONE); popMenuItem.setText(getLocalizedControls().get("CenterOnScreen")); popMenuItem.setImage(_centerOnScreenImage); popMenuItem.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent arg0) { centerOnScreen(); } }); popMenuItem = new MenuItem(popMenu, SWT.NONE); popMenuItem.setText(getLocalizedControls().get("SaveConfiguration")); popMenuItem.setImage(_saveConfigurationImage); popMenuItem.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent arg0) { saveConfiguration(); _ongoingOperation = true; SwtMessageBox.messageBox(getLocalizedMessages().get("CONFIGURATION_SAVED")); _ongoingOperation = false; } }); popMenuItem = new MenuItem(popMenu, SWT.SEPARATOR); popMenuItem = new MenuItem(popMenu, SWT.NONE); popMenuItem.setText(getLocalizedControls().get("About")); popMenuItem.setImage(_aboutImage); popMenuItem.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent arg0) { showAbout(); } }); popMenuItem = new MenuItem(popMenu, SWT.SEPARATOR); popMenuItem = new MenuItem(popMenu, SWT.NONE); popMenuItem.setText(getLocalizedControls().get("Exit")); popMenuItem.setImage(_exitImage); popMenuItem.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent arg0) { _doExit = true; _mainWindow.close(); } }); } /** * Add common "add group" or "add program" menu item * * @param programOrGroup * Item being added the menu item * @param isGroup * true if the item is group, otherwise false * @param popMenu * Menu to add the item to */ private void addCommonAddGroupOrProgramMenuItem(final Item programOrGroup, final boolean isGroup, Menu popMenu) { MenuItem popMenuItem = new MenuItem(popMenu, SWT.NONE); popMenuItem.setText(getLocalizedControls().get(isGroup ? "AddGroup" : "AddItem")); popMenuItem.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent arg0) { _ongoingOperation = true; if (isGroup) { AddUpdateGroup groupDlg = new AddUpdateGroup(_mainWindow, false); if (groupDlg.open() == SWT.OK) { addGroup((ProgramsGroupItem) programOrGroup, groupDlg.getDetails()); if (programOrGroup == null) { _lastSelectedGroup = _tabFolder.getItemCount(); } else { _lastSelectedGroup = getItemIndex(programOrGroup) - 2; } setup(); } } else // program { AddUpdateProgram itemDlg = new AddUpdateProgram(_mainWindow, false); itemDlg.setGroupNames(getGroupNames()); itemDlg.setGroupIndex(_tabFolder.getSelectionIndex()); if (itemDlg.open() == SWT.OK) { addItem((ProgramItem) programOrGroup, itemDlg.getDetails(), itemDlg.getGroupIndex()); _lastSelectedGroup = itemDlg.getGroupIndex(); setup(); } } _ongoingOperation = false; } }); } /** * Add common "move right" menu items * * @param programOrGroup * Item being added the menu items * @param isGroup * true if the item is group, otherwise false * @param popMenu * Menu to add the items to */ private void addCommonMoveRightMenuItems(final Item programOrGroup, final boolean isGroup, Menu popMenu) { MenuItem popMenuItem = new MenuItem(popMenu, SWT.NONE); popMenuItem.setText(getLocalizedControls().get("MoveRight")); popMenuItem.setImage(_swtResourceManager.loadResourceImage(MainWindow.class, LansatorResources.RESOURCES_ICONS_PATH + "right.png")); popMenuItem.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent arg0) { onMoveItemAfter(programOrGroup, isGroup, 1); } }); popMenuItem = new MenuItem(popMenu, SWT.NONE); popMenuItem.setText(getLocalizedControls().get("MoveRight2")); popMenuItem.setImage(_swtResourceManager.loadResourceImage(MainWindow.class, LansatorResources.RESOURCES_ICONS_PATH + "right2.png")); popMenuItem.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent arg0) { onMoveItemAfter(programOrGroup, isGroup, 2); } }); } /** * Add common "move left" menu items * * @param programOrGroup * Item being added the menu items * @param isGroup * true if the item is group, otherwise false * @param popMenu * Menu to add the items to */ private void addCommonMoveLeftMenuItems(final Item programOrGroup, final boolean isGroup, Menu popMenu) { MenuItem popMenuItem = new MenuItem(popMenu, SWT.NONE); popMenuItem.setText(getLocalizedControls().get("MoveLeft")); popMenuItem.setImage(_swtResourceManager.loadResourceImage(MainWindow.class, LansatorResources.RESOURCES_ICONS_PATH + "left.png")); popMenuItem.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent arg0) { onMoveItemBefore(programOrGroup, isGroup, 1); } }); popMenuItem = new MenuItem(popMenu, SWT.NONE); popMenuItem.setText(getLocalizedControls().get("MoveLeft2")); popMenuItem.setImage(_swtResourceManager.loadResourceImage(MainWindow.class, LansatorResources.RESOURCES_ICONS_PATH + "left2.png")); popMenuItem.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent arg0) { onMoveItemBefore(programOrGroup, isGroup, 2); } }); } /** * Add group update menu item * * @param popMenu * Group menu * @param groupData * Config group data */ private void addGroupUpdateMenuItem(Menu popMenu, final ProgramsGroupItem groupData) { MenuItem popMenuItem = new MenuItem(popMenu, SWT.NONE); popMenuItem.setText(getLocalizedControls().get("Update")); popMenuItem.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent arg0) { _ongoingOperation = true; AddUpdateGroup groupDlg = new AddUpdateGroup(_mainWindow, true); groupDlg.setDetails(groupData); if (groupDlg.open() == SWT.OK) { saveConfiguration(); _lastSelectedGroup = _tabFolder.getSelectionIndex(); setup(); } _ongoingOperation = false; } }); } /** * Add group remove menu item * * @param popMenu * Group menu * @param groupData * Config group data */ private void addGroupRemoveMenuItem(Menu popMenu, final ProgramsGroupItem groupData) { MenuItem popMenuItem; // always at least one group in Linux if (Platform.SYSTEM_IS_WINDOWS || _tabFolder.getItemCount() > 1) { popMenuItem = new MenuItem(popMenu, SWT.NONE); popMenuItem.setText(getLocalizedControls().get("Remove")); popMenuItem.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent arg0) { _ongoingOperation = true; if (SwtMessageBox.messageBox( String.format(getLocalizedMessages().get("CONFIRM_REMOVE_GROUP"), groupData.name), SWT.ICON_QUESTION | SWT.OK | SWT.CANCEL) == SWT.OK) { removeGroup(groupData); setup(); } _ongoingOperation = false; } }); } } /** * Show the About window */ private void showAbout() { _ongoingOperation = true; AboutBox about = new AboutBox(_mainWindow, _language, LansatorResources.METADATA_JSON); about.open(true); _ongoingOperation = false; } @Override protected void checkSubclass() { // Disable the check that prevents subclassing of SWT components } /** * On resize main window */ private void onResize() { if (_tabFolder != null) { Rectangle area = _mainWindow.getClientArea(); _tabFolder.setSize(area.width, area.height); } } /** * Add new group * * @param beforeItem * Item to add the group before * @param details * Details of the added group */ private void addGroup(ProgramsGroupItem beforeItem, Item details) { ProgramsGroupItem newGroupItem = new ProgramsGroupItem(); newGroupItem.guid = details.guid; newGroupItem.name = details.name; newGroupItem.imageFile = details.imageFile; newGroupItem.isImageAndText = details.isImageAndText; addGroupItem(beforeItem, newGroupItem); saveConfiguration(); } /** * Remove group * * @param groupItem * Group item */ private void removeGroup(ProgramsGroupItem groupItem) { _config.programsGroups.removeIf(item -> item.guid.equals(groupItem.guid)); saveConfiguration(); } /** * Add new item * * @param beforeItem * Node to add the item before * @param newItem * New item * @param groupIndex * Group index */ private void addItem(ProgramItem beforeItem, ProgramItem newItem, int groupIndex) { addProgramItem(_config.programsGroups.get(groupIndex), beforeItem, newItem); saveConfiguration(); } /** * Update item * * @param oldItem * Old item * @param updatedItem * Updated item * @param groupIndex * Group index */ private void updateItem(ProgramItem oldItem, ProgramItem updatedItem, int groupIndex) { if (!updatedItem.isSeparator && groupIndex != _tabFolder.getSelectionIndex()) { ((ProgramsGroupItem) _tabFolder.getSelection()[0].getData()).programs .removeIf(itm -> itm.guid.equals(oldItem.guid)); ((ProgramsGroupItem) _tabFolder.getItem(groupIndex).getData()).programs.add(updatedItem); } saveConfiguration(); } /** * Duplicate program item * * @param groupItem * Group item to duplicate into * @param programItem * Program item to duplicate */ private void duplicateProgramItem(ProgramsGroupItem groupItem, ProgramItem programItem) throws StringException { groupItem.programs.add(getItemIndex(programItem), new ProgramItem(programItem)); } /** * Remove item * * @param itemNode * Node of the last selected item */ private void removeItem(ProgramsGroupItem groupItem, ProgramItem itemNode) { groupItem.programs.removeIf(item -> item.guid.equals(itemNode.guid)); saveConfiguration(); } /** * Show main window */ public void showMainWindow() { _display.asyncExec(new Runnable() { @Override public void run() { _mainWindow.setVisible(true); _mainWindow.setMinimized(false); _mainWindow.forceActive(); if (Platform.SYSTEM_IS_LINUX) { _tabFolder.forceFocus(); } } }); } /** * Center main window on screen and save the configuration */ private void centerOnScreen() { SwtShell.centerShellOnScreen(_mainWindow, true); saveConfiguration(); } /** * Execute program associated to item * * @param itemData * Data of the item who's program is to be executed * @param asSuperuser * true to execute as superuser, otherwise false * * @return true if successfully executed, otherwise false */ private boolean execute(final ProgramItem itemData, boolean asSuperuser) { String path = itemData.path; if (path.length() == 0) { return false; } String parameters = itemData.parameters; String workingFolder = itemData.runInFolder; if (!asSuperuser) { asSuperuser = itemData.asSuperuser; } Property<Integer> errorCode = new Property<Integer>(); Process executedProcess; if (asSuperuser) { executedProcess = Exec.executeAsSuperuser(path, parameters, workingFolder, errorCode); } else { executedProcess = Exec.execute(path, parameters, workingFolder, errorCode); } if (executedProcess == null) { if (errorCode.get() == 1) { SwtMessageBox.messageBoxError(getLocalizedMessages().get("ERROR_LAUNCHING_PARAMETERS")); } else { SwtMessageBox.messageBoxError(getLocalizedMessages().get("ERROR_LAUNCHING")); } } return executedProcess != null; } /** * Check if an item can be moved before its current position * * @param item * Item to check * * @return true if movable, otherwise false */ private boolean canMoveItemBefore(Item item) { for (int i = 0; i < _config.programsGroups.size(); i++) { if (item.guid.equals(_config.programsGroups.get(i).guid)) { return i != 0; } else if (_config.programsGroups.get(i).programs.size() != 0) { if (_config.programsGroups.get(i).programs.get(0).guid.equals(item.guid)) { return false; } } } return true; } /** * Move item before its current position by a number of positions * * @param item * Item to be moved * * @param positionsToMove * Number of positions to move */ private void moveItemBefore(Item item, int positionsToMove) { for (int i = 0; i < _config.programsGroups.size(); i++) { if (item.guid.equals(_config.programsGroups.get(i).guid)) { ProgramsGroupItem programsGroupItem = _config.programsGroups.remove(i); _config.programsGroups.add(Math.max(0, i - positionsToMove), programsGroupItem); break; } else { for (int j = 1; j < _config.programsGroups.get(i).programs.size(); j++) { { if (item.guid.equals(_config.programsGroups.get(i).programs.get(j).guid)) { ProgramItem programItem = _config.programsGroups.get(i).programs.remove(j); _config.programsGroups.get(i).programs.add(Math.max(0, j - positionsToMove), programItem); break; } } } } } } /** * Check if an item can be moved after its current position * * @param item * Item to check * * @return true if movable, otherwise false */ private boolean canMoveItemAfter(Item item) { for (int i = _config.programsGroups.size() - 1; i >= 0; i--) { if (item.guid.equals(_config.programsGroups.get(i).guid)) { return i != _config.programsGroups.size() - 1; } else if (_config.programsGroups.get(i).programs.size() != 0) { if (_config.programsGroups.get(i).programs .get(_config.programsGroups.get(i).programs.size() - 1).guid.equals(item.guid)) { return false; } } } return true; } /** * Move item by a number of positions after its current position * * @param item * Item to be moved * @param positionsToMove * Number of positions to move */ private void moveItemAfter(Item item, int positionsToMove) { for (int i = 0; i < _config.programsGroups.size(); i++) { if (item.guid.equals(_config.programsGroups.get(i).guid)) { ProgramsGroupItem programsGroupItem = _config.programsGroups.remove(i); _config.programsGroups.add(Math.min(i + positionsToMove, _config.programsGroups.size()), programsGroupItem); break; } else { for (int j = 0; j < _config.programsGroups.get(i).programs.size() - 1; j++) { { if (item.guid.equals(_config.programsGroups.get(i).programs.get(j).guid)) { ProgramItem programItem = _config.programsGroups.get(i).programs.remove(j); _config.programsGroups.get(i).programs.add( Math.min(j + positionsToMove, _config.programsGroups.get(i).programs.size()), programItem); break; } } } } } } /** * Add item before another item * * @param beforeItem * Add before this item * @param newItem * Item to add */ private void addGroupItem(ProgramsGroupItem beforeItem, ProgramsGroupItem newItem) { if (beforeItem == null) { _config.programsGroups.add(newItem); } else { for (int i = 0; i < _config.programsGroups.size(); i++) { if (_config.programsGroups.get(i).guid.equals(beforeItem.guid)) { _config.programsGroups.add(i, newItem); break; } } } } /** * Add item before another item * * @param groupItem * Group item * @param beforeItem * Add before this item * @param newItem * Item to add */ private void addProgramItem(ProgramsGroupItem groupItem, ProgramItem beforeItem, ProgramItem newItem) { if (beforeItem == null) { groupItem.programs.add(newItem); } else { for (int i = 0; i < groupItem.programs.size(); i++) { if (groupItem.programs.get(i).guid.equals(beforeItem.guid)) { groupItem.programs.add(i, newItem); break; } } } } /** * Get item index (starting with 1) with respect to its siblings * * @param item * Item to get the index for * * @return Item index */ private int getItemIndex(Item item) { for (int i = 0; i < _config.programsGroups.size(); i++) { if (item.guid.equals(_config.programsGroups.get(i).guid)) { return i + 1; } else { for (int j = 0; j < _config.programsGroups.get(i).programs.size(); j++) { if (item.guid.equals(_config.programsGroups.get(i).programs.get(j).guid)) { return j + 1; } } } } return -1; } /** * Set item image file * * @param newImageFile * Newly selected image file * @param item * Item to set the image for */ public static void setItemImageFile(String newImageFile, Item item) throws StringException { String imageFileNewName = Text.newGuid() + "." + FilenameUtils.getExtension(newImageFile); if (!Files.exists(IMAGES_PATH)) { Files.createFolder(IMAGES_PATH); } Files.copyFileToFolder(newImageFile, IMAGES_PATH, imageFileNewName); String formerImageFile = item.imageFile; item.imageFile = imageFileNewName; if (formerImageFile.length() > 0 && Files.exists(IMAGES_PATH + formerImageFile)) { Files.delete(IMAGES_PATH + formerImageFile); } } /** * Display fatal error message and exit application * * @param message * ID of localized error message */ private void displayFatalErrorAndExit(String message) { SwtMessageBox.messageBoxError(getLocalizedMessages().get(message)); _mainWindow.close(); System.exit(1); } /** * On move item before its current position * * @param programOrGroup * Item to move * @param isGroup * true if the item is a group, otherwise false * @param positionsToMove * Number of positions to move */ private void onMoveItemBefore(final Item programOrGroup, final boolean isGroup, final int positionsToMove) { _ongoingOperation = true; if (isGroup) { _lastSelectedGroup = Math.max(0, _tabFolder.getSelectionIndex() - positionsToMove); } moveItemBefore(programOrGroup, positionsToMove); setup(); _ongoingOperation = false; } /** * On move item after its current position * * @param programOrGroup * Item to move * @param isGroup * true if the item is a group, otherwise false * @param positionsToMove * Number of positions to move */ private void onMoveItemAfter(final Item programOrGroup, final boolean isGroup, final int positionsToMove) { _ongoingOperation = true; if (isGroup) { _lastSelectedGroup = Math.min(_tabFolder.getSelectionIndex() + positionsToMove, _tabFolder.getItemCount() - 1); } moveItemAfter(programOrGroup, positionsToMove); setup(); _ongoingOperation = false; } // region /** * Save application configuration */ private void saveConfiguration() { try { FileContent.writeTextFile(_mainWindow._gson.toJson(_mainWindow._config) + "\r\n", Platform.CURRENT_DIRECTORY + "lansator.json"); } catch (StringException e) { _log.fatal(e.getMessage()); displayFatalErrorAndExit("CANNOT_SAVE_CONFIGURATION_FILE"); } } /** * Load application configuration */ private void loadConfiguration() { GsonBuilder builder = new GsonBuilder(); _mainWindow._gson = builder.serializeNulls().setPrettyPrinting().create(); try { _mainWindow._config = _mainWindow._gson.fromJson( FileContent.readTextFile(Platform.CURRENT_DIRECTORY + "lansator.json"), Configuration.class); } catch (JsonSyntaxException | StringException e) { _mainWindow._log.fatal(e.getMessage()); _mainWindow.displayFatalErrorAndExit("CANNOT_LOAD_CONFIGURATION_FILE"); } } /** * Report critical error in message box and log file * * @param exception * Exception to report */ public void reportCriticalErrorAndTerminate(Throwable exception) { _log.fatal(Run.getExceptionStackTrace(exception)); SwtMessageBox.messageBoxError(_localizedMessages.get("CRITICAL_APPLICATION_ERROR")); if (!Run.DEBUG_ACTIVE) { _display.asyncExec(new Runnable() { @Override public void run() { close(); } }); } } // region getters /** * @return The localized controls */ public Localization getLocalizedControls() { return _localizedControls; } /** * @param localizedControls * The localizedControls to set */ private void setLocalizedControls(Localization localizedControls) { this._localizedControls = localizedControls; } /** * @return The localized messages */ public Localization getLocalizedMessages() { return _localizedMessages; } /** * @param localizedMessages * The localized messages to set */ private void setLocalizedMessages(Localization localizedMessages) { this._localizedMessages = localizedMessages; } /** * @return The default image of the application */ public Image getDefaultImage() { return _defaultImage; } /** * @param defaultImage * The default image to set */ private void setDefaultImage(Image defaultImage) { this._defaultImage = defaultImage; } /** * Get images path * * @return Images path */ public static String getImagesPath() { return IMAGES_PATH; } }