Package org.rstudio.studio.client.workbench.views.source.editors.codebrowser

Source Code of org.rstudio.studio.client.workbench.views.source.editors.codebrowser.CodeBrowserEditingTargetWidget

/*
* CodeBrowserEditingTargetWidget.java
*
* Copyright (C) 2009-12 by RStudio, Inc.
*
* Unless you have received this program directly from RStudio pursuant
* to the terms of a commercial license agreement with RStudio, then
* this program is licensed to you under the terms of version 3 of the
* GNU Affero General Public License. This program is distributed WITHOUT
* ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING THOSE OF NON-INFRINGEMENT,
* MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Please refer to the
* AGPL (http://www.gnu.org/licenses/agpl-3.0.txt) for more details.
*
*/
package org.rstudio.studio.client.workbench.views.source.editors.codebrowser;

import com.google.gwt.core.client.GWT;
import com.google.gwt.dom.client.NativeEvent;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.logical.shared.SelectionEvent;
import com.google.gwt.event.logical.shared.SelectionHandler;
import com.google.gwt.resources.client.ClientBundle;
import com.google.gwt.resources.client.CssResource;
import com.google.gwt.resources.client.ImageResource;
import com.google.gwt.user.client.Timer;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.ResizeComposite;
import com.google.gwt.user.client.ui.Widget;

import org.rstudio.core.client.command.KeyboardShortcut;
import org.rstudio.core.client.regex.Match;
import org.rstudio.core.client.regex.Pattern;
import org.rstudio.core.client.regex.Pattern.ReplaceOperation;
import org.rstudio.core.client.theme.res.ThemeResources;
import org.rstudio.core.client.widget.InfoBar;
import org.rstudio.core.client.widget.SecondaryToolbar;
import org.rstudio.core.client.widget.Toolbar;
import org.rstudio.core.client.widget.ToolbarButton;
import org.rstudio.core.client.widget.ToolbarPopupMenu;
import org.rstudio.studio.client.application.events.EventBus;
import org.rstudio.studio.client.common.GlobalDisplay;
import org.rstudio.studio.client.common.GlobalProgressDelayer;
import org.rstudio.studio.client.common.SimpleRequestCallback;
import org.rstudio.studio.client.common.codetools.CodeToolsServerOperations;
import org.rstudio.studio.client.common.filetypes.FileTypeRegistry;
import org.rstudio.studio.client.common.filetypes.TextFileType;
import org.rstudio.studio.client.server.ServerError;
import org.rstudio.studio.client.server.ServerRequestCallback;
import org.rstudio.studio.client.server.Void;
import org.rstudio.studio.client.workbench.codesearch.model.SearchPathFunctionDefinition;
import org.rstudio.studio.client.workbench.commands.Commands;
import org.rstudio.studio.client.workbench.prefs.model.UIPrefs;
import org.rstudio.studio.client.workbench.views.console.shell.assist.CompletionManager;
import org.rstudio.studio.client.workbench.views.console.shell.editor.InputEditorLineWithCursorPosition;
import org.rstudio.studio.client.workbench.views.console.shell.editor.InputEditorUtil;
import org.rstudio.studio.client.workbench.views.source.PanelWithToolbars;
import org.rstudio.studio.client.workbench.views.source.editors.EditingTargetToolbar;
import org.rstudio.studio.client.workbench.views.source.editors.text.AceEditor;
import org.rstudio.studio.client.workbench.views.source.editors.text.DocDisplay;
import org.rstudio.studio.client.workbench.views.source.editors.text.TextEditingTargetFindReplace;
import org.rstudio.studio.client.workbench.views.source.editors.text.findreplace.FindReplaceBar;
import org.rstudio.studio.client.workbench.views.source.events.CodeBrowserNavigationEvent;
import org.rstudio.studio.client.workbench.views.source.model.SourcePosition;

public class CodeBrowserEditingTargetWidget extends ResizeComposite
                              implements CodeBrowserEditingTarget.Display
{
   public CodeBrowserEditingTargetWidget(Commands commands,
                                         final GlobalDisplay globalDisplay,
                                         final EventBus eventBus,
                                         final UIPrefs uiPrefs,
                                         final CodeToolsServerOperations server,
                                         final DocDisplay docDisplay)
   {
      commands_ = commands;
      uiPrefs_ = uiPrefs;
      globalDisplay_ = globalDisplay;
      eventBus_ = eventBus;
      server_ = server;
     
      docDisplay_ = docDisplay;
     
      findReplace_ = new TextEditingTargetFindReplace(
         new TextEditingTargetFindReplace.Container() {

            @Override
            public AceEditor getEditor()
            {
               return (AceEditor)docDisplay_;
            }

            @Override
            public void insertFindReplace(FindReplaceBar findReplaceBar)
            {
               panel_.insertNorth(findReplaceBar,
                                  findReplaceBar.getHeight(),
                                  null);
            }

            @Override
            public void removeFindReplace(FindReplaceBar findReplaceBar)
            {
               panel_.remove(findReplaceBar);
            }
          
         },
         false); // don't show replace UI
     
      panel_ = new PanelWithToolbars(createToolbar(),
                                     createSecondaryToolbar(),
                                     docDisplay_.asWidget(),
                                     null);
      panel_.setSize("100%", "100%");
     
      docDisplay_.setReadOnly(true);
      
      // setup custom completion manager for executing F1 and F2 actions
      docDisplay_.setFileType(FileTypeRegistry.R, new CompletionManager() {

         @Override
         public boolean previewKeyDown(NativeEvent event)
         {
            int modifier = KeyboardShortcut.getModifierValue(event);
            if (modifier == KeyboardShortcut.NONE)
            {
               if (event.getKeyCode() == 112) // F1
               {
                  goToHelp();
               }
               else if (event.getKeyCode() == 113) // F2
               {
                  goToFunctionDefinition();
               }
            }
           
            return false;
         }
        
         @Override
         public void goToHelp()
         {
            InputEditorLineWithCursorPosition linePos =
                  InputEditorUtil.getLineWithCursorPosition(docDisplay);
       
            server.getHelpAtCursor(
               linePos.getLine(), linePos.getPosition(),
               new SimpleRequestCallback<Void>("Help"));
         }
        
         @Override
         public void goToFunctionDefinition()
         {
            // determine current line and cursor position
            InputEditorLineWithCursorPosition lineWithPos =
                      InputEditorUtil.getLineWithCursorPosition(docDisplay);
            
            // navigate to the function at this position (if any)
            navigateToFunction(lineWithPos)
         }
        
         @Override
         public void codeCompletion()
         {
            // no-op since this is a code browser
         }

         @Override
         public boolean previewKeyPress(char charCode)
         {
            return false;
         }
        
         @Override
         public void close()
         {
         }
        
      });
     
      initWidget(panel_);

   }
   
   @Override
   public Widget asWidget()
   {
      return this;
   }
  
  
   @Override
   public void adaptToFileType(TextFileType fileType)
   {
      docDisplay_.setFileType(fileType, true);
   }


   @Override
   public void setFontSize(double size)
   {
      docDisplay_.setFontSize(size);
   }
  
   @Override
   public void onActivate()
   {
      docDisplay_.onActivate();
   }
  
   @Override
   public void showFunction(SearchPathFunctionDefinition functionDef)
   {
      currentFunctionNamespace_ = functionDef.getNamespace();
      docDisplay_.setCode(formatCode(functionDef), false);
      // don't send focus to the display for debugging; we want it to stay in
      // the console
      if (!functionDef.isActiveDebugCode())
      {
         docDisplay_.focus();
      }
      contextWidget_.setCurrentFunction(functionDef);
   }
  
   @Override
   public void showFind(boolean defaultForward)
   {
      findReplace_.showFindReplace(defaultForward);
   }
  
   @Override
   public void findNext()
   {
      findReplace_.findNext();
     
   }

   @Override
   public void findPrevious()
   {
      findReplace_.findPrevious();
   }
  
   @Override
   public void findFromSelection()
   {
      findReplace_.findFromSelection();
   }
  
   @Override
   public void scrollToLeft()
   {
      new Timer() {
         @Override
         public void run()
         {
            docDisplay_.scrollToX(0);
         }
      }.schedule(100);
   }
  
   @Override
   public void showWarningBar(String warning)
   {
      if (warningBar_ == null)
      {
         warningBar_ = new InfoBar(InfoBar.WARNING, new ClickHandler() {
            @Override
            public void onClick(ClickEvent event)
            {
               hideWarningBar();
            }
           
         });
      }
      warningBar_.setText(warning);
      panel_.insertNorth(warningBar_, warningBar_.getHeight(), null);
   }

   @Override
   public void hideWarningBar()
   {
      if (warningBar_ != null)
      {
         panel_.remove(warningBar_);
      }
   }

   private void navigateToFunction(
         InputEditorLineWithCursorPosition lineWithPos)
   {
      server_.findFunctionInSearchPath(
            lineWithPos.getLine(),
            lineWithPos.getPosition(),
            currentFunctionNamespace_,
            new FunctionSearchRequestCallback(true));
   }
  
   private class FunctionSearchRequestCallback
                    extends ServerRequestCallback<SearchPathFunctionDefinition>
   {
      public FunctionSearchRequestCallback(boolean searchLocally)
      {
         searchLocally_ = searchLocally;
        
         // delayed progress indicator
         progress_ = new GlobalProgressDelayer(
               globalDisplay_, 1000, "Searching for function definition...");

      }
     
      @Override
      public void onResponseReceived(SearchPathFunctionDefinition def)
      {
         // dismiss progress
         progress_.dismiss();

         // if we got a hit
         if (def != null && def.getName() != null)
         {        
            // try to search for the function locally
            SourcePosition position = searchLocally_ ?
                  docDisplay_.findFunctionPositionFromCursor(def.getName()) :
                  null;
                 
            if (position != null)
            {
               docDisplay_.navigateToPosition(position, true);
            }
            else if (def.getNamespace() != null)
            {
               docDisplay_.recordCurrentNavigationPosition();
               eventBus_.fireEvent(new CodeBrowserNavigationEvent(
                     def));       
            }
         }
      }

      @Override
      public void onError(ServerError error)
      {
         progress_.dismiss();

         globalDisplay_.showErrorMessage(
                                 "Error Searching for Function",
                                 error.getUserMessage());
      }
     
      private final boolean searchLocally_;
      private final GlobalProgressDelayer progress_;
   }
  
   private Toolbar createToolbar()
   {
      Toolbar toolbar = new EditingTargetToolbar(commands_);
     
      toolbar.addLeftWidget(commands_.printSourceDoc().createToolbarButton());
      toolbar.addLeftSeparator();
      toolbar.addLeftWidget(findReplace_.createFindReplaceButton());
    
      ImageResource icon = ThemeResources.INSTANCE.codeTransform();

      ToolbarPopupMenu menu = new ToolbarPopupMenu();
      menu.addItem(commands_.goToHelp().createMenuItem(false));
      menu.addItem(commands_.goToFunctionDefinition().createMenuItem(false));
      ToolbarButton codeTools = new ToolbarButton("", icon, menu);
      codeTools.setTitle("Code Tools");
      toolbar.addLeftWidget(codeTools);
     
      toolbar.addRightWidget(commands_.executeCode().createToolbarButton());
      toolbar.addRightSeparator();
      toolbar.addRightWidget(commands_.executeLastCode().createToolbarButton());
     
      return toolbar;
   }
  
   private Toolbar createSecondaryToolbar()
   {
      SecondaryToolbar toolbar = new SecondaryToolbar();
     
      contextWidget_ = new CodeBrowserContextWidget(RES.styles());
      contextWidget_.addSelectionHandler(new SelectionHandler<String> () {
         @Override
         public void onSelection(SelectionEvent<String> event)
         {
            server_.getMethodDefinition(
                              event.getSelectedItem(),
                              new FunctionSearchRequestCallback(false));
         }
        
      });
      toolbar.addLeftWidget(contextWidget_);
     
      Label readOnlyLabel = new Label("(Read-only)");
      readOnlyLabel.addStyleName(RES.styles().readOnly());
      toolbar.addRightWidget(readOnlyLabel);
        
      return toolbar;
   }
  
   private String formatCode(SearchPathFunctionDefinition functionDef)
   {
      // deal with null
      String code = functionDef.getCode();
      if (code == null)
         return "";
     
      // if this is from a source ref then leave it alone
      if (functionDef.isCodeFromSrcAttrib())
         return code;
     
      // determine the replacement text based on the user's current
      // editing preferences
      String replaceText = "\t";
      if (uiPrefs_.useSpacesForTab().getValue())
      {
         StringBuilder replaceBuilder = new StringBuilder();
         for (int i=0; i<uiPrefs_.numSpacesForTab().getValue(); i++)
            replaceBuilder.append(' ');
         replaceText = replaceBuilder.toString();
      }
     
      // create regex pattern used to find leading space
      // NOTE: the 4 spaces comes from the implementation of printtab2buff
      // in deparse.c -- it is hard-coded to use 4 spaces for the first 4
      // levels of indentation and then 2 spaces for subsequent levels.
      final String replaceWith = replaceText;
      Pattern pattern = Pattern.create("^(    ){1,4}");
      code = pattern.replaceAll(code, new ReplaceOperation()
      {
         @Override
         public String replace(Match m)
         {
            return m.getValue().replace("    ", replaceWith);
         }
      });
      Pattern pattern2 = Pattern.create("^\t{4}(  )+");
      code = pattern2.replaceAll(code, new ReplaceOperation()
      {
         @Override
         public String replace(Match m)
         {
            return m.getValue().replace("  ",  replaceWith);
         }
      });

      return code;
   }
  
   public static void ensureStylesInjected()
   {
      RES.styles().ensureInjected();
   }

   interface Resources extends ClientBundle
   {
      @Source("CodeBrowserEditingTargetWidget.css")
      Styles styles();

   }

   interface Styles extends CssResource
   {
      String captionLabel();
      String menuElement();
      String functionName();
      String functionNamespace();
      String dropDownImage();
      String readOnly();
   }
  
   static Resources RES = GWT.create(Resources.class);

   private final PanelWithToolbars panel_;
   private CodeBrowserContextWidget contextWidget_;
   private final CodeToolsServerOperations server_;
   private final GlobalDisplay globalDisplay_;
   private final EventBus eventBus_;
   private final Commands commands_;
   private final UIPrefs uiPrefs_;
   private final DocDisplay docDisplay_;
   private final TextEditingTargetFindReplace findReplace_;
   private String currentFunctionNamespace_ = null;
   private InfoBar warningBar_;
}
TOP

Related Classes of org.rstudio.studio.client.workbench.views.source.editors.codebrowser.CodeBrowserEditingTargetWidget

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.