MDIApplication Example
#include <QApplication>
#include <QLineEdit>
#include <QMessageBox>
#include <QTextStream>
#include <QFileDialog>
#include <QCheckBox>
#include <QDoubleSpinBox>
#include <QPaintEngine>
#include <QPaintDevice>
#include <QPainter>
#include <QCloseEvent>
#include <QScrollBar>
#include <QtitanRibbon.h>
#include "sketchobject.h"
#include "sketchrepresentation.h"
#include "sketchchild.h"
#include "sketchdocument.h"
#include "sketchtool.h"
class SketchChildPrivate
{
public:
SketchChildPrivate(SketchChild* p);
public:
void init();
public:
void setActive(bool bActivate);
SketchDocument* document() const { return m_document; }
public:
RibbonPage* m_pageHome;
#if defined(QTN_TEST_ContextTab)
RibbonPage* m_pageContext;
#endif // QTN_TEST_ContextTab
QLineEdit* m_editX;
QLineEdit* m_editY;
QTransform m_matrix;
bool m_activeThis;
double m_aspectX;
double m_aspectY;
static int m_currentPageIndex;
protected:
SketchDocument* m_document;
SketchChild* m_parent;
};
int SketchChildPrivate::m_currentPageIndex = -1;
SketchChildPrivate::SketchChildPrivate(SketchChild* p)
{
m_parent = p;
m_document = Q_NULL;
m_activeThis = false;
m_aspectX = 0.0;
m_aspectY = 0.0;
m_pageHome = Q_NULL;
#if defined(QTN_TEST_ContextTab)
m_pageContext = Q_NULL;
#endif // QTN_TEST_ContextTab
m_editX = Q_NULL;
m_editY = Q_NULL;
}
void SketchChildPrivate::init()
{
m_document = new SketchDocument(m_parent);
m_aspectX = m_parent->metric(QPaintDevice::PdmDpiX);
m_aspectY = m_parent->metric(QPaintDevice::PdmDpiY);
}
void SketchChildPrivate::setActive(bool bActivate)
{
m_activeThis = bActivate;
}
SketchChild::SketchChild()
: RibbonWorkspace()
{
m_geomEditObject = Q_NULL;
m_geomGridObject = Q_NULL;
setWindowIcon(QIcon(QStringLiteral(":/res/sketchchild.png")));
m_workTool = Q_NULL;
m_pimpl = new SketchChildPrivate(this);
m_pimpl->init();
setAttribute(Qt::WA_DeleteOnClose);
setAttribute(Qt::WA_MouseTracking);
m_isUntitled = true;
createActions();
setCursor(QCursor(QPixmap(QStringLiteral(":/res/findObjectCursor.png"))));
}
SketchChild::~SketchChild()
{
delete m_pimpl;
}
QSize SketchChild::viewportSizeHint() const
{
return QSize(2000, 2000);
}
void SketchChild::buildUserInterface(RibbonBar* rib, QStatusBar* statusBar, RibbonPage* pageHome)
{
Q_UNUSED(pageHome);
fillRibbonSketch(rib);
fillStatusBarSketch(statusBar);
if (!rib->isMinimized())
{
int indexPage = SketchChildPrivate::m_currentPageIndex != -1 ? SketchChildPrivate::m_currentPageIndex : 0;
rib->setCurrentPageIndex(indexPage);
}
updateActions();
}
void SketchChild::removeUserInterface(RibbonBar* rib, QStatusBar* statusBar, RibbonPage* pageHome)
{
Q_UNUSED(pageHome);
SketchChildPrivate::m_currentPageIndex = rib->currentPageIndex();
clearRibbonSketch(rib);
clearStatusBarSketch(statusBar);
}
void SketchChild::newFile()
{
static int sequenceNumber = 1;
m_isUntitled = true;
m_curFile = tr("sketch%1.skt").arg(sequenceNumber++);
setWindowTitle(m_curFile + QStringLiteral("[*]"));
connect(document(), SIGNAL(contentsChanged()), this, SLOT(documentWasModified()));
}
bool SketchChild::loadFile(const QString& fileName)
{
QFile file(fileName);
if (!file.open(QFile::ReadOnly | QFile::Text))
{
QMessageBox::warning(this, tr("MDI"), tr("Cannot read file %1:\n%2.").arg(fileName).arg(file.errorString()));
return false;
}
QTextStream in(&file);
QApplication::setOverrideCursor(Qt::WaitCursor);
QApplication::restoreOverrideCursor();
setCurrentFile(fileName);
connect(document(), SIGNAL(contentsChanged()), this, SLOT(documentWasModified()));
return true;
}
bool SketchChild::save()
{
return m_isUntitled ? saveAs() : saveFile(m_curFile);
}
bool SketchChild::saveAs()
{
QString fileName = QFileDialog::getSaveFileName(this, tr("Save As"), m_curFile);
if (fileName.isEmpty())
return false;
return saveFile(fileName);
}
bool SketchChild::saveFile(const QString &fileName)
{
QFile file(fileName);
if (!file.open(QFile::WriteOnly | QFile::Text))
{
QMessageBox::warning(this, tr("MDI"), tr("Cannot write file %1:\n%2.").arg(fileName).arg(file.errorString()));
return false;
}
QApplication::setOverrideCursor(Qt::WaitCursor);
QApplication::restoreOverrideCursor();
setCurrentFile(fileName);
return true;
}
QString SketchChild::userFriendlyCurrentFile()
{
return strippedName(m_curFile);
}
bool SketchChild::hasSelection() const
{
return false;
}
SketchDocument* SketchChild::document() const
{
return m_pimpl->document();
}
void SketchChild::createActions()
{
m_createObjectAction = new QAction(QIcon(QStringLiteral(":/res/createobject.png")), tr("Create object"), this);
connect(m_createObjectAction, SIGNAL(triggered()), this, SLOT(createObject()));
m_stopToolAction = new QAction(QIcon(QStringLiteral(":/res/stoptool.png")), tr("Stop Tool"), this);
connect(m_stopToolAction, SIGNAL(triggered()), this, SLOT(selectionAction()));
m_repeatToolAction = new QAction(QIcon(QStringLiteral(":/res/repeat.png")), tr("Cyclical tool"), this);
connect(m_repeatToolAction, SIGNAL(triggered()), this, SLOT(cyclicalTool()));
m_repeatToolAction->setCheckable(true);
m_selectionAction = new QAction(QIcon(QStringLiteral(":/res/selection.png")), tr("Selection Tool"), this);
m_selectionAction->setStatusTip(tr("Choose object selection tool"));
connect(m_selectionAction, SIGNAL(triggered()), this, SLOT(selectionAction()));
m_lineAction = new QAction(QIcon(QStringLiteral(":/res/line.png")), tr("Line Tool"), this);
m_lineAction->setStatusTip(tr("Choose line drawing tool"));
m_lineAction->setCheckable(true);
connect(m_lineAction, SIGNAL(triggered()), this, SLOT(lineAction()));
m_rectangleAction = new QAction(QIcon(QStringLiteral(":/res/rectangle.png")), tr("Rectangle Tool"), this);
m_rectangleAction->setStatusTip(tr("Choose rectangle drawing tool"));
m_rectangleAction->setCheckable(true);
connect(m_rectangleAction, SIGNAL(triggered()), this, SLOT(rectangleAction()));
m_circleAction = new QAction(QIcon(QStringLiteral(":/res/circle.png")), tr("Circle Tool"), this);
m_circleAction->setStatusTip(tr("Choose circle drawing tool"));
m_circleAction->setCheckable(true);
connect(m_circleAction, SIGNAL(triggered()), this, SLOT(circleAction()));
m_ellipseAction = new QAction(QIcon(QStringLiteral(":/res/ellipse.png")), tr("Ellipse Tool"), this);
m_ellipseAction->setStatusTip(tr("Choose ellipse drawing tool"));
m_ellipseAction->setCheckable(true);
m_ellipseAction->setEnabled(false);
connect(m_ellipseAction, SIGNAL(triggered()), this, SLOT(ellipseAction()));
}
void SketchChild::updateActions()
{
m_selectionAction->setEnabled(m_workTool != Q_NULL);
m_lineAction->setChecked(m_workTool && m_workTool->getIdTool() == it_line);
m_rectangleAction->setChecked(m_workTool && m_workTool->getIdTool() == it_rectangle);
m_circleAction->setChecked(m_workTool && m_workTool->getIdTool() == it_circle);
m_ellipseAction->setChecked(m_workTool && m_workTool->getIdTool() == it_ellipse);
m_createObjectAction->setEnabled(!m_repeatToolAction->isChecked());
m_repeatToolAction->setChecked(m_workTool->isAutoCreateObject());
}
void SketchChild::fillRibbonSketch(RibbonBar* rib)
{
m_pimpl->m_pageHome = rib->insertPage(0, tr("&Home"));
if (m_pimpl->m_pageHome)
{
createGeometryGroup(m_pimpl->m_pageHome->addGroup(tr("Geometry")));
createGrigGroup();
createEditGroup();
}
#if defined(QTN_TEST_ContextTab)
m_pimpl->m_pageContext = rib->insertPage(1, tr("Test tab"));
m_pimpl->m_pageContext->setContextColor(RibbonPage::ContextColorRed);
m_pimpl->m_pageContext->setContextTitle(tr("Test tab"));
#endif // QTN_TEST_ContextTab
}
void SketchChild::clearRibbonSketch(RibbonBar* rib)
{
#if defined(QTN_TEST_ContextTab)
if (m_pimpl->m_pageContext)
{
delete m_pimpl->m_pageContext;
m_pimpl->m_pageContext = Q_NULL;
}
#endif // QTN_TEST_ContextTab
if (m_pimpl->m_pageHome)
{
clearEditGroup();
rib->removePage(m_pimpl->m_pageHome);
m_pimpl->m_pageHome = Q_NULL;
m_geomEditObject = Q_NULL;
m_geomGridObject = Q_NULL;
}
}
void SketchChild::createGeometryGroup(RibbonGroup* geomGroup)
{
geomGroup->setContentAlignment(Qt::AlignVCenter);
RibbonToolBarControl* toolBar = new RibbonToolBarControl(geomGroup);
toolBar->addAction(m_selectionAction);
toolBar->addSeparator();
toolBar->addAction(m_lineAction);
toolBar->addAction(m_rectangleAction);
toolBar->addAction(m_circleAction);
toolBar->addAction(m_ellipseAction);
geomGroup->addControl(toolBar);
}
void SketchChild::createEditGroup()
{
if (m_workTool)
{
if (m_geomEditObject)
m_pimpl->m_pageHome->removeGroup(m_geomEditObject);
m_geomEditObject = m_pimpl->m_pageHome->insertGroup(1, tr("Edit"));
m_workTool->setHolder(m_geomEditObject);
m_geomEditObject->addAction(m_createObjectAction);
RibbonControl* control = m_geomEditObject->controlByAction(m_createObjectAction);
control->sizeDefinition(RibbonControlSizeDefinition::GroupLarge)->setImageSize(RibbonControlSizeDefinition::ImageSmall);
control->sizeDefinition(RibbonControlSizeDefinition::GroupLarge)->setLabelVisible(false);
control->sizeDefinition(RibbonControlSizeDefinition::GroupMedium)->setImageSize(RibbonControlSizeDefinition::ImageSmall);
control->sizeDefinition(RibbonControlSizeDefinition::GroupMedium)->setLabelVisible(false);
control->sizeDefinition(RibbonControlSizeDefinition::GroupSmall)->setImageSize(RibbonControlSizeDefinition::ImageSmall);
control->sizeDefinition(RibbonControlSizeDefinition::GroupSmall)->setLabelVisible(false);
m_geomEditObject->addAction(m_stopToolAction);
control = m_geomEditObject->controlByAction(m_stopToolAction);
control->sizeDefinition(RibbonControlSizeDefinition::GroupLarge)->setImageSize(RibbonControlSizeDefinition::ImageSmall);
control->sizeDefinition(RibbonControlSizeDefinition::GroupLarge)->setLabelVisible(false);
control->sizeDefinition(RibbonControlSizeDefinition::GroupMedium)->setImageSize(RibbonControlSizeDefinition::ImageSmall);
control->sizeDefinition(RibbonControlSizeDefinition::GroupMedium)->setLabelVisible(false);
control->sizeDefinition(RibbonControlSizeDefinition::GroupSmall)->setImageSize(RibbonControlSizeDefinition::ImageSmall);
control->sizeDefinition(RibbonControlSizeDefinition::GroupSmall)->setLabelVisible(false);
m_geomEditObject->addAction(m_repeatToolAction);
control = m_geomEditObject->controlByAction(m_repeatToolAction);
control->sizeDefinition(RibbonControlSizeDefinition::GroupLarge)->setImageSize(RibbonControlSizeDefinition::ImageSmall);
control->sizeDefinition(RibbonControlSizeDefinition::GroupLarge)->setLabelVisible(false);
control->sizeDefinition(RibbonControlSizeDefinition::GroupMedium)->setImageSize(RibbonControlSizeDefinition::ImageSmall);
control->sizeDefinition(RibbonControlSizeDefinition::GroupMedium)->setLabelVisible(false);
control->sizeDefinition(RibbonControlSizeDefinition::GroupSmall)->setImageSize(RibbonControlSizeDefinition::ImageSmall);
control->sizeDefinition(RibbonControlSizeDefinition::GroupSmall)->setLabelVisible(false);
m_geomEditObject->addSeparator();
m_workTool->activate();
}
}
void SketchChild::clearEditGroup()
{
if (m_workTool)
{
m_workTool->deactivate();
if (m_geomEditObject)
{
m_geomEditObject->hide();
m_geomEditObject->clear();
}
}
}
void SketchChild::createGrigGroup()
{
m_geomGridObject = m_pimpl->m_pageHome->addGroup(tr("Grid"));
if (m_geomGridObject)
{
QCheckBox* pShowGrid = new QCheckBox(tr("Show grid"));
connect(pShowGrid, SIGNAL(stateChanged(int)), this, SLOT(showGrid(int)));
pShowGrid->setCheckState(Qt::Checked);
m_geomGridObject->addWidget(pShowGrid);
QDoubleSpinBox* pStepGrid = new QDoubleSpinBox;
pStepGrid->setMinimumWidth(100);
pStepGrid->setSuffix(tr("mm"));
pStepGrid->setSingleStep(2.5);
pStepGrid->setRange(1.0, 100.0);
connect(pStepGrid, SIGNAL(valueChanged(double)), this, SLOT(stepGrid(double)));
pStepGrid->setValue(document()->getStepGrid());
m_geomGridObject->addWidget(QIcon(), tr("Step:"), pStepGrid);
}
}
void SketchChild::fillStatusBarSketch(QStatusBar* statusBar)
{
if (m_pimpl->m_editX && m_pimpl->m_editY)
return;
m_pimpl->m_editX = new QLineEdit(statusBar);
m_pimpl->m_editX->setMaximumWidth(60);
m_pimpl->m_editY = new QLineEdit(statusBar);
m_pimpl->m_editY->setMaximumWidth(60);
statusBar->addPermanentWidget(m_pimpl->m_editX);
statusBar->addPermanentWidget(m_pimpl->m_editY);
}
void SketchChild::clearStatusBarSketch(QStatusBar* statusBar)
{
if (m_pimpl->m_editX && m_pimpl->m_editY)
{
statusBar->removeWidget(m_pimpl->m_editX);
statusBar->removeWidget(m_pimpl->m_editY);
delete m_pimpl->m_editX;
delete m_pimpl->m_editY;
m_pimpl->m_editX = Q_NULL;
m_pimpl->m_editY = Q_NULL;
}
}
void SketchChild::startTool(GeometricTool& tool)
{
bool bHasTool = m_workTool && m_workTool->getIdTool() == tool.getIdTool();
stopTool();
if (!bHasTool)
{
m_workTool = &tool;
createEditGroup();
connect(m_workTool, SIGNAL(stateChanged(int)), this, SLOT(stateChanged(int)));
if (!m_workTool->startTool())
stopTool();
}
document()->setSelectObject(Q_NULL, false);
viewport()->update();
updateActions();
}
void SketchChild::stopTool()
{
if (m_workTool)
{
clearEditGroup();
m_workTool->stopTool();
disconnect(m_workTool, SIGNAL(stateChanged(int)), this, SLOT(stateChanged(int)));
delete m_workTool;
m_workTool = Q_NULL;
}
viewport()->update();
updateActions();
}
void SketchChild::selectionAction()
{
stopTool();
}
void SketchChild::lineAction()
{
startTool(*new LineTool(viewport(), document()));
}
void SketchChild::rectangleAction()
{
startTool(*new RectangleTool(viewport(), document()));
}
void SketchChild::circleAction()
{
startTool(*new CircleTool(viewport(), document()));
}
void SketchChild::ellipseAction()
{
updateActions();
}
void SketchChild::stateChanged(int state)
{
m_createObjectAction->setEnabled(!m_workTool->isAutoCreateObject() && state == ss_readyCreateObject);
}
void SketchChild::createObject()
{
if (m_workTool && m_workTool->createObject())
stopTool();
}
void SketchChild::cyclicalTool()
{
if (m_workTool)
{
bool bIsAuto = !m_workTool->isAutoCreateObject();
m_repeatToolAction->setChecked(bIsAuto);
m_workTool->setAutoCreateObject(bIsAuto);
if (m_workTool)
m_workTool->createObject();
updateActions();
}
}
void SketchChild::showGrid(int state)
{
document()->setVisibleGrid(state == Qt::Checked);
viewport()->update();
}
void SketchChild::stepGrid(double val)
{
document()->setStepGrid(val);
viewport()->update();
}
QPointF SketchChild::mapToScene(const QPoint& point) const
{
QPointF p = point;
QTransform mat = m_pimpl->m_matrix;
return mat.inverted().map(p);
}
QPointF SketchChild::mapScreenToMM(const QPointF& point) const
{
if ( m_pimpl->m_aspectX > 0.0 && m_pimpl->m_aspectY > 0.0)
return QPointF(25.4/m_pimpl->m_aspectX*point.x(), 25.4/m_pimpl->m_aspectY*point.y());
return QPointF(0.0, 0.0);
}
void SketchChild::closeEvent(QCloseEvent* event)
{
if (maybeSave())
event->accept();
else
event->ignore();
}
void SketchChild::mousePressEvent(QMouseEvent* event)
{
QAbstractScrollArea::mousePressEvent(event);
QPointF point = mapToScene(event->pos());
point = mapScreenToMM(point);
if (m_workTool)
{
m_workTool->mousePressEvent(point.x(), point.y());
}
else
{
bool bHasSelect = false;
const QList<GeomObject*>& objects = document()->getObjects();
for (int i = 0, count = objects.size(); count > i && !bHasSelect; i++)
{
GeomObject* pObject = objects[i];
if (pObject->distance(point) <= 4.0)
{
document()->setSelectObject(pObject, event->modifiers() & Qt::ControlModifier);
viewport()->update();
bHasSelect = true;
}
}
if (!bHasSelect)
{
document()->setSelectObject(Q_NULL, false);
viewport()->update();
}
}
}
void SketchChild::mouseReleaseEvent(QMouseEvent* event)
{
QAbstractScrollArea::mouseReleaseEvent(event);
}
void SketchChild::mouseDoubleClickEvent(QMouseEvent* event)
{
QAbstractScrollArea::mouseDoubleClickEvent(event);
}
void SketchChild::mouseMoveEvent(QMouseEvent* event)
{
QAbstractScrollArea::mouseMoveEvent(event);
QPointF point = mapToScene(event->pos());
point = mapScreenToMM(point);
if (m_pimpl->m_editX && m_pimpl->m_editY)
{
m_pimpl->m_editX->setText(QStringLiteral("%1").arg(point.x()));
m_pimpl->m_editY->setText(QStringLiteral("%1").arg(point.y()));
}
bool bHighlightObject = false;
if (m_workTool)
m_workTool->mouseMoveEvent(point.x(), point.y());
else
{
const QList<GeomObject*>& objects = document()->getObjects();
for (int i = 0, count = objects.size(); count > i; i++)
{
GeomObject* pObject = objects[i];
if (pObject->distance(point) <= 4.0)
{
document()->setHighlightObject(pObject);
bHighlightObject = true;
viewport()->update();
}
}
}
if (!bHighlightObject && document()->highlightObject())
{
document()->setHighlightObject(Q_NULL);
viewport()->update();
}
}
void SketchChild::keyPressEvent(QKeyEvent* event)
{
QAbstractScrollArea::keyPressEvent(event);
if (focusWidget() == this && event->key() == Qt::Key_Escape)
stopTool();
}
void SketchChild::paintEvent(QPaintEvent* event)
{
Q_UNUSED(event);
QPainter p(viewport());
p.translate(-horizontalOffset(), -verticalOffset());
p.save();
QRect r = viewport()->rect();
QPaintDevice* device = p.paintEngine()->paintDevice();
m_pimpl->m_aspectX = device->logicalDpiX();
m_pimpl->m_aspectY = device->logicalDpiY();
m_pimpl->m_matrix = QTransform().translate(r.width()/2, r.height()/2);
p.setWorldTransform(m_pimpl->m_matrix, true);
const QList<GeomObject*>& objects = document()->getObjects();
for (int i = 0, count = objects.size(); count > i; i++)
{
GeomObject* object = objects[i];
const QList<RepObject*>& listRepresentation = object->getRepresentationDraw();
for (int j = 0, countJ = listRepresentation.size(); countJ > j; j++)
listRepresentation[j]->drawObject(&p);
}
if (m_workTool)
{
GeomObject* pObject = m_workTool->getObject();
if (pObject)
{
const QList<RepObject*>& listRepresentation = pObject->getRepresentationDraw();
for (int j = 0, countJ = listRepresentation.size(); countJ > j; j++)
{
listRepresentation[j]->setStateObjectDraw(RepObject::so_phantom);
listRepresentation[j]->drawObject(&p);
}
}
}
p.restore();
}
void SketchChild::resizeEvent(QResizeEvent* event)
{
QAbstractScrollArea::resizeEvent(event);
#if 0
QRect rc = rect();
QPointF p = mapScreenToMM(QPointF(rc.width(), rc.height()));
document()->setSize(p.x(), p.y());
#endif
QSize s = viewportSizeHint();
document()->setSize(s.width(), s.height());
}
void SketchChild::documentWasModified()
{
setWindowModified(document()->isModified());
}
bool SketchChild::maybeSave()
{
if (document()->isModified())
{
QMessageBox::StandardButton ret;
ret = QMessageBox::warning(this, tr("MDI"),
tr("'%1' has been modified.\n"
"Do you want to save your changes?")
.arg(userFriendlyCurrentFile()),
QMessageBox::Save | QMessageBox::Discard
| QMessageBox::Cancel);
if (ret == QMessageBox::Save)
return save();
else if (ret == QMessageBox::Cancel)
return false;
}
return true;
}
void SketchChild::setCurrentFile(const QString& fileName)
{
m_curFile = QFileInfo(fileName).canonicalFilePath();
m_isUntitled = false;
document()->setModified(false);
setWindowModified(false);
setWindowTitle(userFriendlyCurrentFile() + QStringLiteral("[*]"));
}
QString SketchChild::strippedName(const QString& fullFileName)
{
return QFileInfo(fullFileName).fileName();
}