src/eric7/Templates/TemplateViewer.py

branch
eric7
changeset 9209
b99e7fd55fd3
parent 9153
506e35e424d5
child 9221
bf71ee032bb4
equal deleted inserted replaced
9208:3fc8dfeb6ebe 9209:b99e7fd55fd3
1 # -*- coding: utf-8 -*-
2
3 # Copyright (c) 2005 - 2022 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 pathlib
13 import re
14
15 from PyQt6.QtCore import QFile, QIODevice, Qt, QCoreApplication
16 from PyQt6.QtWidgets import (
17 QTreeWidget, QDialog, QApplication, QMenu, QTreeWidgetItem
18 )
19
20 from EricWidgets.EricApplication import ericApp
21 from EricWidgets import EricMessageBox, EricFileDialog
22
23 import Preferences
24
25 import UI.PixmapCache
26 import Utilities
27
28 from .TemplatesFile import TemplatesFile
29
30
31 class TemplateGroup(QTreeWidgetItem):
32 """
33 Class implementing a template group.
34 """
35 def __init__(self, parent, name, language="All"):
36 """
37 Constructor
38
39 @param parent parent widget of the template group (QWidget)
40 @param name name of the group (string)
41 @param language programming language for the group (string)
42 """
43 self.name = name
44 self.language = language
45 self.entries = {}
46
47 super().__init__(parent, [name])
48
49 if Preferences.getTemplates("ShowTooltip"):
50 self.setToolTip(0, language)
51
52 def setName(self, name):
53 """
54 Public method to update the name of the group.
55
56 @param name name of the group (string)
57 """
58 self.name = name
59 self.setText(0, name)
60
61 def getName(self):
62 """
63 Public method to get the name of the group.
64
65 @return name of the group (string)
66 """
67 return self.name
68
69 def setLanguage(self, language):
70 """
71 Public method to update the name of the group.
72
73 @param language programming language for the group (string)
74 """
75 self.language = language
76 if Preferences.getTemplates("ShowTooltip"):
77 self.setToolTip(0, language)
78
79 def getLanguage(self):
80 """
81 Public method to get the name of the group.
82
83 @return language of the group (string)
84 """
85 return self.language
86
87 def addEntry(self, name, description, template, quiet=False):
88 """
89 Public method to add a template entry to this group.
90
91 @param name name of the entry (string)
92 @param description description of the entry to add (string)
93 @param template template text of the entry (string)
94 @param quiet flag indicating quiet operation (boolean)
95 """
96 if name in self.entries:
97 if not quiet:
98 EricMessageBox.critical(
99 None,
100 QCoreApplication.translate("TemplateGroup",
101 "Add Template"),
102 QCoreApplication.translate(
103 "TemplateGroup",
104 """<p>The group <b>{0}</b> already contains a"""
105 """ template named <b>{1}</b>.</p>""")
106 .format(self.name, name))
107 return
108
109 self.entries[name] = TemplateEntry(self, name, description, template)
110
111 if (
112 Preferences.getTemplates("AutoOpenGroups") and
113 not self.isExpanded()
114 ):
115 self.setExpanded(True)
116
117 def removeEntry(self, name):
118 """
119 Public method to remove a template entry from this group.
120
121 @param name name of the entry to be removed (string)
122 """
123 if name in self.entries:
124 index = self.indexOfChild(self.entries[name])
125 self.takeChild(index)
126 del self.entries[name]
127
128 if (
129 len(self.entries) == 0 and
130 Preferences.getTemplates("AutoOpenGroups") and
131 self.isExpanded()
132 ):
133 self.setExpanded(False)
134
135 def removeAllEntries(self):
136 """
137 Public method to remove all template entries of this group.
138 """
139 for name in list(self.entries.keys())[:]:
140 self.removeEntry(name)
141
142 def hasEntry(self, name):
143 """
144 Public method to check, if the group has an entry with the given name.
145
146 @param name name of the entry to check for (string)
147 @return flag indicating existence (boolean)
148 """
149 return name in self.entries
150
151 def getEntry(self, name):
152 """
153 Public method to get an entry.
154
155 @param name name of the entry to retrieve (string)
156 @return reference to the entry (TemplateEntry)
157 """
158 try:
159 return self.entries[name]
160 except KeyError:
161 return None
162
163 def getEntryNames(self, beginning):
164 """
165 Public method to get the names of all entries, who's name starts with
166 the given string.
167
168 @param beginning string denoting the beginning of the template name
169 (string)
170 @return list of entry names found (list of strings)
171 """
172 names = []
173 for name in self.entries:
174 if name.startswith(beginning):
175 names.append(name)
176
177 return names
178
179 def getAllEntries(self):
180 """
181 Public method to retrieve all entries.
182
183 @return list of all entries (list of TemplateEntry)
184 """
185 return list(self.entries.values())
186
187
188 class TemplateEntry(QTreeWidgetItem):
189 """
190 Class immplementing a template entry.
191 """
192 def __init__(self, parent, name, description, templateText):
193 """
194 Constructor
195
196 @param parent parent widget of the template entry (QWidget)
197 @param name name of the entry (string)
198 @param description descriptive text for the template (string)
199 @param templateText text of the template entry (string)
200 """
201 self.name = name
202 self.description = description
203 self.template = templateText
204 self.__extractVariables()
205
206 super().__init__(parent, [self.__displayText()])
207 if Preferences.getTemplates("ShowTooltip"):
208 self.setToolTip(0, self.template)
209
210 def __displayText(self):
211 """
212 Private method to generate the display text.
213
214 @return display text (string)
215 """
216 txt = (
217 "{0} - {1}".format(self.name, self.description)
218 if self.description else
219 self.name
220 )
221 return txt
222
223 def setName(self, name):
224 """
225 Public method to update the name of the entry.
226
227 @param name name of the entry (string)
228 """
229 self.name = name
230 self.setText(0, self.__displayText())
231
232 def getName(self):
233 """
234 Public method to get the name of the entry.
235
236 @return name of the entry (string)
237 """
238 return self.name
239
240 def setDescription(self, description):
241 """
242 Public method to update the description of the entry.
243
244 @param description description of the entry (string)
245 """
246 self.description = description
247 self.setText(0, self.__displayText())
248
249 def getDescription(self):
250 """
251 Public method to get the description of the entry.
252
253 @return description of the entry (string)
254 """
255 return self.description
256
257 def getGroupName(self):
258 """
259 Public method to get the name of the group this entry belongs to.
260
261 @return name of the group containing this entry (string)
262 """
263 return self.parent().getName()
264
265 def setTemplateText(self, templateText):
266 """
267 Public method to update the template text.
268
269 @param templateText text of the template entry (string)
270 """
271 self.template = templateText
272 self.__extractVariables()
273 if Preferences.getTemplates("ShowTooltip"):
274 self.setToolTip(0, self.template)
275
276 def getTemplateText(self):
277 """
278 Public method to get the template text.
279
280 @return the template text (string)
281 """
282 return self.template
283
284 def getExpandedText(self, varDict, indent):
285 """
286 Public method to get the template text with all variables expanded.
287
288 @param varDict dictionary containing the texts of each variable
289 with the variable name as key.
290 @param indent indentation of the line receiving he expanded
291 template text (string)
292 @return a tuple of the expanded template text (string), the
293 number of lines (integer) and the length of the last line (integer)
294 """
295 txt = self.template
296 for var, val in list(varDict.items()):
297 txt = (
298 self.__expandFormattedVariable(var, val, txt)
299 if var in self.formatedVariables else
300 txt.replace(var, val)
301 )
302 sepchar = Preferences.getTemplates("SeparatorChar")
303 txt = txt.replace("{0}{1}".format(sepchar, sepchar), sepchar)
304 prefix = "{0}{1}".format(os.linesep, indent)
305 trailingEol = txt.endswith(os.linesep)
306 lines = txt.splitlines()
307 lineCount = len(lines)
308 lineLen = len(lines[-1])
309 txt = prefix.join(lines).lstrip()
310 if trailingEol:
311 txt = "{0}{1}".format(txt, os.linesep)
312 lineCount += 1
313 lineLen = 0
314 return txt, lineCount, lineLen
315
316 def __expandFormattedVariable(self, var, val, txt):
317 """
318 Private method to expand a template variable with special formatting.
319
320 @param var template variable name (string)
321 @param val value of the template variable (string)
322 @param txt template text (string)
323 @return expanded and formatted variable (string)
324 """
325 t = ""
326 for line in txt.splitlines():
327 ind = line.find(var)
328 if ind >= 0:
329 variableFormat = var[1:-1].split(':', 1)[1]
330 if variableFormat == 'rl':
331 prefix = line[:ind]
332 postfix = line[ind + len(var):]
333 for v in val.splitlines():
334 t = "{0}{1}{2}{3}{4}".format(
335 t, os.linesep, prefix, v, postfix)
336 elif variableFormat == 'ml':
337 indent = line.replace(line.lstrip(), "")
338 prefix = line[:ind]
339 postfix = line[ind + len(var):]
340 for count, v in enumerate(val.splitlines()):
341 t = (
342 "{0}{1}{2}{3}".format(t, os.linesep, indent, v)
343 if count else
344 "{0}{1}{2}{3}".format(t, os.linesep, prefix, v)
345 )
346 t = "{0}{1}".format(t, postfix)
347 else:
348 t = "{0}{1}{2}".format(t, os.linesep, line)
349 else:
350 t = "{0}{1}{2}".format(t, os.linesep, line)
351 return "".join(t.splitlines(1)[1:])
352
353 def getVariables(self):
354 """
355 Public method to get the list of variables.
356
357 @return list of variables (list of strings)
358 """
359 return self.variables
360
361 def __extractVariables(self):
362 """
363 Private method to retrieve the list of variables.
364 """
365 sepchar = Preferences.getTemplates("SeparatorChar")
366 variablesPattern = re.compile(
367 r"""\{0}[a-zA-Z][a-zA-Z0-9_]*(?::(?:ml|rl))?\{1}""".format(
368 sepchar, sepchar)
369 )
370 variables = variablesPattern.findall(self.template)
371 self.variables = []
372 self.formatedVariables = []
373 for var in variables:
374 if var not in self.variables:
375 self.variables.append(var)
376 if var.find(':') >= 0 and var not in self.formatedVariables:
377 self.formatedVariables.append(var)
378
379
380 class TemplateViewer(QTreeWidget):
381 """
382 Class implementing the template viewer.
383 """
384 def __init__(self, parent, viewmanager):
385 """
386 Constructor
387
388 @param parent the parent (QWidget)
389 @param viewmanager reference to the viewmanager object
390 """
391 super().__init__(parent)
392
393 self.viewmanager = viewmanager
394 self.groups = {}
395
396 self.setHeaderLabels(["Template"])
397 self.header().hide()
398 self.header().setSortIndicator(0, Qt.SortOrder.AscendingOrder)
399 self.setRootIsDecorated(True)
400 self.setAlternatingRowColors(True)
401
402 self.__menu = QMenu(self)
403 self.applyAct = self.__menu.addAction(
404 self.tr("Apply"), self.__templateItemActivated)
405 self.__menu.addSeparator()
406 self.__menu.addAction(self.tr("Add entry..."), self.__addEntry)
407 self.__menu.addAction(self.tr("Add group..."), self.__addGroup)
408 self.__menu.addAction(self.tr("Edit..."), self.__edit)
409 self.__menu.addAction(self.tr("Remove"), self.__remove)
410 self.__menu.addSeparator()
411 self.saveAct = self.__menu.addAction(self.tr("Save"), self.save)
412 self.__menu.addAction(self.tr("Import..."), self.__import)
413 self.__menu.addAction(self.tr("Export..."), self.__export)
414 self.__menu.addAction(self.tr("Reload"), self.__reload)
415 self.__menu.addSeparator()
416 self.__menu.addAction(
417 self.tr("Help about Templates..."), self.__showHelp)
418 self.__menu.addSeparator()
419 self.__menu.addAction(self.tr("Configure..."), self.__configure)
420
421 self.__backMenu = QMenu(self)
422 self.__backMenu.addAction(self.tr("Add group..."), self.__addGroup)
423 self.__backMenu.addSeparator()
424 self.bmSaveAct = self.__backMenu.addAction(self.tr("Save"), self.save)
425 self.__backMenu.addAction(self.tr("Import..."), self.__import)
426 self.bmExportAct = self.__backMenu.addAction(
427 self.tr("Export..."), self.__export)
428 self.__backMenu.addAction(self.tr("Reload"), self.__reload)
429 self.__backMenu.addSeparator()
430 self.__backMenu.addAction(
431 self.tr("Help about Templates..."), self.__showHelp)
432 self.__backMenu.addSeparator()
433 self.__backMenu.addAction(
434 self.tr("Configure..."), self.__configure)
435
436 self.__activating = False
437 self.__dirty = False
438
439 self.__templatesFile = TemplatesFile(self)
440
441 self.setContextMenuPolicy(Qt.ContextMenuPolicy.CustomContextMenu)
442 self.customContextMenuRequested.connect(self.__showContextMenu)
443 self.itemActivated.connect(self.__templateItemActivated)
444
445 self.setWindowIcon(UI.PixmapCache.getIcon("eric"))
446
447 def __resort(self):
448 """
449 Private method to resort the tree.
450 """
451 self.sortItems(self.sortColumn(), self.header().sortIndicatorOrder())
452
453 def __templateItemActivated(self, itm=None, col=0):
454 """
455 Private slot to handle the activation of an item.
456
457 @param itm reference to the activated item (QTreeWidgetItem)
458 @param col column the item was activated in (integer)
459 """
460 if not self.__activating:
461 self.__activating = True
462 itm = self.currentItem()
463 if isinstance(itm, TemplateEntry):
464 self.applyTemplate(itm)
465 self.__activating = False
466
467 def __showContextMenu(self, coord):
468 """
469 Private slot to show the context menu of the list.
470
471 @param coord the position of the mouse pointer (QPoint)
472 """
473 itm = self.itemAt(coord)
474 coord = self.mapToGlobal(coord)
475 if itm is None:
476 self.bmSaveAct.setEnabled(self.__dirty)
477 self.bmExportAct.setEnabled(self.topLevelItemCount() != 0)
478 self.__backMenu.popup(coord)
479 else:
480 self.applyAct.setEnabled(
481 self.viewmanager.activeWindow() is not None and
482 isinstance(itm, TemplateEntry))
483 self.saveAct.setEnabled(self.__dirty)
484 self.__menu.popup(coord)
485
486 def __addEntry(self):
487 """
488 Private slot to handle the Add Entry context menu action.
489 """
490 itm = self.currentItem()
491 groupName = (
492 itm.getName()
493 if isinstance(itm, TemplateGroup) else
494 itm.getGroupName()
495 )
496
497 from .TemplatePropertiesDialog import TemplatePropertiesDialog
498 dlg = TemplatePropertiesDialog(self)
499 dlg.setSelectedGroup(groupName)
500 if dlg.exec() == QDialog.DialogCode.Accepted:
501 name, description, groupName, template = dlg.getData()
502 self.addEntry(groupName, name, description, template)
503 self.__dirty = True
504
505 def __addGroup(self):
506 """
507 Private slot to handle the Add Group context menu action.
508 """
509 from .TemplatePropertiesDialog import TemplatePropertiesDialog
510 dlg = TemplatePropertiesDialog(self, True)
511 if dlg.exec() == QDialog.DialogCode.Accepted:
512 name, language = dlg.getData()
513 self.addGroup(name, language)
514 self.__dirty = True
515
516 def __edit(self):
517 """
518 Private slot to handle the Edit context menu action.
519 """
520 itm = self.currentItem()
521 editGroup = not isinstance(itm, TemplateEntry)
522
523 from .TemplatePropertiesDialog import TemplatePropertiesDialog
524 dlg = TemplatePropertiesDialog(self, editGroup, itm)
525 if dlg.exec() == QDialog.DialogCode.Accepted:
526 if editGroup:
527 name, language = dlg.getData()
528 self.changeGroup(itm.getName(), name, language)
529 else:
530 name, description, groupName, template = dlg.getData()
531 self.changeEntry(itm, name, groupName, description, template)
532 self.__dirty = True
533
534 def __remove(self):
535 """
536 Private slot to handle the Remove context menu action.
537 """
538 itm = self.currentItem()
539 res = EricMessageBox.yesNo(
540 self,
541 self.tr("Remove Template"),
542 self.tr("""<p>Do you really want to remove <b>{0}</b>?</p>""")
543 .format(itm.getName()))
544 if not res:
545 return
546
547 if isinstance(itm, TemplateGroup):
548 self.removeGroup(itm)
549 else:
550 self.removeEntry(itm)
551 self.__dirty = True
552
553 def save(self):
554 """
555 Public slot to save the templates.
556 """
557 if self.__dirty:
558 ok = self.writeTemplates()
559 if ok:
560 self.__dirty = False
561
562 def __import(self):
563 """
564 Private slot to handle the Import context menu action.
565 """
566 fn = EricFileDialog.getOpenFileName(
567 self,
568 self.tr("Import Templates"),
569 "",
570 self.tr("Templates Files (*.ecj);;"
571 "XML Templates Files (*.e4c);;"
572 "All Files (*)"))
573
574 if fn:
575 self.readTemplates(fn)
576 self.__dirty = True
577
578 def __export(self):
579 """
580 Private slot to handle the Export context menu action.
581 """
582 fn, selectedFilter = EricFileDialog.getSaveFileNameAndFilter(
583 self,
584 self.tr("Export Templates"),
585 "",
586 self.tr("Templates Files (*.ecj);;"
587 "All Files (*)"),
588 "",
589 EricFileDialog.DontConfirmOverwrite)
590
591 if fn:
592 fpath = pathlib.Path(fn)
593 if not fpath.suffix:
594 ex = selectedFilter.split("(*")[1].split(")")[0]
595 if ex:
596 fpath = fpath.with_suffix(ex)
597 if fpath.exists():
598 ok = EricMessageBox.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(fpath))
603 else:
604 ok = True
605
606 if ok:
607 self.writeTemplates(str(fpath))
608
609 def __reload(self):
610 """
611 Private slot to reload the templates.
612 """
613 if self.__dirty:
614 res = EricMessageBox.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=EricMessageBox.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 EricMessageBox.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 = ericApp().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 EricMessageBox.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(), "eric7templates.ecj")
981
982 return self.__templatesFile.writeFile(filename)
983
984 def readTemplates(self, filename=None):
985 """
986 Public method to read in the templates file (.e4c).
987
988 @param filename name of a templates file to read
989 @type str
990 """
991 if filename is None:
992 # new JSON based file first
993 filename = os.path.join(
994 Utilities.getConfigDir(), "eric7templates.ecj")
995 if not os.path.exists(filename):
996 # old XML based file second
997 filename = os.path.join(
998 Utilities.getConfigDir(), "eric7templates.e4c")
999 if not os.path.exists(filename):
1000 return
1001
1002 if filename.endswith(".ecj"):
1003 self.__templatesFile.readFile(filename)
1004 else:
1005 f = QFile(filename)
1006 if f.open(QIODevice.OpenModeFlag.ReadOnly):
1007 from EricXML.TemplatesReader import TemplatesReader
1008 reader = TemplatesReader(f, viewer=self)
1009 reader.readXML()
1010 f.close()
1011 else:
1012 EricMessageBox.critical(
1013 self,
1014 self.tr("Read Templates"),
1015 self.tr(
1016 "<p>The templates file <b>{0}</b> could not be read."
1017 "</p>")
1018 .format(filename))
1019
1020 def __configure(self):
1021 """
1022 Private method to open the configuration dialog.
1023 """
1024 ericApp().getObject("UserInterface").showPreferences("templatesPage")
1025
1026 def hasTemplate(self, entryName, groupName=None):
1027 """
1028 Public method to check, if an entry of the given name exists.
1029
1030 @param entryName name of the entry to check for (string)
1031 @param groupName name of the group to check for the entry (string).
1032 None or empty means to check all groups.
1033 @return flag indicating the existence (boolean)
1034 """
1035 if groupName:
1036 if self.hasGroup(groupName):
1037 groups = [self.groups[groupName]]
1038 else:
1039 groups = []
1040 else:
1041 groups = list(self.groups.values())
1042
1043 return any(group.hasEntry(entryName) for group in groups)
1044
1045 def getTemplateNames(self, start, groupName=None):
1046 """
1047 Public method to get the names of templates starting with the
1048 given string.
1049
1050 @param start start string of the name (string)
1051 @param groupName name of the group to get the entry from (string).
1052 None or empty means to look in all groups.
1053 @return sorted list of matching template names (list of strings)
1054 """
1055 names = []
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 for group in groups:
1064 names.extend(group.getEntryNames(start))
1065 return sorted(names)

eric ide

mercurial