1 # -*- coding: utf-8 -*-
2 #Author: Pierre Ratinaud
3 #Copyright (c) 2012, Pierre Ratinaud
9 import wx.lib.agw.customtreectrl as CT
11 from openanalyse import OpenAnalyse
12 from corpus import Corpus, copycorpus
13 from tableau import Tableau, copymatrix
14 from functions import DoConf, GetTxtProfile, TGen
15 from profile_segment import ProfileSegment, ProfilType
16 from search_tools import SearchFrame
17 from dialog import PrefSimpleFile, PrefExport
18 from layout import open_antiprofil, TgenLayout
19 from guifunct import TGenFrame
20 from textaslexico import TgenSpec
22 log = logging.getLogger('iramuteq.tree')
24 class InfoDialog ( wx.Dialog ):
26 def __init__( self, parent, txt, parametres ):
27 wx.Dialog.__init__ ( self, parent, id = wx.ID_ANY, title = u"Informations", pos = wx.DefaultPosition, size = wx.DefaultSize, style = wx.DEFAULT_DIALOG_STYLE )
28 if len(parametres) > 30 :
32 self.SetSizeHintsSz( wx.Size( 500,200 ), wx.DefaultSize )
34 bSizer1 = wx.BoxSizer( wx.VERTICAL )
36 self.m_panel2 = wx.Panel( self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.TAB_TRAVERSAL )
37 bSizer2 = wx.BoxSizer( wx.VERTICAL )
39 self.m_staticText4 = wx.StaticText( self.m_panel2, wx.ID_ANY, txt, wx.DefaultPosition, wx.DefaultSize, 0 )
40 self.m_staticText4.Wrap( -1 )
41 bSizer2.Add( self.m_staticText4, 0, wx.ALL, 5 )
44 self.m_panel2.SetSizer( bSizer2 )
45 self.m_panel2.Layout()
46 bSizer2.Fit( self.m_panel2 )
47 bSizer1.Add( self.m_panel2, 0, wx.EXPAND |wx.ALL, 5 )
49 self.m_panel1 = wx.Panel( self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.TAB_TRAVERSAL )
51 fgSizer1 = wx.FlexGridSizer( 0, nb, 0, 0 )
52 fgSizer1.SetFlexibleDirection( wx.BOTH )
53 fgSizer1.SetNonFlexibleGrowMode( wx.FLEX_GROWMODE_SPECIFIED )
56 for val in parametres :
57 fgSizer1.Add( wx.StaticText( self.m_panel1, wx.ID_ANY, val[0], wx.DefaultPosition, wx.DefaultSize, 0 ), 0, wx.ALL, 0)
58 #fgSizer1.Add( wx.StaticText( self.m_panel1, wx.ID_ANY, val[1], wx.DefaultPosition, wx.DefaultSize, 0 ), 0, wx.ALL, 0)
59 txtctrl.append( wx.TextCtrl( self.m_panel1, wx.ID_ANY, val[1], wx.DefaultPosition, (450, 20), wx.TE_READONLY ) )
60 txtctrl[-1].SetBackgroundColour('#DDE8EB')
61 #wx.SystemSettings.GetColour(wx.SYS_COLOUR_GRAYTEXT))
62 fgSizer1.Add( txtctrl[-1], 0, wx.ALL|wx.EXPAND, 0)
63 #fgSizer1.Add( wx.StaticLine( self.m_panel1, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.LI_HORIZONTAL ), 0, wx.EXPAND |wx.ALL, 0)
64 #fgSizer1.Add( wx.StaticLine( self.m_panel1, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.LI_HORIZONTAL ), 0, wx.EXPAND|wx.ALL, 0)
66 self.m_panel1.SetSizer( fgSizer1 )
67 self.m_panel1.Layout()
68 fgSizer1.Fit( self.m_panel1 )
69 bSizer1.Add( self.m_panel1, 0, wx.EXPAND|wx.ALL, 3 )
71 m_sdbSizer1 = wx.StdDialogButtonSizer()
72 self.m_sdbSizer1OK = wx.Button( self, wx.ID_OK )
73 m_sdbSizer1.AddButton( self.m_sdbSizer1OK )
74 m_sdbSizer1.Realize();
76 bSizer1.Add( m_sdbSizer1, 0, wx.EXPAND, 5 )
79 self.SetSizer( bSizer1 )
83 self.Centre( wx.BOTH )
89 class LeftTree(CT.CustomTreeCtrl):
91 def __init__(self, parent, id=wx.ID_ANY, pos=wx.DefaultPosition,
93 style=wx.SUNKEN_BORDER|wx.WANTS_CHARS,
94 agwStyle=CT.TR_HIDE_ROOT|CT.TR_HAS_BUTTONS|CT.TR_HAS_VARIABLE_ROW_HEIGHT):
96 CT.CustomTreeCtrl.__init__(self, parent, id, pos, size, style, agwStyle)
102 if data.startswith("TR_"):
103 treestyles.append(data)
104 elif data.startswith("EVT_"):
108 self.styles = treestyles
111 self.il = wx.ImageList(16, 16)
113 imgtextroot = self.il.Add(wx.Image(os.path.join(self.parent.images_path,'textroot.png'), wx.BITMAP_TYPE_PNG).Scale(16,16).ConvertToBitmap())
114 self.ild['alceste'] = self.il.Add(wx.Image(os.path.join(self.parent.images_path,'reinert.png'), wx.BITMAP_TYPE_PNG).Scale(16,16).ConvertToBitmap())
115 self.ild['corpus'] = self.il.Add(wx.Image(os.path.join(self.parent.images_path,'textcorpus.png'), wx.BITMAP_TYPE_PNG).Scale(16,16).ConvertToBitmap())
116 self.ild['wordcloud'] = self.il.Add(wx.Image(os.path.join(self.parent.images_path,'wordcloud.png'), wx.BITMAP_TYPE_PNG).Scale(16,16).ConvertToBitmap())
117 self.ild['stat'] = self.il.Add(wx.Image(os.path.join(self.parent.images_path,'stats.png'), wx.BITMAP_TYPE_PNG).Scale(16,16).ConvertToBitmap())
118 self.ild['simitxt'] = self.il.Add(wx.Image(os.path.join(self.parent.images_path,'simitxt.png'), wx.BITMAP_TYPE_PNG).Scale(16,16).ConvertToBitmap())
119 self.ild['clustersimitxt'] = self.il.Add(wx.Image(os.path.join(self.parent.images_path,'clustersimitxt.png'), wx.BITMAP_TYPE_PNG).Scale(16,16).ConvertToBitmap())
120 self.ild['clustercloud'] = self.il.Add(wx.Image(os.path.join(self.parent.images_path,'clustercloud.png'), wx.BITMAP_TYPE_PNG).Scale(16,16).ConvertToBitmap())
121 self.ild['spec'] = self.il.Add(wx.Image(os.path.join(self.parent.images_path,'spec.png'), wx.BITMAP_TYPE_PNG).Scale(16,16).ConvertToBitmap())
122 imgmatroot = self.il.Add(wx.Image(os.path.join(self.parent.images_path,'matroot.png'), wx.BITMAP_TYPE_PNG).Scale(16,16).ConvertToBitmap())
123 self.ild['matrix'] = self.il.Add(wx.Image(os.path.join(self.parent.images_path,'matrix.png'), wx.BITMAP_TYPE_PNG).Scale(16,16).ConvertToBitmap())
124 self.ild['freq'] = self.il.Add(wx.Image(os.path.join(self.parent.images_path,'frequences.png'), wx.BITMAP_TYPE_PNG).Scale(16,16).ConvertToBitmap())
125 self.ild['chi2'] = self.il.Add(wx.Image(os.path.join(self.parent.images_path,'chi2.png'), wx.BITMAP_TYPE_PNG).Scale(16,16).ConvertToBitmap())
126 self.ild['reinertmatrix'] = self.il.Add(wx.Image(os.path.join(self.parent.images_path,'reinertmatrix.png'), wx.BITMAP_TYPE_PNG).Scale(16,16).ConvertToBitmap())
127 self.ild['simimatrix'] = self.il.Add(wx.Image(os.path.join(self.parent.images_path,'simimatrix.png'), wx.BITMAP_TYPE_PNG).Scale(16,16).ConvertToBitmap())
128 self.SetImageList(self.il)
133 self.history = parent.history
134 self.h = self.history.history
135 self.root = self.AddRoot("Iramuteq")
137 if not(self.GetAGWWindowStyleFlag() & CT.TR_HIDE_ROOT):
138 self.SetPyData(self.root, None)
139 self.SetItemImage(self.root, 24, CT.TreeItemIcon_Normal)
140 self.SetItemImage(self.root, 13, CT.TreeItemIcon_Expanded)
142 self.textroot = self.AppendItem(self.root, u'Corpus texte')
143 self.SetPyData(self.textroot, {'uuid': 'textroot'})
144 self.SetItemImage(self.textroot, imgtextroot, CT.TreeItemIcon_Normal)
145 self.SetItemImage(self.textroot, imgtextroot, CT.TreeItemIcon_Expanded)
147 for corpus in reversed(self.h) :
148 child = self.AppendItem(self.textroot, corpus['corpus_name'])
149 self.SetPyData(child, corpus)
150 self.SetItemImage(child, self.ild['corpus'], CT.TreeItemIcon_Normal)
151 self.SetItemImage(child, self.ild['corpus'], CT.TreeItemIcon_Expanded)
153 if 'analyses' in corpus :
154 for y in corpus['analyses'] :
155 last = self.AppendItem(child, y['name'], ct_type=0)
156 self.SetPyData(last, y)
157 if y['type'] in self.ild :
158 img = self.ild[y['type']]
161 self.SetItemImage(last, img, CT.TreeItemIcon_Normal)
162 self.SetItemImage(last, img, CT.TreeItemIcon_Expanded)
164 self.matroot = self.AppendItem(self.root, u'Matrices')
165 self.SetPyData(self.matroot, {'uuid': 'matroot'})
166 self.SetItemImage(self.matroot, imgmatroot, CT.TreeItemIcon_Normal)
167 self.SetItemImage(self.matroot, imgmatroot, CT.TreeItemIcon_Expanded)
170 for matrix in reversed(self.history.matrix) :
171 if 'matrix_name' in matrix :
172 child = self.AppendItem(self.matroot, matrix['matrix_name'])
173 self.SetPyData(child, matrix)
174 self.SetItemImage(child, self.ild['matrix'], CT.TreeItemIcon_Normal)
175 self.SetItemImage(child, self.ild['matrix'], CT.TreeItemIcon_Expanded)
176 if 'analyses' in matrix :
177 for y in matrix['analyses'] :
178 last = self.AppendItem(child, y['name'], ct_type=0)
179 self.SetPyData(last, y)
180 if y['type'] in self.ild :
181 img = self.ild[y['type']]
184 self.SetItemImage(last, img, CT.TreeItemIcon_Normal)
185 self.SetItemImage(last, img, CT.TreeItemIcon_Expanded)
187 orphmat.append(matrix)
189 self.Bind(wx.EVT_LEFT_DCLICK, self.OnLeftDClick)
190 #self.Bind(wx.EVT_IDLE, self.OnIdle)
192 self.eventdict = {'EVT_TREE_BEGIN_DRAG': self.OnBeginDrag, 'EVT_TREE_BEGIN_LABEL_EDIT': self.OnBeginEdit,
193 'EVT_TREE_BEGIN_RDRAG': self.OnBeginRDrag, 'EVT_TREE_DELETE_ITEM': self.OnDeleteItem,
194 'EVT_TREE_END_DRAG': self.OnEndDrag, 'EVT_TREE_END_LABEL_EDIT': self.OnEndEdit,
195 'EVT_TREE_ITEM_ACTIVATED': self.OnActivate, 'EVT_TREE_ITEM_CHECKED': self.OnItemCheck,
196 'EVT_TREE_ITEM_CHECKING': self.OnItemChecking, 'EVT_TREE_ITEM_COLLAPSED': self.OnItemCollapsed,
197 'EVT_TREE_ITEM_COLLAPSING': self.OnItemCollapsing, 'EVT_TREE_ITEM_EXPANDED': self.OnItemExpanded,
198 'EVT_TREE_ITEM_EXPANDING': self.OnItemExpanding, 'EVT_TREE_ITEM_GETTOOLTIP': self.OnToolTip,
199 'EVT_TREE_ITEM_MENU': self.OnItemMenu, 'EVT_TREE_ITEM_RIGHT_CLICK': self.OnRightDown,
200 'EVT_TREE_KEY_DOWN': self.OnKey, 'EVT_TREE_SEL_CHANGED': self.OnSelChanged,
201 'EVT_TREE_SEL_CHANGING': self.OnSelChanging, "EVT_TREE_ITEM_HYPERLINK": self.OnHyperLink}
203 mainframe = wx.GetTopLevelParent(self)
205 if not hasattr(mainframe, "leftpanel"):
206 #self.Bind(CT.EVT_TREE_ITEM_EXPANDED, self.OnItemExpanded)
207 #self.Bind(CT.EVT_TREE_ITEM_COLLAPSED, self.OnItemCollapsed)
208 self.Bind(CT.EVT_TREE_SEL_CHANGED, self.OnSelChanged)
209 self.Bind(CT.EVT_TREE_SEL_CHANGING, self.OnSelChanging)
210 self.Bind(wx.EVT_RIGHT_DOWN, self.OnRightDown)
211 self.Bind(wx.EVT_RIGHT_UP, self.OnRightUp)
213 for combos in mainframe.treeevents:
214 self.BindEvents(combos)
216 if hasattr(mainframe, "leftpanel"):
217 self.ChangeStyle(mainframe.treestyles)
219 if not(self.GetAGWWindowStyleFlag() & CT.TR_HIDE_ROOT):
220 self.SelectItem(self.root)
221 self.Expand(self.root)
224 def BindEvents(self, choice, recreate=False):
226 value = choice.GetValue()
227 text = choice.GetLabel()
230 binder = self.eventdict[text]
233 if evt == "CT.EVT_TREE_BEGIN_RDRAG":
234 self.Bind(wx.EVT_RIGHT_DOWN, None)
235 self.Bind(wx.EVT_RIGHT_UP, None)
236 self.Bind(eval(evt), binder)
238 self.Bind(eval(evt), None)
239 if evt == "CT.EVT_TREE_BEGIN_RDRAG":
240 self.Bind(wx.EVT_RIGHT_DOWN, self.OnRightDown)
241 self.Bind(wx.EVT_RIGHT_UP, self.OnRightUp)
244 def ChangeStyle(self, combos):
248 if combo.GetValue() == 1:
249 style = style | eval("CT." + combo.GetLabel())
251 if self.GetAGWWindowStyleFlag() != style:
252 self.SetAGWWindowStyleFlag(style)
255 def OnCompareItems(self, item1, item2):
257 t1 = self.GetItemText(item1)
258 t2 = self.GetItemText(item2)
269 def OnIdle(self, event):
273 # if self.gauge.IsEnabled() and self.gauge.IsShown():
274 # self.count = self.count + 1
276 # if self.count >= 50:
279 # self.gauge.SetValue(self.count)
287 def CloseItem(self, itemParent = None, uuid = None) :
288 if itemParent is None :
289 itemParent = self.root
290 child, cookie = self.GetFirstChild(itemParent)
292 pydata = self.GetPyData(child)
293 if pydata['uuid'] == uuid :
294 self.SetItemBold(child, False)
296 self.CloseItem(child, uuid)
297 child, cookie = self.GetNextChild(itemParent, cookie)
299 def GiveFocus(self, itemParent = None, uuid = None, bold = False) :
300 if itemParent is None :
301 itemParent = self.root
302 child, cookie = self.GetFirstChild(itemParent)
304 pydata = self.GetPyData(child)
305 if pydata['uuid'] == uuid :
306 self.SelectItem(child)
308 self.SetItemBold(child, True)
310 self.GiveFocus(child, uuid, bold)
311 child, cookie = self.GetNextChild(itemParent, cookie)
313 def IsInTree(self, itemParent = None, uuid = None) :
314 if itemParent is None :
315 itemParent = self.root
316 child, cookie = self.GetFirstChild(itemParent)
319 pydata = self.GetPyData(child)
320 if pydata['uuid'] == uuid :
322 self.GiveFocus(child, uuid)
323 child, cookie = self.GetNextChild(itemParent, cookie)
327 def OnRightDown(self, event):
329 pt = event.GetPosition()
330 item, flags = self.HitTest(pt)
334 #self.log.info("OnRightClick: %s, %s, %s" % (self.GetItemText(item), type(item), item.__class__) + "\n")
335 self.SelectItem(item)
338 def OnRightUp(self, event):
346 if not self.IsItemEnabled(item):
350 # Item Text Appearance
351 ishtml = self.IsItemHyperText(item)
352 back = self.GetItemBackgroundColour(item)
353 fore = self.GetItemTextColour(item)
354 isbold = self.IsBold(item)
355 font = self.GetItemFont(item)
358 normal = self.GetItemImage(item, CT.TreeItemIcon_Normal)
359 selected = self.GetItemImage(item, CT.TreeItemIcon_Selected)
360 expanded = self.GetItemImage(item, CT.TreeItemIcon_Expanded)
361 selexp = self.GetItemImage(item, CT.TreeItemIcon_SelectedExpanded)
363 # Enabling/Disabling Windows Associated To An Item
364 haswin = self.GetItemWindow(item)
366 # Enabling/Disabling Items
367 enabled = self.IsItemEnabled(item)
369 # Generic Item's Info
370 children = self.GetChildrenCount(item)
371 itemtype = self.GetItemType(item)
372 text = self.GetItemText(item)
373 pydata = self.GetPyData(item)
377 self.itemdict = {"ishtml": ishtml, "back": back, "fore": fore, "isbold": isbold,
378 "font": font, "normal": normal, "selected": selected, "expanded": expanded,
379 "selexp": selexp, "haswin": haswin, "children": children,
380 "itemtype": itemtype, "text": text, "pydata": pydata, "enabled": enabled}
382 if not item in [self.textroot, self.matroot] :
384 info = menu.Append(wx.ID_ANY, _(u"Informations").encode('utf8'))
385 rename = menu.Append(wx.ID_ANY, _(u"Rename").encode('utf8'))
386 menu.AppendSeparator()
388 if 'corpus_name' in pydata :
389 stat = menu.Append(wx.ID_ANY, _(u"Statistics").decode('utf8'))
390 spec = menu.Append(wx.ID_ANY, _(u"Specificities and CA").decode('utf8'))
391 classification = wx.Menu()
392 reinert = classification.Append(wx.ID_ANY, _(u"Reinert method").decode('utf8'))
393 #pam = classification.Append(wx.ID_ANY, u"Par matrice des distances")
394 menu.AppendMenu(-1, _(u"Clustering").decode('utf8'), classification)
395 simi = menu.Append(wx.ID_ANY, _(u"Similarities analysis").decode('utf8'))
396 wdc = menu.Append(wx.ID_ANY, _(u"Wordcloud").decode('utf8'))
397 subcorpus = wx.Menu()
398 subcorpusfrommeta = subcorpus.Append(wx.ID_ANY, _(u'Sub corpus from metadata').decode('utf8'))
399 subcorpusfromtheme = subcorpus.Append(wx.ID_ANY, _(u'Sub corpus from thematic').decode('utf8'))
400 menu.AppendMenu(-1, _(u"Sub corpus").decode('utf8'), subcorpus)
401 menu.AppendSeparator()
402 self.Bind(wx.EVT_MENU, self.OnReinert, reinert)
403 #self.Bind(wx.EVT_MENU, self.OnPam, pam)
404 self.Bind(wx.EVT_MENU, self.OnStat, stat)
405 self.Bind(wx.EVT_MENU, self.OnSpec, spec)
406 self.Bind(wx.EVT_MENU, self.OnSimiTxt, simi)
407 self.Bind(wx.EVT_MENU, self.OnWordCloud, wdc)
408 self.Bind(wx.EVT_MENU, self.OnSubTextFromMeta, subcorpusfrommeta)
409 self.Bind(wx.EVT_MENU, self.OnSubTextFromTheme, subcorpusfromtheme)
410 elif 'matrix_name' in pydata :
411 for i in range(self.parent.matrix_menu.GetMenuItemCount()) :
412 item = self.parent.matrix_menu.FindItemByPosition(i)
413 itemid = item.GetId()
414 itemtext = item.GetText()
415 menu.Append(itemid, itemtext)
417 splitfromvar = split.Append(-1, _(u"Split from variable").decode('utf8'))
418 menu.AppendMenu(-1, _(u"Split matrix").decode('utf8'), split)
419 self.Bind(wx.EVT_MENU, self.OnSplitFromVar, splitfromvar)
420 #print item, itemid, itemtext
421 #menu = self.parent.matrix_menu
422 #freq = menu.Append(wx.ID_ANY, _(u"Frequency").decode('utf8'))
423 #chi2 = menu.Append(wx.ID_ANY, _(u"Chi square").decode('utf8'))
424 #chdreinert = menu.Append(wx.ID_ANY, _(u"Reinert clustering").decode('utf8'))
425 #simi = menu.Append(wx.ID_ANY, _(u"Similarity analysis").decode('utf8'))
426 menu.AppendSeparator()
427 #self.Bind(wx.EVT_MENU, self.OnFreq, freq)
428 #self.Bind(wx.EVT_MENU, self.OnChiSquare, chi2)
429 #self.Bind(wx.EVT_MENU, self.OnSimiTab, simi)
430 #self.Bind(wx.EVT_MENU, self.OnCHDReinert, chdreinert)
431 elif pydata.get('type', False) == 'alceste' and pydata['uuid'] in self.parent.history.opened :
433 antipro = openmenu.Append(wx.ID_ANY, _(u"Antiprofiles").decode('utf8'))
434 menu.AppendMenu(wx.ID_ANY, _(u"Open ...").decode('utf8'), openmenu)
436 profsr = menu.Append(wx.ID_ANY, _(u"Repeated segments profiles").decode('utf8'))
437 profgram = menu.Append(wx.ID_ANY, _(u"POS profiles").decode('utf8'))
438 export_corpus = menu.Append(wx.ID_ANY, _(u"Export corpus").decode('utf8'))
439 colored = menu.Append(wx.ID_ANY, _(u"Colored corpus").decode('utf8'))
440 navig = menu.Append(wx.ID_ANY, _(u"Navigator").decode('utf8'))
441 statclasse = menu.Append(wx.ID_ANY, _(u"Clusters statistics").decode('utf8'))
442 rapport = menu.Append(wx.ID_ANY, _(u"Report").decode('utf8'))
443 export_classes = menu.Append(wx.ID_ANY, _(u"Export Clusters").decode('utf8'))
444 menu.AppendSeparator()
445 self.Bind(wx.EVT_MENU, self.OpenAntipro, antipro)
446 self.Bind(wx.EVT_MENU, self.OnProfSR, profsr)
447 self.Bind(wx.EVT_MENU, self.OnProfGram, profgram)
448 self.Bind(wx.EVT_MENU, self.OnExportCorpus, export_corpus)
449 self.Bind(wx.EVT_MENU, self.OnColored, colored)
450 self.Bind(wx.EVT_MENU, self.OnNavig, navig)
451 self.Bind(wx.EVT_MENU, self.StatClasse, statclasse)
452 self.Bind(wx.EVT_MENU, self.OnRapport, rapport)
453 self.Bind(wx.EVT_MENU, self.OnExportClasses, export_classes)
454 elif pydata.get('type', False) == 'stat' and pydata['uuid'] in self.parent.history.opened :
455 export_dictionary = menu.Append(wx.ID_ANY, _(u"Export dictionary").decode('utf8'))
456 export_lems = menu.Append(wx.ID_ANY, _(u"Export lemma dictionary").decode('utf8'))
457 self.Bind(wx.EVT_MENU, self.OnExportDictionary, export_dictionary)
458 self.Bind(wx.EVT_MENU, self.OnExportLems, export_lems)
459 menu.AppendSeparator()
460 elif pydata.get('type', False) == 'spec' and pydata['uuid'] in self.parent.history.opened :
461 tgen = menu.Append(wx.ID_ANY, _(u"Tgen Editor").decode('utf8'))
462 computetgen = menu.Append(wx.ID_ANY, _(u"Compute Tgen").decode('utf8'))
463 self.Bind(wx.EVT_MENU, self.OnTgenEditor, tgen)
464 self.Bind(wx.EVT_MENU, self.OnTgenCompute, computetgen)
465 menu.AppendSeparator()
466 elif pydata.get('type', False) == 'reinertmatrix' and pydata['uuid'] in self.parent.history.opened :
468 antipro = openmenu.Append(wx.ID_ANY, _(u"antiprofiles").decode('utf8'))
469 menu.AppendMenu(wx.ID_ANY, _(u"Open ...").decode('utf8'), openmenu)
470 self.Bind(wx.EVT_MENU, self.OpenAntipro, antipro)
473 itemdelete = menu.Append(wx.ID_ANY, _(u"Delete from history").decode('utf8'))
474 #item11 = menu.Append(wx.ID_ANY, "Prepend An Item")
475 #item12 = menu.Append(wx.ID_ANY, "Append An Item")
477 #self.Bind(wx.EVT_MENU, self.OnItemBackground, item1)
478 #self.Bind(wx.EVT_MENU, self.OnItemForeground, item2)
479 #self.Bind(wx.EVT_MENU, self.OnItemBold, item3)
480 #self.Bind(wx.EVT_MENU, self.OnItemFont, item4)
481 #self.Bind(wx.EVT_MENU, self.OnItemHyperText, item5)
482 #self.Bind(wx.EVT_MENU, self.OnEnableWindow, item6)
483 #self.Bind(wx.EVT_MENU, self.OnDisableItem, item7)
484 #self.Bind(wx.EVT_MENU, self.OnItemIcons, item8)
485 self.Bind(wx.EVT_MENU, self.OnItemInfo, info)
486 self.Bind(wx.EVT_MENU, self.OnRename, rename)
487 self.Bind(wx.EVT_MENU, self.OnItemDelete, itemdelete)
488 #self.Bind(wx.EVT_MENU, self.OnItemPrepend, item11)
489 #self.Bind(wx.EVT_MENU, self.OnItemAppend, item12)
495 busy = wx.BusyInfo(_("Please wait...Reading corpus").decode('utf8'), self.parent)
497 if self.pydata['uuid'] in self.parent.history.openedcorpus :
498 corpus = copycorpus(self.parent.history.openedcorpus[self.pydata['uuid']])
499 elif 'corpus_name' in self.pydata :
500 corpus = Corpus(self.parent, parametres = DoConf(self.pydata['ira']).getoptions('corpus'), read = True)
502 cuuid = self.pydata['corpus']
503 if cuuid in self.parent.history.openedcorpus :
504 corpus = copycorpus(self.parent.history.openedcorpus[cuuid])
506 irapath = self.parent.history.corpus[cuuid]['ira']
507 corpus = Corpus(self.parent, parametres = DoConf(irapath).getoptions('corpus'), read = True)
512 if 'matrix_name' in self.pydata :
513 matrix = Tableau(self.parent, parametres = DoConf(self.pydata['ira']).getoptions('matrix'))
515 return copymatrix(matrix)
517 cuuid = self.pydata['matrix']
518 matrix = Tableau(self.parent, parametres = DoConf(self.history.matrixanalyse[cuuid]['ira']).getoptions('matrix'))
520 return copymatrix(matrix)
522 def OnSpec(self, evt) :
523 self.parent.OnTextSpec(evt, self.getcorpus())
525 def OnStat(self, evt) :
526 self.parent.OnTextStat(evt, self.getcorpus())
528 def OnReinert(self, evt) :
529 self.parent.OnTextReinert(evt, self.getcorpus())
531 def OnPam(self, evt) :
532 self.parent.OnPamSimple(evt, self.getcorpus())
534 def OnSimiTxt(self, evt) :
535 self.parent.OnSimiTxt(evt, self.getcorpus())
537 def OnWordCloud(self, evt) :
538 self.parent.OnWordCloud(evt, self.getcorpus())
540 def OnFreq(self, evt):
541 self.parent.OnFreq(evt, self.getmatrix())
543 def OnChiSquare(self, evt):
544 self.parent.OnChi2(evt, self.getmatrix())
546 def OnSimiTab(self, evt):
547 self.parent.OnSimiTab(evt, self.getmatrix())
549 def OnProto(self, evt):
550 self.parent.OnProto(evt, self.getmatrix())
552 def OnSplitFromVar(self, evt):
553 self.parent.OnSplitVar(evt, self.getmatrix())
555 def OnCHDReinert(self, evt):
556 self.parent.OnCHDReinert(evt, self.getmatrix())
558 def OnSubTextFromMeta(self, evt):
559 self.parent.OnSubText(self.getcorpus(), parametres = {'frommeta' : True})
561 def OnSubTextFromTheme(self, evt):
562 self.parent.OnSubText(self.getcorpus(), parametres = {'fromtheme' : True})
564 def OnProfSR(self, evt) :
565 ProfileSegment(self.parent, self.page.dictpathout, self.page.parametres, self.page.corpus)
567 def OnProfGram(self, evt) :
568 ProfilType(self.parent, self.page.corpus, self.page.parametres)
570 def OnExportCorpus(self, evt) :
571 dial = PrefExport(self, self.parent)
572 dial.fbb.SetValue(os.path.join(os.path.dirname(self.page.dictpathout['ira']), 'export_corpus.txt'))
573 dial.CenterOnParent()
574 res = dial.ShowModal()
576 if dial.radio_type.GetSelection() == 0 : alc = True
578 if dial.radio_lem.GetSelection() == 0 : lem = True
580 if self.page.parametres['classif_mode'] != 2 :
584 self.page.corpus.export_corpus_classes(dial.fbb.GetValue(), alc = alc, lem = lem, uci = uci)
587 dlg = wx.MessageDialog(self.parent, msg, u"Export", wx.OK | wx.NO_DEFAULT | wx.ICON_INFORMATION)
592 def OnColored(self, evt) :
593 dial = PrefSimpleFile(self, self.parent, **{'mask' : '*.html', 'title': _(u"Colored corpus").decode('utf8')})
594 dial.fbb.SetValue(os.path.join(os.path.dirname(self.page.dictpathout['ira']), 'corpus_couleur.html'))
595 dial.CenterOnParent()
596 res = dial.ShowModal()
598 fileout = dial.fbb.GetValue()
600 if self.page.parametres['classif_mode'] != 2 :
604 txt = self.page.corpus.make_colored_corpus(uci = uci)
605 with open(fileout, 'w') as f :
607 msg = ' !\n'.join([_(u"Done").decode('utf8'), _(u"Open in a web browser ?").decode('utf8')])
608 dlg = wx.MessageDialog(self.parent, msg, u"Corpus en couleur", wx.NO | wx.YES | wx.NO_DEFAULT | wx.ICON_QUESTION)
610 if dlg.ShowModal() == wx.ID_YES :
611 webbrowser.open(fileout)
614 def OnNavig(self, evt):
615 if 'FrameSearch' not in dir(self.page) :
616 self.page.FrameSearch = SearchFrame(self.parent, -1, _(u"Search ...").decode('utf8'), self.page.corpus)
617 self.page.FrameSearch.Show()
619 def StatClasse(self, evt):
620 dial = PrefSimpleFile(self, self.parent, **{'mask' : '*.csv', 'title': _(u"Clusters statistics").decode('utf8')})
621 dial.fbb.SetValue( os.path.join(os.path.dirname(self.page.dictpathout['ira']), 'stat_par_classe.csv'))
622 dial.CenterOnParent()
623 res = dial.ShowModal()
625 fileout = dial.fbb.GetValue()
627 self.page.corpus.get_stat_by_cluster(fileout)
629 dlg = wx.MessageDialog(self.parent, msg, _(u"Clusters statistics").decode('utf8'), wx.OK | wx.NO_DEFAULT | wx.ICON_INFORMATION)
631 if dlg.ShowModal() == wx.ID_OK :
634 def OpenAntipro(self, evt) :
636 for i in range(0, self.page.TabChdSim.GetPageCount()) :
637 page = self.page.TabChdSim.GetPage(i)
638 if self.page.TabChdSim.GetPageText(i) == _(u"Antiprofiles").decode('utf8') :
639 self.page.TabChdSim.SetSelection(i)
643 open_antiprofil(self.page, self.page.dictpathout['ANTIPRO_OUT'], self.parent.syscoding)
644 self.page.TabChdSim.SetSelection(self.page.TabChdSim.GetPageCount() - 1)
646 def OnRapport(self, evt) :
647 dial = PrefSimpleFile(self, self.parent, **{'mask' : '*.txt', 'title': _(u"Report").decode('utf8')})
648 dial.fbb.SetValue(self.page.dictpathout['rapport'])
649 dial.CenterOnParent()
650 res = dial.ShowModal()
652 fileout = dial.fbb.GetValue()
654 with open(fileout, 'w') as f :
655 f.write(self.page.debtext + '\n' + GetTxtProfile(self.page.DictProfile, self.page.cluster_size))
657 dlg = wx.MessageDialog(self.parent, msg, _(u"Report").decode('utf8'), wx.OK | wx.NO_DEFAULT | wx.ICON_INFORMATION)
664 def OnExportDictionary(self, evt) :
665 corpus = self.page.corpus
666 corpus.export_dictionary(self.page.pathout['dictionary.csv'], self.parent.syscoding)
667 log.info('export dictionary %s' % self.page.pathout['dictionary.csv'])
668 dial = wx.MessageDialog(self.parent, self.page.pathout['dictionary.csv'], 'Export', wx.OK)
672 def OnExportLems(self, evt) :
673 corpus = self.page.corpus
674 corpus.export_lems(self.page.pathout['lemmes.csv'], self.parent.syscoding)
675 log.info('export lemmes %s' % self.page.pathout['lemmes.csv'])
676 dial = wx.MessageDialog(self.parent, self.page.pathout['lemmes.csv'], 'Export', wx.OK)
680 def OnTgenEditor(self, evt):
681 corpus = self.page.corpus
682 tgenpath = os.path.join(self.page.parametres['pathout'], 'tgen.csv')
683 tgen = TGen(path = tgenpath, encoding = self.parent.syscoding)
684 if os.path.exists(tgenpath) :
686 if isinstance(evt, list) :
688 while 'tgen%i' %i in tgen.tgen :
690 tgenname = 'tgen%i' %i
691 tgen.tgen[tgenname] = evt
692 tgenframe = TGenFrame(self.parent, corpus, tgen)
694 if isinstance(evt, list) :
695 tgenframe.OnNewTgen(None, tgen = tgenname)
697 def OnTgenCompute(self, evt):
698 corpus = self.page.corpus
699 tgenpath = os.path.join(self.page.parametres['pathout'], 'tgen.csv')
700 self.page.parametres['tgenpath'] = tgenpath
701 tgen = TGen(path = tgenpath, encoding = self.parent.syscoding)
702 self.page.parametres['etoiles'] = self.page.etoiles
703 TgenSpec(self.parent, corpus, self.page.parametres)
704 TgenLayout(self.page)
706 def OnExportClasses(self, event):
707 corpus = self.page.corpus
708 if self.page.parametres['classif_mode'] != 2 :
712 busy = wx.BusyInfo(_("Please wait...").decode('utf8'), self.parent)
714 for i in range(1, self.page.parametres['clnb'] + 1) :
715 corpus.export_classe(self.page.pathout['classe_%i_export.txt' % i], i, uci = uci)
717 dial = wx.MessageDialog(self, self.page.pathout['classe_x_export.txt'], u"Export", wx.OK|wx.ICON_INFORMATION)
721 def OnRename(self, event):
722 pydata = self.itemdict['pydata']
725 def OnItemBackground(self, event):
727 colourdata = wx.ColourData()
728 colourdata.SetColour(self.itemdict["back"])
729 dlg = wx.ColourDialog(self, colourdata)
731 dlg.GetColourData().SetChooseFull(True)
733 if dlg.ShowModal() == wx.ID_OK:
734 data = dlg.GetColourData()
735 col1 = data.GetColour().Get()
736 self.SetItemBackgroundColour(self.current, col1)
740 def OnItemForeground(self, event):
742 colourdata = wx.ColourData()
743 colourdata.SetColour(self.itemdict["fore"])
744 dlg = wx.ColourDialog(self, colourdata)
746 dlg.GetColourData().SetChooseFull(True)
748 if dlg.ShowModal() == wx.ID_OK:
749 data = dlg.GetColourData()
750 col1 = data.GetColour().Get()
751 self.SetItemTextColour(self.current, col1)
755 def OnItemBold(self, event):
757 self.SetItemBold(self.current, not self.itemdict["isbold"])
760 def OnItemFont(self, event):
763 font = self.itemdict["font"]
766 font = wx.SystemSettings_GetFont(wx.SYS_DEFAULT_GUI_FONT)
768 data.SetInitialFont(font)
770 dlg = wx.FontDialog(self, data)
772 if dlg.ShowModal() == wx.ID_OK:
773 data = dlg.GetFontData()
774 font = data.GetChosenFont()
775 self.SetItemFont(self.current, font)
780 def OnItemHyperText(self, event):
782 self.SetItemHyperText(self.current, not self.itemdict["ishtml"])
785 def OnEnableWindow(self, event):
787 enable = self.GetItemWindowEnabled(self.current)
788 self.SetItemWindowEnabled(self.current, not enable)
791 def OnDisableItem(self, event):
793 self.EnableItem(self.current, False)
796 def OnItemIcons(self, event):
798 bitmaps = [self.itemdict["normal"], self.itemdict["selected"],
799 self.itemdict["expanded"], self.itemdict["selexp"]]
802 dlg = TreeIcons(self, -1, bitmaps=bitmaps)
807 def SetNewIcons(self, bitmaps):
809 self.SetItemImage(self.current, bitmaps[0], CT.TreeItemIcon_Normal)
810 self.SetItemImage(self.current, bitmaps[1], CT.TreeItemIcon_Selected)
811 self.SetItemImage(self.current, bitmaps[2], CT.TreeItemIcon_Expanded)
812 self.SetItemImage(self.current, bitmaps[3], CT.TreeItemIcon_SelectedExpanded)
815 def OnItemInfo(self, event):
817 itemtext = self.itemdict["text"]
818 numchildren = str(self.itemdict["children"])
819 itemtype = self.itemdict["itemtype"]
820 pydata = self.itemdict['pydata']
821 #if 'analyses' in pydata :
822 # toshow = dict([[val, pydata[val]] for val in pydata if val not in['analyses', 'isload']])
824 toshow = pydata['ira']
825 toshow = DoConf(toshow).getoptions()
826 txt = DoConf().totext(toshow)
827 parametres = [val.split('\t\t:') for val in txt.splitlines()]
833 itemtype = "CheckBox"
835 itemtype = "RadioButton"
837 dlg = InfoDialog(self, itemtext, parametres)
844 def OnItemDelete(self, event):
846 strs = "Are You Sure You Want To Delete Item " + self.GetItemText(self.current) + "?"
847 dlg = wx.MessageDialog(None, strs, 'Deleting Item', wx.OK | wx.CANCEL | wx.ICON_QUESTION)
849 if dlg.ShowModal() in [wx.ID_NO, wx.ID_CANCEL]:
855 pydata = self.itemdict['pydata']
856 if 'corpus_name' in pydata :
857 self.history.delete(pydata, True)
859 self.history.delete(pydata)
860 self.DeleteChildren(self.current)
861 self.Delete(self.current)
866 def OnItemPrepend(self, event):
868 dlg = wx.TextEntryDialog(self, "Please Enter The New Item Name", 'Item Naming', 'Python')
870 if dlg.ShowModal() == wx.ID_OK:
871 newname = dlg.GetValue()
872 newitem = self.PrependItem(self.current, newname)
873 self.EnsureVisible(newitem)
877 def AddAnalyse(self, parametres, itemParent = None, bold = True) :
878 uuid = parametres.get('corpus', None)
879 if uuid is not None :
880 if itemParent is None :
881 itemParent = self.textroot
882 child, cookie = self.GetFirstChild(itemParent)
885 pydata = self.GetPyData(child)
886 if pydata['uuid'] == uuid :
889 self.GiveFocus(child, uuid)
890 child, cookie = self.GetNextChild(itemParent, cookie)
891 #item = self.AppendItem(child, parametres['name'])
892 if corpus is not None :
893 item = self.AppendItem(corpus, parametres['name'])
895 item = self.AppendItem(self.textroot, parametres['name'])
897 item = self.AppendItem(self.matroot, parametres['name'])
898 self.SetPyData(item, parametres)
899 if parametres['type'] in self.ild :
900 img = self.ild[parametres['type']]
903 self.SetItemImage(item, img, CT.TreeItemIcon_Normal)
904 self.SetItemImage(item, 13, CT.TreeItemIcon_Expanded)
905 self.SetItemBold(item, bold)
906 self.SelectItem(item)
908 def AddMatAnalyse(self, parametres, itemParent = None, bold = True) :
909 uuid = parametres.get('matrix', None)
910 if uuid is not None :
911 if itemParent is None :
912 itemParent = self.matroot
913 child, cookie = self.GetFirstChild(itemParent)
916 pydata = self.GetPyData(child)
917 if pydata['uuid'] == uuid :
920 self.GiveFocus(child, uuid)
921 child, cookie = self.GetNextChild(itemParent, cookie)
922 #item = self.AppendItem(child, parametres['name'])
923 if matrix is not None :
924 item = self.AppendItem(matrix, parametres['name'])
926 item = self.AppendItem(self.matroot, parametres['name'])
927 self.SetPyData(item, parametres)
928 if parametres['type'] in self.ild :
929 img = self.ild[parametres['type']]
932 self.SetItemImage(item, img, CT.TreeItemIcon_Normal)
933 self.SetItemImage(item, 13, CT.TreeItemIcon_Expanded)
934 self.SetItemBold(item, bold)
935 self.SelectItem(item)
937 def OnItemAppend(self, item):
938 if 'corpus_name' in item :
939 child = self.InsertItem(self.textroot, 0, item['corpus_name'])
941 child = self.InsertItem(self.matroot, 0, item['matrix_name'])
942 self.SetPyData(child, item)
943 self.history.addtab(item)
944 if item['type'] in self.ild :
945 img = self.ild[item['type']]
948 self.SetItemImage(child, img, CT.TreeItemIcon_Normal)
949 self.SetItemImage(child, img, CT.TreeItemIcon_Expanded)
950 self.SetItemBold(child, True)
952 #dlg = wx.TextEntryDialog(self, "Please Enter The New Item Name", 'Item Naming', 'Python')
954 #if dlg.ShowModal() == wx.ID_OK:
955 # newname = dlg.GetValue()
956 # newitem = self.AppendItem(self.current, newname)
957 # self.EnsureVisible(newitem)
963 def OnBeginEdit(self, event):
965 #self.log.info("OnBeginEdit" + "\n")
966 # show how to prevent edit...
967 item = event.GetItem()
968 if item and self.GetItemText(item) == "The Root Item":
970 #self.log.info("You can't edit this one..." + "\n")
972 # Lets just see what's visible of its children
974 root = event.GetItem()
975 (child, cookie) = self.GetFirstChild(root)
978 #self.log.info("Child [%s] visible = %d" % (self.GetItemText(child), self.IsVisible(child)) + "\n")
979 (child, cookie) = self.GetNextChild(root, cookie)
984 def OnEndEdit(self, event):
986 #self.log.info("OnEndEdit: %s %s" %(event.IsEditCancelled(), event.GetLabel()))
987 # show how to reject edit, we'll not allow any digits
988 for x in event.GetLabel():
989 if x in string.digits:
990 #self.log.info(", You can't enter digits..." + "\n")
997 def OnLeftDClick(self, event):
998 pt = event.GetPosition()
999 item, flags = self.HitTest(pt)
1000 if item is not None :
1001 pydata = self.GetPyData(item)
1002 if pydata['uuid'] in self.parent.history.opened :
1003 for i in range(self.parent.nb.GetPageCount()) :
1004 page = self.parent.nb.GetPage(i)
1005 if 'parametres' in dir(page) :
1006 if page.parametres['uuid'] == pydata['uuid'] :
1007 self.parent.nb.SetSelection(i)
1009 elif pydata['uuid'] in ['textroot', 'matroot'] :
1012 busy = wx.BusyInfo(_("Please wait..."), self.parent)
1014 OpenAnalyse(self.parent, pydata)
1016 self.SetItemBold(item, True)
1017 self.OnSelChanged(pydata = pydata)
1018 #if item and (flags & CT.TREE_HITTEST_ONITEMLABEL):
1019 # if self.GetAGWWindowStyleFlag() & CT.TR_EDIT_LABELS:
1020 # self.log.info("OnLeftDClick: %s (manually starting label edit)"% self.GetItemText(item) + "\n")
1022 #self.EditLabel(item)
1024 # pydata = self.GetPyData(item)
1026 # self.log.info("OnLeftDClick: Cannot Start Manual Editing, Missing Style TR_EDIT_LABELS\n")
1031 def OnItemExpanded(self, event):
1033 item = event.GetItem()
1035 self.log.info("OnItemExpanded: %s" % self.GetItemText(item) + "\n")
1038 def OnItemExpanding(self, event):
1040 item = event.GetItem()
1042 self.log.info("OnItemExpanding: %s" % self.GetItemText(item) + "\n")
1047 def OnItemCollapsed(self, event):
1049 item = event.GetItem()
1051 self.log.info("OnItemCollapsed: %s" % self.GetItemText(item) + "\n")
1054 def OnItemCollapsing(self, event):
1056 item = event.GetItem()
1058 self.log.info("OnItemCollapsing: %s" % self.GetItemText(item) + "\n")
1063 def OnSelChanged(self, event = None, pydata = None):
1064 if event is not None :
1065 item = event.GetItem()
1066 pydata = self.GetPyData(item)
1067 if pydata is not None :
1068 self.pydata = pydata
1069 if pydata['uuid'] in self.parent.history.opened :
1070 for i in range(self.parent.nb.GetPageCount()) :
1071 self.page = self.parent.nb.GetPage(i)
1072 if 'parametres' in dir(self.page) :
1073 if self.page.parametres['uuid'] == pydata['uuid'] :
1074 self.parent.nb.SetSelection(i)
1076 if event is not None :
1080 def OnSelChanging(self, event):
1082 item = event.GetItem()
1083 olditem = event.GetOldItem()
1087 olditemtext = "None"
1089 olditemtext = self.GetItemText(olditem)
1090 #self.log.info("OnSelChanging: From %s" % olditemtext + " To %s" % self.GetItemText(item) + "\n")
1095 def OnBeginDrag(self, event):
1097 self.item = event.GetItem()
1099 self.log.info("Beginning Drag..." + "\n")
1104 def OnBeginRDrag(self, event):
1106 self.item = event.GetItem()
1108 self.log.info("Beginning Right Drag..." + "\n")
1113 def OnEndDrag(self, event):
1115 self.item = event.GetItem()
1117 self.log.info("Ending Drag!" + "\n")
1122 def OnDeleteItem(self, event):
1124 item = event.GetItem()
1129 self.log.info("Deleting Item: %s" % self.GetItemText(item) + "\n")
1133 def OnItemCheck(self, event):
1135 item = event.GetItem()
1136 self.log.info("Item " + self.GetItemText(item) + " Has Been Checked!\n")
1140 def OnItemChecking(self, event):
1142 item = event.GetItem()
1143 self.log.info("Item " + self.GetItemText(item) + " Is Being Checked...\n")
1147 def OnToolTip(self, event):
1149 item = event.GetItem()
1151 event.SetToolTip(wx.ToolTip(self.GetItemText(item)))
1154 def OnItemMenu(self, event):
1156 item = event.GetItem()
1158 self.log.info("OnItemMenu: %s" % self.GetItemText(item) + "\n")
1163 def OnKey(self, event):
1165 keycode = event.GetKeyCode()
1166 keyname = keyMap.get(keycode, None)
1168 if keycode == wx.WXK_BACK:
1169 self.log.info("OnKeyDown: HAHAHAHA! I Vetoed Your Backspace! HAHAHAHA\n")
1173 if "unicode" in wx.PlatformInfo:
1174 keycode = event.GetUnicodeKey()
1176 keycode = event.GetKeyCode()
1177 keyname = "\"" + unichr(event.GetUnicodeKey()) + "\""
1179 keyname = "Ctrl-%s" % chr(ord('A') + keycode-1)
1185 keyname = "Ctrl-%s" % chr(ord('A') + keycode-1)
1187 keyname = "\"%s\"" % chr(keycode)
1189 keyname = "unknown (%s)" % keycode
1191 self.log.info("OnKeyDown: You Pressed '" + keyname + "'\n")
1196 def OnActivate(self, event):
1199 self.log.info("OnActivate: %s" % self.GetItemText(self.item) + "\n")
1204 def OnHyperLink(self, event):
1206 item = event.GetItem()
1208 self.log.info("OnHyperLink: %s" % self.GetItemText(self.item) + "\n")
1211 def OnTextCtrl(self, event):
1213 char = chr(event.GetKeyCode())
1214 self.log.info("EDITING THE TEXTCTRL: You Wrote '" + char + \
1215 "' (KeyCode = " + str(event.GetKeyCode()) + ")\n")
1219 def OnComboBox(self, event):
1221 selection = event.GetEventObject().GetValue()
1222 self.log.info("CHOICE FROM COMBOBOX: You Chose '" + selection + "'\n")