| #include "menubarpopup.h" |
| |
| |
| #include "tapp.h" |
| #include "mainwindow.h" |
| #include "menubar.h" |
| #include "shortcutpopup.h" |
| |
| |
| #include "toonzqt/gutil.h" |
| |
| |
| #include "toonz/toonzfolders.h" |
| |
| |
| #include "tsystem.h" |
| |
| |
| #include <QMainWindow> |
| #include <QPushButton> |
| #include <QVBoxLayout> |
| #include <QHBoxLayout> |
| #include <QGridLayout> |
| #include <QHeaderView> |
| #include <QtDebug> |
| #include <QXmlStreamReader> |
| #include <QXmlStreamWriter> |
| #include <QDataStream> |
| #include <QMimeData> |
| #include <QDrag> |
| #include <QMouseEvent> |
| #include <QPainter> |
| #include <QApplication> |
| #include <QLabel> |
| |
| |
| |
| |
| |
| class MenuBarCommandItem : public QTreeWidgetItem |
| { |
| QAction *m_action; |
| public: |
| MenuBarCommandItem(QTreeWidgetItem *parent, QAction *action) |
| : QTreeWidgetItem(parent, UserType), m_action(action) |
| { |
| setFlags(Qt::ItemIsSelectable | Qt::ItemIsDragEnabled | Qt::ItemIsEnabled | Qt::ItemNeverHasChildren); |
| setText(0, m_action->text().remove("&")); |
| setToolTip(0, QObject::tr("[Drag] to move position")); |
| } |
| QAction *getAction() const { return m_action; } |
| |
| }; |
| |
| |
| |
| |
| |
| class MenuBarSeparatorItem : public QTreeWidgetItem |
| { |
| public: |
| MenuBarSeparatorItem(QTreeWidgetItem *parent) |
| : QTreeWidgetItem(parent, UserType) |
| { |
| setFlags(Qt::ItemIsSelectable | Qt::ItemIsDragEnabled | Qt::ItemIsEnabled | Qt::ItemNeverHasChildren); |
| setText(0, QObject::tr("----Separator----")); |
| setToolTip(0, QObject::tr("[Drag] to move position")); |
| } |
| }; |
| |
| |
| |
| |
| |
| class MenuBarSubmenuItem : public QTreeWidgetItem |
| { |
| public: |
| MenuBarSubmenuItem(QTreeWidgetItem *parent, QString & title) |
| : QTreeWidgetItem(parent, UserType) |
| { |
| setFlags(Qt::ItemIsSelectable | Qt::ItemIsEditable | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled | Qt::ItemIsEnabled); |
| |
| setText(0, StackedMenuBar::tr(title.toStdString().c_str())); |
| QIcon subMenuIcon(":Resources/browser_folder_close.png"); |
| subMenuIcon.addFile(":Resources/browser_folder_open.png", QSize(), QIcon::Normal, QIcon::On); |
| setIcon(0, subMenuIcon); |
| setToolTip(0, QObject::tr("[Drag] to move position, [Double Click] to edit title")); |
| } |
| }; |
| |
| |
| |
| |
| |
| MenuBarTree::MenuBarTree(TFilePath & path, QWidget* parent) |
| : QTreeWidget(parent) |
| , m_path(path) |
| { |
| setObjectName("SolidLineFrame"); |
| setAlternatingRowColors(true); |
| setDragEnabled(true); |
| setDropIndicatorShown(true); |
| setDefaultDropAction(Qt::MoveAction); |
| setDragDropMode(QAbstractItemView::DragDrop); |
| |
| setColumnCount(1); |
| header()->close(); |
| |
| |
| TFilePath fp; |
| if (TFileStatus(path).isWritable()) |
| fp = m_path; |
| else |
| { |
| fp = m_path.withParentDir(ToonzFolder::getTemplateRoomsDir()); |
| if (!TFileStatus(path).isReadable()) |
| fp = ToonzFolder::getTemplateRoomsDir() + "menubar_template.xml"; |
| } |
| |
| loadMenuTree(fp); |
| } |
| |
| |
| |
| void MenuBarTree::loadMenuTree(const TFilePath& fp) |
| { |
| QFile file(toQString(fp)); |
| if (!file.open(QFile::ReadOnly | QFile::Text)){ |
| qDebug() << "Cannot read file" << file.errorString(); |
| return; |
| } |
| |
| QXmlStreamReader reader(&file); |
| |
| if (reader.readNextStartElement()) |
| { |
| if (reader.name() == "menubar") |
| { |
| while (reader.readNextStartElement()) |
| { |
| if (reader.name() == "menu") |
| { |
| QString title = reader.attributes().value("title").toString(); |
| MenuBarSubmenuItem *menu = new MenuBarSubmenuItem(0, title); |
| addTopLevelItem(menu); |
| loadMenuRecursive(reader, menu); |
| } |
| else if (reader.name() == "command") |
| { |
| QString cmdName = reader.readElementText(); |
| |
| QAction *action = CommandManager::instance()->getAction(cmdName.toStdString().c_str()); |
| if (action) |
| { |
| MenuBarCommandItem* item = new MenuBarCommandItem(0, action); |
| addTopLevelItem(item); |
| } |
| } |
| else |
| reader.skipCurrentElement(); |
| } |
| } |
| else |
| reader.raiseError(QObject::tr("Incorrect file")); |
| } |
| |
| if (reader.hasError()) |
| { |
| qDebug() << "Cannot read menubar xml"; |
| } |
| } |
| |
| |
| |
| void MenuBarTree::loadMenuRecursive(QXmlStreamReader& reader, QTreeWidgetItem* parentItem) |
| { |
| while (reader.readNextStartElement()) |
| { |
| if (reader.name() == "menu") |
| { |
| QString title = reader.attributes().value("title").toString(); |
| MenuBarSubmenuItem *subMenu = new MenuBarSubmenuItem(parentItem, title); |
| loadMenuRecursive(reader, subMenu); |
| } |
| else if (reader.name() == "command") |
| { |
| QString cmdName = reader.readElementText(); |
| QAction* action = CommandManager::instance()->getAction(cmdName.toStdString().c_str()); |
| if (action) |
| MenuBarCommandItem* item = new MenuBarCommandItem(parentItem, action); |
| } |
| else if (reader.name() == "command_debug") |
| { |
| #ifndef NDEBUG |
| QString cmdName = reader.readElementText(); |
| QAction* action = CommandManager::instance()->getAction(cmdName.toStdString().c_str()); |
| if (action) |
| MenuBarCommandItem* item = new MenuBarCommandItem(parentItem, action); |
| #else |
| reader.skipCurrentElement(); |
| #endif |
| } |
| else if (reader.name() == "separator") |
| { |
| MenuBarSeparatorItem* sep = new MenuBarSeparatorItem(parentItem); |
| reader.skipCurrentElement(); |
| } |
| else |
| reader.skipCurrentElement(); |
| } |
| } |
| |
| |
| |
| void MenuBarTree::saveMenuTree() |
| { |
| QFile file(toQString(m_path)); |
| if (!file.open(QFile::WriteOnly | QFile::Text)){ |
| qDebug() << "Cannot read file" << file.errorString(); |
| return; |
| } |
| |
| QXmlStreamWriter writer(&file); |
| writer.setAutoFormatting(true); |
| writer.writeStartDocument(); |
| |
| writer.writeStartElement("menubar"); |
| { |
| saveMenuRecursive(writer, invisibleRootItem()); |
| |
| } |
| writer.writeEndElement(); |
| |
| writer.writeEndDocument(); |
| |
| } |
| |
| |
| |
| void MenuBarTree::saveMenuRecursive(QXmlStreamWriter& writer, QTreeWidgetItem* parentItem) |
| { |
| for (int c = 0; c < parentItem->childCount(); c++) |
| { |
| MenuBarCommandItem* command = dynamic_cast<MenuBarCommandItem*>(parentItem->child(c)); |
| MenuBarSeparatorItem* sep = dynamic_cast<MenuBarSeparatorItem*>(parentItem->child(c)); |
| MenuBarSubmenuItem* subMenu = dynamic_cast<MenuBarSubmenuItem*>(parentItem->child(c)); |
| if (command) |
| writer.writeTextElement("command", QString::fromStdString(CommandManager::instance()->getIdFromAction(command->getAction()))); |
| else if (sep) |
| writer.writeEmptyElement("separator"); |
| else if (subMenu) |
| { |
| writer.writeStartElement("menu"); |
| writer.writeAttribute("title", subMenu->text(0)); |
| |
| saveMenuRecursive(writer, subMenu); |
| |
| writer.writeEndElement(); |
| } |
| else |
| {} |
| } |
| } |
| |
| |
| |
| bool MenuBarTree::dropMimeData(QTreeWidgetItem * parent, int index, const QMimeData * data, Qt::DropAction action) |
| { |
| |
| if (data->hasText()) |
| { |
| QString txt = data->text(); |
| QTreeWidgetItem* item; |
| if (txt == "separator") |
| item = new MenuBarSeparatorItem(0); |
| else |
| { |
| QAction * act = CommandManager::instance()->getAction(txt.toStdString().c_str()); |
| if (!act) return false; |
| item = new MenuBarCommandItem(0, act); |
| } |
| |
| |
| if (parent) |
| parent->insertChild(index, item); |
| else |
| insertTopLevelItem(index, item); |
| |
| |
| return true; |
| |
| } |
| |
| return false; |
| |
| } |
| |
| |
| |
| QStringList MenuBarTree::mimeTypes() const |
| { |
| QStringList qstrList; |
| qstrList.append("text/plain"); |
| return qstrList; |
| } |
| |
| |
| |
| void MenuBarTree::contextMenuEvent(QContextMenuEvent * event) |
| { |
| QTreeWidgetItem* item = itemAt(event->pos()); |
| if (item != currentItem()) |
| setCurrentItem(item); |
| QMenu* menu = new QMenu(this); |
| QAction * action; |
| if (!item || indexOfTopLevelItem(item) >= 0) |
| action = menu->addAction(tr("Insert Menu")); |
| else |
| action = menu->addAction(tr("Insert Submenu")); |
| |
| connect(action, SIGNAL(triggered()), this, SLOT(insertMenu())); |
| |
| if (item) |
| { |
| action = menu->addAction(tr("Remove \"%1\"").arg(item->text(0))); |
| connect(action, SIGNAL(triggered()), this, SLOT(removeItem())); |
| } |
| |
| menu->exec(event->globalPos()); |
| delete menu; |
| } |
| |
| |
| |
| void MenuBarTree::insertMenu() |
| { |
| QTreeWidgetItem* item = currentItem(); |
| QString title = tr("New Menu"); |
| MenuBarSubmenuItem * insItem = new MenuBarSubmenuItem(0, title); |
| if (!item) |
| addTopLevelItem(insItem); |
| else if (indexOfTopLevelItem(item) >= 0) |
| insertTopLevelItem(indexOfTopLevelItem(item), insItem); |
| else |
| item->parent()->insertChild(item->parent()->indexOfChild(item), insItem); |
| } |
| |
| |
| |
| void MenuBarTree::removeItem() |
| { |
| QTreeWidgetItem* item = currentItem(); |
| if (!item) return; |
| |
| if (indexOfTopLevelItem(item) >= 0) |
| takeTopLevelItem(indexOfTopLevelItem(item)); |
| else |
| item->parent()->removeChild(item); |
| |
| delete item; |
| } |
| |
| |
| |
| |
| |
| CommandListTree::CommandListTree(QWidget* parent) |
| : QTreeWidget(parent) |
| { |
| setObjectName("SolidLineFrame"); |
| setAlternatingRowColors(true); |
| setDragEnabled(true); |
| setDragDropMode(QAbstractItemView::DragOnly); |
| setColumnCount(1); |
| header()->close(); |
| |
| QIcon menuFolderIcon(":Resources/browser_project_close.png"); |
| menuFolderIcon.addFile(":Resources/browser_project_open.png", QSize(), QIcon::Normal, QIcon::On); |
| invisibleRootItem()->setIcon(0, menuFolderIcon); |
| |
| QTreeWidgetItem *menuCommandFolder = new QTreeWidgetItem(this); |
| menuCommandFolder->setFlags( Qt::ItemIsEnabled ); |
| menuCommandFolder->setText(0, ShortcutTree::tr("Menu Commands")); |
| menuCommandFolder->setExpanded(true); |
| menuCommandFolder->setIcon(0,invisibleRootItem()->icon(0)); |
| |
| addFolder(ShortcutTree::tr("File"), MenuFileCommandType, menuCommandFolder); |
| addFolder(ShortcutTree::tr("Edit"), MenuEditCommandType, menuCommandFolder); |
| addFolder(ShortcutTree::tr("Scan & Cleanup"), MenuScanCleanupCommandType, menuCommandFolder); |
| addFolder(ShortcutTree::tr("Level"), MenuLevelCommandType, menuCommandFolder); |
| addFolder(ShortcutTree::tr("Xsheet"), MenuXsheetCommandType, menuCommandFolder); |
| addFolder(ShortcutTree::tr("Cells"), MenuCellsCommandType, menuCommandFolder); |
| addFolder(ShortcutTree::tr("View"), MenuViewCommandType, menuCommandFolder); |
| addFolder(ShortcutTree::tr("Windows"), MenuWindowsCommandType, menuCommandFolder); |
| |
| addFolder(ShortcutTree::tr("Tools"), ToolCommandType); |
| |
| MenuBarSeparatorItem* sep = new MenuBarSeparatorItem(0); |
| sep->setToolTip(0, QObject::tr("[Drag&Drop] to copy separator to menu bar")); |
| addTopLevelItem(sep); |
| |
| } |
| |
| |
| |
| void CommandListTree::addFolder(const QString &title, int commandType, QTreeWidgetItem *parentFolder) |
| { |
| QTreeWidgetItem *folder; |
| if (!parentFolder) |
| folder = new QTreeWidgetItem(this); |
| else |
| folder = new QTreeWidgetItem(parentFolder); |
| assert(folder); |
| folder->setText(0, title); |
| folder->setIcon(0, invisibleRootItem()->icon(0)); |
| |
| std::vector<QAction *> actions; |
| CommandManager::instance()->getActions((CommandType)commandType, actions); |
| for (int i = 0; i < (int)actions.size(); i++) { |
| MenuBarCommandItem *item = new MenuBarCommandItem(folder, actions[i]); |
| item->setToolTip(0, QObject::tr("[Drag&Drop] to copy command to menu bar")); |
| } |
| } |
| |
| |
| |
| void CommandListTree::mousePressEvent(QMouseEvent *event) |
| { |
| setCurrentItem(itemAt(event->pos())); |
| MenuBarCommandItem *commandItem = dynamic_cast<MenuBarCommandItem*>(itemAt(event->pos())); |
| MenuBarSeparatorItem *separatorItem = dynamic_cast<MenuBarSeparatorItem*>(itemAt(event->pos())); |
| |
| if (commandItem || separatorItem) |
| { |
| std::string dragStr; |
| QString dragPixmapTxt; |
| if (commandItem) |
| { |
| dragStr = CommandManager::instance()->getIdFromAction(commandItem->getAction()); |
| dragPixmapTxt = commandItem->getAction()->text(); |
| dragPixmapTxt.remove("&"); |
| } |
| else |
| { |
| dragStr = "separator"; |
| dragPixmapTxt = tr("----Separator----"); |
| } |
| |
| QMimeData *mimeData = new QMimeData; |
| mimeData->setText(QString::fromStdString(dragStr)); |
| |
| QFontMetrics fm(QApplication::font()); |
| QPixmap pix(fm.boundingRect(dragPixmapTxt).adjusted(-2,-2,2,2).size()); |
| QPainter painter(&pix); |
| painter.fillRect(pix.rect(),Qt::white); |
| painter.setPen(Qt::black); |
| painter.drawText(pix.rect(), Qt::AlignCenter, dragPixmapTxt); |
| |
| QDrag *drag = new QDrag(this); |
| drag->setMimeData(mimeData); |
| drag->setPixmap(pix); |
| |
| drag->exec(Qt::CopyAction); |
| } |
| |
| QTreeWidget::mousePressEvent(event); |
| } |
| |
| |
| |
| |
| |
| MenuBarPopup::MenuBarPopup(Room* room) |
| : Dialog(TApp::instance()->getMainWindow(), true, false, "CustomizeMenuBar") |
| { |
| setWindowTitle(tr("Customize Menu Bar of Room \"%1\"").arg(room->getName())); |
| |
| |
| std::string mbFileName = room->getPath().getName() + "_menubar.xml"; |
| TFilePath mbPath = ToonzFolder::getMyRoomsDir() + mbFileName; |
| |
| m_commandListTree = new CommandListTree(this); |
| m_menuBarTree = new MenuBarTree(mbPath, this); |
| |
| QPushButton *okBtn = new QPushButton(tr("OK"), this); |
| QPushButton *cancelBtn = new QPushButton(tr("Cancel"), this); |
| |
| okBtn->setFocusPolicy(Qt::NoFocus); |
| cancelBtn->setFocusPolicy(Qt::NoFocus); |
| |
| QLabel* menuBarLabel = new QLabel(tr("%1 Menu Bar").arg(room->getName()), this); |
| QLabel* menuItemListLabel = new QLabel(tr("Menu Items"), this); |
| |
| QFont f("Arial", 15, QFont::Bold); |
| menuBarLabel->setFont(f); |
| menuItemListLabel->setFont(f); |
| |
| QLabel* noticeLabel = new QLabel(tr("N.B. If you put unique title to submenu, it may not be translated to another language.\nN.B. Duplicated commands will be ignored. Only the last one will appear in the menu bar."),this); |
| QFont nf("Arial", 9, QFont::Normal); |
| nf.setItalic(true); |
| noticeLabel->setFont(nf); |
| |
| |
| QVBoxLayout* mainLay = new QVBoxLayout(); |
| m_topLayout->setMargin(0); |
| m_topLayout->setSpacing(0); |
| { |
| QGridLayout* mainUILay = new QGridLayout(); |
| mainUILay->setMargin(5); |
| mainUILay->setHorizontalSpacing(8); |
| mainUILay->setVerticalSpacing(5); |
| { |
| mainUILay->addWidget(menuBarLabel, 0, 0); |
| mainUILay->addWidget(menuItemListLabel, 0, 1); |
| mainUILay->addWidget(m_menuBarTree, 1, 0); |
| mainUILay->addWidget(m_commandListTree, 1, 1); |
| |
| mainUILay->addWidget(noticeLabel, 2, 0, 1, 2); |
| } |
| mainUILay->setRowStretch(0, 0); |
| mainUILay->setRowStretch(1, 1); |
| mainUILay->setRowStretch(2, 0); |
| mainUILay->setColumnStretch(0, 1); |
| mainUILay->setColumnStretch(1, 1); |
| |
| m_topLayout->addLayout(mainUILay, 1); |
| } |
| |
| m_buttonLayout->setMargin(0); |
| m_buttonLayout->setSpacing(30); |
| { |
| m_buttonLayout->addStretch(1); |
| m_buttonLayout->addWidget(okBtn, 0); |
| m_buttonLayout->addWidget(cancelBtn, 0); |
| m_buttonLayout->addStretch(1); |
| } |
| |
| |
| |
| bool ret = connect(okBtn, SIGNAL(clicked()), this, SLOT(onOkPressed())); |
| ret = ret && connect(cancelBtn, SIGNAL(clicked()), this, SLOT(reject())); |
| assert(ret); |
| } |
| |
| |
| |
| void MenuBarPopup::onOkPressed() |
| { |
| m_menuBarTree->saveMenuTree(); |
| |
| accept(); |
| } |