From 3800a553be9d62c6617a16eafae1dfdcb3084a7f Mon Sep 17 00:00:00 2001 From: Olivier Keshavjee Date: Fri, 26 Jun 2015 15:55:34 +0200 Subject: [PATCH] UI improvements --- i18n/manuskript.pro | 7 + i18n/manuskript_fr.qm | Bin 21039 -> 26802 bytes i18n/manuskript_fr.ts | 591 ++++++++++++++++++++++++---------- src/functions.py | 2 +- src/models/outlineModel.py | 31 +- src/ui/views/outlineBasics.py | 225 ++++++------- src/ui/views/treeView.py | 48 +++ 7 files changed, 612 insertions(+), 292 deletions(-) diff --git a/i18n/manuskript.pro b/i18n/manuskript.pro index cd3e3c05..b78f9478 100644 --- a/i18n/manuskript.pro +++ b/i18n/manuskript.pro @@ -14,18 +14,25 @@ SOURCES += ../src/loadSave.py SOURCES += ../src/mainWindow.py SOURCES += ../src/settingsWindow.py +SOURCES += ../src/models/outlineModel.py +SOURCES += ../src/models/persosProxyModel.py +SOURCES += ../src/models/plotModel.py + SOURCES += ../src/ui/helpLabel.py SOURCES += ../src/ui/sldImportance.py SOURCES += ../src/ui/welcome.py SOURCES += ../src/ui/editors/editorWidget.py SOURCES += ../src/ui/editors/fullScreenEditor.py +SOURCES += ../src/ui/editors/textFormat.py SOURCES += ../src/ui/views/corkDelegate.py +SOURCES += ../src/ui/views/outlineDelegates.py SOURCES += ../src/ui/views/outlineBasics.py SOURCES += ../src/ui/views/cmbOutlineLabelChoser.py SOURCES += ../src/ui/views/cmbOutlinePersoChoser.py SOURCES += ../src/ui/views/cmbOutlineStatusChoser.py +SOURCES += ../src/ui/views/treeView.py SOURCES += ../src/ui/views/lineEditView.py SOURCES += ../src/ui/views/textEditView.py SOURCES += ../src/ui/views/plotTreeView.py diff --git a/i18n/manuskript_fr.qm b/i18n/manuskript_fr.qm index bf58c90e525ef0d178fd1a8639a167c3e15c50dd..14a7417dfb2c1fb51c0ddd1a3917efb63011d64c 100644 GIT binary patch delta 7287 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 delta 2471 zcmXAqc~}%z7R7IM*Q;LWjU_->WD#UH$f7g?vNlVEBq$&Vei=X<9VJnmXfWCii8E>t zjpa&=k__Sk%4bUBf>9F|6?G(IJ|-9@oA^Z?4Vo}Uodo9S`|H>Bs_NCb=broe<1d8v zX2G6tqSC#0c-Ph|eqLu^{qWO&rxIyb6Hy@1`1?fS4kE*6;7;%dqM+qizf6>!f@`eh zbP=U|Pc-v9k<*Wy;eDK`$B7DTM6MrkM)Yvn=9Ad+Cf;i&(cU2v>61x(%HSC!_Tj@u z4T=35h~m9Cld3qA*K%eIaAt*(I2cZ3$|LdSTi^(1NDHS;OXA%~BC`*PPv(F*;1RHk zSlE|DVb{sdri>CzZK7vPoz9v5kTa{8SjJvd7D_BD7Tip1`UsJ88L^p-5O|GPVFpox zCuiClAf9(VORVY)Dt97QQ%U4Dl~_FrbU#Q;-bm!Vg4m93A`g?DSQ|FN}hnFK}kP zM>F5+o<@$e~CQJRAO0A zH0cq|Rvjg>$E46~hd@*q#~D*Yv#U^{e-)KVcrd1yN?XSf#R*jU+YMYlr0SC@^l%w9 zd!wSzLv$#08K|a?s&5e7G`e!WojQ7H1q3fr2Edd^k7^b-%2)PPppQun*4iK6S& z_x-lmVNI8qH#CQ6TE6(w%XmPWB`zyR23%}neLGsADiyb_{~RMIi952rNi1^q_lOY==nM+Hw<&i7EAelP@e8C zEo%4@8OY(BDsb9*rE2qLjP0OQE9fC4SgJK0B#M|THI{vV4;4#$R^LQOhozRsXz_S& z=~Co#2w@6mM5A=MA3{?S>{9;+a3E}w^xfllgyNF)pG|NgQ%)dpmrmqfJ8PT)~y%2I&(|&#iQD(8`Gv{VF zwm@^;`w4`0Y0I>sI7fDAS4BCaaQjhh1L1?=W!mOoEKCg4p6tGXlj>{jY0tw*^&V}f zGpuv8YkRxkOw?xWqc`5f2M2XNS$NNSSeH8wVbd|)oOKZ5*33Eap>9by9L#jq)t`8fhD^5vYS)t$Rkfcc;J7hO+*E3B^2-Ks?eqE$EAwj1f)t{bzup!fUrdZiY^ z&gd;i{zqgf*IPfY0mC^%f7e&OJ{K*E z!`b3*aKFirR=)u6+YEV~OOSduL&@a;jO8lB{Ano2J;|_6l5w(Tb0#!CCBl*LfG;G+ zb7m(SwjMZ&gDl4I{swml%Qoyg^d4Gp&(I-2kY^%iWR2ls?>>a;HN(Hsyf7^xhCBEE z46AP$9`>LhYrfG~ixvgFV)Q97LFjQ~dhySg`z~X8i5eU>mbcljVZPrnF8n$g^V(|s z+rb3xH3b0*(3c3r^zkU--P@8Z78O5-nczd|_onWE0aYVkFbb@T+* z`%GCw4amZPX|?NZ>}Tgp%rQz{ic$+inig~j? z!jr8wADp)rVau71iw3z@pQ#*oc&L^m9Ywk05B~BAZ;O1$+@qYeTo;5q`M%RQS$0a4 zN8OAXDQ)SJg<<*fBo`Ouno~cMN6N>^u`U+bry@ZvbhIc3+`kv(O%Contexte - + Outline Plan @@ -359,67 +359,67 @@ Mode - + New character Nouveau perso - + (~{} pages) (~{} pages) - + Enter infos about your book, and yourself. Entrez toutes les informations relatives au livre, ainsi qu'à vous. - + Take time to think about a one sentance (~50 words) summary of your book. Then expand it to a paragraph, then to a page, then to a full summary. Prenez le temps de réfléchir à un résumé de votre livre, en une phrase (~50 mots). Puis augmentez cette phrase en un paragraphe, puis en une page, puis en un résumé complet. - + Create your characters. Créez ici vos personnage. - + Develop plots. Développez vos intrigues. - + Create the outline of your masterpiece. Créez le plan de votre chef-d'œuvre. - + Write. Écrivez. - + Debug infos. Sometimes useful. Des infos pour débugger des fois pendant qu'on code c'est utile. - + Dictionary Dictionnaire - + Install PyEnchant to use spellcheck Installez PyEnchant pour profiter du correcteur orthographique - + Words: {}{} Mots: {}{} - + Text Texte @@ -459,7 +459,7 @@ Et si...? - + Index cards Cartes @@ -479,7 +479,7 @@ F9 - + Tree Arbre @@ -504,77 +504,77 @@ Réglages - + Project {} saved. Le projet {} a été enregistré. - + Project {} loaded. Le projet {} a été chargé. - + The basic situation, in the form of a 'What if...?' question. Ex: 'What if the most dangerous evil wizard could wasn't abled to kill a baby?' (Harry Potter) La situation de base, sous la forme d'une question: "Et si...?" Par exemple: "Et si le plus dangereux magiciens mauvais n'était pas capable de tuer un bébé?" (Harry Potter) - + Nothing Rien - + POV POV - + Label Label - + Progress Progrès - + Compile Compilation - + Icon color Couleur de l'icone - + Text color Couleur du texte - + Background color Couleur de l'arrière-plan - + Icon Icone - + Background Arrière-plan - + Border Bordure - + Corner Coin @@ -584,22 +584,22 @@ Fermer le projet - + The file {} does not exist. Try again. Le fichier {} n'existe pas. Essayez encore. - + Project {} loaded with some errors: Le projet {} a été chargé, avec des erreurs: - + * {} wasn't found in project file. * {} n'a pas été trouvé dans le fichier du projet. - + Project {} loaded with some errors. Le projet {} a été chargé avec des erreurs. @@ -617,17 +617,17 @@ Apparence - + Labels Labels - + Status Status - + Fullscreen Plein écran @@ -672,348 +672,348 @@ Enregistrer en quittant - + Views settings Apparence - + Tree Arbre - + Colors Couleurs - + Icon color: Icone: - + Nothing Rien - + POV POV - + Label Label - + Progress Progrès - + Compile Compilation - + Text color: Texte: - + Background color: Arrière-plan: - + Folders Dossiers - + Show item count Afficher le nombre de sous-éléments - + Show wordcount Afficher le nombre de mots - + Show progress Afficher le progrès - + Text Texte - + Outline Plan - + Visible columns Colonnes visibles - + Goal Goal - + Word count Nombre de mots - + Percentage Pourcentage - + Title Titre - + Index cards Cartes - + Item colors Couleurs des cartes - + Border color: Bordure: - + Corner color: Coin: - + Background Arrière-plan - + Color: Couleur: - + Ctrl+S Ctrl+S - + Image: Image: - + New Nouveau - + Edit Modifier - + Delete Supprimer - + Theme name: Nom du thème: - + Apply Enregistrer - + Cancel Annuler - + Window Background Arrière plan de la fenêtre - + Text Background Arrière plan du texte - + Text Options Options du texte - + Paragraph Options Options des paragraphes - + Type: Type: - + No Image Pas d'image - + Tiled Mosaïque - + Centered Centrée - + Stretched Étirée - + Scaled Mise à l'échelle - + Zoomed Zoomée - + Opacity: Opacité: - + % % - + Position: Position: - + Left Gauche - + Center Centre - + Right Droite - + Width: Largeur: - + px px - + Corner radius: Arrondi: - + Margins: Marges: - + Padding: Intérieur: - + Font: Police: - + Size: Taille: - + Misspelled: Orthographe: - + Line spacing: Espacement des lignes: - + Single Simple - + 1.5 lines 1.5 lignes - + Double Double - + Proportional Proportionnel - + Tab width: Tabulation: - + Spacing: Espacement: - + Indent 1st line Retrait 1ère ligne @@ -1037,11 +1037,41 @@ des lignes: Automatically load last project on startup Charger au démarrage le dernier projet ouvert + + + Default text format + Format de texte par défaut + + + + The format set by default when you create a new text item. You can change this on a per item basis. + Le format définit par défaut lorsque vous créez un nouveau élément texte. Vous pouvez changer ce format pour chaque élément. + + + + Text editor + Éditeur de texte + + + + Font + Police + + + + Family: + Famille: + + + + Paragraphs + Paragraphes + SpellAction - + Spelling Suggestions Suggestions @@ -1152,12 +1182,12 @@ des lignes: editorWidget - + {} words / {} {} mots / {} - + {} words {} mots @@ -1173,17 +1203,17 @@ des lignes: fullScreenEditor - + Theme: Thème: - + {} words / {} {} mots / {} - + {} words {} mots @@ -1212,22 +1242,22 @@ des lignes: Form - + Properties Propriétés - + Summary Résumé - + One line summary Résumé en une ligne - + Notes Notes @@ -1235,76 +1265,183 @@ des lignes: outlineBasics - + Copy Copier - + Cut Couper - + Paste Coller - + Delete Supprimer - + Set POV Choisir le POV - + Set Status Choisir le status - + Set Label Choisir le label - + New Folder Nouveau Dossier - + None Aucun - + New Nouveau - + New Text Nouveau text - + Main Principal - + Secondary Secondaire - + Minor Mineur + + outlineModel + + + Title + Titre + + + + POV + POV + + + + Label + Label + + + + Status + Status + + + + Compile + Compilation + + + + Word count + Nombre de mots + + + + Goal + Goal + + + + outlinePersoDelegate + + + None + Aucun + + + + Main + Principal + + + + Secondary + Secondaire + + + + Minor + Mineur + + + + persosProxyModel + + + Main + Principal + + + + Secundary + Secondaire + + + + Minors + Mineurs + + + + plotModel + + + New plot + Nouvelle intrigue + + + + New subplot + Nouvelle sous-intrigue + + + + Main + Principale + + + + Secondary + Secondaire + + + + Minor + Mineure + + plotTreeView @@ -1331,58 +1468,78 @@ des lignes: Form - + POV POV - + Status Status - + Label Label - + Compile Compile - + Goal Goal - + Word count Nombre de mots + + + Text type: + Format: + settingsWindow - + New status Nouveau status - + New label Nouveau label - + newtheme nouveautheme - + New theme Nouveau Thème + + + Txt2Tags + Txt2Tags + + + + Rich Text (html) + Texte riche (html) + + + + Plain Text + Texte simple + sldImportance @@ -1415,11 +1572,77 @@ des lignes: textEditView - + Various Différentes valeurs + + textFormat + + + CTRL+B + CTRL+G + + + + CTRL+I + CTRL+I + + + + CTRL+U + CTRL+U + + + + CTRL+P + CTRL+P + + + + CTRL+L + CTRL+L + + + + CTRL+E + CTRL+E + + + + CTRL+R + CTRL+R + + + + CTRL+J + CTRL+J + + + + treeView + + + Expand {} + Développer {} + + + + Collapse {} + Fermer {} + + + + Expand All + Tout développer + + + + Collapse All + Tout fermer + + welcome @@ -1433,37 +1656,37 @@ des lignes: - + Templates Modèles - + Empty Vide - + Novel Roman - + Novella Nouvelle - + Short Story - + Research paper - + Demo projects Projets de démonstration @@ -1478,129 +1701,149 @@ des lignes: Ajouter le nombre de mots - + Next time, automatically open last project La prochaine fois, ouvrir automatiquement le dernier projet - + Open... Ouvrir... - + Recent Récents - + Create Créer - + Open project Ouvrir le projet - + Manuskript project (*.msk) Projet Manuskript (*.msk) - + Save project as... Enregistrer le projer sous... - + Create New Project Créer un nouveau projet - + Chapter Chapitre - + Scene Scène - + Trilogy Trilogie - + Book Livre - + Section Section - + words each. mots chacun(e). - + of de - + Text Texte - + Something Quelque chose - + <b>Total:</b> {} words (~ {} pages) <b>Total:</b> {} mots (~ {} pages) - + Idea Idée - + Note Note - + Research Recherche - + TODO TODO - + First draft Premier brouillon - + Second draft Second brouillon - + Final Final + + + Default text type: + + + + + Txt2Tags + + + + + Rich Text (html) + + + + + Plain Text + + diff --git a/src/functions.py b/src/functions.py index 8eacdab7..4a7df449 100644 --- a/src/functions.py +++ b/src/functions.py @@ -124,7 +124,7 @@ def outlineItemColors(item): colors["Progress"] = colorFromProgress(pg) # Compile - if item.isCompile() in [0, "0"]: + if item.compile() in [0, "0"]: colors["Compile"] = QColor(Qt.gray) else: colors["Compile"] = QColor(Qt.black) diff --git a/src/models/outlineModel.py b/src/models/outlineModel.py index 0dbc4732..d8dfca7b 100644 --- a/src/models/outlineModel.py +++ b/src/models/outlineModel.py @@ -387,10 +387,10 @@ class outlineItem(): #print("Data: ", column, role) if role == Qt.DisplayRole or role == Qt.EditRole: - if column == Outline.compile.value: - return self.data(column, Qt.CheckStateRole) + #if column == Outline.compile.value: + #return self.data(column, Qt.CheckStateRole) - elif Outline(column) in self._data: + if Outline(column) in self._data: return self._data[Outline(column)] else: @@ -411,7 +411,11 @@ class outlineItem(): #return QBrush(Qt.gray) elif role == Qt.CheckStateRole and column == Outline.compile.value: - return self._data[Outline(column)] + #print(self.title(), self.compile()) + #if self._data[Outline(column)] and not self.compile(): + #return Qt.PartiallyChecked + #else: + return self._data[Outline(column)] elif role == Qt.FontRole: f = QFont() @@ -458,6 +462,9 @@ class outlineItem(): if column == Outline.text.value: wc = wordCount(data) self.setData(Outline.wordCount.value, wc) + + if column == Outline.compile.value: + self.emitDataChanged(cols=[Outline.title.value, Outline.compile.value], recursive=True) if updateWordCount: self.updateWordCount() @@ -527,16 +534,21 @@ class outlineItem(): else: return QModelIndex() - def emitDataChanged(self, cols=None): + def emitDataChanged(self, cols=None, recursive=False): idx = self.index() if idx and self._model: if not cols: # Emit data changed for the whole item (all columns) self._model.dataChanged.emit(idx, self.index(len(Outline))) + else: # Emit only for the specified columns for c in cols: self._model.dataChanged.emit(self.index(c), self.index(c)) + + if recursive: + for c in self.children(): + c.emitDataChanged(cols, recursive=True) def removeChild(self, row): self.childItems.pop(row) @@ -559,8 +571,13 @@ class outlineItem(): def isText(self): return self._data[Outline.type] == "txt" - def isCompile(self): - return Outline.compile in self._data and self._data[Outline.compile] + def compile(self): + if self._data[Outline.compile] in ["0", 0]: + return False + elif self.parent(): + return self.parent().compile() + else: + return True # rootItem always compile def title(self): if Outline.title in self._data: diff --git a/src/ui/views/outlineBasics.py b/src/ui/views/outlineBasics.py index b09b1e1e..472c9873 100644 --- a/src/ui/views/outlineBasics.py +++ b/src/ui/views/outlineBasics.py @@ -23,119 +23,124 @@ class outlineBasics(QAbstractItemView): if event.button() == Qt.RightButton: - index = self.currentIndex() - sel = self.getSelection() - clipboard = qApp.clipboard() - - self.menu = QMenu(self) - - # Add / remove items - self.actAddFolder = QAction(QIcon.fromTheme("folder-new"), qApp.translate("outlineBasics", "New Folder"), self.menu) - self.actAddFolder.triggered.connect(self.addFolder) - self.menu.addAction(self.actAddFolder) - - self.actAddText = QAction(QIcon.fromTheme("document-new"), qApp.translate("outlineBasics", "New Text"), self.menu) - self.actAddText.triggered.connect(self.addText) - self.menu.addAction(self.actAddText) - - self.actDelete = QAction(QIcon.fromTheme("edit-delete"), qApp.translate("outlineBasics", "Delete"), self.menu) - self.actDelete.triggered.connect(self.delete) - self.menu.addAction(self.actDelete) - - self.menu.addSeparator() - - # Copy, cut, paste - self.actCopy = QAction(QIcon.fromTheme("edit-copy"), qApp.translate("outlineBasics", "Copy"), self.menu) - self.actCopy.triggered.connect(self.copy) - self.menu.addAction(self.actCopy) - - self.actCut = QAction(QIcon.fromTheme("edit-cut"), qApp.translate("outlineBasics", "Cut"), self.menu) - self.actCut.triggered.connect(self.cut) - self.menu.addAction(self.actCut) - - self.actPaste = QAction(QIcon.fromTheme("edit-paste"), qApp.translate("outlineBasics", "Paste"), self.menu) - self.actPaste.triggered.connect(self.paste) - self.menu.addAction(self.actPaste) - - self.menu.addSeparator() - - # POV - self.menuPOV = QMenu(qApp.translate("outlineBasics", "Set POV"), self.menu) - mw = mainWindow() - a = QAction(QIcon.fromTheme("edit-delete"), qApp.translate("outlineBasics", "None"), self.menuPOV) - a.triggered.connect(lambda: self.setPOV("")) - self.menuPOV.addAction(a) - self.menuPOV.addSeparator() - - menus = [] - for i in [self.tr("Main"), self.tr("Secondary"), self.tr("Minor")]: - m = QMenu(i, self.menuPOV) - menus.append(m) - self.menuPOV.addMenu(m) - - mpr = QSignalMapper(self.menuPOV) - for i in range(mw.mdlPersos.rowCount()): - a = QAction(mw.mdlPersos.item(i, Perso.name.value).text(), self.menuPOV) - a.triggered.connect(mpr.map) - mpr.setMapping(a, int(mw.mdlPersos.item(i, Perso.ID.value).text())) - - imp = mw.mdlPersos.item(i, Perso.importance.value) - if imp: - imp = toInt(imp.text()) - else: - imp = 0 - - menus[2-imp].addAction(a) - - mpr.mapped.connect(self.setPOV) - self.menu.addMenu(self.menuPOV) - - # Status - self.menuStatus = QMenu(qApp.translate("outlineBasics", "Set Status"), self.menu) - #a = QAction(QIcon.fromTheme("edit-delete"), qApp.translate("outlineBasics", "None"), self.menuStatus) - #a.triggered.connect(lambda: self.setStatus("")) - #self.menuStatus.addAction(a) - #self.menuStatus.addSeparator() - - mpr = QSignalMapper(self.menuStatus) - for i in range(mw.mdlStatus.rowCount()): - a = QAction(mw.mdlStatus.item(i, 0).text(), self.menuStatus) - a.triggered.connect(mpr.map) - mpr.setMapping(a, i) - self.menuStatus.addAction(a) - mpr.mapped.connect(self.setStatus) - self.menu.addMenu(self.menuStatus) - - # Labels - self.menuLabel = QMenu(qApp.translate("outlineBasics", "Set Label"), self.menu) - mpr = QSignalMapper(self.menuLabel) - for i in range(mw.mdlLabels.rowCount()): - a = QAction(mw.mdlLabels.item(i, 0).icon(), - mw.mdlLabels.item(i, 0).text(), - self.menuLabel) - a.triggered.connect(mpr.map) - mpr.setMapping(a, i) - self.menuLabel.addAction(a) - mpr.mapped.connect(self.setLabel) - self.menu.addMenu(self.menuLabel) - + self.menu = self.makePopupMenu() self.menu.popup(event.globalPos()) + + def makePopupMenu(self): + index = self.currentIndex() + sel = self.getSelection() + clipboard = qApp.clipboard() + + menu = QMenu(self) + + # Add / remove items + self.actAddFolder = QAction(QIcon.fromTheme("folder-new"), qApp.translate("outlineBasics", "New Folder"), menu) + self.actAddFolder.triggered.connect(self.addFolder) + menu.addAction(self.actAddFolder) + + self.actAddText = QAction(QIcon.fromTheme("document-new"), qApp.translate("outlineBasics", "New Text"), menu) + self.actAddText.triggered.connect(self.addText) + menu.addAction(self.actAddText) + + self.actDelete = QAction(QIcon.fromTheme("edit-delete"), qApp.translate("outlineBasics", "Delete"), menu) + self.actDelete.triggered.connect(self.delete) + menu.addAction(self.actDelete) + + menu.addSeparator() + + # Copy, cut, paste + self.actCopy = QAction(QIcon.fromTheme("edit-copy"), qApp.translate("outlineBasics", "Copy"), menu) + self.actCopy.triggered.connect(self.copy) + menu.addAction(self.actCopy) + + self.actCut = QAction(QIcon.fromTheme("edit-cut"), qApp.translate("outlineBasics", "Cut"), menu) + self.actCut.triggered.connect(self.cut) + menu.addAction(self.actCut) + + self.actPaste = QAction(QIcon.fromTheme("edit-paste"), qApp.translate("outlineBasics", "Paste"), menu) + self.actPaste.triggered.connect(self.paste) + menu.addAction(self.actPaste) + + menu.addSeparator() - if len(sel) > 0 and index.isValid() and not index.internalPointer().isFolder() \ - or not clipboard.mimeData().hasFormat("application/xml"): - self.actPaste.setEnabled(False) - - if len(sel) > 0 and index.isValid() and not index.internalPointer().isFolder(): - self.actAddFolder.setEnabled(False) - self.actAddText.setEnabled(False) + # POV + self.menuPOV = QMenu(qApp.translate("outlineBasics", "Set POV"), menu) + mw = mainWindow() + a = QAction(QIcon.fromTheme("edit-delete"), qApp.translate("outlineBasics", "None"), self.menuPOV) + a.triggered.connect(lambda: self.setPOV("")) + self.menuPOV.addAction(a) + self.menuPOV.addSeparator() + + menus = [] + for i in [self.tr("Main"), self.tr("Secondary"), self.tr("Minor")]: + m = QMenu(i, self.menuPOV) + menus.append(m) + self.menuPOV.addMenu(m) + + mpr = QSignalMapper(self.menuPOV) + for i in range(mw.mdlPersos.rowCount()): + a = QAction(mw.mdlPersos.item(i, Perso.name.value).text(), self.menuPOV) + a.triggered.connect(mpr.map) + mpr.setMapping(a, int(mw.mdlPersos.item(i, Perso.ID.value).text())) - if len(sel) == 0: - self.actCopy.setEnabled(False) - self.actCut.setEnabled(False) - self.actDelete.setEnabled(False) - self.menuPOV.setEnabled(False) - self.menuStatus.setEnabled(False) - self.menuLabel.setEnabled(False) + imp = mw.mdlPersos.item(i, Perso.importance.value) + if imp: + imp = toInt(imp.text()) + else: + imp = 0 + + menus[2-imp].addAction(a) + + mpr.mapped.connect(self.setPOV) + menu.addMenu(self.menuPOV) + + # Status + self.menuStatus = QMenu(qApp.translate("outlineBasics", "Set Status"), menu) + #a = QAction(QIcon.fromTheme("edit-delete"), qApp.translate("outlineBasics", "None"), self.menuStatus) + #a.triggered.connect(lambda: self.setStatus("")) + #self.menuStatus.addAction(a) + #self.menuStatus.addSeparator() + + mpr = QSignalMapper(self.menuStatus) + for i in range(mw.mdlStatus.rowCount()): + a = QAction(mw.mdlStatus.item(i, 0).text(), self.menuStatus) + a.triggered.connect(mpr.map) + mpr.setMapping(a, i) + self.menuStatus.addAction(a) + mpr.mapped.connect(self.setStatus) + menu.addMenu(self.menuStatus) + + # Labels + self.menuLabel = QMenu(qApp.translate("outlineBasics", "Set Label"), menu) + mpr = QSignalMapper(self.menuLabel) + for i in range(mw.mdlLabels.rowCount()): + a = QAction(mw.mdlLabels.item(i, 0).icon(), + mw.mdlLabels.item(i, 0).text(), + self.menuLabel) + a.triggered.connect(mpr.map) + mpr.setMapping(a, i) + self.menuLabel.addAction(a) + mpr.mapped.connect(self.setLabel) + menu.addMenu(self.menuLabel) + + + if len(sel) > 0 and index.isValid() and not index.internalPointer().isFolder() \ + or not clipboard.mimeData().hasFormat("application/xml"): + self.actPaste.setEnabled(False) + + if len(sel) > 0 and index.isValid() and not index.internalPointer().isFolder(): + self.actAddFolder.setEnabled(False) + self.actAddText.setEnabled(False) + + if len(sel) == 0: + self.actCopy.setEnabled(False) + self.actCut.setEnabled(False) + self.actDelete.setEnabled(False) + self.menuPOV.setEnabled(False) + self.menuStatus.setEnabled(False) + self.menuLabel.setEnabled(False) + + return menu def addFolder(self): self.addItem("folder") diff --git a/src/ui/views/treeView.py b/src/ui/views/treeView.py index 30130989..90fd055e 100644 --- a/src/ui/views/treeView.py +++ b/src/ui/views/treeView.py @@ -29,6 +29,54 @@ class treeView(QTreeView, dndView, outlineBasics): self.titleDelegate = treeTitleDelegate() self.setItemDelegateForColumn(Outline.title.value, self.titleDelegate) + def makePopupMenu(self): + menu = outlineBasics.makePopupMenu(self) + first = menu.actions()[0] + + + if len(self.selectedIndexes()) != 0: + index = self.currentIndex() + item = index.internalPointer() + self.actExpand = QAction(self.tr("Expand {}").format(item.title()), menu) + self.actExpand.triggered.connect(self.expandCurrentIndex) + menu.insertAction(first, self.actExpand) + + self.actCollapse = QAction(self.tr("Collapse {}").format(item.title()), menu) + self.actCollapse.triggered.connect(self.collapseCurrentIndex) + menu.insertAction(first, self.actCollapse) + + menu.insertSeparator(first) + + self.actExpandAll = QAction(self.tr("Expand All"), menu) + self.actExpandAll.triggered.connect(self.expandAll) + menu.insertAction(first, self.actExpandAll) + + self.actCollapseAll = QAction(self.tr("Collapse All"), menu) + self.actCollapseAll.triggered.connect(self.collapseAll) + menu.insertAction(first, self.actCollapseAll) + + menu.insertSeparator(first) + + return menu + + def expandCurrentIndex(self, index=None): + if index is None or type(index) == bool: + index = self.currentIndex() + + self.expand(index) + for i in range(self.model().rowCount(index)): + idx = self.model().index(i, 0, index) + self.expandCurrentIndex(index=idx) + + def collapseCurrentIndex(self, index=None): + if index is None or type(index) == bool: + index = self.currentIndex() + + self.collapse(index) + for i in range(self.model().rowCount(index)): + idx = self.model().index(i, 0, index) + self.collapseCurrentIndex(index=idx) + def dragMoveEvent(self, event): dndView.dragMoveEvent(self, event) QTreeView.dragMoveEvent(self, event)