예제 #1
0
  def getDrives(self):

    if isWindowsOS():
      import win32api
      drives = win32api.GetLogicalDriveStrings()
      drives = drives.split('\x00')
      drives = [normalisePath(drive) for drive in drives if drive]
      drives.sort()
    else:
      drives = []

    return drives
예제 #2
0
    def testWriteAccess(self):

        try:
            fileName = joinPath(self.installRoot, '__write_test__')
            file = open(fileName, 'w')
            file.close()
            os.remove(fileName)
        except:
            if not isWindowsOS():
                message = 'File updates not possible: You do not have write access to %s%s' % (
                    self.installRoot, os.sep)
            else:
                message = 'File updates not possible: You do not have write access to %s%s' % (self.installRoot,os.sep) \
                        + '\n\nTry running Analysis as administrator by right clicking on the Analysis ' \
                        + 'shortcut on the desktop and selecting "Run as administrator", and then apply any updates.'
            self.warningMessage('Failure', message)
            return False

        return True
예제 #3
0
    def installUpdates(self):

        if self.isGraphical and not showOkCancel(
                'Confirmation', 'Continue with file upgrade?'):
            return

        if not self.server:
            self.warningMessage('Warning', 'No accessible server')
            return

        if not self.installRoot:
            self.warningMessage('Warning', 'No installation path')
            return

        updates = self.server.getSelectedUpdates()

        if not updates:
            self.warningMessage('Warning', 'No selected updates to install')
            return

        needMake = False
        needMakeClean = False
        needMakeLinks = False
        for update in updates:
            update.setInstallFromCache()
            if update.fileName.endswith('.c'):
                needMake = True
            elif update.fileName.endswith('.h'):
                needMake = needMakeClean = True
            elif update.fileName == 'Makefile':
                needMake = needMakeClean = needMakeLinks = True

        if not isWindowsOS():
            self.compileCode(needMakeClean=needMakeClean,
                             needMake=needMake,
                             needMakeLinks=needMakeLinks)

        if self.isGraphical and not self.isStandAlone:
            self.warningMessage(
                'Notice',
                'All updates complete. You must restart for changes to take effect.'
            )
예제 #4
0
    def getDrives(self):

        if isWindowsOS():
            #import win32api
            #drives = win32api.GetLogicalDriveStrings()
            #drives = drives.split('\x00')
            #drives = [normalisePath(drive) for drive in drives if drive]
            #drives.sort()
            # 19 Mar 2012: do not use win32api because not standard
            from ctypes import windll
            import string
            drives = []
            bitmask = windll.kernel32.GetLogicalDrives()
            for letter in string.ascii_uppercase:
                if bitmask & 1:
                    drives.append(letter)
                bitmask >>= 1
            drives = [drive + ':\\' for drive in drives]
            drives = [normalisePath(drive) for drive in drives]
        else:
            drives = []

        return drives
예제 #5
0
 def isGeneralDataWriteable(generalDataRepository):
     oldPath = generalDataRepository.url.path
     return (isWindowsOS() or os.access(oldPath, os.W_OK | os.X_OK))
예제 #6
0
def saveProject(project,
                newPath=None,
                newProjectName=None,
                changeBackup=True,
                createFallback=False,
                removeExisting=False,
                showYesNo=None,
                checkValid=False,
                changeDataLocations=False,
                showWarning=None,
                revertToOriginal=False):
    """
  Save the userData for a project to a location given by newPath (the url.path
  of the userData repository) if set, or the existing location if not. 
  If userData does not exist then throws IOError.
  If newPath is not specified then it is set to oldPath.
  If newProjectName is not specified then it is set to oldProjectName if
    newPath==oldPath, otherwise it is set to basename(newPath).
  If changeBackup, then also changes backup URL path for project.
  If createFallback, then makes copy of existing modified topObjects
    files (in newPath, not oldPath) before doing save.
  If newPath != oldPath and newPath exists (either as file or as directory):
    If removeExisting:
      Delete the newPath.
    Else if showYesNo:
      Ask the user if it is ok to delete the newPath
      If yes, delete.  If no, return without saving.
    Else:
      Raise an IOError
  Elif newProjectName != oldProjectName and there exists corresponding path (file/directory):
    If removeExisting:
      Delete the path.
    Else if showYesNo:
      Ask the user if it is ok to delete the path.
      If yes, delete.  If no, return without saving.
    Else:
      Raise an IOError
  If checkValid then does checkAllValid on project
  If changeDataLocations then copy to project directory
  If revertToOriginal then after the save changes paths back to as they were originally
  If there is no exception or early return then at end userData is pointing to newPath.
  Return True if save done, False if not (unless there is an exception)
  """

    # check project valid (so don't save an obviously invalid project)
    if checkValid:
        project.checkAllValid()

    # only want to change path for userData
    userData = project.findFirstRepository(name='userData')
    if not userData:
        raise IOError('Problem: userData not found')

    oldPath = userData.url.path
    oldProjectName = project.name

    if newPath:
        # normalise newPath
        newPath = normalisePath(newPath, makeAbsolute=True)
    else:
        newPath = oldPath

    # if newProjectName isn't specified then use default
    if not newProjectName:
        if newPath == oldPath:
            newProjectName = oldProjectName
        else:
            newProjectName = os.path.basename(newPath)
            # below is because of data model limit
            newProjectName = newProjectName[:32]

    renameProject(project, newProjectName)

    # if newPath same as oldPath, check if newProjectName already exists if it's not same as oldProjectName
    if newPath == oldPath:
        if newProjectName != oldProjectName:
            location = xmlUtil.getTopObjectPath(project)
            if os.path.exists(location):
                answer = checkRemoveIfExists(location, removeExisting,
                                             showYesNo)
                if answer is None:
                    project.__dict__[
                        'name'] = oldProjectName  # TBD: for now name is frozen so change this way
                    return False
    else:  # check instead if newPath already exists
        if os.path.exists(newPath):
            answer = checkRemoveIfExists(newPath, removeExisting, showYesNo)
            if answer is None:
                if newProjectName != oldProjectName:
                    project.__dict__[
                        'name'] = oldProjectName  # TBD: for now name is frozen so change this way
                return False
            # TBD: should we be removing it?
            removePath(newPath)
        else:
            # NBNB 2008/04/03 Rasmus Fogh. Added because it otherwise fell over when
            # target path did not exist
            upDir = os.path.dirname(newPath)
            if not os.path.exists(upDir):
                os.makedirs(upDir)

        # check if any topObject activeRepository is not either of above
        refData = project.findFirstRepository(name='refData')
        genData = project.findFirstRepository(name='generalData')
        topObjects = []
        repositories = set()
        for topObject in project.topObjects:
            repository = topObject.findFirstActiveRepository()
            if repository and repository not in (userData, refData, genData):
                topObjects.append(topObject)
                repositories.add(repository)
        if topObjects:
            print(
                'Warning, topObjects %s, in repositories %s, being left in original locations'
                % (topObjects, repositories))

    try:
        oldUrl = userData.url
        if changeBackup:
            # change project backup url to point to new path
            backupRepository = project.findFirstRepository(name="backup")
            if backupRepository:
                oldBackupUrl = backupRepository.url
            else:
                changeBackup = False

        # copy userData files over
        if newPath != oldPath:
            # if os.path.exists(oldPath):  # only copy if this is a directory
            if os.path.isdir(oldPath):
                # just copy everything from oldPath to newPath
                print(
                    'Copying directory %s to %s (this might take some time if there are big files)'
                    % (oldPath, newPath))
                shutil.copytree(oldPath, newPath)

                # but need toz remove all implementation files
                implPath = joinPath(newPath, ImpConstants.modellingPackageName,
                                    ImpConstants.implementationPackageName)
                #implPath = pathImplDirectory(newPath)
                removePath(implPath)

                # and need to repoint dataUrl's that were copied over
                oldPathP = oldPath + '/'
                for dataLocationStore in project.dataLocationStores:
                    for dataStore in dataLocationStore.dataStores:
                        oldDataPath = dataStore.fullPath
                        if oldDataPath.startswith(oldPathP):
                            dataUrl = dataStore.dataUrl
                            oldDataUrlPath = dataUrl.url.dataLocation
                            if oldDataUrlPath.startswith(
                                    oldPathP):  # normally true
                                newDataUrlPath = newPath + oldDataUrlPath[
                                    len(oldPath):]
                                dataUrl.url = Implementation.Url(
                                    path=newDataUrlPath)
                            else:  # path split awkwardly between absolute and relative
                                newDataUrlPath = newPath
                                dataUrl.url = Implementation.Url(
                                    path=newDataUrlPath)
                                dataStore.path = oldDataPath[len(oldPath):]

            # change userData url to point to new path
            userData.url = Implementation.Url(path=newPath)
            # above will set project.isModified = True

            if changeBackup:
                # change project backup repository url to point to new path
                backupRepository.url = Implementation.Url(path=newPath +
                                                          '_backup')

        # change project name
        if newProjectName != oldProjectName:
            if not project.isModified:  # if it isModified it will be saved below
                if createFallback:
                    createTopObjectFallback(project)
                project.save()

        # create fallbacks and keep track of modified topObjects
        modifiedTopObjects = []
        if createFallback:
            for topObject in (project, ) + tuple(project.topObjects):
                if not topObject.isDeleted and topObject.isModified:
                    createTopObjectFallback(topObject)
                    modifiedTopObjects.append(topObject)

        if changeDataLocations:
            dataLocationStores = project.sortedDataLocationStores()

            userRepository = project.findFirstRepository(name='userData')
            userPath = userRepository.url.dataLocation
            # 2010 Aug 11: remove data directory from path
            #dataPath = joinPath(userPath, 'data')
            dataPath = userPath

            # 2010 Aug 11: change name
            #dataStorePrefix = 'dataStore'
            dataStorePrefix = 'spectra'
            if os.path.exists(dataPath):
                files = [
                    xx for xx in os.listdir(dataPath)
                    if xx.startswith(dataStorePrefix)
                ]
                offset = len(files)
            else:
                offset = 0

            copyingList = []
            dataUrlDict = {}
            for dataLocationStore in dataLocationStores:
                for dataStore in dataLocationStore.sortedDataStores():

                    # wb104: 24 Mar 2010: below check is a complete kludge
                    # we should check whether dataStore is instance of
                    # NumericMatrix, etc., but those are in ccp so should
                    # not be imported here
                    # in any case, there is no proper way to find out if
                    # a dataStore is used without explicit knowledge of class
                    knt = 0
                    # hicard = 1
                    for attr in ('nmrDataSourceImage', ):
                        if hasattr(dataStore, attr):
                            if getattr(dataStore, attr):
                                knt += 1
                    # hicard > 1
                    for attr in ('externalDatas', 'nmrDataSources'):
                        if hasattr(dataStore, attr):
                            knt += len(getattr(dataStore, attr))
                    if knt == 0:
                        continue

                    oldFullPath = dataStore.fullPath
                    if not oldFullPath.startswith(userPath + '/'):
                        # first figure out new dataUrl path
                        dataUrl = dataStore.dataUrl
                        oldPath = dataUrl.url.dataLocation
                        if dataUrl in dataUrlDict:
                            newUrl = dataUrlDict[dataUrl]
                        else:
                            offset += 1
                            newUrlPath = '%s%d' % (dataStorePrefix, offset)
                            newUrlPath = joinPath(dataPath, newUrlPath)
                            newUrl = dataUrlDict[dataUrl] = Implementation.Url(
                                path=newUrlPath)
                        # then add to list to copy over if original data exists
                        if os.path.exists(oldFullPath):
                            newFullPath = joinPath(newUrl.dataLocation,
                                                   dataStore.path)
                            copyingList.append((oldFullPath, newFullPath))

            # now copy data files over
            nfilesToCopy = len(copyingList)
            for n, (oldFullPath, newFullPath) in enumerate(copyingList):
                dirName = os.path.dirname(newFullPath)
                if not os.path.exists(dirName):
                    os.makedirs(dirName)
                print('Copying file %s to %s (%d of %d)' %
                      (oldFullPath, newFullPath, n + 1, nfilesToCopy))
                shutil.copy(oldFullPath, newFullPath)

            # finally change dataUrl paths
            for dataUrl in dataUrlDict:
                dataUrl.url = dataUrlDict[dataUrl]

        # save modifications
        # change way doing save in case exception is thrown
        if createFallback:
            for topObject in modifiedTopObjects:
                try:
                    topObject.save()
                except:
                    location = xmlUtil.getTopObjectPath(topObject)
                    print('Exception working on topObject %s, file %s' %
                          (topObject, location))
                    raise
            # be safe and do below in case new modifications after
            # modifiedTopObjects has been created
            project.saveModified()
        else:
            project.saveModified()

        if not isWindowsOS():
            os.system('touch "%s"' %
                      newPath)  # so that user can see which are most recent

        badTopObjects = []
        for topObject in modifiedTopObjects:
            if not checkFileIntegrity(topObject):
                badTopObjects.append(topObject)

        if badTopObjects:
            if showWarning:
                showWarning(
                    'Incomplete save',
                    'It looks like one or more files did not save completely, see console for list'
                )
            print(
                'It looks like one or more files did not save completely, you should check them:'
            )
            for topObject in badTopObjects:
                print
                print('%s, path:' % topObject)
                print(xmlUtil.getTopObjectPath(topObject))
            return False

        if revertToOriginal:  # TBD: the below does not change back dataUrl paths
            if newProjectName != oldProjectName:
                project.__dict__[
                    'name'] = oldProjectName  # TBD: for now name is frozen so change this way

            if newPath != oldPath:
                userData.url = oldUrl
                if changeBackup:
                    backupRepository.url = oldBackupUrl

        return True

    except:
        # saveModified failed so revert to old values
        if newProjectName != oldProjectName:
            project.__dict__[
                'name'] = oldProjectName  # TBD: for now name is frozen so change this way

        if newPath != oldPath:
            userData.url = oldUrl
            if changeBackup:
                backupRepository.url = oldBackupUrl
            try:
                removePath(newPath)
            except:
                pass

        raise
예제 #7
0
  print 'Error, cannot import core CCPN Python modules:'
  print 'Maybe your PYTHONPATH environment variable is not set or'
  print 'does not contain the current CCPN installation directory.'
  raise

from memops.general.Implementation import ApiError

from memops.gui.MessageReporter import showError

from memops.universal.Util import isWindowsOS

from ccp.gui.Io import loadProject

from ccpnmr.analysis.AnalysisPopup import AnalysisPopup

if isWindowsOS():
  # create interactive session when using MS Windows
  os.environ["PYTHONINSPECT"]="x"

top = None

def main(projectDir=None, cache_size=64, glDirect=None):

  global top

  #print 'cache_size =', cache_size

  root = Tkinter.Tk()
  root.withdraw()
  root.option_add("*Background", "grey90")
  root.option_add("*Font", "Helvetica -12")
예제 #8
0
    def __init__(self,
                 parent,
                 title='',
                 location='',
                 hide=False,
                 font=None,
                 modal=False,
                 transient=False,
                 quitFunc=None,
                 docKey=None,
                 tipText=None,
                 createToolTip=False,
                 *args,
                 **kw):

        self.parent = parent
        self.location = location
        self.isTransient = transient
        self.modal = modal

        if (not kw.has_key('bg') and not kw.has_key('background')):
            kw['bg'] = 'grey90'

        Tkinter.Toplevel.__init__(self, parent, *args, **kw)
        Base.__init__(self,
                      docKey=docKey,
                      tipText=tipText,
                      createToolTip=createToolTip)

        if modal:
            self.config(borderwidth=5, bg='red')

        if (not location):
            x = parent.winfo_rootx() + 50
            y = parent.winfo_rooty() + 50
            location = '+%d+%d' % (x, y)

        if hasattr(parent, 'top'):
            self.top = parent.top
        else:
            self.top = self

        if (parent and transient):
            self.transient(parent)

        self.var = Tkinter.StringVar()

        self.setTitle(title)

        #self.root = self._root()

        self.geometry(location)

        if hide:
            self.withdraw()

        self.protocol('WM_DELETE_WINDOW', self.close)

        #self.bind('<Escape>', self.close)

        self.grid_rowconfigure(0, weight=1)
        self.grid_columnconfigure(0, weight=1)
        frame = Frame(self)
        frame.grid(row=0, column=0, sticky=Tkinter.NSEW)

        if quitFunc:
            self.protocol('WM_DELETE_WINDOW', quitFunc)

        self.initial_focus = self.body(frame)
        if not self.initial_focus:
            self.initial_focus = self
        self.initial_focus.focus_set()

        #base_popups.append(self)

        self.help_popup = None

        if not hasattr(self, 'font'):
            if font is None:
                if hasattr(parent, 'font'):
                    font = parent.font

            self.font = font

        self.setFont()

        if modal:
            self.do_grab()
            self.wait_variable(self.var)

        if isWindowsOS():
            # Fix so that Windows popups aren't empty when opened
            self.update_idletasks()
            geometry = self.geometry()
            size = geometry.split('+')[0]
            x, y = size.split('x')
            x = str(int(x) + 1)
            self.geometry('%sx%s' % (x, y))
예제 #9
0
    def __init__(self, parent, scrollX=True, scrollY=True, *args, **kw):

        self.parent = parent
        self.scrollX = scrollX
        self.scrollY = scrollY

        self.prototypes = []
        self.nodes = []
        self.node = None  # Selected
        self.links = []
        self.link = None  # Selected
        self.objDict = {}  # Map canvas to nodes, links
        self.cornerDict = {}
        self.editWidget = None
        self.mouseOver = None
        self.inMotion = None
        self.inMotion2 = None
        self.inMotion3 = None
        self.dragRegion = None
        self._resizeBusy = False

        self.selectedNodes = []
        self.selectedLinks = []
        self.highlightNodes = []
        self.highlightLinks = []

        kw['relief'] = 'flat'
        kw['borderwidth'] = 0

        Frame.__init__(self, parent, *args, **kw)

        self.canvas = canvas = Canvas(self, relief='flat', borderwidth=0)
        self.canvas.configure(xscrollincrement=2,
                              yscrollincrement=2,
                              bg=self.cget('bg'))
        self.canvas.grid(row=0, column=0, sticky='nsew')

        if scrollX:
            self.horizScrollbar = Tkinter.Scrollbar(self,
                                                    bg=self.cget('bg'),
                                                    command=self.canvas.xview,
                                                    orient=Tkinter.HORIZONTAL,
                                                    borderwidth=1)
            self.canvas.configure(xscrollcommand=self.horizScrollbar.set)

        if scrollY:
            self.vertScrollbar = Tkinter.Scrollbar(self,
                                                   bg=self.cget('bg'),
                                                   command=self.canvas.yview,
                                                   orient=Tkinter.VERTICAL,
                                                   borderwidth=1)
            self.canvas.configure(yscrollcommand=self.vertScrollbar.set)

        canvas.bind('<Button-1>', self._mouseSingleClick)
        if not isWindowsOS():
            canvas.bind('<Button-4>', self.scrollUp)
            canvas.bind('<Button-5>', self.scrollDown)
        else:
            canvas.bind('<MouseWheel>', self._windowsOsScroll)

        canvas.bind('<Double-1>', self._mouseDoubleClick)
        canvas.bind('<B1-Motion>', self._mouseDrag)
        canvas.bind('<ButtonRelease-1>', self._mouseRelease)
        canvas.bind('<Motion>', self._mouseEnter)
        canvas.bind('<Enter>', self._mouseEnter)
        canvas.bind('<Leave>', self._mouseLeave)
        canvas.bind('<KeyPress-Up>', self._moveUp)
        canvas.bind('<KeyPress-Down>', self._moveDown)
        canvas.bind('<KeyPress-Right>', self._moveRight)
        canvas.bind('<KeyPress-Left>', self._moveLeft)
        canvas.bind('<KeyPress-Delete>', self.deleteSelected)
        self.bind('<Configure>', self._resizeAfter)

        self.menu = Menu(self, tearoff=False)

        alignItems = [{
            'kind': 'command',
            'label': 'Y axis',
            'command': self._alignHorizontal
        }, {
            'kind': 'command',
            'label': 'X axis',
            'command': self._alignVertical
        }]

        distributeItems = [{
            'kind': 'command',
            'label': 'Horizontal',
            'command': self._distributeHorizontal
        }, {
            'kind': 'command',
            'label': 'Verical',
            'command': self._distributeVertical
        }]

        menuItems = [
            {
                'kind': 'cascade',
                'label': 'Align',
                'submenu': alignItems
            },  #0
            {
                'kind': 'cascade',
                'label': 'Distribute',
                'submenu': distributeItems
            },  #1
            {
                'kind': 'command',
                'label': 'Link Selected',
                'command': self.linkSelected
            },  #2
            {
                'kind': 'command',
                'label': 'Reset Links',
                'command': self._resetLinks
            },  #3
            {
                'kind': 'separator'
            },
            {
                'kind': 'command',
                'label': 'Delete Links',  #5
                'command': self.deleteLinks
            },
            {
                'kind': 'command',
                'label': 'Delete Items',  #6
                'command': self.deleteNodes
            },
            {
                'kind': 'separator'
            },
            {
                'kind': 'command',
                'label': 'Save PostScript File',
                'command': self.printCanvas
            },
        ]

        self.menuItems = menuItems
        self.menu.setMenuItems(menuItems)

        canvas.bind('<ButtonPress-3>', self._popupMenu)

        self._drawAfter()
예제 #10
0
def saveProject(project, newPath = None, newProjectName = None, changeBackup = True,
                createFallback = False, removeExisting = False, showYesNo = None,
                checkValid = False):
  """
  Save the userData for a project to a location given by newPath (the url.path
  of the userData repository) if set, or the existing location if not. 
  If userData does not exist then throws IOError.
  If newPath is not specified then it is set to oldPath.
  If newProjectName is not specified then it is set to oldProjectName if
    newPath==oldPath, otherwise it is set to basename(newPath).
  If changeBackup, then also changes backup URL path for project.
  If createFallback, then makes copy of existing modified topObjects
    files (in newPath, not oldPath) before doing save.
  If newPath != oldPath and newPath exists (either as file or as directory):
    If removeExisting:
      Delete the newPath.
    Else if showYesNo:
      Ask the user if it is ok to delete the newPath
      If yes, delete.  If no, return without saving.
    Else:
      Raise an IOError
  Elif newProjectName != oldProjectName and there exists corresponding path (file/directory):
    If removeExisting:
      Delete the path.
    Else if showYesNo:
      Ask the user if it is ok to delete the path.
      If yes, delete.  If no, return without saving.
    Else:
      Raise an IOError
  if checkValid then does checkAllValid on project
  If there is no exception or early return then at end userData is pointing to newPath.
  Return True if save done, False if not (unless there is an exception)
  """

  # check project valid (so don't save an obviously invalid project)
  if checkValid:
    project.checkAllValid()

  # only want to change path for userData
  userData = project.findFirstRepository(name='userData')
  if not userData:
    raise IOError('Problem: userData not found')

  oldPath = userData.url.path
  oldProjectName = project.name

  if newPath:
    # normalise newPath
    newPath = normalisePath(newPath, makeAbsolute=True)
  else:
    newPath = oldPath

  # if newProjectName isn't specified then use default
  if not newProjectName:
    if newPath == oldPath:
      newProjectName = oldProjectName
    else:
      newProjectName = os.path.basename(newPath)

  # change project name
  if newProjectName != oldProjectName:
    project.override = True # TBD: for now name is frozen so change this way
    try:
      # below constraint is not checked in setName() if override is True so repeat here
      isValid = newProjectName.isalnum()  # superfluous but faster in most cases
      if not isValid:
        for cc in newProjectName:
          if cc != '_' and not cc.isalnum():
            isValid = False
            break
        else:
          isValid = True
      if (not (isValid)):
        raise ApiError('project name must only have characters that are alphanumeric or underscore')

      # below checks for length of name as well
      project.name = newProjectName
    finally:
      project.override = False

  # if newPath same as oldPath, check if newProjectName already exists if it's not same as oldProjectName
  if newPath == oldPath:
    if newProjectName != oldProjectName:
      location = xmlUtil.getTopObjectPath(project)
      if os.path.exists(location):
        answer = checkRemoveIfExists(location, removeExisting, showYesNo)
        if answer is None:
          project.__dict__['name'] = oldProjectName  # TBD: for now name is frozen so change this way
          return False
  else: # check instead if newPath already exists
    if os.path.exists(newPath):
      answer = checkRemoveIfExists(newPath, removeExisting, showYesNo)
      if answer is None:
        if newProjectName != oldProjectName:
          project.__dict__['name'] = oldProjectName  # TBD: for now name is frozen so change this way
        return False
      # TBD: should we be removing it?
      removePath(newPath)
    else:
      # NBNB 2008/04/03 Rasmus Fogh. Added because it otherwise fell over when
      # target path did not exist
      upDir = os.path.dirname(newPath)
      if not os.path.exists(upDir):
        os.makedirs(upDir)

    # check if any topObject activeRepository is not either of above
    refData = project.findFirstRepository(name='refData')
    genData = project.findFirstRepository(name='generalData')
    topObjects = []
    repositories = set()
    for topObject in project.topObjects:
      repository = topObject.findFirstActiveRepository()
      if repository and repository not in (userData, refData, genData):
        topObjects.append(topObject)
        repositories.add(repository)
    if topObjects:
      print 'Warning, topObjects %s, in repositories %s, being left in original locations' % (topObjects, repositories)

  try:
    oldUrl = userData.url
    if changeBackup:
      # change project backup url to point to new path
      backupRepository = project.findFirstRepository(name="backup")
      if backupRepository:
        oldBackupUrl = backupRepository.url
      else:
        changeBackup = False

    # copy userData files over
    if newPath != oldPath:
      # if os.path.exists(oldPath):  # only copy if this is a directory
      if os.path.isdir(oldPath):
        # just copy everything from oldPath to newPath
        shutil.copytree(oldPath, newPath)

        # but need to remove all implementation files
        implPath = joinPath(newPath, ImpConstants.modellingPackageName,
                            ImpConstants.implementationPackageName)
        #implPath = pathImplDirectory(newPath)
        removePath(implPath)

      # change userData url to point to new path
      userData.url = Implementation.Url(path=newPath)
      # above will set project.isModified = True

      if changeBackup:
        # change project backup repository url to point to new path
        backupRepository.url = Implementation.Url(path=newPath+'_backup')

    # change project name
    if newProjectName != oldProjectName:
      if not project.isModified: # if it isModified it will be saved below
        if createFallback:
          createTopObjectFallback(project)
        project.save()

    # create fallbacks
    if createFallback:
      for topObject in (project,)+tuple(project.topObjects):
        if not topObject.isDeleted and topObject.isModified:
          createTopObjectFallback(topObject)

    # save modifications
    project.saveModified()

    if not isWindowsOS():
      os.system('touch %s' % newPath)  # so that user can see which are most recent

    return True

  except:
    # saveModified failed so revert to old values
    if newProjectName != oldProjectName:
      project.__dict__['name'] = oldProjectName  # TBD: for now name is frozen so change this way

    if newPath != oldPath:
      userData.url = oldUrl
      if changeBackup:
        backupRepository.url = oldBackupUrl
      try:
        removePath(newPath)
      except:
        pass

    raise