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 0000000..3045c5f
Binary files /dev/null and b/glabels/images/TemplateDesigner/ex-1layout.png differ
diff --git a/glabels/images/TemplateDesigner/ex-2layouts.png b/glabels/images/TemplateDesigner/ex-2layouts.png
new file mode 100644
index 0000000..1bb5931
Binary files /dev/null and b/glabels/images/TemplateDesigner/ex-2layouts.png differ
diff --git a/glabels/images/TemplateDesigner/ex-cd-size.png b/glabels/images/TemplateDesigner/ex-cd-size.png
new file mode 100644
index 0000000..68261f0
Binary files /dev/null and b/glabels/images/TemplateDesigner/ex-cd-size.png differ
diff --git a/glabels/images/TemplateDesigner/ex-ellipse-size.png b/glabels/images/TemplateDesigner/ex-ellipse-size.png
new file mode 100644
index 0000000..456ec2e
Binary files /dev/null and b/glabels/images/TemplateDesigner/ex-ellipse-size.png differ
diff --git a/glabels/images/TemplateDesigner/ex-rect-size.png b/glabels/images/TemplateDesigner/ex-rect-size.png
new file mode 100644
index 0000000..2710472
Binary files /dev/null and b/glabels/images/TemplateDesigner/ex-rect-size.png differ
diff --git a/glabels/images/TemplateDesigner/ex-round-size.png b/glabels/images/TemplateDesigner/ex-round-size.png
new file mode 100644
index 0000000..c45d6c3
Binary files /dev/null and b/glabels/images/TemplateDesigner/ex-round-size.png differ
diff --git a/glabels/images/TemplateDesigner/wizard-banner.png b/glabels/images/TemplateDesigner/wizard-banner.png
new file mode 100644
index 0000000..b4fc605
Binary files /dev/null and b/glabels/images/TemplateDesigner/wizard-banner.png differ
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
+
+
+
+
+
+
+
+
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
+
+
+
+
+
+
+
+
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