src/eric7/QScintilla/Editor.py

branch
eric7
changeset 10377
9f6ffcd1db54
parent 10376
4146ac0fd307
child 10388
a34ce7f42e8b
equal deleted inserted replaced
10376:4146ac0fd307 10377:9f6ffcd1db54
630 @param name name of the current file 630 @param name name of the current file
631 @type str 631 @type str
632 """ 632 """
633 renamed = self.fileName != name 633 renamed = self.fileName != name
634 634
635 oldFileName = self.fileName
635 self.fileName = name 636 self.fileName = name
636 637
637 if renamed: 638 if renamed:
638 self.vm.setEditorName(self, self.fileName) 639 self.vm.setEditorName(self, self.fileName)
640 self.vm.removeWatchedFilePath(oldFileName)
641 self.vm.addWatchedFilePath(self.fileName)
639 642
640 if self.fileName: 643 if self.fileName:
641 self.__fileNameExtension = os.path.splitext(self.fileName)[1][1:].lower() 644 self.__fileNameExtension = os.path.splitext(self.fileName)[1][1:].lower()
642 else: 645 else:
643 self.__fileNameExtension = "" 646 self.__fileNameExtension = ""
3373 self.redo() 3376 self.redo()
3374 else: 3377 else:
3375 break 3378 break
3376 # Couldn't find the unmodified state 3379 # Couldn't find the unmodified state
3377 3380
3378 def readFile(self, fn, createIt=False, encoding=""): 3381 def readFile(self, fn, createIt=False, encoding="", noempty=False):
3379 """ 3382 """
3380 Public method to read the text from a file. 3383 Public method to read the text from a file.
3381 3384
3382 @param fn filename to read from (string) 3385 @param fn filename to read from
3386 @type str
3383 @param createIt flag indicating the creation of a new file, if the 3387 @param createIt flag indicating the creation of a new file, if the
3384 given one doesn't exist (boolean) 3388 given one doesn't exist (defaults to False)
3385 @param encoding encoding to be used to read the file (string) 3389 @type bool (optional)
3390 @param encoding encoding to be used to read the file (defaults to "")
3386 (Note: this parameter overrides encoding detection) 3391 (Note: this parameter overrides encoding detection)
3392 @type str (optional)
3393 @param noempty flag indicating to not set an empty text (defaults to False)
3394 @type bool (optional)
3387 """ 3395 """
3388 self.__loadEditorConfig(fileName=fn) 3396 self.__loadEditorConfig(fileName=fn)
3389 3397
3390 try: 3398 try:
3391 with EricOverrideCursor(): 3399 with EricOverrideCursor():
3408 "<p>The file <b>{0}</b> could not be opened.</p>" 3416 "<p>The file <b>{0}</b> could not be opened.</p>"
3409 "<p>Reason: {1}</p>" 3417 "<p>Reason: {1}</p>"
3410 ).format(fn, str(why)), 3418 ).format(fn, str(why)),
3411 ) 3419 )
3412 raise 3420 raise
3421
3422 if noempty and not bool(txt):
3423 return
3413 3424
3414 with EricOverrideCursor(): 3425 with EricOverrideCursor():
3415 modified = False 3426 modified = False
3416 3427
3417 self.setText(txt) 3428 self.setText(txt)
7772 7783
7773 @param event the event object 7784 @param event the event object
7774 @type QFocusEvent 7785 @type QFocusEvent
7775 """ 7786 """
7776 self.recolor() 7787 self.recolor()
7788
7777 self.vm.editActGrp.setEnabled(True) 7789 self.vm.editActGrp.setEnabled(True)
7778 self.vm.editorActGrp.setEnabled(True) 7790 self.vm.editorActGrp.setEnabled(True)
7779 self.vm.copyActGrp.setEnabled(True) 7791 self.vm.copyActGrp.setEnabled(True)
7780 self.vm.viewActGrp.setEnabled(True) 7792 self.vm.viewActGrp.setEnabled(True)
7781 self.vm.searchActGrp.setEnabled(True) 7793 self.vm.searchActGrp.setEnabled(True)
7794
7782 with contextlib.suppress(AttributeError): 7795 with contextlib.suppress(AttributeError):
7783 self.setCaretWidth(self.caretWidth) 7796 self.setCaretWidth(self.caretWidth)
7784 self.__updateReadOnly(False) 7797 self.__updateReadOnly(False)
7785 # TODO: realize this with a QFileSystemWatcher in ViewManager 7798 self.setCursorFlashTime(QApplication.cursorFlashTime())
7799
7800 super().focusInEvent(event)
7801
7802 def focusOutEvent(self, event):
7803 """
7804 Protected method called when the editor loses focus.
7805
7806 @param event the event object
7807 @type QFocusEvent
7808 """
7809 if Preferences.getEditor("AutosaveOnFocusLost") and self.__shouldAutosave():
7810 self.saveFile()
7811
7812 self.vm.editorActGrp.setEnabled(False)
7813 self.setCaretWidth(0)
7814
7815 self.cancelCallTips()
7816
7817 super().focusOutEvent(event)
7818
7819 def changeEvent(self, evt):
7820 """
7821 Protected method called to process an event.
7822
7823 This implements special handling for the events showMaximized,
7824 showMinimized and showNormal. The windows caption is shortened
7825 for the minimized mode and reset to the full filename for the
7826 other modes. This is to make the editor windows work nicer
7827 with the QWorkspace.
7828
7829 @param evt the event, that was generated
7830 @type QEvent
7831 """
7832 if evt.type() == QEvent.Type.WindowStateChange and bool(self.fileName):
7833 cap = (
7834 os.path.basename(self.fileName)
7835 if self.windowState() == Qt.WindowState.WindowMinimized
7836 else self.fileName
7837 )
7838 if self.checkReadOnly():
7839 cap = self.tr("{0} (ro)").format(cap)
7840 self.setWindowTitle(cap)
7841
7842 super().changeEvent(evt)
7843
7844 def mousePressEvent(self, event):
7845 """
7846 Protected method to handle the mouse press event.
7847
7848 @param event the mouse press event
7849 @type QMouseEvent
7850 """
7851 if event.button() == Qt.MouseButton.XButton1:
7852 self.undo()
7853 event.accept()
7854 elif event.button() == Qt.MouseButton.XButton2:
7855 self.redo()
7856 event.accept()
7857 elif event.button() == Qt.MouseButton.LeftButton and bool(
7858 event.modifiers()
7859 & (Qt.KeyboardModifier.MetaModifier | Qt.KeyboardModifier.AltModifier)
7860 ):
7861 line, index = self.lineIndexFromPoint(event.position().toPoint())
7862 self.addCursor(line, index)
7863 event.accept()
7864 else:
7865 self.vm.eventFilter(self, event)
7866 super().mousePressEvent(event)
7867
7868 def mouseDoubleClickEvent(self, evt):
7869 """
7870 Protected method to handle mouse double click events.
7871
7872 @param evt reference to the mouse event
7873 @type QMouseEvent
7874 """
7875 super().mouseDoubleClickEvent(evt)
7876
7877 # accept all double click events even if not handled by QScintilla
7878 evt.accept()
7879
7880 self.mouseDoubleClick.emit(evt.position().toPoint(), evt.buttons())
7881
7882 def wheelEvent(self, evt):
7883 """
7884 Protected method to handle wheel events.
7885
7886 @param evt reference to the wheel event
7887 @type QWheelEvent
7888 """
7889 delta = evt.angleDelta().y()
7890 if evt.modifiers() & Qt.KeyboardModifier.ControlModifier:
7891 if delta < 0:
7892 self.zoomOut()
7893 elif delta > 0:
7894 self.zoomIn()
7895 evt.accept()
7896 return
7897
7898 if evt.modifiers() & Qt.KeyboardModifier.ShiftModifier:
7899 if delta < 0:
7900 self.gotoMethodClass(False)
7901 elif delta > 0:
7902 self.gotoMethodClass(True)
7903 evt.accept()
7904 return
7905
7906 super().wheelEvent(evt)
7907
7908 def event(self, evt):
7909 """
7910 Public method handling events.
7911
7912 @param evt reference to the event
7913 @type QEvent
7914 @return flag indicating, if the event was handled
7915 @rtype bool
7916 """
7917 if evt.type() == QEvent.Type.Gesture:
7918 self.gestureEvent(evt)
7919 return True
7920
7921 return super().event(evt)
7922
7923 def gestureEvent(self, evt):
7924 """
7925 Protected method handling gesture events.
7926
7927 @param evt reference to the gesture event
7928 @type QGestureEvent
7929 """
7930 pinch = evt.gesture(Qt.GestureType.PinchGesture)
7931 if pinch:
7932 if pinch.state() == Qt.GestureState.GestureStarted:
7933 zoom = (self.getZoom() + 10) / 10.0
7934 pinch.setTotalScaleFactor(zoom)
7935 elif pinch.state() == Qt.GestureState.GestureUpdated:
7936 zoom = int(pinch.totalScaleFactor() * 10) - 10
7937 if zoom <= -9:
7938 zoom = -9
7939 pinch.setTotalScaleFactor(0.1)
7940 elif zoom >= 20:
7941 zoom = 20
7942 pinch.setTotalScaleFactor(3.0)
7943 self.zoomTo(zoom)
7944 evt.accept()
7945
7946 def resizeEvent(self, evt):
7947 """
7948 Protected method handling resize events.
7949
7950 @param evt reference to the resize event
7951 @type QResizeEvent
7952 """
7953 super().resizeEvent(evt)
7954 self.__markerMap.calculateGeometry()
7955
7956 def viewportEvent(self, evt):
7957 """
7958 Protected method handling event of the viewport.
7959
7960 @param evt reference to the event
7961 @type QEvent
7962 @return flag indiating that the event was handled
7963 @rtype bool
7964 """
7965 with contextlib.suppress(AttributeError):
7966 self.__markerMap.calculateGeometry()
7967 return super().viewportEvent(evt)
7968
7969 def __updateReadOnly(self, bForce=True):
7970 """
7971 Private method to update the readOnly information for this editor.
7972
7973 If bForce is True, then updates everything regardless if
7974 the attributes have actually changed, such as during
7975 initialization time. A signal is emitted after the
7976 caption change.
7977
7978 @param bForce True to force change, False to only update and emit
7979 signal if there was an attribute change.
7980 """
7981 if self.fileName == "" or not self.isLocalFile():
7982 return
7983
7984 readOnly = self.checkReadOnly()
7985 if not bForce and (readOnly == self.isReadOnly()):
7986 return
7987
7988 cap = self.fileName
7989 if readOnly:
7990 cap = self.tr("{0} (ro)".format(cap))
7991 self.setReadOnly(readOnly)
7992 self.setWindowTitle(cap)
7993 self.captionChanged.emit(cap, self)
7994
7995 def checkReadOnly(self):
7996 """
7997 Public method to check the 'read only' state.
7998
7999 @return flag indicate a 'read only' state
8000 @rtype bool
8001 """
8002 return (
8003 self.isLocalFile() and not os.access(self.fileName, os.W_OK)
8004 ) or self.isReadOnly()
8005
8006 @pyqtSlot()
8007 def checkRereadFile(self):
8008 """
8009 Public slot to check, if the file needs to be re-read, and refresh it if
8010 needed.
8011 """
7786 if ( 8012 if (
7787 self.vm.editorsCheckFocusInEnabled() 8013 self.fileName
7788 and not self.inReopenPrompt
7789 and self.fileName
7790 and pathlib.Path(self.fileName).exists() 8014 and pathlib.Path(self.fileName).exists()
7791 and pathlib.Path(self.fileName).stat().st_mtime != self.lastModified 8015 and pathlib.Path(self.fileName).stat().st_mtime != self.lastModified
7792 ): 8016 ):
7793 self.inReopenPrompt = True
7794 if Preferences.getEditor("AutoReopen") and not self.isModified(): 8017 if Preferences.getEditor("AutoReopen") and not self.isModified():
7795 self.refresh() 8018 self.refresh()
7796 else: 8019 else:
7797 msg = self.tr( 8020 msg = self.tr(
7798 """<p>The file <b>{0}</b> has been changed while it""" 8021 """<p>The file <b>{0}</b> has been changed while it"""
7815 if res: 8038 if res:
7816 self.refresh() 8039 self.refresh()
7817 else: 8040 else:
7818 # do not prompt for this change again... 8041 # do not prompt for this change again...
7819 self.lastModified = pathlib.Path(self.fileName).stat().st_mtime 8042 self.lastModified = pathlib.Path(self.fileName).stat().st_mtime
7820 self.inReopenPrompt = False 8043
7821 8044 @pyqtSlot()
7822 self.setCursorFlashTime(QApplication.cursorFlashTime()) 8045 def recordModificationTime(self):
7823 8046 """
7824 super().focusInEvent(event) 8047 Public slot to record the modification time of our file.
7825 8048 """
7826 def focusOutEvent(self, event): 8049 if self.fileName and pathlib.Path(self.fileName).exists():
7827 """ 8050 self.lastModified = pathlib.Path(self.fileName).stat().st_mtime
7828 Protected method called when the editor loses focus.
7829
7830 @param event the event object
7831 @type QFocusEvent
7832 """
7833 if Preferences.getEditor("AutosaveOnFocusLost") and self.__shouldAutosave():
7834 self.saveFile()
7835
7836 self.vm.editorActGrp.setEnabled(False)
7837 self.setCaretWidth(0)
7838
7839 self.cancelCallTips()
7840
7841 super().focusOutEvent(event)
7842
7843 def changeEvent(self, evt):
7844 """
7845 Protected method called to process an event.
7846
7847 This implements special handling for the events showMaximized,
7848 showMinimized and showNormal. The windows caption is shortened
7849 for the minimized mode and reset to the full filename for the
7850 other modes. This is to make the editor windows work nicer
7851 with the QWorkspace.
7852
7853 @param evt the event, that was generated
7854 @type QEvent
7855 """
7856 if evt.type() == QEvent.Type.WindowStateChange and bool(self.fileName):
7857 cap = (
7858 os.path.basename(self.fileName)
7859 if self.windowState() == Qt.WindowState.WindowMinimized
7860 else self.fileName
7861 )
7862 if self.checkReadOnly():
7863 cap = self.tr("{0} (ro)").format(cap)
7864 self.setWindowTitle(cap)
7865
7866 super().changeEvent(evt)
7867
7868 def mousePressEvent(self, event):
7869 """
7870 Protected method to handle the mouse press event.
7871
7872 @param event the mouse press event
7873 @type QMouseEvent
7874 """
7875 if event.button() == Qt.MouseButton.XButton1:
7876 self.undo()
7877 event.accept()
7878 elif event.button() == Qt.MouseButton.XButton2:
7879 self.redo()
7880 event.accept()
7881 elif event.button() == Qt.MouseButton.LeftButton and bool(
7882 event.modifiers()
7883 & (Qt.KeyboardModifier.MetaModifier | Qt.KeyboardModifier.AltModifier)
7884 ):
7885 line, index = self.lineIndexFromPoint(event.position().toPoint())
7886 self.addCursor(line, index)
7887 event.accept()
7888 else:
7889 self.vm.eventFilter(self, event)
7890 super().mousePressEvent(event)
7891
7892 def mouseDoubleClickEvent(self, evt):
7893 """
7894 Protected method to handle mouse double click events.
7895
7896 @param evt reference to the mouse event
7897 @type QMouseEvent
7898 """
7899 super().mouseDoubleClickEvent(evt)
7900
7901 # accept all double click events even if not handled by QScintilla
7902 evt.accept()
7903
7904 self.mouseDoubleClick.emit(evt.position().toPoint(), evt.buttons())
7905
7906 def wheelEvent(self, evt):
7907 """
7908 Protected method to handle wheel events.
7909
7910 @param evt reference to the wheel event
7911 @type QWheelEvent
7912 """
7913 delta = evt.angleDelta().y()
7914 if evt.modifiers() & Qt.KeyboardModifier.ControlModifier:
7915 if delta < 0:
7916 self.zoomOut()
7917 elif delta > 0:
7918 self.zoomIn()
7919 evt.accept()
7920 return
7921
7922 if evt.modifiers() & Qt.KeyboardModifier.ShiftModifier:
7923 if delta < 0:
7924 self.gotoMethodClass(False)
7925 elif delta > 0:
7926 self.gotoMethodClass(True)
7927 evt.accept()
7928 return
7929
7930 super().wheelEvent(evt)
7931
7932 def event(self, evt):
7933 """
7934 Public method handling events.
7935
7936 @param evt reference to the event
7937 @type QEvent
7938 @return flag indicating, if the event was handled
7939 @rtype bool
7940 """
7941 if evt.type() == QEvent.Type.Gesture:
7942 self.gestureEvent(evt)
7943 return True
7944
7945 return super().event(evt)
7946
7947 def gestureEvent(self, evt):
7948 """
7949 Protected method handling gesture events.
7950
7951 @param evt reference to the gesture event
7952 @type QGestureEvent
7953 """
7954 pinch = evt.gesture(Qt.GestureType.PinchGesture)
7955 if pinch:
7956 if pinch.state() == Qt.GestureState.GestureStarted:
7957 zoom = (self.getZoom() + 10) / 10.0
7958 pinch.setTotalScaleFactor(zoom)
7959 elif pinch.state() == Qt.GestureState.GestureUpdated:
7960 zoom = int(pinch.totalScaleFactor() * 10) - 10
7961 if zoom <= -9:
7962 zoom = -9
7963 pinch.setTotalScaleFactor(0.1)
7964 elif zoom >= 20:
7965 zoom = 20
7966 pinch.setTotalScaleFactor(3.0)
7967 self.zoomTo(zoom)
7968 evt.accept()
7969
7970 def resizeEvent(self, evt):
7971 """
7972 Protected method handling resize events.
7973
7974 @param evt reference to the resize event
7975 @type QResizeEvent
7976 """
7977 super().resizeEvent(evt)
7978 self.__markerMap.calculateGeometry()
7979
7980 def viewportEvent(self, evt):
7981 """
7982 Protected method handling event of the viewport.
7983
7984 @param evt reference to the event
7985 @type QEvent
7986 @return flag indiating that the event was handled
7987 @rtype bool
7988 """
7989 with contextlib.suppress(AttributeError):
7990 self.__markerMap.calculateGeometry()
7991 return super().viewportEvent(evt)
7992
7993 def __updateReadOnly(self, bForce=True):
7994 """
7995 Private method to update the readOnly information for this editor.
7996
7997 If bForce is True, then updates everything regardless if
7998 the attributes have actually changed, such as during
7999 initialization time. A signal is emitted after the
8000 caption change.
8001
8002 @param bForce True to force change, False to only update and emit
8003 signal if there was an attribute change.
8004 """
8005 if self.fileName == "" or not self.isLocalFile():
8006 return
8007
8008 readOnly = self.checkReadOnly()
8009 if not bForce and (readOnly == self.isReadOnly()):
8010 return
8011
8012 cap = self.fileName
8013 if readOnly:
8014 cap = self.tr("{0} (ro)".format(cap))
8015 self.setReadOnly(readOnly)
8016 self.setWindowTitle(cap)
8017 self.captionChanged.emit(cap, self)
8018
8019 def checkReadOnly(self):
8020 """
8021 Public method to check the 'read only' state.
8022
8023 @return flag indicate a 'read only' state
8024 @rtype bool
8025 """
8026 return (
8027 self.isLocalFile() and not os.access(self.fileName, os.W_OK)
8028 ) or self.isReadOnly()
8029 8051
8030 @pyqtSlot() 8052 @pyqtSlot()
8031 def refresh(self): 8053 def refresh(self):
8032 """ 8054 """
8033 Public slot to refresh the editor contents. 8055 Public slot to refresh the editor contents.
8055 self.close() 8077 self.close()
8056 return 8078 return
8057 8079
8058 # reread the file 8080 # reread the file
8059 try: 8081 try:
8060 self.readFile(self.fileName) 8082 self.readFile(self.fileName, noempty=True)
8061 except OSError: 8083 except OSError:
8062 # do not prompt for this change again... 8084 # do not prompt for this change again...
8063 self.lastModified = QDateTime.currentDateTime() 8085 self.lastModified = QDateTime.currentDateTime()
8064 self.setModified(False) 8086 self.setModified(False)
8065 self.__convertTabs() 8087 self.__convertTabs()

eric ide

mercurial