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. |