title: Editable tree view - changing type of editing field
body: <p>I have dictionary like this:</p>
  
  <pre><code>{"key1": 1, "key2": 0, "key3": {"key": 1}, "dupa": None}
  </code></pre>
  
  <p>I would like to edit it as a tree view but I can't change <code>key1</code> to store a string.  </p>
  
  <p>I saw <a href="https://github.com/pyqt/examples/tree/master/itemviews/editabletreemodel" rel="nofollow noreferrer">editable model view example</a>. And <strong>edited</strong> it to display my dictionary.<br>
  Here is example:  </p>
  
  <p><a href="https://i.stack.imgur.com/a9Ow7.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/a9Ow7.png" alt="My tree view"></a> </p>
  
  <p>Look at the read 'area' as u can expect there is no way to insert string in this filed.</p>
  
  <strong>So my questions are:</strong>
  
  <ol>
  <li>Witch class or function should I override to be allowed control edit item that is displayed (I wanna add control that allow change type and remove whole item or add new)? In other words: How can I be able to put string in this filed? </li>
  <li>Where I can find originally definition of this function/class? </li>
  </ol>
  
  <p>I used <code>qt</code> tag because You can answer my in C++ example, I can translate it to python. </p>
  
  <h3>My edited code: (ready to copy and run) but I think there is no need to look at it, to answer my questions.</h3>
  
  <pre><code>from PyQt5.QtCore import (QAbstractItemModel, QFile, QIODevice,
                            QItemSelectionModel, QModelIndex, Qt, QAbstractItemModel, QObject)
  from PyQt5.QtWidgets import QApplication, QMainWindow, QHBoxLayout
  from PyQt5 import QtCore, QtGui, QtWidgets
  
  
  class TreeItem(object):
      def __init__(self, data, parent=None):
          self.parentItem = parent
          self.itemData = data  # it's also []
          self.childItems = []
  
      def child(self, row):
          return self.childItems[row]
  
      def childCount(self):
          return len(self.childItems)
  
      def childNumber(self):
          if self.parentItem is not None:
              return self.parentItem.childItems.index(self)
          return 0
  
      def columnCount(self):
          return len(self.itemData)
  
      def data(self, column):
          return self.itemData[column]
  
      def insertChildren(self, position, count, columns):
          if position &lt; 0 or position &gt; len(self.childItems):
              return False
  
          for row in range(count):
              data = [None for v in range(columns)]
              item = TreeItem(data, self)
              self.childItems.insert(position, item)
  
          return True
  
      def appendChild_by_item(self, item):
          item.parentItem = self
          self.childItems.append(item)
  
      def appendChild_by_data(self, data):
          self.childItems.append(TreeItem(data, self))
  
      def insertColumns(self, position, columns):
          if position &lt; 0 or position &gt; len(self.itemData):
              return False
  
          for column in range(columns):
              self.itemData.insert(position, None)
  
          for child in self.childItems:
              child.insertColumns(position, columns)
  
          return True
  
      def parent(self):
          return self.parentItem
  
      def removeChildren(self, position, count):
          if position &lt; 0 or position + count &gt; len(self.childItems):
              return False
  
          for row in range(count):
              self.childItems.pop(position)
  
          return True
  
      def removeColumns(self, position, columns):
          if position &lt; 0 or position + columns &gt; len(self.itemData):
              return False
  
          for column in range(columns):
              self.itemData.pop(position)
  
          for child in self.childItems:
              child.removeColumns(position, columns)
  
          return True
  
      def setData(self, column, value):
          if column &lt; 0 or column &gt;= len(self.itemData):
              return False
  
          self.itemData[column] = value
  
          return True
  
  
  class TreeModel(QAbstractItemModel):
      def __init__(self, headers, data, parent=None):
          super(TreeModel, self).__init__(parent)
  
          rootData = [header for header in headers]
          self.rootItem = TreeItem(rootData)
          self.setupModelData(data, self.rootItem)
  
          print(self.rootItem.childCount())
  
      def columnCount(self, parent=QModelIndex()):
          return self.rootItem.columnCount()
  
      def data(self, index, role):
          if not index.isValid():
              return None
  
          if role != Qt.DisplayRole and role != Qt.EditRole:
              return None
  
          item = self.getItem(index)
          return item.data(index.column())
  
      def flags(self, index):
          if not index.isValid():
              return 0
  
          return Qt.ItemIsEditable | Qt.ItemIsEnabled | Qt.ItemIsSelectable
  
      def getItem(self, index):
          if index.isValid():
              item = index.internalPointer()
              if item:
                  return item
  
          return self.rootItem
  
      def headerData(self, section, orientation, role=Qt.DisplayRole):
          if orientation == Qt.Horizontal and role == Qt.DisplayRole:
              return self.rootItem.data(section)
  
          return None
  
      def index(self, row, column, parent=QModelIndex()):
          if parent.isValid() and parent.column() != 0:
              return QModelIndex()
  
          parentItem = self.getItem(parent)
          childItem = parentItem.child(row)
          if childItem:
              return self.createIndex(row, column, childItem)
          else:
              return QModelIndex()
  
      def insertColumns(self, position, columns, parent=QModelIndex()):
          self.beginInsertColumns(parent, position, position + columns - 1)
          success = self.rootItem.insertColumns(position, columns)
          self.endInsertColumns()
  
          return success
  
      def insertRows(self, position, rows, parent=QModelIndex()):
          parentItem = self.getItem(parent)
          self.beginInsertRows(parent, position, position + rows - 1)
          success = parentItem.insertChildren(position, rows,
                                              self.rootItem.columnCount())
          self.endInsertRows()
  
          return success
  
      def parent(self, index):
          if not index.isValid():
              return QModelIndex()
  
          childItem = self.getItem(index)
          parentItem = childItem.parent()
  
          if parentItem == self.rootItem:
              return QModelIndex()
  
          return self.createIndex(parentItem.childNumber(), 0, parentItem)
  
      def removeColumns(self, position, columns, parent=QModelIndex()):
          self.beginRemoveColumns(parent, position, position + columns - 1)
          success = self.rootItem.removeColumns(position, columns)
          self.endRemoveColumns()
  
          if self.rootItem.columnCount() == 0:
              self.removeRows(0, self.rowCount())
  
          return success
  
      def removeRows(self, position, rows, parent=QModelIndex()):
          parentItem = self.getItem(parent)
  
          self.beginRemoveRows(parent, position, position + rows - 1)
          success = parentItem.removeChildren(position, rows)
          self.endRemoveRows()
  
          return success
  
      def rowCount(self, parent=QModelIndex()):
          parentItem = self.getItem(parent)
  
          return parentItem.childCount()
  
      def setData(self, index, value, role=Qt.EditRole):
          if role != Qt.EditRole:
              return False
  
          item = self.getItem(index)
          result = item.setData(index.column(), value)
  
          if result:
              self.dataChanged.emit(index, index)
  
          return result
  
      def setHeaderData(self, section, orientation, value, role=Qt.EditRole):
          if role != Qt.EditRole or orientation != Qt.Horizontal:
              return False
  
          result = self.rootItem.setData(section, value)
          if result:
              self.headerDataChanged.emit(orientation, section, section)
  
          return result
  
      def setupModelData(self, nested_dict, parent):
          print(nested_dict)
          for k, v in nested_dict.items():
              if isinstance(v, dict):
                  parent.appendChild_by_data([k, None])
                  self.setupModelData(v, parent.child(parent.childCount() - 1))
              else:
                  parent.appendChild_by_data([k, v])
  
  
  class MainWindow(QMainWindow):
      """docstring for MainWindow"""
  
      def __init__(self, data, parent=None):
          super(MainWindow, self).__init__(parent=None)
  
          headersLabels = ("Key", "value")
          self.orginal_data = data
          print(data)
          self.m_model = TreeModel(headersLabels, data)
  
          self.container = QtWidgets.QWidget()
          self.m_view = QtWidgets.QTreeView()
          self.m_view.setModel(self.m_model)
  
          self.testButton = QtWidgets.QPushButton("Test")
          self.testButton.clicked.connect(self.testAction)
  
          self.buttonLayout = QHBoxLayout()
          self.buttonLayout.addWidget(self.testButton)
  
          self.container_layout = QtWidgets.QVBoxLayout()
          self.container_layout.addWidget(self.m_view)
          self.container_layout.addLayout(self.buttonLayout)
  
          self.container.setLayout(self.container_layout)
          self.setCentralWidget(self.container)
  
      def testAction(self):
  
          selceteds = self.m_view.selectedIndexes()
          print(selceteds)
          for i in selceteds:
              item = self.m_model.getItem(i)
              print(item.data(i.column()))
  
  
  if __name__ == '__main__':
      import sys
  
      _d = {"key1": 1, "key2": 0, "key3": {"key": 1}, "dupa": None}
  
      app = QApplication(sys.argv)
      window = MainWindow(_d)
      window.show()
      sys.exit(app.exec_())
  </code></pre>
  
  <p><em>I Hope my English is understanding enough</em></p>