118 rp = Preferences.Prefs.rsettings.value(recentNameMultiProject) |
117 rp = Preferences.Prefs.rsettings.value(recentNameMultiProject) |
119 if rp is not None: |
118 if rp is not None: |
120 for f in rp: |
119 for f in rp: |
121 if pathlib.Path(f).exists(): |
120 if pathlib.Path(f).exists(): |
122 self.recent.append(f) |
121 self.recent.append(f) |
123 |
122 |
124 def __saveRecent(self): |
123 def __saveRecent(self): |
125 """ |
124 """ |
126 Private method to save the list of recently opened filenames. |
125 Private method to save the list of recently opened filenames. |
127 """ |
126 """ |
128 Preferences.Prefs.rsettings.setValue( |
127 Preferences.Prefs.rsettings.setValue(recentNameMultiProject, self.recent) |
129 recentNameMultiProject, self.recent) |
|
130 Preferences.Prefs.rsettings.sync() |
128 Preferences.Prefs.rsettings.sync() |
131 |
129 |
132 def getMostRecent(self): |
130 def getMostRecent(self): |
133 """ |
131 """ |
134 Public method to get the most recently opened multiproject. |
132 Public method to get the most recently opened multiproject. |
135 |
133 |
136 @return path of the most recently opened multiproject (string) |
134 @return path of the most recently opened multiproject (string) |
137 """ |
135 """ |
138 if len(self.recent): |
136 if len(self.recent): |
139 return self.recent[0] |
137 return self.recent[0] |
140 else: |
138 else: |
141 return None |
139 return None |
142 |
140 |
143 def setDirty(self, b): |
141 def setDirty(self, b): |
144 """ |
142 """ |
145 Public method to set the dirty state. |
143 Public method to set the dirty state. |
146 |
144 |
147 It emits the signal dirty(int). |
145 It emits the signal dirty(int). |
148 |
146 |
149 @param b dirty state (boolean) |
147 @param b dirty state (boolean) |
150 """ |
148 """ |
151 self.__dirty = b |
149 self.__dirty = b |
152 self.saveAct.setEnabled(b) |
150 self.saveAct.setEnabled(b) |
153 self.dirty.emit(bool(b)) |
151 self.dirty.emit(bool(b)) |
154 |
152 |
155 def isDirty(self): |
153 def isDirty(self): |
156 """ |
154 """ |
157 Public method to return the dirty state. |
155 Public method to return the dirty state. |
158 |
156 |
159 @return dirty state (boolean) |
157 @return dirty state (boolean) |
160 """ |
158 """ |
161 return self.__dirty |
159 return self.__dirty |
162 |
160 |
163 def isOpen(self): |
161 def isOpen(self): |
164 """ |
162 """ |
165 Public method to return the opened state. |
163 Public method to return the opened state. |
166 |
164 |
167 @return open state (boolean) |
165 @return open state (boolean) |
168 """ |
166 """ |
169 return self.opened |
167 return self.opened |
170 |
168 |
171 def getMultiProjectPath(self): |
169 def getMultiProjectPath(self): |
172 """ |
170 """ |
173 Public method to get the multi project path. |
171 Public method to get the multi project path. |
174 |
172 |
175 @return multi project path (string) |
173 @return multi project path (string) |
176 """ |
174 """ |
177 return self.ppath |
175 return self.ppath |
178 |
176 |
179 def getMultiProjectFile(self): |
177 def getMultiProjectFile(self): |
180 """ |
178 """ |
181 Public method to get the path of the multi project file. |
179 Public method to get the path of the multi project file. |
182 |
180 |
183 @return path of the multi project file (string) |
181 @return path of the multi project file (string) |
184 """ |
182 """ |
185 return self.pfile |
183 return self.pfile |
186 |
184 |
187 def __checkFilesExist(self): |
185 def __checkFilesExist(self): |
188 """ |
186 """ |
189 Private method to check, if the files in a list exist. |
187 Private method to check, if the files in a list exist. |
190 |
188 |
191 The project files are checked for existance in the |
189 The project files are checked for existance in the |
192 filesystem. Non existant projects are removed from the list and the |
190 filesystem. Non existant projects are removed from the list and the |
193 dirty state of the multi project is changed accordingly. |
191 dirty state of the multi project is changed accordingly. |
194 """ |
192 """ |
195 removelist = [] |
193 removelist = [] |
196 for key, project in self.__projects.items(): |
194 for key, project in self.__projects.items(): |
197 if not os.path.exists(project['file']): |
195 if not os.path.exists(project["file"]): |
198 removelist.append(key) |
196 removelist.append(key) |
199 |
197 |
200 if removelist: |
198 if removelist: |
201 for key in removelist: |
199 for key in removelist: |
202 del self.__projects[key] |
200 del self.__projects[key] |
203 self.setDirty(True) |
201 self.setDirty(True) |
204 |
202 |
205 def __extractCategories(self): |
203 def __extractCategories(self): |
206 """ |
204 """ |
207 Private slot to extract the categories used in the project definitions. |
205 Private slot to extract the categories used in the project definitions. |
208 """ |
206 """ |
209 for project in self.__projects.values(): |
207 for project in self.__projects.values(): |
210 if ( |
208 if project["category"] and project["category"] not in self.categories: |
211 project['category'] and |
209 self.categories.append(project["category"]) |
212 project['category'] not in self.categories |
210 |
213 ): |
|
214 self.categories.append(project['category']) |
|
215 |
|
216 def getCategories(self): |
211 def getCategories(self): |
217 """ |
212 """ |
218 Public method to get the list of defined categories. |
213 Public method to get the list of defined categories. |
219 |
214 |
220 @return list of categories (list of string) |
215 @return list of categories (list of string) |
221 """ |
216 """ |
222 return [c for c in self.categories if c] |
217 return [c for c in self.categories if c] |
223 |
218 |
224 def __readMultiProject(self, fn): |
219 def __readMultiProject(self, fn): |
225 """ |
220 """ |
226 Private method to read in a multi project (.emj, .e4m, .e5m) file. |
221 Private method to read in a multi project (.emj, .e4m, .e5m) file. |
227 |
222 |
228 @param fn filename of the multi project file to be read (string) |
223 @param fn filename of the multi project file to be read (string) |
229 @return flag indicating success |
224 @return flag indicating success |
230 """ |
225 """ |
231 if os.path.splitext(fn)[1] == ".emj": |
226 if os.path.splitext(fn)[1] == ".emj": |
232 # new JSON based format |
227 # new JSON based format |
236 # old XML based format |
231 # old XML based format |
237 f = QFile(fn) |
232 f = QFile(fn) |
238 if f.open(QIODevice.OpenModeFlag.ReadOnly): |
233 if f.open(QIODevice.OpenModeFlag.ReadOnly): |
239 with EricOverrideCursor(): |
234 with EricOverrideCursor(): |
240 from EricXML.MultiProjectReader import MultiProjectReader |
235 from EricXML.MultiProjectReader import MultiProjectReader |
|
236 |
241 reader = MultiProjectReader(f, self) |
237 reader = MultiProjectReader(f, self) |
242 reader.readXML() |
238 reader.readXML() |
243 f.close() |
239 f.close() |
244 res = not reader.hasError() |
240 res = not reader.hasError() |
245 else: |
241 else: |
246 EricMessageBox.critical( |
242 EricMessageBox.critical( |
247 self.ui, |
243 self.ui, |
248 self.tr("Read Multi Project File"), |
244 self.tr("Read Multi Project File"), |
249 self.tr( |
245 self.tr( |
250 "<p>The multi project file <b>{0}</b> could not be" |
246 "<p>The multi project file <b>{0}</b> could not be" " read.</p>" |
251 " read.</p>").format(fn)) |
247 ).format(fn), |
|
248 ) |
252 res = False |
249 res = False |
253 |
250 |
254 if res: |
251 if res: |
255 self.pfile = os.path.abspath(fn) |
252 self.pfile = os.path.abspath(fn) |
256 self.ppath = os.path.abspath(os.path.dirname(fn)) |
253 self.ppath = os.path.abspath(os.path.dirname(fn)) |
257 |
254 |
258 self.__extractCategories() |
255 self.__extractCategories() |
259 |
256 |
260 # insert filename into list of recently opened multi projects |
257 # insert filename into list of recently opened multi projects |
261 self.__syncRecent() |
258 self.__syncRecent() |
262 |
259 |
263 self.name = os.path.splitext(os.path.basename(fn))[0] |
260 self.name = os.path.splitext(os.path.basename(fn))[0] |
264 |
261 |
265 # check, if the files of the multi project still exist |
262 # check, if the files of the multi project still exist |
266 self.__checkFilesExist() |
263 self.__checkFilesExist() |
267 |
264 |
268 return res |
265 return res |
269 |
266 |
270 def __writeMultiProject(self, fn=None): |
267 def __writeMultiProject(self, fn=None): |
271 """ |
268 """ |
272 Private method to save the multi project infos to a multi project file. |
269 Private method to save the multi project infos to a multi project file. |
273 |
270 |
274 @param fn optional filename of the multi project file to be written. |
271 @param fn optional filename of the multi project file to be written. |
275 If fn is None, the filename stored in the multi project object |
272 If fn is None, the filename stored in the multi project object |
276 is used. This is the 'save' action. If fn is given, this filename |
273 is used. This is the 'save' action. If fn is given, this filename |
277 is used instead of the one in the multi project object. This is the |
274 is used instead of the one in the multi project object. This is the |
278 'save as' action. |
275 'save as' action. |
279 @return flag indicating success |
276 @return flag indicating success |
280 """ |
277 """ |
281 if fn is None: |
278 if fn is None: |
282 fn = self.pfile |
279 fn = self.pfile |
283 |
280 |
284 res = self.__multiProjectFile.writeFile(fn) |
281 res = self.__multiProjectFile.writeFile(fn) |
285 if res: |
282 if res: |
286 self.pfile = os.path.abspath(fn) |
283 self.pfile = os.path.abspath(fn) |
287 self.ppath = os.path.abspath(os.path.dirname(fn)) |
284 self.ppath = os.path.abspath(os.path.dirname(fn)) |
288 self.name = os.path.splitext(os.path.basename(fn))[0] |
285 self.name = os.path.splitext(os.path.basename(fn))[0] |
289 self.setDirty(False) |
286 self.setDirty(False) |
290 |
287 |
291 # insert filename into list of recently opened projects |
288 # insert filename into list of recently opened projects |
292 self.__syncRecent() |
289 self.__syncRecent() |
293 |
290 |
294 return res |
291 return res |
295 |
292 |
296 def addProject(self, project): |
293 def addProject(self, project): |
297 """ |
294 """ |
298 Public method to add a project to the multi-project. |
295 Public method to add a project to the multi-project. |
299 |
296 |
300 @param project dictionary containing the project data to be added |
297 @param project dictionary containing the project data to be added |
301 @type dict |
298 @type dict |
302 """ |
299 """ |
303 self.__projects[project['uid']] = project |
300 self.__projects[project["uid"]] = project |
304 |
301 |
305 @pyqtSlot() |
302 @pyqtSlot() |
306 def addNewProject(self, startdir="", category=""): |
303 def addNewProject(self, startdir="", category=""): |
307 """ |
304 """ |
308 Public slot used to add a new project to the multi-project. |
305 Public slot used to add a new project to the multi-project. |
309 |
306 |
310 @param startdir start directory for the selection dialog |
307 @param startdir start directory for the selection dialog |
311 @type str |
308 @type str |
312 @param category category to be preset |
309 @param category category to be preset |
313 @type str |
310 @type str |
314 """ |
311 """ |
315 from .AddProjectDialog import AddProjectDialog |
312 from .AddProjectDialog import AddProjectDialog |
|
313 |
316 if not startdir: |
314 if not startdir: |
317 startdir = self.ppath |
315 startdir = self.ppath |
318 if not startdir: |
316 if not startdir: |
319 startdir = Preferences.getMultiProject("Workspace") |
317 startdir = Preferences.getMultiProject("Workspace") |
320 dlg = AddProjectDialog(self.ui, startdir=startdir, |
318 dlg = AddProjectDialog( |
321 categories=self.categories, category=category) |
319 self.ui, startdir=startdir, categories=self.categories, category=category |
|
320 ) |
322 if dlg.exec() == QDialog.DialogCode.Accepted: |
321 if dlg.exec() == QDialog.DialogCode.Accepted: |
323 name, filename, isMaster, description, category, uid = ( |
322 name, filename, isMaster, description, category, uid = dlg.getData() |
324 dlg.getData() |
323 |
325 ) |
|
326 |
|
327 # step 1: check, if project was already added |
324 # step 1: check, if project was already added |
328 for project in self.__projects.values(): |
325 for project in self.__projects.values(): |
329 if project['file'] == filename: |
326 if project["file"] == filename: |
330 return |
327 return |
331 |
328 |
332 # step 2: check, if master should be changed |
329 # step 2: check, if master should be changed |
333 if isMaster: |
330 if isMaster: |
334 for project in self.__projects.values(): |
331 for project in self.__projects.values(): |
335 if project['master']: |
332 if project["master"]: |
336 project['master'] = False |
333 project["master"] = False |
337 self.projectDataChanged.emit(project) |
334 self.projectDataChanged.emit(project) |
338 self.setDirty(True) |
335 self.setDirty(True) |
339 break |
336 break |
340 |
337 |
341 # step 3: add the project entry |
338 # step 3: add the project entry |
342 project = { |
339 project = { |
343 'name': name, |
340 "name": name, |
344 'file': filename, |
341 "file": filename, |
345 'master': isMaster, |
342 "master": isMaster, |
346 'description': description, |
343 "description": description, |
347 'category': category, |
344 "category": category, |
348 'uid': uid, |
345 "uid": uid, |
349 } |
346 } |
350 self.__projects[uid] = project |
347 self.__projects[uid] = project |
351 if category not in self.categories: |
348 if category not in self.categories: |
352 self.categories.append(category) |
349 self.categories.append(category) |
353 self.projectAdded.emit(project) |
350 self.projectAdded.emit(project) |
354 self.setDirty(True) |
351 self.setDirty(True) |
355 |
352 |
356 def copyProject(self, uid): |
353 def copyProject(self, uid): |
357 """ |
354 """ |
358 Public method to copy the project with given UID on disk. |
355 Public method to copy the project with given UID on disk. |
359 |
356 |
360 @param uid UID of the project to copy |
357 @param uid UID of the project to copy |
361 @type str |
358 @type str |
362 """ |
359 """ |
363 if uid in self.__projects: |
360 if uid in self.__projects: |
364 startdir = self.ppath |
361 startdir = self.ppath |
367 srcProject = self.__projects[uid] |
364 srcProject = self.__projects[uid] |
368 srcProjectDirectory = os.path.dirname(srcProject["file"]) |
365 srcProjectDirectory = os.path.dirname(srcProject["file"]) |
369 dstProjectDirectory, ok = EricPathPickerDialog.getPath( |
366 dstProjectDirectory, ok = EricPathPickerDialog.getPath( |
370 self.parent(), |
367 self.parent(), |
371 self.tr("Copy Project"), |
368 self.tr("Copy Project"), |
372 self.tr("Enter directory for the new project (must not exist" |
369 self.tr( |
373 " already):"), |
370 "Enter directory for the new project (must not exist" " already):" |
|
371 ), |
374 mode=EricPathPickerModes.DIRECTORY_MODE, |
372 mode=EricPathPickerModes.DIRECTORY_MODE, |
375 path=srcProjectDirectory, |
373 path=srcProjectDirectory, |
376 defaultDirectory=startdir, |
374 defaultDirectory=startdir, |
377 ) |
375 ) |
378 if ( |
376 if ok and dstProjectDirectory and not os.path.exists(dstProjectDirectory): |
379 ok and |
|
380 dstProjectDirectory and |
|
381 not os.path.exists(dstProjectDirectory) |
|
382 ): |
|
383 try: |
377 try: |
384 shutil.copytree(srcProjectDirectory, dstProjectDirectory) |
378 shutil.copytree(srcProjectDirectory, dstProjectDirectory) |
385 except shutil.Error: |
379 except shutil.Error: |
386 EricMessageBox.critical( |
380 EricMessageBox.critical( |
387 self.parent(), |
381 self.parent(), |
388 self.tr("Copy Project"), |
382 self.tr("Copy Project"), |
389 self.tr("<p>The source project <b>{0}</b> could not" |
383 self.tr( |
390 " be copied to its destination <b>{1}</b>." |
384 "<p>The source project <b>{0}</b> could not" |
391 "</p>").format(srcProjectDirectory, |
385 " be copied to its destination <b>{1}</b>." |
392 dstProjectDirectory)) |
386 "</p>" |
|
387 ).format(srcProjectDirectory, dstProjectDirectory), |
|
388 ) |
393 return |
389 return |
394 |
390 |
395 dstUid = QUuid.createUuid().toString() |
391 dstUid = QUuid.createUuid().toString() |
396 dstProject = { |
392 dstProject = { |
397 'name': self.tr("{0} - Copy").format(srcProject["name"]), |
393 "name": self.tr("{0} - Copy").format(srcProject["name"]), |
398 'file': os.path.join(dstProjectDirectory, |
394 "file": os.path.join( |
399 os.path.basename(srcProject["file"])), |
395 dstProjectDirectory, os.path.basename(srcProject["file"]) |
400 'master': False, |
396 ), |
401 'description': srcProject["description"], |
397 "master": False, |
402 'category': srcProject["category"], |
398 "description": srcProject["description"], |
403 'uid': dstUid, |
399 "category": srcProject["category"], |
|
400 "uid": dstUid, |
404 } |
401 } |
405 self.__projects[dstUid] = dstProject |
402 self.__projects[dstUid] = dstProject |
406 self.projectAdded.emit(dstProject) |
403 self.projectAdded.emit(dstProject) |
407 self.setDirty(True) |
404 self.setDirty(True) |
408 |
405 |
409 def changeProjectProperties(self, pro): |
406 def changeProjectProperties(self, pro): |
410 """ |
407 """ |
411 Public method to change the data of a project entry. |
408 Public method to change the data of a project entry. |
412 |
409 |
413 @param pro dictionary with the project data (string) |
410 @param pro dictionary with the project data (string) |
414 """ |
411 """ |
415 # step 1: check, if master should be changed |
412 # step 1: check, if master should be changed |
416 if pro['master']: |
413 if pro["master"]: |
417 for project in self.__projects.values(): |
414 for project in self.__projects.values(): |
418 if project['master']: |
415 if project["master"]: |
419 if project['uid'] != pro['uid']: |
416 if project["uid"] != pro["uid"]: |
420 project['master'] = False |
417 project["master"] = False |
421 self.projectDataChanged.emit(project) |
418 self.projectDataChanged.emit(project) |
422 self.setDirty(True) |
419 self.setDirty(True) |
423 break |
420 break |
424 |
421 |
425 # step 2: change the entry |
422 # step 2: change the entry |
426 project = self.__projects[pro['uid']] |
423 project = self.__projects[pro["uid"]] |
427 # project UID is not changeable via interface |
424 # project UID is not changeable via interface |
428 project['file'] = pro['file'] |
425 project["file"] = pro["file"] |
429 project['name'] = pro['name'] |
426 project["name"] = pro["name"] |
430 project['master'] = pro['master'] |
427 project["master"] = pro["master"] |
431 project['description'] = pro['description'] |
428 project["description"] = pro["description"] |
432 project['category'] = pro['category'] |
429 project["category"] = pro["category"] |
433 if project['category'] not in self.categories: |
430 if project["category"] not in self.categories: |
434 self.categories.append(project['category']) |
431 self.categories.append(project["category"]) |
435 self.projectDataChanged.emit(project) |
432 self.projectDataChanged.emit(project) |
436 self.setDirty(True) |
433 self.setDirty(True) |
437 |
434 |
438 def getProjects(self): |
435 def getProjects(self): |
439 """ |
436 """ |
440 Public method to get all project entries. |
437 Public method to get all project entries. |
441 |
438 |
442 @return list of all project entries (list of dictionaries) |
439 @return list of all project entries (list of dictionaries) |
443 """ |
440 """ |
444 return self.__projects.values() |
441 return self.__projects.values() |
445 |
442 |
446 def getProject(self, uid): |
443 def getProject(self, uid): |
447 """ |
444 """ |
448 Public method to get a reference to a project entry. |
445 Public method to get a reference to a project entry. |
449 |
446 |
450 @param uid UID of the project to get |
447 @param uid UID of the project to get |
451 @type str |
448 @type str |
452 @return dictionary containing the project data |
449 @return dictionary containing the project data |
453 @rtype dict |
450 @rtype dict |
454 """ |
451 """ |
455 if uid in self.__projects: |
452 if uid in self.__projects: |
456 return self.__projects[uid] |
453 return self.__projects[uid] |
457 else: |
454 else: |
458 return None |
455 return None |
459 |
456 |
460 def removeProject(self, uid): |
457 def removeProject(self, uid): |
461 """ |
458 """ |
462 Public slot to remove a project from the multi project. |
459 Public slot to remove a project from the multi project. |
463 |
460 |
464 @param uid UID of the project to be removed from the multi |
461 @param uid UID of the project to be removed from the multi |
465 project |
462 project |
466 @type str |
463 @type str |
467 """ |
464 """ |
468 if uid in self.__projects: |
465 if uid in self.__projects: |
469 project = self.__projects[uid] |
466 project = self.__projects[uid] |
470 del self.__projects[uid] |
467 del self.__projects[uid] |
471 self.projectRemoved.emit(project) |
468 self.projectRemoved.emit(project) |
472 self.setDirty(True) |
469 self.setDirty(True) |
473 |
470 |
474 def deleteProject(self, uid): |
471 def deleteProject(self, uid): |
475 """ |
472 """ |
476 Public slot to delete project(s) from the multi project and disk. |
473 Public slot to delete project(s) from the multi project and disk. |
477 |
474 |
478 @param uid UID of the project to be removed from the multi |
475 @param uid UID of the project to be removed from the multi |
479 project |
476 project |
480 @type str |
477 @type str |
481 """ |
478 """ |
482 if uid in self.__projects: |
479 if uid in self.__projects: |
483 project = self.__projects[uid] |
480 project = self.__projects[uid] |
484 projectPath = os.path.dirname(project["file"]) |
481 projectPath = os.path.dirname(project["file"]) |
485 shutil.rmtree(projectPath, True) |
482 shutil.rmtree(projectPath, True) |
486 |
483 |
487 self.removeProject(uid) |
484 self.removeProject(uid) |
488 |
485 |
489 def __newMultiProject(self): |
486 def __newMultiProject(self): |
490 """ |
487 """ |
491 Private slot to build a new multi project. |
488 Private slot to build a new multi project. |
492 |
489 |
493 This method displays the new multi project dialog and initializes |
490 This method displays the new multi project dialog and initializes |
494 the multi project object with the data entered. |
491 the multi project object with the data entered. |
495 """ |
492 """ |
496 if not self.checkDirty(): |
493 if not self.checkDirty(): |
497 return |
494 return |
498 |
495 |
499 from .PropertiesDialog import PropertiesDialog |
496 from .PropertiesDialog import PropertiesDialog |
|
497 |
500 dlg = PropertiesDialog(self, True) |
498 dlg = PropertiesDialog(self, True) |
501 if dlg.exec() == QDialog.DialogCode.Accepted: |
499 if dlg.exec() == QDialog.DialogCode.Accepted: |
502 self.closeMultiProject() |
500 self.closeMultiProject() |
503 dlg.storeData() |
501 dlg.storeData() |
504 self.opened = True |
502 self.opened = True |
506 self.closeAct.setEnabled(True) |
504 self.closeAct.setEnabled(True) |
507 self.saveasAct.setEnabled(True) |
505 self.saveasAct.setEnabled(True) |
508 self.addProjectAct.setEnabled(True) |
506 self.addProjectAct.setEnabled(True) |
509 self.propsAct.setEnabled(True) |
507 self.propsAct.setEnabled(True) |
510 self.newMultiProject.emit() |
508 self.newMultiProject.emit() |
511 |
509 |
512 def __showProperties(self): |
510 def __showProperties(self): |
513 """ |
511 """ |
514 Private slot to display the properties dialog. |
512 Private slot to display the properties dialog. |
515 """ |
513 """ |
516 from .PropertiesDialog import PropertiesDialog |
514 from .PropertiesDialog import PropertiesDialog |
|
515 |
517 dlg = PropertiesDialog(self, False) |
516 dlg = PropertiesDialog(self, False) |
518 if dlg.exec() == QDialog.DialogCode.Accepted: |
517 if dlg.exec() == QDialog.DialogCode.Accepted: |
519 dlg.storeData() |
518 dlg.storeData() |
520 self.setDirty(True) |
519 self.setDirty(True) |
521 self.multiProjectPropertiesChanged.emit() |
520 self.multiProjectPropertiesChanged.emit() |
522 |
521 |
523 @pyqtSlot() |
522 @pyqtSlot() |
524 @pyqtSlot(str) |
523 @pyqtSlot(str) |
525 def openMultiProject(self, fn=None, openMaster=True): |
524 def openMultiProject(self, fn=None, openMaster=True): |
526 """ |
525 """ |
527 Public slot to open a multi project. |
526 Public slot to open a multi project. |
528 |
527 |
529 @param fn optional filename of the multi project file to be |
528 @param fn optional filename of the multi project file to be |
530 read |
529 read |
531 @type str |
530 @type str |
532 @param openMaster flag indicating, that the master project |
531 @param openMaster flag indicating, that the master project |
533 should be opened depending on the configuration |
532 should be opened depending on the configuration |
534 @type bool |
533 @type bool |
535 """ |
534 """ |
536 if not self.checkDirty(): |
535 if not self.checkDirty(): |
537 return |
536 return |
538 |
537 |
539 if fn is None: |
538 if fn is None: |
540 fn = EricFileDialog.getOpenFileName( |
539 fn = EricFileDialog.getOpenFileName( |
541 self.parent(), |
540 self.parent(), |
542 self.tr("Open Multi Project"), |
541 self.tr("Open Multi Project"), |
543 Preferences.getMultiProject("Workspace") or |
542 Preferences.getMultiProject("Workspace") or Utilities.getHomeDir(), |
544 Utilities.getHomeDir(), |
543 self.tr( |
545 self.tr("Multi Project Files (*.emj);;" |
544 "Multi Project Files (*.emj);;" |
546 "XML Multi Project Files (*.e5m *.e4m)")) |
545 "XML Multi Project Files (*.e5m *.e4m)" |
547 |
546 ), |
|
547 ) |
|
548 |
548 if fn == "": |
549 if fn == "": |
549 fn = None |
550 fn = None |
550 |
551 |
551 if fn is not None: |
552 if fn is not None: |
552 self.closeMultiProject() |
553 self.closeMultiProject() |
553 ok = self.__readMultiProject(fn) |
554 ok = self.__readMultiProject(fn) |
554 if ok: |
555 if ok: |
555 self.opened = True |
556 self.opened = True |
556 |
557 |
557 self.closeAct.setEnabled(True) |
558 self.closeAct.setEnabled(True) |
558 self.saveasAct.setEnabled(True) |
559 self.saveasAct.setEnabled(True) |
559 self.addProjectAct.setEnabled(True) |
560 self.addProjectAct.setEnabled(True) |
560 self.propsAct.setEnabled(True) |
561 self.propsAct.setEnabled(True) |
561 |
562 |
562 self.multiProjectOpened.emit() |
563 self.multiProjectOpened.emit() |
563 |
564 |
564 if openMaster and Preferences.getMultiProject( |
565 if openMaster and Preferences.getMultiProject( |
565 "OpenMasterAutomatically"): |
566 "OpenMasterAutomatically" |
|
567 ): |
566 self.__openMasterProject(False) |
568 self.__openMasterProject(False) |
567 |
569 |
568 def saveMultiProject(self): |
570 def saveMultiProject(self): |
569 """ |
571 """ |
570 Public slot to save the current multi project. |
572 Public slot to save the current multi project. |
571 |
573 |
572 @return flag indicating success |
574 @return flag indicating success |
573 @rtype bool |
575 @rtype bool |
574 """ |
576 """ |
575 if self.isDirty(): |
577 if self.isDirty(): |
576 if len(self.pfile) > 0: |
578 if len(self.pfile) > 0: |
577 if self.pfile.endswith((".e4m", ".e5m")): |
579 if self.pfile.endswith((".e4m", ".e5m")): |
578 self.pfile = (self.pfile |
580 self.pfile = self.pfile.replace(".e4m", ".emj").replace( |
579 .replace(".e4m", ".emj") |
581 ".e5m", ".emj" |
580 .replace(".e5m", ".emj")) |
582 ) |
581 self.__syncRecent() |
583 self.__syncRecent() |
582 ok = self.__writeMultiProject() |
584 ok = self.__writeMultiProject() |
583 else: |
585 else: |
584 ok = self.saveMultiProjectAs() |
586 ok = self.saveMultiProjectAs() |
585 else: |
587 else: |
586 ok = True |
588 ok = True |
587 return ok |
589 return ok |
588 |
590 |
589 def saveMultiProjectAs(self): |
591 def saveMultiProjectAs(self): |
590 """ |
592 """ |
591 Public slot to save the current multi project to a different file. |
593 Public slot to save the current multi project to a different file. |
592 |
594 |
593 @return flag indicating success |
595 @return flag indicating success |
594 @rtype bool |
596 @rtype bool |
595 """ |
597 """ |
596 defaultFilter = self.tr("Multi Project Files (*.emj)") |
598 defaultFilter = self.tr("Multi Project Files (*.emj)") |
597 defaultPath = ( |
599 defaultPath = ( |
598 self.ppath |
600 self.ppath |
599 if self.ppath else |
601 if self.ppath |
600 (Preferences.getMultiProject("Workspace") or |
602 else (Preferences.getMultiProject("Workspace") or Utilities.getHomeDir()) |
601 Utilities.getHomeDir()) |
|
602 ) |
603 ) |
603 fn, selectedFilter = EricFileDialog.getSaveFileNameAndFilter( |
604 fn, selectedFilter = EricFileDialog.getSaveFileNameAndFilter( |
604 self.parent(), |
605 self.parent(), |
605 self.tr("Save Multiproject"), |
606 self.tr("Save Multiproject"), |
606 defaultPath, |
607 defaultPath, |
607 self.tr("Multi Project Files (*.emj)"), |
608 self.tr("Multi Project Files (*.emj)"), |
608 defaultFilter, |
609 defaultFilter, |
609 EricFileDialog.DontConfirmOverwrite) |
610 EricFileDialog.DontConfirmOverwrite, |
610 |
611 ) |
|
612 |
611 if fn: |
613 if fn: |
612 fpath = pathlib.Path(fn) |
614 fpath = pathlib.Path(fn) |
613 if not fpath.suffix: |
615 if not fpath.suffix: |
614 ex = selectedFilter.split("(*")[1].split(")")[0] |
616 ex = selectedFilter.split("(*")[1].split(")")[0] |
615 if ex: |
617 if ex: |
616 fpath = fpath.with_suffix(ex) |
618 fpath = fpath.with_suffix(ex) |
617 if fpath.exists(): |
619 if fpath.exists(): |
618 res = EricMessageBox.yesNo( |
620 res = EricMessageBox.yesNo( |
619 self.parent(), |
621 self.parent(), |
620 self.tr("Save File"), |
622 self.tr("Save File"), |
621 self.tr("<p>The file <b>{0}</b> already exists." |
623 self.tr( |
622 " Overwrite it?</p>").format(fn), |
624 "<p>The file <b>{0}</b> already exists." " Overwrite it?</p>" |
623 icon=EricMessageBox.Warning) |
625 ).format(fn), |
|
626 icon=EricMessageBox.Warning, |
|
627 ) |
624 if not res: |
628 if not res: |
625 return False |
629 return False |
626 |
630 |
627 self.name = fpath.stem |
631 self.name = fpath.stem |
628 self.__writeMultiProject(str(fpath)) |
632 self.__writeMultiProject(str(fpath)) |
629 |
633 |
630 self.multiProjectClosed.emit() |
634 self.multiProjectClosed.emit() |
631 self.multiProjectOpened.emit() |
635 self.multiProjectOpened.emit() |
632 return True |
636 return True |
633 else: |
637 else: |
634 return False |
638 return False |
635 |
639 |
636 def checkDirty(self): |
640 def checkDirty(self): |
637 """ |
641 """ |
638 Public method to check the dirty status and open a message window. |
642 Public method to check the dirty status and open a message window. |
639 |
643 |
640 @return flag indicating whether this operation was successful (boolean) |
644 @return flag indicating whether this operation was successful (boolean) |
641 """ |
645 """ |
642 if self.isDirty(): |
646 if self.isDirty(): |
643 res = EricMessageBox.okToClearData( |
647 res = EricMessageBox.okToClearData( |
644 self.parent(), |
648 self.parent(), |
645 self.tr("Close Multiproject"), |
649 self.tr("Close Multiproject"), |
646 self.tr("The current multiproject has unsaved changes."), |
650 self.tr("The current multiproject has unsaved changes."), |
647 self.saveMultiProject) |
651 self.saveMultiProject, |
|
652 ) |
648 if res: |
653 if res: |
649 self.setDirty(False) |
654 self.setDirty(False) |
650 return res |
655 return res |
651 |
656 |
652 return True |
657 return True |
653 |
658 |
654 def closeMultiProject(self): |
659 def closeMultiProject(self): |
655 """ |
660 """ |
656 Public slot to close the current multi project. |
661 Public slot to close the current multi project. |
657 |
662 |
658 @return flag indicating success (boolean) |
663 @return flag indicating success (boolean) |
659 """ |
664 """ |
660 # save the list of recently opened projects |
665 # save the list of recently opened projects |
661 self.__saveRecent() |
666 self.__saveRecent() |
662 |
667 |
663 if not self.isOpen(): |
668 if not self.isOpen(): |
664 return True |
669 return True |
665 |
670 |
666 if not self.checkDirty(): |
671 if not self.checkDirty(): |
667 return False |
672 return False |
668 |
673 |
669 # now close the current project, if it belongs to the multi project |
674 # now close the current project, if it belongs to the multi project |
670 pfile = self.projectObject.getProjectFile() |
675 pfile = self.projectObject.getProjectFile() |
671 if pfile: |
676 if pfile: |
672 for project in self.__projects.values(): |
677 for project in self.__projects.values(): |
673 if project['file'] == pfile: |
678 if project["file"] == pfile: |
674 if not self.projectObject.closeProject(): |
679 if not self.projectObject.closeProject(): |
675 return False |
680 return False |
676 break |
681 break |
677 |
682 |
678 self.__initData() |
683 self.__initData() |
679 self.closeAct.setEnabled(False) |
684 self.closeAct.setEnabled(False) |
680 self.saveasAct.setEnabled(False) |
685 self.saveasAct.setEnabled(False) |
681 self.saveAct.setEnabled(False) |
686 self.saveAct.setEnabled(False) |
682 self.addProjectAct.setEnabled(False) |
687 self.addProjectAct.setEnabled(False) |
683 self.propsAct.setEnabled(False) |
688 self.propsAct.setEnabled(False) |
684 |
689 |
685 self.multiProjectClosed.emit() |
690 self.multiProjectClosed.emit() |
686 |
691 |
687 return True |
692 return True |
688 |
693 |
689 def initActions(self): |
694 def initActions(self): |
690 """ |
695 """ |
691 Public slot to initialize the multi project related actions. |
696 Public slot to initialize the multi project related actions. |
692 """ |
697 """ |
693 self.actions = [] |
698 self.actions = [] |
694 |
699 |
695 self.actGrp1 = createActionGroup(self) |
700 self.actGrp1 = createActionGroup(self) |
696 |
701 |
697 act = EricAction( |
702 act = EricAction( |
698 self.tr('New multiproject'), |
703 self.tr("New multiproject"), |
699 UI.PixmapCache.getIcon("multiProjectNew"), |
704 UI.PixmapCache.getIcon("multiProjectNew"), |
700 self.tr('&New...'), 0, 0, |
705 self.tr("&New..."), |
701 self.actGrp1, 'multi_project_new') |
706 0, |
702 act.setStatusTip(self.tr('Generate a new multiproject')) |
707 0, |
703 act.setWhatsThis(self.tr( |
708 self.actGrp1, |
704 """<b>New...</b>""" |
709 "multi_project_new", |
705 """<p>This opens a dialog for entering the info for a""" |
710 ) |
706 """ new multiproject.</p>""" |
711 act.setStatusTip(self.tr("Generate a new multiproject")) |
707 )) |
712 act.setWhatsThis( |
|
713 self.tr( |
|
714 """<b>New...</b>""" |
|
715 """<p>This opens a dialog for entering the info for a""" |
|
716 """ new multiproject.</p>""" |
|
717 ) |
|
718 ) |
708 act.triggered.connect(self.__newMultiProject) |
719 act.triggered.connect(self.__newMultiProject) |
709 self.actions.append(act) |
720 self.actions.append(act) |
710 |
721 |
711 act = EricAction( |
722 act = EricAction( |
712 self.tr('Open multiproject'), |
723 self.tr("Open multiproject"), |
713 UI.PixmapCache.getIcon("multiProjectOpen"), |
724 UI.PixmapCache.getIcon("multiProjectOpen"), |
714 self.tr('&Open...'), 0, 0, |
725 self.tr("&Open..."), |
715 self.actGrp1, 'multi_project_open') |
726 0, |
716 act.setStatusTip(self.tr('Open an existing multiproject')) |
727 0, |
717 act.setWhatsThis(self.tr( |
728 self.actGrp1, |
718 """<b>Open...</b>""" |
729 "multi_project_open", |
719 """<p>This opens an existing multiproject.</p>""" |
730 ) |
720 )) |
731 act.setStatusTip(self.tr("Open an existing multiproject")) |
|
732 act.setWhatsThis( |
|
733 self.tr( |
|
734 """<b>Open...</b>""" """<p>This opens an existing multiproject.</p>""" |
|
735 ) |
|
736 ) |
721 act.triggered.connect(self.openMultiProject) |
737 act.triggered.connect(self.openMultiProject) |
722 self.actions.append(act) |
738 self.actions.append(act) |
723 |
739 |
724 self.closeAct = EricAction( |
740 self.closeAct = EricAction( |
725 self.tr('Close multiproject'), |
741 self.tr("Close multiproject"), |
726 UI.PixmapCache.getIcon("multiProjectClose"), |
742 UI.PixmapCache.getIcon("multiProjectClose"), |
727 self.tr('&Close'), 0, 0, self, 'multi_project_close') |
743 self.tr("&Close"), |
728 self.closeAct.setStatusTip(self.tr( |
744 0, |
729 'Close the current multiproject')) |
745 0, |
730 self.closeAct.setWhatsThis(self.tr( |
746 self, |
731 """<b>Close</b>""" |
747 "multi_project_close", |
732 """<p>This closes the current multiproject.</p>""" |
748 ) |
733 )) |
749 self.closeAct.setStatusTip(self.tr("Close the current multiproject")) |
|
750 self.closeAct.setWhatsThis( |
|
751 self.tr( |
|
752 """<b>Close</b>""" """<p>This closes the current multiproject.</p>""" |
|
753 ) |
|
754 ) |
734 self.closeAct.triggered.connect(self.closeMultiProject) |
755 self.closeAct.triggered.connect(self.closeMultiProject) |
735 self.actions.append(self.closeAct) |
756 self.actions.append(self.closeAct) |
736 |
757 |
737 self.saveAct = EricAction( |
758 self.saveAct = EricAction( |
738 self.tr('Save multiproject'), |
759 self.tr("Save multiproject"), |
739 UI.PixmapCache.getIcon("multiProjectSave"), |
760 UI.PixmapCache.getIcon("multiProjectSave"), |
740 self.tr('&Save'), 0, 0, self, 'multi_project_save') |
761 self.tr("&Save"), |
741 self.saveAct.setStatusTip(self.tr('Save the current multiproject')) |
762 0, |
742 self.saveAct.setWhatsThis(self.tr( |
763 0, |
743 """<b>Save</b>""" |
764 self, |
744 """<p>This saves the current multiproject.</p>""" |
765 "multi_project_save", |
745 )) |
766 ) |
|
767 self.saveAct.setStatusTip(self.tr("Save the current multiproject")) |
|
768 self.saveAct.setWhatsThis( |
|
769 self.tr("""<b>Save</b>""" """<p>This saves the current multiproject.</p>""") |
|
770 ) |
746 self.saveAct.triggered.connect(self.saveMultiProject) |
771 self.saveAct.triggered.connect(self.saveMultiProject) |
747 self.actions.append(self.saveAct) |
772 self.actions.append(self.saveAct) |
748 |
773 |
749 self.saveasAct = EricAction( |
774 self.saveasAct = EricAction( |
750 self.tr('Save multiproject as'), |
775 self.tr("Save multiproject as"), |
751 UI.PixmapCache.getIcon("multiProjectSaveAs"), |
776 UI.PixmapCache.getIcon("multiProjectSaveAs"), |
752 self.tr('Save &as...'), 0, 0, self, |
777 self.tr("Save &as..."), |
753 'multi_project_save_as') |
778 0, |
754 self.saveasAct.setStatusTip(self.tr( |
779 0, |
755 'Save the current multiproject to a new file')) |
780 self, |
756 self.saveasAct.setWhatsThis(self.tr( |
781 "multi_project_save_as", |
757 """<b>Save as</b>""" |
782 ) |
758 """<p>This saves the current multiproject to a new file.</p>""" |
783 self.saveasAct.setStatusTip( |
759 )) |
784 self.tr("Save the current multiproject to a new file") |
|
785 ) |
|
786 self.saveasAct.setWhatsThis( |
|
787 self.tr( |
|
788 """<b>Save as</b>""" |
|
789 """<p>This saves the current multiproject to a new file.</p>""" |
|
790 ) |
|
791 ) |
760 self.saveasAct.triggered.connect(self.saveMultiProjectAs) |
792 self.saveasAct.triggered.connect(self.saveMultiProjectAs) |
761 self.actions.append(self.saveasAct) |
793 self.actions.append(self.saveasAct) |
762 |
794 |
763 self.addProjectAct = EricAction( |
795 self.addProjectAct = EricAction( |
764 self.tr('Add project to multiproject'), |
796 self.tr("Add project to multiproject"), |
765 UI.PixmapCache.getIcon("fileProject"), |
797 UI.PixmapCache.getIcon("fileProject"), |
766 self.tr('Add &project...'), 0, 0, |
798 self.tr("Add &project..."), |
767 self, 'multi_project_add_project') |
799 0, |
768 self.addProjectAct.setStatusTip(self.tr( |
800 0, |
769 'Add a project to the current multiproject')) |
801 self, |
770 self.addProjectAct.setWhatsThis(self.tr( |
802 "multi_project_add_project", |
771 """<b>Add project...</b>""" |
803 ) |
772 """<p>This opens a dialog for adding a project""" |
804 self.addProjectAct.setStatusTip( |
773 """ to the current multiproject.</p>""" |
805 self.tr("Add a project to the current multiproject") |
774 )) |
806 ) |
|
807 self.addProjectAct.setWhatsThis( |
|
808 self.tr( |
|
809 """<b>Add project...</b>""" |
|
810 """<p>This opens a dialog for adding a project""" |
|
811 """ to the current multiproject.</p>""" |
|
812 ) |
|
813 ) |
775 self.addProjectAct.triggered.connect(self.addNewProject) |
814 self.addProjectAct.triggered.connect(self.addNewProject) |
776 self.actions.append(self.addProjectAct) |
815 self.actions.append(self.addProjectAct) |
777 |
816 |
778 self.propsAct = EricAction( |
817 self.propsAct = EricAction( |
779 self.tr('Multiproject properties'), |
818 self.tr("Multiproject properties"), |
780 UI.PixmapCache.getIcon("multiProjectProps"), |
819 UI.PixmapCache.getIcon("multiProjectProps"), |
781 self.tr('&Properties...'), 0, 0, self, |
820 self.tr("&Properties..."), |
782 'multi_project_properties') |
821 0, |
783 self.propsAct.setStatusTip(self.tr( |
822 0, |
784 'Show the multiproject properties')) |
823 self, |
785 self.propsAct.setWhatsThis(self.tr( |
824 "multi_project_properties", |
786 """<b>Properties...</b>""" |
825 ) |
787 """<p>This shows a dialog to edit the multiproject""" |
826 self.propsAct.setStatusTip(self.tr("Show the multiproject properties")) |
788 """ properties.</p>""" |
827 self.propsAct.setWhatsThis( |
789 )) |
828 self.tr( |
|
829 """<b>Properties...</b>""" |
|
830 """<p>This shows a dialog to edit the multiproject""" |
|
831 """ properties.</p>""" |
|
832 ) |
|
833 ) |
790 self.propsAct.triggered.connect(self.__showProperties) |
834 self.propsAct.triggered.connect(self.__showProperties) |
791 self.actions.append(self.propsAct) |
835 self.actions.append(self.propsAct) |
792 |
836 |
793 self.closeAct.setEnabled(False) |
837 self.closeAct.setEnabled(False) |
794 self.saveAct.setEnabled(False) |
838 self.saveAct.setEnabled(False) |
795 self.saveasAct.setEnabled(False) |
839 self.saveasAct.setEnabled(False) |
796 self.addProjectAct.setEnabled(False) |
840 self.addProjectAct.setEnabled(False) |
797 self.propsAct.setEnabled(False) |
841 self.propsAct.setEnabled(False) |
798 |
842 |
799 def initMenu(self): |
843 def initMenu(self): |
800 """ |
844 """ |
801 Public slot to initialize the multi project menu. |
845 Public slot to initialize the multi project menu. |
802 |
846 |
803 @return the menu generated (QMenu) |
847 @return the menu generated (QMenu) |
804 """ |
848 """ |
805 menu = QMenu(self.tr('&Multiproject'), self.parent()) |
849 menu = QMenu(self.tr("&Multiproject"), self.parent()) |
806 self.recentMenu = QMenu(self.tr('Open &Recent Multiprojects'), |
850 self.recentMenu = QMenu(self.tr("Open &Recent Multiprojects"), menu) |
807 menu) |
851 |
808 |
|
809 self.__menus = { |
852 self.__menus = { |
810 "Main": menu, |
853 "Main": menu, |
811 "Recent": self.recentMenu, |
854 "Recent": self.recentMenu, |
812 } |
855 } |
813 |
856 |
814 # connect the aboutToShow signals |
857 # connect the aboutToShow signals |
815 self.recentMenu.aboutToShow.connect(self.__showContextMenuRecent) |
858 self.recentMenu.aboutToShow.connect(self.__showContextMenuRecent) |
816 self.recentMenu.triggered.connect(self.__openRecent) |
859 self.recentMenu.triggered.connect(self.__openRecent) |
817 menu.aboutToShow.connect(self.__showMenu) |
860 menu.aboutToShow.connect(self.__showMenu) |
818 |
861 |
819 # build the main menu |
862 # build the main menu |
820 menu.setTearOffEnabled(True) |
863 menu.setTearOffEnabled(True) |
821 menu.addActions(self.actGrp1.actions()) |
864 menu.addActions(self.actGrp1.actions()) |
822 self.menuRecentAct = menu.addMenu(self.recentMenu) |
865 self.menuRecentAct = menu.addMenu(self.recentMenu) |
823 menu.addSeparator() |
866 menu.addSeparator() |
877 self.recent.insert(0, self.pfile) |
920 self.recent.insert(0, self.pfile) |
878 maxRecent = Preferences.getProject("RecentNumber") |
921 maxRecent = Preferences.getProject("RecentNumber") |
879 if len(self.recent) > maxRecent: |
922 if len(self.recent) > maxRecent: |
880 self.recent = self.recent[:maxRecent] |
923 self.recent = self.recent[:maxRecent] |
881 self.__saveRecent() |
924 self.__saveRecent() |
882 |
925 |
883 def __showContextMenuRecent(self): |
926 def __showContextMenuRecent(self): |
884 """ |
927 """ |
885 Private method to set up the recent multi projects menu. |
928 Private method to set up the recent multi projects menu. |
886 """ |
929 """ |
887 self.__loadRecent() |
930 self.__loadRecent() |
888 |
931 |
889 self.recentMenu.clear() |
932 self.recentMenu.clear() |
890 |
933 |
891 for idx, rp in enumerate(self.recent, start=1): |
934 for idx, rp in enumerate(self.recent, start=1): |
892 formatStr = '&{0:d}. {1}' if idx < 10 else '{0:d}. {1}' |
935 formatStr = "&{0:d}. {1}" if idx < 10 else "{0:d}. {1}" |
893 act = self.recentMenu.addAction( |
936 act = self.recentMenu.addAction( |
894 formatStr.format( |
937 formatStr.format( |
895 idx, |
938 idx, Utilities.compactPath(rp, self.ui.maxMenuFilePathLen) |
896 Utilities.compactPath(rp, self.ui.maxMenuFilePathLen))) |
939 ) |
|
940 ) |
897 act.setData(rp) |
941 act.setData(rp) |
898 act.setEnabled(pathlib.Path(rp).exists()) |
942 act.setEnabled(pathlib.Path(rp).exists()) |
899 |
943 |
900 self.recentMenu.addSeparator() |
944 self.recentMenu.addSeparator() |
901 self.recentMenu.addAction(self.tr('&Clear'), self.clearRecent) |
945 self.recentMenu.addAction(self.tr("&Clear"), self.clearRecent) |
902 |
946 |
903 def __openRecent(self, act): |
947 def __openRecent(self, act): |
904 """ |
948 """ |
905 Private method to open a multi project from the list of rencently |
949 Private method to open a multi project from the list of rencently |
906 opened multi projects. |
950 opened multi projects. |
907 |
951 |
908 @param act reference to the action that triggered (QAction) |
952 @param act reference to the action that triggered (QAction) |
909 """ |
953 """ |
910 file = act.data() |
954 file = act.data() |
911 if file: |
955 if file: |
912 self.openMultiProject(file) |
956 self.openMultiProject(file) |
913 |
957 |
914 def clearRecent(self): |
958 def clearRecent(self): |
915 """ |
959 """ |
916 Public method to clear the recent multi projects menu. |
960 Public method to clear the recent multi projects menu. |
917 """ |
961 """ |
918 self.recent = [] |
962 self.recent = [] |
919 self.__saveRecent() |
963 self.__saveRecent() |
920 |
964 |
921 def getActions(self): |
965 def getActions(self): |
922 """ |
966 """ |
923 Public method to get a list of all actions. |
967 Public method to get a list of all actions. |
924 |
968 |
925 @return list of all actions (list of EricAction) |
969 @return list of all actions (list of EricAction) |
926 """ |
970 """ |
927 return self.actions[:] |
971 return self.actions[:] |
928 |
972 |
929 def addEricActions(self, actions): |
973 def addEricActions(self, actions): |
930 """ |
974 """ |
931 Public method to add actions to the list of actions. |
975 Public method to add actions to the list of actions. |
932 |
976 |
933 @param actions list of actions (list of EricAction) |
977 @param actions list of actions (list of EricAction) |
934 """ |
978 """ |
935 self.actions.extend(actions) |
979 self.actions.extend(actions) |
936 |
980 |
937 def removeEricActions(self, actions): |
981 def removeEricActions(self, actions): |
938 """ |
982 """ |
939 Public method to remove actions from the list of actions. |
983 Public method to remove actions from the list of actions. |
940 |
984 |
941 @param actions list of actions (list of EricAction) |
985 @param actions list of actions (list of EricAction) |
942 """ |
986 """ |
943 for act in actions: |
987 for act in actions: |
944 with contextlib.suppress(ValueError): |
988 with contextlib.suppress(ValueError): |
945 self.actions.remove(act) |
989 self.actions.remove(act) |
946 |
990 |
947 def getMenu(self, menuName): |
991 def getMenu(self, menuName): |
948 """ |
992 """ |
949 Public method to get a reference to the main menu or a submenu. |
993 Public method to get a reference to the main menu or a submenu. |
950 |
994 |
951 @param menuName name of the menu (string) |
995 @param menuName name of the menu (string) |
952 @return reference to the requested menu (QMenu) or None |
996 @return reference to the requested menu (QMenu) or None |
953 """ |
997 """ |
954 try: |
998 try: |
955 return self.__menus[menuName] |
999 return self.__menus[menuName] |
956 except KeyError: |
1000 except KeyError: |
957 return None |
1001 return None |
958 |
1002 |
959 def openProject(self, filename): |
1003 def openProject(self, filename): |
960 """ |
1004 """ |
961 Public slot to open a project. |
1005 Public slot to open a project. |
962 |
1006 |
963 @param filename filename of the project file (string) |
1007 @param filename filename of the project file (string) |
964 """ |
1008 """ |
965 self.projectObject.openProject(filename) |
1009 self.projectObject.openProject(filename) |
966 self.projectOpened.emit(filename) |
1010 self.projectOpened.emit(filename) |
967 |
1011 |
968 def __openMasterProject(self, reopen=True): |
1012 def __openMasterProject(self, reopen=True): |
969 """ |
1013 """ |
970 Private slot to open the master project. |
1014 Private slot to open the master project. |
971 |
1015 |
972 @param reopen flag indicating, that the master project should be |
1016 @param reopen flag indicating, that the master project should be |
973 reopened, if it has been opened already (boolean) |
1017 reopened, if it has been opened already (boolean) |
974 """ |
1018 """ |
975 for project in self.__projects.values(): |
1019 for project in self.__projects.values(): |
976 if ( |
1020 if project["master"] and ( |
977 project['master'] and |
1021 reopen |
978 (reopen or |
1022 or not self.projectObject.isOpen() |
979 not self.projectObject.isOpen() or |
1023 or self.projectObject.getProjectFile() != project["file"] |
980 self.projectObject.getProjectFile() != project['file']) |
|
981 ): |
1024 ): |
982 self.openProject(project['file']) |
1025 self.openProject(project["file"]) |
983 return |
1026 return |
984 |
1027 |
985 def getMasterProjectFile(self): |
1028 def getMasterProjectFile(self): |
986 """ |
1029 """ |
987 Public method to get the filename of the master project. |
1030 Public method to get the filename of the master project. |
988 |
1031 |
989 @return name of the master project file (string) |
1032 @return name of the master project file (string) |
990 """ |
1033 """ |
991 for project in self.__projects: |
1034 for project in self.__projects: |
992 if project['master']: |
1035 if project["master"]: |
993 return project['file'] |
1036 return project["file"] |
994 |
1037 |
995 return None |
1038 return None |
996 |
1039 |
997 def getDependantProjectFiles(self): |
1040 def getDependantProjectFiles(self): |
998 """ |
1041 """ |
999 Public method to get the filenames of the dependent projects. |
1042 Public method to get the filenames of the dependent projects. |
1000 |
1043 |
1001 @return names of the dependent project files (list of strings) |
1044 @return names of the dependent project files (list of strings) |
1002 """ |
1045 """ |
1003 files = [] |
1046 files = [] |
1004 for project in self.__projects.values(): |
1047 for project in self.__projects.values(): |
1005 if not project['master']: |
1048 if not project["master"]: |
1006 files.append(project['file']) |
1049 files.append(project["file"]) |
1007 return files |
1050 return files |