Browse Source

started reorderable content list

Bachir Soussi Chiadmi 7 years ago
parent
commit
3a735013a4
2 changed files with 344 additions and 4 deletions
  1. 219 4
      classes/content.py
  2. 125 0
      classes/design.py

+ 219 - 4
classes/content.py

@@ -1,16 +1,231 @@
 #!/usr/bin/python
 # -*- coding: utf-8 -*-
 
+import sys, os
+
 from PyQt5 import QtCore
 from PyQt5.QtGui import QFont, QSyntaxHighlighter
-from PyQt5.QtWidgets import QWidget, QLabel, QTabWidget, QHBoxLayout, QSplitter, QPlainTextEdit
+from PyQt5.QtWidgets import QWidget, QLabel, QHBoxLayout, QVBoxLayout, QSplitter, QListView, QAbstractItemView
+
+import markdown
+import re
+import json
 
 
-class Summary(QLabel):
-   def __init__(self):
+class Summary(QWidget):
+   def __init__(self, core):
       super(Summary, self).__init__()
+      self.core = core
+
+      sum_json = open(os.path.join(self.core.cwd,'.config/summary.json')).read()
+      self.sum = json.loads(sum_json)
+
+      vbox = QVBoxLayout()
+      vbox.setContentsMargins(0,0,0,0)
+
+      self.list = SummaryList(self)
+      vbox.addWidget(self.list)
+
+      # self.actions = SummaryActions(self)
+      # self.addWidget(self.actions)
+
+      self.setLayout(vbox)
+
+class SumListModel(QtCore.QAbstractListModel):
+   dragDropFinished = QtCore.pyqtSignal()
+   def __init__(self,sum):
+      QtCore.QAbstractItemModel.__init__(self)
+      self.nodes = ['node0', 'node1', 'node2', 'node3', 'node4', 'node5']
+      self.lastDroppedItems = []
+      self.pendingRemoveRowsAfterDrop = False
+
+   def rowForItem(self, text):
+      '''
+      rowForItem method returns the row corresponding to the passed in item
+      or None if no such item exists in the model
+      '''
+      try:
+         row = self.nodes.index(text)
+      except ValueError:
+         return None
+      return row
+
+   def index(self, row, column, parent):
+      if row < 0 or row >= len(self.nodes):
+         return QtCore.QModelIndex()
+      return self.createIndex(row, column)
+
+   def parent(self, index):
+      return QtCore.QModelIndex()
+
+   def rowCount(self, index):
+      if index.isValid():
+         return 0
+      return len(self.nodes)
+
+   def data(self, index, role):
+      if not index.isValid():
+         return None
+      if role == QtCore.Qt.DisplayRole:
+         row = index.row()
+         if row < 0 or row >= len(self.nodes):
+             return None
+         return self.nodes[row]
+      else:
+         return None
+
+   def supportedDropActions(self):
+      return QtCore.Qt.MoveAction
+
+   def flags(self, index):
+      if not index.isValid():
+         return QtCore.Qt.ItemIsEnabled
+      return QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable | \
+            QtCore.Qt.ItemIsDragEnabled | QtCore.Qt.ItemIsDropEnabled
+
+   def insertRows(self, row, count, index):
+      if index.isValid():
+         return False
+      if count <= 0:
+         return False
+      # inserting 'count' empty rows starting at 'row'
+      self.beginInsertRows(QtCore.QModelIndex(), row, row + count - 1)
+      for i in range(0, count):
+         self.nodes.insert(row + i, '')
+      self.endInsertRows()
+      return True
+
+   def removeRows(self, row, count, index):
+      if index.isValid():
+         return False
+      if count <= 0:
+         return False
+      num_rows = self.rowCount(QtCore.QModelIndex())
+      self.beginRemoveRows(QtCore.QModelIndex(), row, row + count - 1)
+      for i in range(count, 0, -1):
+         self.nodes.pop(row - i + 1)
+      self.endRemoveRows()
+
+      if self.pendingRemoveRowsAfterDrop:
+         '''
+         If we got here, it means this call to removeRows is the automatic
+         'cleanup' action after drag-n-drop performed by Qt
+         '''
+         self.pendingRemoveRowsAfterDrop = False
+         self.dragDropFinished.emit()
+
+      return True
+
+   def setData(self, index, value, role):
+      if not index.isValid():
+         return False
+      if index.row() < 0 or index.row() > len(self.nodes):
+         return False
+      self.nodes[index.row()] = str(value)
+      self.dataChanged.emit(index, index)
+      return True
+
+   def mimeTypes(self):
+      return ['application/vnd.treeviewdragdrop.list']
+
+   def mimeData(self, indexes):
+      mimedata = QtCore.QMimeData()
+      encoded_data = QtCore.QByteArray()
+      stream = QtCore.QDataStream(encoded_data, QtCore.QIODevice.WriteOnly)
+      for index in indexes:
+         if index.isValid():
+             text = self.data(index, 0)
+      stream << QtCore.QByteArray(text.encode('utf-8'))
+      mimedata.setData('application/vnd.treeviewdragdrop.list', encoded_data)
+      return mimedata
+
+   def dropMimeData(self, data, action, row, column, parent):
+      if action == QtCore.Qt.IgnoreAction:
+         return True
+      if not data.hasFormat('application/vnd.treeviewdragdrop.list'):
+         return False
+      if column > 0:
+         return False
+
+      num_rows = self.rowCount(QtCore.QModelIndex())
+      if num_rows <= 0:
+         return False
+
+      if row < 0:
+         if parent.isValid():
+            row = parent.row()
+         else:
+            return False
+
+      encoded_data = data.data('application/vnd.treeviewdragdrop.list')
+      stream = QtCore.QDataStream(encoded_data, QtCore.QIODevice.ReadOnly)
+
+      new_items = []
+      rows = 0
+      while not stream.atEnd():
+         text = QtCore.QByteArray()
+         stream >> text
+         text = bytes(text).decode('utf-8')
+         index = self.nodes.index(text)
+         new_items.append((text, index))
+         rows += 1
+
+      self.lastDroppedItems = []
+      for (text, index) in new_items:
+         target_row = row
+         if index < row:
+            target_row += 1
+         self.beginInsertRows(QtCore.QModelIndex(), target_row, target_row)
+         self.nodes.insert(target_row, text)
+         self.endInsertRows()
+         self.lastDroppedItems.append(text)
+         row += 1
+
+      self.pendingRemoveRowsAfterDrop = True
+      return True
+
+class SumListSelectionModel(QtCore.QItemSelectionModel):
+   def __init__(self, parent=None):
+      QtCore.QItemSelectionModel.__init__(self, parent)
+
+   def onModelItemsReordered(self):
+      new_selection = QtCore.QItemSelection()
+      new_index = QtCore.QModelIndex()
+      for item in self.model().lastDroppedItems:
+         row = self.model().rowForItem(item)
+         if row is None:
+            continue
+         new_index = self.model().index(row, 0, QtCore.QModelIndex())
+         new_selection.select(new_index, new_index)
+
+      self.clearSelection()
+      flags = QtCore.QItemSelectionModel.ClearAndSelect | \
+              QtCore.QItemSelectionModel.Rows | \
+              QtCore.QItemSelectionModel.Current
+      self.select(new_selection, flags)
+      self.setCurrentIndex(new_index, flags)
+
+class SummaryList(QListView):
+   def __init__(self,prt):
+      super(SummaryList, self).__init__()
+      print("list")
+      self.prt = prt
+      model = SumListModel(sum)
+      selectionModel = SumListSelectionModel(model)
+      model.dragDropFinished.connect(selectionModel.onModelItemsReordered)
+      self.setModel(model)
+      self.setSelectionModel(selectionModel)
+      self.setDragDropMode(QAbstractItemView.InternalMove)
+      self.setDragDropOverwriteMode(False)
+
 
+class SummaryActions(QWidget):
+   def __init__(self,sum):
+      print("actions")
+      # for p in self.sum:
 
+# class SummaryActions():
+#    def
 
 class ContentStack(QWidget):
    def __init__(self, core):
@@ -23,7 +238,7 @@ class ContentStack(QWidget):
 
       hsplitter = QSplitter(QtCore.Qt.Horizontal)
 
-      self.summary = QLabel("Summary (markdown files list).")
+      self.summary = Summary(core)
       hsplitter.addWidget(self.summary)
 
       self.mdsource = QLabel("Content (markdown src).")

+ 125 - 0
classes/design.py

@@ -0,0 +1,125 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+import sys, os, re
+
+from PyQt5 import QtCore
+from PyQt5.QtCore import QUrl
+from PyQt5.QtGui import QKeySequence, QFont, QSyntaxHighlighter
+from PyQt5.QtWidgets import QWidget, QLabel, QTabWidget, QVBoxLayout, QHBoxLayout, QSplitter, QPlainTextEdit, QShortcut
+from PyQt5.QtWebKit import QWebSettings
+from PyQt5.QtWebKitWidgets import QWebView, QWebInspector
+
+
+class WebkitView(QWebView):
+   def __init__(self, port):
+      self.port = port
+      self.view = QWebView.__init__(self)
+      self.load(QUrl('http://localhost:'+str(self.port)))
+      self.settings().setAttribute(QWebSettings.DeveloperExtrasEnabled, True)
+      # self.settings().setAttribute(QWebSettings.PluginsEnabled, True)
+
+
+class WebkitInspector(QWebInspector):
+   def __init__(self, webkitview):
+      super(WebkitInspector, self).__init__()
+      self.webkitview = webkitview
+      self.setPage(self.webkitview.page())
+      # TODO: webkitinspector is disappearing when chaging tabs
+
+class CodeEditor(QPlainTextEdit):
+   def __init__(self, core, tabs, file=None):
+      super(CodeEditor, self).__init__()
+      self.core = core
+      self.tabs = tabs
+      # self.file = file
+      self.file = os.path.join(self.core.cwd,file)
+
+      self.insertPlainText(open(self.file, 'r').read())
+      self.changed = False
+      self.textChanged.connect(self.onTextChanged)
+
+      self.shortcut = QShortcut(QKeySequence("Ctrl+s"), self)
+      self.shortcut.activated.connect(self.save)
+
+   def onTextChanged(self):
+      # print('textChanged')
+      # print(self.toPlainText())
+      # open(self.file, 'w').write(self.toPlainText())
+      if not self.changed:
+         self.changed = True
+         i = self.tabs.currentIndex()
+         self.tabs.setTabText(i, "* "+self.tabs.tabText(i))
+
+   def save(self):
+      if self.changed:
+         open(self.file, 'w').write(self.toPlainText())
+         i = self.tabs.currentIndex()
+         self.tabs.setTabText(i, re.sub(r'^\*\s', '', self.tabs.tabText(i)))
+         self.changed = False
+         # TODO: how to combine file save and project save
+
+
+class Editor(QWidget):
+   def __init__(self, core):
+      super(Editor, self).__init__()
+      self.core = core
+
+      self.layout = QVBoxLayout(self)
+      self.layout.setContentsMargins(0,0,0,0)
+
+      # Initialize tab screen
+      self.tabs = QTabWidget()
+
+      self.scsstab = CodeEditor(core, self.tabs, 'assets/scss/styles.scss')
+      self.jstab = CodeEditor(core, self.tabs, 'assets/js/script.js')
+
+      # Add tabs
+      self.tabs.addTab(self.scsstab,"scss")
+      self.tabs.addTab(self.jstab,"js")
+
+      # Add tabs to widget
+      self.layout.addWidget(self.tabs)
+      self.setLayout(self.layout)
+
+      # font = QFont()
+      # font.setFamily('Courier')
+      # font.setFixedPitch(True)
+      # font.setPointSize(10)
+      # self.setFont(font)
+      # self.highlighter = Highlighter(self.document())
+      # https://pypi.python.org/pypi/QScintilla/2.9.2
+
+
+class DesignStack(QWidget):
+   def __init__(self, core):
+      super(DesignStack, self).__init__()
+
+      # self.grid = QGridLayout()
+      hbox = QHBoxLayout()
+      hbox.setContentsMargins(0,0,0,0)
+      self.setLayout(hbox)
+
+
+      # webviewbox = QVBoxLayout()
+      vsplitter = QSplitter(QtCore.Qt.Vertical)
+
+      self.webkitview = WebkitView(core.server.port)
+      vsplitter.addWidget(self.webkitview)
+
+      self.webkitinspector = WebkitInspector(self.webkitview)
+      vsplitter.addWidget(self.webkitinspector)
+
+      hsplitter = QSplitter(QtCore.Qt.Horizontal)
+      hsplitter.addWidget(vsplitter)
+
+      self.editor = Editor(core)
+      hsplitter.addWidget(self.editor)
+
+      hbox.addWidget(hsplitter)
+
+
+   # def onChanged(self, text):
+   #    print("ViewTba Layout Changed")
+   #    self.lbl.setText(text)
+   #    self.lbl.adjustSize()