--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/VCS/ProjectHelper.py Mon Dec 28 16:03:33 2009 +0000 @@ -0,0 +1,476 @@ +# -*- coding: utf-8 -*- + +# Copyright (c) 2005 - 2009 Detlev Offenbach <detlev@die-offenbachs.de> +# + +""" +Module implementing the base class of the VCS project helper. +""" + +import os +import sys +import shutil +import copy + +from PyQt4.QtCore import * +from PyQt4.QtGui import * + +from E4Gui.E4Application import e4App + +import VCS +from CommandOptionsDialog import vcsCommandOptionsDialog +from RepositoryInfoDialog import VcsRepositoryInfoDialog + +from E4Gui.E4Action import E4Action + +import Utilities +import Preferences + +class VcsProjectHelper(QObject): + """ + Class implementing the base class of the VCS project helper. + """ + def __init__(self, vcsObject, projectObject, parent = None, name = None): + """ + Constructor + + @param vcsObject reference to the vcs object + @param projectObject reference to the project object + @param parent parent widget (QWidget) + @param name name of this object (string) + """ + QObject.__init__(self, parent) + if name: + self.setObjectName(name) + + self.vcs = vcsObject + self.project = projectObject + + self.actions = [] + + self.initActions() + + def setObjects(self, vcsObject, projectObject): + """ + Public method to set references to the vcs and project objects. + + @param vcsObject reference to the vcs object + @param projectObject reference to the project object + """ + self.vcs = vcsObject + self.project = projectObject + + def initActions(self): + """ + Public method to generate the action objects. + """ + self.vcsNewAct = E4Action(self.trUtf8('New from repository'), + self.trUtf8('&New from repository...'), 0, 0, self, 'vcs_new') + self.vcsNewAct.setStatusTip(self.trUtf8( + 'Create a new project from the VCS repository' + )) + self.vcsNewAct.setWhatsThis(self.trUtf8( + """<b>New from repository</b>""" + """<p>This creates a new local project from the VCS repository.</p>""" + )) + self.connect(self.vcsNewAct, SIGNAL('triggered()'), self._vcsCheckout) + self.actions.append(self.vcsNewAct) + + self.vcsExportAct = E4Action(self.trUtf8('Export from repository'), + self.trUtf8('&Export from repository...'), 0, 0, self, 'vcs_export') + self.vcsExportAct.setStatusTip(self.trUtf8( + 'Export a project from the repository' + )) + self.vcsExportAct.setWhatsThis(self.trUtf8( + """<b>Export from repository</b>""" + """<p>This exports a project from the repository.</p>""" + )) + self.connect(self.vcsExportAct, SIGNAL('triggered()'), self._vcsExport) + self.actions.append(self.vcsExportAct) + + self.vcsAddAct = E4Action(self.trUtf8('Add to repository'), + self.trUtf8('&Add to repository...'), 0, 0, self, 'vcs_add') + self.vcsAddAct.setStatusTip(self.trUtf8( + 'Add the local project to the VCS repository' + )) + self.vcsAddAct.setWhatsThis(self.trUtf8( + """<b>Add to repository</b>""" + """<p>This adds (imports) the local project to the VCS repository.</p>""" + )) + self.connect(self.vcsAddAct, SIGNAL('triggered()'), self._vcsImport) + self.actions.append(self.vcsAddAct) + + def initMenu(self, menu): + """ + Public method to generate the VCS menu. + + @param menu reference to the menu to be populated (QMenu) + """ + menu.clear() + + menu.addAction(self.vcsNewAct) + menu.addAction(self.vcsExportAct) + menu.addSeparator() + menu.addAction(self.vcsAddAct) + menu.addSeparator() + + def showMenu(self): + """ + Public slot called before the vcs menu is shown. + """ + self.vcsAddAct.setEnabled(self.project.isOpen()) + + def _vcsCheckout(self, export = False): + """ + Protected slot used to create a local project from the repository. + + @param export flag indicating whether an export or a checkout + should be performed + """ + if not self.project.checkDirty(): + return + + vcsSystemsDict = e4App().getObject("PluginManager")\ + .getPluginDisplayStrings("version_control") + vcsSystemsDisplay = [] + keys = sorted(vcsSystemsDict.keys()) + for key in keys: + vcsSystemsDisplay.append(vcsSystemsDict[key]) + vcsSelected, ok = QInputDialog.getItem(\ + None, + self.trUtf8("New Project"), + self.trUtf8("Select version control system for the project"), + vcsSystemsDisplay, + 0, False) + if not ok: + return + for vcsSystem, vcsSystemDisplay in vcsSystemsDict.items(): + if vcsSystemDisplay == vcsSelected: + break + + self.project.pdata["VCS"] = [vcsSystem] + self.project.vcs = self.project.initVCS(vcsSystem) + if self.project.vcs is not None: + vcsdlg = self.project.vcs.vcsNewProjectOptionsDialog() + if vcsdlg.exec_() == QDialog.Accepted: + self.project.closeProject() + projectdir, vcsDataDict = vcsdlg.getData() + self.project.pdata["VCS"] = [vcsSystem] + self.project.vcs = self.project.initVCS(vcsSystem) + # edit VCS command options + vcores = QMessageBox.question(None, + self.trUtf8("New Project"), + self.trUtf8("""Would you like to edit the VCS command options?"""), + QMessageBox.StandardButtons(\ + QMessageBox.No | \ + QMessageBox.Yes), + QMessageBox.No) + if vcores == QMessageBox.Yes: + codlg = vcsCommandOptionsDialog(self.project.vcs) + if codlg.exec_() == QDialog.Accepted: + self.project.vcs.vcsSetOptions(codlg.getOptions()) + + # create the project directory if it doesn't exist already + if not os.path.isdir(projectdir): + try: + os.makedirs(projectdir) + except EnvironmentError: + QMessageBox.critical(None, + self.trUtf8("Create project directory"), + self.trUtf8("<p>The project directory <b>{0}</b> could not" + " be created.</p>").format(projectdir)) + self.project.pdata["VCS"] = ['None'] + self.project.vcs = self.project.initVCS() + return + + # create the project from the VCS + self.project.vcs.vcsSetDataFromDict(vcsDataDict) + if export: + ok = self.project.vcs.vcsExport(vcsDataDict, projectdir) + else: + ok = self.project.vcs.vcsCheckout(vcsDataDict, projectdir, False) + if ok: + projectdir = os.path.normpath(projectdir) + filters = ["*.e4p", "*.e4pz", "*.e3p", "*.e3pz"] + d = QDir(projectdir) + plist = d.entryInfoList(filters) + if len(plist): + if len(plist) == 1: + self.project.openProject(plist[0].absoluteFilePath()) + self.project.emit(SIGNAL('newProject')) + else: + pfilenamelist = d.entryList(filters) + pfilename, ok = QInputDialog.getItem( + None, + self.trUtf8("New project from repository"), + self.trUtf8("Select a project file to open."), + pfilenamelist, 0, False) + if ok: + self.project.openProject(\ + QFileInfo(d, pfilename).absoluteFilePath()) + self.project.emit(SIGNAL('newProject')) + if export: + self.project.pdata["VCS"] = ['None'] + self.project.vcs = self.project.initVCS() + self.project.setDirty(True) + self.project.saveProject() + else: + res = QMessageBox.question(None, + self.trUtf8("New project from repository"), + self.trUtf8("The project retrieved from the repository" + " does not contain an eric project file" + " (*.e4p *.e4pz *.e3p *.e3pz)." + " Create it?"), + QMessageBox.StandardButtons(\ + QMessageBox.No | \ + QMessageBox.Yes), + QMessageBox.Yes) + if res == QMessageBox.Yes: + self.project.ppath = projectdir + self.project.opened = True + + from Project.PropertiesDialog import PropertiesDialog + dlg = PropertiesDialog(self.project, False) + if dlg.exec_() == QDialog.Accepted: + dlg.storeData() + self.project.initFileTypes() + self.project.setDirty(True) + try: + ms = os.path.join(self.project.ppath, + self.project.pdata["MAINSCRIPT"][0]) + if os.path.exists(ms): + self.project.appendFile(ms) + except IndexError: + ms = "" + self.project.newProjectAddFiles(ms) + self.project.saveProject() + self.project.openProject(self.project.pfile) + if not export: + res = QMessageBox.question(None, + self.trUtf8("New project from repository"), + self.trUtf8("Shall the project file be added to" + " the repository?"), + QMessageBox.StandardButtons(\ + QMessageBox.No | \ + QMessageBox.Yes), + QMessageBox.Yes) + if res == QMessageBox.Yes: + self.project.vcs.vcsAdd(self.project.pfile) + else: + QMessageBox.critical(None, + self.trUtf8("New project from repository"), + self.trUtf8("""The project could not be retrieved from""" + """ the repository.""")) + self.project.pdata["VCS"] = ['None'] + self.project.vcs = self.project.initVCS() + else: + self.project.pdata["VCS"] = ['None'] + self.project.vcs = self.project.initVCS() + + def _vcsExport(self): + """ + Protected slot used to export a project from the repository. + """ + self._vcsCheckout(True) + + def _vcsImport(self): + """ + Protected slot used to import the local project into the repository. + + <b>NOTE</b>: + This does not necessarily make the local project a vcs controlled + project. You may have to checkout the project from the repository in + order to accomplish that. + """ + def revertChanges(): + """ + Local function to revert the changes made to the project object. + """ + self.project.pdata["VCS"] = pdata_vcs[:] + self.project.pdata["VCSOPTIONS"] = copy.deepcopy(pdata_vcsoptions) + self.project.pdata["VCSOTHERDATA"] = copy.deepcopy(pdata_vcsother) + self.project.vcs = vcs + self.project.vcsProjectHelper = vcsHelper + self.project.vcsBasicHelper = vcs is None + self.initMenu(self.project.vcsMenu) + self.project.setDirty(True) + self.project.saveProject() + + pdata_vcs = self.project.pdata["VCS"][:] + pdata_vcsoptions = copy.deepcopy(self.project.pdata["VCSOPTIONS"]) + pdata_vcsother = copy.deepcopy(self.project.pdata["VCSOTHERDATA"]) + vcs = self.project.vcs + vcsHelper = self.project.vcsProjectHelper + vcsSystemsDict = e4App().getObject("PluginManager")\ + .getPluginDisplayStrings("version_control") + vcsSystemsDisplay = [] + keys = vcsSystemsDict.keys() + keys.sort() + for key in keys: + vcsSystemsDisplay.append(vcsSystemsDict[key]) + vcsSelected, ok = QInputDialog.getItem(\ + None, + self.trUtf8("Import Project"), + self.trUtf8("Select version control system for the project"), + vcsSystemsDisplay, + 0, False) + if not ok: + return + for vcsSystem, vcsSystemDisplay in vcsSystemsDict.items(): + if vcsSystemDisplay == vcsSelected: + break + + self.project.pdata["VCS"] = [vcsSystem] + self.project.vcs = self.project.initVCS(vcsSystem) + if self.project.vcs is not None: + vcsdlg = self.project.vcs.vcsOptionsDialog(self.project, self.project.name, 1) + if vcsdlg.exec_() == QDialog.Accepted: + vcsDataDict = vcsdlg.getData() + # edit VCS command options + vcores = QMessageBox.question(None, + self.trUtf8("Import Project"), + self.trUtf8("""Would you like to edit the VCS command options?"""), + QMessageBox.StandardButtons(\ + QMessageBox.No | \ + QMessageBox.Yes), + QMessageBox.No) + if vcores == QMessageBox.Yes: + codlg = vcsCommandOptionsDialog(self.project.vcs) + if codlg.exec_() == QDialog.Accepted: + self.project.vcs.vcsSetOptions(codlg.getOptions()) + self.project.setDirty(True) + self.project.vcs.vcsSetDataFromDict(vcsDataDict) + self.project.saveProject() + isVcsControlled = \ + self.project.vcs.vcsImport(vcsDataDict, self.project.ppath)[1] + if isVcsControlled: + # reopen the project + self.project.openProject(self.project.pfile) + else: + # revert the changes to the local project + # because the project dir is not a VCS directory + revertChanges() + else: + # revert the changes because user cancelled + revertChanges() + + def _vcsUpdate(self): + """ + Protected slot used to update the local project from the repository. + """ + shouldReopen = self.vcs.vcsUpdate(self.project.ppath) + if shouldReopen: + res = QMessageBox.information(None, + self.trUtf8("Update"), + self.trUtf8("""The project should be reread. Do this now?"""), + QMessageBox.StandardButtons(\ + QMessageBox.No | \ + QMessageBox.Yes), + QMessageBox.Yes) + if res == QMessageBox.Yes: + self.project.reopenProject() + + def _vcsCommit(self): + """ + Protected slot used to commit changes to the local project to the repository. + """ + if Preferences.getVCS("AutoSaveProject"): + self.project.saveProject() + if Preferences.getVCS("AutoSaveFiles"): + self.project.saveAllScripts() + self.vcs.vcsCommit(self.project.ppath, '') + + def _vcsRemove(self): + """ + Protected slot used to remove the local project from the repository. + + Depending on the parameters set in the vcs object the project + may be removed from the local disk as well. + """ + res = QMessageBox.warning(None, + self.trUtf8("Remove project from repository"), + self.trUtf8("Dou you really want to remove this project from" + " the repository (and disk)?"), + QMessageBox.StandardButtons(\ + QMessageBox.No | \ + QMessageBox.Yes), + QMessageBox.No) + if res == QMessageBox.Yes: + self.vcs.vcsRemove(self.project.ppath, True) + self._vcsCommit() + if not os.path.exists(self.project.pfile): + ppath = self.project.ppath + self.setDirty(False) + self.project.closeProject() + shutil.rmtree(ppath, True) + + def _vcsCommandOptions(self): + """ + Protected slot to edit the VCS command options. + """ + codlg = vcsCommandOptionsDialog(self.vcs) + if codlg.exec_() == QDialog.Accepted: + self.vcs.vcsSetOptions(codlg.getOptions()) + self.project.setDirty(True) + + def _vcsLog(self): + """ + Protected slot used to show the log of the local project. + """ + self.vcs.vcsLog(self.project.ppath) + + def _vcsDiff(self): + """ + Protected slot used to show the difference of the local project to the repository. + """ + self.vcs.vcsDiff(self.project.ppath) + + def _vcsStatus(self): + """ + Protected slot used to show the status of the local project. + """ + self.vcs.vcsStatus(self.project.ppath) + + def _vcsTag(self): + """ + Protected slot used to tag the local project in the repository. + """ + self.vcs.vcsTag(self.project.ppath) + + def _vcsRevert(self): + """ + Protected slot used to revert changes made to the local project. + """ + self.vcs.vcsRevert(self.project.ppath) + + def _vcsSwitch(self): + """ + Protected slot used to switch the local project to another tag/branch. + """ + self.vcs.vcsSwitch(self.project.ppath) + + def _vcsMerge(self): + """ + Protected slot used to merge changes of a tag/revision into the local project. + """ + self.vcs.vcsMerge(self.project.ppath) + + def _vcsCleanup(self): + """ + Protected slot used to cleanup the local project. + """ + self.vcs.vcsCleanup(self.project.ppath) + + def _vcsCommand(self): + """ + Protected slot used to execute an arbitrary vcs command. + """ + self.vcs.vcsCommandLine(self.project.ppath) + + def _vcsInfoDisplay(self): + """ + Protected slot called to show some vcs information. + """ + info = self.vcs.vcsRepositoryInfos(self.project.ppath) + dlg = VcsRepositoryInfoDialog(None, info) + dlg.exec_()