text: """
  src/bitmessageqt/foldertree.py
  ==============================
  """
  # pylint: disable=too-many-arguments,bad-super-call,attribute-defined-outside-init
  
  from PyQt4 import QtCore, QtGui
  
  from bmconfigparser import BMConfigParser
  from helper_sql import sqlExecute, sqlQuery
  from settingsmixin import SettingsMixin
  from tr import _translate
  from utils import avatarize
  
  # for pylupdate
  _translate("MainWindow", "inbox")
  _translate("MainWindow", "new")
  _translate("MainWindow", "sent")
  _translate("MainWindow", "trash")
  
  
  class AccountMixin(object):
      """UI-related functionality for accounts"""
      ALL = 0
      NORMAL = 1
      CHAN = 2
      MAILINGLIST = 3
      SUBSCRIPTION = 4
      BROADCAST = 5
  
      def accountColor(self):
          """QT UI color for an account"""
          if not self.isEnabled:
              return QtGui.QColor(128, 128, 128)
          elif self.type == self.CHAN:
              return QtGui.QColor(216, 119, 0)
          elif self.type in [self.MAILINGLIST, self.SUBSCRIPTION]:
              return QtGui.QColor(137, 4, 177)
          return QtGui.QApplication.palette().text().color()
  
      def folderColor(self):
          """QT UI color for a folder"""
          if not self.parent().isEnabled:
              return QtGui.QColor(128, 128, 128)
          return QtGui.QApplication.palette().text().color()
  
      def accountBrush(self):
          """Account brush (for QT UI)"""
          brush = QtGui.QBrush(self.accountColor())
          brush.setStyle(QtCore.Qt.NoBrush)
          return brush
  
      def folderBrush(self):
          """Folder brush (for QT UI)"""
          brush = QtGui.QBrush(self.folderColor())
          brush.setStyle(QtCore.Qt.NoBrush)
          return brush
  
      def setAddress(self, address):
          """Set bitmessage address of the object"""
          if address is None:
              self.address = None
          else:
              self.address = str(address)
  
      def setUnreadCount(self, cnt):
          """Set number of unread messages"""
          try:
              if self.unreadCount == int(cnt):
                  return
          except AttributeError:
              pass
          self.unreadCount = int(cnt)
          if isinstance(self, QtGui.QTreeWidgetItem):
              self.emitDataChanged()
  
      def setEnabled(self, enabled):
          """Set account enabled (QT UI)"""
          self.isEnabled = enabled
          try:
              self.setExpanded(enabled)
          except AttributeError:
              pass
          if isinstance(self, Ui_AddressWidget):
              for i in range(self.childCount()):
                  if isinstance(self.child(i), Ui_FolderWidget):
                      self.child(i).setEnabled(enabled)
          if isinstance(self, QtGui.QTreeWidgetItem):
              self.emitDataChanged()
  
      def setType(self):
          """Set account type (QT UI)"""
          self.setFlags(self.flags() | QtCore.Qt.ItemIsEditable)
          if self.address is None:
              self.type = self.ALL
              self.setFlags(self.flags() & ~QtCore.Qt.ItemIsEditable)
          elif BMConfigParser().safeGetBoolean(self.address, 'chan'):
              self.type = self.CHAN
          elif BMConfigParser().safeGetBoolean(self.address, 'mailinglist'):
              self.type = self.MAILINGLIST
          elif sqlQuery(
                  '''select label from subscriptions where address=?''', self.address):
              self.type = AccountMixin.SUBSCRIPTION
          else:
              self.type = self.NORMAL
  
      def defaultLabel(self):
          """Default label (in case no label is set manually)"""
          queryreturn = None
          retval = None
          if self.type in (
                  AccountMixin.NORMAL,
                  AccountMixin.CHAN, AccountMixin.MAILINGLIST):
              try:
                  retval = unicode(
                      BMConfigParser().get(self.address, 'label'), 'utf-8')
              except Exception:
                  queryreturn = sqlQuery(
                      '''select label from addressbook where address=?''', self.address)
          elif self.type == AccountMixin.SUBSCRIPTION:
              queryreturn = sqlQuery(
                  '''select label from subscriptions where address=?''', self.address)
          if queryreturn is not None:
              if queryreturn != []:
                  for row in queryreturn:
                      retval, = row
                      retval = unicode(retval, 'utf-8')
          elif self.address is None or self.type == AccountMixin.ALL:
              return unicode(
                  str(_translate("MainWindow", "All accounts")), 'utf-8')
  
          return retval or unicode(self.address, 'utf-8')
  
  
  class BMTreeWidgetItem(QtGui.QTreeWidgetItem, AccountMixin):
      """A common abstract class for Tree widget item"""
  
      def __init__(self, parent, pos, address, unreadCount):
          super(QtGui.QTreeWidgetItem, self).__init__()
          self.setAddress(address)
          self.setUnreadCount(unreadCount)
          self._setup(parent, pos)
  
      def _getAddressBracket(self, unreadCount=False):
          return " (" + str(self.unreadCount) + ")" if unreadCount else ""
  
      def data(self, column, role):
          """Override internal QT method for returning object data"""
          if column == 0:
              if role == QtCore.Qt.DisplayRole:
                  return self._getLabel() + self._getAddressBracket(
                      self.unreadCount > 0)
              elif role == QtCore.Qt.EditRole:
                  return self._getLabel()
              elif role == QtCore.Qt.ToolTipRole:
                  return self._getLabel() + self._getAddressBracket(False)
              elif role == QtCore.Qt.FontRole:
                  font = QtGui.QFont()
                  font.setBold(self.unreadCount > 0)
                  return font
          return super(BMTreeWidgetItem, self).data(column, role)
  
  
  class Ui_FolderWidget(BMTreeWidgetItem):
      """Item in the account/folder tree representing a folder"""
      folderWeight = {"inbox": 1, "new": 2, "sent": 3, "trash": 4}
  
      def __init__(
              self, parent, pos=0, address="", folderName="", unreadCount=0):
          self.setFolderName(folderName)
          super(Ui_FolderWidget, self).__init__(
              parent, pos, address, unreadCount)
  
      def _setup(self, parent, pos):
          parent.insertChild(pos, self)
  
      def _getLabel(self):
          return _translate("MainWindow", self.folderName)
  
      def setFolderName(self, fname):
          """Set folder name (for QT UI)"""
          self.folderName = str(fname)
  
      def data(self, column, role):
          """Override internal QT method for returning object data"""
          if column == 0 and role == QtCore.Qt.ForegroundRole:
              return self.folderBrush()
          return super(Ui_FolderWidget, self).data(column, role)
  
      # inbox, sent, thrash first, rest alphabetically
      def __lt__(self, other):
          if isinstance(other, Ui_FolderWidget):
              if self.folderName in self.folderWeight:
                  x = self.folderWeight[self.folderName]
              else:
                  x = 99
              if other.folderName in self.folderWeight:
                  y = self.folderWeight[other.folderName]
              else:
                  y = 99
              reverse = QtCore.Qt.DescendingOrder == \
                  self.treeWidget().header().sortIndicatorOrder()
              if x == y:
                  return self.folderName < other.folderName
              return x >= y if reverse else x < y
  
          return super(QtGui.QTreeWidgetItem, self).__lt__(other)
  
  
  class Ui_AddressWidget(BMTreeWidgetItem, SettingsMixin):
      """Item in the account/folder tree representing an account"""
      def __init__(self, parent, pos=0, address=None, unreadCount=0, enabled=True):
          super(Ui_AddressWidget, self).__init__(
              parent, pos, address, unreadCount)
          self.setEnabled(enabled)
  
      def _setup(self, parent, pos):
          self.setType()
          parent.insertTopLevelItem(pos, self)
  
      def _getLabel(self):
          if self.address is None:
              return unicode(_translate(
                  "MainWindow", "All accounts").toUtf8(), 'utf-8', 'ignore')
          else:
              try:
                  return unicode(
                      BMConfigParser().get(self.address, 'label'),
                      'utf-8', 'ignore')
              except:
                  return unicode(self.address, 'utf-8')
  
      def _getAddressBracket(self, unreadCount=False):
          ret = "" if self.isExpanded() \
              else super(Ui_AddressWidget, self)._getAddressBracket(unreadCount)
          if self.address is not None:
              ret += " (" + self.address + ")"
          return ret
  
      def data(self, column, role):
          """Override internal QT method for returning object data"""
          if column == 0:
              if role == QtCore.Qt.DecorationRole:
                  return avatarize(
                      self.address or self._getLabel().encode('utf8'))
              elif role == QtCore.Qt.ForegroundRole:
                  return self.accountBrush()
          return super(Ui_AddressWidget, self).data(column, role)
  
      def setData(self, column, role, value):
          """Save account label (if you edit in the the UI, this will be triggered and will save it to keys.dat)"""
          if role == QtCore.Qt.EditRole \
                  and self.type != AccountMixin.SUBSCRIPTION:
              BMConfigParser().set(
                  str(self.address), 'label',
                  str(value.toString().toUtf8())
                  if isinstance(value, QtCore.QVariant)
                  else value.encode('utf-8')
              )
              BMConfigParser().save()
          return super(Ui_AddressWidget, self).setData(column, role, value)
  
      def setAddress(self, address):
          """Set address to object (for QT UI)"""
          super(Ui_AddressWidget, self).setAddress(address)
          self.setData(0, QtCore.Qt.UserRole, self.address)
  
      def _getSortRank(self):
          return self.type if self.isEnabled else (self.type + 100)
  
      # label (or address) alphabetically, disabled at the end
      def __lt__(self, other):
          # pylint: disable=protected-access
          if isinstance(other, Ui_AddressWidget):
              reverse = QtCore.Qt.DescendingOrder == \
                  self.treeWidget().header().sortIndicatorOrder()
              if self._getSortRank() == other._getSortRank():
                  x = self._getLabel().lower()
                  y = other._getLabel().lower()
                  return x < y
              return (
                  not reverse
                  if self._getSortRank() < other._getSortRank() else reverse
              )
  
          return super(QtGui.QTreeWidgetItem, self).__lt__(other)
  
  
  class Ui_SubscriptionWidget(Ui_AddressWidget):
      """Special treating of subscription addresses"""
      # pylint: disable=unused-argument
      def __init__(self, parent, pos=0, address="", unreadCount=0, label="", enabled=True):
          super(Ui_SubscriptionWidget, self).__init__(
              parent, pos, address, unreadCount, enabled)
  
      def _getLabel(self):
          queryreturn = sqlQuery(
              '''select label from subscriptions where address=?''', self.address)
          if queryreturn != []:
              for row in queryreturn:
                  retval, = row
              return unicode(retval, 'utf-8', 'ignore')
          return unicode(self.address, 'utf-8')
  
      def setType(self):
          """Set account type"""
          super(Ui_SubscriptionWidget, self).setType()  # sets it editable
          self.type = AccountMixin.SUBSCRIPTION  # overrides type
  
      def setData(self, column, role, value):
          """Save subscription label to database"""
          if role == QtCore.Qt.EditRole:
              if isinstance(value, QtCore.QVariant):
                  label = str(
                      value.toString().toUtf8()).decode('utf-8', 'ignore')
              else:
                  label = unicode(value, 'utf-8', 'ignore')
              sqlExecute(
                  '''UPDATE subscriptions SET label=? WHERE address=?''',
                  label, self.address)
          return super(Ui_SubscriptionWidget, self).setData(column, role, value)
  
  
  class BMTableWidgetItem(QtGui.QTableWidgetItem, SettingsMixin):
      """A common abstract class for Table widget item"""
  
      def __init__(self, parent=None, label=None, unread=False):
          super(QtGui.QTableWidgetItem, self).__init__()
          self.setLabel(label)
          self.setUnread(unread)
          self._setup()
          if parent is not None:
              parent.append(self)
  
      def setLabel(self, label):
          """Set object label"""
          self.label = label
  
      def setUnread(self, unread):
          """Set/unset read state of an item"""
          self.unread = unread
  
      def data(self, role):
          """Return object data (QT UI)"""
          if role in (
                  QtCore.Qt.DisplayRole, QtCore.Qt.EditRole, QtCore.Qt.ToolTipRole
          ):
              return self.label
          elif role == QtCore.Qt.FontRole:
              font = QtGui.QFont()
              font.setBold(self.unread)
              return font
          return super(BMTableWidgetItem, self).data(role)
  
  
  class BMAddressWidget(BMTableWidgetItem, AccountMixin):
      """A common class for Table widget item with account"""
  
      def _setup(self):
          self.setEnabled(True)
  
      def data(self, role):
          """Return object data (QT UI)"""
          if role == QtCore.Qt.ToolTipRole:
              return self.label + " (" + self.address + ")"
          elif role == QtCore.Qt.DecorationRole:
              if BMConfigParser().safeGetBoolean(
                      'bitmessagesettings', 'useidenticons'):
                  return avatarize(self.address or self.label)
          elif role == QtCore.Qt.ForegroundRole:
              return self.accountBrush()
          return super(BMAddressWidget, self).data(role)
  
  
  class MessageList_AddressWidget(BMAddressWidget):
      """Address item in a messagelist"""
      def __init__(self, parent, address=None, label=None, unread=False):
          self.setAddress(address)
          super(MessageList_AddressWidget, self).__init__(parent, label, unread)
  
      def _setup(self):
          self.isEnabled = True
          self.setFlags(QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled)
          self.setType()
  
      def setLabel(self, label=None):
          """Set label"""
          super(MessageList_AddressWidget, self).setLabel(label)
          if label is not None:
              return
          newLabel = self.address
          queryreturn = None
          if self.type in (
                  AccountMixin.NORMAL,
                  AccountMixin.CHAN, AccountMixin.MAILINGLIST):
              try:
                  newLabel = unicode(
                      BMConfigParser().get(self.address, 'label'),
                      'utf-8', 'ignore')
              except:
                  queryreturn = sqlQuery(
                      '''select label from addressbook where address=?''', self.address)
          elif self.type == AccountMixin.SUBSCRIPTION:
              queryreturn = sqlQuery(
                  '''select label from subscriptions where address=?''', self.address)
          if queryreturn:
              for row in queryreturn:
                  newLabel = unicode(row[0], 'utf-8', 'ignore')
  
          self.label = newLabel
  
      def data(self, role):
          """Return object data (QT UI)"""
          if role == QtCore.Qt.UserRole:
              return self.address
          return super(MessageList_AddressWidget, self).data(role)
  
      def setData(self, role, value):
          """Set object data"""
          if role == QtCore.Qt.EditRole:
              self.setLabel()
          return super(MessageList_AddressWidget, self).setData(role, value)
  
      # label (or address) alphabetically, disabled at the end
      def __lt__(self, other):
          if isinstance(other, MessageList_AddressWidget):
              return self.label.lower() < other.label.lower()
          return super(QtGui.QTableWidgetItem, self).__lt__(other)
  
  
  class MessageList_SubjectWidget(BMTableWidgetItem):
      """Message list subject item"""
      def __init__(self, parent, subject=None, label=None, unread=False):
          self.setSubject(subject)
          super(MessageList_SubjectWidget, self).__init__(parent, label, unread)
  
      def _setup(self):
          self.setFlags(QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled)
  
      def setSubject(self, subject):
          """Set subject"""
          self.subject = subject
  
      def data(self, role):
          """Return object data (QT UI)"""
          if role == QtCore.Qt.UserRole:
              return self.subject
          return super(MessageList_SubjectWidget, self).data(role)
  
      # label (or address) alphabetically, disabled at the end
      def __lt__(self, other):
          if isinstance(other, MessageList_SubjectWidget):
              return self.label.lower() < other.label.lower()
          return super(QtGui.QTableWidgetItem, self).__lt__(other)
  
  
  class Ui_AddressBookWidgetItem(BMAddressWidget):
      """Addressbook item"""
      # pylint: disable=unused-argument
      def __init__(self, label=None, acc_type=AccountMixin.NORMAL):
          self.type = acc_type
          super(Ui_AddressBookWidgetItem, self).__init__(label=label)
  
      def data(self, role):
          """Return object data"""
          if role == QtCore.Qt.UserRole:
              return self.type
          return super(Ui_AddressBookWidgetItem, self).data(role)
  
      def setData(self, role, value):
          """Set data"""
          if role == QtCore.Qt.EditRole:
              self.label = str(
                  value.toString().toUtf8()
                  if isinstance(value, QtCore.QVariant) else value
              )
              if self.type in (
                      AccountMixin.NORMAL,
                      AccountMixin.MAILINGLIST, AccountMixin.CHAN):
                  try:
                      BMConfigParser().get(self.address, 'label')
                      BMConfigParser().set(self.address, 'label', self.label)
                      BMConfigParser().save()
                  except:
                      sqlExecute('''UPDATE addressbook set label=? WHERE address=?''', self.label, self.address)
              elif self.type == AccountMixin.SUBSCRIPTION:
                  sqlExecute('''UPDATE subscriptions set label=? WHERE address=?''', self.label, self.address)
              else:
                  pass
          return super(Ui_AddressBookWidgetItem, self).setData(role, value)
  
      def __lt__(self, other):
          if isinstance(other, Ui_AddressBookWidgetItem):
              reverse = QtCore.Qt.DescendingOrder == \
                  self.tableWidget().horizontalHeader().sortIndicatorOrder()
  
              if self.type == other.type:
                  return self.label.lower() < other.label.lower()
              return not reverse if self.type < other.type else reverse
          return super(QtGui.QTableWidgetItem, self).__lt__(other)
  
  
  class Ui_AddressBookWidgetItemLabel(Ui_AddressBookWidgetItem):
      """Addressbook label item"""
      def __init__(self, address, label, acc_type):
          super(Ui_AddressBookWidgetItemLabel, self).__init__(label, acc_type)
          self.address = address
  
      def data(self, role):
          """Return object data"""
          self.label = self.defaultLabel()
          return super(Ui_AddressBookWidgetItemLabel, self).data(role)
  
  
  class Ui_AddressBookWidgetItemAddress(Ui_AddressBookWidgetItem):
      """Addressbook address item"""
      def __init__(self, address, label, acc_type):
          super(Ui_AddressBookWidgetItemAddress, self).__init__(address, acc_type)
          self.address = address
          self.setFlags(QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled)
  
      def data(self, role):
          """Return object data"""
          if role == QtCore.Qt.ToolTipRole:
              return self.address
          if role == QtCore.Qt.DecorationRole:
              return None
          return super(Ui_AddressBookWidgetItemAddress, self).data(role)
  
  
  class AddressBookCompleter(QtGui.QCompleter):
      """Addressbook completer"""
  
      def __init__(self):
          super(AddressBookCompleter, self).__init__()
          self.cursorPos = -1
  
      def onCursorPositionChanged(self, oldPos, newPos):  # pylint: disable=unused-argument
          """Callback for cursor position change"""
          if oldPos != self.cursorPos:
              self.cursorPos = -1
  
      def splitPath(self, path):
          """Split on semicolon"""
          text = unicode(path.toUtf8(), 'utf-8')
          return [text[:self.widget().cursorPosition()].split(';')[-1].strip()]
  
      def pathFromIndex(self, index):
          """Perform autocompletion (reimplemented QCompleter method)"""
          autoString = unicode(
              index.data(QtCore.Qt.EditRole).toString().toUtf8(), 'utf-8')
          text = unicode(self.widget().text().toUtf8(), 'utf-8')
  
          # If cursor position was saved, restore it, else save it
          if self.cursorPos != -1:
              self.widget().setCursorPosition(self.cursorPos)
          else:
              self.cursorPos = self.widget().cursorPosition()
  
          # Get current prosition
          curIndex = self.widget().cursorPosition()
  
          # prev_delimiter_index should actually point at final white space
          # AFTER the delimiter
          # Get index of last delimiter before current position
          prevDelimiterIndex = text[0:curIndex].rfind(";")
          while text[prevDelimiterIndex + 1] == " ":
              prevDelimiterIndex += 1
  
          # Get index of first delimiter after current position
          # (or EOL if no delimiter after cursor)
          nextDelimiterIndex = text.find(";", curIndex)
          if nextDelimiterIndex == -1:
              nextDelimiterIndex = len(text)
  
          # Get part of string that occurs before cursor
          part1 = text[0:prevDelimiterIndex + 1]
  
          # Get string value from before auto finished string is selected
          # pre = text[prevDelimiterIndex + 1:curIndex - 1]
  
          # Get part of string that occurs AFTER cursor
          part2 = text[nextDelimiterIndex:]
  
          return part1 + autoString + part2
  