Example #1
0
	def DoConfigChange(self):
		# Bit of a hack I dont kow what to do about - these should be "editor options"
		from pywin.framework.editor import GetEditorOption
		self.bAutoCompleteAttributes = GetEditorOption("Autocomplete Attributes", 1)
		self.bShowCallTips = GetEditorOption("Show Call Tips", 1)
		# Update the key map and extension data.
		configManager.configure(self, self._GetSubConfigNames())
		if configManager.last_error:
			win32ui.MessageBox(configManager.last_error, "Configuration Error")
		self.bMatchBraces = GetEditorOption("Match Braces", 1)
		self.ApplyFormattingStyles(1)
Example #2
0
    def OnInitDialog(self):
        for name, val in self.autooptions:
            self[name] = GetEditorOption(name, val)

        # Note that these MUST be in the same order as the BAK constants.
        cbo = self.GetDlgItem(win32ui.IDC_COMBO1)
        cbo.AddString("None")
        cbo.AddString(".BAK File")
        cbo.AddString("TEMP dir")
        cbo.AddString("Own dir")

        # Source Safe
        bVSS = (GetEditorOption("Source Control Module",
                                "") == "pywin.framework.editor.vss")
        self["bVSS"] = bVSS

        edit = self.GetDlgItem(win32ui.IDC_RIGHTEDGE_SAMPLE)
        edit.SetWindowText("Sample Color")

        rc = dialog.PropertyPage.OnInitDialog(self)

        try:
            self.GetDlgItem(win32ui.IDC_KEYBOARD_CONFIG).SelectString(
                -1, GetEditorOption("Keyboard Config", "default"))
        except win32ui.error:
            import traceback

            traceback.print_exc()
            pass

        self.HookCommand(self.OnButSimple, win32ui.IDC_FOLD_ENABLE)
        self.HookCommand(self.OnButSimple, win32ui.IDC_RADIO1)
        self.HookCommand(self.OnButSimple, win32ui.IDC_RADIO2)
        self.HookCommand(self.OnButSimple, win32ui.IDC_RIGHTEDGE_ENABLE)
        self.HookCommand(self.OnButEdgeColor, win32ui.IDC_RIGHTEDGE_DEFINE)

        butMarginEnabled = self["Marker Margin Width"] > 0
        self.GetDlgItem(win32ui.IDC_RADIO1).SetCheck(butMarginEnabled)
        self.GetDlgItem(win32ui.IDC_RADIO2).SetCheck(not butMarginEnabled)

        self.edgeColor = self.initialEdgeColor = GetEditorOption(
            "Right Edge Color", win32api.RGB(0xEF, 0xEF, 0xEF))
        for spinner_id in (win32ui.IDC_SPIN1, win32ui.IDC_SPIN2,
                           win32ui.IDC_SPIN3):
            spinner = self.GetDlgItem(spinner_id)
            spinner.SetRange(0, 100)
        self.UpdateUIForState()

        return rc
Example #3
0
	def __init__(self):
		dialog.PropertyPage.__init__(self, win32ui.IDD_PP_EDITOR)
		self.autooptions = []
		self._AddEditorOption(win32ui.IDC_AUTO_RELOAD, "i", "Auto Reload", 1)
		self._AddEditorOption(win32ui.IDC_COMBO1, "i", "Backup Type", document.BAK_DOT_BAK_BAK_DIR)
		self._AddEditorOption(win32ui.IDC_AUTOCOMPLETE, "i", "Autocomplete Attributes", 1)
		self._AddEditorOption(win32ui.IDC_CALLTIPS, "i", "Show Call Tips", 1)
		self._AddEditorOption(win32ui.IDC_MARGIN_LINENUMBER, "i", "Line Number Margin Width", 0)
		self._AddEditorOption(win32ui.IDC_RADIO1, "i", "MarkersInMargin", None)
		self._AddEditorOption(win32ui.IDC_MARGIN_MARKER, "i", "Marker Margin Width", None)
		self["Marker Margin Width"] = GetEditorOption("Marker Margin Width", 16)

		# Folding		
		self._AddEditorOption(win32ui.IDC_MARGIN_FOLD, "i", "Fold Margin Width", 12)
		self._AddEditorOption(win32ui.IDC_FOLD_ENABLE, "i", "Enable Folding", 1)
		self._AddEditorOption(win32ui.IDC_FOLD_ON_OPEN, "i", "Fold On Open", 0)
		self._AddEditorOption(win32ui.IDC_FOLD_SHOW_LINES, "i", "Fold Lines", 1)

		# Right edge.
		self._AddEditorOption(win32ui.IDC_RIGHTEDGE_ENABLE, "i", "Right Edge Enabled", 0)
		self._AddEditorOption(win32ui.IDC_RIGHTEDGE_COLUMN, "i", "Right Edge Column", 75)

		# Source control, etc		
		self.AddDDX(win32ui.IDC_VSS_INTEGRATE, "bVSS")
		self.AddDDX(win32ui.IDC_KEYBOARD_CONFIG, "Configs", "l")
		self["Configs"] = pywin.scintilla.config.find_config_files()
Example #4
0
	def OnOK(self):
		for name, defVal in self.autooptions:
			SetEditorOption(name, self[name])
		# Margin width gets handled differently.
		if self['MarkersInMargin'] == 0:
			SetEditorOption("Marker Margin Width", self["Marker Margin Width"])
		else:
			SetEditorOption("Marker Margin Width", 0)
		if self.edgeColor != self.initialEdgeColor:
			SetEditorOption("Right Edge Color", self.edgeColor)
		if self['bVSS']:
			SetEditorOption("Source Control Module", "pywin.framework.editor.vss")
		else:
			if GetEditorOption("Source Control Module", "")=='pywin.framework.editor.vss':
				SetEditorOption("Source Control Module", "")
		# Keyboard config
		configname = self.GetDlgItem(win32ui.IDC_KEYBOARD_CONFIG).GetWindowText()
		if configname:
			if configname == "default":
				DeleteEditorOption("Keyboard Config")
			else:
				SetEditorOption("Keyboard Config", configname)

			import pywin.scintilla.view
			pywin.scintilla.view.LoadConfiguration()

		# Now tell all views we have changed.
##		for doc in editorTemplate.GetDocumentList():
##			for view in doc.GetAllViews():
##				try:
##					fn = view.OnConfigChange
##				except AttributeError:
##					continue
##				fn()
		return 1
Example #5
0
	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())
Example #6
0
	def _AddEditorOption(self, idd, typ, optionName, defaultVal):
		self.AddDDX(idd, optionName, typ)
		# some options are "derived" - ie, can be implied from others
		# (eg, "view markers in background" is implied from "markerMarginWidth==0"
		# So we don't actually store these values, but they do still get DDX support.
		if defaultVal is not None:
			self[optionName] = GetEditorOption(optionName, defaultVal)
			self.autooptions.append((optionName, defaultVal))
Example #7
0
	def __init__(self, doc):
		ParentEditorView.__init__(self, doc)
		if isRichText:
			self.SetWordWrap(win32ui.CRichEditView_WrapNone)

		self.addToMRU = 1
		self.HookHandlers()
		self.bCheckingFile = 0
		
		self.defCharFormat = GetEditorFontOption("Default Font", defaultCharacterFormat)

		# Smart tabs override everything else if context can be worked out.
		self.bSmartTabs = GetEditorOption("Smart Tabs", 1)

		self.tabSize = GetEditorOption("Tab Size", 8)
		self.indentSize = GetEditorOption("Indent Size", 8)
		# If next indent is at a tab position, and useTabs is set, a tab will be inserted.
		self.bUseTabs = GetEditorOption("Use Tabs", 1)
Example #8
0
	def OnInitDialog(self):
		for name, val in self.autooptions:
			self[name] = GetEditorOption(name, val)

		rc = dialog.PropertyPage.OnInitDialog(self)

		idc = win32ui.IDC_TABTIMMY_NONE
		if GetEditorOption("Use Tab Timmy", 1):
			idc = win32ui.IDC_TABTIMMY_IND
		self.GetDlgItem(idc).SetCheck(1)

		idc = win32ui.IDC_RADIO1
		if GetEditorOption("Use Tabs", 0):
			idc = win32ui.IDC_USE_TABS
		self.GetDlgItem(idc).SetCheck(1)

		tt_color = GetEditorOption("Tab Timmy Color", win32api.RGB(0xff, 0, 0))
		self.cbo = self.GetDlgItem(win32ui.IDC_COMBO1)
		for c in paletteVGA:
			self.cbo.AddString(c[0])
		sel = 0
		for c in paletteVGA:
			if tt_color == win32api.RGB(c[1], c[2], c[3]):
				break
			sel = sel + 1
		else:
			sel = -1
		self.cbo.SetCurSel(sel)
		self.HookCommand(self.OnButSimple, win32ui.IDC_TABTIMMY_NONE)
		self.HookCommand(self.OnButSimple, win32ui.IDC_TABTIMMY_IND)
		self.HookCommand(self.OnButSimple, win32ui.IDC_TABTIMMY_BG)
		# Set ranges for the spinners.
		for spinner_id in [win32ui.IDC_SPIN1, win32ui.IDC_SPIN2]:
			spinner = self.GetDlgItem(spinner_id)
			spinner.SetRange(1, 16)
		return rc
Example #9
0
	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())
Example #10
0
	def DoConfigChange(self):
		SyntEditViewParent.DoConfigChange(self)
		tabSize = GetEditorOption("Tab Size", 4, 2)
		indentSize = GetEditorOption("Indent Size", 4, 2)
		bUseTabs = GetEditorOption("Use Tabs", 0)
		bSmartTabs = GetEditorOption("Smart Tabs", 1)
		ext = self.idle.IDLEExtension("AutoIndent") # Required extension.

		self.SCISetViewWS( GetEditorOption("View Whitespace", 0) )
		self.SCISetViewEOL( GetEditorOption("View EOL", 0) )
		self.SCISetIndentationGuides( GetEditorOption("View Indentation Guides", 0) )

		if GetEditorOption("Right Edge Enabled", 0):
			mode = EDGE_BACKGROUND
		else:
			mode = EDGE_NONE
		self.SCISetEdgeMode(mode)
		self.SCISetEdgeColumn( GetEditorOption("Right Edge Column", 75) )
		self.SCISetEdgeColor( GetEditorOption("Right Edge Color", win32api.RGB(0xef, 0xef, 0xef)))

		width = GetEditorOption("Marker Margin Width", 16)
		self.SCISetMarginWidthN(1, width)
		width = GetEditorOption("Folding Margin Width", 12)
		self.SCISetMarginWidthN(2, width)
		width = GetEditorOption("Line Number Margin Width", 0)
		self.SCISetMarginWidthN(0, width)
		self.bFolding = GetEditorOption("Enable Folding", 1)
		fold_flags = 0
		self.SendScintilla(SCI_SETMODEVENTMASK, SC_MOD_CHANGEFOLD);
		if self.bFolding:
			if GetEditorOption("Fold Lines", 1):
				fold_flags = 16

		self.SCISetProperty("fold", self.bFolding)
		self.SCISetFoldFlags(fold_flags)

		tt_color = GetEditorOption("Tab Timmy Color", win32api.RGB(0xff, 0, 0))
		self.SendScintilla(SCI_INDICSETFORE, 1, tt_color)

		tt_use = GetEditorOption("Use Tab Timmy", 1)
		if tt_use:
			self.SCISetProperty("tab.timmy.whinge.level", "1")

		# Auto-indent has very complicated behaviour.  In a nutshell, the only
		# way to get sensible behaviour from it is to ensure tabwidth != indentsize.
		# Further, usetabs will only ever go from 1->0, never 0->1.
		# This is _not_ the behaviour Pythonwin wants:
		# * Tab width is arbitary, so should have no impact on smarts.
		# * bUseTabs setting should reflect how new files are created, and
		#   if Smart Tabs disabled, existing files are edited
		# * If "Smart Tabs" is enabled, bUseTabs should have no bearing
		#   for existing files (unless of course no context can be determined)
		#
		# So for smart tabs we configure the widget with completely dummy
		# values (ensuring tabwidth != indentwidth), ask it to guess, then
		# look at the values it has guessed, and re-configure
		if bSmartTabs:
			ext.config(usetabs=1, tabwidth=5, indentwidth=4)
			ext.set_indentation_params(1)
			if ext.indentwidth==5:
				# Either 5 literal spaces, or a single tab character. Assume a tab
				usetabs = 1
				indentwidth = tabSize
			else:
				# Either Indented with spaces, and indent size has been guessed or
				# an empty file (or no context found - tough!)
				if self.GetTextLength()==0: # emtpy
					usetabs = bUseTabs
					indentwidth = indentSize
				else: # guessed.
					indentwidth = ext.indentwidth
					usetabs = 0
			# Tab size can never be guessed - set at user preference.
			ext.config(usetabs=usetabs, indentwidth=indentwidth, tabwidth=tabSize)
		else:
			# Dont want smart-tabs - just set the options!
			ext.config(usetabs=bUseTabs, tabwidth=tabSize, indentwidth=indentSize)
		self.SCISetIndent(indentSize)
		self.SCISetTabWidth(tabSize)
Example #11
0
	def _AddEditorOption(self, idd, typ, optionName, defaultVal):
		self.AddDDX(idd, optionName, typ)
		self[optionName] = GetEditorOption(optionName, defaultVal)
		self.autooptions.append((optionName, defaultVal))
Example #12
0
	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()
Example #13
0
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 as details:
            win32ui.MessageBox("Error - could not save file\r\n\r\n%s" % details)
            return 0
        except (UnicodeEncodeError, LookupError) as details:
            rc = win32ui.MessageBox(
                "Encoding failed: \r\n%s" % details
                + "\r\nPlease add desired source encoding as first line of file, eg \r\n"
                + "# -*- coding: mbcs -*-\r\n\r\n"
                + "If you continue, the file will be saved as binary and will\r\n"
                + "not be valid in the declared encoding.\r\n\r\n"
                + "Save the file as binary with an invalid encoding?",
                "File save failed",
                win32con.MB_YESNO | win32con.MB_DEFBUTTON2,
            )
            if rc == win32con.IDYES:
                try:
                    self.SaveFile(fileName, encoding="latin-1")
                except IOError as details:
                    win32ui.MessageBox(
                        "Error - could not save file\r\n\r\n%s" % details
                    )
                    return 0
            else:
                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 as 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()
Example #14
0
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 as details:
			win32ui.MessageBox("Error - could not save file\r\n\r\n%s"%details)
			return 0
		except (UnicodeEncodeError, LookupError) as details:
			rc = win32ui.MessageBox("Encoding failed: \r\n%s"%details +
					'\r\nPlease add desired source encoding as first line of file, eg \r\n' +
					'# -*- coding: mbcs -*-\r\n\r\n' +
					'If you continue, the file will be saved as binary and will\r\n' +
					'not be valid in the declared encoding.\r\n\r\n' +
					'Save the file as binary with an invalid encoding?',
					"File save failed",
					win32con.MB_YESNO | win32con.MB_DEFBUTTON2)
			if rc==win32con.IDYES:
				try:
					self.SaveFile(fileName, encoding="latin-1")
				except IOError as details:
					win32ui.MessageBox("Error - could not save file\r\n\r\n%s"%details)
					return 0
			else:
				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 as 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()