Exemple #1
0
  def __init__(self, parent):
    super(QWidget, self).__init__()
    EventHandler.__init__(self)
    self.setupUi(self)

    self.mainwindow = parent.parent.parent.parent
    self.model = ListNodeModel(self)
    self.name = self.windowTitle()
    self.type = "filebrowser"
    self.setObjectName(self.name)

    self.vfs = vfs.vfs()
    self.VFS = VFS.Get()
    self.loader = loader.loader()
    self.lmodules = self.loader.modules
    self.taskmanager = TaskManager()

    self.parent = parent
    self.icon = None

    self.createSubMenu()
    self.createLayout()
Exemple #2
0
  def __init__(self, parent):
    super(QWidget, self).__init__()
    EventHandler.__init__(self)
    self.filterThread = FilterThread(self)
    self.parent = parent
    self.vfs = vfs()
    self.setupUi(self)
    self.name = self.windowTitle()
    self.setObjectName(self.name)

    self.clause_list = []
    self.operator_list = []

    self.completeClause.setText("")
    self.__totalnodes = 0
    self.__totalhits = 0
    self.__processednodes = 0

    self.icon = ":search.png"
    self.translation()
    self.xtd_attr = PropertyTable(None)

    self.attrsTree.addWidget(self.xtd_attr)

    self.model = ListNodeModel(self)
    self.searchResults = SearchNodeBrowser(self)
    self.nodeBrowserLayout.addWidget(self.searchResults)
    self.node_name = QLineEdit()
    self.node_name.setReadOnly(True)
    self.nodeBrowserLayout.addWidget(self.node_name)

    self.searchResults.addTableView()
    self.searchResults.tableView.setModel(self.model)    
    self.connect(self.searchResults.tableView, SIGNAL("nodeClicked"), self.change_node_name)
    
    if QtCore.PYQT_VERSION_STR >= "4.5.0":
      self.nameContain.textChanged.connect(self.rebuildQuery)

      self.caseSensitiveName.stateChanged.connect(self.case_sens_changed)
      self.typeName.currentIndexChanged.connect(self.case_sens_changed)

      self.launchSearchButton.clicked.connect(self.launchSearch)
      self.stopSearchButton.clicked.connect(self.stopSearch)
      self.exportButton.clicked.connect(self.export)
    else:
      QtCore.QObject.connect(self.nameContain.textChanged, SIGNAL("clicked(bool)"), self.rebuildQuery)

      QtCore.QObject.connect(self.caseSensitiveName, SIGNAL("stateChanged(int)"), \
                               self.case_sens_changed)

      QtCore.QObject.connect(self.typeName, SIGNAL("currentIndexChanged(int)"), \
                               self.case_sens_changed)

      QtCore.QObject.connect(self.launchSearchButton, SIGNAL("clicked(bool)"), self.launchSearch)
      QtCore.QObject.connect(self.stopSearchButton, SIGNAL("clicked(bool)"), self.stopSearch)
      QtCore.QObject.connect(self.exportButton, SIGNAL("clicked(bool)"), self.export)

    self.typeName.addItem("Fixed string", QVariant("f"))
    self.typeName.addItem("Wildcard", QVariant("w"))
    self.typeName.addItem("Fuzzy", QVariant("fz"))
    self.typeName.addItem("Reg exp", QVariant("re"))

    self.stopSearchButton.hide()
    self.exportButton.setEnabled(False)
    self.addedOpt = []

    if QtCore.PYQT_VERSION_STR >= "4.5.0":
      self.addOption.clicked.connect(self.addSearchOptions)
    else:
      QtCore.QObject.connect(self.addOption, SIGNAL("clicked(bool)"), self.addSearchOptions)


    self.connect(self.filterThread, SIGNAL("CountNodes"), self.__progressUpdate)
    self.connect(self.filterThread, SIGNAL("finished"), self.searchFinished)
    QtCore.QObject.connect(self.selectAll, SIGNAL("stateChanged(int)"), self.select_all)
Exemple #3
0
class AdvSearch(QWidget, Ui_SearchTab, EventHandler):
  """
  When this widget is instanciated, a new tab is opened in DFF main interface.
  It contains several sub-widgets used to perform a search by specifying more
  specifics parameters that the quick search.

  The tab is devided into two parts ::
        * The left part is dedicated to a view which is a kind of NodeBrowser
        designed to display search results.
        * The right part is a view with several fields used to build the search
        query.
  """

  def __init__(self, parent):
    super(QWidget, self).__init__()
    EventHandler.__init__(self)
    self.filterThread = FilterThread(self)
    self.parent = parent
    self.vfs = vfs()
    self.setupUi(self)
    self.name = self.windowTitle()
    self.setObjectName(self.name)

    self.clause_list = []
    self.operator_list = []

    self.completeClause.setText("")
    self.__totalnodes = 0
    self.__totalhits = 0
    self.__processednodes = 0

    self.icon = ":search.png"
    self.translation()
    self.xtd_attr = PropertyTable(None)

    self.attrsTree.addWidget(self.xtd_attr)

    self.model = ListNodeModel(self)
    self.searchResults = SearchNodeBrowser(self)
    self.nodeBrowserLayout.addWidget(self.searchResults)
    self.node_name = QLineEdit()
    self.node_name.setReadOnly(True)
    self.nodeBrowserLayout.addWidget(self.node_name)

    self.searchResults.addTableView()
    self.searchResults.tableView.setModel(self.model)    
    self.connect(self.searchResults.tableView, SIGNAL("nodeClicked"), self.change_node_name)
    
    if QtCore.PYQT_VERSION_STR >= "4.5.0":
      self.nameContain.textChanged.connect(self.rebuildQuery)

      self.caseSensitiveName.stateChanged.connect(self.case_sens_changed)
      self.typeName.currentIndexChanged.connect(self.case_sens_changed)

      self.launchSearchButton.clicked.connect(self.launchSearch)
      self.stopSearchButton.clicked.connect(self.stopSearch)
      self.exportButton.clicked.connect(self.export)
    else:
      QtCore.QObject.connect(self.nameContain.textChanged, SIGNAL("clicked(bool)"), self.rebuildQuery)

      QtCore.QObject.connect(self.caseSensitiveName, SIGNAL("stateChanged(int)"), \
                               self.case_sens_changed)

      QtCore.QObject.connect(self.typeName, SIGNAL("currentIndexChanged(int)"), \
                               self.case_sens_changed)

      QtCore.QObject.connect(self.launchSearchButton, SIGNAL("clicked(bool)"), self.launchSearch)
      QtCore.QObject.connect(self.stopSearchButton, SIGNAL("clicked(bool)"), self.stopSearch)
      QtCore.QObject.connect(self.exportButton, SIGNAL("clicked(bool)"), self.export)

    self.typeName.addItem("Fixed string", QVariant("f"))
    self.typeName.addItem("Wildcard", QVariant("w"))
    self.typeName.addItem("Fuzzy", QVariant("fz"))
    self.typeName.addItem("Reg exp", QVariant("re"))

    self.stopSearchButton.hide()
    self.exportButton.setEnabled(False)
    self.addedOpt = []

    if QtCore.PYQT_VERSION_STR >= "4.5.0":
      self.addOption.clicked.connect(self.addSearchOptions)
    else:
      QtCore.QObject.connect(self.addOption, SIGNAL("clicked(bool)"), self.addSearchOptions)


    self.connect(self.filterThread, SIGNAL("CountNodes"), self.__progressUpdate)
    self.connect(self.filterThread, SIGNAL("finished"), self.searchFinished)
    QtCore.QObject.connect(self.selectAll, SIGNAL("stateChanged(int)"), self.select_all)
    #self.searchBar.setMaximum(100)

  def __progressUpdate(self, val):
    self.searchBar.setValue(val)
    self.__totalhits = self.model.rowCount()
    self.totalHits.setText(self.currentMatchsText + str(self.__totalhits))


  def case_sens_changed(self, state):
    self.rebuildQuery()

  def addSearchOptions(self, changed):
    clause = {}
    clause_box = BuildSearchClause()
    ret = clause_box.exec_()
    if ret:
      idx = self.typeName.currentIndex()
      data_type = self.typeName.itemData(idx)
      
      for i in range(0, clause_box.advancedOptions.count()):
        widget = clause_box.advancedOptions.itemAt(i).widget()
        if not len(widget.edit.text()):
          continue
        try:
          if len(clause[widget.edit.field]):
            clause[widget.edit.field] += (widget.edit.operator() + " " + widget.edit.field)
            clause[widget.edit.field] += (widget.edit.text())
        except KeyError:
          clause[widget.edit.field] = (widget.edit.text())

      table_clause_widget = SearchClause(self)
      table_clause_widget.clause_widget.insertColumn(0)
      table_clause_widget.clause_widget.insertColumn(1)
      table_clause_widget.clause_widget.horizontalHeader().setStretchLastSection(True)
      table_clause_widget.clause_widget.horizontalHeader().setFixedHeight(5)

      if QtCore.PYQT_VERSION_STR >= "4.5.0":
        table_clause_widget.clause_widget.itemChanged.connect(self.editing_clause)
      else:
        QtCore.QObject.connect(self.table_clause_widget.clause_widget,\
                                 SIGNAL("itemChanged(QTableWidgetItem)"), self.editing_clause)
      nb_line = 0
      text = ""
      if not self.nameContain.text().isEmpty():
        text += ("(name (\"" + self.nameContain.text() + ")\"")
        if not self.caseSensitiveName.isChecked():
          text += ",i)"
        else:
          text += ")"
        text += ")"
        if len(self.clause_list):
          text += " or "

      for i in clause:
        table_clause_widget.clause_widget.insertRow(table_clause_widget.clause_widget.rowCount())
	item = QTableWidgetItem(i)
	item.setFlags(Qt.ItemFlags(Qt.ItemIsUserCheckable | Qt.ItemIsEnabled))
	item.setToolTip(self.fieldText)
        table_clause_widget.clause_widget.setItem(table_clause_widget.clause_widget.rowCount() - 1, \
                                                    0, item)
	item = QTableWidgetItem(clause[i])
	item.setFlags(Qt.ItemFlags(Qt.ItemIsUserCheckable | Qt.ItemIsEnabled))
	item.setToolTip(self.clauseText)
        table_clause_widget.clause_widget.setItem(table_clause_widget.clause_widget.rowCount() - 1, 1,\
                                                   item)
        table_clause_widget.clause_widget.resizeRowToContents(table_clause_widget.clause_widget.rowCount() - 1)
        if nb_line == 0:
          text += ("(" + i + " " + clause[i] + ")")
        else:
          text += (" or (" + i + " " +  clause[i] + ")")
        nb_line = nb_line + 1
      text += ")"

      if nb_line:
        if len(self.clause_list) != 0:
          if QtCore.PYQT_VERSION_STR >= "4.5.0":
            table_clause_widget.and_clause.clicked.connect(self.rebuildQuery)
            table_clause_widget.or_clause.clicked.connect(self.rebuildQuery)
          else:
            QtCore.QObject.connect( table_clause_widget.and_clause, SIGNAL("clicked(bool)"), \
                                      self.rebuildQuery)
            QtCore.QObject.connect( table_clause_widget.or_clause, SIGNAL("clicked(bool)"), \
                                      self.rebuildQuery)
        else:
          table_clause_widget.or_clause.hide()
          table_clause_widget.and_clause.hide()
          table_clause_widget.bool_operator.deleteLater()
         
# Set height to : (rows amount * row size) + margin + header height, visible to have resize available
        table_clause_widget.clause_widget.setMaximumHeight((table_clause_widget.clause_widget.rowCount() *    \
                                                           table_clause_widget.clause_widget.rowHeight(0)) + \
							   4 + 5)
        self.completeClause.setText(text)
        self.advancedOptions.addWidget(table_clause_widget, self.advancedOptions.rowCount(), 0, Qt.AlignTop)
        self.clause_list.append(table_clause_widget)
    self.rebuildQuery()

  def editing_clause(self, item):
    self.rebuildQuery()

  def rebuildQuery(self):
    text = ""
    if not self.nameContain.text().isEmpty():
      prefix = self.typeName.itemData(self.typeName.currentIndex()).toString()
      text += ("(name==" + prefix + "(\"" + self.nameContain.text() + "\"")
      if not self.caseSensitiveName.isChecked():
        text += ",i)"
      else:
        text += ")"
      text += ")"
      if len(self.clause_list):
        text += " or "
    for i in range(0, len(self.clause_list)):
      if i == 0:
        text += "("
        self.clause_list[i].or_clause.hide()
        self.clause_list[i].and_clause.hide()
      else:
        if self.clause_list[i].or_clause.isChecked():
          text += " or ("
        else:
          text += " and ("
      clause_widget = self.clause_list[i]
      for j in range(0, clause_widget.clause_widget.rowCount()):
        if j != 0:
          text += " or " 
        text += "("
        text += (clause_widget.clause_widget.item(j, 0).text() + " ")
        text += clause_widget.clause_widget.item(j, 1).text()
        text += ")"
      text += ")"
    self.completeClause.setText(text)

  def select_all(self, state):
    checked = Qt.Unchecked
    if state == Qt.Checked:
      checked = Qt.Checked
    nb_row = self.model.rowCount()
    self.model.emit(SIGNAL("layoutAboutToBeChanged()"))
    for i in range(0, nb_row):
      index = self.model.index(i, 0)
      if not index.isValid():
        continue
      self.model.setData(index, checked, Qt.CheckStateRole)
    self.model.emit(SIGNAL("layoutChanged()"))

  def change_node_name(self, button, node):
    self.node_name.setText(node.absolute())


  def searchFinished(self):
    if self.__totalhits:
      self.exportButton.setEnabled(True)
    self.stopSearchButton.hide()
    self.launchSearchButton.show()

  def export(self):
    text, ok = QInputDialog.getText(self, "Advanced search", "Filter export name",\
                                      QLineEdit.Normal, "") 
    if ok and text != "":
      siNode = self.vfs.getnode("/Searched items")
      filtersNode = Node(str(text), 0, siNode, None)
      filtersNode.__disown__()
      filtersNode.setDir()
      e = event()
      e.thisown = False
      vnode = Variant(filtersNode)
      vnode.thisown = False
      e.value = vnode
      VFS.Get().notify(e)
      nb_row = self.model.rowCount()
      for i in range(0, nb_row):
        index = self.model.index(i, 0)
        if not index.isValid():
          continue
        data = self.model.data(index, Qt.CheckStateRole)
        if data == Qt.Checked or data == Qt.PartiallyChecked:
          n = VFS.Get().getNodeFromPointer(long(index.internalId()))
          l = VLink(n, filtersNode)
          l.__disown__()
    else:
      box = QMessageBox(QMessageBox.Warning, "Error", "Error node already exists", \
                          QMessageBox.NoButton, self)
      box.exec_()

  def stopSearch(self, changed):
    self.emit(SIGNAL("stop_search()"))

  def launchSearch(self, changed):
    clause = {}

    self.emit(SIGNAL("NewSearch"))
    self.__totalhits = 0
    self.searchBar.setValue(0)
    self.totalHits.setText("0  " + self.tr("match(s)"))
    self.exportButton.setEnabled(False)
    idx = self.typeName.currentIndex()
    data_type = self.typeName.itemData(idx)
    if not self.nameContain.text().isEmpty():
      search = str(data_type.toString())
      search += ("(\"" + str(self.nameContain.text()) + "\"")
      if not self.caseSensitiveName.isChecked():
        search += ",i)"
      else:
        search += ")"
      clause["name"] = search

    try:
      self.filterThread.setContext(self.completeClause.text(), self.vfs.getnode(str(self.path.text())))
      self.filterThread.model = self.model
      self.searchBar.show()
      self.launchSearchButton.hide()
      self.stopSearchButton.show()
      self.totalHits.setText(self.currentMatchsText + "0")
      self.filterThread.start()
    except RuntimeError as err:
      box = QMessageBox(QMessageBox.Warning, self.tr("Invalid clause"),
                        str(err), QMessageBox.Ok, self)
      box.exec_()
      
  def showMoreOptions(self, changed):
    pass

  def setCurrentNode(self, path):
    self.search_in_node = path

  def changeEvent(self, event):
    """ Search for a language change event
    
    This event have to call retranslateUi to change interface language on
    the fly.
    """
    if event.type() == QEvent.LanguageChange:
      self.retranslateUi(self)
      self.translation()
    else:
      QWidget.changeEvent(self, event)

  def translation(self):
    self.fieldText = self.tr("Field")
    self.clauseText = self.tr("Clause")
    self.currentMatchsText = self.tr("current match(s): ")
Exemple #4
0
class SearchNodeBrowser(QWidget, EventHandler, Ui_NodeBrowser):
  def __init__(self, parent):
    super(QWidget, self).__init__()
    EventHandler.__init__(self)
    self.setupUi(self)

    self.mainwindow = parent.parent.parent.parent
    self.model = ListNodeModel(self)
    self.name = self.windowTitle()
    self.type = "filebrowser"
    self.setObjectName(self.name)

    self.vfs = vfs.vfs()
    self.VFS = VFS.Get()
    self.loader = loader.loader()
    self.lmodules = self.loader.modules
    self.taskmanager = TaskManager()

    self.parent = parent
    self.icon = None

    self.createSubMenu()
    self.createLayout()

  def Event(self, e):
    self.model.emit(SIGNAL("layoutAboutToBeChanged()")) 
    self.model.emit(SIGNAL("layoutChanged()"))

  def getWindowGeometry(self):
    self.winWidth = self.mainwindow.width()

  def createLayout(self):
    self.baseLayout = QVBoxLayout(self)
    self.baseLayout.setMargin(0)
    self.baseLayout.setSpacing(0)
    self.browserLayout = QSplitter(self)
    self.baseLayout.insertWidget(0, self.browserLayout)
    self.baseLayout.setStretchFactor(self.browserLayout, 1)

  def addNodeView(self):
    self.addTableView()
    self.addThumbsView()

  def addTableView(self): 
    self.tableView = NodeTableView(self)
    self.tableView.horizontalHeader().setStretchLastSection(True)
    self.tableView.setColumnWidth(0, 200)
    self.tableView.setSizePolicy(QSizePolicy(QSizePolicy.Maximum, QSizePolicy.Maximum))
    self.browserLayout.addWidget(self.tableView)

    self.browserLayout.setStretchFactor(self.browserLayout.indexOf(self.tableView), 1)

    self.connect(self.tableView, SIGNAL("nodePressed"), self.nodePressed)
    self.connect(self.tableView, SIGNAL("nodeClicked"), self.nodeClicked)
    self.connect(self.tableView, SIGNAL("nodeDoubleClicked"), self.nodeDoubleClicked)
    self.connect(self.tableView, SIGNAL(""), self.selectAttr)

  def applyModule(self, modname, modtype, selected):
      appMod = ApplyModule(self)
      appMod.openApplyModule(modname, modtype, selected)

  def selectAttr(self):
    pass
    
  def addThumbsView(self):
    self.thumbsView = NodeThumbsView(self)
    self.thumbsView.setModel(self.model) 
    self.thumbsView.setSizePolicy(QSizePolicy(QSizePolicy.Maximum, QSizePolicy.Maximum))
    self.browserLayout.addWidget(self.thumbsView)
    self.browserLayout.setStretchFactor(self.browserLayout.indexOf(self.thumbsView), 1)
    self.connect(self.thumbsView, SIGNAL("nodePressed"), self.nodePressed)
    self.connect(self.thumbsView, SIGNAL("nodeClicked"), self.nodeClicked)
    self.connect(self.thumbsView, SIGNAL("nodeDoubleClicked"), self.nodeDoubleClicked)

  def currentProxyModel(self):
     if self.thumbsView.isVisible():
       return self.thumbsView.model()
     elif self.tableView.isVisible():
       return self.tableView.model()

  def currentModel(self):
      return self.tableView.model() 
 
  def currentView(self):
      return self.tableView

  def currentNodes(self):
     indexList = self.currentView().selectionModel().selectedRows()
     nodeList = []
     for index in indexList:
       if index.isValid():
         nodeList.append(self.VFS.getNodeFromPointer(index.internalId()))
     return nodeList

  def currentNode(self):
     index = self.currentView().selectionModel().currentIndex()
     if index.isValid():
         return self.VFS.getNodeFromPointer(index.internalId())

  def nodePressed(self, key, node, index = None):
    if key in [Qt.Key_Up, Qt.Key_Down, Qt.Key_PageUp, Qt.Key_PageDown]:
      self.parent.xtd_attr.fill(node)
      self.mainwindow.emit(SIGNAL("previewUpdate"), node)	

  def nodeClicked(self, mouseButton, node, index = None):
     if mouseButton == Qt.LeftButton:
	 self.mainwindow.emit(SIGNAL("previewUpdate"), node)
     if mouseButton == Qt.RightButton:
       self.menuRelevant = MenuRelevant(self, self, node)
       if node.hasChildren() or node.isDir():
         self.actionOpen_in_new_tab.setEnabled(True)
       else:
         self.actionOpen_in_new_tab.setEnabled(False)
       self.submenuFile.popup(QCursor.pos())
       self.submenuFile.show()
     self.parent.xtd_attr.fill(node)

  def nodeTreeDoubleClicked(self, mouseButton, node, index = None):
    if node == None:
      return
    if self.currentView().enterInDirectory:
      if node.hasChildren() or node.isDir():
        self.currentModel().setRootPath(node) 

  def nodeDoubleClicked(self, mouseButton, node, index = None):
    if node == None:
      return
    if self.currentView().enterInDirectory:
      if node.hasChildren() or node.isDir():
        self.openAsNewTab()
      else:
        self.openDefault(node)
    else:  
      self.openDefault(node)

  def sizeChanged(self, string):
     if self.nodeViewBox.thumbSize.currentIndex() == 0:
       self.thumbsView.setIconGridSize(64, 64)
     elif self.nodeViewBox.thumbSize.currentIndex() == 1:
       self.thumbsView.setIconGridSize(96, 96)
     elif self.nodeViewBox.thumbSize.currentIndex() == 2:
       self.thumbsView.setIconGridSize(128, 128)

  def openDefault(self, node = None):
     if not node:
       node = self.currentNode()
       if not node:
	 return
     mods = node.compatibleModules()
     mods.reverse()	
     if len(mods):
       for mod in mods:
          if "Viewers" in self.lmodules[mod].tags:
	    break
       try:
         priority = modulePriority[mod]
       except KeyError:
         modulePriority[mod] = 0
         priority = 0
       if not priority: 
         mbox = QMessageBox(QMessageBox.Question, self.tr("Apply module"), self.tr("Do you want to apply module ") + str(mod) + self.tr(" on this node ?"), QMessageBox.Yes | QMessageBox.No, self)
         mbox.addButton(self.tr("Always"), QMessageBox.AcceptRole)
	 reply = mbox.exec_() 
         if reply == QMessageBox.No:
           return		
         elif reply == QMessageBox.AcceptRole:
	   modulePriority[mod] = 1 
       if self.lmodules[mod]:
         conf = self.lmodules[mod].conf
         arguments = conf.arguments()
         marg = {}
         for argument in arguments:
           if argument.type() == typeId.Node:
             marg[argument.name()] = node
         args = conf.generate(marg)
         self.taskmanager.add(mod, args, ["thread", "gui"])
	 return
     else:
       errnodes = ""
       if node.size():
         conf = self.lmodules["hexadecimal"].conf
         try:
           arg = conf.generate({"file": node})
           self.taskmanager.add("hexadecimal", arg, ["thread", "gui"])
         except RuntimeError:
           errnodes += node.absolute() + "\n"
       else:
         errnodes += node.absolute() + "\n"
       if len(errnodes):
         msg = QMessageBox(self)
         msg.setWindowTitle(self.tr("Empty files"))
         msg.setText(self.tr("the following nodes could not be opened with Hex viewer because they are either empty or folders\n"))
         msg.setIcon(QMessageBox.Warning)
         msg.setDetailedText(errnodes)
         msg.setStandardButtons(QMessageBox.Ok)
         ret = msg.exec_()
 

  def createSubMenu(self):
     self.extractor = Extractor(self.parent)
     self.connect(self.extractor, SIGNAL("filled"), self.launchExtract)
     self.submenuFile = QMenu()
     self.submenuFile.addAction(self.actionOpen)
     self.connect(self.actionOpen, SIGNAL("triggered()"), self.openDefault)
     self.submenuFile.addAction(self.actionOpen_in_new_tab)
     self.connect(self.actionOpen_in_new_tab, SIGNAL("triggered()"), self.openAsNewTab)
     self.submenuRelevant = self.submenuFile.addMenu(self.actionRelevant_module.icon(), self.actionRelevant_module.text())
     self.menu = {}
     self.menuModule = self.submenuFile.addMenu(self.actionOpen_with.icon(), self.actionOpen_with.text())
     self.menuTags = MenuTags(self,     self.parent.parent.parent.parent, self.currentNodes)
     self.submenuFile.addSeparator()
     self.submenuFile.addAction(self.actionHex_viewer)
     self.connect(self.actionHex_viewer, SIGNAL("triggered()"), self.launchHexedit)
     self.submenuFile.addAction(self.actionExtract)
     self.connect(self.actionExtract, SIGNAL("triggered()"), self.extractNodes)
     self.submenuFile.addSeparator()

  def openAsNewTab(self):
    node = self.currentNode()
    self.parent.parent.parent.parent.addNodeBrowser(node)

  def launchHexedit(self):
     nodes = self.currentNodes()
     conf = self.loader.get_conf("hexadecimal")
     errnodes = ""
     for node in nodes:
       if node.size():
         try:
           arg = conf.generate({"file": node})
           self.taskmanager.add("hexadecimal", arg, ["thread", "gui"])
         except RuntimeError:
           errnodes += node.absolute() + "\n"
       else:
         errnodes += node.absolute() + "\n"
     if len(errnodes):
       msg = QMessageBox(self)
       msg.setWindowTitle(self.tr("Empty files"))
       msg.setText(self.tr("the following nodes could not be opened with Hex viewer because they are either empty or folders\n"))
       msg.setIcon(QMessageBox.Warning)
       msg.setDetailedText(errnodes)
       msg.setStandardButtons(QMessageBox.Ok)
       ret = msg.exec_()

  def extractNodes(self):
     self.extractor.launch(self.currentNodes())

  def launchExtract(self):
     res = self.extractor.getArgs()
     args = {}
     args["files"] = res["nodes"]
     args["syspath"] = str(res["path"])
     args["recursive"] = res["recurse"]
     conf = self.loader.get_conf("extract")
     try:
       margs = conf.generate(args)
       self.taskmanager.add("extract", margs, ["thread", "gui"])
     except RuntimeError:
       pass

  def changeEvent(self, event):
    """ Search for a language change event
    
    This event have to call retranslateUi to change interface language on
    the fly.
    """
    if event.type() == QEvent.LanguageChange:
      self.retranslateUi(self)
      self.menuModule.setTitle(self.actionOpen_with.text())
      self.submenuRelevant.setTitle(self.actionRelevant_module.text())
      self.model.translation()
    else:
      QWidget.changeEvent(self, event)