10 import bisect |
10 import bisect |
11 import collections |
11 import collections |
12 import contextlib |
12 import contextlib |
13 import difflib |
13 import difflib |
14 import os |
14 import os |
|
15 import pathlib |
15 import re |
16 import re |
16 |
17 |
17 import editorconfig |
18 import editorconfig |
18 |
19 |
19 from PyQt6.QtCore import ( |
20 from PyQt6.QtCore import ( |
20 pyqtSignal, pyqtSlot, Qt, QDir, QTimer, QModelIndex, QFileInfo, |
21 pyqtSignal, pyqtSlot, Qt, QDir, QTimer, QModelIndex, QCryptographicHash, |
21 QCryptographicHash, QEvent, QDateTime, QPoint, QSize |
22 QEvent, QDateTime, QPoint, QSize |
22 ) |
23 ) |
23 from PyQt6.QtGui import QPalette, QFont, QPixmap, QPainter, QActionGroup |
24 from PyQt6.QtGui import QPalette, QFont, QPixmap, QPainter, QActionGroup |
24 from PyQt6.QtWidgets import ( |
25 from PyQt6.QtWidgets import ( |
25 QLineEdit, QDialog, QInputDialog, QApplication, QMenu |
26 QLineEdit, QDialog, QInputDialog, QApplication, QMenu |
26 ) |
27 ) |
395 |
396 |
396 self.isResourcesFile = False |
397 self.isResourcesFile = False |
397 if editor is None: |
398 if editor is None: |
398 if self.fileName: |
399 if self.fileName: |
399 if ( |
400 if ( |
400 (QFileInfo(self.fileName).size() // 1024) > |
401 (pathlib.Path(self.fileName).stat().st_size // 1024) > |
401 Preferences.getEditor("WarnFilesize") |
402 Preferences.getEditor("WarnFilesize") |
402 ): |
403 ): |
403 res = EricMessageBox.yesNo( |
404 res = EricMessageBox.yesNo( |
404 self, |
405 self, |
405 self.tr("Open File"), |
406 self.tr("Open File"), |
406 self.tr("""<p>The size of the file <b>{0}</b>""" |
407 self.tr("""<p>The size of the file <b>{0}</b>""" |
407 """ is <b>{1} KB</b>.""" |
408 """ is <b>{1} KB</b>.""" |
408 """ Do you really want to load it?</p>""") |
409 """ Do you really want to load it?</p>""") |
409 .format(self.fileName, |
410 .format( |
410 QFileInfo(self.fileName).size() // 1024), |
411 self.fileName, |
|
412 pathlib.Path(self.fileName).stat().st_size // 1024 |
|
413 ), |
411 icon=EricMessageBox.Warning) |
414 icon=EricMessageBox.Warning) |
412 if not res: |
415 if not res: |
413 raise OSError() |
416 raise OSError() |
414 self.readFile(self.fileName, True) |
417 self.readFile(self.fileName, True) |
415 self.__bindLexer(self.fileName) |
418 self.__bindLexer(self.fileName) |
1966 m and self. |
1969 m and self. |
1967 |
1970 |
1968 @param m modification status |
1971 @param m modification status |
1969 """ |
1972 """ |
1970 if not m and bool(self.fileName): |
1973 if not m and bool(self.fileName): |
1971 self.lastModified = QFileInfo(self.fileName).lastModified() |
1974 self.lastModified = pathlib.Path(self.fileName).stat().st_mtime |
1972 self.modificationStatusChanged.emit(m, self) |
1975 self.modificationStatusChanged.emit(m, self) |
1973 self.undoAvailable.emit(self.isUndoAvailable()) |
1976 self.undoAvailable.emit(self.isUndoAvailable()) |
1974 self.redoAvailable.emit(self.isRedoAvailable()) |
1977 self.redoAvailable.emit(self.isRedoAvailable()) |
1975 |
1978 |
1976 def __cursorPositionChanged(self, line, index): |
1979 def __cursorPositionChanged(self, line, index): |
3228 self.setEolModeByEolString(fileEol) |
3231 self.setEolModeByEolString(fileEol) |
3229 |
3232 |
3230 self.extractTasks() |
3233 self.extractTasks() |
3231 |
3234 |
3232 self.setModified(modified) |
3235 self.setModified(modified) |
3233 self.lastModified = QFileInfo(self.fileName).lastModified() |
3236 self.lastModified = pathlib.Path(fn).stat().st_mtime |
3234 |
3237 |
3235 def __convertTabs(self): |
3238 def __convertTabs(self): |
3236 """ |
3239 """ |
3237 Private slot to convert tabulators to spaces. |
3240 Private slot to convert tabulators to spaces. |
3238 """ |
3241 """ |
3374 |
3377 |
3375 if fn: |
3378 if fn: |
3376 if fn.endswith("."): |
3379 if fn.endswith("."): |
3377 fn = fn[:-1] |
3380 fn = fn[:-1] |
3378 |
3381 |
3379 ext = QFileInfo(fn).suffix() |
3382 fpath = pathlib.Path(fn) |
3380 if not ext: |
3383 if not fpath.suffix: |
3381 ex = selectedFilter.split("(*")[1].split(")")[0] |
3384 ex = selectedFilter.split("(*")[1].split(")")[0] |
3382 if ex: |
3385 if ex: |
3383 fn += ex |
3386 fpath = fpath.with_suffix(ex) |
3384 if QFileInfo(fn).exists(): |
3387 if fpath.exists(): |
3385 res = EricMessageBox.yesNo( |
3388 res = EricMessageBox.yesNo( |
3386 self, |
3389 self, |
3387 self.tr("Save File"), |
3390 self.tr("Save File"), |
3388 self.tr("<p>The file <b>{0}</b> already exists." |
3391 self.tr("<p>The file <b>{0}</b> already exists." |
3389 " Overwrite it?</p>").format(fn), |
3392 " Overwrite it?</p>").format(fpath), |
3390 icon=EricMessageBox.Warning) |
3393 icon=EricMessageBox.Warning) |
3391 if not res: |
3394 if not res: |
3392 return "" |
3395 return "" |
3393 fn = Utilities.toNativeSeparators(fn) |
3396 |
3394 |
3397 return str(fpath) |
3395 return fn |
|
3396 |
3398 |
3397 def saveFileCopy(self, path=None): |
3399 def saveFileCopy(self, path=None): |
3398 """ |
3400 """ |
3399 Public method to save a copy of the file. |
3401 Public method to save a copy of the file. |
3400 |
3402 |
3480 self.project.appendFile(fn) |
3482 self.project.appendFile(fn) |
3481 self.addedToProject() |
3483 self.addedToProject() |
3482 |
3484 |
3483 self.setLanguage(self.fileName) |
3485 self.setLanguage(self.fileName) |
3484 |
3486 |
3485 self.lastModified = QFileInfo(self.fileName).lastModified() |
3487 self.lastModified = pathlib.Path(fn).stat().st_mtime |
3486 if newName is not None: |
3488 if newName is not None: |
3487 self.vm.addToRecentList(newName) |
3489 self.vm.addToRecentList(newName) |
3488 self.editorSaved.emit(self.fileName) |
3490 self.editorSaved.emit(self.fileName) |
3489 self.checkSyntax() |
3491 self.checkSyntax() |
3490 self.extractTasks() |
3492 self.extractTasks() |
3491 self.__resetOnlineChangeTraceInfo() |
3493 self.__resetOnlineChangeTraceInfo() |
3492 self.__checkEncoding() |
3494 self.__checkEncoding() |
3493 return True |
3495 return True |
3494 else: |
3496 else: |
3495 self.lastModified = QFileInfo(fn).lastModified() |
3497 self.lastModified = pathlib.Path(fn).stat().st_mtime |
3496 return False |
3498 return False |
3497 |
3499 |
3498 def saveFileAs(self, path=None, toProject=False): |
3500 def saveFileAs(self, path=None, toProject=False): |
3499 """ |
3501 """ |
3500 Public slot to save a file with a new name. |
3502 Public slot to save a file with a new name. |
3521 self.__loadEditorConfig() |
3523 self.__loadEditorConfig() |
3522 |
3524 |
3523 if self.lexer_ is None: |
3525 if self.lexer_ is None: |
3524 self.setLanguage(self.fileName) |
3526 self.setLanguage(self.fileName) |
3525 |
3527 |
3526 self.lastModified = QFileInfo(self.fileName).lastModified() |
3528 self.lastModified = pathlib.Path(fn).stat().st_mtime |
3527 self.vm.setEditorName(self, self.fileName) |
3529 self.vm.setEditorName(self, self.fileName) |
3528 self.__updateReadOnly(True) |
3530 self.__updateReadOnly(True) |
3529 |
3531 |
3530 def fileRenamed(self, fn): |
3532 def fileRenamed(self, fn): |
3531 """ |
3533 """ |
6873 EricFileDialog.DontConfirmOverwrite) |
6875 EricFileDialog.DontConfirmOverwrite) |
6874 |
6876 |
6875 if not fname: |
6877 if not fname: |
6876 return # user aborted |
6878 return # user aborted |
6877 |
6879 |
6878 ext = QFileInfo(fname).suffix() |
6880 fpath = pathlib.Path(fname) |
6879 if not ext: |
6881 if not fpath.suffix: |
6880 ex = selectedFilter.split("(*")[1].split(")")[0] |
6882 ex = selectedFilter.split("(*")[1].split(")")[0] |
6881 if ex: |
6883 if ex: |
6882 fname += ex |
6884 fpath = fpath.with_suffix(ex) |
6883 if QFileInfo(fname).exists(): |
6885 if fpath.exists(): |
6884 res = EricMessageBox.yesNo( |
6886 res = EricMessageBox.yesNo( |
6885 self, |
6887 self, |
6886 self.tr("Save macro"), |
6888 self.tr("Save macro"), |
6887 self.tr("<p>The macro file <b>{0}</b> already exists." |
6889 self.tr("<p>The macro file <b>{0}</b> already exists." |
6888 " Overwrite it?</p>").format(fname), |
6890 " Overwrite it?</p>").format(fpath), |
6889 icon=EricMessageBox.Warning) |
6891 icon=EricMessageBox.Warning) |
6890 if not res: |
6892 if not res: |
6891 return |
6893 return |
6892 fname = Utilities.toNativeSeparators(fname) |
|
6893 |
6894 |
6894 try: |
6895 try: |
6895 with open(fname, "w", encoding="utf-8") as f: |
6896 with fpath.open("w", encoding="utf-8") as f: |
6896 f.write("{0}{1}".format(name, "\n")) |
6897 f.write("{0}{1}".format(name, "\n")) |
6897 f.write(self.macros[name].save()) |
6898 f.write(self.macros[name].save()) |
6898 except OSError: |
6899 except OSError: |
6899 EricMessageBox.critical( |
6900 EricMessageBox.critical( |
6900 self, |
6901 self, |
6901 self.tr("Error saving macro"), |
6902 self.tr("Error saving macro"), |
6902 self.tr( |
6903 self.tr( |
6903 "<p>The macro file <b>{0}</b> could not be written.</p>") |
6904 "<p>The macro file <b>{0}</b> could not be written.</p>") |
6904 .format(fname)) |
6905 .format(fpath)) |
6905 return |
6906 return |
6906 |
6907 |
6907 def macroRecordingStart(self): |
6908 def macroRecordingStart(self): |
6908 """ |
6909 """ |
6909 Public method to start macro recording. |
6910 Public method to start macro recording. |
7081 self.setCaretWidth(self.caretWidth) |
7082 self.setCaretWidth(self.caretWidth) |
7082 self.__updateReadOnly(False) |
7083 self.__updateReadOnly(False) |
7083 if ( |
7084 if ( |
7084 self.vm.editorsCheckFocusInEnabled() and |
7085 self.vm.editorsCheckFocusInEnabled() and |
7085 not self.inReopenPrompt and self.fileName and |
7086 not self.inReopenPrompt and self.fileName and |
7086 QFileInfo(self.fileName).lastModified().toString() != |
7087 pathlib.Path(self.fileName).stat().st_mtime != self.lastModified |
7087 self.lastModified.toString() |
|
7088 ): |
7088 ): |
7089 self.inReopenPrompt = True |
7089 self.inReopenPrompt = True |
7090 if Preferences.getEditor("AutoReopen") and not self.isModified(): |
7090 if Preferences.getEditor("AutoReopen") and not self.isModified(): |
7091 self.refresh() |
7091 self.refresh() |
7092 else: |
7092 else: |
7107 yesDefault=yesDefault) |
7107 yesDefault=yesDefault) |
7108 if res: |
7108 if res: |
7109 self.refresh() |
7109 self.refresh() |
7110 else: |
7110 else: |
7111 # do not prompt for this change again... |
7111 # do not prompt for this change again... |
7112 self.lastModified = QFileInfo(self.fileName).lastModified() |
7112 self.lastModified = ( |
|
7113 pathlib.Path(self.fileName).stat().st_mtime |
|
7114 ) |
7113 self.inReopenPrompt = False |
7115 self.inReopenPrompt = False |
7114 |
7116 |
7115 self.setCursorFlashTime(QApplication.cursorFlashTime()) |
7117 self.setCursorFlashTime(QApplication.cursorFlashTime()) |
7116 |
7118 |
7117 super().focusInEvent(event) |
7119 super().focusInEvent(event) |
7443 """ |
7445 """ |
7444 if event.mimeData().hasUrls(): |
7446 if event.mimeData().hasUrls(): |
7445 for url in event.mimeData().urls(): |
7447 for url in event.mimeData().urls(): |
7446 fname = url.toLocalFile() |
7448 fname = url.toLocalFile() |
7447 if fname: |
7449 if fname: |
7448 if not QFileInfo(fname).isDir(): |
7450 if not pathlib.Path(fname).is_dir(): |
7449 self.vm.openSourceFile(fname) |
7451 self.vm.openSourceFile(fname) |
7450 else: |
7452 else: |
7451 EricMessageBox.information( |
7453 EricMessageBox.information( |
7452 self, |
7454 self, |
7453 self.tr("Drop Error"), |
7455 self.tr("Drop Error"), |