]>
Commit | Line | Data |
---|---|---|
1f780e48 RD |
1 | #---------------------------------------------------------------------------- |
2 | # Name: UICommon.py | |
3 | # Purpose: Shared UI stuff | |
4 | # | |
02b800ce | 5 | # Author: Matt Fryer, Morgan Hua |
1f780e48 RD |
6 | # |
7 | # Created: 3/10/05 | |
8 | # CVS-ID: $Id$ | |
9 | # Copyright: (c) 2005 ActiveGrid, Inc. | |
10 | # License: wxWindows License | |
11 | #---------------------------------------------------------------------------- | |
12 | ||
13 | import os | |
14 | import os.path | |
15 | import wx | |
02b800ce | 16 | import string |
1f780e48 | 17 | import ProjectEditor |
02b800ce RD |
18 | import activegrid.util.sysutils as sysutils |
19 | import activegrid.util.strutils as strutils | |
20 | import activegrid.util.appdirs as appdirs | |
1f780e48 RD |
21 | _ = wx.GetTranslation |
22 | ||
02b800ce | 23 | def CreateDirectoryControl( parent, fileLabel=_("File Name:"), dirLabel=_("Directory"), fileExtension="*", startingName="", startingDirectory=None, choiceDirs=None, appDirDefaultStartDir=False, returnAll=False): |
1f780e48 | 24 | |
02b800ce RD |
25 | if not choiceDirs: |
26 | choiceDirs = [] | |
27 | projectDirs = [] | |
28 | ||
29 | if appDirDefaultStartDir: | |
30 | appDirectory = wx.ConfigBase_Get().Read(ProjectEditor.PROJECT_DIRECTORY_KEY, ProjectEditor.NEW_PROJECT_DIRECTORY_DEFAULT) | |
31 | else: | |
32 | appDirectory = wx.ConfigBase_Get().Read(ProjectEditor.PROJECT_DIRECTORY_KEY) | |
33 | if appDirectory: | |
34 | choiceDirs.append(appDirectory) | |
35 | if appDirDefaultStartDir and not startingDirectory: | |
36 | startingDirectory = appDirectory | |
37 | ||
38 | projectService = wx.GetApp().GetService(ProjectEditor.ProjectService) | |
39 | if projectService: | |
40 | curProjectDoc = projectService.GetCurrentProject() | |
41 | if curProjectDoc: | |
42 | homeDir = curProjectDoc.GetAppDocMgr().homeDir | |
43 | if homeDir and (homeDir not in choiceDirs): | |
44 | choiceDirs.append(homeDir) | |
45 | if not startingDirectory: | |
46 | startingDirectory = homeDir | |
47 | ||
48 | for projectDoc in projectService.GetOpenProjects(): | |
49 | if projectDoc == curProjectDoc: | |
50 | continue | |
51 | homeDir = projectDoc.GetAppDocMgr().homeDir | |
52 | if homeDir and (homeDir not in projectDirs): | |
53 | projectDirs.append(homeDir) | |
54 | projectDirs.sort(CaseInsensitiveCompare) | |
55 | for projectDir in projectDirs: | |
56 | if projectDir not in choiceDirs: | |
57 | choiceDirs.append(projectDir) | |
58 | ||
59 | if startingDirectory and (startingDirectory not in choiceDirs): | |
60 | choiceDirs.insert(0, startingDirectory) | |
61 | ||
62 | if os.getcwd() not in choiceDirs: | |
63 | choiceDirs.append(os.getcwd()) | |
64 | if appdirs.documents_folder not in choiceDirs: | |
65 | choiceDirs.append(appdirs.documents_folder) | |
66 | ||
67 | if not startingDirectory: | |
68 | startingDirectory = os.getcwd() | |
69 | ||
1f780e48 RD |
70 | nameControl = wx.TextCtrl(parent, -1, startingName, size=(-1,-1)) |
71 | nameLabelText = wx.StaticText(parent, -1, fileLabel) | |
72 | dirLabelText = wx.StaticText(parent, -1, dirLabel) | |
02b800ce | 73 | dirControl = wx.ComboBox(parent, -1, startingDirectory, size=(-1,-1), choices=choiceDirs) |
1f780e48 | 74 | dirControl.SetToolTipString(startingDirectory) |
02b800ce RD |
75 | button = wx.Button(parent, -1, _("Browse...")) |
76 | allControls = [nameControl, nameLabelText, dirLabelText, dirControl, button] | |
1f780e48 RD |
77 | |
78 | def OnFindDirClick(event): | |
79 | name = "" | |
80 | nameCtrlValue = nameControl.GetValue() | |
81 | if nameCtrlValue: | |
82 | root, ext = os.path.splitext( nameCtrlValue ) | |
83 | if ext == '.' + fileExtension: | |
84 | name = nameCtrlValue | |
85 | else: | |
86 | name = _("%s.%s") % (nameCtrlValue, fileExtension) | |
02b800ce RD |
87 | |
88 | dlg = wx.FileDialog(parent, _("Choose a filename and directory"), | |
89 | defaultDir = dirControl.GetValue().strip(), | |
90 | defaultFile = name, | |
91 | wildcard= "*.%s" % fileExtension, | |
92 | style=wx.SAVE|wx.CHANGE_DIR) | |
1f780e48 | 93 | |
02b800ce RD |
94 | if dlg.ShowModal() != wx.ID_OK: |
95 | dlg.Destroy() | |
96 | return | |
97 | path = dlg.GetPath() | |
98 | dlg.Destroy() | |
99 | ||
1f780e48 RD |
100 | if path: |
101 | dir, filename = os.path.split(path) | |
02b800ce RD |
102 | if dirControl.FindString(dir) == wx.NOT_FOUND: |
103 | dirControl.Insert(dir, 0) | |
1f780e48 RD |
104 | dirControl.SetValue(dir) |
105 | dirControl.SetToolTipString(dir) | |
106 | nameControl.SetValue(filename) | |
107 | ||
108 | parent.Bind(wx.EVT_BUTTON, OnFindDirClick, button) | |
109 | ||
02b800ce RD |
110 | def Validate(allowOverwriteOnPrompt=False, infoString='', noFirstCharDigit=False): |
111 | projName = nameControl.GetValue().strip() | |
112 | if projName == "": | |
113 | wx.MessageBox(_("Please provide a %sfile name.") % infoString, _("Provide a File Name")) | |
114 | return False | |
115 | if noFirstCharDigit and projName[0].isdigit(): | |
116 | wx.MessageBox(_("File name cannot start with a number. Please enter a different name."), _("Invalid File Name")) | |
1f780e48 | 117 | return False |
02b800ce RD |
118 | if projName.find(' ') != -1: |
119 | wx.MessageBox(_("Please provide a %sfile name that does not contains spaces.") % infoString, _("Spaces in File Name")) | |
1f780e48 | 120 | return False |
26ee3a06 | 121 | if not os.path.exists(dirControl.GetValue()): |
02b800ce | 122 | wx.MessageBox(_("That %sdirectory does not exist. Please choose an existing directory.") % infoString, _("Provide a Valid Directory")) |
26ee3a06 RD |
123 | return False |
124 | ||
02b800ce | 125 | filePath = os.path.join(dirControl.GetValue(), MakeNameEndInExtension(projName, "." + fileExtension)) |
1f780e48 RD |
126 | if os.path.exists(filePath): |
127 | if allowOverwriteOnPrompt: | |
02b800ce | 128 | res = wx.MessageBox(_("That %sfile already exists. Would you like to overwrite it.") % infoString, "File Exists", style=wx.YES_NO|wx.NO_DEFAULT) |
1f780e48 RD |
129 | return (res == wx.YES) |
130 | else: | |
02b800ce | 131 | wx.MessageBox(_("That %sfile already exists. Please choose a different name.") % infoString, "File Exists") |
1f780e48 RD |
132 | return False |
133 | return True | |
134 | HALF_SPACE = 5 | |
135 | flexGridSizer = wx.FlexGridSizer(cols = 3, vgap = HALF_SPACE, hgap = HALF_SPACE) | |
136 | flexGridSizer.AddGrowableCol(1,1) | |
02b800ce | 137 | flexGridSizer.Add(nameLabelText, 0, wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_LEFT) |
1f780e48 RD |
138 | flexGridSizer.Add(nameControl, 2, flag=wx.ALIGN_CENTER_VERTICAL|wx.EXPAND) |
139 | flexGridSizer.Add(button, flag=wx.ALIGN_RIGHT|wx.LEFT, border=HALF_SPACE) | |
140 | ||
02b800ce RD |
141 | flexGridSizer.Add(dirLabelText, flag=wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_LEFT) |
142 | flexGridSizer.Add(dirControl, 2, flag=wx.ALIGN_CENTER_VERTICAL|wx.EXPAND) | |
1f780e48 | 143 | flexGridSizer.Add(wx.StaticText(parent, -1, ""), 0) |
02b800ce RD |
144 | if returnAll: |
145 | return nameControl, dirControl, flexGridSizer, Validate, allControls | |
146 | else: | |
147 | return nameControl, dirControl, flexGridSizer, Validate | |
148 | ||
149 | ||
150 | def CreateDirectoryOnlyControl( parent, dirLabel=_("Location:"), startingDirectory=None, choiceDirs=None, appDirDefaultStartDir=False): | |
151 | ||
152 | if not choiceDirs: | |
153 | choiceDirs = [] | |
154 | projectDirs = [] | |
155 | ||
156 | if appDirDefaultStartDir: | |
157 | appDirectory = wx.ConfigBase_Get().Read(ProjectEditor.PROJECT_DIRECTORY_KEY, ProjectEditor.NEW_PROJECT_DIRECTORY_DEFAULT) | |
158 | else: | |
159 | appDirectory = wx.ConfigBase_Get().Read(ProjectEditor.PROJECT_DIRECTORY_KEY) | |
160 | if appDirectory: | |
161 | choiceDirs.append(appDirectory) | |
162 | if appDirDefaultStartDir and not startingDirectory: | |
163 | startingDirectory = appDirectory | |
164 | ||
165 | projectService = wx.GetApp().GetService(ProjectEditor.ProjectService) | |
166 | if projectService: | |
167 | curProjectDoc = projectService.GetCurrentProject() | |
168 | if curProjectDoc: | |
169 | homeDir = curProjectDoc.GetAppDocMgr().homeDir | |
170 | if homeDir and (homeDir not in choiceDirs): | |
171 | choiceDirs.append(homeDir) | |
172 | if not startingDirectory: | |
173 | startingDirectory = homeDir | |
174 | ||
175 | for projectDoc in projectService.GetOpenProjects(): | |
176 | if projectDoc == curProjectDoc: | |
177 | continue | |
178 | homeDir = projectDoc.GetAppDocMgr().homeDir | |
179 | if homeDir and (homeDir not in projectDirs): | |
180 | projectDirs.append(homeDir) | |
181 | projectDirs.sort(CaseInsensitiveCompare) | |
182 | for projectDir in projectDirs: | |
183 | if projectDir not in choiceDirs: | |
184 | choiceDirs.append(projectDir) | |
185 | ||
186 | if startingDirectory and (startingDirectory not in choiceDirs): | |
187 | choiceDirs.insert(0, startingDirectory) | |
188 | ||
189 | if os.getcwd() not in choiceDirs: | |
190 | choiceDirs.append(os.getcwd()) | |
191 | if appdirs.documents_folder not in choiceDirs: | |
192 | choiceDirs.append(appdirs.documents_folder) | |
193 | ||
194 | ||
195 | if not startingDirectory: | |
196 | startingDirectory = os.getcwd() | |
197 | ||
198 | dirLabelText = wx.StaticText(parent, -1, dirLabel) | |
199 | dirControl = wx.ComboBox(parent, -1, startingDirectory, size=(-1,-1), choices=choiceDirs) | |
200 | dirControl.SetToolTipString(startingDirectory) | |
201 | button = wx.Button(parent, -1, _("Browse...")) | |
202 | ||
203 | def OnFindDirClick(event): | |
204 | dlg = wx.DirDialog(wx.GetApp().GetTopWindow(), | |
205 | _("Choose a directory:"), | |
206 | defaultPath=dirControl.GetValue().strip(), | |
207 | style=wx.DD_DEFAULT_STYLE|wx.DD_NEW_DIR_BUTTON) | |
208 | dlg.CenterOnParent() | |
209 | if dlg.ShowModal() == wx.ID_OK: | |
210 | dir = dlg.GetPath() | |
211 | if dirControl.FindString(dir) == wx.NOT_FOUND: | |
212 | dirControl.Insert(dir, 0) | |
213 | dirControl.SetValue(dir) | |
214 | dirControl.SetToolTipString(dir) | |
215 | dlg.Destroy() | |
216 | ||
217 | parent.Bind(wx.EVT_BUTTON, OnFindDirClick, button) | |
218 | ||
219 | def Validate(allowOverwriteOnPrompt=False): | |
220 | dirName = dirControl.GetValue().strip() | |
221 | if dirName == "": | |
222 | wx.MessageBox(_("Please provide a directory."), _("Provide a Directory")) | |
223 | return False | |
224 | if not os.path.exists(dirName): | |
225 | wx.MessageBox(_("That directory does not exist. Please choose an existing directory."), _("Provide a Valid Directory")) | |
226 | return False | |
227 | return True | |
228 | ||
229 | HALF_SPACE = 5 | |
230 | flexGridSizer = wx.FlexGridSizer(cols = 3, vgap = HALF_SPACE, hgap = HALF_SPACE) | |
231 | flexGridSizer.AddGrowableCol(1,1) | |
232 | flexGridSizer.Add(dirLabelText, flag=wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_LEFT|wx.RIGHT, border=HALF_SPACE) | |
233 | flexGridSizer.Add(dirControl, 2, flag=wx.ALIGN_CENTER_VERTICAL|wx.EXPAND, border=HALF_SPACE) | |
234 | flexGridSizer.Add(button, flag=wx.ALIGN_RIGHT|wx.LEFT, border=HALF_SPACE) | |
235 | ||
236 | return dirControl, flexGridSizer, Validate | |
237 | ||
238 | ||
239 | def CreateNameOnlyControl( parent, fileLabel, startingName="", startingDirectoryControl=None): | |
240 | ||
241 | fileLabelText = wx.StaticText(parent, -1, fileLabel) | |
242 | nameControl = wx.TextCtrl(parent, -1, startingName, size=(-1,-1)) | |
243 | ||
244 | def Validate(allowOverwriteOnPrompt=False, noFirstCharDigit=False): | |
245 | projName = nameControl.GetValue().strip() | |
246 | if projName == "": | |
247 | wx.MessageBox(_("Blank name. Please enter a valid name."), _("Project Name")) | |
248 | return False | |
249 | if noFirstCharDigit and projName[0].isdigit(): | |
250 | wx.MessageBox(_("Name cannot start with a number. Please enter a valid name."), _("Project Name")) | |
251 | return False | |
252 | if projName.find(' ') != -1: | |
253 | wx.MessageBox(_("Spaces in name. Name cannot have spaces.") % infoString, _("Project Name")) | |
254 | return False | |
255 | path = os.path.join(startingDirectoryControl.GetValue().strip(), projName) | |
256 | if os.path.exists(path): | |
257 | if os.path.isdir(path): | |
258 | message = _("Project '%s' already exists. Would you like to overwrite the contents of the project?") % projName | |
259 | else: # os.path.isfile(path): | |
260 | message = _("'%s' already exists as a file. Would you like to replace it with the project?") % nameControl.GetValue().strip() | |
261 | ||
262 | yesNoMsg = wx.MessageDialog(wx.GetApp().GetTopWindow(), | |
263 | message, | |
264 | _("Project Directory Exists"), | |
265 | wx.YES_NO|wx.ICON_QUESTION | |
266 | ) | |
267 | yesNoMsg.CenterOnParent() | |
268 | status = yesNoMsg.ShowModal() | |
269 | yesNoMsg.Destroy() | |
270 | if status == wx.ID_NO: | |
271 | return False | |
272 | return True | |
273 | ||
274 | HALF_SPACE = 5 | |
275 | flexGridSizer = wx.FlexGridSizer(cols = 2, vgap = HALF_SPACE, hgap = HALF_SPACE) | |
276 | flexGridSizer.AddGrowableCol(1,1) | |
277 | flexGridSizer.Add(fileLabelText, flag=wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_LEFT|wx.TOP|wx.RIGHT, border=HALF_SPACE) | |
278 | flexGridSizer.Add(nameControl, 2, flag=wx.ALIGN_CENTER_VERTICAL|wx.EXPAND, border=HALF_SPACE) | |
279 | ||
280 | return nameControl, flexGridSizer, Validate | |
281 | ||
1f780e48 | 282 | |
02b800ce RD |
283 | def GetCurrentProject(): |
284 | projectDocument = None | |
285 | projectService = wx.GetApp().GetService(ProjectEditor.ProjectService) | |
286 | if projectService: | |
287 | projectDocument = projectService.GetCurrentProject() | |
288 | return projectDocument | |
289 | ||
290 | def AddFilesToCurrentProject(paths, folderPath=None, types=None, names=None, save=False): | |
1f780e48 RD |
291 | projectService = wx.GetApp().GetService(ProjectEditor.ProjectService) |
292 | if projectService: | |
293 | projectDocument = projectService.GetCurrentProject() | |
294 | if projectDocument: | |
295 | files = projectDocument.GetFiles() | |
296 | for path in paths: | |
297 | if path in files: | |
298 | paths.remove(path) | |
299 | if paths: | |
02b800ce | 300 | projectDocument.GetCommandProcessor().Submit(ProjectEditor.ProjectAddFilesCommand(projectDocument, paths, folderPath=folderPath, types=types, names=names)) |
1f780e48 RD |
301 | if save: |
302 | projectDocument.OnSaveDocument(projectDocument.GetFilename()) | |
303 | ||
02b800ce RD |
304 | def AddFilesToProject(projectDocument, paths, types=None, names=None, save=False): |
305 | if projectDocument: | |
306 | files = projectDocument.GetFiles() | |
307 | for path in paths: | |
308 | if path in files: | |
309 | paths.remove(path) | |
310 | if paths: | |
311 | projectDocument.GetCommandProcessor().Submit(ProjectEditor.ProjectAddFilesCommand(projectDocument, paths, types=types, names=names)) | |
312 | if save: | |
313 | projectDocument.OnSaveDocument(projectDocument.GetFilename()) | |
314 | ||
315 | ||
1f780e48 RD |
316 | def MakeNameEndInExtension(name, extension): |
317 | if not name: | |
318 | return name | |
319 | root, ext = os.path.splitext(name) | |
320 | if ext == extension: | |
321 | return name | |
322 | else: | |
323 | return name + extension | |
324 | ||
02b800ce | 325 | |
2eeaec19 RD |
326 | def GetPythonExecPath(): |
327 | pythonExecPath = wx.ConfigBase_Get().Read("ActiveGridPythonLocation") | |
328 | if not pythonExecPath: | |
02b800ce | 329 | pythonExecPath = sysutils.pythonExecPath |
2eeaec19 RD |
330 | return pythonExecPath |
331 | ||
332 | ||
02b800ce RD |
333 | def _DoRemoveRecursive(path, skipFile=None, skipped=False): |
334 | if path == skipFile: | |
335 | skipped = True | |
336 | elif os.path.isdir(path): | |
337 | for file in os.listdir(path): | |
338 | file_or_dir = os.path.join(path,file) | |
339 | if skipFile == file_or_dir: | |
340 | skipped = True | |
341 | elif os.path.isdir(file_or_dir) and not os.path.islink(file_or_dir): | |
342 | if _DoRemoveRecursive(file_or_dir, skipFile): # it's a directory recursive call to function again | |
343 | skipped = True | |
344 | else: | |
345 | os.remove(file_or_dir) # it's a file, delete it | |
346 | if not skipped: | |
347 | os.rmdir(path) # delete the directory here | |
348 | else: | |
349 | os.remove(path) | |
350 | ||
351 | return skipped | |
352 | ||
353 | ||
354 | def RemoveRecursive(path, skipFile=None): | |
355 | _DoRemoveRecursive(path, skipFile) | |
356 | ||
357 | ||
358 | def CaseInsensitiveCompare(s1, s2): | |
359 | """ Method used by sort() to sort values in case insensitive order """ | |
360 | return strutils.caseInsensitiveCompare(s1, s2) | |
361 | ||
362 | ||
363 | def GetAnnotation(model, elementName): | |
364 | """ Get an object's annotation used for tooltips """ | |
365 | if hasattr(model, "__xsdcomplextype__"): | |
366 | ct = model.__xsdcomplextype__ | |
367 | if ct: | |
368 | el = ct.findElement(elementName) | |
369 | if el and el.annotation: | |
370 | return el.annotation | |
371 | ||
372 | return "" | |
373 | ||
374 | ||
375 | #---------------------------------------------------------------------------- | |
376 | # Methods for finding application level info | |
377 | #---------------------------------------------------------------------------- | |
378 | ||
379 | def GetProjectForDoc(doc): | |
380 | """ Given a document find which project it belongs to. | |
381 | Tries to intelligently resolve conflicts if it is in more than one open project. | |
382 | """ | |
383 | projectService = wx.GetApp().GetService(ProjectEditor.ProjectService) | |
384 | ||
385 | projectDoc = projectService.FindProjectFromMapping(doc) | |
386 | if projectDoc: | |
387 | return projectDoc | |
388 | ||
389 | projectDoc = projectService.GetCurrentProject() | |
390 | if not projectDoc: | |
391 | return None | |
392 | if projectDoc.IsFileInProject(doc.GetFilename()): | |
393 | return projectDoc | |
394 | ||
395 | projects = [] | |
396 | openDocs = wx.GetApp().GetDocumentManager().GetDocuments() | |
397 | for openDoc in openDocs: | |
398 | if openDoc == projectDoc: | |
399 | continue | |
400 | if(isinstance(openDoc, ProjectEditor.ProjectDocument)): | |
401 | if openDoc.IsFileInProject(doc.GetFilename()): | |
402 | projects.append(openDoc) | |
403 | ||
404 | if projects: | |
405 | if len(projects) == 1: | |
406 | return projects[0] | |
407 | else: | |
408 | choices = [os.path.basename(project.GetFilename()) for project in projects] | |
409 | dlg = wx.SingleChoiceDialog(wx.GetApp().GetTopWindow(), _("'%s' found in more than one project.\nWhich project should be used for this operation?") % os.path.basename(doc.GetFilename()), _("Select Project"), choices, wx.DEFAULT_DIALOG_STYLE|wx.RESIZE_BORDER|wx.OK|wx.CENTRE) | |
410 | dlg.CenterOnParent() | |
411 | projectDoc = None | |
412 | if dlg.ShowModal() == wx.ID_OK: | |
413 | i = dlg.GetSelection() | |
414 | projectDoc = projects[i] | |
415 | dlg.Destroy() | |
416 | return projectDoc | |
417 | ||
418 | return None | |
419 | ||
420 | ||
421 | def GetAppInfoForDoc(doc): | |
422 | """ Get the AppInfo for a given document """ | |
423 | projectDoc = GetProjectForDoc(doc) | |
424 | if projectDoc: | |
425 | return projectDoc.GetAppInfo() | |
426 | return None | |
427 | ||
428 | ||
429 | def GetAppDocMgrForDoc(doc): | |
430 | """ Get the AppDocMgr for a given document """ | |
431 | projectDoc = GetProjectForDoc(doc) | |
432 | if projectDoc: | |
433 | return projectDoc.GetModel() | |
434 | return None | |
435 | ||
436 | ||
437 | def GetAppInfoLanguage(doc=None): | |
438 | from activegrid.server.deployment import LANGUAGE_DEFAULT | |
439 | if doc: | |
440 | language = doc.GetAppInfo().language | |
441 | else: | |
442 | language = None | |
443 | ||
444 | if not language: | |
445 | config = wx.ConfigBase_Get() | |
446 | language = config.Read(ProjectEditor.APP_LAST_LANGUAGE, LANGUAGE_DEFAULT) | |
447 | ||
448 | if doc: | |
449 | doc.GetAppInfo().language = language # once it is selected, it must be set. | |
450 | ||
451 | return language |