Beispiel #1
0
  private void manageChunkIcons(AceEditorNative editor) {
    Element container = editor.getContainer();
    if (container == null) return;

    Element[] icons =
        DomUtils.getElementsByClassName(container, ThemeStyles.INSTANCE.inlineChunkToolbar());

    for (Element icon : icons) icon.removeFromParent();

    if (!uiPrefs_.showInlineToolbarForRCodeChunks().getValue()) return;

    if (!shouldDisplayIcons(editor)) return;

    Element[] chunkStarts = DomUtils.getElementsByClassName("rstudio_chunk_start ace_start");

    for (int i = 0; i < chunkStarts.length; i++) {
      Element el = chunkStarts[i];

      if (isPseudoMarker(el)) continue;

      if (!isRunnableChunk(el, editor)) continue;

      if (!DomUtils.isVisibleVert(container, el)) continue;

      if (el.getChildCount() > 0) el.removeAllChildren();

      addToolbar(el, isSetupChunk(el, editor), editor);
    }
  }
Beispiel #2
0
 public void scrollToCursor(ScrollPanel scrollPanel, int paddingVert, int paddingHoriz) {
   DomUtils.ensureVisibleVert(
       scrollPanel.getElement(),
       widget_.getEditor().getRenderer().getCursorElement(),
       paddingVert);
   DomUtils.ensureVisibleHoriz(
       scrollPanel.getElement(),
       widget_.getEditor().getRenderer().getCursorElement(),
       paddingHoriz,
       paddingHoriz,
       false);
 }
Beispiel #3
0
  public void showModal() {
    if (mainWidget_ == null) {
      mainWidget_ = createMainWidget();

      // get the main widget to line up with the right edge of the buttons.
      mainWidget_.getElement().getStyle().setMarginRight(3, Unit.PX);

      mainPanel_.insert(mainWidget_, 0);
    }

    originallyActiveElement_ = DomUtils.getActiveElement();
    if (originallyActiveElement_ != null) originallyActiveElement_.blur();

    // position the dialog
    positionAndShowDialog();

    // defer shown notification to allow all elements to render
    // before attempting to interact w/ them programatically (e.g. setFocus)
    Timer timer =
        new Timer() {
          public void run() {
            onDialogShown();
          }
        };
    timer.schedule(100);
  }
 @Override
 public void ensureSelectedRowIsVisible() {
   ArrayList<TableRowElement> rows = table_.getSelectedRows();
   if (rows.size() > 0) {
     DomUtils.ensureVisibleVert(scrollPanel_.getElement(), rows.get(0), 20);
   }
 }
Beispiel #5
0
    public void onClick(ClickEvent event) {
      // If clicking on the input panel already, stop propagation.
      if (event.getSource() == input_) {
        event.stopPropagation();
        return;
      }

      // Don't drive focus to the input unless there is no selection.
      // Otherwise it would interfere with the ability to select stuff
      // from the output buffer for copying to the clipboard.
      // (BUG: DomUtils.selectionExists() doesn't work in a timely
      // fashion on IE8.)
      if (!DomUtils.selectionExists() && isInputOnscreen()) {
        input_.setFocus(true);
        DomUtils.collapseSelection(false);
      }
    }
Beispiel #6
0
  private boolean trimExcess() {
    if (maxLines_ <= 0) return false; // No limit in effect

    int linesToTrim = lines_ - maxLines_;
    if (linesToTrim > 0) {
      lines_ -= DomUtils.trimLines(output_.getElement(), lines_ - maxLines_);
      return true;
    }

    return false;
  }
 private Element getTabBarElement() {
   return (Element)
       DomUtils.findNode(
           getElement(),
           true,
           false,
           new NodePredicate() {
             public boolean test(Node n) {
               if (n.getNodeType() != Node.ELEMENT_NODE) return false;
               return ((Element) n).getClassName().contains("gwt-TabLayoutPanelTabs");
             }
           });
 }
    private void commitPosition(int pos) {
      lastElementX_ = pos;

      // check to see if we're overlapping with another tab
      for (int i = 0; i < dragTabsHost_.getChildCount(); i++) {
        // skip non-element DOM nodes
        Node node = dragTabsHost_.getChild(i);
        if (node.getNodeType() != Node.ELEMENT_NODE) {
          continue;
        }

        // skip the current candidate (no point in testing it for swap)
        if (i == candidatePos_) {
          continue;
        }

        // skip the element we're dragging and elements that are not tabs
        Element ele = (Element) node;
        if (ele == dragElement_ || ele.getClassName().indexOf("gwt-TabLayoutPanelTab") < 0) {
          continue;
        }

        int left = DomUtils.leftRelativeTo(dragTabsHost_, ele);
        int right = left + ele.getClientWidth();
        int minOverlap = Math.min(initDragWidth_ / 2, ele.getClientWidth() / 2);

        // a little complicated: compute the number of overlapping pixels
        // with this element; if the overlap is more than half of our width
        // (or the width of the candidate), it's swapping time
        if (Math.min(lastElementX_ + initDragWidth_, right) - Math.max(lastElementX_, left)
            >= minOverlap) {
          dragTabsHost_.removeChild(dragPlaceholder_);
          if (candidatePos_ > i) {
            dragTabsHost_.insertBefore(dragPlaceholder_, ele);
          } else {
            dragTabsHost_.insertAfter(dragPlaceholder_, ele);
          }
          candidatePos_ = i;

          // account for the extra element when moving to the right of the
          // original location
          if (dragElement_ != null && startPos_ != null) {
            destPos_ = startPos_ <= candidatePos_ ? candidatePos_ - 1 : candidatePos_;
          } else {
            destPos_ = candidatePos_;
          }
        }
      }
    }
Beispiel #9
0
  private void display(Widget panel, Element underlyingMarker) {
    // Bail if the underlying marker isn't wide enough
    if (underlyingMarker.getOffsetWidth() < 250) return;

    // Get the 'virtual' parent -- this is the Ace scroller that houses all
    // of the Ace content, where we want our icons to live. We need them
    // to live here so that they properly hide when the user scrolls and
    // e.g. markers are only partially visible.
    Element virtualParent = DomUtils.getParent(underlyingMarker, 3);

    // We'd prefer to use 'getOffsetTop()' here, but that seems to give
    // some janky dimensions due to how the Ace layers are ... layered,
    // so we manually compute it.
    int top = underlyingMarker.getAbsoluteTop() - virtualParent.getAbsoluteTop();

    panel.getElement().getStyle().setTop(top, Unit.PX);
    virtualParent.appendChild(panel.getElement());
  }
Beispiel #10
0
 private boolean isInputOnscreen() {
   return DomUtils.isVisibleVert(scrollPanel_.getElement(), inputLine_.getElement());
 }
Beispiel #11
0
  private boolean output(String text, String className, boolean addToTop) {
    if (text.indexOf('\f') >= 0) clearOutput();

    Node node;
    boolean isOutput = StringUtil.isNullOrEmpty(className) || className.equals(styles_.output());

    if (isOutput && !addToTop && trailingOutput_ != null) {
      // Short-circuit the case where we're appending output to the
      // bottom, and there's already some output there. We need to
      // treat this differently in case the new output uses control
      // characters to pound over parts of the previous output.

      int oldLineCount = DomUtils.countLines(trailingOutput_, true);
      trailingOutputConsole_.submit(text);
      trailingOutput_.setNodeValue(ensureNewLine(trailingOutputConsole_.toString()));
      int newLineCount = DomUtils.countLines(trailingOutput_, true);
      lines_ += newLineCount - oldLineCount;
    } else {
      Element outEl = output_.getElement();

      text = VirtualConsole.consolify(text);
      if (isOutput) {
        VirtualConsole console = new VirtualConsole();
        console.submit(text);
        String consoleSnapshot = console.toString();

        // We use ensureNewLine to make sure that even if output
        // doesn't end with \n, a prompt will appear on its own line.
        // However, if we call ensureNewLine indiscriminantly (i.e.
        // on an output that's going to be followed by another output)
        // we can end up inserting newlines where they don't belong.
        //
        // It's safe to add a newline when we're appending output to
        // the end of the console, because if the next append is also
        // output, we'll use the contents of VirtualConsole and the
        // newline we add here will be plowed over.
        //
        // If we're prepending output to the top of the console, then
        // it's safe to add a newline if the next chunk (which is already
        // there) is something besides output.
        if (!addToTop
            || (!outEl.hasChildNodes() || outEl.getFirstChild().getNodeType() != Node.TEXT_NODE)) {
          consoleSnapshot = ensureNewLine(consoleSnapshot);
        }

        node = Document.get().createTextNode(consoleSnapshot);
        if (!addToTop) {
          trailingOutput_ = (Text) node;
          trailingOutputConsole_ = console;
        }
      } else {
        SpanElement span = Document.get().createSpanElement();
        span.setClassName(className);
        span.setInnerText(text);
        node = span;
        if (!addToTop) {
          trailingOutput_ = null;
          trailingOutputConsole_ = null;
        }
      }

      if (addToTop) outEl.insertFirst(node);
      else outEl.appendChild(node);

      lines_ += DomUtils.countLines(node, true);
    }
    return !trimExcess();
  }
    public void endDrag(final Event evt, int action) {
      if (curState_ == STATE_NONE) return;

      // remove the properties used to position for dragging
      if (dragElement_ != null) {
        dragElement_.getStyle().clearLeft();
        dragElement_.getStyle().clearPosition();
        dragElement_.getStyle().clearZIndex();
        dragElement_.getStyle().clearDisplay();
        dragElement_.getStyle().clearOpacity();

        // insert this tab where the placeholder landed if we're not
        // cancelling
        if (action == ACTION_COMMIT) {
          dragTabsHost_.removeChild(dragElement_);
          dragTabsHost_.insertAfter(dragElement_, dragPlaceholder_);
        }
      }

      // remove the placeholder
      if (dragPlaceholder_ != null) {
        dragTabsHost_.removeChild(dragPlaceholder_);
        dragPlaceholder_ = null;
      }

      if (dragElement_ != null && action == ACTION_EXTERNAL) {
        // if we own the dragged tab, change to external drag state
        dragElement_.getStyle().setOpacity(0.4);
        curState_ = STATE_EXTERNAL;
      } else {
        // otherwise, we're back to pristine
        curState_ = STATE_NONE;
        events_.fireEvent(new DocTabDragStateChangedEvent(DocTabDragStateChangedEvent.STATE_NONE));
      }

      if (dragElement_ != null && action == ACTION_COMMIT) {
        // let observer know we moved; adjust the destination position one to
        // the left if we're right of the start position to account for the
        // position of the tab prior to movement
        if (startPos_ != null && startPos_ != destPos_) {
          TabReorderEvent event = new TabReorderEvent(startPos_, destPos_);
          fireEvent(event);
        }
      }

      // this is the case when we adopt someone else's doc
      if (dragElement_ == null && evt != null && action == ACTION_COMMIT) {
        // pull the document ID and source window out
        String data = evt.getDataTransfer().getData(getDataTransferFormat());
        if (StringUtil.isNullOrEmpty(data)) return;

        // the data format is docID|windowID; windowID can be omitted if
        // the main window is the origin
        String pieces[] = data.split("\\|");
        if (pieces.length < 1) return;

        events_.fireEvent(
            new DocWindowChangedEvent(
                pieces[0], pieces.length > 1 ? pieces[1] : "", initDragParams_, destPos_));
      }

      // this is the case when our own drag ends; if it ended outside our
      // window and outside all satellites, treat it as a tab tear-off
      if (dragElement_ != null && evt != null && action == ACTION_CANCEL) {
        // if this is the last tab in satellite, we don't want to tear
        // it out
        boolean isLastSatelliteTab = docTabs_.size() == 1 && Satellite.isCurrentWindowSatellite();

        // did the user drag the tab outside this doc?
        if (!isLastSatelliteTab
            && DomUtils.elementFromPoint(evt.getClientX(), evt.getClientY()) == null) {
          // did it end in any RStudio satellite window?
          String targetWindowName;
          Satellite satellite = RStudioGinjector.INSTANCE.getSatellite();
          if (Satellite.isCurrentWindowSatellite()) {
            // this is a satellite, ask the main window
            targetWindowName = satellite.getWindowAtPoint(evt.getScreenX(), evt.getScreenY());
          } else {
            // this is the main window, query our own satellites
            targetWindowName =
                RStudioGinjector.INSTANCE
                    .getSatelliteManager()
                    .getWindowAtPoint(evt.getScreenX(), evt.getScreenY());
          }
          if (targetWindowName == null) {
            // it was dragged over nothing RStudio owns--pop it out
            events_.fireEvent(
                new PopoutDocInitiatedEvent(
                    initDragParams_.getDocId(), new Point(evt.getScreenX(), evt.getScreenY())));
          }
        }
      }

      if (curState_ != STATE_EXTERNAL) {
        // if we're in an end state, clear the drag element
        dragElement_ = null;
      }
    }
    private void beginDrag(Event evt) {
      String docId = initDragParams_.getDocId();
      int dragTabWidth = initDragWidth_;

      // set drag element state
      dragTabsHost_ = getTabBarElement();
      dragScrollHost_ = dragTabsHost_.getParentElement();
      outOfBounds_ = 0;
      candidatePos_ = null;
      startPos_ = null;

      // attempt to determine which tab the cursor is over
      Point hostPos = DomUtils.getRelativePosition(Document.get().getBody(), dragTabsHost_);
      int dragX = evt.getClientX() - hostPos.getX();
      for (int i = 0; i < dragTabsHost_.getChildCount(); i++) {
        Node node = dragTabsHost_.getChild(i);
        if (node.getNodeType() == Node.ELEMENT_NODE) {
          int left =
              DomUtils.leftRelativeTo(dragTabsHost_, Element.as(node))
                  - dragScrollHost_.getScrollLeft();
          int right = left + Element.as(node).getOffsetWidth();
          if (left <= dragX && dragX <= right) {
            candidatePos_ = i;
            break;
          }
        }
      }

      // let the rest of the IDE know we're dragging (this will enable us to
      // disable drag targets that might otherwise be happy to accept the
      // data)
      curState_ = STATE_DRAGGING;
      events_.fireEvent(
          new DocTabDragStateChangedEvent(DocTabDragStateChangedEvent.STATE_DRAGGING));

      // the relative position of the last node determines how far we
      // can drag
      dragMax_ =
          DomUtils.leftRelativeTo(dragTabsHost_, getLastChildElement(dragTabsHost_))
              + getLastChildElement(dragTabsHost_).getClientWidth();
      lastCursorX_ = evt.getClientX();

      // account for cursor starting out of bounds (e.g. dragging into
      // empty space on the right of the panel)
      if (lastCursorX_ > dragMax_ + (initDragParams_.getCursorOffset()))
        outOfBounds_ = (lastCursorX_ - dragMax_) - initDragParams_.getCursorOffset();

      // attempt to ascertain whether the element being dragged is one of
      // our own documents
      for (DocTab tab : docTabs_) {
        if (tab.getDocId() == docId) {
          dragElement_ = tab.getElement().getParentElement().getParentElement();
          break;
        }
      }

      // if we couldn't find the horizontal drag position in any tab, append
      // to the end
      if (candidatePos_ == null) {
        candidatePos_ = dragTabsHost_.getChildCount();
      }

      destPos_ = candidatePos_;

      // if we're dragging one of our own documents, figure out its physical
      // position
      if (dragElement_ != null) {
        for (int i = 0; i < dragTabsHost_.getChildCount(); i++) {
          if (dragTabsHost_.getChild(i) == dragElement_) {
            startPos_ = i;
            break;
          }
        }
      }

      // compute the start location for the drag
      if (candidatePos_ >= dragTabsHost_.getChildCount()) {
        Element lastTab = getLastChildElement(dragTabsHost_);
        lastElementX_ = DomUtils.leftRelativeTo(dragTabsHost_, lastTab) + lastTab.getOffsetWidth();
      } else {
        lastElementX_ =
            DomUtils.leftRelativeTo(
                dragTabsHost_, Element.as(dragTabsHost_.getChild(candidatePos_)));
      }

      // if we're dragging one of our own tabs, snap it out of the
      // tabset
      if (dragElement_ != null) {
        dragElement_.getStyle().setPosition(Position.ABSOLUTE);
        dragElement_.getStyle().setLeft(lastElementX_, Unit.PX);
        dragElement_.getStyle().setZIndex(100);
        Scheduler.get()
            .scheduleDeferred(
                new ScheduledCommand() {
                  @Override
                  public void execute() {
                    dragElement_.getStyle().setDisplay(Display.NONE);
                  }
                });
      }

      // create the placeholder that shows where this tab will go when the
      // mouse is released
      dragPlaceholder_ = Document.get().createDivElement();
      dragPlaceholder_.getStyle().setWidth(dragTabWidth - 4, Unit.PX);
      dragPlaceholder_.getStyle().setHeight(dragTabsHost_.getClientHeight() - 3, Unit.PX);
      dragPlaceholder_.getStyle().setDisplay(Display.INLINE_BLOCK);
      dragPlaceholder_.getStyle().setPosition(Position.RELATIVE);
      dragPlaceholder_.getStyle().setFloat(Float.LEFT);
      dragPlaceholder_.getStyle().setBorderStyle(BorderStyle.DOTTED);
      dragPlaceholder_.getStyle().setBorderColor("#A1A2A3");
      dragPlaceholder_.getStyle().setBorderWidth(1, Unit.PX);
      dragPlaceholder_.getStyle().setMarginLeft(1, Unit.PX);
      dragPlaceholder_.getStyle().setMarginRight(1, Unit.PX);
      dragPlaceholder_.getStyle().setProperty("borderTopLeftRadius", "4px");
      dragPlaceholder_.getStyle().setProperty("borderTopRightRadius", "4px");
      dragPlaceholder_.getStyle().setProperty("borderBottom", "0px");
      if (candidatePos_ < dragTabsHost_.getChildCount()) {
        dragTabsHost_.insertBefore(dragPlaceholder_, dragTabsHost_.getChild(candidatePos_));
      } else {
        dragTabsHost_.appendChild(dragPlaceholder_);
      }
    }
    @Override
    public void onBrowserEvent(Event event) {
      if (event.getType() == "dragenter") {
        if (dropPoint_ != null
            && event.getClientX() == dropPoint_.getX()
            && event.getClientY() == dropPoint_.getY()) {
          // Very occasionally (~5%?), dropping a tab will generate a
          // superfluous "dragenter" event immediately after the drop event
          // at exactly the same coordinates. We want to ignore this since
          // it will send us into dragging state; to do so, we cache the
          // coordinates when a tab is dropped and suppress entering drag
          // mode from those coordinates very briefly (note that this won't
          // keep the user from immediately dragging the tab around since
          // you need to move the cursor in some way to initiate a drag,
          // invalidating the coordinates.)
          dropPoint_ = null;
          return;
        }

        if (curState_ == STATE_EXTERNAL) {
          // element that was being dragged around outside boundaries
          // has come back in; clear it and treat like a new drag
          dragElement_.getStyle().clearOpacity();
          dragElement_ = null;
          curState_ = STATE_NONE;
        }
        if (curState_ == STATE_NONE) {
          beginDrag(event);
        }
        event.preventDefault();
      } else if (event.getType() == "dragover") {
        if (curState_ == STATE_DRAGGING) drag(event);
        event.preventDefault();
      } else if (event.getType() == "drop") {
        endDrag(event, ACTION_COMMIT);
        event.preventDefault();

        // cache the drop point for 250ms (see comments in event handler for
        // dragenter)
        dropPoint_ = new Point(event.getClientX(), event.getClientY());
        Scheduler.get()
            .scheduleFixedDelay(
                new Scheduler.RepeatingCommand() {
                  @Override
                  public boolean execute() {
                    dropPoint_ = null;
                    return false;
                  }
                },
                250);
      } else if (event.getType() == "dragend") {
        if (curState_ != STATE_NONE) {
          endDrag(event, ACTION_CANCEL);
        }
        event.preventDefault();
      } else if (event.getType() == "dragleave") {
        if (curState_ == STATE_NONE) return;

        // when a drag leaves the window entirely, we get a dragleave event
        // at 0, 0 (which we always want to treat as a cancel)
        if (!(event.getClientX() == 0 && event.getClientY() == 0)) {
          // look at where the cursor is now--if it's inside the tab panel,
          // do nothing, but if it's outside the tab panel, treat that as
          // a cancel
          Element ele = DomUtils.elementFromPoint(event.getClientX(), event.getClientY());
          while (ele != null && ele != Document.get().getBody()) {
            if (ele.getClassName().contains("gwt-TabLayoutPanelTabs")) {
              return;
            }
            ele = ele.getParentElement();
          }
        }

        if (dragElement_ != null) {
          // dim the element being drag to hint that it'll be moved
          endDrag(event, ACTION_EXTERNAL);
        } else {
          // if this wasn't our element, we can cancel the drag entirely
          endDrag(event, ACTION_CANCEL);
        }
      }
    }
  public void ensureSelectedTabIsVisible(boolean animate) {
    if (currentAnimation_ != null) {
      currentAnimation_.cancel();
      currentAnimation_ = null;
    }

    Element selectedTab =
        (Element)
            DomUtils.findNode(
                getElement(),
                true,
                false,
                new NodePredicate() {
                  public boolean test(Node n) {
                    if (n.getNodeType() != Node.ELEMENT_NODE) return false;
                    return ((Element) n).getClassName().contains("gwt-TabLayoutPanelTab-selected");
                  }
                });
    if (selectedTab == null) {
      return;
    }
    selectedTab = selectedTab.getFirstChildElement().getFirstChildElement();

    Element tabBar = getTabBarElement();

    if (!isVisible() || !isAttached() || tabBar.getOffsetWidth() == 0) return; // not yet loaded

    final Element tabBarParent = tabBar.getParentElement();

    final int start = tabBarParent.getScrollLeft();
    int end =
        DomUtils.ensureVisibleHoriz(
            tabBarParent, selectedTab, padding_, padding_ + rightMargin_, true);

    // When tabs are closed, the overall width shrinks, and this can lead
    // to cases where there's too much empty space on the screen
    Node lastTab = getLastChildElement(tabBar);
    if (lastTab == null || lastTab.getNodeType() != Node.ELEMENT_NODE) return;
    int edge =
        DomUtils.getRelativePosition(tabBarParent, Element.as(lastTab)).x
            + Element.as(lastTab).getOffsetWidth();
    end = Math.min(end, Math.max(0, edge - (tabBarParent.getOffsetWidth() - rightMargin_)));

    if (edge <= tabBarParent.getOffsetWidth() - rightMargin_) end = 0;

    if (start != end) {
      if (!animate) {
        tabBarParent.setScrollLeft(end);
      } else {
        final int finalEnd = end;
        currentAnimation_ =
            new Animation() {
              @Override
              protected void onUpdate(double progress) {
                double delta = (finalEnd - start) * progress;
                tabBarParent.setScrollLeft((int) (start + delta));
              }

              @Override
              protected void onComplete() {
                if (this == currentAnimation_) {
                  tabBarParent.setScrollLeft(finalEnd);
                  currentAnimation_ = null;
                }
              }
            };
        currentAnimation_.run(Math.max(200, Math.min(1500, Math.abs(end - start) * 2)));
      }
    }
  }
Beispiel #16
0
 private void ensureRowVisible(final int row) {
   if (scrollPanel_ != null) DomUtils.ensureVisibleVert(scrollPanel_.getElement(), getRow(row), 0);
 }