7 Module implementing a class used to display the parts of the project, that |
7 Module implementing a class used to display the parts of the project, that |
8 don't fit the other categories. |
8 don't fit the other categories. |
9 """ |
9 """ |
10 |
10 |
11 import contextlib |
11 import contextlib |
|
12 import os |
12 |
13 |
13 from PyQt6.QtCore import QUrl, pyqtSignal |
14 from PyQt6.QtCore import QUrl, pyqtSignal |
14 from PyQt6.QtGui import QDesktopServices |
15 from PyQt6.QtGui import QDesktopServices |
15 from PyQt6.QtWidgets import QDialog, QMenu |
16 from PyQt6.QtWidgets import QDialog, QMenu |
16 |
17 |
17 from eric7 import Preferences |
18 from eric7 import Preferences |
18 from eric7.EricGui import EricPixmapCache |
19 from eric7.EricGui import EricPixmapCache |
19 from eric7.EricWidgets import EricMessageBox |
20 from eric7.EricWidgets import EricMessageBox, EricPathPickerDialog |
|
21 from eric7.EricWidgets.EricApplication import ericApp |
|
22 from eric7.EricWidgets.EricPathPickerDialog import EricPathPickerModes |
20 from eric7.SystemUtilities import FileSystemUtilities |
23 from eric7.SystemUtilities import FileSystemUtilities |
21 from eric7.UI.DeleteFilesConfirmationDialog import DeleteFilesConfirmationDialog |
24 from eric7.UI.DeleteFilesConfirmationDialog import DeleteFilesConfirmationDialog |
22 from eric7.Utilities import MimeTypes |
25 from eric7.Utilities import MimeTypes |
23 |
26 |
24 from .FileCategoryRepositoryItem import FileCategoryRepositoryItem |
27 from .FileCategoryRepositoryItem import FileCategoryRepositoryItem |
153 act = self.menu.addAction(self.tr("Remove from project"), self.__removeItem) |
156 act = self.menu.addAction(self.tr("Remove from project"), self.__removeItem) |
154 self.menuActions.append(act) |
157 self.menuActions.append(act) |
155 act = self.menu.addAction(self.tr("Delete"), self.__deleteItem) |
158 act = self.menu.addAction(self.tr("Delete"), self.__deleteItem) |
156 self.menuActions.append(act) |
159 self.menuActions.append(act) |
157 self.menu.addSeparator() |
160 self.menu.addSeparator() |
|
161 self.menu.addAction(self.tr("New file..."), self.__addNewOthersFile) |
|
162 self.menu.addAction(self.tr("New directory..."), self.__addNewOthersDirectory) |
|
163 self.menu.addSeparator() |
158 self.menu.addAction(self.tr("Add files..."), self.__addOthersFiles) |
164 self.menu.addAction(self.tr("Add files..."), self.__addOthersFiles) |
159 self.menu.addAction(self.tr("Add directory..."), self.__addOthersDirectory) |
165 self.menu.addAction(self.tr("Add directory..."), self.__addOthersDirectory) |
160 self.menu.addSeparator() |
166 self.menu.addSeparator() |
161 self.menu.addAction(self.tr("Refresh"), self.__refreshItem) |
167 self.menu.addAction(self.tr("Refresh"), self.__refreshItem) |
162 self.menu.addSeparator() |
168 self.menu.addSeparator() |
178 self.deleteDirAct = self.dirMenu.addAction( |
184 self.deleteDirAct = self.dirMenu.addAction( |
179 self.tr("Delete"), self._deleteDirectory |
185 self.tr("Delete"), self._deleteDirectory |
180 ) |
186 ) |
181 self.dirMenuActions.append(self.deleteDirAct) |
187 self.dirMenuActions.append(self.deleteDirAct) |
182 self.dirMenu.addSeparator() |
188 self.dirMenu.addSeparator() |
|
189 self.dirMenu.addAction(self.tr("New file..."), self.__addNewOthersFile) |
|
190 self.dirMenu.addAction( |
|
191 self.tr("New directory..."), self.__addNewOthersDirectory |
|
192 ) |
|
193 self.dirMenu.addSeparator() |
183 self.dirMenu.addAction(self.tr("Add files..."), self.__addOthersFiles) |
194 self.dirMenu.addAction(self.tr("Add files..."), self.__addOthersFiles) |
184 self.dirMenu.addAction(self.tr("Add directory..."), self.__addOthersDirectory) |
195 self.dirMenu.addAction(self.tr("Add directory..."), self.__addOthersDirectory) |
185 self.dirMenu.addSeparator() |
196 self.dirMenu.addSeparator() |
186 self.dirMenuFileManagerAct = self.dirMenu.addAction( |
197 self.dirMenuFileManagerAct = self.dirMenu.addAction( |
187 self.tr("Show in File Manager"), self._showInFileManager |
198 self.tr("Show in File Manager"), self._showInFileManager |
194 ) |
205 ) |
195 self.dirMenu.addSeparator() |
206 self.dirMenu.addSeparator() |
196 self.dirMenu.addAction(self.tr("Configure..."), self._configure) |
207 self.dirMenu.addAction(self.tr("Configure..."), self._configure) |
197 |
208 |
198 self.backMenu = QMenu(self) |
209 self.backMenu = QMenu(self) |
|
210 self.backMenu.addAction( |
|
211 self.tr("New file..."), |
|
212 lambda: self.__addNewOthersFile(useCurrent=False), |
|
213 ) |
|
214 self.backMenu.addAction( |
|
215 self.tr("New directory..."), |
|
216 lambda: self.__addNewOthersDirectory(useCurrent=False), |
|
217 ) |
|
218 self.backMenu.addSeparator() |
199 self.backMenu.addAction( |
219 self.backMenu.addAction( |
200 self.tr("Add files..."), lambda: self.project.addFiles("OTHERS") |
220 self.tr("Add files..."), lambda: self.project.addFiles("OTHERS") |
201 ) |
221 ) |
202 self.backMenu.addAction( |
222 self.backMenu.addAction( |
203 self.tr("Add directory..."), lambda: self.project.addDirectory("OTHERS") |
223 self.tr("Add directory..."), lambda: self.project.addDirectory("OTHERS") |
459 ) |
479 ) |
460 if ok: |
480 if ok: |
461 textMimeTypesList.append(mimetype) |
481 textMimeTypesList.append(mimetype) |
462 Preferences.setUI("TextMimeTypes", textMimeTypesList) |
482 Preferences.setUI("TextMimeTypes", textMimeTypesList) |
463 |
483 |
|
484 def __addNewOthersDirectory(self, useCurrent=True): |
|
485 """ |
|
486 Private method to add a new directory to the project. |
|
487 |
|
488 @param useCurrent flag indicating to use the current index for the directory |
|
489 dialog (defaults to True) |
|
490 @type bool (optional) |
|
491 """ |
|
492 from .NewDirectoryDialog import NewDirectoryDialog |
|
493 |
|
494 isRemote = FileSystemUtilities.isRemoteFileName(self.project.getProjectPath()) |
|
495 remotefsInterface = ( |
|
496 ericApp().getObject("EricServer").getServiceInterface("FileSystem") |
|
497 ) |
|
498 |
|
499 dn = self.currentDirectory() if useCurrent else self.project.getProjectPath() |
|
500 dlg = NewDirectoryDialog(strPath=dn, defaultDirectory=dn, remote=isRemote) |
|
501 if dlg.exec() == QDialog.DialogCode.Accepted: |
|
502 dirname, addToProject = dlg.getDirectory() |
|
503 exists = ( |
|
504 remotefsInterface.exists(dirname) |
|
505 if isRemote |
|
506 else os.path.exists(dirname) |
|
507 ) |
|
508 if exists: |
|
509 EricMessageBox.critical( |
|
510 self, |
|
511 self.tr("New directory"), |
|
512 self.tr( |
|
513 "<p>A file or directory named <b>{0}</b> already exists." |
|
514 " The action will be aborted.</p>" |
|
515 ).format(dirname), |
|
516 ) |
|
517 return |
|
518 |
|
519 try: |
|
520 if isRemote: |
|
521 remotefsInterface.makedirs(dirname) |
|
522 else: |
|
523 os.makedirs(dirname) |
|
524 except OSError as err: |
|
525 EricMessageBox.critical( |
|
526 self, |
|
527 self.tr("New directory"), |
|
528 self.tr( |
|
529 "<p>The directory <b>{0}</b> could not be created." |
|
530 " Aborting...</p><p>Reason: {1}</p>" |
|
531 ).format(dirname, str(err)), |
|
532 ) |
|
533 return |
|
534 |
|
535 parentDirname = ( |
|
536 remotefsInterface.dirname(dirname) |
|
537 if isRemote |
|
538 else os.path.dirname(dirname) |
|
539 ) |
|
540 |
|
541 if addToProject and not self.project.isProjectCategory(dirname, "OTHERS"): |
|
542 self.project.addToOthers(dirname) |
|
543 elif parentDirname == self.project.getProjectPath(): |
|
544 dn = self.project.getRelativePath(dirname) |
|
545 self._model.addNewItem("OTHERS", dn, simple=True) |
|
546 while True: |
|
547 # recursively expand all parent items |
|
548 dirname = ( |
|
549 remotefsInterface.dirname(dirname) |
|
550 if isRemote |
|
551 else os.path.dirname(dirname) |
|
552 ) |
|
553 dirIndex = self._sortModel.mapFromSource( |
|
554 self._model.itemIndexByName(dirname) |
|
555 ) |
|
556 if dirIndex.isValid(): |
|
557 self.expand(dirIndex) |
|
558 else: |
|
559 break |
|
560 |
|
561 def __addNewOthersFile(self, useCurrent=True): |
|
562 """ |
|
563 Private method to add a new source file to the project. |
|
564 |
|
565 @param useCurrent flag indicating to use the current index for the directory |
|
566 dialog (defaults to True) |
|
567 @type bool (optional) |
|
568 """ |
|
569 isRemote = FileSystemUtilities.isRemoteFileName(self.project.getProjectPath()) |
|
570 remotefsInterface = ( |
|
571 ericApp().getObject("EricServer").getServiceInterface("FileSystem") |
|
572 ) |
|
573 |
|
574 dn = self.currentDirectory() if useCurrent else self.project.getProjectPath() |
|
575 filename, ok = EricPathPickerDialog.getStrPath( |
|
576 self, |
|
577 self.tr("New file"), |
|
578 self.tr("Enter the path of the new file:"), |
|
579 mode=EricPathPickerModes.SAVE_FILE_ENSURE_EXTENSION_MODE, |
|
580 strPath=dn, |
|
581 defaultDirectory=dn, |
|
582 filters=self.project.getFileCategoryFilters( |
|
583 categories=["OTHERS"], withAll=False |
|
584 ), |
|
585 remote=isRemote, |
|
586 ) |
|
587 if ok: |
|
588 exists = ( |
|
589 remotefsInterface.exists(filename) |
|
590 if isRemote |
|
591 else os.path.exists(filename) |
|
592 ) |
|
593 if exists: |
|
594 EricMessageBox.critical( |
|
595 self, |
|
596 self.tr("New file"), |
|
597 self.tr( |
|
598 "<p>The file <b>{0}</b> already exists. The action will be" |
|
599 " aborted.</p>" |
|
600 ).format(filename), |
|
601 ) |
|
602 return |
|
603 |
|
604 dirname = ( |
|
605 remotefsInterface.dirname(filename) |
|
606 if isRemote |
|
607 else os.path.dirname(filename) |
|
608 ) |
|
609 try: |
|
610 if isRemote: |
|
611 remotefsInterface.makedirs(dirname, exist_ok=True) |
|
612 else: |
|
613 os.makedirs(dirname, exist_ok=True) |
|
614 newline = ( |
|
615 None if self.project.useSystemEol() else self.project.getEolString() |
|
616 ) |
|
617 if isRemote: |
|
618 remotefsInterface.writeFile(filename, b"", newline=newline) |
|
619 else: |
|
620 with open(filename, "w", newline=newline) as f: |
|
621 f.write("") |
|
622 except OSError as err: |
|
623 EricMessageBox.critical( |
|
624 self, |
|
625 self.tr("New file"), |
|
626 self.tr( |
|
627 "<p>The file <b>{0}</b> could not be created. Aborting...</p>" |
|
628 "<p>Reason: {1}</p>" |
|
629 ).format(filename, str(err)), |
|
630 ) |
|
631 return |
|
632 |
|
633 if not self.project.isProjectCategory(filename, "OTHERS"): |
|
634 self.project.appendFile(filename) |
|
635 while True: |
|
636 # recursively expand all parent items |
|
637 dirIndex = self._sortModel.mapFromSource( |
|
638 self._model.itemIndexByName(dirname) |
|
639 ) |
|
640 if dirIndex.isValid(): |
|
641 self.expand(dirIndex) |
|
642 dirname = ( |
|
643 remotefsInterface.dirname(dirname) |
|
644 if isRemote |
|
645 else os.path.dirname(dirname) |
|
646 ) |
|
647 else: |
|
648 break |
|
649 |
|
650 if MimeTypes.isTextFile(filename): |
|
651 self.sourceFile.emit(filename) |
|
652 |
464 def __addOthersFiles(self): |
653 def __addOthersFiles(self): |
465 """ |
654 """ |
466 Private method to add files to the project. |
655 Private method to add files to the project. |
467 """ |
656 """ |
468 self.project.addFiles("OTHERS", self.currentDirectory()) |
657 self.project.addFiles("OTHERS", self.currentDirectory()) |