Package com.google.gdt.eclipse.designer.mobile.preferences.device

Source Code of com.google.gdt.eclipse.designer.mobile.preferences.device.DevicesPreferencePage

/*******************************************************************************
* Copyright 2011 Google Inc. All Rights Reserved.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*******************************************************************************/
package com.google.gdt.eclipse.designer.mobile.preferences.device;

import com.google.common.collect.Lists;
import com.google.gdt.eclipse.designer.mobile.Activator;
import com.google.gdt.eclipse.designer.mobile.device.DeviceManager;
import com.google.gdt.eclipse.designer.mobile.device.command.CategoryAddCommand;
import com.google.gdt.eclipse.designer.mobile.device.command.CategoryMoveCommand;
import com.google.gdt.eclipse.designer.mobile.device.command.CategoryNameCommand;
import com.google.gdt.eclipse.designer.mobile.device.command.CategoryRemoveCommand;
import com.google.gdt.eclipse.designer.mobile.device.command.Command;
import com.google.gdt.eclipse.designer.mobile.device.command.DeviceMoveCommand;
import com.google.gdt.eclipse.designer.mobile.device.command.DeviceRemoveCommand;
import com.google.gdt.eclipse.designer.mobile.device.command.ElementVisibilityCommand;
import com.google.gdt.eclipse.designer.mobile.device.model.AbstractDeviceInfo;
import com.google.gdt.eclipse.designer.mobile.device.model.CategoryInfo;
import com.google.gdt.eclipse.designer.mobile.device.model.DeviceInfo;

import org.eclipse.wb.internal.core.utils.GenericsUtils;
import org.eclipse.wb.internal.core.utils.check.Assert;
import org.eclipse.wb.internal.core.utils.ui.EmptyTransfer;
import org.eclipse.wb.internal.core.utils.ui.GridDataFactory;
import org.eclipse.wb.internal.core.utils.ui.GridLayoutFactory;

import org.eclipse.jface.dialogs.InputDialog;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.preference.PreferencePage;
import org.eclipse.jface.viewers.CheckStateChangedEvent;
import org.eclipse.jface.viewers.CheckboxTreeViewer;
import org.eclipse.jface.viewers.DoubleClickEvent;
import org.eclipse.jface.viewers.ICheckStateListener;
import org.eclipse.jface.viewers.IDoubleClickListener;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.viewers.ViewerDropAdapter;
import org.eclipse.jface.window.Window;
import org.eclipse.swt.SWT;
import org.eclipse.swt.dnd.DND;
import org.eclipse.swt.dnd.DragSourceEvent;
import org.eclipse.swt.dnd.DragSourceListener;
import org.eclipse.swt.dnd.DropTargetEvent;
import org.eclipse.swt.dnd.Transfer;
import org.eclipse.swt.dnd.TransferData;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Item;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.ui.IWorkbench;
import org.eclipse.ui.IWorkbenchPreferencePage;

import org.apache.commons.lang.ArrayUtils;

import java.util.List;

/**
* {@link PreferencePage} for configuring {@link DeviceManager}.
*
* @author scheglov_ke
* @coverage gwt.mobile.device
*/
public final class DevicesPreferencePage extends PreferencePage implements IWorkbenchPreferencePage {
  ////////////////////////////////////////////////////////////////////////////
  //
  // Constructor
  //
  ////////////////////////////////////////////////////////////////////////////
  public DevicesPreferencePage() {
    setPreferenceStore(Activator.getDefault().getPreferenceStore());
  }

  ////////////////////////////////////////////////////////////////////////////
  //
  // IWorkbenchPreferencePage
  //
  ////////////////////////////////////////////////////////////////////////////
  public void init(IWorkbench workbench) {
  }

  ////////////////////////////////////////////////////////////////////////////
  //
  // GUI
  //
  ////////////////////////////////////////////////////////////////////////////
  private static final Image IMAGE_CATEGORY = Activator.getImage("device/category.png");
  private static final Image IMAGE_DEVICE = Activator.getImage("device/device.png");
  private CheckboxTreeViewer m_viewer;

  @Override
  protected Control createContents(Composite parent) {
    Composite container = new Composite(parent, SWT.NONE);
    GridLayoutFactory.create(container).columns(3);
    //
    createViewer(container);
    createButtonsComposite(container);
    createPreviewComposite(container);
    //
    return container;
  }

  ////////////////////////////////////////////////////////////////////////////
  //
  // GUI: viewer
  //
  ////////////////////////////////////////////////////////////////////////////
  /**
   * Creates {@link CheckboxTreeViewer} for categories/devices.
   */
  private void createViewer(Composite parent) {
    m_viewer = new CheckboxTreeViewer(parent, SWT.BORDER | SWT.MULTI);
    GridDataFactory.create(m_viewer.getTree()).grab().fill().hintC(50, 20);
    // content provider
    m_viewer.setContentProvider(new ITreeContentProvider() {
      public Object[] getElements(Object inputElement) {
        return DeviceManager.getCategories().toArray();
      }

      public Object[] getChildren(Object parentElement) {
        if (parentElement instanceof CategoryInfo) {
          return ((CategoryInfo) parentElement).getDevices().toArray();
        }
        return ArrayUtils.EMPTY_OBJECT_ARRAY;
      }

      public boolean hasChildren(Object element) {
        return getChildren(element).length != 0;
      }

      public Object getParent(Object element) {
        if (element instanceof DeviceInfo) {
          return ((DeviceInfo) element).getCategory();
        }
        return null;
      }

      public void dispose() {
      }

      public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
      }
    });
    // label provider
    m_viewer.setLabelProvider(new LabelProvider() {
      @Override
      public Image getImage(Object element) {
        if (element instanceof CategoryInfo) {
          return IMAGE_CATEGORY;
        }
        return IMAGE_DEVICE;
      }

      @Override
      public String getText(Object element) {
        if (element instanceof CategoryInfo) {
          CategoryInfo category = (CategoryInfo) element;
          return category.getName();
        } else if (element instanceof DeviceInfo) {
          DeviceInfo device = (DeviceInfo) element;
          return device.getName()
              + "     -     "
              + device.getDisplayBounds().width
              + "x"
              + device.getDisplayBounds().height;
        }
        return null;
      }
    });
    // set input
    m_viewer.setInput(this);
    refreshViewer();
    refreshViewChecks();
    // listeners
    m_viewer.addCheckStateListener(new ICheckStateListener() {
      public void checkStateChanged(CheckStateChangedEvent event) {
        AbstractDeviceInfo element = (AbstractDeviceInfo) event.getElement();
        commands_add(new ElementVisibilityCommand(element, event.getChecked()));
      }
    });
    m_viewer.addSelectionChangedListener(new ISelectionChangedListener() {
      public void selectionChanged(SelectionChangedEvent event) {
        updateButtons();
        updatePreview();
      }
    });
    m_viewer.addDoubleClickListener(new IDoubleClickListener() {
      public void doubleClick(DoubleClickEvent event) {
        if (m_editButton.isEnabled()) {
          onEdit();
        }
      }
    });
    // DND
    configureDND();
  }

  /**
   * Shows actual state of devices in {@link #m_viewer}.
   */
  private void refreshViewer() {
    m_viewer.refresh();
  }

  /**
   * Shows state of "visible" state. Note that this method is slow, in particular
   * {@link CheckboxTreeViewer#setCheckedElements(Object[])}, so should be used carefully.
   */
  private void refreshViewChecks() {
    List<Object> visibleElements = Lists.newArrayList();
    for (CategoryInfo category : DeviceManager.getCategories()) {
      if (category.isVisible()) {
        visibleElements.add(category);
      }
      for (DeviceInfo device : category.getDevices()) {
        if (device.isVisible()) {
          visibleElements.add(device);
        }
      }
    }
    // update viewer
    m_viewer.setCheckedElements(visibleElements.toArray());
  }

  /**
   * @return the {@link List} of selected elements.
   */
  @SuppressWarnings("unchecked")
  private List<Object> getSelectedElements() {
    IStructuredSelection selection = (IStructuredSelection) m_viewer.getSelection();
    return selection.toList();
  }

  ////////////////////////////////////////////////////////////////////////////
  //
  // GUI: buttons
  //
  ////////////////////////////////////////////////////////////////////////////
  private Button m_addEntryButton;
  private Button m_editButton;
  private Button m_removeButton;
  private Button m_moveUpButton;
  private Button m_moveDownButton;

  /**
   * Creates {@link Composite} with buttons to modify devices.
   */
  private void createButtonsComposite(Composite parent) {
    Composite buttonsComposite = new Composite(parent, SWT.NONE);
    GridDataFactory.create(buttonsComposite).grabV().fill();
    GridLayoutFactory.create(buttonsComposite).noMargins();
    //
    createButton(buttonsComposite, "Add Category...", new Listener() {
      public void handleEvent(Event event) {
        onAddCategory();
      }
    });
    m_addEntryButton = createButton(buttonsComposite, "Add device...", new Listener() {
      public void handleEvent(Event event) {
        onAddDevice();
      }
    });
    //
    createButtonSeparator(buttonsComposite);
    m_editButton = createButton(buttonsComposite, "Edit...", new Listener() {
      public void handleEvent(Event event) {
        onEdit();
      }
    });
    m_removeButton = createButton(buttonsComposite, "Remove...", new Listener() {
      public void handleEvent(Event event) {
        onRemove();
      }
    });
    //
    createButtonSeparator(buttonsComposite);
    m_moveUpButton = createButton(buttonsComposite, "Up", new Listener() {
      public void handleEvent(Event event) {
        onMove(-1);
      }
    });
    m_moveDownButton = createButton(buttonsComposite, "Down", new Listener() {
      public void handleEvent(Event event) {
        onMove(+2);
      }
    });
    //
    createButtonSeparator(buttonsComposite);
    createButton(buttonsComposite, "Collapse All", new Listener() {
      public void handleEvent(Event event) {
        m_viewer.collapseAll();
      }
    });
    createButton(buttonsComposite, "Expand All", new Listener() {
      public void handleEvent(Event event) {
        m_viewer.expandAll();
      }
    });
    // update buttons first time
    updateButtons();
  }

  /**
   * Creates {@link Button} with given text and {@link SWT#Selection} listener.
   */
  private static Button createButton(Composite parent, String text, Listener selectionListener) {
    Button button = new Button(parent, SWT.NONE);
    GridDataFactory.create(button).grabH().fillH();
    button.setText(text);
    button.addListener(SWT.Selection, selectionListener);
    return button;
  }

  /**
   * Creates separator between buttons on vertical buttons bar.
   */
  private static void createButtonSeparator(Composite parent) {
    Label separator = new Label(parent, SWT.NONE);
    GridDataFactory.create(separator).hintV(7);
  }

  /**
   * Updates buttons according to selection in {@link #m_viewer}.
   */
  private void updateButtons() {
    List<Object> selection = getSelectedElements();
    m_addEntryButton.setEnabled(!selection.isEmpty());
    m_editButton.setEnabled(selection.size() == 1);
    m_removeButton.setEnabled(!selection.isEmpty());
    // move up/down
    List<CategoryInfo> categories = DeviceManager.getCategories();
    {
      boolean upEnabled = !selection.isEmpty();
      boolean downEnabled = !selection.isEmpty();
      for (Object element : selection) {
        if (element instanceof CategoryInfo) {
          upEnabled &= categories.indexOf(element) != 0;
          downEnabled &= categories.indexOf(element) != categories.size() - 1;
        } else if (element instanceof DeviceInfo) {
          DeviceInfo device = (DeviceInfo) element;
          List<DeviceInfo> devices = device.getCategory().getDevices();
          m_editButton.setEnabled(m_editButton.isEnabled() && !device.isContributed());
          upEnabled &= devices.indexOf(device) != 0;
          downEnabled &= devices.indexOf(device) != devices.size() - 1;
        }
      }
      m_moveUpButton.setEnabled(upEnabled);
      m_moveDownButton.setEnabled(downEnabled);
    }
  }

  ////////////////////////////////////////////////////////////////////////////
  //
  // GUI: preview
  //
  ////////////////////////////////////////////////////////////////////////////
  private DevicePreviewCanvas m_previewCanvas;

  /**
   * Creates {@link DevicePreviewCanvas} for preview selected {@link DeviceInfo}.
   */
  private void createPreviewComposite(Composite parent) {
    m_previewCanvas = new DevicePreviewCanvas(parent, SWT.NONE);
    GridDataFactory.create(m_previewCanvas).fill().hintH(150);
  }

  /**
   * Shows selected {@link DeviceInfo} in preview.
   */
  private void updatePreview() {
    List<Object> selection = getSelectedElements();
    if (selection.size() == 1 && selection.get(0) instanceof DeviceInfo) {
      DeviceInfo device = (DeviceInfo) selection.get(0);
      m_previewCanvas.setDevice(device);
    } else {
      m_previewCanvas.setDevice(null);
    }
  }

  ////////////////////////////////////////////////////////////////////////////
  //
  // Operations
  //
  ////////////////////////////////////////////////////////////////////////////
  /**
   * Edits device element.
   */
  private void onEdit() {
    Object element = getSelectedElements().get(0);
    if (element instanceof CategoryInfo) {
      CategoryInfo category = (CategoryInfo) element;
      InputDialog inputDialog =
          new InputDialog(getShell(),
              "Category",
              "Enter new category name:",
              category.getName(),
              null);
      // execute dialog
      if (inputDialog.open() == Window.OK) {
        commands_add(new CategoryNameCommand(category, inputDialog.getValue()));
      }
    } else if (element instanceof DeviceInfo) {
      DeviceInfo device = (DeviceInfo) element;
      DeviceEditDialog dialog = new DeviceEditDialog(device);
      // execute dialog
      if (dialog.open() == Window.OK) {
        commands_add(dialog.getCommand());
      }
    }
  }

  /**
   * Removes selected {@link CategoryInfo} or {@link DeviceInfo}.
   */
  private void onRemove() {
    List<Object> selection = getSelectedElements();
    if (MessageDialog.openConfirm(getShell(), "Confirm", "Are you sure you want to remove "
        + selection.size()
        + " selected element(s)?")) {
      for (Object element : selection) {
        if (element instanceof CategoryInfo) {
          commands_add(new CategoryRemoveCommand((CategoryInfo) element));
        } else if (element instanceof DeviceInfo) {
          commands_add(new DeviceRemoveCommand((DeviceInfo) element));
        }
      }
      refreshViewer();
    }
  }

  /**
   * Adds new {@link CategoryInfo}.
   */
  private void onAddCategory() {
    InputDialog inputDialog =
        new InputDialog(getShell(), "New category", "Enter new category name:", "", null);
    if (inputDialog.open() == Window.OK) {
      commands_add(new CategoryAddCommand("category_" + System.currentTimeMillis(),
          inputDialog.getValue()));
    }
  }

  /**
   * Adds new {@link DeviceInfo}.
   */
  private void onAddDevice() {
    final CategoryInfo targetCategory;
    {
      Object element = getSelectedElements().get(0);
      if (element instanceof CategoryInfo) {
        targetCategory = (CategoryInfo) element;
      } else if (element instanceof DeviceInfo) {
        targetCategory = ((DeviceInfo) element).getCategory();
      } else {
        return;
      }
    }
    // open dialog
    DeviceAddDialog deviceAddDialog = new DeviceAddDialog();
    if (deviceAddDialog.open() == Window.OK) {
      commands_add(deviceAddDialog.getCommand(targetCategory));
    }
  }

  /**
   * Moves selected elements up/down.
   */
  private void onMove(int delta) {
    m_viewer.getTree().setRedraw(false);
    try {
      for (Object element : getSelectedElements()) {
        if (element instanceof CategoryInfo) {
          CategoryInfo category = (CategoryInfo) element;
          List<CategoryInfo> categories = DeviceManager.getCategories();
          int index = categories.indexOf(element);
          int targetIndex = index + delta;
          CategoryInfo nextCategory =
              targetIndex < categories.size() ? (CategoryInfo) categories.get(targetIndex) : null;
          commands_add(new CategoryMoveCommand(category, nextCategory));
        } else if (element instanceof DeviceInfo) {
          DeviceInfo device = (DeviceInfo) element;
          CategoryInfo category = device.getCategory();
          List<DeviceInfo> devices = category.getDevices();
          int index = devices.indexOf(device);
          if (index + delta < devices.size()) {
            commands_add(new DeviceMoveCommand(device, category, devices.get(index + delta)));
          } else {
            commands_add(new DeviceMoveCommand(device, category, null));
          }
        }
      }
      refreshViewer();
      updateButtons();
    } finally {
      m_viewer.getTree().setRedraw(true);
    }
  }

  ////////////////////////////////////////////////////////////////////////////
  //
  // DND
  //
  ////////////////////////////////////////////////////////////////////////////
  private List<Object> m_dragElements;
  private boolean m_dragCategory;

  /**
   * Configures DND in {@link #m_viewer}.
   */
  private void configureDND() {
    Transfer[] transfers = new Transfer[]{EmptyTransfer.INSTANCE};
    m_viewer.addDragSupport(DND.DROP_MOVE, transfers, new DragSourceListener() {
      public void dragStart(DragSourceEvent event) {
        m_dragElements = getSelectedElements();
        m_dragCategory = m_dragElements.get(0) instanceof CategoryInfo;
        // check that we drag only categories or only entries
        for (Object element : m_dragElements) {
          if (m_dragCategory != element instanceof CategoryInfo) {
            event.doit = false;
          }
        }
      }

      public void dragSetData(DragSourceEvent event) {
      }

      public void dragFinished(DragSourceEvent event) {
      }
    });
    ViewerDropAdapter dropAdapter = new ViewerDropAdapter(m_viewer) {
      @Override
      protected int determineLocation(DropTargetEvent event) {
        if (event.item instanceof Item) {
          Item item = (Item) event.item;
          Point coordinates = m_viewer.getControl().toControl(event.x, event.y);
          Rectangle bounds = getBounds(item);
          // when drag device, relation with category can be only ON
          if (!m_dragCategory && determineTarget(event) instanceof CategoryInfo) {
            return LOCATION_ON;
          }
          // in all other cases, drop before/after
          return coordinates.y < bounds.y + bounds.height / 2 ? LOCATION_BEFORE : LOCATION_AFTER;
        }
        return LOCATION_NONE;
      }

      @Override
      public boolean validateDrop(Object target, int operation, TransferData transferType) {
        // category can be dragged only relative other category
        if (m_dragCategory) {
          return target instanceof CategoryInfo;
        }
        // all other cases are valid
        return true;
      }

      @Override
      public boolean performDrop(Object data) {
        Object target = getCurrentTarget();
        int location = getCurrentLocation();
        if (m_dragCategory) {
          Assert.instanceOf(CategoryInfo.class, target);
          Assert.isTrue(location == LOCATION_BEFORE || location == LOCATION_AFTER);
          // prepare next category
          CategoryInfo nextCategory;
          {
            List<CategoryInfo> categories = DeviceManager.getCategories();
            int index = categories.indexOf(target);
            if (location == LOCATION_BEFORE) {
              nextCategory = categories.get(index);
            } else {
              nextCategory = GenericsUtils.getNextOrNull(categories, index);
            }
          }
          // add commands
          for (Object element : m_dragElements) {
            CategoryInfo category = (CategoryInfo) element;
            commands_add(new CategoryMoveCommand(category, nextCategory));
          }
        } else if (target instanceof CategoryInfo) {
          Assert.isTrue(location == LOCATION_ON);
          CategoryInfo targetCategory = (CategoryInfo) target;
          for (Object element : m_dragElements) {
            DeviceInfo device = (DeviceInfo) element;
            commands_add(new DeviceMoveCommand(device, targetCategory, null));
          }
        } else {
          DeviceInfo targetDevice = (DeviceInfo) target;
          CategoryInfo targetCategory = targetDevice.getCategory();
          // prepare next device
          DeviceInfo nextDevice;
          {
            List<DeviceInfo> entries = targetCategory.getDevices();
            int index = entries.indexOf(targetDevice);
            if (location == LOCATION_BEFORE) {
              nextDevice = entries.get(index);
            } else {
              nextDevice = GenericsUtils.getNextOrNull(entries, index);
            }
          }
          // add commands
          for (Object element : m_dragElements) {
            DeviceInfo device = (DeviceInfo) element;
            commands_add(new DeviceMoveCommand(device, targetCategory, nextDevice));
          }
        }
        // refresh viewer to show result of applying commands
        refreshViewer();
        return true;
      }
    };
    dropAdapter.setScrollExpandEnabled(false);
    m_viewer.addDropSupport(DND.DROP_MOVE, transfers, dropAdapter);
  }

  ////////////////////////////////////////////////////////////////////////////
  //
  // Commands
  //
  ////////////////////////////////////////////////////////////////////////////
  /**
   * Executes new {@link Command} and updates {@link #m_viewer} accordingly.
   */
  private void commands_add(Command command) {
    DeviceManager.commandsAdd(command);
    refreshViewer();
  }

  ////////////////////////////////////////////////////////////////////////////
  //
  // State
  //
  ////////////////////////////////////////////////////////////////////////////
  @Override
  public boolean performOk() {
    // write all executed commands
    DeviceManager.commandsWrite();
    return true;
  }

  @Override
  public boolean performCancel() {
    // don't save commands, force reload to undo executed commands
    DeviceManager.forceReload();
    return super.performCancel();
  }

  @Override
  protected void performDefaults() {
    super.performDefaults();
    // remove all commands
    DeviceManager.resetToDefaults();
    // show new state
    refreshViewer();
  }
}
TOP

Related Classes of com.google.gdt.eclipse.designer.mobile.preferences.device.DevicesPreferencePage

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.