From a0e1dae5cf2c074f394607d4b2cee56e44fefc93 Mon Sep 17 00:00:00 2001 From: Jim Evins Date: Sat, 7 Apr 2018 22:24:09 -0400 Subject: [PATCH] Implemented TemplateDesigner. --- CMakeLists.txt | 1 + README.md | 6 +- docs/PRODUCT-TEMPLATES.md | 10 +- glabels/CMakeLists.txt | 14 + glabels/File.cpp | 11 + glabels/File.h | 1 + glabels/MainWindow.cpp | 4 +- glabels/TemplateDesigner.cpp | 1436 +++++++++++++++++ glabels/TemplateDesigner.h | 289 ++++ glabels/images.qrc | 11 + .../images/TemplateDesigner/ex-1layout.png | Bin 0 -> 1567 bytes .../images/TemplateDesigner/ex-2layouts.png | Bin 0 -> 1610 bytes .../images/TemplateDesigner/ex-cd-size.png | Bin 0 -> 32300 bytes .../TemplateDesigner/ex-ellipse-size.png | Bin 0 -> 16779 bytes .../images/TemplateDesigner/ex-rect-size.png | Bin 0 -> 4972 bytes .../images/TemplateDesigner/ex-round-size.png | Bin 0 -> 16682 bytes .../images/TemplateDesigner/wizard-banner.png | Bin 0 -> 45285 bytes glabels/ui/TemplateDesignerApplyPage.ui | 69 + glabels/ui/TemplateDesignerCdPage.ui | 190 +++ glabels/ui/TemplateDesignerEllipsePage.ui | 156 ++ glabels/ui/TemplateDesignerIntroPage.ui | 76 + glabels/ui/TemplateDesignerNLayoutsPage.ui | 250 +++ glabels/ui/TemplateDesignerNamePage.ui | 134 ++ glabels/ui/TemplateDesignerOneLayoutPage.ui | 218 +++ glabels/ui/TemplateDesignerPageSizePage.ui | 107 ++ glabels/ui/TemplateDesignerRectPage.ui | 177 ++ glabels/ui/TemplateDesignerRoundPage.ui | 139 ++ glabels/ui/TemplateDesignerShapePage.ui | 81 + glabels/ui/TemplateDesignerTwoLayoutPage.ui | 256 +++ model/Db.cpp | 69 +- model/Db.h | 5 +- model/FileUtil.cpp | 22 + model/FileUtil.h | 1 + model/Settings.cpp | 34 + model/Settings.h | 5 +- model/Template.cpp | 10 +- model/Template.h | 7 +- model/XmlTemplateParser.cpp | 14 +- model/XmlTemplateParser.h | 6 +- translations/glabels_C.ts | 661 +++++++- 40 files changed, 4397 insertions(+), 73 deletions(-) create mode 100644 glabels/TemplateDesigner.cpp create mode 100644 glabels/TemplateDesigner.h create mode 100644 glabels/images/TemplateDesigner/ex-1layout.png create mode 100644 glabels/images/TemplateDesigner/ex-2layouts.png create mode 100644 glabels/images/TemplateDesigner/ex-cd-size.png create mode 100644 glabels/images/TemplateDesigner/ex-ellipse-size.png create mode 100644 glabels/images/TemplateDesigner/ex-rect-size.png create mode 100644 glabels/images/TemplateDesigner/ex-round-size.png create mode 100644 glabels/images/TemplateDesigner/wizard-banner.png create mode 100644 glabels/ui/TemplateDesignerApplyPage.ui create mode 100644 glabels/ui/TemplateDesignerCdPage.ui create mode 100644 glabels/ui/TemplateDesignerEllipsePage.ui create mode 100644 glabels/ui/TemplateDesignerIntroPage.ui create mode 100644 glabels/ui/TemplateDesignerNLayoutsPage.ui create mode 100644 glabels/ui/TemplateDesignerNamePage.ui create mode 100644 glabels/ui/TemplateDesignerOneLayoutPage.ui create mode 100644 glabels/ui/TemplateDesignerPageSizePage.ui create mode 100644 glabels/ui/TemplateDesignerRectPage.ui create mode 100644 glabels/ui/TemplateDesignerRoundPage.ui create mode 100644 glabels/ui/TemplateDesignerShapePage.ui create mode 100644 glabels/ui/TemplateDesignerTwoLayoutPage.ui diff --git a/CMakeLists.txt b/CMakeLists.txt index ce923e1..14b5bee 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -83,6 +83,7 @@ find_package (Qt5Test 5.4 QUIET) # (not recommended -- only for testing -- also not portable) # #add_compile_options("-Wall" "-Werror" "-Wpedantic") +add_compile_options("-g") #======================================= diff --git a/README.md b/README.md index 29d796c..e0c25cf 100644 --- a/README.md +++ b/README.md @@ -25,10 +25,8 @@ gLabels-qt is the development version of the next major version of gLabels (4.0) gLabels-qt has been under off-and-on development for several years.. It is still missing several features to bring it in parity with glabels-3.4. These include -- Batch mode -- Compatability with older glabels files -- Custom product templates designer -- Online manual +- Compatability with older glabels project files +- An online manual ## Download diff --git a/docs/PRODUCT-TEMPLATES.md b/docs/PRODUCT-TEMPLATES.md index fadf9d0..1be42f4 100644 --- a/docs/PRODUCT-TEMPLATES.md +++ b/docs/PRODUCT-TEMPLATES.md @@ -6,11 +6,11 @@ This document is a reference for manually creating *gLabels* product templates. *gLabels* searches for templates in several locations as described here:

-Location | Description ------------------------------------------|----------------------------------------- -${prefix}/share/libglabels-qt/templates/ | Predefined templates distributed with glabels. -${XDG_CONFIG_HOME}/libglabels/templates | User defined templates created with the gLabels Template Designer. -${HOME}/.glabels | Manually created templates should be placed here. +Location | Description +------------------------------------------|----------------------------------------- +${prefix}/share/glabels-qt/templates/ | Predefined templates distributed with glabels. +${XDG_CONFIG_HOME}/glabels.org/glabels-qt | User defined templates created with the gLabels Product Template Designer. **Do not place manually created templates here!** +${HOME}/.glabels | Manually created templates should be placed here. diff --git a/glabels/CMakeLists.txt b/glabels/CMakeLists.txt index 30aa1cd..262395b 100644 --- a/glabels/CMakeLists.txt +++ b/glabels/CMakeLists.txt @@ -33,6 +33,7 @@ set (glabels_sources SelectProductDialog.cpp SimplePreview.cpp StartupView.cpp + TemplateDesigner.cpp TemplatePicker.cpp TemplatePickerItem.cpp UndoRedoModel.cpp @@ -61,6 +62,7 @@ set (glabels_qobject_headers SelectProductDialog.h SimplePreview.h StartupView.h + TemplateDesigner.h TemplatePicker.h UndoRedoModel.h ) @@ -74,6 +76,18 @@ set (glabels_forms ui/PropertiesView.ui ui/SelectProductDialog.ui ui/StartupView.ui + ui/TemplateDesignerIntroPage.ui + ui/TemplateDesignerNamePage.ui + ui/TemplateDesignerPageSizePage.ui + ui/TemplateDesignerShapePage.ui + ui/TemplateDesignerRectPage.ui + ui/TemplateDesignerRoundPage.ui + ui/TemplateDesignerEllipsePage.ui + ui/TemplateDesignerCdPage.ui + ui/TemplateDesignerNLayoutsPage.ui + ui/TemplateDesignerOneLayoutPage.ui + ui/TemplateDesignerTwoLayoutPage.ui + ui/TemplateDesignerApplyPage.ui ) set (glabels_resource_files diff --git a/glabels/File.cpp b/glabels/File.cpp index d07d0e4..f87a4c8 100644 --- a/glabels/File.cpp +++ b/glabels/File.cpp @@ -22,6 +22,7 @@ #include "MainWindow.h" #include "SelectProductDialog.h" +#include "TemplateDesigner.h" #include "model/FileUtil.h" #include "model/Model.h" @@ -221,6 +222,16 @@ namespace glabels } + /// + /// Template Designer + /// + void File::templateDesigner( MainWindow *window ) + { + TemplateDesigner dialog( window ); + dialog.exec(); + } + + /// /// Close file /// diff --git a/glabels/File.h b/glabels/File.h index 0329a1f..f151b04 100644 --- a/glabels/File.h +++ b/glabels/File.h @@ -46,6 +46,7 @@ namespace glabels static void open( MainWindow *window ); static bool save( MainWindow *window ); static bool saveAs( MainWindow *window ); + static void templateDesigner( MainWindow *window ); static void close( MainWindow *window ); static void exit(); diff --git a/glabels/MainWindow.cpp b/glabels/MainWindow.cpp index 603e453..112ae2d 100644 --- a/glabels/MainWindow.cpp +++ b/glabels/MainWindow.cpp @@ -246,7 +246,7 @@ namespace glabels fileSaveAsAction->setStatusTip( tr("Save current gLabels project to a different name") ); connect( fileSaveAsAction, SIGNAL(triggered()), this, SLOT(fileSaveAs()) ); - fileTemplateDesignerAction = new QAction( tr("Template &Designer..."), this ); + fileTemplateDesignerAction = new QAction( tr("Product Template &Designer..."), this ); fileTemplateDesignerAction->setStatusTip( tr("Create custom templates") ); connect( fileTemplateDesignerAction, SIGNAL(triggered()), this, SLOT(fileTemplateDesigner()) ); @@ -1041,7 +1041,7 @@ namespace glabels /// void MainWindow::fileTemplateDesigner() { - qDebug() << "ACTION: file->Template Designer"; + File::templateDesigner( this ); } diff --git a/glabels/TemplateDesigner.cpp b/glabels/TemplateDesigner.cpp new file mode 100644 index 0000000..3ed5bce --- /dev/null +++ b/glabels/TemplateDesigner.cpp @@ -0,0 +1,1436 @@ +/* TemplateDesigner.cpp + * + * Copyright (C) 2018 Jim Evins + * + * This file is part of gLabels-qt. + * + * gLabels-qt is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * gLabels-qt is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with gLabels-qt. If not, see . + */ + +#include "TemplateDesigner.h" + +#include "SelectProductDialog.h" +#include "model/Db.h" +#include "model/Distance.h" +#include "model/FrameCd.h" +#include "model/FrameEllipse.h" +#include "model/FrameRect.h" +#include "model/FrameRound.h" +#include "model/Markup.h" +#include "model/Model.h" +#include "model/PageRenderer.h" +#include "model/Settings.h" + +#include +#include +#include +#include +#include + +#include +#include + +namespace glabels +{ + + // + // Private types and constants + // + namespace + { + + enum PageId + { + IntroPageId, + NamePageId, + PageSizePageId, + ShapePageId, + RectPageId, + RoundPageId, + EllipsePageId, + CdPageId, + NLayoutsPageId, + OneLayoutPageId, + TwoLayoutPageId, + ApplyPageId + }; + + + const QString defaultPageSize[] = + { + /* ISO */ "A4", + /* US */ "US Letter" + }; + + + const double maxPageSize[] = + { + /* PT */ 5000, + /* IN */ 70, + /* MM */ 1800, + /* CM */ 180, + /* PC */ 420 + }; + + const model::Distance defaultMargin = model::Distance::in(0.125); + const model::Distance defaultWaste = model::Distance::in(0); + + const model::Distance defaultRectW = model::Distance::in(3.5); + const model::Distance defaultRectH = model::Distance::in(2.0); + const model::Distance defaultRectR = model::Distance::in(0); + + const model::Distance defaultRoundR = model::Distance::in(0.75); + + const model::Distance defaultEllipseW = model::Distance::in(3.5); + const model::Distance defaultEllipseH = model::Distance::in(2.0); + + const model::Distance defaultCdR1 = model::Distance::in(2.3125); + const model::Distance defaultCdR2 = model::Distance::in(0.8125); + const model::Distance defaultCdClip = model::Distance::in(0); + + } + + + /// + /// Constructor + /// + TemplateDesigner::TemplateDesigner( QWidget* parent ) + : mIsBasedOnCopy(false), QWizard(parent) + { + setWindowTitle( tr("Product Template Designer") ); + setPixmap( QWizard::LogoPixmap, QPixmap( ":icons/scalable/apps/glabels.svg" ) ); + setWizardStyle( QWizard::ModernStyle ); + setOption( QWizard::IndependentPages, false ); + setOption( QWizard::NoBackButtonOnStartPage, true ); + + setPage( IntroPageId, new TemplateDesignerIntroPage() ); + setPage( NamePageId, new TemplateDesignerNamePage() ); + setPage( PageSizePageId, new TemplateDesignerPageSizePage() ); + setPage( ShapePageId, new TemplateDesignerShapePage() ); + setPage( RectPageId, new TemplateDesignerRectPage() ); + setPage( RoundPageId, new TemplateDesignerRoundPage() ); + setPage( EllipsePageId, new TemplateDesignerEllipsePage() ); + setPage( CdPageId, new TemplateDesignerCdPage() ); + setPage( NLayoutsPageId, new TemplateDesignerNLayoutsPage() ); + setPage( OneLayoutPageId, new TemplateDesignerOneLayoutPage() ); + setPage( TwoLayoutPageId, new TemplateDesignerTwoLayoutPage() ); + setPage( ApplyPageId, new TemplateDesignerApplyPage() ); + } + + + /// + /// Control wizard's non-linear page order + /// + int TemplateDesigner::nextId() const + { + switch (currentId()) + { + + case IntroPageId: + return NamePageId; + + case NamePageId: + return PageSizePageId; + + case PageSizePageId: + return ShapePageId; + + case ShapePageId: + if ( field( "shape.rect" ).toBool() ) + { + return RectPageId; + } + else if ( field( "shape.round" ).toBool() ) + { + return RoundPageId; + } + else if ( field( "shape.ellipse" ).toBool() ) + { + return EllipsePageId; + } + else + { + return CdPageId; + } + + case RectPageId: + return NLayoutsPageId; + + case RoundPageId: + return NLayoutsPageId; + + case EllipsePageId: + return NLayoutsPageId; + + case CdPageId: + return NLayoutsPageId; + + case NLayoutsPageId: + if ( field( "nLayouts.one" ).toBool() ) + { + return OneLayoutPageId; + } + else + { + return TwoLayoutPageId; + } + + case OneLayoutPageId: + return ApplyPageId; + + case TwoLayoutPageId: + return ApplyPageId; + + case ApplyPageId: + default: + return -1; + } + } + + + /// + /// Determine width of individual item + /// + double TemplateDesigner::itemWidth() + { + // Note: all distance units are the same in wizard, so no conversions needed + if ( field( "shape.rect" ).toBool() ) + { + return field( "rect.w" ).toDouble(); + } + else if ( field( "shape.round" ).toBool() ) + { + return 2 * field( "round.r" ).toDouble(); + } + else if ( field( "shape.ellipse" ).toBool() ) + { + return field( "ellipse.w" ).toDouble(); + } + else + { + if ( field( "cd.xClip" ).toDouble() == 0 ) + { + return 2 * field( "cd.r1" ).toDouble(); + } + else + { + return field( "cd.xClip" ).toDouble(); + } + } + } + + + /// + /// Determine height of individual item + /// + double TemplateDesigner::itemHeight() + { + // Note: all distance units are the same in wizard, so no conversions needed + if ( field( "shape.rect" ).toBool() ) + { + return field( "rect.h" ).toDouble(); + } + else if ( field( "shape.round" ).toBool() ) + { + return 2 * field( "round.r" ).toDouble(); + } + else if ( field( "shape.ellipse" ).toBool() ) + { + return field( "ellipse.h" ).toDouble(); + } + else + { + if ( field( "cd.xClip" ).toDouble() == 0 ) + { + return 2 * field( "cd.r1" ).toDouble(); + } + else + { + return field( "cd.yClip" ).toDouble(); + } + } + } + + + /// + /// Determine X Waste of individual item + /// + double TemplateDesigner::itemXWaste() + { + // Note: all distance units are the same in wizard, so no conversions needed + if ( field( "shape.rect" ).toBool() ) + { + return field( "rect.xWaste" ).toDouble(); + } + else if ( field( "shape.round" ).toBool() ) + { + return 2 * field( "round.waste" ).toDouble(); + } + else if ( field( "shape.ellipse" ).toBool() ) + { + return field( "ellipse.waste" ).toDouble(); + } + else + { + return field( "cd.waste" ).toDouble(); + } + } + + + /// + /// Determine Y Waste of individual item + /// + double TemplateDesigner::itemYWaste() + { + // Note: all distance units are the same in wizard, so no conversions needed + if ( field( "shape.rect" ).toBool() ) + { + return field( "rect.yWaste" ).toDouble(); + } + else if ( field( "shape.round" ).toBool() ) + { + return 2 * field( "round.waste" ).toDouble(); + } + else if ( field( "shape.ellipse" ).toBool() ) + { + return field( "ellipse.waste" ).toDouble(); + } + else + { + return field( "cd.waste" ).toDouble(); + } + } + + + /// + /// Build template from wizard pages + /// + model::Template* TemplateDesigner::buildTemplate() + { + model::Units units = model::Settings::units(); + + QString brand = field( "name.brand" ).toString(); + QString part = field( "name.part" ).toString(); + QString description = field( "name.description" ).toString(); + QString paperId = model::Db::lookupPaperIdFromName( field( "pageSize.pageSize" ).toString() ); + model::Distance pageW( field( "pageSize.w" ).toDouble(), units ); + model::Distance pageH( field( "pageSize.h" ).toDouble(), units ); + + auto t = new model::Template( brand, part, description, paperId, pageW, pageH, true ); + + model::Frame* frame; + if ( field( "shape.rect" ).toBool() ) + { + model::Distance w( field( "rect.w" ).toDouble(), units ); + model::Distance h( field( "rect.h" ).toDouble(), units ); + model::Distance r( field( "rect.r" ).toDouble(), units ); + model::Distance xWaste( field( "rect.xWaste" ).toDouble(), units ); + model::Distance yWaste( field( "rect.yWaste" ).toDouble(), units ); + model::Distance margin( field( "rect.margin" ).toDouble(), units ); + + frame = new model::FrameRect( w, h, r, xWaste, yWaste ); + frame->addMarkup( new model::MarkupMargin( frame, margin ) ); + } + else if ( field( "shape.round" ).toBool() ) + { + model::Distance r( field( "round.r" ).toDouble(), units ); + model::Distance waste( field( "round.waste" ).toDouble(), units ); + model::Distance margin( field( "round.margin" ).toDouble(), units ); + + frame = new model::FrameRound( r, waste ); + frame->addMarkup( new model::MarkupMargin( frame, margin ) ); + } + else if ( field( "shape.ellipse" ).toBool() ) + { + model::Distance w( field( "ellipse.w" ).toDouble(), units ); + model::Distance h( field( "ellipse.h" ).toDouble(), units ); + model::Distance waste( field( "ellipse.waste" ).toDouble(), units ); + model::Distance margin( field( "ellipse.margin" ).toDouble(), units ); + + frame = new model::FrameEllipse( w, h, waste ); + frame->addMarkup( new model::MarkupMargin( frame, margin ) ); + } + else + { + model::Distance r1( field( "cd.r1" ).toDouble(), units ); + model::Distance r2( field( "cd.r2" ).toDouble(), units ); + model::Distance xClip( field( "cd.xClip" ).toDouble(), units ); + model::Distance yClip( field( "cd.yClip" ).toDouble(), units ); + model::Distance waste( field( "cd.waste" ).toDouble(), units ); + model::Distance margin( field( "cd.margin" ).toDouble(), units ); + + frame = new model::FrameCd( r1, r2, xClip, yClip, waste ); + frame->addMarkup( new model::MarkupMargin( frame, margin ) ); + } + t->addFrame( frame ); + + if ( field( "nLayouts.one" ).toBool() ) + { + int nx = field( "oneLayout.nx" ).toInt(); + int ny = field( "oneLayout.ny" ).toInt(); + model::Distance x0( field( "oneLayout.x0" ).toDouble(), units ); + model::Distance y0( field( "oneLayout.y0" ).toDouble(), units ); + model::Distance dx( field( "oneLayout.dx" ).toDouble(), units ); + model::Distance dy( field( "oneLayout.dy" ).toDouble(), units ); + + frame->addLayout( new model::Layout( nx, ny, x0, y0, dx, dy ) ); + } + else + { + int nx1 = field( "twoLayout.nx1" ).toInt(); + int ny1 = field( "twoLayout.ny1" ).toInt(); + model::Distance x01( field( "twoLayout.x01" ).toDouble(), units ); + model::Distance y01( field( "twoLayout.y01" ).toDouble(), units ); + model::Distance dx1( field( "twoLayout.dx1" ).toDouble(), units ); + model::Distance dy1( field( "twoLayout.dy1" ).toDouble(), units ); + + int nx2 = field( "twoLayout.nx2" ).toInt(); + int ny2 = field( "twoLayout.ny2" ).toInt(); + model::Distance x02( field( "twoLayout.x02" ).toDouble(), units ); + model::Distance y02( field( "twoLayout.y02" ).toDouble(), units ); + model::Distance dx2( field( "twoLayout.dx2" ).toDouble(), units ); + model::Distance dy2( field( "twoLayout.dy2" ).toDouble(), units ); + + frame->addLayout( new model::Layout( nx1, ny1, x01, y01, dx1, dy1 ) ); + frame->addLayout( new model::Layout( nx2, ny2, x02, y02, dx2, dy2 ) ); + } + + return t; + } + + + /// + /// Print test sheet + /// + void TemplateDesigner::printTestSheet() + { + auto sheet = new model::Model(); + sheet->setTmplate( buildTemplate() ); + + model::PageRenderer renderer( sheet ); + renderer.setNCopies( sheet->frame()->nLabels() ); + renderer.setStartLabel( 0 ); + renderer.setPrintOutlines( true ); + + QPrinter printer( QPrinter::HighResolution ); + + QPrintDialog printDialog( &printer, this ); + printDialog.setOption( QAbstractPrintDialog::PrintToFile, true ); + printDialog.setOption( QAbstractPrintDialog::PrintSelection, false ); + printDialog.setOption( QAbstractPrintDialog::PrintPageRange, false ); + printDialog.setOption( QAbstractPrintDialog::PrintShowPageSize, true ); + printDialog.setOption( QAbstractPrintDialog::PrintCollateCopies, false ); + printDialog.setOption( QAbstractPrintDialog::PrintCurrentPage, false ); + + if ( printDialog.exec() == QDialog::Accepted ) + { + renderer.print( &printer ); + } + + delete sheet; + } + + + /// + /// Load wizard from template + /// + void TemplateDesigner::loadFromTemplate( const model::Template* tmplate ) + { + mIsBasedOnCopy = true; + + model::Units units = model::Settings::units(); + + setField( "name.brand", tmplate->brand() ); + setField( "name.part", tmplate->part() + QString(" (%1)").arg( tr("Copy") ) ); + setField( "name.description", tmplate->description() ); + + setField( "pageSize.pageSize", model::Db::lookupPaperNameFromId( tmplate->paperId() ) ); + setField( "pageSize.w", tmplate->pageWidth().inUnits( units ) ); + setField( "pageSize.h", tmplate->pageHeight().inUnits( units ) ); + + const model::Frame* frame = tmplate->frames().first(); + if ( auto frameRect = dynamic_cast( frame ) ) + { + setField( "shape.rect", true ); + + setField( "rect.w", frameRect->w().inUnits( units ) ); + setField( "rect.h", frameRect->h().inUnits( units ) ); + setField( "rect.r", frameRect->r().inUnits( units ) ); + setField( "rect.xWaste", frameRect->xWaste().inUnits( units ) ); + setField( "rect.yWaste", frameRect->yWaste().inUnits( units ) ); + } + else if ( auto frameRound = dynamic_cast( frame ) ) + { + setField( "shape.round", true ); + + setField( "round.r", frameRound->r().inUnits( units ) ); + setField( "round.waste", frameRound->waste().inUnits( units ) ); + } + else if ( auto frameEllipse = dynamic_cast( frame ) ) + { + setField( "shape.ellipse", true ); + + setField( "ellipse.w", frameEllipse->w().inUnits( units ) ); + setField( "ellipse.h", frameEllipse->h().inUnits( units ) ); + setField( "ellipse.waste", frameEllipse->waste().inUnits( units ) ); + } + else if ( auto frameCd = dynamic_cast( frame ) ) + { + setField( "shape.cd", true ); + + setField( "cd.r1", frameCd->r1().inUnits( units ) ); + setField( "cd.r2", frameCd->r2().inUnits( units ) ); + setField( "cd.xClip", frameCd->w().inUnits( units ) ); + setField( "cd.yClip", frameCd->h().inUnits( units ) ); + setField( "cd.waste", frameCd->waste().inUnits( units ) ); + } + + foreach( auto markup, frame->markups() ) + { + if ( auto markupMargin = dynamic_cast( markup ) ) + { + setField( "rect.margin", markupMargin->size().inUnits( units ) ); + setField( "round.margin", markupMargin->size().inUnits( units ) ); + setField( "ellipse.margin", markupMargin->size().inUnits( units ) ); + setField( "cd.margin", markupMargin->size().inUnits( units ) ); + } + } + + QList layouts = frame->layouts(); + if ( layouts.size() == 1 ) + { + setField( "oneLayout.nx", layouts[0]->nx() ); + setField( "oneLayout.ny", layouts[0]->ny() ); + setField( "oneLayout.x0", layouts[0]->x0().inUnits( units ) ); + setField( "oneLayout.y0", layouts[0]->y0().inUnits( units ) ); + setField( "oneLayout.dx", layouts[0]->dx().inUnits( units ) ); + setField( "oneLayout.dy", layouts[0]->dy().inUnits( units ) ); + } + else if ( layouts.size() > 1 ) + { + setField( "twoLayout.nx1", layouts[0]->nx() ); + setField( "twoLayout.ny1", layouts[0]->ny() ); + setField( "twoLayout.x01", layouts[0]->x0().inUnits( units ) ); + setField( "twoLayout.y01", layouts[0]->y0().inUnits( units ) ); + setField( "twoLayout.dx1", layouts[0]->dx().inUnits( units ) ); + setField( "twoLayout.dy1", layouts[0]->dy().inUnits( units ) ); + + setField( "twoLayout.nx2", layouts[1]->nx() ); + setField( "twoLayout.ny2", layouts[1]->ny() ); + setField( "twoLayout.x02", layouts[1]->x0().inUnits( units ) ); + setField( "twoLayout.y02", layouts[1]->y0().inUnits( units ) ); + setField( "twoLayout.dx2", layouts[1]->dx().inUnits( units ) ); + setField( "twoLayout.dy2", layouts[1]->dy().inUnits( units ) ); + } + } + + + /// + /// Is the wizard based on a copy? + /// + bool TemplateDesigner::isBasedOnCopy() + { + return mIsBasedOnCopy; + } + + + /// + /// Intro Page + /// + TemplateDesignerIntroPage::TemplateDesignerIntroPage( QWidget* parent ) : QWizardPage(parent) + { + setTitle( tr("Welcome") ); + setSubTitle( tr("Welcome to the gLabels Product Template Designer.") ); + setPixmap( QWizard::WatermarkPixmap, QPixmap( ":images/TemplateDesigner/wizard-banner.png" ) ); + + QWidget* widget = new QWidget; + setupUi( widget ); + + connect( copyButton, &QCommandLinkButton::clicked, this, &TemplateDesignerIntroPage::onCopyButtonClicked ); + connect( newButton, &QCommandLinkButton::clicked, this, &TemplateDesignerIntroPage::onNewButtonClicked ); + + QVBoxLayout* layout = new QVBoxLayout; + layout->addWidget( widget ); + setLayout( layout ); + } + + + bool TemplateDesignerIntroPage::isComplete() const + { + // Use CommandLinkButtons on intro page to advance + return false; + } + + + void TemplateDesignerIntroPage::onCopyButtonClicked() + { + SelectProductDialog dialog; + dialog.exec(); + + const model::Template* tmplate = dialog.tmplate(); + if ( tmplate ) + { + if ( auto td = dynamic_cast( wizard() ) ) + { + td->loadFromTemplate( tmplate ); + td->next(); + } + } + } + + + void TemplateDesignerIntroPage::onNewButtonClicked() + { + wizard()->next(); + } + + + /// + /// Name and Description Page + /// + TemplateDesignerNamePage::TemplateDesignerNamePage( QWidget* parent ) : QWizardPage(parent) + { + setTitle( tr("Name and Description") ); + setSubTitle( tr("Please enter the following identifying information about the product.") ); + + QWidget* widget = new QWidget; + setupUi( widget ); + + warningLabel->setText( "" ); + + registerField( "name.brand", brandEntry ); + registerField( "name.part", partEntry ); + registerField( "name.description", descriptionEntry ); + + connect( brandEntry, &QLineEdit::textChanged, this, &TemplateDesignerNamePage::onChanged ); + connect( partEntry, &QLineEdit::textChanged, this, &TemplateDesignerNamePage::onChanged ); + + QVBoxLayout* layout = new QVBoxLayout; + layout->addWidget( widget ); + setLayout( layout ); + } + + + bool TemplateDesignerNamePage::isComplete() const + { + return mCanContinue; + } + + + void TemplateDesignerNamePage::onChanged() + { + bool isDuplicate = model::Db::isSystemTemplateKnown( brandEntry->text(), partEntry->text() ); + if ( isDuplicate ) + { + QString warningText = tr("Brand and part number match an existing built-in product template!"); + warningLabel->setText( "" + warningText + "" ); + } + else + { + warningLabel->setText( "" ); + } + + mCanContinue = !brandEntry->text().isEmpty() && !partEntry->text().isEmpty() && !isDuplicate; + emit completeChanged(); + } + + + /// + /// Page Size Page + /// + TemplateDesignerPageSizePage::TemplateDesignerPageSizePage( QWidget* parent ) : QWizardPage(parent) + { + setTitle( tr("Page Size") ); + setSubTitle( tr("Please select the product page size.") ); + + QWidget* widget = new QWidget; + setupUi( widget ); + + pageSizeCombo->insertItem( 0, tr("Other") ); + pageSizeCombo->insertItems( 1, model::Db::paperNames() ); + pageSizeCombo->setCurrentText( defaultPageSize[ model::Settings::preferedPageSizeFamily() ] ); + + wSpin->setSuffix( " " + model::Settings::units().toTrName() ); + wSpin->setDecimals( model::Settings::units().resolutionDigits() ); + wSpin->setSingleStep( model::Settings::units().resolution() ); + wSpin->setMaximum( maxPageSize[ model::Settings::units().toEnum() ] ); + wSpin->setEnabled( pageSizeCombo->currentText() == tr("Other") ); + + hSpin->setSuffix( " " + model::Settings::units().toTrName() ); + hSpin->setDecimals( model::Settings::units().resolutionDigits() ); + hSpin->setSingleStep( model::Settings::units().resolution() ); + hSpin->setMaximum( maxPageSize[ model::Settings::units().toEnum() ] ); + hSpin->setEnabled( pageSizeCombo->currentText() == tr("Other") ); + + if ( pageSizeCombo->currentText() != tr("Other") ) + { + const model::Paper* paper = model::Db::lookupPaperFromName( pageSizeCombo->currentText() ); + wSpin->setValue( paper->width().inUnits( model::Settings::units() ) ); + hSpin->setValue( paper->height().inUnits( model::Settings::units() ) ); + } + + registerField( "pageSize.pageSize", pageSizeCombo, "currentText" ); + registerField( "pageSize.w", wSpin, "value" ); + registerField( "pageSize.h", hSpin, "value" ); + + connect( pageSizeCombo, &QComboBox::currentTextChanged, this, &TemplateDesignerPageSizePage::onComboChanged ); + + QVBoxLayout* layout = new QVBoxLayout; + layout->addWidget( widget ); + setLayout( layout ); + } + + + void TemplateDesignerPageSizePage::initializePage() + { + } + + + void TemplateDesignerPageSizePage::cleanupPage() + { + // Leave current settings alone + } + + + void TemplateDesignerPageSizePage::onComboChanged() + { + if ( pageSizeCombo->currentText() != tr("Other") ) + { + const model::Paper* paper = model::Db::lookupPaperFromName( pageSizeCombo->currentText() ); + wSpin->setValue( paper->width().inUnits( model::Settings::units() ) ); + hSpin->setValue( paper->height().inUnits( model::Settings::units() ) ); + } + + wSpin->setEnabled( pageSizeCombo->currentText() == tr("Other") ); + hSpin->setEnabled( pageSizeCombo->currentText() == tr("Other") ); + } + + + /// + /// Shape Page + /// + TemplateDesignerShapePage::TemplateDesignerShapePage( QWidget* parent ) : QWizardPage(parent) + { + setTitle( tr("Product Shape") ); + setSubTitle( tr("Please select the basic product shape.") ); + + QWidget* widget = new QWidget; + setupUi( widget ); + + registerField( "shape.rect", rectRadio ); + registerField( "shape.round", roundRadio ); + registerField( "shape.ellipse", ellipseRadio ); + registerField( "shape.cd", cdRadio ); + + QVBoxLayout* layout = new QVBoxLayout; + layout->addWidget( widget ); + setLayout( layout ); + } + + + void TemplateDesignerShapePage::initializePage() + { + } + + + void TemplateDesignerShapePage::cleanupPage() + { + // Leave current settings alone + } + + + /// + /// Rectangular Product Page + /// + TemplateDesignerRectPage::TemplateDesignerRectPage( QWidget* parent ) : QWizardPage(parent) + { + setTitle( tr("Product Size") ); + setSubTitle( tr("Please adjust the size parameters of a single product item.") ); + + QWidget* widget = new QWidget; + setupUi( widget ); + + wSpin->setSuffix( " " + model::Settings::units().toTrName() ); + wSpin->setDecimals( model::Settings::units().resolutionDigits() ); + wSpin->setSingleStep( model::Settings::units().resolution() ); + + hSpin->setSuffix( " " + model::Settings::units().toTrName() ); + hSpin->setDecimals( model::Settings::units().resolutionDigits() ); + hSpin->setSingleStep( model::Settings::units().resolution() ); + + rSpin->setSuffix( " " + model::Settings::units().toTrName() ); + rSpin->setDecimals( model::Settings::units().resolutionDigits() ); + rSpin->setSingleStep( model::Settings::units().resolution() ); + + xWasteSpin->setSuffix( " " + model::Settings::units().toTrName() ); + xWasteSpin->setDecimals( model::Settings::units().resolutionDigits() ); + xWasteSpin->setSingleStep( model::Settings::units().resolution() ); + + yWasteSpin->setSuffix( " " + model::Settings::units().toTrName() ); + yWasteSpin->setDecimals( model::Settings::units().resolutionDigits() ); + yWasteSpin->setSingleStep( model::Settings::units().resolution() ); + + marginSpin->setSuffix( " " + model::Settings::units().toTrName() ); + marginSpin->setDecimals( model::Settings::units().resolutionDigits() ); + marginSpin->setSingleStep( model::Settings::units().resolution() ); + + registerField( "rect.w", wSpin, "value" ); + registerField( "rect.h", hSpin, "value" ); + registerField( "rect.r", rSpin, "value" ); + registerField( "rect.xWaste", xWasteSpin, "value" ); + registerField( "rect.yWaste", yWasteSpin, "value" ); + registerField( "rect.margin", marginSpin, "value" ); + + QVBoxLayout* layout = new QVBoxLayout; + layout->addWidget( widget ); + setLayout( layout ); + } + + + void TemplateDesignerRectPage::initializePage() + { + if ( auto td = dynamic_cast( wizard() ) ) + { + // set realistic limits based on previously chosen page size + double wMax = field("pageSize.w").toDouble(); + double hMax = field("pageSize.h").toDouble(); + + wSpin->setMaximum( wMax ); + hSpin->setMaximum( hMax ); + rSpin->setMaximum( std::min(wMax,hMax)/2.0 ); + xWasteSpin->setMaximum( std::min(wMax,hMax)/4.0 ); + yWasteSpin->setMaximum( std::min(wMax,hMax)/4.0 ); + marginSpin->setMaximum( std::min(wMax,hMax)/4.0 ); + + static bool alreadyInitialized = false; + if ( !td->isBasedOnCopy() && !alreadyInitialized ) + { + alreadyInitialized = true; + + // Set some realistic defaults + wSpin->setValue( defaultRectW.inUnits( model::Settings::units() ) ); + hSpin->setValue( defaultRectH.inUnits( model::Settings::units() ) ); + rSpin->setValue( defaultRectR.inUnits( model::Settings::units() ) ); + xWasteSpin->setValue( defaultWaste.inUnits( model::Settings::units() ) ); + yWasteSpin->setValue( defaultWaste.inUnits( model::Settings::units() ) ); + marginSpin->setValue( defaultMargin.inUnits( model::Settings::units() ) ); + } + } + } + + + void TemplateDesignerRectPage::cleanupPage() + { + // Leave current settings alone + } + + + /// + /// Round Product Page + /// + TemplateDesignerRoundPage::TemplateDesignerRoundPage( QWidget* parent ) : QWizardPage(parent) + { + setTitle( tr("Product Size") ); + setSubTitle( tr("Please adjust the size parameters of a single product item.") ); + + QWidget* widget = new QWidget; + setupUi( widget ); + + rSpin->setSuffix( " " + model::Settings::units().toTrName() ); + rSpin->setDecimals( model::Settings::units().resolutionDigits() ); + rSpin->setSingleStep( model::Settings::units().resolution() ); + + wasteSpin->setSuffix( " " + model::Settings::units().toTrName() ); + wasteSpin->setDecimals( model::Settings::units().resolutionDigits() ); + wasteSpin->setSingleStep( model::Settings::units().resolution() ); + + marginSpin->setSuffix( " " + model::Settings::units().toTrName() ); + marginSpin->setDecimals( model::Settings::units().resolutionDigits() ); + marginSpin->setSingleStep( model::Settings::units().resolution() ); + + registerField( "round.r", rSpin, "value" ); + registerField( "round.waste", wasteSpin, "value" ); + registerField( "round.margin", marginSpin, "value" ); + + QVBoxLayout* layout = new QVBoxLayout; + layout->addWidget( widget ); + setLayout( layout ); + } + + + void TemplateDesignerRoundPage::initializePage() + { + if ( auto td = dynamic_cast( wizard() ) ) + { + // set realistic limits based on previously chosen page size + double wMax = field("pageSize.w").toDouble(); + double hMax = field("pageSize.h").toDouble(); + + rSpin->setMaximum( std::min(wMax,hMax)/2.0 ); + wasteSpin->setMaximum( std::min(wMax,hMax)/4.0 ); + marginSpin->setMaximum( std::min(wMax,hMax)/4.0 ); + + static bool alreadyInitialized = false; + if ( !td->isBasedOnCopy() && !alreadyInitialized ) + { + alreadyInitialized = true; + + // Set some realistic defaults + rSpin->setValue( defaultRoundR.inUnits( model::Settings::units() ) ); + wasteSpin->setValue( defaultWaste.inUnits( model::Settings::units() ) ); + marginSpin->setValue( defaultMargin.inUnits( model::Settings::units() ) ); + } + } + } + + + void TemplateDesignerRoundPage::cleanupPage() + { + // Leave current settings alone + } + + + /// + /// Elliptical Product Page + /// + TemplateDesignerEllipsePage::TemplateDesignerEllipsePage( QWidget* parent ) : QWizardPage(parent) + { + setTitle( tr("Product Size") ); + setSubTitle( tr("Please adjust the size parameters of a single product item.") ); + + QWidget* widget = new QWidget; + setupUi( widget ); + + wSpin->setSuffix( " " + model::Settings::units().toTrName() ); + wSpin->setDecimals( model::Settings::units().resolutionDigits() ); + wSpin->setSingleStep( model::Settings::units().resolution() ); + + hSpin->setSuffix( " " + model::Settings::units().toTrName() ); + hSpin->setDecimals( model::Settings::units().resolutionDigits() ); + hSpin->setSingleStep( model::Settings::units().resolution() ); + + wasteSpin->setSuffix( " " + model::Settings::units().toTrName() ); + wasteSpin->setDecimals( model::Settings::units().resolutionDigits() ); + wasteSpin->setSingleStep( model::Settings::units().resolution() ); + + marginSpin->setSuffix( " " + model::Settings::units().toTrName() ); + marginSpin->setDecimals( model::Settings::units().resolutionDigits() ); + marginSpin->setSingleStep( model::Settings::units().resolution() ); + + registerField( "ellipse.w", wSpin, "value" ); + registerField( "ellipse.h", hSpin, "value" ); + registerField( "ellipse.waste", wasteSpin, "value" ); + registerField( "ellipse.margin", marginSpin, "value" ); + + QVBoxLayout* layout = new QVBoxLayout; + layout->addWidget( widget ); + setLayout( layout ); + } + + + void TemplateDesignerEllipsePage::initializePage() + { + if ( auto td = dynamic_cast( wizard() ) ) + { + // set realistic limits based on previously chosen page size + double wMax = field("pageSize.w").toDouble(); + double hMax = field("pageSize.h").toDouble(); + + wSpin->setMaximum( wMax ); + hSpin->setMaximum( hMax ); + wasteSpin->setMaximum( std::min(wMax,hMax)/4.0 ); + marginSpin->setMaximum( std::min(wMax,hMax)/4.0 ); + + static bool alreadyInitialized = false; + if ( !td->isBasedOnCopy() && !alreadyInitialized ) + { + alreadyInitialized = true; + + // Set some realistic defaults + wSpin->setValue( defaultEllipseW.inUnits( model::Settings::units() ) ); + hSpin->setValue( defaultEllipseH.inUnits( model::Settings::units() ) ); + wasteSpin->setValue( defaultWaste.inUnits( model::Settings::units() ) ); + marginSpin->setValue( defaultMargin.inUnits( model::Settings::units() ) ); + } + } + } + + + void TemplateDesignerEllipsePage::cleanupPage() + { + // Leave current settings alone + } + + + /// + /// CD/DVD Product Page + /// + TemplateDesignerCdPage::TemplateDesignerCdPage( QWidget* parent ) : QWizardPage(parent) + { + setTitle( tr("Product Size") ); + setSubTitle( tr("Please adjust the size parameters of a single product item.") ); + + QWidget* widget = new QWidget; + setupUi( widget ); + + r1Spin->setSuffix( " " + model::Settings::units().toTrName() ); + r1Spin->setDecimals( model::Settings::units().resolutionDigits() ); + r1Spin->setSingleStep( model::Settings::units().resolution() ); + + r2Spin->setSuffix( " " + model::Settings::units().toTrName() ); + r2Spin->setDecimals( model::Settings::units().resolutionDigits() ); + r2Spin->setSingleStep( model::Settings::units().resolution() ); + + xClipSpin->setSuffix( " " + model::Settings::units().toTrName() ); + xClipSpin->setDecimals( model::Settings::units().resolutionDigits() ); + xClipSpin->setSingleStep( model::Settings::units().resolution() ); + + yClipSpin->setSuffix( " " + model::Settings::units().toTrName() ); + yClipSpin->setDecimals( model::Settings::units().resolutionDigits() ); + yClipSpin->setSingleStep( model::Settings::units().resolution() ); + + wasteSpin->setSuffix( " " + model::Settings::units().toTrName() ); + wasteSpin->setDecimals( model::Settings::units().resolutionDigits() ); + wasteSpin->setSingleStep( model::Settings::units().resolution() ); + + marginSpin->setSuffix( " " + model::Settings::units().toTrName() ); + marginSpin->setDecimals( model::Settings::units().resolutionDigits() ); + marginSpin->setSingleStep( model::Settings::units().resolution() ); + + registerField( "cd.r1", r1Spin, "value" ); + registerField( "cd.r2", r2Spin, "value" ); + registerField( "cd.xClip", xClipSpin, "value" ); + registerField( "cd.yClip", yClipSpin, "value" ); + registerField( "cd.waste", wasteSpin, "value" ); + registerField( "cd.margin", marginSpin, "value" ); + + QVBoxLayout* layout = new QVBoxLayout; + layout->addWidget( widget ); + setLayout( layout ); + } + + + void TemplateDesignerCdPage::initializePage() + { + if ( auto td = dynamic_cast( wizard() ) ) + { + // set realistic limits based on previously chosen page size + double wMax = field("pageSize.w").toDouble(); + double hMax = field("pageSize.h").toDouble(); + + r1Spin->setMaximum( std::min(wMax,hMax)/2.0 ); + r2Spin->setMaximum( std::min(wMax,hMax)/4.0 ); + xClipSpin->setMaximum( std::min(wMax,hMax)/4.0 ); + yClipSpin->setMaximum( std::min(wMax,hMax)/4.0 ); + wasteSpin->setMaximum( std::min(wMax,hMax)/4.0 ); + marginSpin->setMaximum( std::min(wMax,hMax)/4.0 ); + + static bool alreadyInitialized = false; + if ( !td->isBasedOnCopy() && !alreadyInitialized ) + { + alreadyInitialized = true; + + // Set some realistic defaults + r1Spin->setValue( defaultCdR1.inUnits( model::Settings::units() ) ); + r2Spin->setValue( defaultCdR2.inUnits( model::Settings::units() ) ); + xClipSpin->setValue( defaultCdClip.inUnits( model::Settings::units() ) ); + yClipSpin->setValue( defaultCdClip.inUnits( model::Settings::units() ) ); + wasteSpin->setValue( defaultWaste.inUnits( model::Settings::units() ) ); + marginSpin->setValue( defaultMargin.inUnits( model::Settings::units() ) ); + } + } + } + + + void TemplateDesignerCdPage::cleanupPage() + { + // Leave current settings alone + } + + + /// + /// Number of Layouts Page + /// + TemplateDesignerNLayoutsPage::TemplateDesignerNLayoutsPage( QWidget* parent ) : QWizardPage(parent) + { + setTitle( tr("Number of Layouts") ); + setSubTitle( tr("Please select the number of layouts required.") ); + + QWidget* widget = new QWidget; + setupUi( widget ); + + registerField( "nLayouts.one", oneLayoutRadio ); + registerField( "nLayouts.two", twoLayoutsRadio ); + + QVBoxLayout* layout = new QVBoxLayout; + layout->addWidget( widget ); + setLayout( layout ); + } + + + void TemplateDesignerNLayoutsPage::initializePage() + { + } + + + void TemplateDesignerNLayoutsPage::cleanupPage() + { + // Leave current settings alone + } + + + /// + /// One Layout Page + /// + TemplateDesignerOneLayoutPage::TemplateDesignerOneLayoutPage( QWidget* parent ) : QWizardPage(parent) + { + setTitle( tr("Layout") ); + setSubTitle( tr("Please enter parameters for your single layout.") ); + + QWidget* widget = new QWidget; + setupUi( widget ); + + x0Spin->setSuffix( " " + model::Settings::units().toTrName() ); + x0Spin->setDecimals( model::Settings::units().resolutionDigits() ); + x0Spin->setSingleStep( model::Settings::units().resolution() ); + + y0Spin->setSuffix( " " + model::Settings::units().toTrName() ); + y0Spin->setDecimals( model::Settings::units().resolutionDigits() ); + y0Spin->setSingleStep( model::Settings::units().resolution() ); + + dxSpin->setSuffix( " " + model::Settings::units().toTrName() ); + dxSpin->setDecimals( model::Settings::units().resolutionDigits() ); + dxSpin->setSingleStep( model::Settings::units().resolution() ); + + dySpin->setSuffix( " " + model::Settings::units().toTrName() ); + dySpin->setDecimals( model::Settings::units().resolutionDigits() ); + dySpin->setSingleStep( model::Settings::units().resolution() ); + + registerField( "oneLayout.nx", nxSpin ); + registerField( "oneLayout.ny", nySpin ); + registerField( "oneLayout.x0", x0Spin, "value" ); + registerField( "oneLayout.y0", y0Spin, "value" ); + registerField( "oneLayout.dx", dxSpin, "value" ); + registerField( "oneLayout.dy", dySpin, "value" ); + + connect( nxSpin, SIGNAL(valueChanged(int)), this, SLOT(onChanged()) ); + connect( nySpin, SIGNAL(valueChanged(int)), this, SLOT(onChanged()) ); + connect( x0Spin, SIGNAL(valueChanged(double)), this, SLOT(onChanged()) ); + connect( y0Spin, SIGNAL(valueChanged(double)), this, SLOT(onChanged()) ); + connect( dxSpin, SIGNAL(valueChanged(double)), this, SLOT(onChanged()) ); + connect( dySpin, SIGNAL(valueChanged(double)), this, SLOT(onChanged()) ); + + connect( printButton, SIGNAL(clicked()), this, SLOT(onPrintButtonClicked()) ); + + QVBoxLayout* layout = new QVBoxLayout; + layout->addWidget( widget ); + setLayout( layout ); + } + + + void TemplateDesignerOneLayoutPage::initializePage() + { + if ( auto td = dynamic_cast( wizard() ) ) + { + // set realistic limits based on previously chosen values + double pageW = field("pageSize.w").toDouble(); + double pageH = field("pageSize.h").toDouble(); + double w = td->itemWidth(); + double h = td->itemHeight(); + double xWaste = td->itemXWaste(); + double yWaste = td->itemYWaste(); + + int nxMax = std::max( pageW/(w + 2*xWaste), 1.0 ); + int nyMax = std::max( pageH/(h + 2*yWaste), 1.0 ); + double x0Min = xWaste; + double x0Max = pageW - w - 2*xWaste; + double y0Min = yWaste; + double y0Max = pageH - h - 2*yWaste; + double dxMin = w + 2*xWaste; + double dxMax = pageW - w - 2*xWaste; + double dyMin = h + 2*yWaste; + double dyMax = pageH - h - 2*yWaste; + + nxSpin->setRange( 1, nxMax ); + nySpin->setRange( 1, nyMax ); + x0Spin->setRange( x0Min, x0Max ); + y0Spin->setRange( y0Min, y0Max ); + dxSpin->setRange( dxMin, dxMax ); + dySpin->setRange( dyMin, dxMax ); + + static bool alreadyInitialized = false; + if ( !td->isBasedOnCopy() && !alreadyInitialized ) + { + alreadyInitialized = true; + + // Set some realistic defaults based on symetric sheet using previosly chosen values + nxSpin->setValue( nxMax ); + nySpin->setValue( nyMax ); + x0Spin->setValue( (pageW - (nxMax-1)*dxMin - w) / 2 ); + y0Spin->setValue( (pageH - (nyMax-1)*dyMin - h) / 2 ); + dxSpin->setValue( dxMin ); + dySpin->setValue( dyMin ); + } + + preview->setTemplate( td->buildTemplate() ); + } + } + + + void TemplateDesignerOneLayoutPage::cleanupPage() + { + // Leave current settings alone + } + + + void TemplateDesignerOneLayoutPage::onChanged() + { + if ( auto td = dynamic_cast( wizard() ) ) + { + preview->setTemplate( td->buildTemplate() ); + } + } + + + void TemplateDesignerOneLayoutPage::onPrintButtonClicked() + { + if ( auto td = dynamic_cast( wizard() ) ) + { + td->printTestSheet(); + } + } + + + /// + /// Two Layout Page + /// + TemplateDesignerTwoLayoutPage::TemplateDesignerTwoLayoutPage( QWidget* parent ) : QWizardPage(parent) + { + setTitle( tr("Layouts") ); + setSubTitle( tr("Please enter parameters for your two layouts.") ); + + QWidget* widget = new QWidget; + setupUi( widget ); + + x0Spin1->setSuffix( " " + model::Settings::units().toTrName() ); + x0Spin1->setDecimals( model::Settings::units().resolutionDigits() ); + x0Spin1->setSingleStep( model::Settings::units().resolution() ); + + y0Spin1->setSuffix( " " + model::Settings::units().toTrName() ); + y0Spin1->setDecimals( model::Settings::units().resolutionDigits() ); + y0Spin1->setSingleStep( model::Settings::units().resolution() ); + + dxSpin1->setSuffix( " " + model::Settings::units().toTrName() ); + dxSpin1->setDecimals( model::Settings::units().resolutionDigits() ); + dxSpin1->setSingleStep( model::Settings::units().resolution() ); + + dySpin1->setSuffix( " " + model::Settings::units().toTrName() ); + dySpin1->setDecimals( model::Settings::units().resolutionDigits() ); + dySpin1->setSingleStep( model::Settings::units().resolution() ); + + x0Spin2->setSuffix( " " + model::Settings::units().toTrName() ); + x0Spin2->setDecimals( model::Settings::units().resolutionDigits() ); + x0Spin2->setSingleStep( model::Settings::units().resolution() ); + + y0Spin2->setSuffix( " " + model::Settings::units().toTrName() ); + y0Spin2->setDecimals( model::Settings::units().resolutionDigits() ); + y0Spin2->setSingleStep( model::Settings::units().resolution() ); + + dxSpin2->setSuffix( " " + model::Settings::units().toTrName() ); + dxSpin2->setDecimals( model::Settings::units().resolutionDigits() ); + dxSpin2->setSingleStep( model::Settings::units().resolution() ); + + dySpin2->setSuffix( " " + model::Settings::units().toTrName() ); + dySpin2->setDecimals( model::Settings::units().resolutionDigits() ); + dySpin2->setSingleStep( model::Settings::units().resolution() ); + + registerField( "twoLayout.nx1", nxSpin1 ); + registerField( "twoLayout.ny1", nySpin1 ); + registerField( "twoLayout.x01", x0Spin1, "value" ); + registerField( "twoLayout.y01", y0Spin1, "value" ); + registerField( "twoLayout.dx1", dxSpin1, "value" ); + registerField( "twoLayout.dy1", dySpin1, "value" ); + + registerField( "twoLayout.nx2", nxSpin2 ); + registerField( "twoLayout.ny2", nySpin2 ); + registerField( "twoLayout.x02", x0Spin2, "value" ); + registerField( "twoLayout.y02", y0Spin2, "value" ); + registerField( "twoLayout.dx2", dxSpin2, "value" ); + registerField( "twoLayout.dy2", dySpin2, "value" ); + + connect( nxSpin1, SIGNAL(valueChanged(int)), this, SLOT(onChanged()) ); + connect( nySpin1, SIGNAL(valueChanged(int)), this, SLOT(onChanged()) ); + connect( x0Spin1, SIGNAL(valueChanged(double)), this, SLOT(onChanged()) ); + connect( y0Spin1, SIGNAL(valueChanged(double)), this, SLOT(onChanged()) ); + connect( dxSpin1, SIGNAL(valueChanged(double)), this, SLOT(onChanged()) ); + connect( dySpin1, SIGNAL(valueChanged(double)), this, SLOT(onChanged()) ); + + connect( nxSpin2, SIGNAL(valueChanged(int)), this, SLOT(onChanged()) ); + connect( nySpin2, SIGNAL(valueChanged(int)), this, SLOT(onChanged()) ); + connect( x0Spin2, SIGNAL(valueChanged(double)), this, SLOT(onChanged()) ); + connect( y0Spin2, SIGNAL(valueChanged(double)), this, SLOT(onChanged()) ); + connect( dxSpin2, SIGNAL(valueChanged(double)), this, SLOT(onChanged()) ); + connect( dySpin2, SIGNAL(valueChanged(double)), this, SLOT(onChanged()) ); + + connect( printButton, SIGNAL(clicked()), this, SLOT(onPrintButtonClicked()) ); + + QVBoxLayout* layout = new QVBoxLayout; + layout->addWidget( widget ); + setLayout( layout ); + } + + + void TemplateDesignerTwoLayoutPage::initializePage() + { + if ( auto td = dynamic_cast( wizard() ) ) + { + // set realistic limits based on previously chosen values + double pageW = field("pageSize.w").toDouble(); + double pageH = field("pageSize.h").toDouble(); + double w = td->itemWidth(); + double h = td->itemHeight(); + double xWaste = td->itemXWaste(); + double yWaste = td->itemYWaste(); + + int nxMax = std::max( pageW/(w + 2*xWaste), 1.0 ); + int nyMax = std::max( pageH/(h + 2*yWaste), 1.0 ); + double x0Min = xWaste; + double x0Max = pageW - w - 2*xWaste; + double y0Min = yWaste; + double y0Max = pageH - h - 2*yWaste; + double dxMin = w + 2*xWaste; + double dxMax = pageW - w - 2*xWaste; + double dyMin = h + 2*yWaste; + double dyMax = pageH - h - 2*yWaste; + + nxSpin1->setRange( 1, nxMax ); + nySpin1->setRange( 1, nyMax ); + x0Spin1->setRange( x0Min, x0Max ); + y0Spin1->setRange( y0Min, y0Max ); + dxSpin1->setRange( dxMin, dxMax ); + dySpin1->setRange( dyMin, dyMax ); + + nxSpin2->setRange( 1, nxMax ); + nySpin2->setRange( 1, nyMax ); + x0Spin2->setRange( x0Min, x0Max ); + y0Spin2->setRange( y0Min, y0Max ); + dxSpin2->setRange( dxMin, dxMax ); + dySpin2->setRange( dyMin, dyMax ); + + static bool alreadyInitialized = false; + if ( !td->isBasedOnCopy() && !alreadyInitialized ) + { + alreadyInitialized = true; + + // Set some realistic defaults based on symetric sheet using previosly chosen values + nxSpin1->setValue( nxMax ); + nySpin1->setValue( nyMax - nyMax/2 ); + x0Spin1->setValue( (pageW - (nxMax-1)*dxMin - w) / 2 ); + y0Spin1->setValue( (pageH - (nyMax-1)*dyMin - h) / 2 ); + dxSpin1->setValue( dxMin ); + dySpin1->setValue( 2*dyMin ); + + nxSpin2->setValue( nxMax ); + nySpin2->setValue( nyMax/2 ); + x0Spin2->setValue( (pageW - (nxMax-1)*dxMin - w) / 2 ); + y0Spin2->setValue( (pageH - (nyMax-1)*dyMin - h) / 2 + dyMin ); + dxSpin2->setValue( dxMin ); + dySpin2->setValue( 2*dyMin ); + } + + preview->setTemplate( td->buildTemplate() ); + } + } + + + void TemplateDesignerTwoLayoutPage::cleanupPage() + { + // Leave current settings alone + } + + + void TemplateDesignerTwoLayoutPage::onChanged() + { + if ( auto td = dynamic_cast( wizard() ) ) + { + preview->setTemplate( td->buildTemplate() ); + } + } + + + void TemplateDesignerTwoLayoutPage::onPrintButtonClicked() + { + if ( auto td = dynamic_cast( wizard() ) ) + { + td->printTestSheet(); + } + } + + + /// + /// Apply Page + /// + TemplateDesignerApplyPage::TemplateDesignerApplyPage( QWidget* parent ) : QWizardPage(parent) + { + setTitle( tr("Save Product Template") ); + setSubTitle( tr("Click \"Save\" to save your custom product template!") ); + + setFinalPage( true ); + setButtonText( QWizard::FinishButton, "Save" ); + + QWidget* widget = new QWidget; + setupUi( widget ); + + QVBoxLayout* layout = new QVBoxLayout; + layout->addWidget( widget ); + setLayout( layout ); + } + + + bool TemplateDesignerApplyPage::validatePage() + { + // + // Save button pressed + // + QString brand = field( "name.brand" ).toString(); + QString part = field( "name.part" ).toString(); + QString filename = model::Db::userTemplateFilename( brand, part ); + + if ( QFileInfo::exists(filename) ) + { + QMessageBox msgBox( wizard() ); + msgBox.setWindowTitle( tr("Save Product Template") ); + msgBox.setIcon( QMessageBox::Warning ); + msgBox.setText( tr("User product template (%1 %2) already exists.").arg(brand).arg(part) ); + msgBox.setInformativeText( tr("Do you want to replace it?") ); + msgBox.setStandardButtons( QMessageBox::Yes | QMessageBox::No ); + msgBox.setDefaultButton( QMessageBox::No ); + + if ( msgBox.exec() == QMessageBox::No ) + { + return false; + } + + model::Db::deleteUserTemplateByBrandPart( brand, part ); + } + + if ( auto td = dynamic_cast( wizard() ) ) + { + model::Db::registerUserTemplate( td->buildTemplate() ); + } + return true; + } + + +} // namespace glabels diff --git a/glabels/TemplateDesigner.h b/glabels/TemplateDesigner.h new file mode 100644 index 0000000..15534f3 --- /dev/null +++ b/glabels/TemplateDesigner.h @@ -0,0 +1,289 @@ +/* TemplateDesigner.h + * + * Copyright (C) 2018 Jim Evins + * + * This file is part of gLabels-qt. + * + * gLabels-qt is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * gLabels-qt is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with gLabels-qt. If not, see . + */ + +#ifndef TemplateDesigner_h +#define TemplateDesigner_h + + +#include "ui_TemplateDesignerIntroPage.h" +#include "ui_TemplateDesignerNamePage.h" +#include "ui_TemplateDesignerPageSizePage.h" +#include "ui_TemplateDesignerShapePage.h" +#include "ui_TemplateDesignerRectPage.h" +#include "ui_TemplateDesignerRoundPage.h" +#include "ui_TemplateDesignerEllipsePage.h" +#include "ui_TemplateDesignerCdPage.h" +#include "ui_TemplateDesignerNLayoutsPage.h" +#include "ui_TemplateDesignerOneLayoutPage.h" +#include "ui_TemplateDesignerTwoLayoutPage.h" +#include "ui_TemplateDesignerApplyPage.h" + +#include "model/Template.h" + +#include +#include + + +namespace glabels +{ + /// + /// About Dialog Widget + /// + class TemplateDesigner : public QWizard + { + Q_OBJECT + + // My subpages are my friends :-) + friend class TemplateDesignerIntroPage; + friend class TemplateDesignerNamePage; + friend class TemplateDesignerPageSizePage; + friend class TemplateDesignerShapePage; + friend class TemplateDesignerRectPage; + friend class TemplateDesignerRoundPage; + friend class TemplateDesignerEllipsePage; + friend class TemplateDesignerCdPage; + friend class TemplateDesignerNLayoutsPage; + friend class TemplateDesignerOneLayoutPage; + friend class TemplateDesignerTwoLayoutPage; + friend class TemplateDesignerApplyPage; + + + ///////////////////////////////// + // Life Cycle + ///////////////////////////////// + public: + TemplateDesigner( QWidget *parent = nullptr ); + + + ///////////////////////////////// + // Private methods + ///////////////////////////////// + private: + int nextId() const override; + + double itemWidth(); + double itemHeight(); + double itemXWaste(); + double itemYWaste(); + model::Template* buildTemplate(); + void printTestSheet(); + void loadFromTemplate( const model::Template* tmplate ); + bool isBasedOnCopy(); + + + ///////////////////////////////// + // Private methods + ///////////////////////////////// + private: + bool mIsBasedOnCopy; + }; + + + // + // Intro Page + // + class TemplateDesignerIntroPage : public QWizardPage, public Ui::TemplateDesignerIntroPage + { + Q_OBJECT + + public: + TemplateDesignerIntroPage( QWidget* parent = nullptr ); + + bool isComplete() const override; + + private slots: + void onCopyButtonClicked(); + void onNewButtonClicked(); + }; + + + // + // Name Page + // + class TemplateDesignerNamePage : public QWizardPage, public Ui::TemplateDesignerNamePage + { + Q_OBJECT + public: + TemplateDesignerNamePage( QWidget* parent = nullptr ); + + bool isComplete() const override; + + private slots: + void onChanged(); + + private: + bool mCanContinue = false; + }; + + + // + // Page Size Page + // + class TemplateDesignerPageSizePage : public QWizardPage, public Ui::TemplateDesignerPageSizePage + { + Q_OBJECT + public: + TemplateDesignerPageSizePage( QWidget* parent = nullptr ); + + void initializePage() override; + void cleanupPage() override; + + private slots: + void onComboChanged(); + }; + + + // + // Shape Page + // + class TemplateDesignerShapePage : public QWizardPage, public Ui::TemplateDesignerShapePage + { + Q_OBJECT + public: + TemplateDesignerShapePage( QWidget* parent = nullptr ); + + void initializePage() override; + void cleanupPage() override; + }; + + + // + // Rect Page + // + class TemplateDesignerRectPage : public QWizardPage, public Ui::TemplateDesignerRectPage + { + Q_OBJECT + public: + TemplateDesignerRectPage( QWidget* parent = nullptr ); + + void initializePage() override; + void cleanupPage() override; + }; + + + // + // Round Page + // + class TemplateDesignerRoundPage : public QWizardPage, public Ui::TemplateDesignerRoundPage + { + Q_OBJECT + public: + TemplateDesignerRoundPage( QWidget* parent = nullptr ); + + void initializePage() override; + void cleanupPage() override; + }; + + + // + // Ellipse Page + // + class TemplateDesignerEllipsePage : public QWizardPage, public Ui::TemplateDesignerEllipsePage + { + Q_OBJECT + public: + TemplateDesignerEllipsePage( QWidget* parent = nullptr ); + + void initializePage() override; + void cleanupPage() override; + }; + + + // + // Cd Page + // + class TemplateDesignerCdPage : public QWizardPage, public Ui::TemplateDesignerCdPage + { + Q_OBJECT + public: + TemplateDesignerCdPage( QWidget* parent = nullptr ); + + void initializePage() override; + void cleanupPage() override; + }; + + + // + // NLayouts Page + // + class TemplateDesignerNLayoutsPage : public QWizardPage, public Ui::TemplateDesignerNLayoutsPage + { + Q_OBJECT + public: + TemplateDesignerNLayoutsPage( QWidget* parent = nullptr ); + + void initializePage() override; + void cleanupPage() override; + }; + + + // + // OneLayout Page + // + class TemplateDesignerOneLayoutPage : public QWizardPage, public Ui::TemplateDesignerOneLayoutPage + { + Q_OBJECT + public: + TemplateDesignerOneLayoutPage( QWidget* parent = nullptr ); + + void initializePage() override; + void cleanupPage() override; + + private slots: + void onChanged(); + void onPrintButtonClicked(); + }; + + + // + // TwoLayout Page + // + class TemplateDesignerTwoLayoutPage : public QWizardPage, public Ui::TemplateDesignerTwoLayoutPage + { + Q_OBJECT + public: + TemplateDesignerTwoLayoutPage( QWidget* parent = nullptr ); + + void initializePage() override; + void cleanupPage() override; + + private slots: + void onChanged(); + void onPrintButtonClicked(); + }; + + + // + // Apply Page + // + class TemplateDesignerApplyPage : public QWizardPage, public Ui::TemplateDesignerApplyPage + { + Q_OBJECT + public: + TemplateDesignerApplyPage( QWidget* parent = nullptr ); + + bool validatePage(); + }; + + +} + + +#endif // TemplateDesigner_h diff --git a/glabels/images.qrc b/glabels/images.qrc index 315a144..9b6b53b 100644 --- a/glabels/images.qrc +++ b/glabels/images.qrc @@ -2,8 +2,19 @@ + images/glabels-label-designer.png images/glabels-logo.png + images/checkerboard.png + + images/TemplateDesigner/wizard-banner.png + images/TemplateDesigner/ex-1layout.png + images/TemplateDesigner/ex-2layouts.png + images/TemplateDesigner/ex-cd-size.png + images/TemplateDesigner/ex-ellipse-size.png + images/TemplateDesigner/ex-rect-size.png + images/TemplateDesigner/ex-round-size.png + diff --git a/glabels/images/TemplateDesigner/ex-1layout.png b/glabels/images/TemplateDesigner/ex-1layout.png new file mode 100644 index 0000000000000000000000000000000000000000..3045c5f231a11ae86e2d076d8e762a7ca2914618 GIT binary patch literal 1567 zcmV+)2H^RLP)1c~ z2F5lvRuiIX3W+oZ7rV_C9^+wjwn&tCvx+TQI{IUu9~cdHtnXZXKDk$au8xAuP=N2` zjZZIILj1=kegXJ7$d`zA$16oq0N@LNC4g@Lz9Z&j5Wj$*c)OKZQ~&&7 zU-S`pn{y+5lG0t#{sTZ2z;Adve_;13EQ7&-&d<+DRaG(!gPxwAXt7w3>$*fl6zU=Uj$IQ?21G>(oZrR%kG8MVo;FkD_<(&_0bJw85$+VAo4 zkxoxf>GJY2mVRvO*S?-(WfsSAP^nZZbA|(0}O{l zj7B3gn@tw|X0wUWXoTT#$fECuBvuBvy}iZV-JN%rJ9ZRB!QI^*Zf|c{^!<>;N*Tv- z@bK^u`syz%nx^65;UTfBL`kfa>2|xgxw%Os*3Hcgy4`Lfu_7myq9~C*N$X~fe!q`K zqmf9gMx%j#zn@5~NY4t1=_x*!ZWggD3kL@WiNrcMIDlnYiNunrFlDCGDGG%`BC!gE z0;bbxBC#TkSaD4`??)&u-7GSn&l8)v6-B{(K2Ic8#bOaelt_Px z2*qNNJq{pKVd|7hB`lZAL}D$MOO#5bL}E!|rHrO&n9XL1#G1`!?Dxw&B(YMaUazCq z>m?Ga*XyBPuO|{K2y35wN5xNrOV?{hhE_M&woR(4Mn2vksHz%z3C*^C$%vIQs;c7T zuVN$KP0g-K&@6owOYmf{XL8R z{rx?v)hcSW8jJq6tet$M|8=UA)k(hAZ@MnPWx3gy=(WX*ey;WR1^ziitk zUDwGljMw)E!{WLw8HPc+u188LBDpHu8B|rpcszc6g)8jUqGegHua1q!a=atMpAT>yRASuTk z8L2@ku&}E&NTnQi%6K(M4-XI7W96y_DG^2bB(0k@qz35+Prjq#r@^J`wIf5T8>9xQ zz=G5u71)p(qyh_4gVbmKjf$TJm#){244q@GA}dG*7CM~{E-o%$nr19|rfK5h;sTvc zClW2wl!t3jGa z@|aj@A~i^bOc7{x!@exKiwp59SYmww@CASh;4}PB-V{8a`xRu&Rsj40;8y^Jl{VnnG&fuy1Hq;1L3sZ0zajqQTIW|@ z3GG+V16JOB*LS~0qoEuhAHV+J*RNj*0D8S%q#uq!msYkMBUT{4aztpq{sp2{ZDY__ R>8Ahy002ovPDHLkV1ne**HHif literal 0 HcmV?d00001 diff --git a/glabels/images/TemplateDesigner/ex-2layouts.png b/glabels/images/TemplateDesigner/ex-2layouts.png new file mode 100644 index 0000000000000000000000000000000000000000..1bb5931ac2ec6d60075bb44d514d58fef7e60fcf GIT binary patch literal 1610 zcmV-Q2DSN#P)8#64SWS@1RuaR z5EVr)VxL>Q2wwKGh!Y&f+Jl;%&7VnESykQIzYmCEu&aK4^X=+XSM_%cd<^sOnN#Cp z|IQ%)`;lG%e)aMp#?D78!!Q8gGk^_%uK>P5vKdG(;1{)J1r`&)p8%o&44-Q`1-SJJ ztFdALeh2UgWGpXm>*eWE$jfXtL%ZEZx7&r|I9MzeSg+TJMx#h160j@_`FtKXH#aa% zQ$-0Mae>`Qb(W^uU%rHR=Q7T%m(&rf-|wSbE~8j1A{L9GUa!M(9IRF=FvhT2t>8Eg z>h(Heu^5WQBFg15`u)DlG6?Jp!u#@}#*cY?d}P2%7judmtT<0IE` zqG0!j=U)J_0RF&#Gajvass4_#juX}E=n-o+n<10QAeBmCJRZZcEUx1%%ffg(MkNzHaoT?;zW4Y;jZhlWHQM{qmj@V@{-YL#FEJ*b6r zraCYhjaWLJmfGfzs1)iWy>ua3!&}FR>Lq+BtW+v^cz8f6l@e{@O;V{89v&W0sZ^x4 zOXx+&Sp9wvqV7*!{C0&gxgr{b{n-?O==PEQLEL^Znw4cbxtsW zo1;wfO;T=Sb-P^@3I%Be{ER}OfNr;|r7uD*+-rr7;~*Z7tElA_@pv4L<7nyYoKUb< z$PKr#7K;TUk%*MeKOz!|V6j+e>FeAOF^J5+v$!vX>-AdMZ15$9VPL&pYw3%S3%9YN z(WthSaK;#-(WsWb2)S?@E0IWGv)QPq5IvwQmc`bbr`uX2#x9hshG)TIJmmH@@r2#aU?>E(A8=c_xJb8W`~S1+~41$TCFN+KMb7QS|I@B zayewPSu~qXsl^;hnSOC@vJ=Xa)w1bpSuTw-+ucIEOXti3ny}iYF zJU*tGXU5|(Zf|eVYPF=aM+BRnI@)zzmQJUcZQE?S-3px*+wGRww$0M%w9*GD7^4x3 z7g4>Ae*DWcO$>*_=SR4BXN!*GJU==%91dv~7$Q8oyVvWnQmMpD(`2@7v-y0^o}Qkb zN3!j9%buQ|*nB=`wrw-hG+C)sV!d8Z)d}|s(1^u_s9s*?nEUp<6XfiM{j~ZEfWHB_ z`}gk>yWrL<$cXBt#8^RwjKznjUSW+fA{0Z$B9uVJB9uVJB9x#c(eGG-JgX$U5vUQ1 z5&^@7mK$-p5&=OsNVyQz%l8qB5&^@Dva`XDL_pAp#f3_}lojpAelC?lsn*L6MD_CR zQb>t_=Z!DM3R@ze$o_K``_Ogbi?PC(2*?7y|6DfOjYWxo;Xu2wC=oCmXg3xm0)_+a z#-c>PaG>2-ln59Ov>S^O0mFfIV^JbtIMBWy>yQX|d3mY4uOKA?p7PC35wwq3VN3)R zxjB03H%YY{ixL5e15#JZ{Z0gg54#)oeG0w&MpQ5DBUV@w0a=JHgMd$q(3A*x{`g`n zN(3YT+Ch4>UZNVR)SjmX5xsnUn1T`k!;R82LU$q{XvE^KK}0X#AOE66!0@8&?9h=2 z2pX}tYY@>Zkilyzvm5*fUJJticq$4d`gw#B{rI3nKO#_&u?Qu2+K&~sy+p@CdU-R} z1%S^0OaL*wJu5Jmjqhh8r)W3~a{ z6M)|UM1J_UQ-)#p%l``b<|4h|{R@&bb@Bjb+07*qo IM6N<$f>vJvIRF3v literal 0 HcmV?d00001 diff --git a/glabels/images/TemplateDesigner/ex-cd-size.png b/glabels/images/TemplateDesigner/ex-cd-size.png new file mode 100644 index 0000000000000000000000000000000000000000..68261f0367506c6374d30fc53b9c3bd6ab50fc74 GIT binary patch literal 32300 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ⅈ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 literal 0 HcmV?d00001 diff --git a/glabels/images/TemplateDesigner/ex-ellipse-size.png b/glabels/images/TemplateDesigner/ex-ellipse-size.png new file mode 100644 index 0000000000000000000000000000000000000000..456ec2eb19e1a03dfcc2eec4fc2dc33202c6ffaa GIT binary patch literal 16779 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 oa4gh($ literal 0 HcmV?d00001 diff --git a/glabels/images/TemplateDesigner/ex-rect-size.png b/glabels/images/TemplateDesigner/ex-rect-size.png new file mode 100644 index 0000000000000000000000000000000000000000..2710472f1e1776090d6d03e7c62a7572ae3db054 GIT binary patch literal 4972 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 P=VAat3kk2eZ6Ez#4FiW5 literal 0 HcmV?d00001 diff --git a/glabels/images/TemplateDesigner/ex-round-size.png b/glabels/images/TemplateDesigner/ex-round-size.png new file mode 100644 index 0000000000000000000000000000000000000000..c45d6c3b509388b6225af33bb5b743f052ef24d6 GIT binary patch literal 16682 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 AWB>pF literal 0 HcmV?d00001 diff --git a/glabels/images/TemplateDesigner/wizard-banner.png b/glabels/images/TemplateDesigner/wizard-banner.png new file mode 100644 index 0000000000000000000000000000000000000000..b4fc60565bde0830b53044eb3ca2f8843f966cea GIT binary patch literal 45285 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 VxTGC&#_#|D002ovPDHLkV1hhzhp+$u literal 0 HcmV?d00001 diff --git a/glabels/ui/TemplateDesignerApplyPage.ui b/glabels/ui/TemplateDesignerApplyPage.ui new file mode 100644 index 0000000..d0ed63b --- /dev/null +++ b/glabels/ui/TemplateDesignerApplyPage.ui @@ -0,0 +1,69 @@ + + + TemplateDesignerApplyPage + + + + 0 + 0 + 640 + 400 + + + + + 0 + 0 + + + + + 640 + 400 + + + + Form + + + + 18 + + + + + You have completed the gLabels Product Template Designer. If you wish to accept and save your product template, click "Save." + + + true + + + + + + + Otherwise, you may click "Cancel" to abandon your design or "Back" to review or continue editing this product template. + + + true + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + diff --git a/glabels/ui/TemplateDesignerCdPage.ui b/glabels/ui/TemplateDesignerCdPage.ui new file mode 100644 index 0000000..f61fa31 --- /dev/null +++ b/glabels/ui/TemplateDesignerCdPage.ui @@ -0,0 +1,190 @@ + + + TemplateDesignerCdPage + + + + 0 + 0 + 640 + 400 + + + + + 0 + 0 + + + + + 640 + 400 + + + + Form + + + + + + + + + + true + + + in + + + + + + + 6. Margin: + + + + + + + 1. Outer radius: + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + 4. Clipping height: + + + + + + + 2. Inner radius: + + + + + + + 3. Clipping width: + + + + + + + true + + + in + + + + + + + true + + + in + + + + + + + true + + + in + + + + + + + true + + + in + + + + + + + true + + + in + + + + + + + 5. Waste: + + + + + + + + + + 0 + 0 + + + + + + + :/images/TemplateDesigner/ex-cd-size.png + + + Qt::AlignCenter + + + + + + + + + Qt::Vertical + + + + 20 + 65 + + + + + + + + + + + diff --git a/glabels/ui/TemplateDesignerEllipsePage.ui b/glabels/ui/TemplateDesignerEllipsePage.ui new file mode 100644 index 0000000..53dec92 --- /dev/null +++ b/glabels/ui/TemplateDesignerEllipsePage.ui @@ -0,0 +1,156 @@ + + + TemplateDesignerEllipsePage + + + + 0 + 0 + 640 + 400 + + + + + 0 + 0 + + + + + 640 + 400 + + + + Form + + + + + + + + + + true + + + in + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + 2. Height: + + + + + + + 1. Width: + + + + + + + 3. Waste: + + + + + + + true + + + in + + + + + + + 4. Margin: + + + + + + + true + + + in + + + + + + + true + + + in + + + + + + + + + + 0 + 0 + + + + + + + :/images/TemplateDesigner/ex-ellipse-size.png + + + Qt::AlignCenter + + + + + + + + + Qt::Vertical + + + + 20 + 65 + + + + + + + + + + + diff --git a/glabels/ui/TemplateDesignerIntroPage.ui b/glabels/ui/TemplateDesignerIntroPage.ui new file mode 100644 index 0000000..4f9a594 --- /dev/null +++ b/glabels/ui/TemplateDesignerIntroPage.ui @@ -0,0 +1,76 @@ + + + TemplateDesignerIntroPage + + + + 0 + 0 + 640 + 400 + + + + + 0 + 0 + + + + + 640 + 400 + + + + Form + + + + 12 + + + + + <html><head/><body><p>This dialog will help you create a custom product template. Let's get started:</p></body></html> + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + Copy/Edit Product + + + Copy and edit an existing product template + + + + + + + New Product + + + Create a a new product template from scratch + + + + + + + + diff --git a/glabels/ui/TemplateDesignerNLayoutsPage.ui b/glabels/ui/TemplateDesignerNLayoutsPage.ui new file mode 100644 index 0000000..df42ffd --- /dev/null +++ b/glabels/ui/TemplateDesignerNLayoutsPage.ui @@ -0,0 +1,250 @@ + + + TemplateDesignerNLayoutsPage + + + + 0 + 0 + 640 + 400 + + + + + 0 + 0 + + + + + 640 + 400 + + + + Form + + + + QLayout::SetDefaultConstraint + + + + + 18 + + + + + A layout is a set of labels or cards that can be arranged in a simple grid. Most products only need one layout, as in the first example below. The second example illustrates when two layouts are needed. + + + true + + + + + + + QLayout::SetDefaultConstraint + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + QLayout::SetDefaultConstraint + + + + + + 0 + 0 + + + + + 0 + 75 + + + + + + + :/images/TemplateDesigner/ex-1layout.png + + + Qt::AlignCenter + + + + + + + + 0 + 0 + + + + Products needing only one layout. + + + Qt::AlignCenter + + + true + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + QLayout::SetDefaultConstraint + + + + + + 0 + 0 + + + + + 0 + 75 + + + + + + + :/images/TemplateDesigner/ex-2layouts.png + + + Qt::AlignCenter + + + + + + + + 0 + 0 + + + + Products needing two layouts. + + + Qt::AlignCenter + + + true + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + Note: if more than two layouts are required, the product template must be edited manually. + + + true + + + + + + + 3 + + + + + One layout + + + true + + + + + + + Two layouts + + + + + + + + + + + Qt::Vertical + + + + 20 + 58 + + + + + + + + + + + diff --git a/glabels/ui/TemplateDesignerNamePage.ui b/glabels/ui/TemplateDesignerNamePage.ui new file mode 100644 index 0000000..9bf0d13 --- /dev/null +++ b/glabels/ui/TemplateDesignerNamePage.ui @@ -0,0 +1,134 @@ + + + TemplateDesignerNamePage + + + + 0 + 0 + 640 + 400 + + + + + 0 + 0 + + + + + 640 + 400 + + + + Form + + + + 6 + + + + + Qt::Vertical + + + + 20 + 123 + + + + + + + + 12 + + + + + + + + + + + + + + + (e.g. "Mailing Labels," "Business Cards," ...) + + + + + + + Brand: + + + + + + + Part #: + + + + + + + <b>Warning Text</b> + + + Qt::RichText + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + + + + + Description: + + + + + + + + + + (e.g. 8163A) + + + + + + + + + + (e.g. Avery, Acme, ...) + + + + + + + + + + + + + + + + + diff --git a/glabels/ui/TemplateDesignerOneLayoutPage.ui b/glabels/ui/TemplateDesignerOneLayoutPage.ui new file mode 100644 index 0000000..47ec90e --- /dev/null +++ b/glabels/ui/TemplateDesignerOneLayoutPage.ui @@ -0,0 +1,218 @@ + + + TemplateDesignerOneLayoutPage + + + + 0 + 0 + 640 + 400 + + + + + 0 + 0 + + + + + 640 + 400 + + + + Form + + + + + + 12 + + + + + Number across (nx): + + + + + + + 1 + + + + + + + Number down (ny): + + + + + + + 1 + + + + + + + Distance from left edge (x0): + + + + + + + true + + + in + + + + + + + Distance from top edge (y0); + + + + + + + true + + + in + + + + + + + Horizontal pitch (dx): + + + + + + + true + + + in + + + + + + + Vertical pitch (dy): + + + + + + + true + + + in + + + + + + + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 0 + 0 + + + + Print test sheet + + + + :/icons/32x32/actions/print.svg:/icons/32x32/actions/print.svg + + + + 32 + 32 + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + Qt::Vertical + + + + 20 + 133 + + + + + + + + + glabels::SimplePreview + QGraphicsView +
SimplePreview.h
+
+
+ + + + +
diff --git a/glabels/ui/TemplateDesignerPageSizePage.ui b/glabels/ui/TemplateDesignerPageSizePage.ui new file mode 100644 index 0000000..c65edaa --- /dev/null +++ b/glabels/ui/TemplateDesignerPageSizePage.ui @@ -0,0 +1,107 @@ + + + TemplateDesignerPageSizePage + + + + 0 + 0 + 640 + 400 + + + + + 0 + 0 + + + + + 640 + 400 + + + + Form + + + + + + + + Page size: + + + + + + + Width: + + + + + + + true + + + in + + + + + + + Height: + + + + + + + true + + + in + + + + + + + + + + + + Qt::Horizontal + + + + 182 + 20 + + + + + + + + Qt::Vertical + + + + 20 + 173 + + + + + + + + + diff --git a/glabels/ui/TemplateDesignerRectPage.ui b/glabels/ui/TemplateDesignerRectPage.ui new file mode 100644 index 0000000..d8b2132 --- /dev/null +++ b/glabels/ui/TemplateDesignerRectPage.ui @@ -0,0 +1,177 @@ + + + TemplateDesignerRectPage + + + + 0 + 0 + 640 + 400 + + + + + 0 + 0 + + + + + 640 + 400 + + + + Form + + + + + + + + + + 2. Height: + + + + + + + true + + + in + + + + + + + true + + + in + + + + + + + true + + + in + + + + + + + true + + + in + + + + + + + 1. Width: + + + + + + + true + + + in + + + + + + + 4. Horizontal waste: + + + + + + + 3. Corner radius + + + + + + + 6. Margin: + + + + + + + true + + + in + + + + + + + 5. Vertical waste: + + + + + + + + + + 0 + 0 + + + + + + + :/images/TemplateDesigner/ex-rect-size.png + + + Qt::AlignCenter + + + + + + + + + Qt::Vertical + + + + 20 + 65 + + + + + + + + + + + diff --git a/glabels/ui/TemplateDesignerRoundPage.ui b/glabels/ui/TemplateDesignerRoundPage.ui new file mode 100644 index 0000000..c51aa03 --- /dev/null +++ b/glabels/ui/TemplateDesignerRoundPage.ui @@ -0,0 +1,139 @@ + + + TemplateDesignerRoundPage + + + + 0 + 0 + 640 + 400 + + + + + 0 + 0 + + + + + 640 + 400 + + + + Form + + + + + + + + + + true + + + in + + + + + + + true + + + in + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + true + + + in + + + + + + + 3. Margin + + + + + + + 1. Radius: + + + + + + + 2. Waste: + + + + + + + + + + 0 + 0 + + + + + + + :/images/TemplateDesigner/ex-round-size.png + + + Qt::AlignCenter + + + + + + + + + Qt::Vertical + + + + 20 + 65 + + + + + + + + + + + diff --git a/glabels/ui/TemplateDesignerShapePage.ui b/glabels/ui/TemplateDesignerShapePage.ui new file mode 100644 index 0000000..0466fbb --- /dev/null +++ b/glabels/ui/TemplateDesignerShapePage.ui @@ -0,0 +1,81 @@ + + + TemplateDesignerShapePage + + + + 0 + 0 + 640 + 400 + + + + + 0 + 0 + + + + + 640 + 400 + + + + Form + + + + + + + + Rectangular or square (can have rounded corners) + + + true + + + + + + + Round + + + + + + + Elliptical + + + + + + + CD/DVD (including credit card CDs) + + + + + + + + + Qt::Vertical + + + + 20 + 149 + + + + + + + + + diff --git a/glabels/ui/TemplateDesignerTwoLayoutPage.ui b/glabels/ui/TemplateDesignerTwoLayoutPage.ui new file mode 100644 index 0000000..11cb70e --- /dev/null +++ b/glabels/ui/TemplateDesignerTwoLayoutPage.ui @@ -0,0 +1,256 @@ + + + TemplateDesignerTwoLayoutPage + + + + 0 + 0 + 640 + 400 + + + + + 0 + 0 + + + + + 640 + 400 + + + + Form + + + + + + 12 + + + + + Distance from left edge (x0): + + + + + + + + + + true + + + in + + + + + + + Number down (ny): + + + + + + + true + + + in + + + + + + + Distance from top edge (y0); + + + + + + + true + + + in + + + + + + + + + + Number across (nx): + + + + + + + Horizontal pitch (dx): + + + + + + + true + + + in + + + + + + + Vertical pitch (dy): + + + + + + + + + + + + + true + + + in + + + + + + + true + + + in + + + + + + + true + + + in + + + + + + + true + + + in + + + + + + + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 0 + 0 + + + + Print test sheet + + + + :/icons/32x32/actions/print.svg:/icons/32x32/actions/print.svg + + + + 32 + 32 + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + Qt::Vertical + + + + 20 + 133 + + + + + + + + + glabels::SimplePreview + QGraphicsView +
SimplePreview.h
+
+
+ + + + +
diff --git a/model/Db.cpp b/model/Db.cpp index 5321c2a..6592193 100644 --- a/model/Db.cpp +++ b/model/Db.cpp @@ -23,9 +23,11 @@ #include "Config.h" #include "StrUtil.h" #include "FileUtil.h" +#include "Settings.h" #include "XmlCategoryParser.h" #include "XmlPaperParser.h" #include "XmlTemplateParser.h" +#include "XmlTemplateCreator.h" #include "XmlVendorParser.h" #include @@ -497,6 +499,22 @@ namespace glabels } + bool Db::isSystemTemplateKnown( const QString& brand, const QString& part ) + { + foreach ( Template *tmplate, mTemplates ) + { + if ( (tmplate->brand() == brand) && + (tmplate->part() == part) && + !tmplate->isUserDefined() ) + { + return true; + } + } + + return false; + } + + QStringList Db::getNameListOfSimilarTemplates( const QString& name ) { QStringList list; @@ -523,21 +541,52 @@ namespace glabels } - void Db::registerUserTemplate( Template *templat ) + QString Db::userTemplateFilename( const QString& brand, const QString& part ) { - // TODO + QString filename = brand + "_" + part + ".template"; + return FileUtil::userTemplatesDir().filePath( filename ); } - void Db::deleteUserTemplateByName( const QString& name ) + void Db::registerUserTemplate( Template *tmplate ) { - // TODO + QString filename = userTemplateFilename( tmplate->brand(), tmplate->part() ); + + // Write file + if ( XmlTemplateCreator().writeTemplate( tmplate, filename ) ) + { + // Add template to list of registered templates + registerTemplate( tmplate ); + Settings::addToRecentTemplateList( tmplate->name() ); + } + else + { + qWarning() << "Problem writing user template" << filename; + } } void Db::deleteUserTemplateByBrandPart( const QString& brand, const QString& part ) { - // TODO + Template* tmplate; + foreach ( Template *candidate, mTemplates ) + { + if ( candidate->isUserDefined() && + (candidate->brand() == brand) && (candidate->part() == part) ) + { + tmplate = candidate; + break; + } + } + + if ( tmplate ) + { + mTemplates.removeOne( tmplate ); + delete tmplate; + + QString filename = userTemplateFilename( brand, part ); + QFile( filename ).remove(); + } } @@ -667,15 +716,15 @@ namespace glabels void Db::readTemplates() { - readTemplatesFromDir( FileUtil::systemTemplatesDir() ); - - // TODO: Read user directories + readTemplatesFromDir( FileUtil::systemTemplatesDir(), false ); + readTemplatesFromDir( FileUtil::manualUserTemplatesDir(), false ); + readTemplatesFromDir( FileUtil::userTemplatesDir(), true ); std::stable_sort( mTemplates.begin(), mTemplates.end(), partNameLessThan ); } - void Db::readTemplatesFromDir( const QDir& dir ) + void Db::readTemplatesFromDir( const QDir& dir, bool isUserDefined ) { QStringList filters; filters << "*-templates.xml" << "*.template"; @@ -684,7 +733,7 @@ namespace glabels foreach ( QString fileName, dir.entryList( filters, QDir::Files ) ) { - parser.readFile( dir.absoluteFilePath( fileName ) ); + parser.readFile( dir.absoluteFilePath( fileName ), isUserDefined ); } } diff --git a/model/Db.h b/model/Db.h index a7be79e..6964a81 100644 --- a/model/Db.h +++ b/model/Db.h @@ -90,10 +90,11 @@ namespace glabels static const Template *lookupTemplateFromBrandPart( const QString& brand, const QString& part ); static bool isTemplateKnown( const QString& brand, const QString& part ); + static bool isSystemTemplateKnown( const QString& brand, const QString& part ); static QStringList getNameListOfSimilarTemplates( const QString& name ); + static QString userTemplateFilename( const QString& brand, const QString& part ); static void registerUserTemplate( Template *tmplate ); - static void deleteUserTemplateByName( const QString& name ); static void deleteUserTemplateByBrandPart( const QString& brand, const QString& part ); @@ -116,7 +117,7 @@ namespace glabels static void readVendorsFromDir( const QDir& dir ); static void readTemplates(); - static void readTemplatesFromDir( const QDir& dir ); + static void readTemplatesFromDir( const QDir& dir, bool isUserDefined ); private: diff --git a/model/FileUtil.cpp b/model/FileUtil.cpp index c31b790..09e61d2 100644 --- a/model/FileUtil.cpp +++ b/model/FileUtil.cpp @@ -23,6 +23,7 @@ #include "Config.h" #include +#include namespace glabels @@ -64,6 +65,27 @@ namespace glabels } + QDir FileUtil::manualUserTemplatesDir() + { + // Location for manually created user-defined templates + QDir dir( QStandardPaths::writableLocation(QStandardPaths::HomeLocation) ); + dir.mkpath( ".glabels" ); + dir.cd( ".glabels" ); + + return dir; + } + + + QDir FileUtil::userTemplatesDir() + { + // Location for user-defined templates created using TemplateDesigner + QDir dir( QStandardPaths::writableLocation(QStandardPaths::AppConfigLocation) ); + dir.mkpath( "." ); + + return dir; + } + + QDir FileUtil::translationsDir() { QDir dir; diff --git a/model/FileUtil.h b/model/FileUtil.h index 00d9c5b..ed76de0 100644 --- a/model/FileUtil.h +++ b/model/FileUtil.h @@ -37,6 +37,7 @@ namespace glabels QString addExtension( const QString& rawFilename, const QString& extension ); QDir systemTemplatesDir(); + QDir manualUserTemplatesDir(); QDir userTemplatesDir(); QDir translationsDir(); diff --git a/model/Settings.cpp b/model/Settings.cpp index b8096b8..b0ac10e 100644 --- a/model/Settings.cpp +++ b/model/Settings.cpp @@ -92,6 +92,40 @@ namespace glabels } + Settings::PageSizeFamily Settings::preferedPageSizeFamily() + { + // Guess at a suitable default + QString defaultFamily; + switch (QLocale::system().country()) + { + case QLocale::UnitedStates: + case QLocale::Canada: + defaultFamily = "us"; + break; + + default: + defaultFamily = "iso"; + break; + } + + mInstance->beginGroup( "Locale" ); + QString value = mInstance->value( "preferedPageSizeFamily", defaultFamily ).toString(); + mInstance->endGroup(); + + return (value == "iso") ? ISO : US; + } + + + void Settings::setPreferedPageSizeFamily( PageSizeFamily preferedPageSizeFamily ) + { + mInstance->beginGroup( "Locale" ); + mInstance->setValue( "preferedPageSizeFamily", preferedPageSizeFamily == ISO ? "iso" : "us" ); + mInstance->endGroup(); + + emit mInstance->changed(); + } + + bool Settings::searchIsoPaperSizes() { // Guess at a suitable default diff --git a/model/Settings.h b/model/Settings.h index bd950d4..f16c4f0 100644 --- a/model/Settings.h +++ b/model/Settings.h @@ -41,7 +41,7 @@ namespace glabels Q_OBJECT public: - enum class PageSizeFamilty { ISO, US, }; + enum PageSizeFamily { ISO, US, }; ///////////////////////////////// @@ -69,6 +69,9 @@ namespace glabels static Units units(); static void setUnits( const Units& units ); + static PageSizeFamily preferedPageSizeFamily(); + static void setPreferedPageSizeFamily( PageSizeFamily preferedPageSizeFamily ); + static bool searchIsoPaperSizes(); static void setSearchIsoPaperSizes( bool searchIsoPaperSizes ); diff --git a/model/Template.cpp b/model/Template.cpp index eaffb1e..6acc685 100644 --- a/model/Template.cpp +++ b/model/Template.cpp @@ -35,13 +35,15 @@ namespace glabels const QString& description, const QString& paperId, const Distance& pageWidth, - const Distance& pageHeight ) + const Distance& pageHeight, + bool isUserDefined ) : mBrand(brand), mPart(part), mDescription(description), mPaperId(paperId), mPageWidth(pageWidth), mPageHeight(pageHeight), + mIsUserDefined(isUserDefined), mIsSizeIso(false), mIsSizeUs(false), mName("") @@ -179,6 +181,12 @@ namespace glabels } + bool Template::isUserDefined() const + { + return mIsUserDefined; + } + + QString Template::equivPart() const { return mEquivPart; diff --git a/model/Template.h b/model/Template.h index b05d087..144d8a6 100644 --- a/model/Template.h +++ b/model/Template.h @@ -48,7 +48,8 @@ namespace glabels const QString& description, const QString& paperId, const Distance& pageWidth, - const Distance& pageHeight ); + const Distance& pageHeight, + bool isUserDefined = false ); Template( const Template& other ); @@ -74,6 +75,8 @@ namespace glabels bool isSizeUs() const; bool isSizeOther() const; + bool isUserDefined() const; + QString equivPart() const; void setEquivPart( const QString& value ); @@ -104,6 +107,8 @@ namespace glabels bool mIsSizeIso; bool mIsSizeUs; + bool mIsUserDefined; + QString mEquivPart; QString mName; diff --git a/model/XmlTemplateParser.cpp b/model/XmlTemplateParser.cpp index 2c063a1..3bf7452 100644 --- a/model/XmlTemplateParser.cpp +++ b/model/XmlTemplateParser.cpp @@ -41,7 +41,7 @@ namespace glabels namespace model { - bool XmlTemplateParser::readFile( const QString &fileName ) + bool XmlTemplateParser::readFile( const QString &fileName, bool isUserDefined ) { QFile file( fileName ); @@ -73,18 +73,18 @@ namespace glabels return false; } - parseRootNode( root ); + parseRootNode( root, isUserDefined ); return true; } - void XmlTemplateParser::parseRootNode( const QDomElement &node ) + void XmlTemplateParser::parseRootNode( const QDomElement &node, bool isUserDefined ) { for ( QDomNode child = node.firstChild(); !child.isNull(); child = child.nextSibling() ) { if ( child.toElement().tagName() == "Template" ) { - Template *tmplate = parseTemplateNode( child.toElement() ); + Template *tmplate = parseTemplateNode( child.toElement(), isUserDefined ); if ( tmplate != nullptr ) { Db::registerTemplate( tmplate ); @@ -104,7 +104,7 @@ namespace glabels } - Template *XmlTemplateParser::parseTemplateNode( const QDomElement &node ) + Template *XmlTemplateParser::parseTemplateNode( const QDomElement &node, bool isUserDefined ) { QString brand = XmlUtil::getStringAttr( node, "brand", "" ); QString part = XmlUtil::getStringAttr( node, "part", "" ); @@ -163,14 +163,14 @@ namespace glabels } tmplate = new Template( brand, part, description, - paper->id(), paper->width(), paper->height() ); + paper->id(), paper->width(), paper->height(), isUserDefined ); } else { Distance width = XmlUtil::getLengthAttr( node, "width", Distance(0) ); Distance height = XmlUtil::getLengthAttr( node, "height", Distance(0) ); - tmplate = new Template( brand, part, description, paperId, width, height ); + tmplate = new Template( brand, part, description, paperId, width, height, isUserDefined ); } for ( QDomNode child = node.firstChild(); !child.isNull(); child = child.nextSibling() ) diff --git a/model/XmlTemplateParser.h b/model/XmlTemplateParser.h index a64413d..e48434f 100644 --- a/model/XmlTemplateParser.h +++ b/model/XmlTemplateParser.h @@ -38,11 +38,11 @@ namespace glabels public: XmlTemplateParser() = default; - bool readFile( const QString &fileName ); - Template *parseTemplateNode( const QDomElement &node ); + bool readFile( const QString &fileName, bool isUserDefined = false ); + Template *parseTemplateNode( const QDomElement &node, bool isUserDefined = false ); private: - void parseRootNode( const QDomElement &node ); + void parseRootNode( const QDomElement &node, bool isUserDefined ); void parseMetaNode( const QDomElement &node, Template *tmplate ); void parseLabelRectangleNode( const QDomElement &node, Template *tmplate ); void parseLabelEllipseNode( const QDomElement &node, Template *tmplate ); diff --git a/translations/glabels_C.ts b/translations/glabels_C.ts index e4e4d65..665f97a 100644 --- a/translations/glabels_C.ts +++ b/translations/glabels_C.ts @@ -785,6 +785,397 @@ + + TemplateDesignerApplyPage + + + Form + + + + + You have completed the gLabels Product Template Designer. If you wish to accept and save your product template, click "Save." + + + + + Otherwise, you may click "Cancel" to abandon your design or "Back" to review or continue editing this product template. + + + + + TemplateDesignerCdPage + + + Form + + + + + 4. Clipping height: + + + + + 2. Inner radius: + + + + + 1. Outer radius: + + + + + 5. Waste: + + + + + 3. Clipping width: + + + + + 6. Margin: + + + + + TemplateDesignerEllipsePage + + + Form + + + + + 3. Waste: + + + + + 2. Height: + + + + + 1. Width: + + + + + 4. Margin: + + + + + TemplateDesignerIntroPage + + + Form + + + + + <html><head/><body><p>This dialog will help you create a custom product template. Let's get started:</p></body></html> + + + + + Copy/Edit Product + + + + + Copy and edit an existing product template + + + + + New Product + + + + + Create a a new product template from scratch + + + + + TemplateDesignerNLayoutsPage + + + Form + + + + + A layout is a set of labels or cards that can be arranged in a simple grid. Most products only need one layout, as in the first example below. The second example illustrates when two layouts are needed. + + + + + Products needing only one layout. + + + + + Products needing two layouts. + + + + + Note: if more than two layouts are required, the product template must be edited manually. + + + + + One layout + + + + + Two layouts + + + + + TemplateDesignerNamePage + + + Form + + + + + Brand: + + + + + (e.g. Avery, Acme, ...) + + + + + Part #: + + + + + (e.g. 8163A) + + + + + Description: + + + + + (e.g. "Mailing Labels," "Business Cards," ...) + + + + + TemplateDesignerOneLayoutPage + + + Form + + + + + Number across (nx): + + + + + Number down (ny): + + + + + Distance from left edge (x0): + + + + + Distance from top edge (y0); + + + + + Horizontal pitch (dx): + + + + + Vertical pitch (dy): + + + + + Print test sheet + + + + + TemplateDesignerPageSizePage + + + Form + + + + + Page size: + + + + + Width: + + + + + Height: + + + + + TemplateDesignerRectPage + + + Form + + + + + 1. Width: + + + + + 2. Height: + + + + + 3. Corner radius + + + + + 4. Horizontal waste: + + + + + 5. Vertical waste: + + + + + 6. Margin: + + + + + TemplateDesignerRoundPage + + + Form + + + + + 2. Waste: + + + + + 1. Radius: + + + + + 3. Margin + + + + + TemplateDesignerShapePage + + + Form + + + + + Rectangular or square (can have rounded corners) + + + + + Round + + + + + Elliptical + + + + + CD/DVD (including credit card CDs) + + + + + TemplateDesignerTwoLayoutPage + + + Form + + + + + Distance from left edge (x0): + + + + + Number down (ny): + + + + + Distance from top edge (y0); + + + + + Number across (nx): + + + + + Horizontal pitch (dx): + + + + + Vertical pitch (dy): + + + + + Print test sheet + + + glabels::AboutDialog @@ -834,43 +1225,43 @@ glabels::File - + gLabels - Open Project - - + + glabels files (*.glabels);;All files (*) - + Unable to open " - + ". - + gLabels - Save Project As - + Save Label As - + %1 already exists. - + Do you want to replace it? @@ -961,7 +1352,7 @@ - Template &Designer... + Product Template &Designer... @@ -1004,7 +1395,7 @@ - + Cut @@ -1232,7 +1623,7 @@ - + Bring To Front @@ -1243,7 +1634,7 @@ - + Send To Back @@ -1254,7 +1645,7 @@ - + Rotate Left @@ -1265,7 +1656,7 @@ - + Rotate Right @@ -1276,7 +1667,7 @@ - + Flip Horizontally @@ -1287,7 +1678,7 @@ - + Flip Vertically @@ -1298,7 +1689,7 @@ - + Align Left @@ -1309,7 +1700,7 @@ - + Align Center @@ -1320,7 +1711,7 @@ - + Align Right @@ -1331,7 +1722,7 @@ - + Align Top @@ -1342,7 +1733,7 @@ - + Align Middle @@ -1353,7 +1744,7 @@ - + Align Bottom @@ -1364,7 +1755,7 @@ - + Center Horizontally @@ -1375,7 +1766,7 @@ - + Center Vertically @@ -1470,62 +1861,62 @@ - + (modified) - + Save changes to project "%1" before closing? - + Your changes will be lost if you don't save them. - + Save project? - + Paste - + Delete - + Create Text - + Create Box - + Create Line - + Create Ellipse - + Create Image - + Create Barcode @@ -1727,6 +2118,202 @@ + + glabels::TemplateDesigner + + + Product Template Designer + + + + + Copy + + + + + glabels::TemplateDesignerApplyPage + + + + Save Product Template + + + + + Click "Save" to save your custom product template! + + + + + User product template (%1 %2) already exists. + + + + + Do you want to replace it? + + + + + glabels::TemplateDesignerCdPage + + + Product Size + + + + + Please adjust the size parameters of a single product item. + + + + + glabels::TemplateDesignerEllipsePage + + + Product Size + + + + + Please adjust the size parameters of a single product item. + + + + + glabels::TemplateDesignerIntroPage + + + Welcome + + + + + Welcome to the gLabels Product Template Designer. + + + + + glabels::TemplateDesignerNLayoutsPage + + + Number of Layouts + + + + + Please select the number of layouts required. + + + + + glabels::TemplateDesignerNamePage + + + Name and Description + + + + + Please enter the following identifying information about the product. + + + + + Brand and part number match an existing built-in product template! + + + + + glabels::TemplateDesignerOneLayoutPage + + + Layout + + + + + Please enter parameters for your single layout. + + + + + glabels::TemplateDesignerPageSizePage + + + Page Size + + + + + Please select the product page size. + + + + + + + + + + + Other + + + + + glabels::TemplateDesignerRectPage + + + Product Size + + + + + Please adjust the size parameters of a single product item. + + + + + glabels::TemplateDesignerRoundPage + + + Product Size + + + + + Please adjust the size parameters of a single product item. + + + + + glabels::TemplateDesignerShapePage + + + Product Shape + + + + + Please select the basic product shape. + + + + + glabels::TemplateDesignerTwoLayoutPage + + + Layouts + + + + + Please enter parameters for your two layouts. + + + main