Java tutorial
/* * Copyright (C) 2010 mightypocket.com. All rights reserved. Use is * subject to license terms. */ package com.mightypocket.ashot; import com.mightypocket.utils.AndroidSdkHelper; import java.awt.Dimension; import org.jdesktop.application.Task; import javax.swing.AbstractButton; import java.io.File; import java.awt.Desktop; import java.awt.event.ActionEvent; import java.beans.PropertyChangeEvent; import java.util.HashMap; import java.util.Map; import java.awt.Image; import java.awt.event.ActionListener; import java.util.List; import org.jdesktop.application.Action; import java.beans.PropertyChangeListener; import java.beans.PropertyChangeSupport; import java.util.LinkedHashMap; import java.util.prefs.Preferences; import javax.swing.ButtonGroup; import javax.swing.JButton; import javax.swing.JCheckBoxMenuItem; import javax.swing.JComponent; import javax.swing.JMenu; import javax.swing.JMenuBar; import javax.swing.JMenuItem; import javax.swing.JRadioButtonMenuItem; import javax.swing.JToggleButton; import javax.swing.JToolBar; import javax.swing.SwingUtilities; import javax.swing.event.SwingPropertyChangeSupport; import org.apache.commons.lang.StringUtils; import org.jdesktop.application.ApplicationActionMap; import org.jdesktop.application.ResourceMap; import org.jdesktop.application.TaskEvent; import org.jdesktop.application.TaskListener.Adapter; import org.jdesktop.beansbinding.BindingGroup; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import static com.mightypocket.utils.BindingHelper.*; /** * * @author Illya Yalovyy */ public final class Mediator implements PreferencesNames { private final Logger logger = LoggerFactory.getLogger(Mediator.class); private final Preferences p = Preferences.userNodeForPackage(AShot.class); private ImageProcessor imageProcessor = new ImageProcessor();; private JMenu menuFileDevices; private final Map<String, JRadioButtonMenuItem> devices = new HashMap<String, JRadioButtonMenuItem>(); private final ButtonGroup devicesGroup = new ButtonGroup(); private final ImageSaver imageSaver; private final FullScreenFrame fullScreenFrame; private ImagePresenter presenter; // Constants // Components private final PropertyChangeSupport pcs; private final AShot application; private final JToolBar toolBar; private final JMenuBar menuBar; private final StatusBar statusBar; private final MainPanel mainPanel; private final AndroDemon demon; private final Map<String, JComponent> toolBarMap = new LinkedHashMap<String, JComponent>(); // State private ImageEx lastImage; public Mediator(final AShot application) { this.application = application; pcs = new SwingPropertyChangeSupport(this, true); toolBar = createToolBar(); menuBar = createMenuBar(); statusBar = new StatusBar(this); mainPanel = new MainPanel(this); presenter = mainPanel.getPresenter(); imageSaver = new ImageSaver(this); fullScreenFrame = new FullScreenFrame(this); demon = new AndroDemon(this); installListeners(); initProperties(); } private ApplicationActionMap getActionMap() { return application.getContext().getActionMap(this); } private void initProperties() { //TODO Read from preferences setLandscape(p.getBoolean(PREF_SCREENSHOT_LANDSCAPE, false)); Double scale = p.getDouble(PREF_SCREENSHOT_SCALE, 0.0); if (scale == 0.0) { setScaleFit(true); } else { getImageProcessor().setScale(scale); } setShowToolbarLabels(p.getBoolean(PREF_GUI_SHOW_TEXT_IN_TOOLBAR, true)); } private void installListeners() { demon.addTaskListener(new Adapter<Void, ImageEx>() { @Override public void process(TaskEvent<List<ImageEx>> event) { List<ImageEx> value = event.getValue(); if (!value.isEmpty()) { final ImageEx img = value.get(0); updateImageProcessor(img); final Image imgp = imageProcessor.process(img.getValue()); showImage(imgp); if (isRecording() && !(p.getBoolean(PREF_SAVE_SKIP_DUPLICATES, true) && img.isDuplicate())) { imageSaver.saveImage((saveOriginal) ? img.getValue() : imgp); } lastImage = img; } else { showImage(generateDummyImage()); } } }); addPropertyChangeListener(PROP_CONNECTED_DEVICE, new PropertyChangeListener() { @Override public void propertyChange(PropertyChangeEvent evt) { final JRadioButtonMenuItem disconnected = devices.get((String) evt.getOldValue()); final JRadioButtonMenuItem connected = devices.get((String) evt.getNewValue()); if (disconnected != null) { disconnected.setSelected(false); } if (connected != null) { connected.setSelected(true); } else { devicesGroup.clearSelection(); } } }); addPropertyChangeListener(PROP_FULL_SCREEN, new PropertyChangeListener() { @Override public void propertyChange(PropertyChangeEvent evt) { logger.debug("Full screen: {}", evt.getNewValue()); boolean fs = (Boolean) evt.getNewValue(); presenter = fs ? fullScreenFrame.getPresenter() : mainPanel.getPresenter(); } }); } private void updateImageProcessor(final ImageEx img) { final boolean ls = isLandscape(); if (isScaleFit()) { Dimension customBounds = presenter.getPresenterDimension(); int w = img.getValue().getWidth(null); int h = img.getValue().getHeight(null); if (landscape != img.isLandscape()) { final int t = w; w = h; h = t; } double scale = Math.min(customBounds.getWidth() / w, customBounds.getHeight() / h); imageProcessor.setScale(scale); } final boolean ccw = p.getBoolean(PREF_ROTATION_CCW, true); if (ls != img.isLandscape()) { if (ccw == img.isCcw()) { if (ccw) imageProcessor.setRotation(ls ? ImageProcessor.Rotation.R270 : ImageProcessor.Rotation.R90); else imageProcessor.setRotation(ls ? ImageProcessor.Rotation.R90 : ImageProcessor.Rotation.R270); } else { if (ls) { imageProcessor.setRotation(ccw ? ImageProcessor.Rotation.R270 : ImageProcessor.Rotation.R90); } else { imageProcessor .setRotation(img.isCcw() ? ImageProcessor.Rotation.R90 : ImageProcessor.Rotation.R270); } } } else { if (ccw == img.isCcw()) { imageProcessor.setRotation(ImageProcessor.Rotation.R0); } else { imageProcessor.setRotation(ls ? ImageProcessor.Rotation.R180 : ImageProcessor.Rotation.R0); } } } private JMenuBar createMenuBar() { BindingGroup menuBinding = new BindingGroup(); ResourceMap resourceMap = application.getContext().getResourceMap(Mediator.class); ApplicationActionMap actionMap = getActionMap(); JMenuBar bar = new JMenuBar(); // Menu File JMenu menuFile = new JMenu(resourceMap.getString("menu.file")); menuFileDevices = new JMenu(resourceMap.getString("menu.file.devices.text")); menuFileDevices.setIcon(resourceMap.getIcon("menu.file.devices.icon")); menuFile.add(menuFileDevices); menuBinding.addBinding(bindRead(this, PROP_DEVICES, menuFileDevices, "enabled")); menuFile.addSeparator(); menuFile.add(new JMenuItem(actionMap.get(ACTION_SAVE_SCREENSHOT))); menuFile.add(new JCheckBoxMenuItem(actionMap.get(ACTION_RECORDING))); menuFile.add(new JMenuItem(actionMap.get(ACTION_OPEN_DESTINATION_FOLDER))); menuFile.addSeparator(); menuFile.add(new JMenuItem(actionMap.get(ACTION_CHANGE_DEFAULT_FOLDER))); menuFile.add(new JMenuItem(actionMap.get(ACTION_CHANGE_SDK_FOLDER))); menuFile.addSeparator(); menuFile.add(new JMenuItem(actionMap.get("quit"))); // Menu Edit JMenu menuEdit = new JMenu(resourceMap.getString("menu.edit")); menuEdit.add(new JMenuItem(actionMap.get(ACTION_COPY_TO_CLIPBOARD))); // Menu View JMenu menuView = new JMenu(resourceMap.getString("menu.view")); menuView.add(new JCheckBoxMenuItem(actionMap.get(ACTION_SHOW_TOOLBAR_LABELS))); menuView.addSeparator(); menuView.add(new JCheckBoxMenuItem(actionMap.get(ACTION_LANDSCAPE))); menuView.add(new JCheckBoxMenuItem(actionMap.get(ACTION_LANDSCAPE_CW))); menuView.addSeparator(); menuView.add(new JMenuItem(actionMap.get(ACTION_ZOOM_IN))); menuView.add(new JMenuItem(actionMap.get(ACTION_ZOOM_OUT))); menuView.add(new JMenuItem(actionMap.get(ACTION_SIZE_ORIGINAL))); menuView.add(new JMenuItem(actionMap.get(ACTION_SIZE_SMALL))); menuView.add(new JMenuItem(actionMap.get(ACTION_SIZE_LARGE))); menuView.add(new JCheckBoxMenuItem(actionMap.get(ACTION_SIZE_FIT))); menuView.addSeparator(); menuView.add(new JMenuItem(actionMap.get(ACTION_FULL_SCREEN))); // Menu Tools JMenu toolsView = new JMenu(resourceMap.getString("menu.tools")); toolsView.add(new JMenuItem(actionMap.get(ACTION_INSTALL))); toolsView.addSeparator(); toolsView.add(new JMenuItem(actionMap.get(ACTION_OPTIONS))); // Menu Help JMenu menuHelp = new JMenu(resourceMap.getString("menu.help")); menuHelp.add(new JMenuItem(actionMap.get(ACTION_CHECK_UPDATES))); menuHelp.add(new JMenuItem(actionMap.get(ACTION_ABOUT))); bar.add(menuFile); bar.add(menuEdit); bar.add(menuView); bar.add(toolsView); bar.add(menuHelp); menuBinding.bind(); return bar; } private JToolBar createToolBar() { ApplicationActionMap actionMap = getActionMap(); JToolBar bar = new JToolBar(); bar.setRollover(true); toolBarMap.clear(); final boolean hideText = !p.getBoolean(PREF_GUI_SHOW_TEXT_IN_TOOLBAR, true); for (String actionName : TOOLBAR) { if (TOOLBAR_SEPARATOR.equals(actionName)) { bar.addSeparator(); } else { AbstractButton bt; if (actionName.startsWith(TOOLBAR_TOGGLE_BUTTON)) { actionName = StringUtils.substring(actionName, TOOLBAR_TOGGLE_BUTTON.length()); bt = new JToggleButton(actionMap.get(actionName)); } else { bt = new JButton(actionMap.get(actionName)); } bt.setFocusable(false); bt.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); bt.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); bt.setHideActionText(hideText); bar.add(bt); toolBarMap.put(actionName, bt); } } return bar; } private ImageProcessor getImageProcessor() { return imageProcessor; } public AShot getApplication() { return application; } MainPanel getMainPanel() { return mainPanel; } JMenuBar getMenuBar() { return menuBar; } StatusBar getStatusBar() { return statusBar; } JToolBar getToolBar() { return toolBar; } ImageEx getLastImage() { return lastImage; } public synchronized void removePropertyChangeListener(String propertyName, PropertyChangeListener listener) { pcs.removePropertyChangeListener(propertyName, listener); } public synchronized void removePropertyChangeListener(PropertyChangeListener listener) { pcs.removePropertyChangeListener(listener); } public synchronized boolean hasListeners(String propertyName) { return pcs.hasListeners(propertyName); } public synchronized PropertyChangeListener[] getPropertyChangeListeners(String propertyName) { return pcs.getPropertyChangeListeners(propertyName); } public synchronized PropertyChangeListener[] getPropertyChangeListeners() { return pcs.getPropertyChangeListeners(); } public synchronized void addPropertyChangeListener(String propertyName, PropertyChangeListener listener) { pcs.addPropertyChangeListener(propertyName, listener); } public synchronized void addPropertyChangeListener(PropertyChangeListener listener) { pcs.addPropertyChangeListener(listener); } public void startDemon() { application.getContext().getTaskService().execute(demon); } public void stopDemon() { logger.trace("stopDemon"); demon.cancel(true); } void addDevice(final String deviceStr) { if (!devices.containsKey(deviceStr)) { try { SwingUtilities.invokeAndWait(new Runnable() { @Override public void run() { JRadioButtonMenuItem item = new JRadioButtonMenuItem(deviceStr); item.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { JRadioButtonMenuItem source = (JRadioButtonMenuItem) e.getSource(); String device = source.getText(); demon.connectTo(device); } }); devicesGroup.add(item); devices.put(deviceStr, item); menuFileDevices.add(item); pcs.firePropertyChange(PROP_DEVICES, null, null); } }); } catch (Exception ignore) { } } } void removeDevice(final String deviceStr) { if (devices.containsKey(deviceStr)) { try { SwingUtilities.invokeAndWait(new Runnable() { @Override public void run() { JRadioButtonMenuItem item = devices.get(deviceStr); devicesGroup.remove(item); devices.remove(item.getText()); menuFileDevices.remove(item); pcs.firePropertyChange(PROP_DEVICES, null, null); } }); } catch (Exception ignore) { } } } void showMain() { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { toolBar.setVisible(true); mainPanel.showMain(); } }); } private Image generateDummyImage() { return application.getContext().getResourceMap().getImageIcon("dummyImage").getImage(); } // Actions: public static final String ACTION_SAVE_SCREENSHOT = "saveScreenshot"; @Action(name = ACTION_SAVE_SCREENSHOT, enabledProperty = PROP_CONNECTED) public void saveScreenshot() { imageSaver.saveImage(lastImage.getValue()); } public static final String ACTION_RECORDING = "recording"; @Action(name = ACTION_RECORDING, enabledProperty = PROP_CONNECTED, selectedProperty = PROP_RECORDING) public void recording() { if (StringUtils.isBlank(p.get(PREF_DEFAULT_FILE_FOLDER, null))) { String f = requestDefaultFolder(); if (StringUtils.isBlank(f)) { setRecording(false); return; } p.put(PREF_DEFAULT_FILE_FOLDER, f); } demon.resetLastImage(); JToggleButton bt = (JToggleButton) toolBarMap.get(ACTION_RECORDING); ResourceMap resourceMap = application.getContext().getResourceMap(Mediator.class); if (isRecording()) { bt.setText(resourceMap.getString("recording.Action.selectedText")); } else { bt.setText(resourceMap.getString("recording.Action.text")); } } public static final String ACTION_OPEN_DESTINATION_FOLDER = "openDestinationFolder"; @Action(name = ACTION_OPEN_DESTINATION_FOLDER) public void openDestinationFolder() { if (Desktop.isDesktopSupported()) { try { Desktop.getDesktop().open(new File(p.get(PREF_DEFAULT_FILE_FOLDER, ""))); } catch (Exception ignore) { } } } public static final String ACTION_COPY_TO_CLIPBOARD = "copyToClipboard"; @Action(name = ACTION_COPY_TO_CLIPBOARD, enabledProperty = PROP_CONNECTED) public void copyToClipboard() { mainPanel.getPresenter().copy(); } public static final String ACTION_OPTIONS = "options"; @Action(name = ACTION_OPTIONS) public void options() { OptionsDialog.showDialog(this); } public static final String ACTION_LANDSCAPE = "landscape"; @Action(name = ACTION_LANDSCAPE, selectedProperty = PROP_LANDSCAPE) public void landscape() { p.putBoolean(PREF_ROTATION_CCW, true); p.putBoolean(PREF_SCREENSHOT_LANDSCAPE, isLandscape()); updateLastImage(); } public static final String ACTION_LANDSCAPE_CW = "landscapeCW"; @Action(name = ACTION_LANDSCAPE_CW, selectedProperty = PROP_LANDSCAPE) public void landscapeCW() { p.putBoolean(PREF_ROTATION_CCW, false); p.putBoolean(PREF_SCREENSHOT_LANDSCAPE, isLandscape()); updateLastImage(); } public static final String ACTION_FULL_SCREEN = "fullScreen"; @Action(name = ACTION_FULL_SCREEN, enabledProperty = PROP_CONNECTED) public void fullScreen() { fullScreenFrame.showFullScreen(); } public static final String ACTION_SIZE_ORIGINAL = "sizeOriginal"; @Action(name = ACTION_SIZE_ORIGINAL) public void sizeOriginal() { setScale(1.0); } public static final String ACTION_SIZE_LARGE = "sizeLarge"; @Action(name = ACTION_SIZE_LARGE) public void sizeLarge() { setScale(1.5); } public static final String ACTION_SIZE_SMALL = "sizeSmall"; @Action(name = ACTION_SIZE_SMALL) public void sizeSmall() { setScale(0.5); } public static final String ACTION_ZOOM_IN = "zoomIn"; @Action(name = ACTION_ZOOM_IN) public void zoomIn() { double scale = imageProcessor.getScale() * 1.1; if (scale > 3.0) scale = 3.0; setScale(scale); } public static final String ACTION_ZOOM_OUT = "zoomOut"; @Action(name = ACTION_ZOOM_OUT) public void zoomOut() { double scale = imageProcessor.getScale() * 0.9090909090909091; if (scale < 0.1) scale = 0.1; setScale(scale); } public static final String ACTION_SIZE_FIT = "sizeFit"; @Action(name = ACTION_SIZE_FIT, selectedProperty = PROP_SCALE_FIT) public void sizeFit() { p.putDouble(PREF_SCREENSHOT_SCALE, 0.0); updateLastImage(); } public static final String ACTION_CHECK_UPDATES = "checkUpdates"; @Action(name = ACTION_CHECK_UPDATES, block = Task.BlockingScope.WINDOW) public Task checkUpdates() { return new UpdateChecker(this); } public static final String ACTION_ABOUT = "about"; @Action(name = ACTION_ABOUT) public void about() { toolBar.setVisible(false); mainPanel.showIntro(); } public static final String ACTION_INSTALL = "install"; @Action(name = ACTION_INSTALL, block = Task.BlockingScope.WINDOW, enabledProperty = PROP_CONNECTED) public Task install() { ResourceMap resourceMap = application.getContext().getResourceMap(Mediator.class); String path = PathRequestDialog.requestFileFor("", resourceMap.getString("dialog.installfile.title"), resourceMap.getString("dialog.installfile.desc")); if (StringUtils.isNotBlank(path)) { return new AppInstaller(this, new File(path)); } else { return null; } } public static final String ACTION_CHANGE_DEFAULT_FOLDER = "changeDefaultFolder"; @Action(name = ACTION_CHANGE_DEFAULT_FOLDER) public void changeDefaultFolder() { ResourceMap resourceMap = application.getContext().getResourceMap(Mediator.class); String folder = PathRequestDialog.requestFolderFor(p.get(PREF_DEFAULT_FILE_FOLDER, null), resourceMap.getString("save.request.title"), resourceMap.getString("save.request.desc")); if (StringUtils.isNotBlank(folder)) { p.put(PREF_DEFAULT_FILE_FOLDER, folder); } } public static final String ACTION_CHANGE_SDK_FOLDER = "changeSdkFolder"; @Action(name = ACTION_CHANGE_SDK_FOLDER) public void changeSdkFolder() { ResourceMap resourceMap = application.getContext().getResourceMap(OptionsDialog.class); String folder = PathRequestDialog.requestFolderFor(p.get(PREF_ANDROID_SDK_PATH, null), resourceMap.getString("sdk.request.title"), resourceMap.getString("sdk.request.desc")); if (StringUtils.isNotBlank(folder)) { if (AndroidSdkHelper.validatePath(folder)) { p.put(PREF_ANDROID_SDK_PATH, folder); } else { application.showErrorMessage("error.sdk"); } } } public static final String ACTION_SHOW_TOOLBAR_LABELS = "showToolbarLables"; @Action(name = ACTION_SHOW_TOOLBAR_LABELS, selectedProperty = PROP_SHOW_TOOLBAR_LABELS) public void showToolbarLables() { boolean state = isShowToolbarLabels(); p.putBoolean(PREF_GUI_SHOW_TEXT_IN_TOOLBAR, state); updateToolbarLabels(!state); } // Properties private String connectedDevice; public static final String PROP_CONNECTED_DEVICE = "connectedDevice"; public String getConnectedDevice() { return connectedDevice; } public void setConnectedDevice(String connectedDevice) { String oldValue = this.connectedDevice; this.connectedDevice = connectedDevice; pcs.firePropertyChange(PROP_CONNECTED_DEVICE, oldValue, connectedDevice); setConnected(connectedDevice != null); } private boolean recording; public static final String PROP_RECORDING = "recording"; public boolean isRecording() { return recording; } public void setRecording(boolean recording) { boolean oldRecording = this.recording; this.recording = recording; pcs.firePropertyChange(PROP_RECORDING, oldRecording, recording); } private boolean autoSave = false; public static final String PROP_AUTO_SAVE = "autoSave"; public boolean isAutoSave() { return autoSave; } public void setAutoSave(boolean autoSave) { boolean oldValue = this.autoSave; this.autoSave = autoSave; pcs.firePropertyChange(PROP_AUTO_SAVE, oldValue, autoSave); } private boolean fullScreen = false; public static final String PROP_FULL_SCREEN = "fullScreen"; public boolean isFullScreen() { return fullScreen; } public void setFullScreen(boolean fullScreen) { boolean oldValue = this.fullScreen; this.fullScreen = fullScreen; pcs.firePropertyChange(PROP_FULL_SCREEN, oldValue, fullScreen); } private boolean saveOriginal = true; public static final String PROP_SAVE_ORIGINAL = "saveOriginal"; public boolean isSaveOriginal() { return saveOriginal; } public void setSaveOriginal(boolean saveOriginal) { boolean oldValue = this.saveOriginal; this.saveOriginal = saveOriginal; pcs.firePropertyChange(PROP_SAVE_ORIGINAL, oldValue, saveOriginal); } private boolean connected = false; public static final String PROP_CONNECTED = "connected"; public boolean isConnected() { return connected; } public void setConnected(boolean connected) { boolean oldValue = this.connected; this.connected = connected; pcs.firePropertyChange(PROP_CONNECTED, oldValue, connected); } public static final String PROP_DEVICES = "devices"; public boolean isDevices() { return !devices.isEmpty(); } private volatile boolean landscape = false; public static final String PROP_LANDSCAPE = "landscape"; public boolean isLandscape() { return landscape; } public void setLandscape(boolean landscape) { boolean oldValue = this.landscape; this.landscape = landscape; pcs.firePropertyChange(PROP_LANDSCAPE, oldValue, landscape); } private boolean scaleFit; public static final String PROP_SCALE_FIT = "scaleFit"; public boolean isScaleFit() { return scaleFit; } public void setScaleFit(boolean scaleFit) { boolean oldScaleFit = this.scaleFit; this.scaleFit = scaleFit; pcs.firePropertyChange(PROP_SCALE_FIT, oldScaleFit, scaleFit); } protected boolean showToolbarLabels = true; public static final String PROP_SHOW_TOOLBAR_LABELS = "showToolbarLabels"; public boolean isShowToolbarLabels() { return showToolbarLabels; } public void setShowToolbarLabels(boolean showToolbarLabels) { boolean oldShowToolbarLabels = this.showToolbarLabels; this.showToolbarLabels = showToolbarLabels; pcs.firePropertyChange(PROP_SHOW_TOOLBAR_LABELS, oldShowToolbarLabels, showToolbarLabels); } // internal methods private void showImage(Image img) { if (presenter != null) presenter.setImage(img); } private void updateLastImage() { if (lastImage != null) { updateImageProcessor(lastImage); showImage(imageProcessor.process(lastImage.getValue())); } } private void setScale(double scale) { setScaleFit(false); getImageProcessor().setScale(scale); p.putDouble(PREF_SCREENSHOT_SCALE, scale); updateLastImage(); } public void setStatus(String key, Object... args) { String string = application.getContext().getResourceMap().getString(key, args); statusBar.setMessage(string); } void executeAction(String actionName) { application.getContext().getActionManager().getActionMap(Mediator.class, this).get(actionName) .actionPerformed(new ActionEvent(this, ActionEvent.ACTION_PERFORMED, null)); } private String requestDefaultFolder() { ResourceMap resourceMap = application.getContext().getResourceMap(OptionsDialog.class); return PathRequestDialog.requestFolderFor(p.get(PREF_DEFAULT_FILE_FOLDER, ""), resourceMap.getString("save.request.title"), resourceMap.getString("save.request.desc")); } private void updateToolbarLabels(boolean state) { for (JComponent bt : toolBarMap.values()) { if (bt instanceof AbstractButton) { ((AbstractButton) bt).setHideActionText(state); } } } // We can provide configuration option for toolbar // Toolbar private static final String TOOLBAR_SEPARATOR = "-----"; private static final String TOOLBAR_TOGGLE_BUTTON = "TOGGLE::"; private static final String[] TOOLBAR = { ACTION_SAVE_SCREENSHOT, TOOLBAR_TOGGLE_BUTTON + ACTION_RECORDING, ACTION_OPEN_DESTINATION_FOLDER, TOOLBAR_SEPARATOR, ACTION_FULL_SCREEN, TOOLBAR_SEPARATOR, ACTION_OPTIONS }; }