Пример #1
0
 def exportThumbnail(self, report_path, thumbpath, name, node, size=None):
     self.thumbnailer = Thumbnailer()
     if self.thumbnailer.isThumbnailable(node):
         pixmap = self.thumbnailer.generate(node,
                                            iconSize=256,
                                            frames=10,
                                            blocking=True)
         self.thumbnailer.unregister()
         if pixmap:
             try:
                 exportPath = os.path.join(report_path,
                                           os.path.join(thumbpath, name))
                 array = QByteArray()
                 qfile = QBuffer(array)
                 qfile.open(QIODevice.ReadWrite)
                 pixmap.save(qfile, 'JPG')
                 qfile.seek(0)
                 with open(exportPath, 'wb') as f:
                     f.write(qfile.read(qfile.size()))
                 qfile.close()
                 return True
             except Exception as e:
                 qfile.close()
                 return False
         else:
             return False
Пример #2
0
 def generateThumbnail(self):
     self.thumbnailer = Thumbnailer()
     self.connect(self.thumbnailer, SIGNAL("ThumbnailUpdate"),
                  self.updateThumbnail)
     pixmap = self.thumbnailer.generate(self.node,
                                        iconSize=self.IconSize,
                                        frames=self.Frames)
     if pixmap:
         self.updateThumbnail(self.node, pixmap)
Пример #3
0
 def __init__(self, parent, request):
     QNetworkReply.__init__(self, parent)
     self.qbuffer = None
     self.connect(self, SIGNAL('abouteToClose()'), self.__close)
     self.byteArray = QByteArray()
     self.qbuffer = QBuffer(self.byteArray)
     self.node = vfs().getnode(str(request.url().path().toUtf8()))
     self.thumbnailer = Thumbnailer()
     self.connect(self.thumbnailer, SIGNAL("ThumbnailUpdate"),
                  self.updateThumbnail)
     self.setRequest(request)
     self.setOperation(QNetworkAccessManager.GetOperation)
     mime = "image/jpg"
     self.setHeader(QNetworkRequest.ContentTypeHeader, QVariant(mime))
     self.open()
     self.setUrl(request.url())
     self.connect(parent, SIGNAL("ready"), self.ready)
     self.ready()
Пример #4
0
 def __init__(self, selection):
   QAbstractItemModel.__init__(self)
   self._list = []
   self._rows = []
   self._current_row = 0
   self._row_selected = 0
   self._thumb = True
   self._visible_rows = 0
   self._visible_cols = 0
   self._recursive = False
   self._root = None
   self.selection = selection
   if self.selection != None:
     self.connect(self.selection, SIGNAL("selectionChanged"), self.updateSelected)
   self.setDefaultAttributes()
   self.connectSignals()
   self.thumbnailer = Thumbnailer()
   self.connect(self.thumbnailer, SIGNAL("ThumbnailUpdate"), self.thumbnailUpdate)
   self.headerorder = {0:0}
Пример #5
0
 def __init__(self, parent):
     QTreeWidget.__init__(self)
     self.treeItemMenu = ReportTreeItemMenu(self)
     self.treeNewItemMenu = ReportTreeNewItemMenu(self)
     self.header().hide()
     self.connect(parent, SIGNAL("newCategory"), self.newCategory)
     self.connect(parent, SIGNAL("newPage"), self.newPage)
     self.connect(self, SIGNAL("itemClicked(QTreeWidgetItem*, int)"),
                  self.clicked)
     self.thumbnailer = Thumbnailer()
     self.reportManager = ReportManager()
     self.__categoryItems = []
Пример #6
0
 def dumpsJSON(self):
     thead = []
     for head in self.thead:
         thead.append(head['title'])
     if NodeListFragment.HeaderAttributes:
         for attribute in NodeListFragment.HeaderAttributes:
             thead.append(attribute)
     buff = '{"title": "' + self.title + '",' + '"widget": "node_list", "thead":'
     buff += json.dumps(thead)
     buff += ', "view" : ' + str(self.view) + ', "data" : ['
     for node in self.nodes:
         try:
             rowjson = {}
             rowjson['widget'] = 'node'
             for head in self.thead:
                 cb = head['callback'](node)
                 if type(cb) == str:
                     cb = cb.decode('utf-8', 'replace').encode('utf-8')
                 rowjson[head['title']] = cb
                 if self.gui:  #Need qt gui for QPixmap or will crash in console
                     #print 'self as GUI !', QApplication.instance()
                     self.thumbnailer = Thumbnailer()
                     if self.thumbnailer.isThumbnailable(node):
                         rowjson[
                             "thumb"] = "dff-node-thumbnail://" + node.absolute(
                             ).decode('utf-8', 'replace').encode('utf-8')
                     self.thumbnailer.unregister()
             rowjson['row_details'] = {
                 'widget': 'node_attribute',
                 'data': self.attributesToMap(node.attributes())
             }
             buff += json.dumps(rowjson)
             buff += ","
         except UnicodeError as e:
             print "Can't dump node " + str(
                 node.absolute()) + " : " + str(e)
     buff += "]}"
     return buff
Пример #7
0
class NodeListFragment(ReportPageFragment):
    DefaultHeader = [
        {
            'title': 'name',
            'callback': lambda Node: Node.name()
        },
        {
            'title': 'size',
            'callback': lambda Node: Node.size()
        },
        {
            'title': 'tags',
            'callback': lambda Node: getTags(Node)
        },
    ]
    ListView = 0
    GalleryView = 1
    DetailedAttributes = None
    HeaderAttributes = None
    HeaderAttributesName = None

    def __init__(self, title, nodes, thead, view):
        ReportPageFragment.__init__(self, title)
        self.nodes = nodes
        self.thead = thead
        self.view = view
        self.extract = Extract()
        self.filepath = None
        self.thumbpath = None
        if QApplication.instance():
            self.gui = True
        else:
            self.gui = False
        #XXX header don't support '.' in name
    def addNode(self, node):
        self.nodes.append(node)

    def elements(self):
        return self.nodes

    def dumpsJSON(self):
        thead = []
        for head in self.thead:
            thead.append(head['title'])
        if NodeListFragment.HeaderAttributes:
            for attribute in NodeListFragment.HeaderAttributes:
                thead.append(attribute)
        buff = '{"title": "' + self.title + '",' + '"widget": "node_list", "thead":'
        buff += json.dumps(thead)
        buff += ', "view" : ' + str(self.view) + ', "data" : ['
        for node in self.nodes:
            try:
                rowjson = {}
                rowjson['widget'] = 'node'
                for head in self.thead:
                    cb = head['callback'](node)
                    if type(cb) == str:
                        cb = cb.decode('utf-8', 'replace').encode('utf-8')
                    rowjson[head['title']] = cb
                    if self.gui:  #Need qt gui for QPixmap or will crash in console
                        #print 'self as GUI !', QApplication.instance()
                        self.thumbnailer = Thumbnailer()
                        if self.thumbnailer.isThumbnailable(node):
                            rowjson[
                                "thumb"] = "dff-node-thumbnail://" + node.absolute(
                                ).decode('utf-8', 'replace').encode('utf-8')
                        self.thumbnailer.unregister()
                rowjson['row_details'] = {
                    'widget': 'node_attribute',
                    'data': self.attributesToMap(node.attributes())
                }
                buff += json.dumps(rowjson)
                buff += ","
            except UnicodeError as e:
                print "Can't dump node " + str(
                    node.absolute()) + " : " + str(e)
        buff += "]}"
        return buff

    def writeSize(self, exportContent):
        size = 0
        if exportContent:
            for node in self.nodes:
                size += node.size()
        return size

    def writeJSON__(self, fd, page_path, report_path, exportContent=True):
        self.filepath = page_path + "/" + 'files'
        self.thumbpath = page_path + "/" + 'thumbs'
        buff = '{"title": "' + self.title + '",' + '"widget": "node_list", "thead":'
        fd.write(buff)
        thead = []
        for head in self.thead:
            thead.append(head['title'])
        #XXX header don't support '.' in name
        if NodeListFragment.HeaderAttributesName:
            for name in NodeListFragment.HeaderAttributesName:
                thead.append(name)
        json.dump(thead, fd)
        bdata = ', "view" : ' + str(self.view) + ', "data" : ['
        fd.write(bdata)
        self.notifyWrite(ReportPageFragment.EventWriteElements,
                         len(self.nodes))
        for node in self.nodes:
            self.notifyWrite(ReportPageFragment.EventWriteElementStart,
                             node.absolute())
            try:
                filename = None
                if exportContent:
                    filename = self.exportNode(node, self.filepath,
                                               report_path)
                self.nodeToJSON(node, filename, fd, report_path, page_path,
                                True)
                fd.write(',\n')
            except Exception as e:
                print "Can't write node " + str(
                    node.absolute()) + " : " + str(e)
            self.notifyWrite(ReportPageFragment.EventWriteElementFinish,
                             node.absolute())
        fd.write("]}")

    def attributesToMap(self, attributes):
        attributesMap = {}
        for key, variantMap in attributes.iteritems():
            vmap = self.recurseVariant(variantMap, {}, '')
            if len(vmap):
                attributesMap[key] = vmap
        attributesMap = OrderedDict(
            sorted(attributesMap.items(), key=lambda t: t[0]))
        return attributesMap

    def recurseVariant(self, variant, varMap, keyPath):
        if isinstance(variant, VMap):
            for key, vvar in variant.iteritems():
                if len(keyPath):
                    self.recurseVariant(vvar, varMap, keyPath + '.' + str(key))
                else:
                    self.recurseVariant(vvar, varMap, str(key))
        if isinstance(variant, VList):
            l = []
            for i in range(len(variant)):
                self.recurseVariant(variant[i], varMap,
                                    keyPath + ' (' + str(i) + ')')
        if isinstance(variant, Variant) or isinstance(variant, RCVariant):
            val = variant.value()
            if isinstance(val, VMap) or isinstance(val, VList):
                self.recurseVariant(val, varMap, keyPath)
            else:
                if isinstance(val, DateTime):
                    try:
                        val = str(val)
                    except:
                        val = "Invalid"
                if type(val) == str:
                    val = val.decode('utf-8', 'replace').encode('utf-8')
                translated = False
                if NodeListFragment.DetailedAttributes:
                    for (
                            finalName, attributeName
                    ) in NodeListFragment.DetailedAttributes:  #HeaderAttributes depend of this because it's attribute filled in the table will use the result of this function called by attributesMap if there is no detailed attributes there will no translation and the header can't be filled
                        if keyPath == attributeName:
                            varMap[finalName] = val
                if not translated:
                    varMap[keyPath] = val
        varMap = OrderedDict(sorted(varMap.items(), key=lambda t: t[0]))
        return varMap

    def findInAttributesMap(self, attribute, attributesMap):
        for module in attributesMap:
            moduleAttributes = attributesMap.get(module)
            if moduleAttributes:
                result = moduleAttributes.get(attribute)
                if result:
                    return result
        return ""

    def nodeToJSON(self,
                   node,
                   filename,
                   fd,
                   report_path,
                   page_path,
                   thumb=False):
        rowjson = {}
        rowjson['widget'] = 'node'
        attrMap = self.attributesToMap(node.attributes())
        for head in self.thead:
            cb = head['callback'](node)
            if type(cb) == str:
                cb = cb.decode('utf-8', 'replace').encode('utf-8')
            rowjson[head['title']] = cb
        if NodeListFragment.HeaderAttributes:
            for (name, attribute) in NodeListFragment.HeaderAttributes:
                result = self.findInAttributesMap(name, attrMap)
                rowjson[name] = result
        if filename:
            rowjson["file"] = self.filepath + "/" + filename
            if thumb and self.gui:
                if self.exportThumbnail(report_path, self.thumbpath,
                                        filename + '.jpg', node):
                    rowjson["thumb"] = self.thumbpath + "/" + filename + '.jpg'
        rowjson['row_details'] = {'widget': 'node_attribute', 'data': attrMap}
        try:
            json.dump(rowjson, fd)
        except UnicodeError as e:
            print 'report.fragment.nodeToJSON failed ' + str(e)
            print rowjson

    def exportThumbnail(self, report_path, thumbpath, name, node, size=None):
        self.thumbnailer = Thumbnailer()
        if self.thumbnailer.isThumbnailable(node):
            pixmap = self.thumbnailer.generate(node,
                                               iconSize=256,
                                               frames=10,
                                               blocking=True)
            self.thumbnailer.unregister()
            if pixmap:
                try:
                    exportPath = os.path.join(report_path,
                                              os.path.join(thumbpath, name))
                    array = QByteArray()
                    qfile = QBuffer(array)
                    qfile.open(QIODevice.ReadWrite)
                    pixmap.save(qfile, 'JPG')
                    qfile.seek(0)
                    with open(exportPath, 'wb') as f:
                        f.write(qfile.read(qfile.size()))
                    qfile.close()
                    return True
                except Exception as e:
                    qfile.close()
                    return False
            else:
                return False

    def exportNode(self, node, path, report_path):
        abspath = os.path.join(report_path, path)
        try:
            local_path = self.extract.extractFile(node, abspath)
        except Exception as e:
            pass

        if local_path:
            return os.path.basename(local_path)
        else:
            return None
Пример #8
0
class NodeThumbnailRenderReply(QNetworkReply):
    def __init__(self, parent, request):
        QNetworkReply.__init__(self, parent)
        self.qbuffer = None
        self.connect(self, SIGNAL('abouteToClose()'), self.__close)
        self.byteArray = QByteArray()
        self.qbuffer = QBuffer(self.byteArray)
        self.node = vfs().getnode(str(request.url().path().toUtf8()))
        self.thumbnailer = Thumbnailer()
        self.connect(self.thumbnailer, SIGNAL("ThumbnailUpdate"),
                     self.updateThumbnail)
        self.setRequest(request)
        self.setOperation(QNetworkAccessManager.GetOperation)
        mime = "image/jpg"
        self.setHeader(QNetworkRequest.ContentTypeHeader, QVariant(mime))
        self.open()
        self.setUrl(request.url())
        self.connect(parent, SIGNAL("ready"), self.ready)
        self.ready()

    def ready(self):
        if self.node.dataType().find('video') != -1:
            pixmap = self.thumbnailer.generate(self.node,
                                               iconSize=128,
                                               frames=10)
        else:
            pixmap = self.thumbnailer.generate(self.node,
                                               iconSize=256,
                                               frames=10)
        if pixmap:
            self.updateThumbnail(self.node, pixmap)

    def updateThumbnail(self, node, pixmap):
        if pixmap == None:
            pixmap = QPixmap(":file_broken.png")
        pixmap.save(self.qbuffer, 'JPG')
        self.qbuffer.seek(0)
        QTimer.singleShot(0, self, SIGNAL("readyRead()"))
        QTimer.singleShot(0, self, SIGNAL("finished()"))

    def abort(self):
        self.close()

    def __del__(self):
        self.thumbnailer.unregister()

    def open(self, mode=None):
        try:
            self.qbuffer.open(QIODevice.ReadWrite | QIODevice.Unbuffered)
            self.setOpenMode(QIODevice.ReadWrite | QIODevice.Unbuffered)
            return True
        except (AttributeError, IOError):
            return False

    def seek(self, pos):
        if self.qbuffer:
            return self.qbuffer.seek(pos)
        return False

    def __close(self):
        if self.qbuffer:
            self.qbuffer.close()
            self.qbuffer = None
        return True

    def readData(self, size):
        if self.qbuffer:
            return self.qbuffer.read(size)
        return ""

    def pos(self):
        if self.qbuffer:
            return self.qbuffer.pos()
        return 0

    def isSequential(self):
        if self.qbuffer:
            return self.qbuffer.isSequential()
        return False

    def size(self):
        return self.qbuffer.size()

    def reset(self):
        if self.qbuffer:
            self.qbuffer.seek(0)
            return True
        return False

    def atEnd(self):
        if self.qbuffer:
            return self.qbuffer.atEnd()
        return False
Пример #9
0
class ThumbnailVideoView(QWidget, Script):
    IconSize = 256
    Frames = 10

    def __init__(self):
        Script.__init__(self, "thumbnailvideo")
        self.icon = None
        self.vfs = vfs.vfs()

    def start(self, args):
        try:
            self.preview = args["preview"].value()
        except IndexError:
            self.preview = False
        try:
            self.node = args["file"].value()
        except KeyError:
            pass

    def g_display(self):
        QWidget.__init__(self)
        self.copyMenu = CopyMenu(self)
        self.copySelectionMenu = CopySelectionMenu(self)
        self.rubberBand = None
        self.hlayout = QVBoxLayout()
        self.setLayout(self.hlayout)

        self.menuLayout = QHBoxLayout()
        self.hlayout.addLayout(self.menuLayout)

        self.frameLayout = QFormLayout()
        self.menuLayout.addLayout(self.frameLayout)
        self.frameNumberEdit = QLineEdit(str(self.Frames))
        self.frameNumberEdit.setFixedWidth(40)
        self.frameNumberEdit.setValidator(QIntValidator(0, 256))
        self.frameLayout.addRow("Number of frame: ", self.frameNumberEdit)
        self.connect(self.frameNumberEdit, SIGNAL("textChanged(QString)"),
                     self.setFrameNumber)

        self.iconLayout = QFormLayout()
        self.menuLayout.addLayout(self.iconLayout)
        self.iconSizeEdit = QLineEdit(str(self.IconSize))
        self.iconSizeEdit.setFixedWidth(40)
        self.iconSizeEdit.setValidator(QIntValidator(0, 512))
        self.iconLayout.addRow("Size: ", self.iconSizeEdit)
        self.connect(self.iconSizeEdit, SIGNAL("textChanged(QString)"),
                     self.setIconSize)

        self.refreshButton = QPushButton("Refresh")
        self.menuLayout.addWidget(self.refreshButton)
        self.connect(self.refreshButton, SIGNAL("clicked()"),
                     self.generateThumbnail)

        self.scrollArea = QScrollArea()
        self.hlayout.addWidget(self.scrollArea)

        self.generateThumbnail()

    def mousePressEvent(self, event):
        self.dragPosition = event.pos()
        if not self.rubberBand:
            self.rubberBand = QRubberBand(QRubberBand.Rectangle, self)
        self.rubberBand.setGeometry(QRect(self.dragPosition, QSize()))
        self.rubberBand.show()

    def mouseMoveEvent(self, event):
        self.rubberBand.setGeometry(
            QRect(self.dragPosition, event.pos()).normalized())

    def mouseReleaseEvent(self, event):
        if not self.rubberBand.size().isEmpty():
            rect = QRect(self.rubberBand.pos(), self.rubberBand.size())
            rect.moveLeft(rect.left() -
                          (self.width() - self.thumbLabel.pixmap().width()) /
                          2.0)
            rect.moveTop(rect.top() -
                         (self.height() - self.thumbLabel.pixmap().height()) /
                         2.0)
            self.currentSelection = rect
            self.copySelectionMenu.popup(QCursor.pos())
        else:
            self.copyMenu.popup(QCursor.pos())
        self.rubberBand.hide()

    def copySelectionToClipboard(self):
        QApplication.clipboard().setPixmap(self.thumbLabel.pixmap().copy(
            self.currentSelection))

    def copyPixmapToClipboard(self):
        QApplication.clipboard().setPixmap(self.thumbLabel.pixmap())

    def setIconSize(self, size):
        ThumbnailVideoView.IconSize = int(size)

    def setFrameNumber(self, number):
        ThumbnailVideoView.Frames = int(number)

    def generateThumbnail(self):
        self.thumbnailer = Thumbnailer()
        self.connect(self.thumbnailer, SIGNAL("ThumbnailUpdate"),
                     self.updateThumbnail)
        pixmap = self.thumbnailer.generate(self.node,
                                           iconSize=self.IconSize,
                                           frames=self.Frames)
        if pixmap:
            self.updateThumbnail(self.node, pixmap)

    def updateThumbnail(self, node, pixmap):
        if pixmap:
            self.thumbLabel = QLabel()
            self.thumbLabel.setSizePolicy(QSizePolicy.Expanding,
                                          QSizePolicy.Expanding)
            self.thumbLabel.setWordWrap(True)
            self.thumbLabel.setPixmap(pixmap)
            self.scrollArea.setWidget(self.thumbLabel)
        else:
            self.thumbLabel.setText("Can't render, video is corrupted.")
            self.thumbLabel.setAlignment(Qt.AlignCenter)
        self.thumbnailer.unregister()

    def updateWidget(self):
        pass
Пример #10
0
class NodeListModel(QAbstractItemModel):
  def __init__(self, selection):
    QAbstractItemModel.__init__(self)
    self._list = []
    self._rows = []
    self._current_row = 0
    self._row_selected = 0
    self._thumb = True
    self._visible_rows = 0
    self._visible_cols = 0
    self._recursive = False
    self._root = None
    self.selection = selection
    if self.selection != None:
      self.connect(self.selection, SIGNAL("selectionChanged"), self.updateSelected)
    self.setDefaultAttributes()
    self.connectSignals()
    self.thumbnailer = Thumbnailer()
    self.connect(self.thumbnailer, SIGNAL("ThumbnailUpdate"), self.thumbnailUpdate)
    self.headerorder = {0:0}

  def thumbnailUpdate(self, node, pixmap):
     currentRow = self.currentRow()
     visibleRow = self.visibleRows()
     nodeList = self.list()
     currentList = nodeList[currentRow:currentRow + visibleRow]
     index = 0
     for cnode in currentList:
         if node.uid() == cnode.uid():
	   modelIndex = self.index(index, 0)
           self.emit(SIGNAL("dataChanged"), modelIndex, modelIndex)
         index += 1

  def _removeNode(self, node):
    children = node.children()
    for child in children:
      self._removeNode(child)
    for n in self._list:
      if n.uid() == node.uid():
        self._list.remove(n)
        self._row_selected = 0 
    for n in self._rows:
      if n.uid() == node.uid():
        self._rows.remove(n)      

  def removeNode(self, node): 
    try:
     if self._root == None or (self._root.path().find(node.parent().path()) != -1):
      self._row_selected = 0 
      self.changeList(node.parent(), self._recursive, None)
    except Exception as e :
      pass
    self._removeNode(node)

  def vfsNotification(self, node, eventType = None):
    if eventType == 0xde1:
      pass #called by noedelistwidget
    else:
      if node.parent().uid() == self._root.uid():
        self.changeList(self._root, self._recursive, self._list[self._row_selected])

  def updateSelected(self, count):
    self.emit(SIGNAL("layoutChanged()"))

  def connectSignals(self):
    self.connect(self, SIGNAL("appendList"), self.appendList)

  def setData(self, index, value, role):
    """
    \reimp

    Set the data which value is `value` at index `index` with role `role`.

    \return `True` if no error occured, `False` otherwise.
    """
    if not index.isValid():
      return QVariant()
    column = index.column()
    if role == Qt.CheckStateRole:
      if column == HNAME:
        node = self.VFS.getNodeById(index.internalId())
        if node == None:
          pass
        if value == Qt.Unchecked:
          if (node.uid(), 1) in self.checkedNodes:
            self.checkedNodes.remove((node.uid(), 1))
        else:
          self.checkedNodes.add((node.uid() , 1))
    QAbstractItemModel.setData(self, index, value, role)
    return True

  def changeList(self, root, recursive=False, selected=None):
    """ 
    Change the current list based on root children.
    If recursive is True, the list will be based on the recursion
    If selected is provided it will automatically be the current row
    """
    if root != None:
      self._root = root
      self._recursive = recursive
      self._list = []
      self.row_selected = 0
      self._current_row = 0
      if recursive:
        self._fillRecursiveList(root.children())
      else:
        self._list = root.children()
      self.sort(self.headerorder.keys()[0], self.headerorder[self.headerorder.keys()[0]])
      idx = 0
      if not recursive and selected != None:
        for i in xrange(0, len(self._list)):
          if selected.uid() == self._list[i].uid():
            idx = i
            break
      self.emit(SIGNAL("maximum"), len(self._list))
      if idx > self._current_row + self._visible_rows:
        self._current_row = idx
        self.select(0)
      else:
        self.select(idx)
      self.emit(SIGNAL("changeList"))

  def currentRoot(self):
    return self._root

  def recursive(self):
    return self._recursive

  def updateList(self, nodes, recursive=False, selected=None):
    """ 
    Update list from an existing one.
    Useful when switching from filtered view
    """
    if len(nodes):
      self._recursive = recursive
      self._list = nodes
      if not recursive and selected != None:
        for i in xrange(0, len(self._list)):
          if selected.uid() == self._list[i].uid():
            self._current_row = i
            self.row_selected = i
            break
      self.emit(SIGNAL("maximum"), len(self._list))
      self.select(0)
      self.emit(SIGNAL("changeList"))

  def _fillRecursiveList(self, nodes):
    for node in nodes:
      self._list.append(node)
      if node.hasChildren():
        self._fillRecursiveList(node.children())

  def appendList(self, node):
    """
    Append a new node to the existing model's list and emit an appended signal with the new size.
    """
    if node != None:
      try:
        self._list.append(node)
        self.emit(SIGNAL("nodeAppended"))
        self.emit(SIGNAL("maximum"), len(self._list))
        self.refresh(self._current_row)
      except:
        print "Error while appending node"
        return

  def defaultAttributes(self):
    return self._default_attributes

  def clearList(self):
    self.emit(SIGNAL("clearList"))
    self._recursive = False
    self._list = []
    self._current_row = 0
    self.refresh(self._current_row)

  def columnCount(self, index):
    attrs = self.availableAttributes()
    return len(attrs)

  def data(self, index, role):
    attributes = self.availableAttributes()
    if not index.isValid():
      return QVariant()
    if index.row() > len(self._list) or index.row() < 0:
      return QVariant()
    try:
      node = self._rows[index.row()]
    except:
      return QVariant()
    if role == Qt.DisplayRole :
      attrpath = str(unicode(attributes[index.column()]).encode('utf-8'))
      if attrpath == "name":
          return QVariant(QString.fromUtf8(node.name()))
      elif attrpath == "size":
          return QVariant(node.size())
      elif attrpath == "extension":
          return QVariant(QString.fromUtf8(node.extension()))
      elif attrpath == "path":
          if isinstance(node, VLink):
            return QVariant(QString.fromUtf8(node.linkPath()))
          else:
            return QVariant(QString.fromUtf8(node.path()))
      elif attrpath == "absolute":
          if isinstance(node, VLink):
            return QVariant(QString.fromUtf8(node.linkAbsolute()))
          else:
           return QVariant(QString.fromUtf8(node.absolute()))
      elif attrpath == "module":
	  if node.fsobj():
            return QVariant(QString.fromUtf8(node.fsobj().name))
          return QVariant()
      elif attrpath == "has children":
          if isinstance(node, VLink):
            return QVariant(node.linkHasChildren())
          else:
            return QVariant(node.hasChildren())
      elif attrpath == "child count":
          if isinstance(node, VLink):
            return QVariant(node.linkChildCount())
          else:
            return QVariant(node.childCount())
      elif attrpath == "is deleted":
          return QVariant(node.isDeleted())
      elif attrpath == "tags":
          #Special case tag use a delegate to draw boxes
          return QVariant()
      else:
	try :
          val = node.attributesByName(attrpath, ABSOLUTE_ATTR_NAME)
	except Exception as e:
	   print "NodeListModel data can't get attribute " + attrpath + " by name " + str(e)
	   return QVariant()
        if len(val) == 1:
          if val[0].type() == typeId.DateTime:
            dateTime = val[0].value()
            if dateTime:
              try:
                return QVariant(str(dateTime))
              except:
                return QVariant()
          elif val[0].type() == typeId.String:
            return QVariant(QString.fromUtf8(val[0].value()))
          else:
            return QVariant(val[0].value())
        else:
          return QVariant()
    if role == Qt.ToolTipRole :
      return QVariant(QString.fromUtf8(node.name()))

    # Display icons
    if (role == Qt.DecorationRole) and (attributes[index.column()] == "name"):
      pixmap = None
      if self._thumb:
	if self.thumbnailer.isThumbnailable(node):
	  pixmap = self.thumbnailer.generate(node)
          if pixmap is None:
	    pixmap = QPixmap(":file_temporary.png")
      if not pixmap:
        pixmap = self.getIconPixmap(node)
        if not pixmap:
          pixmap = QPixmap(node.icon())
        
        if isinstance(node, VLink):
          pixmap = pixmap.scaled(QSize(128, 128), Qt.KeepAspectRatio)
          painter = QPainter(pixmap)
          linkPixmap = QPixmap(":vlink") 
          painter.drawPixmap(0, 0, linkPixmap)
          painter.end()

	elif node.hasChildren():
          try:
            pfsobj = node.children()[0].fsobj().this
          except AttributeError:
  	    pfsobj = None
          try:
            nfsobj = node.fsobj().this
          except AttributeError:
	    nfsobj = None
          if pfsobj != nfsobj:
            pixmap = pixmap.scaled(QSize(128, 128), Qt.KeepAspectRatio)
            painter = QPainter(pixmap)
            rootPixmap = QPixmap(":root")
            painter.drawPixmap(0, 0, rootPixmap)
            painter.end()
      return QVariant(QIcon(pixmap))
	
    if role == Qt.BackgroundRole:
      if index.row() == self.activeSelection():
        palette = QPalette().color(QPalette.Highlight)
        return QVariant(QColor(palette))
    if role == Qt.ForegroundRole:
      if index.row() == self.activeSelection():
        palette = QPalette().color(QPalette.HighlightedText)
        return QVariant(QColor(palette))
      if node.isDeleted():
        return  QVariant(QColor(Qt.red))

    if (role == Qt.CheckStateRole) and (attributes[index.column()] == "name"):
      if node.uid() in self.selection.get():
        return Qt.Checked
      else:
        return Qt.Unchecked
    return QVariant()

  def setThumb(self, state):
    self._thumb = state

  def getIconPixmap(self, node):
    ext = self.getExtension(node)
    if ext != None:
      if ext in IMAGES:
        return QPixmap(":image.png")
      elif ext in AUDIO:
        return QPixmap(":sound.png")
      elif ext == "pdf":
        return QPixmap(":pdf.png")
      elif ext in DOCUMENT:
        return QPixmap(":document.png")
      elif ext in VIDEO:
        return QPixmap(":video.png")
      elif ext in ARCHIVES:
        return QPixmap(":zip")
      elif ext in SPREADSHEET:
        return QPixmap(":spreadsheet.png")
      else:
        return None

  def getExtension(self, node):
    name = node.name()
    sext = name.split(".")
    if len(sext) > 1:
      return sext[len(sext) - 1]
    else:
      return None

  def getNode(self, row):
    try:
      node = self._list[row]
      if node:
        return node
      else:
        return None
    except IndexError:
      return None

  def index(self, row, column, parent = QModelIndex()):
    if not self.hasIndex(row, column, parent):
     return QModelIndex()
    if not parent.isValid():
      index = self.createIndex(row, column, self._rows[row])
      return index
    return QModelIndex()

  def parent(self, index):
    return QModelIndex()

  def refresh(self, start):
    llist = len(self._list)
    if start < 0:
      rstart = 0
    elif (start >= llist):
      # End of list
      rstart = llist - (self._visible_rows)
      if rstart < 0:
        rstart = 0
    # elif ((llist - start) <= self._visible_rows + 1):
    #   rstart = self._current_row
    #   if rstart < 0:
    #     rstart = 0
    else:
      rstart = start

    # End of List range
    if (rstart + self._visible_rows) > len(self._list):
      end = len(self._list)
    else:
      end = rstart + self._visible_rows + 1
    self.resetDisplay()
    try:
      tmplist = self._list[rstart:end]
    except IndexError:
      return
    try:
      for nodeId in range(0, len(tmplist)):
        if tmplist[nodeId] != None:
          self._rows.append(tmplist[nodeId])
      self.emit(SIGNAL("layoutAboutToBeChanged()"))
      self.emit(SIGNAL("layoutChanged()"))

      if self._current_row >= 0:
        self._current_row = rstart
      else:
        self._current_row = 0
      self.emit(SIGNAL("current"), self._current_row)
    except IndexError:
      print "Error while refreshing model"
      pass

  def resetDisplay(self):
    if len(self._rows) > 0:
      self._rows = []
      self.emit(SIGNAL("layoutAboutToBeChanged()"))
      self.emit(SIGNAL("layoutChanged()"))

  def rowCount(self, parent = None):
    return len(self._rows)

  def currentRow(self):
    return self._current_row

  def size(self):
    return len(self._list)

  def setVisibleRows(self, rows):
    self._visible_rows = rows + 1
    self.emit(SIGNAL("maximum"), len(self._list))
    if self._visible_rows > self.size():
      self.emit(SIGNAL("hideScroll"))
    self.refresh(self._current_row)

  def visibleRows(self):
    return self._visible_rows

  def seek(self, position, where = 0):
    if where == 0:
      self.refresh(position)
    elif where == 1:
      pos = self._current_row + position
      self.refresh(pos)
    else:
      self.refresh(self._current_row)

  def select(self, row):
    """
    Set absolute selected row id in model's list
    """
    absrow = self._current_row + row
    try:
      node = self._list[absrow]
      self._row_selected = absrow
      self.refresh(self._current_row)
      self.emit(SIGNAL("nodeListClicked"), Qt.NoButton)
      return True
    except:
      return False

  def activeSelection(self):
    """
    Return relative selected row id
    """
    return self._row_selected - self._current_row

  def currentNode(self):
    try:
      node = self._list[self._row_selected]
      return node 
    except:
      return None

  def nodeSelected(self):
    nodes = []
    nodes.append(self._list[self._row_selected])
    return nodes

  def setDefaultAttributes(self):
    self._default_attributes = ["name", "size","tags", "path", "extension", "absolute", "module", "has children", "child count", "is deleted"]
    self.setSelectedAttributes(["name", "size", "tags", "path"])

  def setSelectedAttributes(self, attributes):
    self._selected_attributes = attributes
    self.refresh(self._current_row)

  def selectedAttributes(self):
    return self._selected_attributes

  def availableAttributes(self):
    attrs = self.selectedAttributes()[:]
    return attrs

  def setHeaderData(self, section, orientation, value, role):
    self.emit(SIGNAL("layoutAboutToBeChanged()"))
    QAbstractItemModel.setHeaderData(self, section, orientation, value, role)
    self.emit(SIGNAL("layoutChanged()"))

  def headerData(self, section, orientation, role=Qt.DisplayRole):
    if role != Qt.DisplayRole:
      return QVariant()
    if orientation == Qt.Horizontal:
      attrs = self.availableAttributes()
      return QVariant(attrs[section])

  def sort(self, column, order):
    """
    Sort model's list and check.
    """
    self.headerorder.clear()
    self.headerorder[column] = order
    QApplication.setOverrideCursor(QCursor(Qt.WaitCursor))
    if order == Qt.DescendingOrder:
      Reverse = True
    else:
      Reverse = False
    attrs = self.availableAttributes()
    try:
      attrpath = str(unicode(attrs[column]).encode('utf-8'))
    except IndexError:
      QApplication.restoreOverrideCursor()
      self.headerorder.clear()
      self.headerorder = {0:0}
      self.refresh(0)
      self.select(0)
      return

    if isinstance(self._list, VecNode):
      tmplist = []
      for i in range(0, len(self._list)):
        tmplist.append(self._list[i])
      self._list = tmplist
    if attrpath in self._default_attributes:
      if attrpath == "name":
        self._list = sorted(self._list, cmp=locale.strcoll,
                           key=lambda Node: Node.name(), 
                           reverse=Reverse)
      elif attrpath == "size":
        self._list = sorted(self._list,
                           key=lambda Node: Node.size(),
                           reverse=Reverse)
      elif attrpath == "extension":
        self._list = sorted(self._list, cmp=locale.strcoll,
                           key=lambda Node: Node.extension(),
                           reverse=Reverse)
      elif attrpath == "path":
        self._list = sorted(self._list, cmp=locale.strcoll,
                           key=lambda Node: Node.path(),
                           reverse=Reverse)
      elif attrpath == "absolute":
 	self._list = sorted(self._list, cmp=locale.strcoll,
			     key=lambda Node: Node.absolute(),
			     reverse=Reverse)
      elif attrpath == "module":
	self._list = sorted(self._list, cmp=self.cmp_fsobj, 
			    key=lambda Node: Node.fsobj(),
			    reverse=Reverse)
      elif attrpath == "has children":
	self._list = sorted(self._list, key=lambda Node: Node.hasChildren(), reverse=Reverse)
      elif attrpath == "child count":
	self._list = sorted(self._list, key=lambda Node: Node.childCount(), reverse=Reverse)
      elif attrpath == "is deleted": 
	self._list = sorted(self._list, key=lambda Node: Node.isDeleted(), reverse=Reverse)
      elif attrpath == "tags":
        self._list = sorted(self._list,
                             key=lambda Node: len(Node.tags()),
                             reverse=Reverse)
    else:
        self._list = sorted(self._list,
                             cmp=self.cmp_none, key=lambda Node: self.attributesByName(Node, attrpath, ABSOLUTE_ATTR_NAME),
                             reverse=Reverse)
    QApplication.restoreOverrideCursor()
    self.refresh(0)
    self.select(0)
    return

  def cmp_fsobj(self, x, y):
     try:
	return cmp(x.name, y.name)
     except AttributeError:
        if x == y == None:
	  return 0
        elif x == None:
	  return -1
	elif y is None:
	  return 1

  def cmp_none(self,x, y):
     try:
	return cmp(x, y)
     except TypeError: 
	if x == None and y == None:
	  return 0
        elif x == None:
	  return -1
	elif y is None:
	  return 1
     except  ValueError:
       if x is None and y is None:
        return 0
       elif x is None:
         return -1
       elif y is None:
         return 1  

  def attributesByName(self, node, attrpath, ABSOLUTE_ATTR_NAME):
      val = node.attributesByName(attrpath, ABSOLUTE_ATTR_NAME)
      if len(val) == 1:
        if val[0].type() == typeId.DateTime:
          return DateTime(val[0].value()) #must copy because or set variant this own to false because rc_variant store DateTime*  that is deleted at function return
        else:
          val = val[0].value()
          return val

  def list(self):
    return self._list

  def allListChecked(self):
    checked = self.selection.get()
    for node in self._list:
      if not node.uid() in checked:
        return False
    return True

  def selectAll(self):
    for node in self._list:
      self.selection.add(node)

  def unselectAll(self):
    for node in self._list:
      self.selection.rm(node)