document.py :  » Windows » pyExcelerator » pywin32-214 » pythonwin » pywin » framework » editor » Python Open Source

Home
Python Open Source
1.3.1.2 Python
2.Ajax
3.Aspect Oriented
4.Blog
5.Build
6.Business Application
7.Chart Report
8.Content Management Systems
9.Cryptographic
10.Database
11.Development
12.Editor
13.Email
14.ERP
15.Game 2D 3D
16.GIS
17.GUI
18.IDE
19.Installer
20.IRC
21.Issue Tracker
22.Language Interface
23.Log
24.Math
25.Media Sound Audio
26.Mobile
27.Network
28.Parser
29.PDF
30.Project Management
31.RSS
32.Search
33.Security
34.Template Engines
35.Test
36.UML
37.USB Serial
38.Web Frameworks
39.Web Server
40.Web Services
41.Web Unit
42.Wiki
43.Windows
44.XML
Python Open Source » Windows » pyExcelerator 
pyExcelerator » pywin32 214 » pythonwin » pywin » framework » editor » document.py
# We no longer support the old, non-colour editor!

from pywin.mfc import docview,object
from pywin.framework.editor import GetEditorOption
import win32ui
import os
import win32con
import string
import traceback
import win32api
import shutil

BAK_NONE=0
BAK_DOT_BAK=1
BAK_DOT_BAK_TEMP_DIR=2
BAK_DOT_BAK_BAK_DIR=3

MSG_CHECK_EXTERNAL_FILE = win32con.WM_USER+1999 ## WARNING: Duplicated in editor.py and coloreditor.py

import pywin.scintilla.document
ParentEditorDocument=pywin.scintilla.document.CScintillaDocument
class EditorDocumentBase(ParentEditorDocument):
  def __init__(self, template):
    self.bAutoReload = GetEditorOption("Auto Reload", 1)
    self.bDeclinedReload = 0 # Has the user declined to reload.
    self.fileStat = None
    self.bReportedFileNotFound = 0

    # what sort of bak file should I create.
    # default to write to %temp%/bak/filename.ext
    self.bakFileType=GetEditorOption("Backup Type", BAK_DOT_BAK_BAK_DIR)

    self.watcherThread = FileWatchingThread(self)
    self.watcherThread.CreateThread()
    # Should I try and use VSS integration?
    self.scModuleName=GetEditorOption("Source Control Module", "")
    self.scModule = None # Loaded when first used.
    ParentEditorDocument.__init__(self, template, template.CreateWin32uiDocument())

  def OnCloseDocument(self ):
    self.watcherThread.SignalStop()
    return self._obj_.OnCloseDocument()

#  def OnOpenDocument(self, name):
#    rc = ParentEditorDocument.OnOpenDocument(self, name)
#    self.GetFirstView()._SetLoadedText(self.text)
#    self._DocumentStateChanged()
#    return rc

  def OnSaveDocument( self, fileName ):
    win32ui.SetStatusText("Saving file...",1)
    # rename to bak if required.
    dir, basename = os.path.split(fileName)
    if self.bakFileType==BAK_DOT_BAK:
      bakFileName=dir+'\\'+os.path.splitext(basename)[0]+'.bak'
    elif self.bakFileType==BAK_DOT_BAK_TEMP_DIR:
      bakFileName=win32api.GetTempPath()+'\\'+os.path.splitext(basename)[0]+'.bak'
    elif self.bakFileType==BAK_DOT_BAK_BAK_DIR:
      tempPath=os.path.join(win32api.GetTempPath(),'bak')
      try:
        os.mkdir(tempPath,0)
      except os.error:
        pass
      bakFileName=os.path.join(tempPath,basename)
    try:
      os.unlink(bakFileName)  # raise NameError if no bakups wanted.
    except (os.error, NameError):
      pass
    try:
      # Do a copy as it might be on different volumes,
      # and the file may be a hard-link, causing the link
      # to follow the backup.
      shutil.copy2(fileName, bakFileName)
    except (os.error, NameError, IOError):
      pass
    try:
      self.SaveFile(fileName)
    except IOError, details:
      win32ui.MessageBox("Error - could not save file\r\n\r\n%s"%details)
      return 0
    self.SetModifiedFlag(0) # No longer dirty
    self.bDeclinedReload = 0 # They probably want to know if it changes again!
    win32ui.AddToRecentFileList(fileName)
    self.SetPathName(fileName)
    win32ui.SetStatusText("Ready")
    self._DocumentStateChanged()
    return 1

  def FinalizeViewCreation(self, view):
    ParentEditorDocument.FinalizeViewCreation(self, view)
    if view == self.GetFirstView():
      self._DocumentStateChanged()
      if view.bFolding and GetEditorOption("Fold On Open", 0):
        view.FoldTopLevelEvent()

  def HookViewNotifications(self, view):
    ParentEditorDocument.HookViewNotifications(self, view)

  # Support for reloading the document from disk - presumably after some
  # external application has modified it (or possibly source control has
  # checked it out.
  def ReloadDocument(self):
    """Reloads the document from disk.  Assumes the file has
    been saved and user has been asked if necessary - it just does it!
    """
    win32ui.SetStatusText("Reloading document.  Please wait...", 1)
    self.SetModifiedFlag(0)
    # Loop over all views, saving their state, then reload the document
    views = self.GetAllViews()
    states = []
    for view in views:
      try:
        info = view._PrepareUserStateChange()
      except AttributeError: # Not our editor view?
        info = None
      states.append(info)
    self.OnOpenDocument(self.GetPathName())
    for view, info in zip(views, states):
      if info is not None:
        view._EndUserStateChange(info)
    self._DocumentStateChanged()
    win32ui.SetStatusText("Document reloaded.")

  # Reloading the file
  def CheckExternalDocumentUpdated(self):
    if self.bDeclinedReload or not self.GetPathName():
      return
    try:
      newstat = os.stat(self.GetPathName())
    except os.error, exc:
      if not self.bReportedFileNotFound:
        print "The file '%s' is open for editing, but\nchecking it for changes caused the error: %s" % (self.GetPathName(), exc.strerror)
        self.bReportedFileNotFound = 1
      return
    if self.bReportedFileNotFound:
      print "The file '%s' has re-appeared - continuing to watch for changes..." % (self.GetPathName(),)
      self.bReportedFileNotFound = 0 # Once found again we want to start complaining.
    changed = (self.fileStat is None) or \
      self.fileStat[0] != newstat[0] or \
      self.fileStat[6] != newstat[6] or \
      self.fileStat[8] != newstat[8] or \
      self.fileStat[9] != newstat[9]
    if changed:
      question = None
      if self.IsModified():
        question = "%s\r\n\r\nThis file has been modified outside of the source editor.\r\nDo you want to reload it and LOSE THE CHANGES in the source editor?" % self.GetPathName()
        mbStyle = win32con.MB_YESNO | win32con.MB_DEFBUTTON2 # Default to "No"
      else:
        if not self.bAutoReload:
          question = "%s\r\n\r\nThis file has been modified outside of the source editor.\r\nDo you want to reload it?" % self.GetPathName()
          mbStyle = win32con.MB_YESNO # Default to "Yes"
      if question:
        rc = win32ui.MessageBox(question, None, mbStyle)
        if rc!=win32con.IDYES:
          self.bDeclinedReload = 1
          return
      self.ReloadDocument()

  def _DocumentStateChanged(self):
    """Called whenever the documents state (on disk etc) has been changed
    by the editor (eg, as the result of a save operation)
    """
    if self.GetPathName():
      try:
        self.fileStat = os.stat(self.GetPathName())
      except os.error:
        self.fileStat = None
    else:
      self.fileStat = None
    self.watcherThread._DocumentStateChanged()
    self._UpdateUIForState()
    self._ApplyOptionalToViews("_UpdateUIForState")
    self._ApplyOptionalToViews("SetReadOnly", self._IsReadOnly())
    self._ApplyOptionalToViews("SCISetSavePoint")
    # Allow the debugger to reset us too.
    import pywin.debugger
    if pywin.debugger.currentDebugger is not None:
      pywin.debugger.currentDebugger.UpdateDocumentLineStates(self)
      
  # Read-only document support - make it obvious to the user
  # that the file is read-only.
  def _IsReadOnly(self):
    return self.fileStat is not None and (self.fileStat[0] & 128)==0

  def _UpdateUIForState(self):
    """Change the title to reflect the state of the document - 
    eg ReadOnly, Dirty, etc
    """
    filename = self.GetPathName()
    if not filename: return # New file - nothing to do
    try:
      # This seems necessary so the internal state of the window becomes
      # "visible".  without it, it is still shown, but certain functions
      # (such as updating the title) dont immediately work?
      self.GetFirstView().ShowWindow(win32con.SW_SHOW)
      title = win32ui.GetFileTitle(filename)
    except win32ui.error:
      title = filename
    if self._IsReadOnly():
      title = title + " (read-only)"
    self.SetTitle(title)

  def MakeDocumentWritable(self):
    pretend_ss = 0 # Set to 1 to test this without source safe :-)
    if not self.scModuleName and not pretend_ss: # No Source Control support.
      win32ui.SetStatusText("Document is read-only, and no source-control system is configured")
      win32api.MessageBeep()
      return 0

    # We have source control support - check if the user wants to use it.
    msg = "Would you like to check this file out?"
    defButton = win32con.MB_YESNO
    if self.IsModified(): 
      msg = msg + "\r\n\r\nALL CHANGES IN THE EDITOR WILL BE LOST"
      defButton = win32con.MB_YESNO
    if win32ui.MessageBox(msg, None, defButton)!=win32con.IDYES:
      return 0

    if pretend_ss:
      print "We are only pretending to check it out!"
      win32api.SetFileAttributes(self.GetPathName(), win32con.FILE_ATTRIBUTE_NORMAL)
      self.ReloadDocument()
      return 1
      
    # Now call on the module to do it.
    if self.scModule is None:
      try:
        self.scModule = __import__(self.scModuleName)
        for part in self.scModuleName.split('.')[1:]:
          self.scModule = getattr(self.scModule, part)
      except:
        traceback.print_exc()
        print "Error loading source control module."
        return 0
    
    if self.scModule.CheckoutFile(self.GetPathName()):
      self.ReloadDocument()
      return 1
    return 0

  def CheckMakeDocumentWritable(self):
    if self._IsReadOnly():
      return self.MakeDocumentWritable()
    return 1

  def SaveModified(self):
    # Called as the document is closed.  If we are about
    # to prompt for a save, bring the document to the foreground.
    if self.IsModified():
      frame = self.GetFirstView().GetParentFrame()
      try:
        frame.MDIActivate()
        frame.AutoRestore()
      except:
        print "Could not bring document to foreground"
    return self._obj_.SaveModified()

# NOTE - I DONT use the standard threading module,
# as this waits for all threads to terminate at shutdown.
# When using the debugger, it is possible shutdown will
# occur without Pythonwin getting a complete shutdown,
# so we deadlock at the end - threading is waiting for
import pywin.mfc.thread
import win32event
class FileWatchingThread(pywin.mfc.thread.WinThread):
  def __init__(self, doc):
    self.doc = doc
    self.adminEvent = win32event.CreateEvent(None, 0, 0, None)
    self.stopEvent = win32event.CreateEvent(None, 0, 0, None)
    self.watchEvent = None
    pywin.mfc.thread.WinThread.__init__(self)

  def _DocumentStateChanged(self):
    win32event.SetEvent(self.adminEvent)

  def RefreshEvent(self):
    self.hwnd = self.doc.GetFirstView().GetSafeHwnd()
    if self.watchEvent is not None:
      win32api.FindCloseChangeNotification(self.watchEvent)
      self.watchEvent = None
    path = self.doc.GetPathName()
    if path: path = os.path.dirname(path)
    if path:
      filter = win32con.FILE_NOTIFY_CHANGE_FILE_NAME | \
           win32con.FILE_NOTIFY_CHANGE_ATTRIBUTES | \
           win32con.FILE_NOTIFY_CHANGE_LAST_WRITE
      try:
        self.watchEvent = win32api.FindFirstChangeNotification(path, 0, filter)
      except win32api.error, exc:
        print "Can not watch file", path, "for changes -", exc.strerror
  def SignalStop(self):
    win32event.SetEvent(self.stopEvent)
  def Run(self):
    while 1:
      handles = [self.stopEvent, self.adminEvent]
      if self.watchEvent is not None:
        handles.append(self.watchEvent)
      rc = win32event.WaitForMultipleObjects(handles, 0, win32event.INFINITE)
      if rc == win32event.WAIT_OBJECT_0:
        break
      elif rc == win32event.WAIT_OBJECT_0+1:
        self.RefreshEvent()
      else:
        win32api.PostMessage(self.hwnd, MSG_CHECK_EXTERNAL_FILE, 0, 0)
        try:
          # If the directory has been removed underneath us, we get this error.
          win32api.FindNextChangeNotification(self.watchEvent)
        except win32api.error, exc:
          print "Can not watch file", self.doc.GetPathName(), "for changes -", exc.strerror
          break

    # close a circular reference
    self.doc = None
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.