<commit_before>/*
 * Synctex.java
 *
 * Copyright (C) 2009-11 by RStudio, Inc.
 *
 * 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.common.synctex;

import org.rstudio.core.client.FilePosition;
import org.rstudio.core.client.StringUtil;
import org.rstudio.core.client.dom.WindowEx;
import org.rstudio.core.client.files.FileSystemItem;
import org.rstudio.core.client.widget.ProgressIndicator;
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.compilepdf.events.CompilePdfCompletedEvent;
import org.rstudio.studio.client.common.compilepdf.events.CompilePdfStartedEvent;
import org.rstudio.studio.client.common.filetypes.FileTypeRegistry;
import org.rstudio.studio.client.common.satellite.Satellite;
import org.rstudio.studio.client.common.satellite.SatelliteManager;
import org.rstudio.studio.client.common.synctex.events.SynctexStatusChangedEvent;
import org.rstudio.studio.client.common.synctex.events.SynctexViewPdfEvent;
import org.rstudio.studio.client.common.synctex.model.PdfLocation;
import org.rstudio.studio.client.common.synctex.model.SourceLocation;
import org.rstudio.studio.client.common.synctex.model.SynctexServerOperations;
import org.rstudio.studio.client.pdfviewer.PDFViewerApplication;
import org.rstudio.studio.client.server.ServerError;
import org.rstudio.studio.client.server.ServerRequestCallback;
import org.rstudio.studio.client.workbench.commands.Commands;
import org.rstudio.studio.client.workbench.model.Session;

import com.google.gwt.core.client.JavaScriptObject;
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.inject.Inject;
import com.google.inject.Singleton;

@Singleton
public class Synctex implements CompilePdfStartedEvent.Handler,
                                CompilePdfCompletedEvent.Handler
{
   @Inject
   public Synctex(GlobalDisplay globalDisplay,
                  EventBus eventBus,
                  Commands commands,
                  SynctexServerOperations server,
                  FileTypeRegistry fileTypeRegistry,
                  Session session,
                  Satellite satellite, 
                  SatelliteManager satelliteManager)
   {
      globalDisplay_ = globalDisplay;
      eventBus_ = eventBus;
      commands_ = commands;
      server_ = server;
      fileTypeRegistry_ = fileTypeRegistry;
      session_ = session;
      satellite_ = satellite;
      satelliteManager_ = satelliteManager;
      
      // main window and satellite export callbacks to eachother
      if (!satellite.isCurrentWindowSatellite())
      {
         registerMainWindowCallbacks();
      }
      else if (isCurrentWindowPdfViewerSatellite())
      {
         registerSatelliteCallbacks();
         
         Window.addWindowClosingHandler(new ClosingHandler() {
            @Override
            public void onWindowClosing(ClosingEvent event)
            {
               callNotifyPdfViewerClosed();
            }
         });
      }
      
      // disable commands at the start
      setSynctexStatus(null);
      
      // subscribe to compile pdf status event so we can update command status
      eventBus_.addHandler(CompilePdfStartedEvent.TYPE, this);
      eventBus_.addHandler(CompilePdfCompletedEvent.TYPE, this);
   }
   
   @Override
   public void onCompilePdfStarted(CompilePdfStartedEvent event)
   {
      setSynctexStatus(null);
   }

   @Override
   public void onCompilePdfCompleted(CompilePdfCompletedEvent event)
   {
      boolean synctexAvailable =
            event.getResult().isSynctexAvailable() &&
            session_.getSessionInfo().isInternalPdfPreviewEnabled();
       
      if (synctexAvailable)
         setSynctexStatus(event.getResult().getPdfPath());
      else
         setSynctexStatus(null);
   }
   
   public boolean isSynctexAvailable()
   {
      return pdfPath_ != null;
   }
   
   public String getPdfPath()
   {
      return pdfPath_;
   }
   
   public void enableCommands(boolean enabled)
   {
      commands_.synctexForwardSearch().setVisible(enabled);
      commands_.synctexForwardSearch().setEnabled(enabled);
      commands_.synctexInverseSearch().setVisible(enabled);
      commands_.synctexInverseSearch().setEnabled(enabled);
   }

   public boolean forwardSearch(SourceLocation sourceLocation)
   {
      // return false if there is no pdf viewer
      WindowEx window = satelliteManager_.getSatelliteWindowObject(
                                                   PDFViewerApplication.NAME);
      if (window == null)
         return false;
      
      // activate the satellite
      satelliteManager_.activateSatelliteWindow(PDFViewerApplication.NAME);
         
      // execute the forward search
      callForwardSearch(window, sourceLocation);
  
      return true;
   }
   
   public void inverseSearch(PdfLocation pdfLocation)
   {
      satellite_.focusMainWindow();
      callInverseSearch(pdfLocation);
   }
   
   
   private void doForwardSearch(JavaScriptObject sourceLocationObject)
   {
      SourceLocation sourceLocation = sourceLocationObject.cast();
      <commit_msg>warning for firefox users that syncing back to the main editor window isn't supported in firefox<commit_after>/*
 * Synctex.java
 *
 * Copyright (C) 2009-11 by RStudio, Inc.
 *
 * 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.common.synctex;

import org.rstudio.core.client.BrowseCap;
import org.rstudio.core.client.FilePosition;
import org.rstudio.core.client.StringUtil;
import org.rstudio.core.client.dom.WindowEx;
import org.rstudio.core.client.files.FileSystemItem;
import org.rstudio.core.client.widget.MessageDialog;
import org.rstudio.core.client.widget.ProgressIndicator;
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.compilepdf.events.CompilePdfCompletedEvent;
import org.rstudio.studio.client.common.compilepdf.events.CompilePdfStartedEvent;
import org.rstudio.studio.client.common.filetypes.FileTypeRegistry;
import org.rstudio.studio.client.common.satellite.Satellite;
import org.rstudio.studio.client.common.satellite.SatelliteManager;
import org.rstudio.studio.client.common.synctex.events.SynctexStatusChangedEvent;
import org.rstudio.studio.client.common.synctex.events.SynctexViewPdfEvent;
import org.rstudio.studio.client.common.synctex.model.PdfLocation;
import org.rstudio.studio.client.common.synctex.model.SourceLocation;
import org.rstudio.studio.client.common.synctex.model.SynctexServerOperations;
import org.rstudio.studio.client.pdfviewer.PDFViewerApplication;
import org.rstudio.studio.client.server.ServerError;
import org.rstudio.studio.client.server.ServerRequestCallback;
import org.rstudio.studio.client.workbench.commands.Commands;
import org.rstudio.studio.client.workbench.model.Session;

import com.google.gwt.core.client.JavaScriptObject;
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.inject.Inject;
import com.google.inject.Singleton;

@Singleton
public class Synctex implements CompilePdfStartedEvent.Handler,
                                CompilePdfCompletedEvent.Handler
{
   @Inject
   public Synctex(GlobalDisplay globalDisplay,
                  EventBus eventBus,
                  Commands commands,
                  SynctexServerOperations server,
                  FileTypeRegistry fileTypeRegistry,
                  Session session,
                  Satellite satellite, 
                  SatelliteManager satelliteManager)
   {
      globalDisplay_ = globalDisplay;
      eventBus_ = eventBus;
      commands_ = commands;
      server_ = server;
      fileTypeRegistry_ = fileTypeRegistry;
      session_ = session;
      satellite_ = satellite;
      satelliteManager_ = satelliteManager;
      
      // main window and satellite export callbacks to eachother
      if (!satellite.isCurrentWindowSatellite())
      {
         registerMainWindowCallbacks();
      }
      else if (isCurrentWindowPdfViewerSatellite())
      {
         registerSatelliteCallbacks();
         
         Window.addWindowClosingHandler(new ClosingHandler() {
            @Override
            public void onWindowClosing(ClosingEvent event)
            {
               callNotifyPdfViewerClosed();
            }
         });
      }
      
      // disable commands at the start
      setSynctexStatus(null);
      
      // subscribe to compile pdf status event so we can update command status
      eventBus_.addHandler(CompilePdfStartedEvent.TYPE, this);
      eventBus_.addHandler(CompilePdfCompletedEvent.TYPE, this);
   }
   
   @Override
   public void onCompilePdfStarted(CompilePdfStartedEvent event)
   {
      setSynctexStatus(null);
   }

   @Override
   public void onCompilePdfCompleted(CompilePdfCompletedEvent event)
   {
      boolean synctexAvailable =
            event.getResult().isSynctexAvailable() &&
            session_.getSessionInfo().isInternalPdfPreviewEnabled();
       
      if (synctexAvailable)
         setSynctexStatus(event.getResult().getPdfPath());
      else
         setSynctexStatus(null);
   }
   
   public boolean isSynctexAvailable()
   {
      return pdfPath_ != null;
   }
   
   public String getPdfPath()
   {
      return pdfPath_;
   }
   
   public void enableCommands(boolean enabled)
   {
      commands_.synctexForwardSearch().setVisible(enabled);
      commands_.synctexForwardSearch().setEnabled(enabled);
      commands_.synctexInverseSearch().setVisible(enabled);
      commands_.synctexInverseSearch().setEnabled(enabled);
   }

   public boolean forwardSearch(SourceLocation sourceLocation)
   {
      // return false if there is no pdf viewer
      WindowEx window = satelliteManager_.getSatelliteWindowObject(
                                                   PDFViewerApplication.NAME);
      if (window == null)
         return false;
      
      // activate the satellite
      satelliteManager_.activateSatelliteWindow(PDFViewerApplication.NAME);
         
      // execute the forward search
      callForwardSearch(window, sourceLocation);
  
      return true;
   }
   
   public void inverseSearch(PdfLocation pdfLocation)
   {
      // switch back to the main window 
      satellite_.focusMainWindow();
      
      // warn firefox users that this doesn't really work in Firefox
      if (BrowseCap.isFirefox())
      {
         globalDisplay_.showMessage(
            MessageDialog.INFO,
            "Source Editor Updated",
            "The source editor was updated to sync to the PDF location " +
            "however Firefox has disallowed switching windows back to " +
            "the source editor.\n\n" +
            "To prevent this problem in the future you may want to use " +
            "Google Chrome rather than Firefox when compiling and " +
            "previewing PDFs.");
      }
      
      // do the inverse search
      callInverseSearch(pdfLocation);
   }
   
   
   private void doForwardSearch(JavaScriptObject sourceLocationObject)
   {
      SourceLocation sourceLocation = sourceLocationObject.cast();
      
{'fraction_non_alphanumeric': 0.08088114417228341, 'fraction_numerical': 0.0014795331251027453, 'mean_word_length': 3.019491245457549, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 4, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4669875', 'n_tokens_mistral': 3490, 'n_tokens_neox': 3356, 'n_words': 666}