class UndoableEditor(QWidget):
    def __init__(self):
        QWidget.__init__(self)
        self.filename = ""
        self.undoStack = QUndoStack()
        self.undo = FlatButton(":/images/undo_normal.png",
                               ":/images/undo_hover.png", "",
                               ":/images/undo_disabled.png")
        self.redo = FlatButton(":/images/redo_normal.png",
                               ":/images/redo_hover.png", "",
                               ":/images/redo_disabled.png")
        self.undo.setToolTip("Undo")
        self.redo.setToolTip("Redo")
        self.undo.setEnabled(False)
        self.redo.setEnabled(False)
        hbox = QHBoxLayout()
        hbox.addStretch(0)
        hbox.addWidget(self.undo)
        hbox.addWidget(self.redo)

        self.titleLabel = QLabel()
        fnt = self.titleLabel.font()
        fnt.setPointSize(20)
        fnt.setBold(True)
        self.titleLabel.setFont(fnt)
        self.layout = QGridLayout()
        self.layout.addWidget(self.titleLabel, 0, 0)
        self.layout.addLayout(hbox, 0, 2)
        self.setLayout(self.layout)

        #connect(self.redo, SIGNAL(clicked()), self, SLOT(redo()))
        #connect(self.undo, SIGNAL(clicked()), self, SLOT(undo()))
        #connect(self.undoStack, SIGNAL(canUndoChanged(bool)), self, SLOT(canUndoChanged(bool)))
        #connect(self.undoStack, SIGNAL(canRedoChanged(bool)), self, SLOT(canRedoChanged(bool)))
        #connect(self.undoStack, SIGNAL(undoTextChanged(QString)), self, SLOT(undoTextChanged(QString)))
        #connect(self.undoStack, SIGNAL(redoTextChanged(QString)), self, SLOT(redoTextChanged(QString)))

    def contentChanged(self, text):
        changeCommand = ChangeFileCommand(self, self.filename, text)
        self.undoStack.push(changeCommand)
Пример #2
0
class ContentList(QWidget):
    editContent = pyqtSignal(object)

    def __init__(self, site, type):
        QWidget.__init__(self)
        self.site = site
        self.addedContentName = ""
        self.type = type
        self.undoStack = QUndoStack()
        vbox = QVBoxLayout()
        layout = QGridLayout()
        titleLabel = QLabel()
        button = QPushButton()
        if self.type == ContentType.PAGE:
            button.setText("Add Page")
        else:
            button.setText("Add Post")
        button.setMaximumWidth(120)
        if self.type == ContentType.PAGE:
            titleLabel.setText("Pages")
        else:
            titleLabel.setText("Posts")
        fnt = titleLabel.font()
        fnt.setPointSize(20)
        fnt.setBold(True)
        titleLabel.setFont(fnt)

        self.undo = FlatButton(":/images/undo_normal.png",
                               ":/images/undo_hover.png", "",
                               ":/images/undo_disabled.png")
        self.redo = FlatButton(":/images/redo_normal.png",
                               ":/images/redo_hover.png", "",
                               ":/images/redo_disabled.png")
        self.undo.setToolTip("Undo")
        self.redo.setToolTip("Redo")
        self.undo.setEnabled(False)
        self.redo.setEnabled(False)
        hbox = QHBoxLayout()
        hbox.addStretch(0)
        hbox.addWidget(self.undo)
        hbox.addWidget(self.redo)

        self.list = QTableWidget(0, 6, self)
        self.list.verticalHeader().hide()
        self.list.setSelectionMode(QAbstractItemView.SingleSelection)
        self.list.setSelectionBehavior(QAbstractItemView.SelectRows)
        self.list.horizontalHeader().setSectionResizeMode(
            1, QHeaderView.Stretch)
        self.list.setToolTip("Double click to edit item")
        labels = ["", "Name", "Source", "Layout", "Author", "Date"]
        self.list.setHorizontalHeaderLabels(labels)

        self.reload()

        layout.addWidget(titleLabel, 0, 0)
        layout.addLayout(hbox, 0, 2)
        layout.addWidget(button, 1, 0)
        layout.addWidget(self.list, 2, 0, 1, 3)
        vbox.addLayout(layout)
        self.setLayout(vbox)

        button.clicked.connect(self.addPage)
        self.list.cellDoubleClicked.connect(self.tableDoubleClicked)
        self.redo.clicked.connect(self.doredo)
        self.undo.clicked.connect(self.doundo)
        self.undoStack.canUndoChanged.connect(self.canUndoChanged)
        self.undoStack.canRedoChanged.connect(self.canRedoChanged)
        self.undoStack.redoTextChanged.connect(self.redoTextChanged)

    def reload(self):
        self.list.setRowCount(0)
        row = -1

        itemToEdit = None
        if self.type == ContentType.PAGE:
            self.site.loadPages()
            for i in range(len(self.site.pages)):
                content = self.site.pages[i]
                self.addListItem(content)
                if content.source == self.addedContentName:
                    row = self.list.rowCount() - 1
                    itemToEdit = self.list.item(row, 1)
        else:
            self.site.loadPosts()
            for i in range(0, len(self.site.posts)):
                content = self.site.posts[i]
                self.addListItem(content)
                if content.source == self.addedContentName:
                    row = self.list.rowCount() - 1

        if itemToEdit:
            self.addedContentName = ""
            self.list.selectRow(row)
            self.editContent.emit(itemToEdit)

    def addListItem(self, content):
        rows = self.list.rowCount()
        self.list.setRowCount(rows + 1)
        tcb = TableCellButtons()
        tcb.setItem(content)
        tcb.deleteItem.connect(self.deleteContent)
        tcb.editItem.connect(self.edit)
        self.list.setCellWidget(rows, 0, tcb)
        self.list.setRowHeight(rows, tcb.sizeHint().height())
        titleItem = QTableWidgetItem(content.title)
        titleItem.setFlags(titleItem.flags() ^ Qt.ItemIsEditable)
        titleItem.setData(Qt.UserRole, content)
        self.list.setItem(rows, 1, titleItem)

        sourceItem = QTableWidgetItem(content.source)
        sourceItem.setFlags(titleItem.flags() ^ Qt.ItemIsEditable)
        self.list.setItem(rows, 2, sourceItem)

        layoutItem = QTableWidgetItem(content.layout)
        layoutItem.setFlags(layoutItem.flags() ^ Qt.ItemIsEditable)
        self.list.setItem(rows, 3, layoutItem)

        authorItem = QTableWidgetItem(content.author)
        authorItem.setFlags(authorItem.flags() ^ Qt.ItemIsEditable)
        self.list.setItem(rows, 4, authorItem)
        dateItem = QTableWidgetItem(content.date.toString("dd.MM.yyyy"))
        dateItem.setFlags(dateItem.flags() ^ Qt.ItemIsEditable)
        self.list.setItem(rows, 5, dateItem)

    def canUndoChanged(self, can):
        self.undo.setEnabled(can)

    def canRedoChanged(self, can):
        self.redo.setEnabled(can)

    def undoTextChanged(self, text):
        self.undo.setToolTip("Undo " + text)

    def redoTextChanged(self, text):
        self.redo.setToolTip("Redo " + text)

    def doundo(self):
        self.undoStack.undo()

    def doredo(self):
        self.undoStack.redo()

    def addPage(self):
        self.addedContentName = self.site.createTemporaryContent(self.type)
        info = QFileInfo(self.addedContentName)
        self.addedContentName = info.fileName()
        self.reload()

    def tableDoubleClicked(self, r, i):
        item = self.list.item(r, 1)
        self.undoStack.clear()
        self.editContent.emit(item)

    def edit(self, content):
        for row in range(self.list.rowCount()):
            item = self.list.item(row, 1)
            m = item.data(Qt.UserRole)
            if m == content:
                self.list.selectRow(row)
                self.undoStack.clear()
                self.editContent.emit(item)
                break

    def deleteContent(self, content):
        for row in range(self.list.rowCount()):
            item = self.list.item(row, 1)
            m = item.data(Qt.UserRole)
            if m == content:
                if m.content_type == ContentType.PAGE:
                    subdir = "pages"
                else:
                    subdir = "posts"
                delCommand = DeleteContentCommand(
                    self, os.path.join(self.site.source_path, subdir,
                                       m.source), "delete content " + m.title)
                self.undoStack.push(delCommand)
                break
Пример #3
0
class MenuEditorTableCellButtons(QWidget):
    deleteItem = pyqtSignal(object)
    editItem = pyqtSignal(object)
    itemLeft = pyqtSignal(object)
    itemRight = pyqtSignal(object)
    itemUp = pyqtSignal(object)
    itemDown = pyqtSignal(object)

    def __init__(self):
        QWidget.__init__(self)
        self.delete = FlatButton(":/images/trash_normal.png",
                                 ":/images/trash_hover.png")
        self.edit = FlatButton(":/images/edit_normal.png",
                               ":/images/edit_hover.png")
        self.left = FlatButton(":/images/left_normal.png",
                               ":/images/left_hover.png", "",
                               ":/images/left_disabled.png")
        self.right = FlatButton(":/images/right_normal.png",
                                ":/images/right_hover.png", "",
                                ":/images/right_disabled.png")
        self.up = FlatButton(":/images/up_normal.png", ":/images/up_hover.png",
                             "", ":/images/up_disabled.png")
        self.down = FlatButton(":/images/down_normal.png",
                               ":/images/down_hover.png", "",
                               ":/images/down_disabled.png")
        self.edit.setToolTip("Edit Item")
        self.delete.setToolTip("Delete Item")
        self.left.setToolTip("Make Mainitem")
        self.right.setToolTip("Make Subitem")
        self.up.setToolTip("Sort Up")
        self.down.setToolTip("Sort Down")
        self.left.setEnabled(False)
        self.right.setEnabled(False)
        self.up.setEnabled(False)
        self.down.setEnabled(False)
        self.item = None

        hbox = QHBoxLayout()
        hbox.addWidget(self.edit)
        hbox.addWidget(self.up)
        hbox.addWidget(self.down)
        hbox.addWidget(self.left)
        hbox.addWidget(self.right)
        hbox.addWidget(self.delete)
        self.setLayout(hbox)

        self.delete.clicked.connect(self.deleteItemClicked)
        self.edit.clicked.connect(self.editItemClicked)
        self.left.clicked.connect(self.itemLeftClicked)
        self.right.clicked.connect(self.itemRightClicked)
        self.up.clicked.connect(self.itemUpClicked)
        self.down.clicked.connect(self.itemDownClicked)

    def setMenuItem(self, m):
        self.item = m

    def deleteItemClicked(self):
        self.deleteItem.emit(self.item)

    def editItemClicked(self):
        self.editItem.emit(self.item)

    def itemLeftClicked(self):
        self.itemLeft.emit(self.item)

    def itemRightClicked(self):
        self.itemRight.emit(self.item)

    def itemUpClicked(self):
        self.itemUp.emit(self.item)

    def itemDownClicked(self):
        self.itemDown.emit(self.item)

    def setEnableLeft(self, mode):
        self.left.setEnabled(mode)

    def setEnableRight(self, mode):
        self.right.setEnabled(mode)

    def setEnableUp(self, mode):
        self.up.setEnabled(mode)

    def setEnableDown(self, mode):
        self.down.setEnabled(mode)
Пример #4
0
class MenuEditor(AnimateableEditor):
    contentChanged = pyqtSignal(object)
    menuChanged = pyqtSignal(str)

    def __init__(self, win, menu, site):
        AnimateableEditor.__init__(self)
        self.win = win
        self.menu = menu
        self.site = site
        self.changed = False

        self.setAutoFillBackground(True)

        titleLabel = QLabel("Menu Editor")
        fnt = titleLabel.font()
        fnt.setPointSize(20)
        fnt.setBold(True)
        titleLabel.setFont(fnt)

        self.close = FlatButton(":/images/close_normal.png",
                                ":/images/close_hover.png")
        self.close.setToolTip("Close Content Editor")
        self.undo = FlatButton(":/images/undo_normal.png",
                               ":/images/undo_hover.png", "",
                               ":/images/undo_disabled.png")
        self.redo = FlatButton(":/images/redo_normal.png",
                               ":/images/redo_hover.png", "",
                               ":/images/redo_disabled.png")
        self.undo.setToolTip("Undo")
        self.redo.setToolTip("Redo")
        self.undo.setEnabled(False)
        self.redo.setEnabled(False)
        hbox = QHBoxLayout()
        hbox.addStretch(0)
        hbox.addWidget(self.undo)
        hbox.addWidget(self.redo)
        hbox.addWidget(self.close)

        addButton = QPushButton("Add Menuitem")
        addButton.setMaximumWidth(120)

        self.name = QLineEdit()
        self.name.setText(menu.name)
        self.name.setMaximumWidth(200)

        labels = ["Title", "Url", "Icon", "", "Sort"]

        self.tree = QTreeWidget()
        self.tree.setHeaderLabels(labels)
        self.tree.header().setSectionResizeMode(0, QHeaderView.Stretch)
        self.tree.header().hideSection(4)
        self.tree.setSelectionMode(QAbstractItemView.NoSelection)
        self.tree.setToolTip("Double Click To Edit")
        self.tree.setColumnWidth(2, 40)

        layout = QGridLayout()
        layout.addWidget(titleLabel, 0, 0)
        layout.addLayout(hbox, 0, 2)
        layout.addWidget(QLabel("Name"), 1, 0)
        layout.addWidget(self.name, 2, 0)
        layout.addWidget(addButton, 3, 0)
        layout.addWidget(self.tree, 4, 0, 1, 3)
        self.setLayout(layout)

        self.reloadMenu(menu)

        addButton.clicked.connect(self.addButtonClicked)
        self.close.clicked.connect(self.closeEditor)
        self.name.editingFinished.connect(self.nameChanged)
        self.redo.clicked.connect(self.redoEdit)
        self.undo.clicked.connect(self.undoEdit)
        self.tree.itemChanged.connect(self.itemChanged)

    def reloadMenu(self, menu):
        if not menu:
            self.close.emit()
            return

        self.menu = menu
        self.tree.clear()

        self.name.setText(menu.name)
        for i in range(0, len(self.menu.items)):
            item = self.menu.items[i]
            self.addTreeItem(item)

        self.tree.expandAll()
        self.tree.sortItems(4, Qt.AscendingOrder)
        self.updateButtonStates()

    def addTreeItem(self, item):
        twi = QTreeWidgetItem()
        twi.setFlags(twi.flags() | Qt.ItemIsEditable)
        twi.setText(0, item.title)
        twi.setText(1, item.url)

        twi.setText(4, str(self.tree.topLevelItemCount()))
        twi.setData(0, Qt.UserRole, item)
        self.tree.addTopLevelItem(twi)
        self.addTableCellButtons(item, twi)

        for i in range(len(item.items)):
            sub = item.items[i]
            stwi = QTreeWidgetItem()
            stwi.setFlags(stwi.flags() | Qt.ItemIsEditable)
            stwi.setText(0, sub.title)
            stwi.setText(1, sub.url)
            stwi.setText(4, str(i))
            stwi.setData(0, Qt.UserRole, sub)
            twi.addChild(stwi)
            self.addTableCellButtons(sub, stwi)

    def addTableCellButtons(self, item, twi):
        tcb = MenuEditorTableCellButtons()
        tcb.setMenuItem(item)
        self.tree.setItemWidget(twi, 3, tcb)
        self.tree.setColumnWidth(3, tcb.sizeHint().width())
        if item.isSubitem():
            tcb.deleteItem.connect(self.deleteSubItem)
            tcb.itemLeft.connect(self.itemLeft)
        else:
            tcb.deleteItem.connect(self.deleteItem)
            tcb.itemUp.connect(self.itemUp)
            tcb.itemDown.connect(self.itemDown)
            tcb.itemRight.connect(self.itemRight)
            tcb.editItem.connect(self.editItem)

        imgs = ImageSelector()
        imgs.setToolTip("Click to select image, right click to reset image")
        imgs.setItem(item)
        imgs.setMaximumSize(24, 24)
        isw = QWidget()
        vbox = QVBoxLayout()
        vbox.addWidget(imgs)
        isw.setLayout(vbox)
        if not item.icon:
            imgs.setImage(QImage(":/images/image_placeholder.png"))
        else:
            imgs.setImage(QImage(self.site.source_path + "/" + item.icon))
        self.tree.setItemWidget(twi, 2, isw)
        imgs.clicked.connect(self.iconClicked)

    def registerUndoStack(self, stack):
        self.undoStack = stack
        self.undoStack.canUndoChanged.connect(self.canUndoChanged)
        self.undoStack.canRedoChanged.connect(self.canRedoChanged)
        self.undoStack.undoTextChanged.connect(self.undoTextChanged)
        self.undoStack.redoTextChanged.connect(self.redoTextChanged)
        self.undo.setEnabled(self.undoStack.canUndo())
        self.redo.setEnabled(self.undoStack.canRedo())
        self.undo.setToolTip("Undo " + self.undoStack.undoText())
        self.redo.setToolTip("Redo " + self.undoStack.redoText())

    def canUndoChanged(self, can):
        self.undo.setEnabled(can)

    def canRedoChanged(self, can):
        self.redo.setEnabled(can)

    def undoTextChanged(self, text):
        self.undo.setToolTip("Undo " + text)

    def redoTextChanged(self, text):
        self.redo.setToolTip("Redo " + text)

    def getUndoRedoText(self, item, action):
        return "menuitem (" + item.title + ") from menu (" + self.menu.name + ") " + action

    def undoEdit(self):
        self.undoStack.undo()

    def redoEdit(self):
        self.undoStack.redo()

    def addButtonClicked(self):
        menuitem = MenuItem()
        self.menu.addMenuitem(menuitem)
        self.addTreeItem(menuitem)
        self.menuChanged.emit(self.getUndoRedoText(menuitem, "added"))

        self.updateButtonStates()
        item = self.tree.topLevelItem(self.getRow(menuitem))
        self.tree.editItem(item, 0)

    def closeEditor(self):
        self.closes.emit()

    def nameChanged(self):
        if self.menu.name != self.name.text:
            action = "menu name changed from \"" + self.menu.name + "\" to \"" + self.name.text + "\""
            self.menu.setName(self.name.text())
            self.contentChanged.emit(self.menu)
            self.menuChanged.emit(action)

    def itemChanged(self, twi, column):
        action = ""
        item = twi.data(0, Qt.UserRole)
        if column == 0:
            item.title = twi.text(0)
            action = "title changed"
        elif column == 1:
            item.url = twi.text(1)
            action = "url changed"
        self.menuChanged.emit(self.getUndoRedoText(item, action))

    def getRow(self, menuitem):
        for i in range(0, self.tree.topLevelItemCount()):
            item = self.tree.topLevelItem(i)
            mi = item.data(0, Qt.UserRole)
            if mi == menuitem:
                return i
        return -1

    def deleteSubItem(self, menuitem):
        row = self.getRow(menuitem.parentItem)
        parent = self.tree.topLevelItem(row)
        if parent:
            for i in range(0, parent.childCount()):
                child = parent.child(i)
                mi = child.data(0, Qt.UserRole)
                if mi == menuitem:
                    parent.removeChild(child)
                    del child
                    break

        if menuitem.parentItem:
            menuitem.parentItem.removeMenuitem(menuitem)

        self.updateButtonStates()
        self.menuChanged.emit(self.getUndoRedoText(menuitem, "deleted"))

    def itemLeft(self, menuitem):
        row = self.getRow(menuitem.parentItem())
        parent = self.tree.topLevelItem(row)
        for i in range(parent.childCount()):
            child = parent.child(i)
            mi = child.data(0, Qt.UserRole)
            if mi == menuitem:
                menuitem.parentItem().removeMenuitem(menuitem)
                menuitem.setSubitem(False)
                self.menu.addMenuitem(menuitem)
                parent.takeChild(i)
                self.addTreeItem(menuitem)
                break

        self.updateButtonStates()
        self.menuChanged.emit(
            self.getUndoRedoText(menuitem, "changed to top item"))

    def iconClicked(self, itemselector, button):
        mi = itemselector.item()
        action = ""
        if button == Qt.LeftButton:
            fileName = ""
            dialog = QFileDialog()
            dialog.setFileMode(QFileDialog.AnyFile)
            dialog.setNameFilter("Images (*.png *.gif *.jpg)All (*)")
            dialog.setWindowTitle("Load Image")
            dialog.setOption(QFileDialog.DontUseNativeDialog, True)
            dialog.setAcceptMode(QFileDialog.AcceptOpen)
            if dialog.exec_():
                fileName = dialog.selectedFiles().first()
            del dialog
            if not fileName:
                return

            # copy file to assets dir
            info = QFileInfo(fileName)
            name = info.fileName().replace(" ", "_")
            path = self.site.source_path + "/assets/images/" + name
            QFile.copy(fileName, path)

            # also copy file to deploy dir for previews
            dpath = self.site.deploy_path + "/assets/images/" + name
            QFile.copy(fileName, dpath)

            mi.setIcon(path.mid(path.indexOf("assets/images/")))
            itemselector.setImage(QImage(path))
            action = "icon changed"

        elif button == Qt.RightButton:
            action = "icon removed"
            mi.setIcon("")
            itemselector.setImage(QImage(":/images/image_placeholder.png"))

        self.menuChanged.emit(self.getUndoRedoText(mi, action))

    def updateButtonStates(self):
        for i in range(0, self.tree.topLevelItemCount()):
            twi = self.tree.topLevelItem(i)
            tcb = self.tree.itemWidget(twi, 3)
            menuitem = twi.data(0, Qt.UserRole)
            tcb.setEnableDown(i != self.tree.topLevelItemCount() - 1)
            tcb.setEnableUp(i != 0)
            tcb.setEnableRight(i != 0 and len(menuitem.items) == 0)
            tcb.setEnableLeft(False)
            for j in range(0, twi.childCount()):
                stwi = twi.child(j)
                stcb = self.tree.itemWidget(stwi, 3)
                stcb.setEnableLeft(True)
Пример #5
0
class ContentEditor(AnimateableEditor):
    contentChanged = pyqtSignal(object)
    preview = pyqtSignal(object)

    def __init__(self, win, site, content):
        AnimateableEditor.__init__(self)

        self.win = win
        self.site = site
        self.content = content
        self.is_new = False
        self.editor = None
        self.undoStack = QUndoStack()
        self.changed = False
        self.setAutoFillBackground(True)

        self.previewLink = HyperLink("")
        self.vbox = QVBoxLayout()
        self.layout = QGridLayout()
        self.titleLabel = QLabel()

        fnt = self.titleLabel.font()
        fnt.setPointSize(20)
        fnt.setBold(True)
        self.titleLabel.setFont(fnt)
        self.script = QPushButton("Page Script")
        self.title = QLineEdit()
        self.source = QLineEdit()
        self.source.setPlaceholderText("*.qml")
        self.excerpt = QLineEdit()
        self.date = QLineEdit()
        self.labelPermalink = QLabel("Permalink")
        self.labelTitle = QLabel("Title")
        self.labelAuthor = QLabel("Author")
        self.labelKeyword = QLabel("Keywords")
        self.labelLayout = QLabel("Layout")
        self.labelMenu = QLabel("Menu")
        self.author = QLineEdit()
        self.keywords = QLineEdit()
        self.menus = QComboBox()
        self.layouts = QComboBox()
        self.layouts.setMaximumWidth(100)

        for menu in self.site.menus.menus:
            self.menus.addItem(menu.name)

        for root, dirs, files in os.walk(
                os.path.join(self.site.source_path, "layouts")):
            for file in files:
                self.layouts.addItem(Path(file).stem)

        for root, dirs, files in os.walk(
                os.path.join(Generator.themesPath(), self.site.theme,
                             "layouts")):
            for file in files:
                self.layouts.addItem(Path(file).stem)

        self.close = FlatButton(":/images/close_normal.png",
                                ":/images/close_hover.png")
        self.close.setToolTip("Close Content Editor")
        self.undo = FlatButton(":/images/undo_normal.png",
                               ":/images/undo_hover.png", "",
                               ":/images/undo_disabled.png")
        self.redo = FlatButton(":/images/redo_normal.png",
                               ":/images/redo_hover.png", "",
                               ":/images/redo_disabled.png")
        self.undo.setToolTip("Undo")
        self.redo.setToolTip("Redo")
        self.undo.setEnabled(False)
        self.redo.setEnabled(False)
        hbox = QHBoxLayout()
        hbox.addWidget(self.undo)
        hbox.addWidget(self.redo)
        hbox.addWidget(self.close)

        self.scroll = QScrollArea()
        self.scroll.setHorizontalScrollBarPolicy(Qt.ScrollBarAsNeeded)
        self.scroll.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded)
        self.scroll.setWidgetResizable(True)
        self.scroll.installEventFilter(self)
        self.layout.addWidget(self.titleLabel, 0, 0)
        self.layout.addWidget(self.previewLink, 0, 1)
        self.layout.addLayout(hbox, 0, 3)
        self.layout.addWidget(self.labelTitle, 1, 0)
        self.layout.addWidget(self.title, 2, 0)
        self.layout.addWidget(self.labelPermalink, 1, 1)
        self.layout.addWidget(self.source, 2, 1)
        self.layout.addWidget(self.labelAuthor, 3, 0)
        self.layout.addWidget(self.author, 4, 0)
        self.layout.addWidget(self.labelKeyword, 3, 1)
        self.layout.addWidget(self.keywords, 4, 1)
        self.layout.addWidget(self.labelMenu, 3, 2)
        self.layout.addWidget(self.menus, 4, 2)
        self.layout.addWidget(self.labelLayout, 3, 3)
        self.layout.addWidget(self.layouts, 4, 3)
        self.layout.addWidget(self.scroll, 7, 0, 1, 4)
        self.layout.addWidget(self.script, 8, 0, 1, 4)
        self.vbox.addLayout(self.layout)
        self.setLayout(self.vbox)

        if self.content.content_type == ContentType.POST:
            self.previewLink.setText("view post")
            self.excerptLabel = QLabel("Excerpt")
            self.layout.addWidget(self.excerptLabel, 5, 0)
            self.layout.addWidget(self.excerpt, 6, 0, 1, 2)
            self.datelabel = QLabel("Date")
            self.layout.addWidget(self.datelabel, 5, 2)
            self.layout.addWidget(self.date, 6, 2, 1, 2)
            self.filename = self.site.source_path + "/posts/" + content.source
        else:
            self.previewLink.setText("view page")
            self.filename = self.site.source_path + "/pages/" + content.source

        self.load()

        self.close.clicked.connect(self.closeEditor)
        self.title.editingFinished.connect(self.titleFinished)
        self.title.textChanged.connect(self.titleChanged)
        self.source.editingFinished.connect(self.sourceChanged)
        self.excerpt.editingFinished.connect(self.excerptChanged)
        self.date.editingFinished.connect(self.dateChanged)
        self.author.editingFinished.connect(self.authorChanged)
        self.keywords.editingFinished.connect(self.keywordsChanged)
        self.menus.currentTextChanged.connect(self.menuChanged)
        self.layouts.currentTextChanged.connect(self.layoutChanged)
        self.undoStack.canUndoChanged.connect(self.canUndoChanged)
        self.undoStack.canRedoChanged.connect(self.canRedoChanged)
        self.undoStack.undoTextChanged.connect(self.undoTextChanged)
        self.undoStack.redoTextChanged.connect(self.redoTextChanged)
        self.undo.clicked.connect(self.undoAction)
        self.redo.clicked.connect(self.redoAction)
        self.previewLink.clicked.connect(self.previewPage)
        self.script.clicked.connect(self.scriptClicked)

    def scriptClicked(self):
        self.editor = Plugins.element_plugins["TextEditor"]
        self.editor.setContent(None)
        self.editor.setText(self.content.script)
        self.editor.setCaption("Page Script")
        self.editor.close.connect(self.scriptEditorClose)
        self.animate(self.scroll.widget().placeholder)

    def scriptEditorClose(self):
        if self.editor and self.editor.changed:
            self.content.script = self.editor.getText()
            self.editChanged("Update Script")
            self.editor.close.disconnect()
        self.editorClosed()

    def previewPage(self):
        self.preview.emit(self.content)

    def rowEdit(self, re):
        from widgets.rowpropertyeditor import RowPropertyEditor

        self.row_editor = re
        self.editor = RowPropertyEditor()
        self.editor.setRow(re.row)
        self.editor.close.connect(self.rowEditorClose)
        self.animate(re)

    def rowEditorClose(self):
        if self.editor and self.editor.changed:
            self.row_editor.load(self.editor.row)
            self.editChanged("Update Row")
            self.editor.close.disconnect()
        self.editorClosed()

    def canUndoChanged(self, can):
        self.undo.setEnabled(can)

    def canRedoChanged(self, can):
        self.redo.setEnabled(can)

    def undoTextChanged(self, text):
        self.undo.setToolTip("Undo " + text)

    def redoTextChanged(self, text):
        self.redo.setToolTip("Redo " + text)

    def undoAction(self):
        self.undoStack.undo()

    def redoAction(self):
        self.undoStack.redo()

    def menuChanged(self, menu):
        if menu != self.content.menu:
            self.content.menu = menu
            self.contentChanged.emit(self.content)
            self.editChanged("Menu Changed")

    def layoutChanged(self, layout):
        if layout != self.content.layout:
            self.content.layout = layout
            self.contentChanged.emit(self.content)
            self.editChanged("Layout Changed")

    def keywordsChanged(self):
        if self.keywords.text() != self.content.keywords:
            self.content.keywords = self.keywords.text()
            self.contentChanged.emit(self.content)
            self.editChanged("Keywords Changed")

    def authorChanged(self):
        if self.author.text() != self.content.author:
            self.content.author = self.author.text()
            self.contentChanged.emit(self.content)
            self.editChanged("Author Changed")

    def excerptChanged(self):
        if self.excerpt.text() != self.content.excerpt:
            self.content.excerpt = self.excerpt.text()
            self.contentChanged.emit(self.content)
            self.editChanged("Excerpt Changed")

    def dateChanged(self):
        if self.date.text() != self.content.date.toString("dd.MM.yyyy"):
            self.content.date = QDate.fromString(self.date.text(),
                                                 "dd.MM.yyyy")
            self.contentChanged.emit(self.content)
            self.editChanged("Date Changed")

    def sourceChanged(self):
        if self.source.text() != self.content.source:
            oldname = self.filename
            self.content.source = self.source.text()
            if self.content.content_type == ContentType.PAGE:
                self.filename = self.site.source_path + "/pages/" + self.content.source
            else:
                self.filename = self.site.source_path + "/posts/" + self.content.source

            self.contentChanged.emit(self.content)

            renameCommand = RenameContentCommand(self, oldname, self.filename,
                                                 "content file renamed")
            self.undoStack.push(renameCommand)

    def titleChanged(self, title):
        if self.is_new:
            source = title.lower().replace(" ", "_") + ".qml"
            self.source.setText(source)

    def titleFinished(self):
        if self.title.text() != self.content.title:
            if self.is_new:
                self.sourceChanged()
            self.content.title = self.title.text()
            self.contentChanged.emit(self.content)
            self.editChanged("Titel Changed")

    def sectionEdit(self, se):
        self.section_editor = se

        self.editor = SectionPropertyEditor()
        self.editor.setSection(se.section)
        self.editor.close.connect(self.sectionEditorClose)
        self.animate(se)

    def sectionEditorClose(self):
        if self.editor.changed:
            self.section_editor.setSection(self.editor.section)
            self.editChanged("Update Section")
            self.editor.close.disconnect()
        self.editorClosed()

    def load(self):
        from widgets.sectioneditor import SectionEditor
        self.content = self.site.loadContent(self.content.source,
                                             self.content.content_type)
        self.is_new = not self.content.title
        self.title.setText(self.content.title)
        self.source.setText(self.content.source)
        self.author.setText(self.content.author)
        self.keywords.setText(self.content.keywords)
        self.menus.setCurrentText(self.content.menu)
        self.layouts.setCurrentText(self.content.layout)
        if self.content.content_type == ContentType.POST:
            self.excerpt.setText(self.content.excerpt)
            self.date.setText(self.content.date.toString("dd.MM.yyyy"))

        pe = PageEditor()
        self.scroll.setWidget(pe)
        for item in self.content.items:
            if isinstance(item, Section):
                se = SectionEditor(item.fullwidth)
                se.load(item)
                pe.addSection(se)
            # todo other types

    def siteLoaded(self, site):
        self.site = site
        if self.content.contentType == ContentType.PAGE:
            for c in self.site.pages:
                if c.source == self.content.source:
                    self.title.setText(c.title)
        else:
            for c in self.site.posts:
                if c.source == self.content.source:
                    self.excerpt.setText(c.excerpt)
                    self.title.setText(c.title)

    def closeEditor(self):
        if self.editor:
            self.editor.closeEditor()
        self.closes.emit()

    def elementEdit(self, ee):
        self.element_editor = ee
        plugin_name = ""
        if ee.type:
            plugin_name = Plugins.getElementPluginByTagname(ee.type)
        if plugin_name:
            self.editor = Plugins.element_plugins[plugin_name]
        else:
            self.editor = Plugins.element_plugins["TextEditor"]
            self.editor.setCaption("Text Module")
        self.editor.site = self.site
        self.editor.setContent(ee.getContent())
        self.editor.close.connect(self.editorClose)
        self.animate(ee)

    def animate(self, widget):
        self.sourcewidget = widget
        pos = widget.mapTo(self.scroll, QPoint(0, 0))

        self.editor.setParent(self.scroll)
        self.editor.move(pos)
        self.editor.resize(widget.size())
        self.editor.show()

        self.animationgroup = QParallelAnimationGroup()
        self.animx = QPropertyAnimation()
        self.animx.setDuration(300)
        self.animx.setStartValue(pos.x())
        self.animx.setEndValue(0)
        self.animx.setTargetObject(self.editor)
        self.animx.setPropertyName("x".encode("utf-8"))
        self.animationgroup.addAnimation(self.animx)
        self.animy = QPropertyAnimation()
        self.animy.setDuration(300)
        self.animy.setStartValue(pos.y())
        self.animy.setEndValue(0)
        self.animy.setTargetObject(self.editor)
        self.animy.setPropertyName("y".encode("utf-8"))
        self.animationgroup.addAnimation(self.animy)
        self.animw = QPropertyAnimation()
        self.animw.setDuration(300)
        self.animw.setStartValue(widget.size().width())
        self.animw.setEndValue(self.scroll.size().width())
        self.animw.setTargetObject(self.editor)
        self.animw.setPropertyName("width".encode("utf-8"))
        self.animationgroup.addAnimation(self.animw)
        self.animh = QPropertyAnimation()
        self.animh.setDuration(300)
        self.animh.setStartValue(widget.size().height())
        self.animh.setEndValue(self.scroll.size().height())
        self.animh.setTargetObject(self.editor)
        self.animh.setPropertyName("height".encode("utf-8"))
        self.animationgroup.addAnimation(self.animh)
        self.animationgroup.finished.connect(self.animationFineshedZoomIn)
        self.animationgroup.start()

    def animationFineshedZoomIn(self):
        self.scroll.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.scroll.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)

        self.title.setEnabled(False)
        self.author.setEnabled(False)
        self.keywords.setEnabled(False)
        self.menus.setEnabled(False)
        self.layouts.setEnabled(False)
        self.labelAuthor.setEnabled(False)
        self.labelKeyword.setEnabled(False)
        self.labelMenu.setEnabled(False)
        self.labelLayout.setEnabled(False)
        self.labelTitle.setEnabled(False)
        self.labelPermalink.setEnabled(False)
        self.previewLink.hide()
        self.undo.hide()
        self.redo.hide()
        self.close.hide()
        self.source.setEnabled(False)
        if self.content.content_type == ContentType.POST:
            self.excerpt.setEnabled(False)
            self.excerptLabel.setEnabled(False)
        self.animationgroup.finished.disconnect(self.animationFineshedZoomIn)

    def editorClose(self):
        if self.editor.changed:
            self.element_editor.setContent(self.editor.getContent())
            self.editChanged("Update Element")
        self.editor.close.disconnect()
        self.editorClosed()

    def editorClosed(self):
        self.scroll.setHorizontalScrollBarPolicy(Qt.ScrollBarAsNeeded)
        self.scroll.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded)
        pos = self.sourcewidget.mapTo(self.scroll, QPoint(0, 0))
        # correct end values in case of resizing the window
        self.animx.setStartValue(pos.x())
        self.animy.setStartValue(pos.y())
        self.animw.setStartValue(self.sourcewidget.size().width())
        self.animh.setStartValue(self.sourcewidget.size().height())
        self.animationgroup.setDirection(QAbstractAnimation.Backward)
        self.animationgroup.finished.connect(self.animationFineshedZoomOut)
        self.animationgroup.start()

    def animationFineshedZoomOut(self):
        from widgets.rowpropertyeditor import RowPropertyEditor
        from widgets.sectionpropertyeditor import SectionPropertyEditor

        self.title.setEnabled(True)
        self.source.setEnabled(True)
        self.author.setEnabled(True)
        self.keywords.setEnabled(True)
        self.menus.setEnabled(True)
        self.layouts.setEnabled(True)
        self.labelAuthor.setEnabled(True)
        self.labelKeyword.setEnabled(True)
        self.labelMenu.setEnabled(True)
        self.labelLayout.setEnabled(True)
        self.labelTitle.setEnabled(True)
        self.labelPermalink.setEnabled(True)
        self.previewLink.show()
        self.undo.show()
        self.redo.show()
        self.close.show()
        if self.content.content_type == ContentType.POST:
            self.excerpt.setEnabled(True)
            self.excerptLabel.setEnabled(True)
        del self.animationgroup
        self.editor.hide()
        # parent has to be set to NULL, otherwise the plugin will be dropped by parent
        self.editor.setParent(None)
        # only delete Row- and SectionPropertyEditor the other editors are plugins
        if isinstance(self.editor, RowPropertyEditor):
            del self.editor
        elif isinstance(self.editor, SectionPropertyEditor):
            self.editor.close.disconnect(self.sectionEditorClose)
            del self.editor
        self.editor = None

    def editChanged(self, text):
        changeCommand = ChangeContentCommand(self.win, self, text)
        self.undoStack.push(changeCommand)

    def save(self):
        self.content.save(self.filename)

    def contentRenamed(self, name):
        self.filename = name
        base = os.path.basename(name)
        self.source.setText(base)
        self.content.source = base