Package mindnotes.client.ui

Source Code of mindnotes.client.ui.MindMapWidget

package mindnotes.client.ui;

import static com.google.gwt.dom.client.Style.Unit.PX;
import mindnotes.client.presentation.ActionOptions;
import mindnotes.client.presentation.CloudActionsView;
import mindnotes.client.presentation.MindMapSelectionView;
import mindnotes.client.presentation.MindMapView;
import mindnotes.client.presentation.NodeView;
import mindnotes.client.presentation.ShareOptionsView;
import mindnotes.client.ui.embedded.widgets.EmbeddedObjectWidgetFactory;
import mindnotes.client.ui.resize.ResizeController;

import com.allen_sauer.gwt.dnd.client.DragEndEvent;
import com.allen_sauer.gwt.dnd.client.DragHandler;
import com.allen_sauer.gwt.dnd.client.DragStartEvent;
import com.allen_sauer.gwt.dnd.client.PickupDragController;
import com.allen_sauer.gwt.dnd.client.VetoDragException;
import com.google.gwt.dom.client.NativeEvent;
import com.google.gwt.dom.client.Style;
import com.google.gwt.dom.client.Style.Position;
import com.google.gwt.user.client.Command;
import com.google.gwt.user.client.DeferredCommand;
import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.Event.NativePreviewEvent;
import com.google.gwt.user.client.Event.NativePreviewHandler;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.Window.ClosingEvent;
import com.google.gwt.user.client.Window.ClosingHandler;
import com.google.gwt.user.client.ui.AbsolutePanel;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.PopupPanel.PositionCallback;
import com.google.gwt.user.client.ui.RequiresResize;
import com.google.gwt.user.client.ui.ScrollPanel;
import com.google.gwt.user.client.ui.Widget;

public class MindMapWidget extends Composite implements MindMapView,
    NodeContainer, RequiresResize, PopupContainer, ButtonContainer {

  private ActionButtons _actionButtons;

  private Listener _listener;
  private NodeWidget _rootNode;

  private MindMapSelectionDialog _mindMapSelectionDialog;
  private AbsolutePanel _viewportPanel;
  private ScrollPanel _scrollPanel;
  private CanvasRenderWidget _arrowsWidget;
  private MindNotesUI _window;

  private boolean _layoutValid;

  private MessageBar _messageBar;

  private boolean _holdLayoutUpdates;

  private PickupDragController _dragController;
  private MindMapDropController _dropController;

  private int _ox;
  private int _oy;

  private boolean _holdCentering;
  private InsertMenu _insertMenu;

  private boolean _viewer;

  private ShareOptionsDialog _shareOptionsDialog;

  public MindMapWidget(boolean viewer) {
    _viewer = viewer;

    initArrows();
    initViewport();
    initRootNode(viewer);

    if (!_viewer) {
      initKeyboardShortcuts();
      initActionButtons();
      initContextMenu();
      initDragDrop();

    }
    addNode(_rootNode);

    initWidget(_scrollPanel);

    if (!_viewer) {
      initMindMapSelectionDialog();
    }

    initWindowClosingHandler();
  }

  private void initWindowClosingHandler() {
    Window.addWindowClosingHandler(new ClosingHandler() {

      @Override
      public void onWindowClosing(ClosingEvent event) {
        if (_listener != null && _listener.windowClosing()) {
          event.setMessage("There are unsaved changes in your mind map. Are you sure you want to close this window?");
        } else {
          event.setMessage(null);
        }
      }
    });

  }

  /**
   * @param viewOnly
   *
   */
  private void initRootNode(boolean viewOnly) {
    _rootNode = new NodeWidget();
    _rootNode.setEmbeddedObjectFactory(new EmbeddedObjectWidgetFactory(
        new ResizeController(_viewportPanel), viewOnly));
    _rootNode.setContainer(this);

  }

  /**
   *
   */
  private void initArrows() {
    _arrowsWidget = new CanvasRenderWidget(this);
    _arrowsWidget.setPixelSize(1000, 1000);
  }

  /**
   *
   */
  private void initViewport() {
    _viewportPanel = new AbsolutePanel();
    _viewportPanel.add(_arrowsWidget, 0, 0);

    _scrollPanel = new ScrollPanel(_viewportPanel);
    // _scrollPanel.setPixelSize(600, 500);
    _scrollPanel.setScrollPosition(250);
    _scrollPanel.setHorizontalScrollPosition(250);
    _scrollPanel.setAlwaysShowScrollBars(true);
    _viewportPanel.setPixelSize(1000, 1000);
    // _viewportPanel.addStyleName("checkers-bg");

    // fix scroll panel positioning to let the scroll panel take up the
    // whole parent
    Style style = _scrollPanel.getElement().getStyle();
    style.setPosition(Position.ABSOLUTE);
    style.setLeft(0, PX);
    style.setTop(0, PX);
    style.setRight(0, PX);
    style.setBottom(0, PX);
  }

  /**
   *
   */
  private void initMindMapSelectionDialog() {
    _mindMapSelectionDialog = new MindMapSelectionDialog();
    _mindMapSelectionDialog.setPositionCallback(new PositionCallback() {

      @Override
      public void setPosition(int offsetWidth, int offsetHeight) {
        if (_window == null)
          return;
        int maxLeft = Window.getClientWidth() - offsetWidth - 16;
        int left = _window.cloudBarPanel.loadButton.getAbsoluteLeft();
        int top = _window.cloudBarPanel.getAbsoluteTop()
            + _window.cloudBarPanel.getOffsetHeight();
        if (left > maxLeft)
          left = maxLeft;
        _mindMapSelectionDialog.setPopupPosition(left, top);
      }
    });
  }

  /**
   *
   */
  private void initDragDrop() {
    _dragController = new PickupDragController(_viewportPanel, false);
    _dragController.setBehaviorDragStartSensitivity(40);

    _dropController = new MindMapDropController(this);
    _dragController.registerDropController(_dropController);

    _dragController.addDragHandler(new DragHandler() {

      private NodeWidget _dragged;
      private int _index;
      private NodeWidget _parentNodeWidget;

      @Override
      public void onPreviewDragStart(DragStartEvent event)
          throws VetoDragException {

      }

      @Override
      public void onPreviewDragEnd(DragEndEvent event)
          throws VetoDragException {

      }

      @Override
      public void onDragStart(DragStartEvent event) {
        hideActions();
        holdCentering();
        _dragged = (NodeWidget) event.getContext().draggable;
        _parentNodeWidget = _dragged.getParentNodeWidget();
        _index = _parentNodeWidget.indexOfChild(_dragged);
        _dragged.getParentNodeWidget().removeChild(_dragged);
        _viewportPanel.add(_dragged, 0, 0);
      }

      @Override
      public void onDragEnd(DragEndEvent event) {
        if (event.getContext().finalDropController == null) {
          _viewportPanel.remove(_dragged);
          _parentNodeWidget.addChildAtIndex(_dragged, _index);

        }
        resumeCentering();
        showActions();

      }
    });
  }

  /**
   *
   */
  private void initContextMenu() {
    NodeContextMenu contextMenu = new NodeContextMenu();
    contextMenu.setListener(new NodeContextMenu.Listener() {

      @Override
      public void onMenuPaste() {
        if (_listener != null)
          _listener.pasteGesture();

      }

      @Override
      public void onMenuDelete() {
        if (_listener != null)
          _listener.deleteGesture();

      }

      @Override
      public void onMenuCut() {
        if (_listener != null)
          _listener.cutGesture();
      }

      @Override
      public void onMenuCopy() {
        if (_listener != null)
          _listener.copyGesture();

      }
    });
    _rootNode.setContextMenu(contextMenu);
  }

  /**
   *
   */
  private void initKeyboardShortcuts() {
    Event.addNativePreviewHandler(new NativePreviewHandler() {

      @Override
      public void onPreviewNativeEvent(NativePreviewEvent event) {
        /**
         * Chrome does not fire a 'keypress' event with ctr+c, ctrl+v,
         * ctrl+x (it does for ctrl+z) Firefox does not exhibit this
         * behavior. Oh well.
         */
        if (event.getTypeInt() == Event.ONKEYDOWN) {

          NativeEvent nativeEvent = event.getNativeEvent();

          // hack for Macs to make cmd button behave like ctrl
          // on
          // other platforms
          boolean meta = Window.Navigator.getPlatform().equals(
              "MacIntel") ? nativeEvent.getMetaKey()
              : nativeEvent.getCtrlKey();

          if (_listener != null) {
            _listener.keyboardShortcut(nativeEvent.getKeyCode(),
                meta, nativeEvent.getShiftKey(),
                nativeEvent.getAltKey());
          }
        }

      }
    });
  }

  /**
   *
   */
  private void initActionButtons() {
    _actionButtons = new ActionButtons();

    _actionButtons.setListener(new ActionButtons.Listener() {

      @Override
      public void deleteClicked() {
        if (_listener != null)
          _listener.deleteGesture();
      }

      @Override
      public void addRightClicked() {
        if (_listener != null)
          _listener.addRightGesture();
      }

      @Override
      public void addLeftClicked() {
        if (_listener != null)
          _listener.addLeftGesture();
      }

      @Override
      public void expandClicked() {
        if (_listener != null)
          _listener.expandGesture();
      }

      @Override
      public void addUpClicked() {
        if (_listener != null)
          _listener.addUpGesture();
      }

      @Override
      public void addDownClicked() {
        if (_listener != null)
          _listener.addDownGesture();
      }

      @Override
      public void insertMenuFired(int x, int y) {
        if (_listener != null)
          _listener.insertMenuGesture(x, y);
      }
    });
    _actionButtons.setContainer(this);
    _actionButtons.setNodeContainer(this);
  }

  @Override
  public void showInsertMenu(int x, int y, String text) {
    if (_insertMenu == null) {
      _insertMenu = new InsertMenu();
      _insertMenu.setListener(new InsertMenu.Listener() {

        @Override
        public void imageChosenGesture(String url) {
          if (_listener != null) {
            _listener.imageInsertGesture(url);
            _insertMenu.hide();
          }
        }

        @Override
        public void mapInsertGesture() {
          if (_listener != null) {
            _listener.mapInsertGesture();
            _insertMenu.hide();
          }
        }

        /*@Override
        public void onResize(int offsetWidth, int offsetHeight) {
          int x = _insertMenu.getAbsoluteLeft();
          int y = _insertMenu.getAbsoluteTop();
          int w = _insertMenu.getOffsetWidth();
          int h = _insertMenu.getOffsetHeight();
          if (x + w > Window.getClientWidth()) {
            x = Window.getClientWidth() - w - 30;
          }
          if (y + h > Window.getClientHeight()) {
            y = Window.getClientHeight() - h - 30;
          }
          _insertMenu.setPopupPosition(x, y);
        }*/

        @Override
        public void textInsertGesture() {
          if (_listener != null) {
            _listener.textInsertGesture();
            _insertMenu.hide();
          }
        }
      });
    }
    _insertMenu.performSearches(stripHTML(text));
    // showPopup(null, x, y, _searchMenu);
    _insertMenu.showAt(x, y);

  }

  private native String stripHTML(String text)/*-{
    return text.replace(/<\/?[^>]*>/g, '');
  }-*/;

  @Override
  public NodeView getRootNodeView() {
    return _rootNode;
  }

  @Override
  public int getNodeRelativeTop(NodeWidget node) {
    // TODO maybe those methods could use cached values instead of DOM calls
    return node.getAbsoluteTop() - _viewportPanel.getAbsoluteTop();
  }

  @Override
  public int getNodeRelativeLeft(NodeWidget node) {
    return node.getAbsoluteLeft() - _viewportPanel.getAbsoluteLeft();
  }

  public AbsolutePanel getViewportPanel() {
    return _viewportPanel;
  }

  @Override
  public void showActions(NodeView view, ActionOptions options) {
    _actionButtons.showNextTo((NodeWidget) view, options);
  }

  public void showActions() {
    _actionButtons.show();
  }

  @Override
  public void setListener(Listener l) {
    _listener = l;
  }

  @Override
  public void hideActions() {
    _actionButtons.hideButtons();
  }

  @Override
  public void onResize() {
    _layoutValid = false;
    updateLayout();
  }

  public void setTitle(String title) {
    if (_window != null) {
      _window.setMindMapTitle(title);
    }
  }

  /**
   * Also called by arrowmaker
   */
  public void onClick() {
    // let the presenter decide what to do
    if (_listener != null)
      _listener.clickGesture();
  }

  @Override
  public void removeNode(NodeWidget node) {
    _viewportPanel.remove(node);
    for (NodeWidget child : node.getNodeChildren()) {
      removeNode(child);
    }
  }

  @Override
  public void addNode(NodeWidget node) {

    _viewportPanel.add(node, 0, 0);
    for (NodeWidget child : node.getNodeChildren()) {
      addNode(child);
    }
    if (node.getParentNodeWidget() != null && _dragController != null) {
      _dragController.makeDraggable(node, node.getContentWidget());
    }
  }

  public void updateLayout() {
    if (_layoutValid)
      return;
    NodeLayout.doLayout(_rootNode);
    // use top level node's suggested width and height as a suggested size
    // for the whole tree.
    Box bounds = _rootNode.getBranchBounds();

    // suggest a new size for the viewport panel
    int paneWidth = _scrollPanel.getElement().getClientWidth();
    int paneHeight = _scrollPanel.getElement().getClientHeight();

    int viewportWidth = Math.max(paneWidth, bounds.w + 100);
    int viewportHeight = Math.max(paneHeight, bounds.h + 100);

    _viewportPanel.setPixelSize(viewportWidth, viewportHeight);
    _arrowsWidget.setCanvasSize(viewportWidth, viewportHeight);

    if (!_holdCentering) {
      _ox = -bounds.x + (viewportWidth - bounds.w) / 2;
      _oy = -bounds.y + (viewportHeight - bounds.h) / 2;
    }
    setBranchPositions(_rootNode, _ox, _oy);

    _arrowsWidget.render(_ox, _oy);

    if (_actionButtons != null)
      _actionButtons.updateButtonLayout();
    _layoutValid = true;

  }

  private void holdCentering() {
    _holdCentering = true;
  }

  private void resumeCentering() {
    _holdCentering = false;
  }

  public int getLayoutOffsetX() {
    return _ox;
  }

  public int getLayoutOffsetY() {
    return _oy;
  }

  private void setBranchPositions(NodeWidget node, int x, int y) {
    // TODO optimize by not updating every widget
    _viewportPanel.setWidgetPosition(node, x, y);
    for (LayoutTreeElement child : node.getLayoutChildren()) {
      if (child instanceof NodeWidget) {
        setBranchPositions((NodeWidget) child, x + child.getOffsetX(),
            y + child.getOffsetY());
      }
    }
  }

  @Override
  public void onNodeLayoutInvalidated(NodeWidget node) {
    _layoutValid = false;
    if (!_holdLayoutUpdates) {
      updateLayout();
    }
  }

  public NodeWidget getRootNodeWidget() {
    return _rootNode;
  }

  @Override
  public MindMapSelectionView getMindMapSelectionView() {

    return _mindMapSelectionDialog;
  }

  @Override
  public String askForDocumentTitle() {
    return askForDocumentTitle("Untitled map");

  }

  public String askForDocumentTitle(String oldTitle) {
    // TODO make this a neat DialogBox
    final String title = Window
        .prompt("Enter the title of your mind map:\n(A proper dialog is on the way)",
            oldTitle);

    DeferredCommand.addCommand(new Command() {

      @Override
      public void execute() {
        if (_listener != null) {
          _listener.titleChanged(title);
        }

      }
    });

    return title;
  }

  public void setEditorWindow(MindNotesUI window) {
    _window = window;
    _window.cloudBarPanel.setListener(new CloudActionsView.Listener() {

      @Override
      public void newClicked() {
        if (_listener != null) {
          _listener.newMapGesture();
        }
      }

      @Override
      public void loadFromCloudClicked() {
        if (_listener != null) {
          _listener.loadFromCloudGesture();
        }
      }

      @Override
      public void saveToCloudClicked() {
        if (_listener != null) {
          _listener.saveToCloudGesture();
        }
      }

      @Override
      public void saveLocalClicked() {
        if (_listener != null) {
          _listener.saveLocalGesture();
        }
      }

      @Override
      public void shareClicked() {
        if (_listener != null) {
          _listener.shareClickGesture();
        }
      }

      @Override
      public void tryAgainClicked() {
        if (_listener != null) {
          _listener.reconnectGesture();
        }
      }

    });
  }

  @Override
  public void showPopup(Widget anchor, int left, int top, Widget popup) {
    int anchorOffsetX = anchor == null ? 0 : anchor.getAbsoluteLeft();
    int anchorOffsetY = anchor == null ? 0 : anchor.getAbsoluteTop();
    int x = anchorOffsetX - _viewportPanel.getAbsoluteLeft() + left;
    int y = anchorOffsetY - _viewportPanel.getAbsoluteTop() + top;
    _viewportPanel.add(popup, x, y);
    int dw = x + popup.getOffsetWidth();
    int dh = y + popup.getOffsetHeight();
    if (dw > _viewportPanel.getOffsetWidth()
        || dh > _viewportPanel.getOffsetHeight()) {
      _viewportPanel.setPixelSize(dw, dh);
    }
    popup.setVisible(true);

  }

  @Override
  public void addButton(Widget widget) {
    _viewportPanel.add(widget);

  }

  @Override
  public void setButtonPosition(Widget button, int x, int y) {
    _viewportPanel.setWidgetPosition(button, x, y);

  }

  @Override
  public void showMessage(String string) {
    if (_messageBar == null) {
      _messageBar = new MessageBar();
    }
    _messageBar.showMessage(string);
  }

  @Override
  public void holdLayout() {
    _holdLayoutUpdates = true;
  }

  @Override
  public void resumeLayout() {
    _holdLayoutUpdates = false;
    if (!_layoutValid) {
      updateLayout();
    }
  }

  public GhostNode getGhostNode() {
    if (_dropController != null)
      return _dropController.getGhostNode();
    else
      return null;

  }

  @Override
  public int getRelativeTop(Widget button) {
    return button.getAbsoluteTop() - _viewportPanel.getAbsoluteTop();
  }

  @Override
  public int getRelativeLeft(Widget button) {
    return button.getAbsoluteLeft() - _viewportPanel.getAbsoluteLeft();
  }

  @Override
  public ShareOptionsView showShareDialog() {
    if (_shareOptionsDialog == null) {
      _shareOptionsDialog = new ShareOptionsDialog();
    }
    DeferredCommand.addCommand(new Command() {

      @Override
      public void execute() {
        _shareOptionsDialog
            .setPopupPositionAndShow(new PositionCallback() {

              @Override
              public void setPosition(int offsetWidth,
                  int offsetHeight) {
                int x = _window.cloudBarPanel.shareButton
                    .getAbsoluteLeft();
                int y = _window.cloudBarPanel.getAbsoluteTop()
                    + _window.cloudBarPanel
                        .getOffsetHeight();
                if (x + offsetWidth > Window.getClientWidth()) {
                  x -= offsetWidth
                      - _window.cloudBarPanel.shareButton
                          .getOffsetWidth();
                }
                _shareOptionsDialog.setPopupPosition(x, y);
              }
            });
      }
    });

    return _shareOptionsDialog;
  }

  @Override
  public CloudActionsView getCloudActionsView() {
    return _window.cloudBarPanel;
  }
}
TOP

Related Classes of mindnotes.client.ui.MindMapWidget

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.