eric7/Templates/TemplateViewer.py

branch
eric7
changeset 8312
800c432b34c8
parent 8260
2161475d9639
child 8314
e3642a6a1e71
equal deleted inserted replaced
8311:4e8b98454baa 8312:800c432b34c8
1 # -*- coding: utf-8 -*-
2
3 # Copyright (c) 2005 - 2021 Detlev Offenbach <detlev@die-offenbachs.de>
4 #
5
6 """
7 Module implementing a template viewer and associated classes.
8 """
9
10 import datetime
11 import os
12 import re
13
14 from PyQt5.QtCore import QFile, QFileInfo, QIODevice, Qt, QCoreApplication
15 from PyQt5.QtWidgets import (
16 QTreeWidget, QDialog, QApplication, QMenu, QTreeWidgetItem
17 )
18
19 from E5Gui.E5Application import e5App
20 from E5Gui import E5MessageBox, E5FileDialog
21
22 import Preferences
23
24 import UI.PixmapCache
25 import Utilities
26
27 from .TemplatesFile import TemplatesFile
28
29
30 class TemplateGroup(QTreeWidgetItem):
31 """
32 Class implementing a template group.
33 """
34 def __init__(self, parent, name, language="All"):
35 """
36 Constructor
37
38 @param parent parent widget of the template group (QWidget)
39 @param name name of the group (string)
40 @param language programming language for the group (string)
41 """
42 self.name = name
43 self.language = language
44 self.entries = {}
45
46 super().__init__(parent, [name])
47
48 if Preferences.getTemplates("ShowTooltip"):
49 self.setToolTip(0, language)
50
51 def setName(self, name):
52 """
53 Public method to update the name of the group.
54
55 @param name name of the group (string)
56 """
57 self.name = name
58 self.setText(0, name)
59
60 def getName(self):
61 """
62 Public method to get the name of the group.
63
64 @return name of the group (string)
65 """
66 return self.name
67
68 def setLanguage(self, language):
69 """
70 Public method to update the name of the group.
71
72 @param language programming language for the group (string)
73 """
74 self.language = language
75 if Preferences.getTemplates("ShowTooltip"):
76 self.setToolTip(0, language)
77
78 def getLanguage(self):
79 """
80 Public method to get the name of the group.
81
82 @return language of the group (string)
83 """
84 return self.language
85
86 def addEntry(self, name, description, template, quiet=False):
87 """
88 Public method to add a template entry to this group.
89
90 @param name name of the entry (string)
91 @param description description of the entry to add (string)
92 @param template template text of the entry (string)
93 @param quiet flag indicating quiet operation (boolean)
94 """
95 if name in self.entries:
96 if not quiet:
97 E5MessageBox.critical(
98 None,
99 QCoreApplication.translate("TemplateGroup",
100 "Add Template"),
101 QCoreApplication.translate(
102 "TemplateGroup",
103 """<p>The group <b>{0}</b> already contains a"""
104 """ template named <b>{1}</b>.</p>""")
105 .format(self.name, name))
106 return
107
108 self.entries[name] = TemplateEntry(self, name, description, template)
109
110 if (
111 Preferences.getTemplates("AutoOpenGroups") and
112 not self.isExpanded()
113 ):
114 self.setExpanded(True)
115
116 def removeEntry(self, name):
117 """
118 Public method to remove a template entry from this group.
119
120 @param name name of the entry to be removed (string)
121 """
122 if name in self.entries:
123 index = self.indexOfChild(self.entries[name])
124 self.takeChild(index)
125 del self.entries[name]
126
127 if (
128 len(self.entries) == 0 and
129 Preferences.getTemplates("AutoOpenGroups") and
130 self.isExpanded()
131 ):
132 self.setExpanded(False)
133
134 def removeAllEntries(self):
135 """
136 Public method to remove all template entries of this group.
137 """
138 for name in list(self.entries.keys())[:]:
139 self.removeEntry(name)
140
141 def hasEntry(self, name):
142 """
143 Public method to check, if the group has an entry with the given name.
144
145 @param name name of the entry to check for (string)
146 @return flag indicating existence (boolean)
147 """
148 return name in self.entries
149
150 def getEntry(self, name):
151 """
152 Public method to get an entry.
153
154 @param name name of the entry to retrieve (string)
155 @return reference to the entry (TemplateEntry)
156 """
157 try:
158 return self.entries[name]
159 except KeyError:
160 return None
161
162 def getEntryNames(self, beginning):
163 """
164 Public method to get the names of all entries, who's name starts with
165 the given string.
166
167 @param beginning string denoting the beginning of the template name
168 (string)
169 @return list of entry names found (list of strings)
170 """
171 names = []
172 for name in self.entries:
173 if name.startswith(beginning):
174 names.append(name)
175
176 return names
177
178 def getAllEntries(self):
179 """
180 Public method to retrieve all entries.
181
182 @return list of all entries (list of TemplateEntry)
183 """
184 return list(self.entries.values())
185
186
187 class TemplateEntry(QTreeWidgetItem):
188 """
189 Class immplementing a template entry.
190 """
191 def __init__(self, parent, name, description, templateText):
192 """
193 Constructor
194
195 @param parent parent widget of the template entry (QWidget)
196 @param name name of the entry (string)
197 @param description descriptive text for the template (string)
198 @param templateText text of the template entry (string)
199 """
200 self.name = name
201 self.description = description
202 self.template = templateText
203 self.__extractVariables()
204
205 super().__init__(parent, [self.__displayText()])
206 if Preferences.getTemplates("ShowTooltip"):
207 self.setToolTip(0, self.template)
208
209 def __displayText(self):
210 """
211 Private method to generate the display text.
212
213 @return display text (string)
214 """
215 txt = (
216 "{0} - {1}".format(self.name, self.description)
217 if self.description else
218 self.name
219 )
220 return txt
221
222 def setName(self, name):
223 """
224 Public method to update the name of the entry.
225
226 @param name name of the entry (string)
227 """
228 self.name = name
229 self.setText(0, self.__displayText())
230
231 def getName(self):
232 """
233 Public method to get the name of the entry.
234
235 @return name of the entry (string)
236 """
237 return self.name
238
239 def setDescription(self, description):
240 """
241 Public method to update the description of the entry.
242
243 @param description description of the entry (string)
244 """
245 self.description = description
246 self.setText(0, self.__displayText())
247
248 def getDescription(self):
249 """
250 Public method to get the description of the entry.
251
252 @return description of the entry (string)
253 """
254 return self.description
255
256 def getGroupName(self):
257 """
258 Public method to get the name of the group this entry belongs to.
259
260 @return name of the group containing this entry (string)
261 """
262 return self.parent().getName()
263
264 def setTemplateText(self, templateText):
265 """
266 Public method to update the template text.
267
268 @param templateText text of the template entry (string)
269 """
270 self.template = templateText
271 self.__extractVariables()
272 if Preferences.getTemplates("ShowTooltip"):
273 self.setToolTip(0, self.template)
274
275 def getTemplateText(self):
276 """
277 Public method to get the template text.
278
279 @return the template text (string)
280 """
281 return self.template
282
283 def getExpandedText(self, varDict, indent):
284 """
285 Public method to get the template text with all variables expanded.
286
287 @param varDict dictionary containing the texts of each variable
288 with the variable name as key.
289 @param indent indentation of the line receiving he expanded
290 template text (string)
291 @return a tuple of the expanded template text (string), the
292 number of lines (integer) and the length of the last line (integer)
293 """
294 txt = self.template
295 for var, val in list(varDict.items()):
296 txt = (
297 self.__expandFormattedVariable(var, val, txt)
298 if var in self.formatedVariables else
299 txt.replace(var, val)
300 )
301 sepchar = Preferences.getTemplates("SeparatorChar")
302 txt = txt.replace("{0}{1}".format(sepchar, sepchar), sepchar)
303 prefix = "{0}{1}".format(os.linesep, indent)
304 trailingEol = txt.endswith(os.linesep)
305 lines = txt.splitlines()
306 lineCount = len(lines)
307 lineLen = len(lines[-1])
308 txt = prefix.join(lines).lstrip()
309 if trailingEol:
310 txt = "{0}{1}".format(txt, os.linesep)
311 lineCount += 1
312 lineLen = 0
313 return txt, lineCount, lineLen
314
315 def __expandFormattedVariable(self, var, val, txt):
316 """
317 Private method to expand a template variable with special formatting.
318
319 @param var template variable name (string)
320 @param val value of the template variable (string)
321 @param txt template text (string)
322 @return expanded and formatted variable (string)
323 """
324 t = ""
325 for line in txt.splitlines():
326 ind = line.find(var)
327 if ind >= 0:
328 variableFormat = var[1:-1].split(':', 1)[1]
329 if variableFormat == 'rl':
330 prefix = line[:ind]
331 postfix = line[ind + len(var):]
332 for v in val.splitlines():
333 t = "{0}{1}{2}{3}{4}".format(
334 t, os.linesep, prefix, v, postfix)
335 elif variableFormat == 'ml':
336 indent = line.replace(line.lstrip(), "")
337 prefix = line[:ind]
338 postfix = line[ind + len(var):]
339 for count, v in enumerate(val.splitlines()):
340 t = (
341 "{0}{1}{2}{3}".format(t, os.linesep, indent, v)
342 if count else
343 "{0}{1}{2}{3}".format(t, os.linesep, prefix, v)
344 )
345 t = "{0}{1}".format(t, postfix)
346 else:
347 t = "{0}{1}{2}".format(t, os.linesep, line)
348 else:
349 t = "{0}{1}{2}".format(t, os.linesep, line)
350 return "".join(t.splitlines(1)[1:])
351
352 def getVariables(self):
353 """
354 Public method to get the list of variables.
355
356 @return list of variables (list of strings)
357 """
358 return self.variables
359
360 def __extractVariables(self):
361 """
362 Private method to retrieve the list of variables.
363 """
364 sepchar = Preferences.getTemplates("SeparatorChar")
365 variablesPattern = re.compile(
366 r"""\{0}[a-zA-Z][a-zA-Z0-9_]*(?::(?:ml|rl))?\{1}""".format(
367 sepchar, sepchar)
368 )
369 variables = variablesPattern.findall(self.template)
370 self.variables = []
371 self.formatedVariables = []
372 for var in variables:
373 if var not in self.variables:
374 self.variables.append(var)
375 if var.find(':') >= 0 and var not in self.formatedVariables:
376 self.formatedVariables.append(var)
377
378
379 class TemplateViewer(QTreeWidget):
380 """
381 Class implementing the template viewer.
382 """
383 def __init__(self, parent, viewmanager):
384 """
385 Constructor
386
387 @param parent the parent (QWidget)
388 @param viewmanager reference to the viewmanager object
389 """
390 super().__init__(parent)
391
392 self.viewmanager = viewmanager
393 self.groups = {}
394
395 self.setHeaderLabels(["Template"])
396 self.header().hide()
397 self.header().setSortIndicator(0, Qt.SortOrder.AscendingOrder)
398 self.setRootIsDecorated(True)
399 self.setAlternatingRowColors(True)
400
401 self.__menu = QMenu(self)
402 self.applyAct = self.__menu.addAction(
403 self.tr("Apply"), self.__templateItemActivated)
404 self.__menu.addSeparator()
405 self.__menu.addAction(self.tr("Add entry..."), self.__addEntry)
406 self.__menu.addAction(self.tr("Add group..."), self.__addGroup)
407 self.__menu.addAction(self.tr("Edit..."), self.__edit)
408 self.__menu.addAction(self.tr("Remove"), self.__remove)
409 self.__menu.addSeparator()
410 self.saveAct = self.__menu.addAction(self.tr("Save"), self.save)
411 self.__menu.addAction(self.tr("Import..."), self.__import)
412 self.__menu.addAction(self.tr("Export..."), self.__export)
413 self.__menu.addAction(self.tr("Reload"), self.__reload)
414 self.__menu.addSeparator()
415 self.__menu.addAction(
416 self.tr("Help about Templates..."), self.__showHelp)
417 self.__menu.addSeparator()
418 self.__menu.addAction(self.tr("Configure..."), self.__configure)
419
420 self.__backMenu = QMenu(self)
421 self.__backMenu.addAction(self.tr("Add group..."), self.__addGroup)
422 self.__backMenu.addSeparator()
423 self.bmSaveAct = self.__backMenu.addAction(self.tr("Save"), self.save)
424 self.__backMenu.addAction(self.tr("Import..."), self.__import)
425 self.bmExportAct = self.__backMenu.addAction(
426 self.tr("Export..."), self.__export)
427 self.__backMenu.addAction(self.tr("Reload"), self.__reload)
428 self.__backMenu.addSeparator()
429 self.__backMenu.addAction(
430 self.tr("Help about Templates..."), self.__showHelp)
431 self.__backMenu.addSeparator()
432 self.__backMenu.addAction(
433 self.tr("Configure..."), self.__configure)
434
435 self.__activating = False
436 self.__dirty = False
437
438 self.__templatesFile = TemplatesFile(self)
439
440 self.setContextMenuPolicy(Qt.ContextMenuPolicy.CustomContextMenu)
441 self.customContextMenuRequested.connect(self.__showContextMenu)
442 self.itemActivated.connect(self.__templateItemActivated)
443
444 self.setWindowIcon(UI.PixmapCache.getIcon("eric"))
445
446 def __resort(self):
447 """
448 Private method to resort the tree.
449 """
450 self.sortItems(self.sortColumn(), self.header().sortIndicatorOrder())
451
452 def __templateItemActivated(self, itm=None, col=0):
453 """
454 Private slot to handle the activation of an item.
455
456 @param itm reference to the activated item (QTreeWidgetItem)
457 @param col column the item was activated in (integer)
458 """
459 if not self.__activating:
460 self.__activating = True
461 itm = self.currentItem()
462 if isinstance(itm, TemplateEntry):
463 self.applyTemplate(itm)
464 self.__activating = False
465
466 def __showContextMenu(self, coord):
467 """
468 Private slot to show the context menu of the list.
469
470 @param coord the position of the mouse pointer (QPoint)
471 """
472 itm = self.itemAt(coord)
473 coord = self.mapToGlobal(coord)
474 if itm is None:
475 self.bmSaveAct.setEnabled(self.__dirty)
476 self.bmExportAct.setEnabled(self.topLevelItemCount() != 0)
477 self.__backMenu.popup(coord)
478 else:
479 self.applyAct.setEnabled(
480 self.viewmanager.activeWindow() is not None and
481 isinstance(itm, TemplateEntry))
482 self.saveAct.setEnabled(self.__dirty)
483 self.__menu.popup(coord)
484
485 def __addEntry(self):
486 """
487 Private slot to handle the Add Entry context menu action.
488 """
489 itm = self.currentItem()
490 groupName = (
491 itm.getName()
492 if isinstance(itm, TemplateGroup) else
493 itm.getGroupName()
494 )
495
496 from .TemplatePropertiesDialog import TemplatePropertiesDialog
497 dlg = TemplatePropertiesDialog(self)
498 dlg.setSelectedGroup(groupName)
499 if dlg.exec() == QDialog.DialogCode.Accepted:
500 name, description, groupName, template = dlg.getData()
501 self.addEntry(groupName, name, description, template)
502 self.__dirty = True
503
504 def __addGroup(self):
505 """
506 Private slot to handle the Add Group context menu action.
507 """
508 from .TemplatePropertiesDialog import TemplatePropertiesDialog
509 dlg = TemplatePropertiesDialog(self, True)
510 if dlg.exec() == QDialog.DialogCode.Accepted:
511 name, language = dlg.getData()
512 self.addGroup(name, language)
513 self.__dirty = True
514
515 def __edit(self):
516 """
517 Private slot to handle the Edit context menu action.
518 """
519 itm = self.currentItem()
520 editGroup = not isinstance(itm, TemplateEntry)
521
522 from .TemplatePropertiesDialog import TemplatePropertiesDialog
523 dlg = TemplatePropertiesDialog(self, editGroup, itm)
524 if dlg.exec() == QDialog.DialogCode.Accepted:
525 if editGroup:
526 name, language = dlg.getData()
527 self.changeGroup(itm.getName(), name, language)
528 else:
529 name, description, groupName, template = dlg.getData()
530 self.changeEntry(itm, name, groupName, description, template)
531 self.__dirty = True
532
533 def __remove(self):
534 """
535 Private slot to handle the Remove context menu action.
536 """
537 itm = self.currentItem()
538 res = E5MessageBox.yesNo(
539 self,
540 self.tr("Remove Template"),
541 self.tr("""<p>Do you really want to remove <b>{0}</b>?</p>""")
542 .format(itm.getName()))
543 if not res:
544 return
545
546 if isinstance(itm, TemplateGroup):
547 self.removeGroup(itm)
548 else:
549 self.removeEntry(itm)
550 self.__dirty = True
551
552 def save(self):
553 """
554 Public slot to save the templates.
555 """
556 if self.__dirty:
557 ok = self.writeTemplates()
558 if ok:
559 self.__dirty = False
560
561 def __import(self):
562 """
563 Private slot to handle the Import context menu action.
564 """
565 fn = E5FileDialog.getOpenFileName(
566 self,
567 self.tr("Import Templates"),
568 "",
569 self.tr("Templates Files (*.ecj);;"
570 "XML Templates Files (*.e4c);;"
571 "All Files (*)"))
572
573 if fn:
574 self.readTemplates(fn)
575 self.__dirty = True
576
577 def __export(self):
578 """
579 Private slot to handle the Export context menu action.
580 """
581 fn, selectedFilter = E5FileDialog.getSaveFileNameAndFilter(
582 self,
583 self.tr("Export Templates"),
584 "",
585 self.tr("Templates Files (*.ecj);;"
586 "XML Templates Files (*.e4c);;"
587 "All Files (*)"),
588 "",
589 E5FileDialog.Options(E5FileDialog.DontConfirmOverwrite))
590
591 if fn:
592 ext = QFileInfo(fn).suffix()
593 if not ext:
594 ex = selectedFilter.split("(*")[1].split(")")[0]
595 if ex:
596 fn += ex
597 if os.path.exists(fn):
598 ok = E5MessageBox.yesNo(
599 self,
600 self.tr("Export Templates"),
601 self.tr("""<p>The templates file <b>{0}</b> exists"""
602 """ already. Overwrite it?</p>""").format(fn))
603 else:
604 ok = True
605
606 if ok:
607 self.writeTemplates(fn)
608
609 def __reload(self):
610 """
611 Private slot to reload the templates.
612 """
613 if self.__dirty:
614 res = E5MessageBox.yesNo(
615 self,
616 self.tr("Reload Templates"),
617 self.tr(
618 """The templates contain unsaved changes. Shall these"""
619 """ changes be discarded?"""),
620 icon=E5MessageBox.Warning)
621 if not res:
622 return
623
624 self.clear()
625 self.groups = {}
626
627 self.readTemplates()
628
629 def __showHelp(self):
630 """
631 Private method to show some help.
632 """
633 E5MessageBox.information(
634 self,
635 self.tr("Template Help"),
636 self.tr(
637 """<p><b>Template groups</b> are a means of grouping"""
638 """ individual templates. Groups have an attribute that"""
639 """ specifies, which programming language they apply for."""
640 """ In order to add template entries, at least one group"""
641 """ has to be defined.</p>"""
642 """<p><b>Template entries</b> are the actual templates."""
643 """ They are grouped by the template groups. Help about"""
644 """ how to define them is available in the template edit"""
645 """ dialog.</p>"""))
646
647 def __getPredefinedVars(self):
648 """
649 Private method to return predefined variables.
650
651 @return dictionary of predefined variables and their values
652 """
653 project = e5App().getObject("Project")
654 editor = self.viewmanager.activeWindow()
655 now = datetime.datetime.now()
656 sepchar = Preferences.getTemplates("SeparatorChar")
657 keyfmt = sepchar + "{0}" + sepchar
658 varValues = {
659 keyfmt.format('date'): now.date().isoformat(),
660 keyfmt.format('year'): str(now.date().year),
661 keyfmt.format('time'): now.time().strftime("%H:%M:%S"),
662 }
663
664 if project.name:
665 varValues[keyfmt.format('project_name')] = project.name
666
667 if project.ppath:
668 varValues[keyfmt.format('project_path')] = project.ppath
669
670 path_name = editor.getFileName()
671 if path_name:
672 dir_name, file_name = os.path.split(path_name)
673 base_name, ext = os.path.splitext(file_name)
674 if ext:
675 ext = ext[1:]
676 path_name_rel = project.getRelativePath(path_name)
677 dir_name_rel = project.getRelativePath(dir_name)
678 varValues.update({
679 keyfmt.format('path_name'): path_name,
680 keyfmt.format('path_name_rel'): path_name_rel,
681 keyfmt.format('dir_name'): dir_name,
682 keyfmt.format('dir_name_rel'): dir_name_rel,
683 keyfmt.format('file_name'): file_name,
684 keyfmt.format('base_name'): base_name,
685 keyfmt.format('ext'): ext
686 })
687
688 varValues[keyfmt.format('clipboard:ml')] = (
689 QApplication.clipboard().text()
690 )
691 varValues[keyfmt.format('clipboard')] = QApplication.clipboard().text()
692
693 if editor.hasSelectedText():
694 varValues[keyfmt.format('cur_select:ml')] = editor.selectedText()
695 varValues[keyfmt.format('cur_select')] = editor.selectedText()
696 else:
697 varValues[keyfmt.format('cur_select:ml')] = os.linesep
698 varValues[keyfmt.format('cur_select')] = ""
699
700 varValues[keyfmt.format('insertion')] = "i_n_s_e_r_t_i_o_n"
701
702 varValues[keyfmt.format('select_start')] = "s_e_l_e_c_t_s_t_a_r_t"
703 varValues[keyfmt.format('select_end')] = "s_e_l_e_c_t_e_n_d"
704
705 return varValues
706
707 def applyTemplate(self, itm):
708 """
709 Public method to apply the template.
710
711 @param itm reference to the template item to apply (TemplateEntry)
712 """
713 editor = self.viewmanager.activeWindow()
714 if editor is None:
715 return
716
717 ok = False
718 variables = itm.getVariables()
719 varValues = self.__getPredefinedVars()
720
721 # Remove predefined variables from list so user doesn't have to fill
722 # these values out in the dialog.
723 for v in list(varValues.keys()):
724 if v in variables:
725 variables.remove(v)
726
727 if variables:
728 if Preferences.getTemplates("SingleDialog"):
729 from .TemplateMultipleVariablesDialog import (
730 TemplateMultipleVariablesDialog
731 )
732 dlg = TemplateMultipleVariablesDialog(variables, self)
733 if dlg.exec() == QDialog.DialogCode.Accepted:
734 varValues.update(dlg.getVariables())
735 ok = True
736 else:
737 from .TemplateSingleVariableDialog import (
738 TemplateSingleVariableDialog
739 )
740 for var in variables:
741 dlg = TemplateSingleVariableDialog(var, self)
742 if dlg.exec() == QDialog.DialogCode.Accepted:
743 varValues[var] = dlg.getVariable()
744 else:
745 return
746 del dlg
747 ok = True
748 else:
749 ok = True
750
751 if ok:
752 line = editor.text(
753 editor.getCursorPosition()[0]).replace(os.linesep, "")
754 indent = line.replace(line.lstrip(), "")
755 txt, lines, count = itm.getExpandedText(varValues, indent)
756 # It should be done in this way to allow undo
757 editor.beginUndoAction()
758 if editor.hasSelectedText():
759 line, index = editor.getSelection()[0:2]
760 editor.removeSelectedText()
761 else:
762 line, index = editor.getCursorPosition()
763
764 if lines == 1:
765 count += index
766 else:
767 if len(indent) > 0:
768 count += len(indent)
769
770 if "i_n_s_e_r_t_i_o_n" in txt and "s_e_l_e_c_t" in txt:
771 txt = (
772 "'Insertion and selection can not be in"
773 " template together'"
774 )
775
776 if "i_n_s_e_r_t_i_o_n" in txt:
777 lines = 1
778 for aline in txt.splitlines():
779 count = aline.find("i_n_s_e_r_t_i_o_n")
780 if count >= 0:
781 txt = txt.replace("i_n_s_e_r_t_i_o_n", "")
782 if lines == 1:
783 count += index
784 else:
785 if len(indent) > 0:
786 count += len(indent)
787 break
788 else:
789 lines += 1
790
791 setselect = False
792 if "s_e_l_e_c_t_s_t_a_r_t" in txt and "s_e_l_e_c_t_e_n_d" in txt:
793 setselect = True
794 linea = 1
795 for aline in txt.splitlines():
796 posa = aline.find("s_e_l_e_c_t_s_t_a_r_t")
797 if posa >= 0:
798 txt = txt.replace("s_e_l_e_c_t_s_t_a_r_t", "")
799 break
800 else:
801 linea += 1
802 lineb = 1
803 for aline in txt.splitlines():
804 posb = aline.find("s_e_l_e_c_t_e_n_d")
805 if posb >= 0:
806 txt = txt.replace("s_e_l_e_c_t_e_n_d", "")
807 break
808 else:
809 lineb += 1
810
811 editor.insert(txt)
812
813 if setselect:
814 editor.setSelection(line + linea - 1, posa,
815 line + lineb - 1, posb)
816 else:
817 editor.setCursorPosition(line + lines - 1, count)
818
819 editor.endUndoAction()
820 editor.setFocus()
821
822 def applyNamedTemplate(self, templateName, groupName=None):
823 """
824 Public method to apply a template given a template name.
825
826 @param templateName name of the template item to apply (string)
827 @param groupName name of the group to get the entry from (string).
828 None or empty means to apply the first template found with the
829 given name.
830 """
831 if groupName:
832 if self.hasGroup(groupName):
833 groups = [self.groups[groupName]]
834 else:
835 return
836 else:
837 groups = list(self.groups.values())
838 for group in groups:
839 template = group.getEntry(templateName)
840 if template is not None:
841 self.applyTemplate(template)
842 break
843
844 def addEntry(self, groupName, name, description, template, quiet=False):
845 """
846 Public method to add a template entry.
847
848 @param groupName name of the group to add to (string)
849 @param name name of the entry to add (string)
850 @param description description of the entry to add (string)
851 @param template template text of the entry (string)
852 @param quiet flag indicating quiet operation (boolean)
853 """
854 self.groups[groupName].addEntry(
855 name, description, template, quiet=quiet)
856 self.__resort()
857
858 def hasGroup(self, name):
859 """
860 Public method to check, if a group with the given name exists.
861
862 @param name name of the group to be checked for (string)
863 @return flag indicating an existing group (boolean)
864 """
865 return name in self.groups
866
867 def addGroup(self, name, language="All"):
868 """
869 Public method to add a group.
870
871 @param name name of the group to be added (string)
872 @param language programming language for the group (string)
873 """
874 if name not in self.groups:
875 self.groups[name] = TemplateGroup(self, name, language)
876 self.__resort()
877
878 def changeGroup(self, oldname, newname, language="All"):
879 """
880 Public method to rename a group.
881
882 @param oldname old name of the group (string)
883 @param newname new name of the group (string)
884 @param language programming language for the group (string)
885 """
886 if oldname != newname:
887 if newname in self.groups:
888 E5MessageBox.warning(
889 self,
890 self.tr("Edit Template Group"),
891 self.tr("""<p>A template group with the name"""
892 """ <b>{0}</b> already exists.</p>""")
893 .format(newname))
894 return
895
896 self.groups[newname] = self.groups[oldname]
897 del self.groups[oldname]
898 self.groups[newname].setName(newname)
899
900 self.groups[newname].setLanguage(language)
901 self.__resort()
902
903 def getAllGroups(self):
904 """
905 Public method to get all groups.
906
907 @return list of all groups (list of TemplateGroup)
908 """
909 return list(self.groups.values())
910
911 def getGroupNames(self):
912 """
913 Public method to get all group names.
914
915 @return list of all group names (list of strings)
916 """
917 groups = sorted(list(self.groups.keys())[:])
918 return groups
919
920 def removeGroup(self, itm):
921 """
922 Public method to remove a group.
923
924 @param itm template group to be removed (TemplateGroup)
925 """
926 name = itm.getName()
927 itm.removeAllEntries()
928 index = self.indexOfTopLevelItem(itm)
929 self.takeTopLevelItem(index)
930 del self.groups[name]
931
932 def removeEntry(self, itm):
933 """
934 Public method to remove a template entry.
935
936 @param itm template entry to be removed (TemplateEntry)
937 """
938 groupName = itm.getGroupName()
939 self.groups[groupName].removeEntry(itm.getName())
940
941 def changeEntry(self, itm, name, groupName, description, template):
942 """
943 Public method to change a template entry.
944
945 @param itm template entry to be changed (TemplateEntry)
946 @param name new name for the entry (string)
947 @param groupName name of the group the entry should belong to
948 (string)
949 @param description description of the entry (string)
950 @param template template text of the entry (string)
951 """
952 if itm.getGroupName() != groupName:
953 # move entry to another group
954 self.groups[itm.getGroupName()].removeEntry(itm.getName())
955 self.groups[groupName].addEntry(name, description, template)
956 return
957
958 if itm.getName() != name:
959 # entry was renamed
960 self.groups[groupName].removeEntry(itm.getName())
961 self.groups[groupName].addEntry(name, description, template)
962 return
963
964 tmpl = self.groups[groupName].getEntry(name)
965 tmpl.setDescription(description)
966 tmpl.setTemplateText(template)
967 self.__resort()
968
969 def writeTemplates(self, filename=None):
970 """
971 Public method to write the templates data to a JSON file (.ecj).
972
973 @param filename name of a templates file to write
974 @type str
975 @return flag indicating success
976 @rtype bool
977 """
978 if filename is None:
979 filename = os.path.join(
980 Utilities.getConfigDir(), "eric6templates.ecj")
981 if filename.endswith(".ecj"):
982 # new JSON based file
983 res = self.__templatesFile.writeFile(filename)
984 else:
985 # old XML based file
986 f = QFile(filename)
987 ok = f.open(QIODevice.OpenModeFlag.WriteOnly)
988 if not ok:
989 E5MessageBox.critical(
990 self,
991 self.tr("Save Templates"),
992 self.tr(
993 "<p>The templates file <b>{0}</b> could not be"
994 " written.</p>")
995 .format(filename))
996 res = False
997 else:
998 from E5XML.TemplatesWriter import TemplatesWriter
999 TemplatesWriter(f, self).writeXML()
1000 f.close()
1001 res = True
1002
1003 return res
1004
1005 def readTemplates(self, filename=None):
1006 """
1007 Public method to read in the templates file (.e4c).
1008
1009 @param filename name of a templates file to read
1010 @type str
1011 """
1012 if filename is None:
1013 # new JSON based file first
1014 filename = os.path.join(
1015 Utilities.getConfigDir(), "eric6templates.ecj")
1016 if not os.path.exists(filename):
1017 # old XML based file second
1018 filename = os.path.join(
1019 Utilities.getConfigDir(), "eric6templates.e4c")
1020 if not os.path.exists(filename):
1021 return
1022
1023 if filename.endswith(".ecj"):
1024 self.__templatesFile.readFile(filename)
1025 else:
1026 f = QFile(filename)
1027 if f.open(QIODevice.OpenModeFlag.ReadOnly):
1028 from E5XML.TemplatesReader import TemplatesReader
1029 reader = TemplatesReader(f, viewer=self)
1030 reader.readXML()
1031 f.close()
1032 else:
1033 E5MessageBox.critical(
1034 self,
1035 self.tr("Read Templates"),
1036 self.tr(
1037 "<p>The templates file <b>{0}</b> could not be read."
1038 "</p>")
1039 .format(filename))
1040
1041 def __configure(self):
1042 """
1043 Private method to open the configuration dialog.
1044 """
1045 e5App().getObject("UserInterface").showPreferences("templatesPage")
1046
1047 def hasTemplate(self, entryName, groupName=None):
1048 """
1049 Public method to check, if an entry of the given name exists.
1050
1051 @param entryName name of the entry to check for (string)
1052 @param groupName name of the group to check for the entry (string).
1053 None or empty means to check all groups.
1054 @return flag indicating the existence (boolean)
1055 """
1056 if groupName:
1057 if self.hasGroup(groupName):
1058 groups = [self.groups[groupName]]
1059 else:
1060 groups = []
1061 else:
1062 groups = list(self.groups.values())
1063
1064 return any(group.hasEntry(entryName) for group in groups)
1065
1066 def getTemplateNames(self, start, groupName=None):
1067 """
1068 Public method to get the names of templates starting with the
1069 given string.
1070
1071 @param start start string of the name (string)
1072 @param groupName name of the group to get the entry from (string).
1073 None or empty means to look in all groups.
1074 @return sorted list of matching template names (list of strings)
1075 """
1076 names = []
1077 if groupName:
1078 if self.hasGroup(groupName):
1079 groups = [self.groups[groupName]]
1080 else:
1081 groups = []
1082 else:
1083 groups = list(self.groups.values())
1084 for group in groups:
1085 names.extend(group.getEntryNames(start))
1086 return sorted(names)

eric ide

mercurial