Exemple #1
0
 def _createFunc(self,wrapperNames,wrappersToReturn,parent,token):
     wrapper = Wrapper(self.nameToElement[token])
     if parent is not None:
         assert parent.element.id in wrapper.element.parents
         wrapper.parent = parent
     if token in wrapperNames:
         wrappersToReturn[wrapperNames.index(token)] = wrapper
     return wrapper
Exemple #2
0
 def createWrapper(id):
     """Create a wrapper to be inserted in the browser. If the wrapper should contain all of its
     element's contents, create a BrowserWrapper, that will load the contents """
     element = levels.real[id]
     if id in cDict: # wrapper should contain only a part of its element's contents
         wrapper = Wrapper(element)
         wrapper.setContents([createWrapper(cid) for cid in cDict[id]])
         return wrapper
     elif element.isFile() or len(element.contents) == 0:
         return Wrapper(element)
     else:
         return bnodes.BrowserWrapper(element) # a wrapper that will load all its contents when needed
Exemple #3
0
 def createWrapper(id):
     """Create a wrapper to be inserted in the browser. If the wrapper should contain all of its
     element's contents, create a BrowserWrapper, that will load the contents """
     element = levels.real[id]
     if id in cDict:  # wrapper should contain only a part of its element's contents
         wrapper = Wrapper(element)
         wrapper.setContents([createWrapper(cid) for cid in cDict[id]])
         return wrapper
     elif element.isFile() or len(element.contents) == 0:
         return Wrapper(element)
     else:
         return bnodes.BrowserWrapper(
             element
         )  # a wrapper that will load all its contents when needed
Exemple #4
0
def _buildTree(wrappers, seqs, boundingSeq, toplevelIds):
    """Build a tree over the part of *wrappers* specified by *boundingSeq* (on over all wrappers if
    *boundingSeq* is None). *seqs* is the SequenceDict, *toplevelIds* are the elements that may be used at 
    the highest level.
    """
    # Root nodes are not necessarily added in correct order. Insert them indexed by the start point of their
    # sequence and at the end sort them by the start point.
    roots = {}
    
    while True:
        # Choose the longest sequence (bounded to boundingSeq and only from elements within toplevelIds)
        # The second restriction increases performance and avoids that we accidentally choose a child when
        # its parent has the same sequence (this happens only for single children).
        longestSeq, element = seqs.longest(toplevelIds,boundingSeq)
        if longestSeq is None:
            # All wrappers in *boundingSeq* are covered
            break
        boundedSeq = longestSeq.bounded(Sequence(0,len(wrappers)-1))
        if boundedSeq is None or len(boundedSeq) == 0:
            # Skip sequences that are completely out of range (this may happen due to preWrapper/postWrapper)
            seqs.remove(longestSeq)
            continue
        
        # Create a wrapper for the tree
        assert element.isContainer()
        wrapper = Wrapper(element)
        childContents = _buildTree(wrappers, seqs, boundedSeq, element.contents.ids)
        wrapper.setContents(childContents)
        findPositions(wrapper,wrapper.contents)
        
        # Add the wrapper to roots and remove the sequence from all sequences
        roots[boundedSeq.asTuple()] = wrapper
        seqs.remove(longestSeq)
    
    # Finally add elements that have not been covered by any container
    uncovered = []
    for i in boundingSeq.asRange() if boundingSeq is not None else range(len(wrappers)):
        if not any(startIndex <= i <= endIndex for (startIndex, endIndex), root in roots.items()):
            uncovered.append(i)
    for i in uncovered:
        roots[(i,i)] = wrappers[i]
        
    # Sort root nodes by start point
    return [roots[key] for key in sorted(roots.keys())]
Exemple #5
0
 def _buildWrappersFromUrls(self, urls):
     """Build wrappers for the given urls and if possible add containers.
     In other words: convert a flat playlist to a tree playlist.
     """
     files = [Wrapper(element) for element in self.level.collect(urls)]
     wrappers = treebuilder.buildTree(self.level, files)
     for i in range(len(wrappers)):
         while wrappers[i].getContentsCount() == 1:
             wrappers[i] = wrappers[i].contents[0]
     return wrappers
Exemple #6
0
 def insertUrlsAtOffset(self, offset, urls, updateBackend='always'):
     """Insert the given paths at the given offset."""
     wrappers = [Wrapper(element) for element in self.level.collect(urls)]
     file = self.root.fileAtOffset(offset, allowFileCount=True)
     if file is None:
         parent = self.root
         position = self.root.getContentsCount()
     else:
         parent = file.parent
         position = parent.index(file)
     self.insert(parent, position, wrappers, updateBackend)
Exemple #7
0
 def _createFunc(parent, token):
     """This is used as createFunc-argument for Level.createWrappers."""
     if token.startswith('EXT:'):
         url = urllib.parse.unquote(token[4:]) # remove "EXT:"
         url = urls.URL(url)
         try:
             element = self.level.collect(url)
         except OSError as e:
             raise ValueError(str(e))
     else:
         element = self.level.collect(int(token))
     return Wrapper(element, parent=parent)
Exemple #8
0
    def dropMimeData(self, mimeData, action, row, column, parentIndex):
        # Compute drop position
        parent = self.data(parentIndex, Qt.EditRole)
        if parent.isFile(): # Drop onto a file => drop behind it
            position = parent.parent.index(parent) + 1
            parent = parent.parent
        elif row == -1:
            # no specific position: insert at the beginning or end
            if self.dndTarget is not None and self.dndTarget.isExpanded(parentIndex):
                position = 0
            else: position = parent.getContentsCount()
        else: position = row
        
        # Handle internal moves separately
        if action == Qt.MoveAction and isinstance(self.dndSource, QtWidgets.QTreeView) \
                and isinstance(self.dndSource.model(), PlaylistModel) \
                and self.dndSource.model().backend == self.backend:
            return self.move(list(mimeData.wrappers()), parent, position)
 
        self.stack.beginMacro(self.tr("Drop elements"))
        
        # Create wrappers
        if mimeData.hasFormat(config.options.gui.mime):
            # Do not simply copy wrappers from other levels as they might be invalid on real level
            if hasattr(mimeData, 'level') and mimeData.level == self.level:
                wrappers = [wrapper.copy() for wrapper in mimeData.wrappers()]
            else:
                wrappers = [Wrapper(self.level.collect(wrapper.element.id))
                            for wrapper in mimeData.fileWrappers()]   
        else:
            urls = utils.files.collectAsList(mimeData.urls())
            wrappers = [Wrapper(element) for element in self.level.collect(urls)]
        
        if len(wrappers) == 0:
            return True
        
        if self.insert(parent, position, wrappers):
            self.stack.endMacro()
            return True
        else: return False # macro has been aborted
Exemple #9
0
 def move(self, wrappers, parent, position):
     """Move *wrappers* at *position* into *parent*. If the current song is moved, keep the player
     unchanged (contrary to removing and inserting the wrappers again).
     
     Return False if the move is not possible because *parent* or one of its ancestors is in *wrappers*
     and True otherwise.
     """
     # Abort if the drop target or one of its ancestors would be moved
     if any(p in wrappers for p in parent.getParents(includeSelf=True)):
         return False
     
     self.stack.beginMacro(self.tr("Move elements"))
     
     # First change the backend
     # We use a special command to really move songs within the backend (contrary to removing and
     # inserting them). This keeps the status of the current song intact even if it is moved.
     self.stack.push(PlaylistMoveInBackendCommand(self, wrappers, parent, position))
     
     # Remove wrappers.
     # This might change the insert position for several reasons:
     # - we might remove wrappers within parent and before the insert position,
     # - we might remove wrappers making a parent node empty,
     # - after any removal adjacent wrappers may be glued
     # While we could easily calculate a new position taking the first effect into account, this is
     # difficult for the other ones. Therefore we mark the insert position with a special wrapper.
     # We use the super()-methods when we don't want fancy stuff like glueing
     # We use _dontGlueAway to avoid the following problems: Assume the playlist contains the containers
     # A, B, A. If we now move B into one of the A-containers, both A-containers are glued. This might
     # delete our insert parent! Similarly nodes behind the before position might be glued with nodes
     # behind it.
     marker = Wrapper(wrappers[0].element)
     super().insert(parent, position, [marker])
     self._dontGlueAway = [parent, marker]
     self.removeWrappers(wrappers, updateBackend='never')
     position = parent.index(marker)
     super().removeMany([(parent, position, position)])
     self._dontGlueAway = None
     self.insert(parent, position, wrappers, updateBackend='never')
             
     self.stack.endMacro()
     return True
 def setElement(self, element):
     """Shortcut: Display the given element (inside a Wrapper)."""
     self.setNode(Wrapper(element))