BayTemplate/source/mainwindow.cpp

412 lines
14 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "mainwindow.h"
#include "graphicsItem/graphicsItemGroup.h"
#include "ui_mainwindow.h"
#include <QWidgetAction>
#include <QTableWidget>
#include <QSettings>
#include <QUndoStack>
#include <QGraphicsScene>
#include <QGraphicsItem>
#include <QFileDialog>
#include <QMessageBox>
#include <QFileInfo>
#include "DockAreaWidget.h"
#include "DockAreaTitleBar.h"
#include "DockAreaTabBar.h"
#include "FloatingDockContainer.h"
#include "DockComponentsFactory.h"
#include "QQuickDetailsViewMananger.h"
#include "propertyType/PropertyTypeCustomization_CustomType.h"
#include "propertyType/CustomType.h"
#include "QDetailsView.h"
#include "util/selectorManager.h"
#include "drawingPanel.h"
#include "designerScene.h"
#include "designerView.h"
#include "graphicElementsPanel.h"
#include "operationCommand.h"
#include "document.h"
using namespace ads;
CMainWindow::CMainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::CMainWindow)
{
ui->setupUi(this);
m_pUndoStack = nullptr;
m_pDocument = nullptr;
initializeDockUi();
initializeAction();
initializeDocument();
connect(m_pGraphicElementsPanel,SIGNAL(addGraphicsItem(GraphicsItemType&)),m_pDrawingPanel,SLOT(onSignal_addGraphicsItem(GraphicsItemType&)));
}
CMainWindow::~CMainWindow()
{
delete m_pDocument;
delete ui;
}
void CMainWindow::closeEvent(QCloseEvent* event)
{
// 检查是否有未保存的修改
if (m_pDocument && m_pDocument->isModified()) {
int ret = QMessageBox::warning(this, tr("确认关闭"),
tr("文档已修改,是否保存?"),
QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel);
if (ret == QMessageBox::Save) {
// 尝试保存,如果保存失败则取消关闭
if (!m_pDocument->saveToFile()) {
event->ignore();
return;
}
} else if (ret == QMessageBox::Cancel) {
event->ignore();
return;
}
}
// Delete dock manager here to delete all floating widgets. This ensures
// that all top level windows of the dock manager are properly closed
m_pDockManager->deleteLater();
QMainWindow::closeEvent(event);
}
void CMainWindow::changeEvent(QEvent* event)
{
if (event->type() == QEvent::WindowStateChange)
m_pDrawingPanel->grahpicsViewZoomFit();
}
void CMainWindow::initializeDockUi()
{
CDockManager::setConfigFlag(CDockManager::OpaqueSplitterResize, true);
CDockManager::setConfigFlag(CDockManager::XmlCompressionEnabled, false);
CDockManager::setConfigFlag(CDockManager::FocusHighlighting, true);
m_pDockManager = new CDockManager(this);
// Set central widget
m_pDrawingPanel = new DrawingPanel();
DesignerScene* designerScene = m_pDrawingPanel->getDesignerScene();
connect(designerScene, SIGNAL(signalAddItem(GraphicsBaseItem*)), this, SLOT(onSignal_addItem(GraphicsBaseItem*)));
connect(designerScene, SIGNAL(selectionChanged()), this, SLOT(onSignal_selectionChanged()));
CDockWidget* centralDockWidget = new CDockWidget("CentralWidget");
centralDockWidget->setWidget(m_pDrawingPanel);
auto* centralDockArea = m_pDockManager->setCentralWidget(centralDockWidget);
centralDockArea->setAllowedAreas(DockWidgetArea::OuterDockAreas);
// create other dock widgets
m_pGraphicElementsPanel = new GraphicElementsPanel();
CDockWidget* grapicElementsDockWidget = new CDockWidget(QString::fromWCharArray(L"图元面板"));
grapicElementsDockWidget->setWidget(m_pGraphicElementsPanel);
grapicElementsDockWidget->setMinimumSizeHintMode(CDockWidget::MinimumSizeHintFromDockWidget);
grapicElementsDockWidget->resize(400, 150);
grapicElementsDockWidget->setMinimumSize(200,150);
m_pDockManager->addDockWidget(DockWidgetArea::LeftDockWidgetArea, grapicElementsDockWidget);
ui->menuView->addAction(grapicElementsDockWidget->toggleViewAction());
QQuickDetailsViewManager::Get()->registerPropertyTypeCustomization<QCustomType, PropertyTypeCustomization_CustomType>();
m_pPropertiesEditorView = new QDetailsView();
CDockWidget* propertiesDockWidget = new CDockWidget(QString::fromWCharArray(L"属性编辑器"));
propertiesDockWidget->setWidget(m_pPropertiesEditorView);
propertiesDockWidget->setMinimumSizeHintMode(CDockWidget::MinimumSizeHintFromDockWidget);
propertiesDockWidget->resize(550, 150);
propertiesDockWidget->setMinimumSize(500,150);
m_pPropertiesEditorView->setObject(m_pDrawingPanel->getQGraphicsScene());
m_pDockManager->addDockWidget(DockWidgetArea::RightDockWidgetArea, propertiesDockWidget, centralDockArea);
ui->menuView->addAction(propertiesDockWidget->toggleViewAction());
}
void CMainWindow::initializeAction()
{
//撤销、重做
m_pUndoStack = new QUndoStack(this);
ui->actionUndo = m_pUndoStack->createUndoAction(this, tr("撤销"));
ui->actionUndo->setIcon(QIcon::fromTheme(QString::fromUtf8("edit-undo")));
ui->actionUndo->setShortcuts(QKeySequence::Undo);
ui->actionRedo = m_pUndoStack->createRedoAction(this, tr("重做"));
ui->actionRedo->setIcon(QIcon::fromTheme(QString::fromUtf8("edit-redo")));
ui->actionRedo->setShortcuts(QKeySequence::Redo);
ui->toolBar->addAction(ui->actionUndo);
ui->toolBar->addAction(ui->actionRedo);
ui->actionUndo->setEnabled(m_pUndoStack->canUndo());
ui->actionRedo->setEnabled(m_pUndoStack->canRedo());
ui->actionDelete->setShortcut(QKeySequence::Delete);
connect(ui->actionDelete, SIGNAL(triggered()), this, SLOT(onSignal_deleteItem()));
connect(ui->actionZoomIn, SIGNAL(triggered()), this, SLOT(onAction_zoomIn()));
connect(ui->actionZoomOut, SIGNAL(triggered()), this, SLOT(onAction_zoomOut()));
connect(ui->actionZoomFit, SIGNAL(triggered()), this, SLOT(onAction_zoomFit()));
connect(ui->actionGroup, SIGNAL(triggered()), this, SLOT(onAction_createGroup()));
connect(ui->actionUngroup, SIGNAL(triggered()), this, SLOT(onAction_destroyGroup()));
// 文件操作
connect(ui->actionNew, SIGNAL(triggered()), this, SLOT(onAction_new()));
connect(ui->actionOpen, SIGNAL(triggered()), this, SLOT(onAction_open()));
connect(ui->actionSave, SIGNAL(triggered()), this, SLOT(onAction_save()));
connect(ui->actionSaveAs, SIGNAL(triggered()), this, SLOT(onAction_saveAs()));
}
void CMainWindow::onAction_zoomIn()
{
m_pDrawingPanel->grahpicsViewZoomIn();
}
void CMainWindow::onAction_zoomOut()
{
m_pDrawingPanel->grahpicsViewZoomOut();
}
void CMainWindow::onAction_zoomFit()
{
m_pDrawingPanel->grahpicsViewZoomFit();
}
void CMainWindow::onAction_createGroup()
{
GraphicsItemGroup* group = m_pDrawingPanel->createItemGroup();
if(group)
{
QGraphicsScene* scene = m_pDrawingPanel->getQGraphicsScene();
QUndoCommand* createItemGropu = new CreateItemGoupCommand(group, scene);
m_pUndoStack->push(createItemGropu);
}
}
void CMainWindow::onAction_destroyGroup()
{
QGraphicsScene* scene = m_pDrawingPanel->getQGraphicsScene();
QList<QGraphicsItem*> listItem = scene->selectedItems();
if(listItem.count() != 1)
return; //只能选择一个解组
QGraphicsItem* item = listItem.first();
if(!item)
return;
GraphicsItemGroup *group = dynamic_cast<GraphicsItemGroup*>(item);
if(group)
{
QUndoCommand* destroyItemGropu = new DestroyItemGoupCommand(group, scene);
m_pUndoStack->push(destroyItemGropu);
}
}
void CMainWindow::onSignal_addItem(GraphicsBaseItem* item)
{
if(item)
{
QUndoCommand* addItemCommand = new AddItemCommand(item, item->scene());
m_pUndoStack->push(addItemCommand);
}
}
void CMainWindow::onSignal_deleteItem()
{
QGraphicsScene* scene = m_pDrawingPanel->getQGraphicsScene();
if (scene && scene->selectedItems().isEmpty())
return;
QUndoCommand* deleteItemCommand = new DeleteItemCommand(scene);
m_pUndoStack->push(deleteItemCommand); //push时会自动调用一次command的redo函数
}
void CMainWindow::onSignal_selectionChanged()
{
QList<QGraphicsItem*> selectedItems = m_pDrawingPanel->getQGraphicsScene()->selectedItems();
if(selectedItems.count() != 1) {
m_pPropertiesEditorView->setObject(m_pDrawingPanel->getQGraphicsScene());
return;
}
GraphicsBaseItem *item = static_cast<GraphicsBaseItem*>(selectedItems.first());
m_pPropertiesEditorView->setObject(static_cast<QObject*>(item));
}
// =================================================================
// Document 初始化
// =================================================================
void CMainWindow::initializeDocument()
{
// 创建新文档
m_pDocument = new Document(this);
// 关联 DesignerScene
DesignerScene* scene = m_pDrawingPanel->getDesignerScene();
m_pDocument->setScene(scene);
// 连接 Document 信号
connect(m_pDocument, &Document::modifiedChanged,
this, &CMainWindow::onDocument_modifiedChanged);
connect(m_pDocument, &Document::filenameChanged,
this, &CMainWindow::onDocument_filenameChanged);
connect(m_pDocument, &Document::saveStatusChanged,
this, &CMainWindow::onDocument_saveStatusChanged);
// 连接场景选择变化信号,当选择变化时标记文档为已修改
// 注意Qt6.5 之前没有 itemsAdded/itemsRemoved 信号
connect(scene, &QGraphicsScene::selectionChanged,
this, [this]() {
if (m_pDocument && !m_pDocument->isModified()) {
m_pDocument->setModified(true);
}
});
// 初始化窗口标题
updateWindowTitle();
// 将文件操作添加到文件菜单
ui->menuFile->addAction(ui->actionNew);
ui->menuFile->addAction(ui->actionOpen);
ui->menuFile->addAction(ui->actionSave);
ui->menuFile->addAction(ui->actionSaveAs);
ui->menuFile->addSeparator();
}
// =================================================================
// Document 文件操作
// =================================================================
void CMainWindow::onAction_new()
{
// 如果当前文档有修改,提示用户保存
if (m_pDocument->isModified()) {
int ret = QMessageBox::warning(this, tr("确认新建"),
tr("当前文档已修改,是否保存?"),
QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel);
if (ret == QMessageBox::Save) {
onAction_save();
} else if (ret == QMessageBox::Cancel) {
return;
}
}
// 清空场景
DesignerScene* scene = m_pDrawingPanel->getDesignerScene();
scene->clear();
// 创建新文档
delete m_pDocument;
m_pDocument = new Document(this);
m_pDocument->setScene(scene);
connect(m_pDocument, &Document::modifiedChanged,
this, &CMainWindow::onDocument_modifiedChanged);
connect(m_pDocument, &Document::filenameChanged,
this, &CMainWindow::onDocument_filenameChanged);
connect(m_pDocument, &Document::saveStatusChanged,
this, &CMainWindow::onDocument_saveStatusChanged);
updateWindowTitle();
}
void CMainWindow::onAction_open()
{
// 如果当前文档有修改,提示用户保存
if (m_pDocument->isModified()) {
int ret = QMessageBox::warning(this, tr("确认打开"),
tr("当前文档已修改,是否保存?"),
QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel);
if (ret == QMessageBox::Save) {
onAction_save();
} else if (ret == QMessageBox::Cancel) {
return;
}
}
QString fileName = QFileDialog::getOpenFileName(this, tr("打开文档"), "",
tr("BayTemplate Files (*.bay);;All Files (*)"));
if (fileName.isEmpty()) {
return;
}
if (!m_pDocument->loadFromFile(fileName)) {
QMessageBox::critical(this, tr("错误"), tr("无法打开文件:%1").arg(fileName));
}
}
void CMainWindow::onAction_save()
{
// 如果文档没有文件名,执行另存为
if (m_pDocument->filename().isEmpty()) {
onAction_saveAs();
return;
}
if (m_pDocument->saveToFile()) {
updateWindowTitle();
}
}
void CMainWindow::onAction_saveAs()
{
QString defaultFileName = m_pDocument->filename();
if (defaultFileName.isEmpty()) {
defaultFileName = QString("未命名.bay");
}
QString fileName = QFileDialog::getSaveFileName(this, tr("另存为"), defaultFileName,
tr("BayTemplate Files (*.bay);;All Files (*)"));
if (fileName.isEmpty()) {
return;
}
// 确保文件扩展名为.bay
if (!fileName.toLower().endsWith(".bay")) {
fileName += ".bay";
}
if (!m_pDocument->saveAsToFile(fileName)) {
QMessageBox::critical(this, tr("错误"), tr("无法保存文件:%1").arg(fileName));
}
}
// =================================================================
// Document 信号处理
// =================================================================
void CMainWindow::onDocument_modifiedChanged(bool modified)
{
updateWindowTitle();
}
void CMainWindow::onDocument_filenameChanged(const QString& filename)
{
updateWindowTitle();
}
void CMainWindow::onDocument_saveStatusChanged(bool success, const QString& message)
{
if (!success) {
QMessageBox::warning(this, tr("文档操作"), message);
}
}
void CMainWindow::updateWindowTitle()
{
QString title = tr("BayTemplate");
if (!m_pDocument->filename().isEmpty()) {
title = QFileInfo(m_pDocument->filename()).fileName();
} else {
title = tr("未命名");
}
if (m_pDocument->isModified()) {
title += " *";
}
setWindowTitle(title);
}