diff --git a/.appveyor.yml b/.appveyor.yml
index 66a4c85..40d0245 100644
--- a/.appveyor.yml
+++ b/.appveyor.yml
@@ -27,6 +27,7 @@ install:
- set PATH=%PATH%;%QTDIR%/bin
build_script:
+ - git checkout master # re-attach to master to satisfy auto version tooling
- mkdir build
- cd build
- cmake -G "Visual Studio 15 2017 Win64" -DCMAKE_PREFIX_PATH=%QTDIR% ..
diff --git a/.gitignore b/.gitignore
index f512be1..168c78a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -34,3 +34,6 @@ core
*.sav*
.directory
TEST-DATA
+SAV*
+OLD*
+
diff --git a/.travis.yml b/.travis.yml
index 45fec74..a6fd501 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -10,9 +10,12 @@ before_install:
install:
- sudo apt-get -y install qt59base qt59svg qt59tools qt59translations zlib1g-dev xvfb
- sudo apt-get -y install barcode libqrencode-dev
+ - wget https://downloads.sourceforge.net/project/zint/zint/2.6.3/zint-2.6.3_final.tar.gz && tar xzf zint-2.6.3_final.tar.gz && cd zint-2.6.3.src && mkdir build && cd build && cmake .. && make && sudo make install && cd ../..
- source /opt/qt5*/bin/qt5*-env.sh
script:
+ - git fetch --unshallow # restore repository depth to properly count commits in auto versioning
+ - git checkout master # re-attach to master to satisfy auto versioning
- mkdir build
- cd build
- cmake .. -DCMAKE_INSTALL_PREFIX=/usr
@@ -24,7 +27,7 @@ after_success:
- wget -c "https://github.com/jimevins/linuxdeployqt/releases/download/continuous/linuxdeployqt-continuous-x86_64.AppImage"
- chmod a+x linuxdeployqt*.AppImage
- unset QTDIR; unset QT_PLUGIN_PATH ; unset LD_LIBRARY_PATH
- - export LD_LIBRARY_PATH=/opt/qt*/lib/:$LD_LIBRARY_PATH
+ - export LD_LIBRARY_PATH=/opt/qt*/lib/:/usr/local/lib:$LD_LIBRARY_PATH
- ./linuxdeployqt*.AppImage ./appdir/usr/share/applications/*.desktop -bundle-non-qt-libs
- ./linuxdeployqt*.AppImage ./appdir/usr/share/applications/*.desktop -appimage
- find ./appdir -executable -type f -exec ldd {} \; | grep " => /usr" | cut -d " " -f 2-3 | sort | uniq
diff --git a/.version.in b/.version.in
new file mode 100644
index 0000000..f3e763d
--- /dev/null
+++ b/.version.in
@@ -0,0 +1 @@
+@VERSION_STRING@
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 885788f..e03fcb2 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -17,6 +17,26 @@ set (CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/Modules/"
set (WEBSITE "glabels.org")
set (BUG_WEBSITE "https://github.com/jimevins/glabels-qt/issues")
+execute_process(
+ COMMAND git symbolic-ref --short HEAD
+ RESULT_VARIABLE BRANCH_VALID
+ OUTPUT_VARIABLE BRANCH
+ OUTPUT_STRIP_TRAILING_WHITESPACE
+)
+if (NOT ${BRANCH_VALID} STREQUAL "0")
+ set (BRANCH "Unkonwn")
+endif ()
+
+execute_process(
+ COMMAND git rev-list --count ${BRANCH}
+ RESULT_VARIABLE COMMIT_COUNT_VALID
+ OUTPUT_VARIABLE COMMIT_COUNT
+ OUTPUT_STRIP_TRAILING_WHITESPACE
+)
+if (NOT ${COMMIT_COUNT_VALID} STREQUAL "0")
+ set (COMMIT_COUNT "?")
+endif ()
+
execute_process(
COMMAND git log -1 --format=%h
RESULT_VARIABLE COMMIT_HASH_VALID
@@ -38,11 +58,16 @@ if (NOT ${COMMIT_DATE_VALID} STREQUAL "0")
endif ()
# Uncomment for snapshots, comment for releases
-set(VERSION_STRING "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}-snapshot (${COMMIT_HASH} ${COMMIT_DATE})")
+set(VERSION_STRING "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}-${BRANCH}${COMMIT_COUNT}")
# Uncomment for releases, comment for snapshots
#set(VERSION_STRING "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}")
+set(LONG_VERSION_STRING "${VERSION_STRING} (${COMMIT_HASH} ${COMMIT_DATE})")
+
+# Auto-generate version file
+configure_file (.version.in VERSION @ONLY)
+
#=======================================
# Packaging Information
@@ -147,7 +172,7 @@ add_subdirectory (data)
#=======================================
message (STATUS "")
message (STATUS "Project name ............ " ${CMAKE_PROJECT_NAME})
-message (STATUS "Project version ......... " ${VERSION_STRING})
+message (STATUS "Project version ......... " ${LONG_VERSION_STRING})
message (STATUS "Installation prefix ..... " ${CMAKE_INSTALL_PREFIX})
message (STATUS "Source code location .... " ${glabels_SOURCE_DIR})
message (STATUS "CMake version ........... " ${CMAKE_VERSION})
diff --git a/backends/barcode/Backends.cpp b/backends/barcode/Backends.cpp
index 040e81e..96fc83b 100644
--- a/backends/barcode/Backends.cpp
+++ b/backends/barcode/Backends.cpp
@@ -205,7 +205,7 @@ namespace glabels
glbarcode::Factory::registerType( "zint::kix", Zint::Kix::create );
glbarcode::Factory::registerType( "zint::ean", Zint::Ean::create );
glbarcode::Factory::registerType( "zint::gmtx", Zint::Gmtx::create );
- glbarcode::Factory::registerType( "zint::gs1128", Zint::Gs1128::create );
+ glbarcode::Factory::registerType( "zint::gs1-128", Zint::Gs1128::create );
glbarcode::Factory::registerType( "zint::rss14", Zint::Rss14::create );
glbarcode::Factory::registerType( "zint::rssltd", Zint::Rssltd::create );
glbarcode::Factory::registerType( "zint::rssexp", Zint::Rssexp::create );
diff --git a/backends/barcode/QrEncode.cpp b/backends/barcode/QrEncode.cpp
index 2772660..2fd8bcf 100644
--- a/backends/barcode/QrEncode.cpp
+++ b/backends/barcode/QrEncode.cpp
@@ -80,7 +80,6 @@ namespace glabels
QRcode_free( qrcode );
- QRcode_clearCache();
return true;
}
diff --git a/backends/merge/Merge.cpp b/backends/merge/Merge.cpp
index 993c0d1..8277ac5 100644
--- a/backends/merge/Merge.cpp
+++ b/backends/merge/Merge.cpp
@@ -31,7 +31,7 @@ namespace glabels
///
/// Constructor
///
- Merge::Merge( const Merge* merge ) : mSource(merge->mSource)
+ Merge::Merge( const Merge* merge ) : mId(merge->mId), mSource(merge->mSource)
{
foreach ( Record* record, merge->mRecordList )
{
diff --git a/backends/merge/Text.cpp b/backends/merge/Text.cpp
index 9d40cc3..93d5350 100644
--- a/backends/merge/Text.cpp
+++ b/backends/merge/Text.cpp
@@ -45,7 +45,7 @@ namespace glabels
Text::Text( const Text* merge )
: Merge( merge ),
mDelimeter(merge->mDelimeter), mLine1HasKeys(merge->mLine1HasKeys),
- mNFieldsMax(merge->mNFieldsMax)
+ mKeys(merge->mKeys), mNFieldsMax(merge->mNFieldsMax)
{
}
diff --git a/cmake/Modules/FindLibZint.cmake b/cmake/Modules/FindLibZint.cmake
index b44d80a..9f1a754 100644
--- a/cmake/Modules/FindLibZint.cmake
+++ b/cmake/Modules/FindLibZint.cmake
@@ -11,7 +11,7 @@ set (LIBZINT_DEFINITIONS "")
find_path (LIBZINT_INCLUDE_DIR NAMES zint.h)
-find_library (LIBZINT_LIBRARIES NAMES zint )
+find_library (LIBZINT_LIBRARY NAMES zint )
if (LIBZINT_LIBRARY AND LIBZINT_INCLUDE_DIR)
diff --git a/docs/BUILD-INSTRUCTIONS-LINUX.md b/docs/BUILD-INSTRUCTIONS-LINUX.md
index 6571fee..8f19722 100644
--- a/docs/BUILD-INSTRUCTIONS-LINUX.md
+++ b/docs/BUILD-INSTRUCTIONS-LINUX.md
@@ -1,7 +1,8 @@
gLabels Linux Build Instructions
================================
-## Prerequisites
+## General
+### Prerequisites
- g++
- CMake 2.8.12+
@@ -12,7 +13,7 @@ gLabels Linux Build Instructions
> may also need to be installed. Development packages are usually named something like
> libraryName-dev or libraryName-devel.
-## Compile and Install
+### Compile and Install
gLabels uses the CMake meta build system. Use the following commands to build and install gLabels:
@@ -24,3 +25,45 @@ $ cmake ..
$ make
$ sudo make install
+
+## Example: Ubuntu 19.04
+
+### Installing Prerequisites
+```
+sudo apt install cmake
+sudo apt install qtbase5-dev libqt5svg5-dev qttools5-dev zlib1g-dev
+```
+_QREncode (Optional)_
+```
+sudo apt install pkgconf libqrencode-dev
+```
+_Zint (Optional)_
+
+Install zint from source:
+```
+wget https://downloads.sourceforge.net/project/zint/zint/2.6.3/zint-2.6.3_final.tar.gz
+tar xzf zint-2.6.3_final.tar.gz
+cd zint-2.6.3.src/
+mkdir build && cd build && cmake .. && make
+sudo make install
+```
+_GNU Barcode (Optional)_
+
+As of version 0.99, GNU Barcode no longer installs its library. So install 0.98 from source:
+```
+wget https://ftp.gnu.org/gnu/barcode/barcode-0.98.tar.gz
+tar xzf barcode-0.98.tar.gz
+cd barcode-0.98/
+./configure && make
+sudo make install
+```
+### Compile and Install gLabels
+
+```
+$ cd glabels-qt
+$ mkdir build
+$ cd build
+$ cmake ..
+$ make
+$ sudo make install
+```
diff --git a/docs/BUILD-INSTRUCTIONS-MACOS.md b/docs/BUILD-INSTRUCTIONS-MACOS.md
new file mode 100644
index 0000000..5f0b440
--- /dev/null
+++ b/docs/BUILD-INSTRUCTIONS-MACOS.md
@@ -0,0 +1,20 @@
+gLabels MacOS Build Instructions
+================================
+
+## Prerequisites
+
+```
+brew install cmake
+brew install qt
+```
+
+## Compile and Install
+
+
+cd glabels_source_directory
+mkdir build
+cd build
+cmake -D CMAKE_PREFIX_PATH=/usr/local/opt/qt ..
+make
+sudo make install
+
diff --git a/docs/SUBSTITUTION-FIELD-SPEC.md b/docs/SUBSTITUTION-FIELD-SPEC.md
index b69ff38..ddfc2ef 100644
--- a/docs/SUBSTITUTION-FIELD-SPEC.md
+++ b/docs/SUBSTITUTION-FIELD-SPEC.md
@@ -17,6 +17,28 @@ modifiers = modifier [ ":" modifiers ] ;
modifier = format-modifier | default-value-modifier | new-line-modifier;
```
+
+Field Names
+-----------
+Field names can refer to either [Document Merge Fields](#document-merge-fields) or [User Variables](#user-variables). If a document merge field and a user variable share the same name, the document merge field takes precidence. Its syntax is simply:
+
+```ebnf
+field-name = merge-field-name | user-variable-name ;
+```
+
+### Document Merge Fields
+Document merge fields are the primary source of substitution fields. A document merge field represents a field from an external data source, such as a CSV file. The valid syntax for a document merge field name is determined by the merge source, with the following exception. Merge field names cannot contain either a colon (":") or closing curly bracket ("}").
+
+### User Variables
+Substitution fields can also refer to user variables. The syntax for valid user variable names is
+
+```ebnf
+letter = "a" | "b" | ... | "z" | "A" | ... | "Z";
+digit = "0" | "1" | "2" | ... | "9";
+user-variable-name = ( letter | "_" ) , { letter | digit | "_" } ;
+```
+
+
Modifiers
---------
### Format-Modifier (`%`)
@@ -89,20 +111,3 @@ ${CITY} ${STATE} ${ZIP}
`${ADDR2}` would be printed on its own line, only if it is set and non-empty.
-Document Merge Fields
----------------------
-Document merge fields are the primary source of substitution fields. A document merge field represents a field from an external data source, such as a CSV file.
-
-User Defined Variables
-----------------------
-Alternatively, merge fields can refer to user defined variables.
-
-Built-In Variables
-------------------
-Potentially, merge fields may also refer to built-in variables. Candidates include:
- - LABEL_NUMBER
- - PAGE_NUMBER
- - DATE
- - TIME
- - FILE_NAME
-
diff --git a/docs/TODO.md b/docs/TODO.md
index 6eb3cb8..039f682 100644
--- a/docs/TODO.md
+++ b/docs/TODO.md
@@ -29,3 +29,15 @@ Add support for "Continuous Roll" labels
Write help documentation
------------------------
+
+
+To Do List for gLabels 4.1 -- 2019-03-17
+========================================
+
+Create a "built-in" merge source
+--------------------------------
+As an alternative to external merge sources, let the user edit the merge source
+in situ. The user can add fields. The user can add records using those fields.
+The user created database will become part of the glabels project file.
+For simple databases, such as a small address list, this would be much easier
+to deal with than creating it externally.
diff --git a/glabels-batch/main.cpp b/glabels-batch/main.cpp
index e857f44..8240d02 100644
--- a/glabels-batch/main.cpp
+++ b/glabels-batch/main.cpp
@@ -60,7 +60,7 @@ int main( int argc, char **argv )
QCoreApplication::setOrganizationName( "glabels.org" );
QCoreApplication::setOrganizationDomain( "glabels.org" );
QCoreApplication::setApplicationName( "glabels-batch-qt" );
- QCoreApplication::setApplicationVersion( glabels::model::Version::STRING );
+ QCoreApplication::setApplicationVersion( glabels::model::Version::LONG_STRING );
//
// Setup translators
@@ -175,7 +175,7 @@ int main( int argc, char **argv )
}
glabels::model::PageRenderer renderer( model );
- renderer.setNCopies( 1 );
+ renderer.setNCopies( parser.value( "copies" ).toInt() );
renderer.setStartLabel( parser.value( "first" ).toInt() - 1 );
renderer.setPrintOutlines( parser.isSet( "outlines" ) );
renderer.setPrintCropMarks( parser.isSet( "crop-marks" ) );
diff --git a/glabels/AboutDialog.cpp b/glabels/AboutDialog.cpp
index ef9ff99..acfb423 100644
--- a/glabels/AboutDialog.cpp
+++ b/glabels/AboutDialog.cpp
@@ -38,7 +38,7 @@ namespace glabels
{
setupUi( this );
- QString version = tr("Version") + " " + model::Version::STRING;
+ QString version = tr("Version") + " " + model::Version::LONG_STRING;
QString description = tr("A program to create labels and business cards.");
diff --git a/glabels/CMakeLists.txt b/glabels/CMakeLists.txt
index 6679ac9..f8ba83f 100644
--- a/glabels/CMakeLists.txt
+++ b/glabels/CMakeLists.txt
@@ -13,9 +13,9 @@ set (glabels_sources
ColorHistory.cpp
ColorPaletteDialog.cpp
ColorPaletteItem.cpp
- ColorPaletteButtonItem.cpp
ColorSwatch.cpp
Cursors.cpp
+ EditVariableDialog.cpp
FieldButton.cpp
File.cpp
Help.cpp
@@ -40,6 +40,7 @@ set (glabels_sources
TemplatePicker.cpp
TemplatePickerItem.cpp
UndoRedoModel.cpp
+ VariablesView.cpp
)
set (glabels_qobject_headers
@@ -51,7 +52,7 @@ set (glabels_qobject_headers
ColorHistory.h
ColorPaletteDialog.h
ColorPaletteItem.h
- ColorPaletteButtonItem.h
+ EditVariableDialog.h
FieldButton.h
File.h
LabelEditor.h
@@ -69,10 +70,12 @@ set (glabels_qobject_headers
TemplateDesigner.h
TemplatePicker.h
UndoRedoModel.h
+ VariablesView.h
)
set (glabels_forms
ui/AboutDialog.ui
+ ui/EditVariableDialog.ui
ui/MergeView.ui
ui/ObjectEditor.ui
ui/PreferencesDialog.ui
@@ -95,6 +98,7 @@ set (glabels_forms
ui/TemplateDesignerOneLayoutPage.ui
ui/TemplateDesignerTwoLayoutPage.ui
ui/TemplateDesignerApplyPage.ui
+ ui/VariablesView.ui
)
set (glabels_resource_files
diff --git a/glabels/ColorButton.cpp b/glabels/ColorButton.cpp
index 1abb9a0..28ea4c8 100644
--- a/glabels/ColorButton.cpp
+++ b/glabels/ColorButton.cpp
@@ -48,8 +48,9 @@ namespace glabels
void ColorButton::init( const QString& defaultLabel,
- const QColor& defaultColor,
- const QColor& color )
+ const QColor& defaultColor,
+ const QColor& color,
+ bool showUseFieldButton )
{
mDefaultColor = defaultColor;
mColorNode = model::ColorNode( color );
@@ -61,7 +62,10 @@ namespace glabels
setText( "" );
setCheckable( true );
- mDialog = new ColorPaletteDialog( defaultLabel, defaultColor, color );
+ mDialog = new ColorPaletteDialog( defaultLabel,
+ defaultColor,
+ color,
+ showUseFieldButton );
connect( this, SIGNAL(toggled(bool)), this, SLOT(onButtonToggled(bool)) );
connect( mDialog, SIGNAL(colorChanged(model::ColorNode,bool)),
@@ -124,15 +128,10 @@ namespace glabels
}
- void ColorButton::setKeys( const QList keyList )
+ void ColorButton::setKeys( const merge::Merge* merge,
+ const model::Variables* variables )
{
- mDialog->setKeys( keyList );
- }
-
-
- void ColorButton::clearKeys()
- {
- mDialog->clearKeys();
+ mDialog->setKeys( merge, variables );
}
diff --git a/glabels/ColorButton.h b/glabels/ColorButton.h
index eb16611..81ba63d 100644
--- a/glabels/ColorButton.h
+++ b/glabels/ColorButton.h
@@ -58,13 +58,18 @@ namespace glabels
// Public Methods
/////////////////////////////////
public:
- void init( const QString& defaultLabel, const QColor& defaultColor, const QColor& color );
+ void init( const QString& defaultLabel,
+ const QColor& defaultColor,
+ const QColor& color,
+ bool showUseFieldButton = true );
+
void setColorNode( model::ColorNode colorNode );
void setColor( QColor color );
void setToDefault();
model::ColorNode colorNode();
- void setKeys( const QList keyList );
- void clearKeys();
+
+ void setKeys( const merge::Merge* merge,
+ const model::Variables* variables );
/////////////////////////////////
diff --git a/glabels/ColorHistory.cpp b/glabels/ColorHistory.cpp
index 60ff08f..ba564de 100644
--- a/glabels/ColorHistory.cpp
+++ b/glabels/ColorHistory.cpp
@@ -46,23 +46,25 @@ namespace glabels
}
- void ColorHistory::addColor( const QColor &color )
+ void ColorHistory::addColor( const QColor &color, const QString& name )
{
- QList colorList = readColorList();
+ QString nameColor = name + ":" + color.name();
+
+ QStringList nameColorList = readNameColorList();
// Remove any occurrences of this color already in list
- colorList.removeAll( color );
+ nameColorList.removeAll( nameColor );
// Now add to list
- colorList.append( color );
+ nameColorList.append( nameColor );
// Remove oldest colors, if size exceeds current max
- while ( colorList.size() > MAX_COLORS )
+ while ( nameColorList.size() > MAX_COLORS )
{
- colorList.removeFirst();
+ nameColorList.removeFirst();
}
- writeColorList( colorList );
+ writeNameColorList( nameColorList );
emit changed();
}
@@ -70,55 +72,83 @@ namespace glabels
QList ColorHistory::getColors()
{
- return readColorList();
- }
-
-
- QColor ColorHistory::getColor( int id )
- {
- QList colors = readColorList();
- return colors[id];
- }
-
-
- QList ColorHistory::readColorList()
- {
- QStringList defaultList;
- QSettings settings;
-
- settings.beginGroup( "ColorHistory" );
- QStringList colorNameList = settings.value( "colors", defaultList ).toStringList();
- settings.endGroup();
-
QList colorList;
- foreach ( QString colorName, colorNameList )
+
+ for ( QString& nameColor : readNameColorList() )
{
- colorList << QColor( colorName );
- }
-
- // Remove oldest colors, if size exceeds current max
- while ( colorList.size() > MAX_COLORS )
- {
- colorList.removeFirst();
+ QStringList v = nameColor.split( ':' );
+ if ( v.size() == 2 )
+ {
+ colorList << QColor( v[1] );
+ }
+ else if ( v.size() == 1 )
+ {
+ // Old-style, no name
+ colorList << QColor( v[0] );
+ }
+ else
+ {
+ // Should not happen
+ qWarning() << "Invalid color history.";
+ }
}
return colorList;
}
- void ColorHistory::writeColorList( const QList& colorList )
+ QStringList ColorHistory::getNames()
{
- // Build name list
- QStringList colorNameList;
- foreach ( QColor color, colorList )
+ QStringList nameList;
+
+ for ( QString& nameColor : readNameColorList() )
{
- colorNameList << color.name();
+ QStringList v = nameColor.split( ':' );
+ if ( v.size() == 2 )
+ {
+ nameList << v[0];
+ }
+ else if ( v.size() == 1 )
+ {
+ // Old-style, no name
+ nameList << QString(tr("color %1")).arg( v[0] );
+ }
+ else
+ {
+ // Should not happen
+ qWarning() << "Invalid color history.";
+ }
}
+ return nameList;
+ }
+
+
+ QStringList ColorHistory::readNameColorList()
+ {
+ QStringList defaultList;
+ QSettings settings;
+
+ settings.beginGroup( "ColorHistory" );
+ QStringList nameColorList = settings.value( "colors", defaultList ).toStringList();
+ settings.endGroup();
+
+ // Remove oldest colors, if size exceeds current max
+ while ( nameColorList.size() > MAX_COLORS )
+ {
+ nameColorList.removeFirst();
+ }
+
+ return nameColorList;
+ }
+
+
+ void ColorHistory::writeNameColorList( const QStringList& nameColorList )
+ {
// Save
QSettings settings;
settings.beginGroup( "ColorHistory" );
- settings.setValue( "colors", colorNameList );
+ settings.setValue( "colors", nameColorList );
settings.endGroup();
}
diff --git a/glabels/ColorHistory.h b/glabels/ColorHistory.h
index b74b3b4..eb14812 100644
--- a/glabels/ColorHistory.h
+++ b/glabels/ColorHistory.h
@@ -60,17 +60,17 @@ namespace glabels
// Public Methods
/////////////////////////////////
public:
- void addColor( const QColor &color );
+ void addColor( const QColor& color, const QString& name );
QList getColors();
- QColor getColor( int id );
+ QStringList getNames();
/////////////////////////////////
// Private Methods
/////////////////////////////////
private:
- QList readColorList();
- void writeColorList( const QList& colorList );
+ QStringList readNameColorList();
+ void writeNameColorList( const QStringList& nameColorList );
/////////////////////////////////
diff --git a/glabels/ColorPaletteButtonItem.cpp b/glabels/ColorPaletteButtonItem.cpp
deleted file mode 100644
index ce8d5bf..0000000
--- a/glabels/ColorPaletteButtonItem.cpp
+++ /dev/null
@@ -1,124 +0,0 @@
-/* ColorPaletteButtonItem.cpp
- *
- * Copyright (C) 2014 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 "ColorPaletteButtonItem.h"
-
-#include
-#include
-
-
-namespace glabels
-{
-
- //
- // Private
- //
- namespace
- {
- const int border = 4;
- const int hBox = 25;
- const int outlineWidthPixels = 1;
- }
-
-
- ///
- /// Constructor From Data
- ///
- ColorPaletteButtonItem::ColorPaletteButtonItem( const QString& text, QWidget* parent )
- : QWidget(parent), mText(text), mHover(false)
- {
- setSizePolicy( QSizePolicy( QSizePolicy::Preferred, QSizePolicy::Fixed ) );
- setMinimumSize( hBox+2*border+1, hBox+2*border+1 );
- }
-
-
- ///
- /// Paint Event
- ///
- void ColorPaletteButtonItem::paintEvent( QPaintEvent* event )
- {
- QPainter painter(this);
-
- //
- // Draw background
- //
- if ( isEnabled() && mHover )
- {
- QLinearGradient gradient( 0, 0, 0, height() );
- gradient.setColorAt( 0, palette().color( QPalette::Highlight ).lighter() );
- gradient.setColorAt( 1, palette().color( QPalette::Highlight ) );
- painter.setBrush( QBrush( gradient ) );
-
- QPen pen( palette().color( QPalette::Text ) );
- pen.setWidth( outlineWidthPixels );
- painter.setPen( pen );
-
- painter.drawRect( 0, 0, width()-1, height()-1 );
- }
-
- //
- // Draw text
- //
- painter.setBrush( QBrush( Qt::NoBrush ) );
-
- if ( isEnabled() && mHover )
- {
- painter.setPen( QPen( palette().color( QPalette::HighlightedText ) ) );
- }
- else
- {
- painter.setPen( QPen( palette().color( QPalette::Text ) ) );
- }
-
- QRect textRect( border, border, width()-2*border, hBox );
-
- painter.drawText( textRect, Qt::AlignLeft|Qt::AlignVCenter, mText );
- }
-
-
- ///
- /// Enter Event
- ///
- void ColorPaletteButtonItem::enterEvent( QEvent* event )
- {
- mHover = true;
- update();
- }
-
-
- ///
- /// Leave Event
- ///
- void ColorPaletteButtonItem::leaveEvent( QEvent* event )
- {
- mHover = false;
- update();
- }
-
-
- ///
- /// Mouse Press Event
- ///
- void ColorPaletteButtonItem::mousePressEvent( QMouseEvent* event )
- {
- emit activated();
- }
-
-} // namespace glabels
diff --git a/glabels/ColorPaletteDialog.cpp b/glabels/ColorPaletteDialog.cpp
index 71feb32..9ad496a 100644
--- a/glabels/ColorPaletteDialog.cpp
+++ b/glabels/ColorPaletteDialog.cpp
@@ -18,14 +18,16 @@
* along with gLabels-qt. If not, see .
*/
+
#include "ColorPaletteDialog.h"
#include
-#include
-#include
-#include
#include
+#include
+#include
+#include
#include
+#include
#include
@@ -83,6 +85,7 @@ namespace glabels
ColorPaletteDialog::ColorPaletteDialog( const QString& defaultLabel,
const QColor& defaultColor,
const QColor& color,
+ bool showUseFieldButton,
QWidget* parent )
: QDialog( parent )
{
@@ -99,14 +102,12 @@ namespace glabels
vLayout->setContentsMargins( 0, 0, 0, 0 );
vLayout->setSpacing( 0 );
- auto* defaultButton = new ColorPaletteButtonItem( defaultLabel );
- connect( defaultButton, SIGNAL(activated()), this, SLOT(onDefaultItemActivated()) );
- vLayout->addWidget( defaultButton );
-
- QFrame* hline1 = new QFrame;
- hline1->setFrameStyle( QFrame::HLine | QFrame::Plain );
- hline1->setLineWidth( 1 );
- vLayout->addWidget( hline1 );
+ //
+ // Construct Standard Colors Grid
+ //
+ auto* standardColorsGroup = new QGroupBox( tr("Standard Colors") );
+ standardColorsGroup->setAlignment( Qt::AlignHCenter );
+ vLayout->addWidget( standardColorsGroup );
auto* mainPaletteLayout = new QGridLayout();
mainPaletteLayout->setSpacing( 0 );
@@ -119,17 +120,20 @@ namespace glabels
ColorPaletteItem* item = new ColorPaletteItem( i,
QColor( mColorTable[i].colorSpec ),
tr(mColorTable[i].trname) );
- connect( item, SIGNAL(activated(int)), this, SLOT(onPaletteItemActivated(int)) );
+ connect( item, SIGNAL(activated(int)),
+ this, SLOT(onPaletteItemActivated(int)) );
mainPaletteLayout->addWidget( item, iRow, iCol );
}
}
- vLayout->addLayout( mainPaletteLayout );
+ standardColorsGroup->setLayout( mainPaletteLayout );
- QFrame* hline2 = new QFrame;
- hline2->setFrameStyle( QFrame::HLine | QFrame::Plain );
- hline2->setLineWidth( 1 );
- vLayout->addWidget( hline2 );
+ //
+ // Construct Recent Colors Grid
+ //
+ auto* recentColorsGroup = new QGroupBox( tr("Recent Colors") );
+ recentColorsGroup->setAlignment( Qt::AlignHCenter );
+ vLayout->addWidget( recentColorsGroup );
auto* customPaletteLayout = new QHBoxLayout();
customPaletteLayout->setSpacing( 0 );
@@ -137,40 +141,49 @@ namespace glabels
{
mHistoryItem[iCol] = new ColorPaletteItem( iCol, QColor(0,0,0,0), "" );
mHistoryItem[iCol]->setEnabled( false );
- connect( mHistoryItem[iCol], SIGNAL(activated(int)), this, SLOT(onHistoryItemActivated(int)) );
+ connect( mHistoryItem[iCol], SIGNAL(activated(int)),
+ this, SLOT(onHistoryItemActivated(int)) );
customPaletteLayout->addWidget( mHistoryItem[iCol] );
}
- vLayout->addLayout( customPaletteLayout );
+ recentColorsGroup->setLayout( customPaletteLayout );
- QFrame* hline3 = new QFrame;
- hline3->setFrameStyle( QFrame::HLine | QFrame::Plain );
- hline3->setLineWidth( 1 );
- vLayout->addWidget( hline3 );
-
- ColorPaletteButtonItem* customColorButton = new ColorPaletteButtonItem( tr("Custom color...") );
- connect( customColorButton, SIGNAL(activated()), this, SLOT(onCustomColorItemActivated()) );
+ //
+ // Construct Default (e.g. "No Fill") Button
+ //
+ auto* defaultColorButton = new QPushButton( defaultLabel );
+ defaultColorButton->setAutoDefault( false );
+ defaultColorButton->setDefault( false );
+ connect( defaultColorButton, SIGNAL(clicked()), this, SLOT(onDefaultButtonClicked()) );
+ vLayout->addWidget( defaultColorButton );
+
+ //
+ // Construct Custom Color Button
+ //
+ auto* customColorButton = new QPushButton( tr("Custom color...") );
+ customColorButton->setAutoDefault( false );
+ customColorButton->setDefault( false );
+ connect( customColorButton, SIGNAL(clicked()), this, SLOT(onCustomColorButtonClicked()) );
vLayout->addWidget( customColorButton );
- QFrame* hline4 = new QFrame;
- hline4->setFrameStyle( QFrame::HLine | QFrame::Plain );
- hline4->setLineWidth( 1 );
- vLayout->addWidget( hline4 );
+ //
+ // Construct "Use field" Button
+ //
+ if ( showUseFieldButton )
+ {
+ mFieldButton = new FieldButton();
+ mFieldButton->setText( tr("Use substitution field") );
+ mFieldButton->setAutoDefault( false );
+ mFieldButton->setDefault( false );
+ connect( mFieldButton, SIGNAL(keySelected(QString)), this, SLOT(onKeySelected(QString)) );
+ vLayout->addWidget( mFieldButton );
+ }
+ else
+ {
+ mFieldButton = nullptr;
+ }
- mMergeFieldCombo = new QComboBox();
- mMergeFieldCombo->addItem( tr("Merge key...") );
- mMergeFieldCombo->setMinimumSize( 34, 34 );
- mMergeFieldCombo->setFrame( false );
- mMergeFieldCombo->setEnabled( false );
- connect( mMergeFieldCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(onComboIndexChanged(int)) );
- vLayout->addWidget( mMergeFieldCombo );
-
- // Item 0 is the ComboBox title, not an item intended for selection. So disable it.
- const auto* model = qobject_cast(mMergeFieldCombo->model());
- QStandardItem* item = model->item(0);
- item->setFlags( item->flags() & ~(Qt::ItemIsSelectable|Qt::ItemIsEnabled) );
-
setLayout( vLayout );
loadCustomColorHistory();
@@ -183,41 +196,47 @@ namespace glabels
}
- void ColorPaletteDialog::setKeys( const QStringList& keyList )
+ void ColorPaletteDialog::setKeys( const merge::Merge* merge,
+ const model::Variables* variables )
{
- mKeys = keyList;
-
- // Clear old keys, (all entries, except item 0)
- for ( int index = mMergeFieldCombo->count()-1; index > 0; index-- )
+ if (mFieldButton)
{
- mMergeFieldCombo->removeItem( index );
- }
-
- // Add new keys
- if ( keyList.size() > 0 )
- {
- mMergeFieldCombo->addItems( keyList );
- mMergeFieldCombo->setEnabled( true );
- }
- else
- {
- mMergeFieldCombo->setEnabled( false );
+ mFieldButton->setKeys( merge, variables );
}
}
- void ColorPaletteDialog::clearKeys()
+ void ColorPaletteDialog::onPaletteItemActivated( int id )
{
-
- for ( int index = mMergeFieldCombo->count()-1; index > 0; index-- )
+ model::ColorNode newColorNode;
+ newColorNode.setField( false );
+ newColorNode.setColor( QColor( mColorTable[id].colorSpec ) );
+ newColorNode.setKey( "" );
+
+ if ( newColorNode != mColorNode )
{
- mMergeFieldCombo->removeItem( index );
+ mColorNode = newColorNode;
+
+ mColorHistory->addColor( mColorNode.color(), mColorTable[id].trname );
+
+ emit colorChanged( mColorNode, false );
+ accept();
}
- mMergeFieldCombo->setEnabled( false );
}
- void ColorPaletteDialog::onDefaultItemActivated()
+ void ColorPaletteDialog::onHistoryItemActivated( int id )
+ {
+ mColorNode.setField( false );
+ mColorNode.setColor( mColorHistory->getColors()[id] );
+ mColorNode.setKey( "" );
+
+ emit colorChanged( mColorNode, false );
+ accept();
+ }
+
+
+ void ColorPaletteDialog::onDefaultButtonClicked()
{
mColorNode.setField( false );
mColorNode.setColor( mDefaultColor );
@@ -228,29 +247,7 @@ namespace glabels
}
- void ColorPaletteDialog::onPaletteItemActivated( int id )
- {
- mColorNode.setField( false );
- mColorNode.setColor( QColor( mColorTable[id].colorSpec ) );
- mColorNode.setKey( "" );
-
- emit colorChanged( mColorNode, false );
- accept();
- }
-
-
- void ColorPaletteDialog::onHistoryItemActivated( int id )
- {
- mColorNode.setField( false );
- mColorNode.setColor( mColorHistory->getColor(id) );
- mColorNode.setKey( "" );
-
- emit colorChanged( mColorNode, false );
- accept();
- }
-
-
- void ColorPaletteDialog::onCustomColorItemActivated()
+ void ColorPaletteDialog::onCustomColorButtonClicked()
{
QColorDialog dlg( mColorNode.color(), this );
dlg.setWindowTitle( tr("Custom Color") );
@@ -267,7 +264,10 @@ namespace glabels
{
mColorNode = newColorNode;
- mColorHistory->addColor( mColorNode.color() );
+ // TRANSLATORS
+ //: %1 = color specification in hex. String must not contain a colon (:).
+ mColorHistory->addColor( mColorNode.color(),
+ QString(tr("Custom Color %1")).arg(mColorNode.color().name()) );
emit colorChanged( mColorNode, false );
accept();
@@ -284,12 +284,13 @@ namespace glabels
void ColorPaletteDialog::loadCustomColorHistory()
{
+ QStringList nameList = mColorHistory->getNames();
QList colorList = mColorHistory->getColors();
int id = 0;
foreach ( QColor color, colorList )
{
- mHistoryItem[id]->setColor( id, color, QString(tr("Custom color #%1").arg(id+1) ) );
+ mHistoryItem[id]->setColor( id, color, nameList[id] );
mHistoryItem[id]->setEnabled( true );
id++;
}
@@ -302,25 +303,14 @@ namespace glabels
}
- void ColorPaletteDialog::onComboIndexChanged( int index )
+ void ColorPaletteDialog::onKeySelected( QString key )
{
- if ( index != 0 )
- {
- mColorNode.setField( true );
- mColorNode.setColor( QColor( 0xee, 0xee, 0xec ) );
- mColorNode.setKey( mKeys[index-1] );
+ mColorNode.setField( true );
+ mColorNode.setColor( QColor( 0xee, 0xee, 0xec ) );
+ mColorNode.setKey( key );
- emit colorChanged( mColorNode, false );
- accept();
- }
- }
-
-
- void ColorPaletteDialog::showEvent( QShowEvent* event )
- {
- mMergeFieldCombo->setCurrentIndex( 0 );
-
- QDialog::showEvent( event );
+ emit colorChanged( mColorNode, false );
+ accept();
}
} // namespace glabels
diff --git a/glabels/ColorPaletteDialog.h b/glabels/ColorPaletteDialog.h
index db5f7e1..6e1a22c 100644
--- a/glabels/ColorPaletteDialog.h
+++ b/glabels/ColorPaletteDialog.h
@@ -24,11 +24,10 @@
#include "ColorHistory.h"
#include "ColorPaletteItem.h"
-#include "ColorPaletteButtonItem.h"
+#include "FieldButton.h"
#include "model/ColorNode.h"
-#include
#include
@@ -50,6 +49,7 @@ namespace glabels
ColorPaletteDialog( const QString& defaultLabel,
const QColor& defaultColor,
const QColor& color,
+ bool showUseFieldButton = true,
QWidget* parent = nullptr );
@@ -64,25 +64,23 @@ namespace glabels
// Public Methods
/////////////////////////////////
public:
- void setColorNode( const model::ColorNode& colorNode );
- void setKeys( const QStringList& keyList );
- void clearKeys();
+ void setColorNode( const model::ColorNode& colorNode );
+
+ void setKeys( const merge::Merge* merge,
+ const model::Variables* variables );
/////////////////////////////////
// Slots
/////////////////////////////////
private slots:
- void onDefaultItemActivated();
void onPaletteItemActivated( int id );
void onHistoryItemActivated( int id );
- void onCustomColorItemActivated();
+ void onDefaultButtonClicked();
+ void onCustomColorButtonClicked();
+ void onKeySelected( QString key );
void onColorHistoryChanged();
- void onComboIndexChanged( int index );
- protected:
- void showEvent( QShowEvent* event ) override;
-
/////////////////////////////////
// Private Methods
@@ -111,8 +109,7 @@ namespace glabels
ColorHistory* mColorHistory;
ColorPaletteItem* mHistoryItem[PALETTE_COLS];
- QComboBox* mMergeFieldCombo;
- QStringList mKeys;
+ FieldButton* mFieldButton;
};
diff --git a/glabels/EditVariableDialog.cpp b/glabels/EditVariableDialog.cpp
new file mode 100644
index 0000000..a685e73
--- /dev/null
+++ b/glabels/EditVariableDialog.cpp
@@ -0,0 +1,220 @@
+/* EditVariableDialog.cpp
+ *
+ * Copyright (C) 2019 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 "EditVariableDialog.h"
+
+#include "model/Settings.h"
+
+#include
+
+
+namespace
+{
+ // All variable types. (must be in sorted order)
+ const QVector allTypes = {
+ glabels::model::Variable::Type::STRING,
+ glabels::model::Variable::Type::INTEGER,
+ glabels::model::Variable::Type::FLOATING_POINT,
+ glabels::model::Variable::Type::COLOR
+ };
+
+ // All variable increments. (must be in sorted order)
+ const QVector allIncrements = {
+ glabels::model::Variable::Increment::NEVER,
+ glabels::model::Variable::Increment::PER_ITEM,
+ glabels::model::Variable::Increment::PER_COPY,
+ glabels::model::Variable::Increment::PER_PAGE
+ };
+}
+
+
+namespace glabels
+{
+
+ ///
+ /// Constructor
+ ///
+ EditVariableDialog::EditVariableDialog( QWidget *parent )
+ : QDialog(parent)
+ {
+ setupUi( this );
+
+ QRegularExpression reIdentifier( "[a-zA-Z_][a-zA-Z_0-9]*" );
+ nameEdit->setValidator( new QRegularExpressionValidator( reIdentifier ) );
+
+ colorValueButton->init( tr("Default"),
+ QColor(0,0,0,255),
+ QColor(0,0,0,255),
+ false );
+
+ for ( auto type : allTypes )
+ {
+ typeCombo->addItem( model::Variable::typeToI18nString( type ) );
+ }
+
+ for ( auto type : allIncrements )
+ {
+ incrementCombo->addItem( model::Variable::incrementToI18nString( type ) );
+ }
+
+ stepSizeEdit->setText( "1" );
+ }
+
+
+ ///
+ /// Set variable
+ ///
+ void EditVariableDialog::setVariable( const model::Variable& variable )
+ {
+ typeCombo->setCurrentIndex( static_cast(variable.type()) );
+ nameEdit->setText( variable.name() );
+ valueEdit->setText( variable.initialValue() );
+ colorValueButton->setColor( QColor( variable.initialValue() ) );
+ incrementCombo->setCurrentIndex( static_cast(variable.increment()) );
+ stepSizeEdit->setText( variable.stepSize() );
+
+ updateControls();
+ }
+
+
+ ///
+ /// Get variable
+ ///
+ model::Variable EditVariableDialog::variable() const
+ {
+ return model::Variable( static_cast(typeCombo->currentIndex()),
+ nameEdit->text(),
+ valueEdit->text(),
+ static_cast(incrementCombo->currentIndex()),
+ stepSizeEdit->text() );
+ }
+
+
+ ///
+ /// nameEdit Changed
+ ///
+ void EditVariableDialog::onNameEditChanged()
+ {
+ validateCurrentInputs();
+ }
+
+
+ ///
+ /// typeCombo Changed
+ ///
+ void EditVariableDialog::onTypeComboChanged()
+ {
+ updateControls();
+ }
+
+
+ ///
+ /// valueEdit Changed
+ ///
+ void EditVariableDialog::onValueEditChanged()
+ {
+ validateCurrentInputs();
+ }
+
+
+ ///
+ /// colorValueButton Changed
+ ///
+ void EditVariableDialog::onColorValueButtonChanged()
+ {
+ valueEdit->setText( colorValueButton->colorNode().color().name() );
+ validateCurrentInputs();
+ }
+
+
+ ///
+ /// incrementCombo Changed
+ ///
+ void EditVariableDialog::onIncrementComboChanged()
+ {
+ updateControls();
+ }
+
+
+ ///
+ /// stepSizeEdit Changed
+ ///
+ void EditVariableDialog::onStepSizeEditChanged()
+ {
+ validateCurrentInputs();
+ }
+
+
+ ///
+ /// update controls
+ ///
+ void EditVariableDialog::updateControls()
+ {
+ auto type = static_cast(typeCombo->currentIndex());
+ auto increment = static_cast(incrementCombo->currentIndex());
+
+ switch (type)
+ {
+
+ case model::Variable::Type::INTEGER:
+ valueEdit->setValidator( new QIntValidator() );
+ stepSizeEdit->setValidator( new QIntValidator() );
+ break;
+
+ case model::Variable::Type::FLOATING_POINT:
+ valueEdit->setValidator( new QDoubleValidator() );
+ stepSizeEdit->setValidator( new QDoubleValidator() );
+ break;
+
+ default:
+ valueEdit->setValidator( nullptr );
+ stepSizeEdit->setValidator( nullptr );
+ break;
+
+ }
+
+ colorValueButton->setVisible( type == model::Variable::Type::COLOR );
+
+ bool isNumeric = ( type == model::Variable::Type::INTEGER ) ||
+ ( type == model::Variable::Type::FLOATING_POINT );
+
+ incrementGroup->setVisible( isNumeric );
+ stepSizeLabel->setEnabled( isNumeric && (increment != model::Variable::Increment::NEVER) );
+ stepSizeEdit->setEnabled( isNumeric && (increment != model::Variable::Increment::NEVER) );
+
+ validateCurrentInputs();
+ }
+
+
+ ///
+ /// validate current inputs
+ ///
+ void EditVariableDialog::validateCurrentInputs()
+ {
+ bool hasValidIdentifier = nameEdit->hasAcceptableInput();
+ bool hasValidValue = valueEdit->hasAcceptableInput();
+ bool hasValidStepSize = stepSizeEdit->hasAcceptableInput();
+
+ bool isValid = hasValidIdentifier && hasValidValue && hasValidStepSize;
+ buttonBox->button(QDialogButtonBox::Ok)->setEnabled( isValid );
+ }
+
+
+} // namespace glabels
diff --git a/glabels/ColorPaletteButtonItem.h b/glabels/EditVariableDialog.h
similarity index 59%
rename from glabels/ColorPaletteButtonItem.h
rename to glabels/EditVariableDialog.h
index 0ffc627..6c71d61 100644
--- a/glabels/ColorPaletteButtonItem.h
+++ b/glabels/EditVariableDialog.h
@@ -1,6 +1,6 @@
-/* ColorPaletteButtonItem.h
+/* EditVariableDialog.h
*
- * Copyright (C) 2014 Jim Evins
+ * Copyright (C) 2019 Jim Evins
*
* This file is part of gLabels-qt.
*
@@ -18,21 +18,21 @@
* along with gLabels-qt. If not, see .
*/
-#ifndef ColorPaletteButtonItem_h
-#define ColorPaletteButtonItem_h
+#ifndef EditVariableDialog_h
+#define EditVariableDialog_h
-#include
-#include
+#include "ui_EditVariableDialog.h"
+#include "model/Variable.h"
namespace glabels
{
///
- /// Color Palette Item
+ /// New Label Dialog Widget
///
- class ColorPaletteButtonItem : public QWidget
+ class EditVariableDialog : public QDialog, public Ui_EditVariableDialog
{
Q_OBJECT
@@ -40,36 +40,37 @@ namespace glabels
// Life Cycle
/////////////////////////////////
public:
- ColorPaletteButtonItem( const QString& text, QWidget* parent = nullptr );
+ EditVariableDialog( QWidget *parent = nullptr );
/////////////////////////////////
- // Signals
+ // Public methods
/////////////////////////////////
- signals:
- void activated();
-
+ void setVariable( const model::Variable& variable );
+ model::Variable variable() const;
+
/////////////////////////////////
- // Event handlers
+ // Slots
/////////////////////////////////
- protected:
- void paintEvent( QPaintEvent* event ) override;
- void enterEvent( QEvent* event ) override;
- void leaveEvent( QEvent* event ) override;
- void mousePressEvent( QMouseEvent* event ) override;
-
+ private slots:
+ void onNameEditChanged();
+ void onTypeComboChanged();
+ void onValueEditChanged();
+ void onColorValueButtonChanged();
+ void onIncrementComboChanged();
+ void onStepSizeEditChanged();
+
/////////////////////////////////
- // Private Data
+ // Private methods
/////////////////////////////////
- private:
- QString mText;
+ void updateControls();
+ void validateCurrentInputs();
- bool mHover;
};
}
-#endif // ColorPaletteButtonItem_h
+#endif // EditVariableDialog_h
diff --git a/glabels/FieldButton.cpp b/glabels/FieldButton.cpp
index f6c25b6..483e770 100644
--- a/glabels/FieldButton.cpp
+++ b/glabels/FieldButton.cpp
@@ -1,6 +1,6 @@
/* FieldButton.cpp
*
- * Copyright (C) 2014-2016 Jim Evins
+ * Copyright (C) 2019 Jim Evins
*
* This file is part of gLabels-qt.
*
@@ -30,79 +30,61 @@ namespace glabels
///
/// Constructor
///
- FieldButton::FieldButton( QWidget* parent )
- : QComboBox(parent)
+ FieldButton::FieldButton( QWidget* parent ) : QPushButton(parent)
{
setEnabled( false );
-
- connect( this, SIGNAL(currentIndexChanged(int)), this, SLOT(onIndexChanged(int)) );
+ setMenu( &mMenu );
+
+ connect( &mMenu, SIGNAL(triggered(QAction*)),
+ this, SLOT(onMenuActionTriggered(QAction*)) );
}
- void FieldButton::setName( const QString& name )
- {
- mName = name;
- if ( count() == 0 )
- {
- addItem( mName );
- }
- else
- {
- setItemText( 0, mName );
- }
-
- // Item 0 is the ComboBox title, not an item intended for selection. So disable it.
- const auto* itemModel = qobject_cast(model());
- QStandardItem* item = itemModel->item(0);
- item->setFlags( item->flags() & ~(Qt::ItemIsSelectable|Qt::ItemIsEnabled) );
- }
-
-
- void FieldButton::setKeys( const QStringList& keyList )
+ ///
+ /// Set Keys
+ ///
+ void FieldButton::setKeys( const merge::Merge* merge,
+ const model::Variables* variables )
{
// Clear old keys
- clear();
- addItem( mName );
+ mMenu.clear();
+
+ // Add merge keys, if any
+ mMenu.addSection( tr("Merge fields") );
+ for ( auto& key : merge->keys() )
+ {
+ auto* action = mMenu.addAction( QString( "${%1}" ).arg( key ) );
+ action->setData( key );
+ }
+ if ( merge->keys().empty() )
+ {
+ auto* action = mMenu.addAction( "None" );
+ action->setEnabled( false );
+ }
- // Item 0 is the ComboBox title, not an item intended for selection. So disable it.
- const auto* itemModel = qobject_cast(model());
- QStandardItem* item = itemModel->item(0);
- item->setFlags( item->flags() & ~(Qt::ItemIsSelectable|Qt::ItemIsEnabled) );
-
- // Add new keys
- if ( keyList.size() > 0 )
+ // Add variable keys, if any
+ mMenu.addSection( tr("Variables") );
+ for ( auto& key : variables->keys() )
{
- addItems( keyList );
- setEnabled( true );
+ auto* action = mMenu.addAction( QString( "${%1}" ).arg( key ) );
+ action->setData( key );
}
- else
+ if ( variables->keys().empty() )
{
- setEnabled( false );
+ auto* action = mMenu.addAction( "None" );
+ action->setEnabled( false );
}
+
+ setEnabled( !merge->keys().empty() || !variables->keys().empty() );
}
- void FieldButton::clearKeys()
- {
- clear();
- addItem( mName );
-
- setEnabled( false );
- }
-
-
-
///
- /// onMenuKeySelected slot
+ /// onMenuActionTriggered slot
///
- void FieldButton::onIndexChanged( int index )
+ void FieldButton::onMenuActionTriggered( QAction* action )
{
- if ( index > 0 )
- {
- emit keySelected( itemText(index) );
-
- setCurrentIndex( 0 );
- }
+ emit keySelected( action->data().toString() );
}
} // namespace glabels
diff --git a/glabels/FieldButton.h b/glabels/FieldButton.h
index 1da2d57..230a86d 100644
--- a/glabels/FieldButton.h
+++ b/glabels/FieldButton.h
@@ -1,6 +1,6 @@
/* FieldButton.h
*
- * Copyright (C) 2014-2016 Jim Evins
+ * Copyright (C) 2019 Jim Evins
*
* This file is part of gLabels-qt.
*
@@ -22,8 +22,13 @@
#define FieldButton_h
-#include
-#include
+#include "model/Variables.h"
+#include "merge/Merge.h"
+
+#include
+#include
+#include
+#include
namespace glabels
@@ -32,7 +37,7 @@ namespace glabels
///
/// Field Button
///
- class FieldButton : public QComboBox
+ class FieldButton : public QPushButton
{
Q_OBJECT
@@ -54,23 +59,22 @@ namespace glabels
// Public Methods
/////////////////////////////////
public:
- void setName( const QString& name = "" );
- void setKeys( const QStringList& keyList );
- void clearKeys();
+ void setKeys( const merge::Merge* merge,
+ const model::Variables* variables );
/////////////////////////////////
// Slots
/////////////////////////////////
private slots:
- void onIndexChanged( int index );
+ void onMenuActionTriggered( QAction* action );
/////////////////////////////////
// Private Data
/////////////////////////////////
private:
- QString mName;
+ QMenu mMenu;
};
diff --git a/glabels/File.cpp b/glabels/File.cpp
index 71fa160..5a35473 100644
--- a/glabels/File.cpp
+++ b/glabels/File.cpp
@@ -112,8 +112,6 @@ namespace glabels
model::Model *model = model::XmlLabelParser::readFile( fileName );
if ( model )
{
- model->setFileName( fileName );
-
// Either apply to current window or open a new one
if ( window->isEmpty() )
{
@@ -152,8 +150,6 @@ namespace glabels
model::Model *model = model::XmlLabelParser::readFile( fileName );
if ( model )
{
- model->setFileName( fileName );
-
// Either apply to current window or open a new one
if ( window->isEmpty() )
{
@@ -213,7 +209,8 @@ namespace glabels
///
bool File::saveAs( MainWindow *window )
{
- // Either use the saved CWD from a previous open/save or grab it from the path of the current file
+ // Either use the saved CWD from a previous open/save or grab it from the path
+ // of the current file.
QString cwd = mCwd;
if ( window->model() && !window->model()->fileName().isEmpty() )
{
diff --git a/glabels/Icons.h b/glabels/Icons.h
index 5f02ed2..37dd081 100644
--- a/glabels/Icons.h
+++ b/glabels/Icons.h
@@ -473,6 +473,16 @@ namespace glabels
};
+ class Variables : public QIcon
+ {
+ public:
+ Variables()
+ {
+ addPixmap( QPixmap( ":icons/flat/48x48/glabels-variables.svg" ) );
+ }
+ };
+
+
class ZoomBestFit : public QIcon
{
public:
diff --git a/glabels/LabelEditor.cpp b/glabels/LabelEditor.cpp
index ef7fe05..85ede54 100644
--- a/glabels/LabelEditor.cpp
+++ b/glabels/LabelEditor.cpp
@@ -469,6 +469,10 @@ namespace glabels
mResizeObject = handle->owner();
mResizeHandle = handle;
mResizeHonorAspect = event->modifiers() & Qt::ControlModifier;
+ if ( mResizeObject->lockAspectRatio() )
+ {
+ mResizeHonorAspect = !mResizeHonorAspect;
+ }
mState = ArrowResize;
}
@@ -657,6 +661,7 @@ namespace glabels
break;
case ArrowResize:
+ mUndoRedoModel->checkpoint( tr("Resize") );
handleResizeMotion( xWorld, yWorld );
break;
@@ -1157,7 +1162,7 @@ namespace glabels
void
LabelEditor::drawObjectsLayer( QPainter* painter )
{
- mModel->draw( painter );
+ mModel->draw( painter, true, nullptr, nullptr );
}
diff --git a/glabels/MainWindow.cpp b/glabels/MainWindow.cpp
index 15bfda9..42c939d 100644
--- a/glabels/MainWindow.cpp
+++ b/glabels/MainWindow.cpp
@@ -31,6 +31,7 @@
#include "PropertiesView.h"
#include "StartupView.h"
#include "UndoRedoModel.h"
+#include "VariablesView.h"
#include "model/Db.h"
#include "model/Model.h"
@@ -51,7 +52,8 @@ namespace
EDITOR_PAGE_INDEX = 1,
PROPERTIES_PAGE_INDEX = 2,
MERGE_PAGE_INDEX = 3,
- PRINT_PAGE_INDEX = 4,
+ VARIABLES_PAGE_INDEX = 4,
+ PRINT_PAGE_INDEX = 5,
};
}
@@ -62,7 +64,7 @@ namespace glabels
///
/// Constructor
///
- MainWindow::MainWindow() : mModel(nullptr)
+ MainWindow::MainWindow() : mModel(nullptr), mUndoRedoModel(nullptr)
{
setWindowIcon( Icons::Glabels() );
@@ -76,6 +78,7 @@ namespace glabels
QWidget* editorPage = createEditorPage();
QWidget* propertiesPage = createPropertiesPage();
QWidget* mergePage = createMergePage();
+ QWidget* variablesPage = createVariablesPage();
QWidget* printPage = createPrintPage();
// Table of contents widget
@@ -141,6 +144,18 @@ namespace glabels
mMergeAction = mContents->addWidget( mMergeButton );
group->addButton( mMergeButton );
+ // Add "Variables" page
+ mPages->addWidget( variablesPage );
+ mVariablesButton = new QToolButton( this );
+ mVariablesButton->setIcon( Icons::Variables() );
+ mVariablesButton->setText( tr("Variables") );
+ mVariablesButton->setToolButtonStyle( Qt::ToolButtonTextUnderIcon );
+ mVariablesButton->setCheckable( true );
+ mVariablesButton->setSizePolicy( QSizePolicy::MinimumExpanding,
+ QSizePolicy::Preferred );
+ mVariablesAction = mContents->addWidget( mVariablesButton );
+ group->addButton( mVariablesButton );
+
// Add "Print" page
mPages->addWidget( printPage );
mPrintButton = new QToolButton( this );
@@ -175,6 +190,7 @@ namespace glabels
connect( mEditorButton, SIGNAL(toggled(bool)), this, SLOT(changePage(bool)));
connect( mPropertiesButton, SIGNAL(toggled(bool)), this, SLOT(changePage(bool)));
connect( mMergeButton, SIGNAL(toggled(bool)), this, SLOT(changePage(bool)));
+ connect( mVariablesButton, SIGNAL(toggled(bool)), this, SLOT(changePage(bool)));
connect( mPrintButton, SIGNAL(toggled(bool)), this, SLOT(changePage(bool)));
connect( mLabelEditor, SIGNAL(zoomChanged()), this, SLOT(onZoomChanged()) );
connect( model::Settings::instance(), SIGNAL(changed()), this, SLOT(onSettingsChanged()) );
@@ -194,7 +210,16 @@ namespace glabels
///
MainWindow::~MainWindow()
{
- // empty
+ if ( mUndoRedoModel )
+ {
+ delete mUndoRedoModel;
+ }
+ if ( mModel )
+ {
+ delete mModel->merge(); // Ownership of final Merge instance is ours
+ delete mModel->variables(); // Ownership of Variables instance is ours
+ delete mModel;
+ }
}
@@ -212,13 +237,14 @@ namespace glabels
///
void MainWindow::setModel( model::Model* model )
{
- mModel = model;
+ mModel = model; // Ownership passes to us
mUndoRedoModel = new UndoRedoModel( mModel );
mPropertiesView->setModel( mModel, mUndoRedoModel );
mLabelEditor->setModel( mModel, mUndoRedoModel );
mObjectEditor->setModel( mModel, mUndoRedoModel );
- mMergeView->setModel( mModel , mUndoRedoModel );
+ mMergeView->setModel( mModel, mUndoRedoModel );
+ mVariablesView->setModel( mModel, mUndoRedoModel );
mPrintView->setModel( mModel );
mEditorButton->setChecked( true );
@@ -315,6 +341,11 @@ namespace glabels
fileShowMergePageAction->setStatusTip( tr("Select project Merge mode") );
connect( fileShowMergePageAction, SIGNAL(triggered()), this, SLOT(fileShowMergePage()) );
+ fileShowVariablesPageAction = new QAction( tr("&Variables") , this );
+ fileShowVariablesPageAction->setShortcut( QKeySequence( Qt::CTRL + Qt::Key_4 ) );
+ fileShowVariablesPageAction->setStatusTip( tr("Select project Variables mode") );
+ connect( fileShowVariablesPageAction, SIGNAL(triggered()), this, SLOT(fileShowVariablesPage()) );
+
fileShowPrintPageAction = new QAction( tr("&Print") , this );
fileShowPrintPageAction->setShortcut( QKeySequence::Print );
fileShowPrintPageAction->setStatusTip( tr("Select project Print mode") );
@@ -603,6 +634,7 @@ namespace glabels
fileMenu->addAction( fileShowEditorPageAction );
fileMenu->addAction( fileShowPropertiesPageAction );
fileMenu->addAction( fileShowMergePageAction );
+ fileMenu->addAction( fileShowVariablesPageAction );
fileMenu->addAction( fileShowPrintPageAction );
fileMenu->addSeparator();
fileMenu->addAction( fileTemplateDesignerAction );
@@ -815,6 +847,17 @@ namespace glabels
}
+ ///
+ /// Create Variables Page
+ ///
+ QWidget* MainWindow::createVariablesPage()
+ {
+ mVariablesView = new VariablesView();
+
+ return mVariablesView;
+ }
+
+
///
/// Create Print Page
///
@@ -839,6 +882,7 @@ namespace glabels
bool isEditorPage = mEditorButton->isChecked();
bool isPropertiesPage = mPropertiesButton->isChecked();
bool isMergePage = mMergeButton->isChecked();
+ bool isVariablesPage = mVariablesButton->isChecked();
bool isPrintPage = mPrintButton->isChecked();
// What is the current selection state?
@@ -851,6 +895,7 @@ namespace glabels
mEditorAction->setVisible( !isWelcomePage );
mPropertiesAction->setVisible( !isWelcomePage );
mMergeAction->setVisible( !isWelcomePage );
+ mVariablesAction->setVisible( !isWelcomePage );
mPrintAction->setVisible( !isWelcomePage );
// Recent file actions
@@ -876,14 +921,45 @@ namespace glabels
fileShowEditorPageAction->setEnabled( !isWelcomePage && !isEditorPage );
fileShowPropertiesPageAction->setEnabled( !isWelcomePage && !isPropertiesPage );
fileShowMergePageAction->setEnabled( !isWelcomePage && !isMergePage );
+ fileShowVariablesPageAction->setEnabled( !isWelcomePage && !isVariablesPage );
fileShowPrintPageAction->setEnabled( !isWelcomePage && !isPrintPage );
fileTemplateDesignerAction->setEnabled( true );
fileCloseAction->setEnabled( true );
fileExitAction->setEnabled( true );
// Edit actions
- editUndoAction->setEnabled( hasModel && mUndoRedoModel->canUndo() );
- editRedoAction->setEnabled( hasModel && mUndoRedoModel->canRedo() );
+ if ( hasModel )
+ {
+ if ( mUndoRedoModel->canUndo() )
+ {
+ editUndoAction->setEnabled( true );
+ /* Translators: %1 is the action description to undo. */
+ editUndoAction->setText( QString( tr("Undo %1") ).arg( mUndoRedoModel->undoDescription() ) );
+ }
+ else
+ {
+ editUndoAction->setEnabled( false );
+ editUndoAction->setText( tr("Undo") );
+ }
+ if ( mUndoRedoModel->canRedo() )
+ {
+ editRedoAction->setEnabled( true );
+ /* Translators: %1 is the action description to redo. */
+ editRedoAction->setText( QString( tr("Redo %1") ).arg( mUndoRedoModel->redoDescription() ) );
+ }
+ else
+ {
+ editRedoAction->setEnabled( false );
+ editRedoAction->setText( tr("Redo") );
+ }
+ }
+ else
+ {
+ editUndoAction->setEnabled( false );
+ editUndoAction->setText( tr("Undo") );
+ editRedoAction->setEnabled( false );
+ editRedoAction->setText( tr("Redo") );
+ }
editCutAction->setEnabled( isEditorPage && hasSelection );
editCopyAction->setEnabled( isEditorPage && hasSelection );
editPasteAction->setEnabled( isEditorPage && canPaste );
@@ -1072,6 +1148,10 @@ namespace glabels
{
mPages->setCurrentIndex( MERGE_PAGE_INDEX );
}
+ else if ( mVariablesButton->isChecked() )
+ {
+ mPages->setCurrentIndex( VARIABLES_PAGE_INDEX );
+ }
else if ( mPrintButton->isChecked() )
{
mPages->setCurrentIndex( PRINT_PAGE_INDEX );
@@ -1168,6 +1248,15 @@ namespace glabels
}
+ ///
+ /// File->Show Variables Page
+ ///
+ void MainWindow::fileShowVariablesPage()
+ {
+ mVariablesButton->setChecked( true );
+ }
+
+
///
/// File->Show Print Page
///
diff --git a/glabels/MainWindow.h b/glabels/MainWindow.h
index dc6a2a2..56e4fab 100644
--- a/glabels/MainWindow.h
+++ b/glabels/MainWindow.h
@@ -47,6 +47,7 @@ namespace glabels
class PropertiesView;
class StartupView;
class UndoRedoModel;
+ class VariablesView;
///
@@ -97,6 +98,7 @@ namespace glabels
void fileShowEditorPage();
void fileShowPropertiesPage();
void fileShowMergePage();
+ void fileShowVariablesPage();
void fileShowPrintPage();
void fileTemplateDesigner();
void fileClose();
@@ -175,6 +177,7 @@ namespace glabels
QWidget* createEditorPage();
QWidget* createPropertiesPage();
QWidget* createMergePage();
+ QWidget* createVariablesPage();
QWidget* createPrintPage();
void manageActions();
@@ -222,12 +225,14 @@ namespace glabels
QToolButton* mEditorButton;
QToolButton* mPropertiesButton;
QToolButton* mMergeButton;
+ QToolButton* mVariablesButton;
QToolButton* mPrintButton;
QAction* mWelcomeAction;
QAction* mEditorAction;
QAction* mPropertiesAction;
QAction* mMergeAction;
+ QAction* mVariablesAction;
QAction* mPrintAction;
QStackedWidget* mPages;
@@ -237,6 +242,7 @@ namespace glabels
ObjectEditor* mObjectEditor;
PropertiesView* mPropertiesView;
MergeView* mMergeView;
+ VariablesView* mVariablesView;
PrintView* mPrintView;
QLabel* zoomInfoLabel;
@@ -249,6 +255,7 @@ namespace glabels
QAction* fileShowEditorPageAction;
QAction* fileShowPropertiesPageAction;
QAction* fileShowMergePageAction;
+ QAction* fileShowVariablesPageAction;
QAction* fileShowPrintPageAction;
QAction* fileTemplateDesignerAction;
QAction* fileCloseAction;
diff --git a/glabels/MergeView.cpp b/glabels/MergeView.cpp
index 0a1eea6..c932324 100644
--- a/glabels/MergeView.cpp
+++ b/glabels/MergeView.cpp
@@ -22,6 +22,8 @@
#include "merge/Factory.h"
+#include "model/FileUtil.h"
+
#include
#include
#include
@@ -63,14 +65,7 @@ namespace glabels
mUndoRedoModel = undoRedoModel;
// Initialize CWD
- if ( model->fileName().isEmpty() )
- {
- mCwd = ".";
- }
- else
- {
- mCwd = QFileInfo( model->fileName() ).absolutePath();
- }
+ mCwd = mModel->dirPath();
onMergeChanged();
connect( mModel, SIGNAL(mergeChanged()), this, SLOT(onMergeChanged()) );
@@ -87,26 +82,22 @@ namespace glabels
mOldFormatComboIndex = index;
formatCombo->setCurrentIndex( index );
+ QString fn;
+
switch ( merge::Factory::idToType( mModel->merge()->id() ) )
{
case merge::Factory::NONE:
case merge::Factory::FIXED:
locationLabel->setEnabled( false );
- locationButton->setEnabled( false );
- locationButton->setText( "" );
+ locationLineEdit->setText( "" );
+ locationBrowseButton->setVisible( false );
break;
case merge::Factory::FILE:
locationLabel->setEnabled( true );
- locationButton->setEnabled( true );
- if ( mModel->merge()->source().isEmpty() )
- {
- locationButton->setText( "Select file..." );
- }
- else
- {
- locationButton->setText( mModel->merge()->source() );
- }
+ fn = model::FileUtil::makeRelativeIfInDir( mModel->dir(), mModel->merge()->source() );
+ locationLineEdit->setText( fn );
+ locationBrowseButton->setVisible( true );
break;
default:
@@ -135,7 +126,8 @@ namespace glabels
///
void MergeView::onMergeSourceChanged()
{
- locationButton->setText( mModel->merge()->source() );
+ QString fn = model::FileUtil::makeRelativeIfInDir( mModel->dir(), mModel->merge()->source() );
+ locationLineEdit->setText( fn );
recordsTable->clear();
recordsTable->setColumnCount( 0 );
@@ -185,7 +177,7 @@ namespace glabels
///
/// Location button clicked handler
///
- void MergeView::onLocationButtonClicked()
+ void MergeView::onLocationBrowseButtonClicked()
{
QString fileName =
QFileDialog::getOpenFileName( this,
diff --git a/glabels/MergeView.h b/glabels/MergeView.h
index 8734994..e0ddead 100644
--- a/glabels/MergeView.h
+++ b/glabels/MergeView.h
@@ -67,7 +67,7 @@ namespace glabels
void onMergeSelectionChanged();
void onFormatComboActivated();
- void onLocationButtonClicked();
+ void onLocationBrowseButtonClicked();
void onSelectAllButtonClicked();
void onUnselectAllButtonClicked();
void onCellChanged( int iRow, int iCol );
diff --git a/glabels/ObjectEditor.cpp b/glabels/ObjectEditor.cpp
index f61e9fe..0ddefde 100644
--- a/glabels/ObjectEditor.cpp
+++ b/glabels/ObjectEditor.cpp
@@ -30,12 +30,14 @@
#include "model/ModelImageObject.h"
#include "model/ModelLineObject.h"
#include "model/ModelTextObject.h"
+#include "model/FileUtil.h"
#include "model/Settings.h"
#include "model/Size.h"
#include "merge/Merge.h"
#include
+#include
#include
#include
@@ -67,9 +69,9 @@ namespace glabels
barcodeColorButton->init( tr("Default"), QColor(0,0,0,255), QColor(0,0,0,255) );
shadowColorButton->init( tr("Default"), QColor(0,0,0,255), QColor(0,0,0,255) );
- textInsertFieldCombo->setName( tr("Insert Field") );
- barcodeInsertFieldCombo->setName( tr("Insert Field") );
- imageFieldCombo->setName( tr("Key") );
+ textInsertFieldButton->setText( tr("Insert substitution field") );
+ barcodeInsertFieldButton->setText( tr("Insert substitution field") );
+ imageFieldButton->setText( tr("Use substitution field") );
setEnabled( false );
hidePages();
@@ -93,11 +95,14 @@ namespace glabels
this, SLOT(onSelectionChanged()) );
connect( mModel, SIGNAL(mergeSourceChanged()),
- this, SLOT(onMergeSourceChanged()) );
+ this, SLOT(onFieldsAvailableChanged()) );
+
+ connect( mModel, SIGNAL(variablesChanged()),
+ this, SLOT(onFieldsAvailableChanged()) );
onLabelSizeChanged();
onSelectionChanged();
- onMergeSourceChanged();
+ onFieldsAvailableChanged();
}
@@ -122,12 +127,12 @@ namespace glabels
if ( filenameNode.isField() )
{
- QString field = QString("${%1}").arg( filenameNode.data() );
- imageFilenameLineEdit->setText( field );
+ imageFilenameLineEdit->setText( QString("${%1}").arg(filenameNode.data()) );
}
else
{
- imageFilenameLineEdit->setText( filenameNode.data() );
+ QString fn = model::FileUtil::makeRelativeIfInDir( mModel->dir(), filenameNode.data() );
+ imageFilenameLineEdit->setText( fn );
}
mBlocked = false;
@@ -188,6 +193,7 @@ namespace glabels
sizeWSpin->setValue( mObject->w().inUnits(mUnits) );
sizeHSpin->setValue( mObject->h().inUnits(mUnits) );
+ sizeAspectCheck->setChecked( mObject->lockAspectRatio() );
model::Size originalSize = mObject->naturalSize();
QString originalSizeString = QString( "%1: %2 x %3 %4" )
@@ -454,8 +460,8 @@ namespace glabels
loadTextPage();
loadPositionPage();
+ loadRectSizePage();
loadShadowPage();
- loadRectSizePage();
setEnabled( true );
}
@@ -473,6 +479,7 @@ namespace glabels
loadBarcodePage();
loadPositionPage();
+ loadRectSizePage();
setEnabled( true );
}
@@ -497,17 +504,19 @@ namespace glabels
}
- void ObjectEditor::onMergeSourceChanged()
+ void ObjectEditor::onFieldsAvailableChanged()
{
if ( !mBlocked )
{
- QStringList keys = mModel->merge()->keys();
- lineColorButton->setKeys( keys );
- fillColorButton->setKeys( keys );
- textInsertFieldCombo->setKeys( keys );
- barcodeInsertFieldCombo->setKeys( keys );
- imageFieldCombo->setKeys( keys );
- shadowColorButton->setKeys( keys );
+ lineColorButton->setKeys( mModel->merge(), mModel->variables() );
+ fillColorButton->setKeys( mModel->merge(), mModel->variables() );
+ textColorButton->setKeys( mModel->merge(), mModel->variables() );
+ barcodeColorButton->setKeys( mModel->merge(), mModel->variables() );
+ shadowColorButton->setKeys( mModel->merge(), mModel->variables() );
+
+ textInsertFieldButton->setKeys( mModel->merge(), mModel->variables() );
+ barcodeInsertFieldButton->setKeys( mModel->merge(), mModel->variables() );
+ imageFieldButton->setKeys( mModel->merge(), mModel->variables() );
}
}
@@ -618,8 +627,11 @@ namespace glabels
void ObjectEditor::onImageKeySelected( QString key )
{
- mUndoRedoModel->checkpoint( tr("Set image") );
- mObject->setFilenameNode( model::TextNode( true, key ) );
+ if ( mObject )
+ {
+ mUndoRedoModel->checkpoint( tr("Set image") );
+ mObject->setFilenameNode( model::TextNode( true, key ) );
+ }
}
@@ -629,7 +641,7 @@ namespace glabels
{
mBlocked = true;
- mUndoRedoModel->checkpoint( tr("Move") );
+ mUndoRedoModel->checkpoint( tr("Position") );
model::Distance x = model::Distance(posXSpin->value(), mUnits);
model::Distance y = model::Distance(posYSpin->value(), mUnits);
@@ -654,6 +666,7 @@ namespace glabels
if ( sizeAspectCheck->isChecked() )
{
+ mObject->setLockAspectRatio( true );
if ( fabs(spinW - mObject->w()) > fabs(spinH - mObject->h()) )
{
mObject->setWHonorAspect( spinW );
@@ -667,6 +680,7 @@ namespace glabels
}
else
{
+ mObject->setLockAspectRatio( false );
mObject->setSize( spinW, spinH );
}
@@ -740,6 +754,8 @@ namespace glabels
{
mBlocked = true;
+ mUndoRedoModel->checkpoint( tr("Barcode") );
+
barcode::Style bcStyle = barcodeStyleButton->bcStyle();
barcodeShowTextCheck->setEnabled( bcStyle.textOptional() );
@@ -774,6 +790,8 @@ namespace glabels
void ObjectEditor::onResetImageSize()
{
+ mUndoRedoModel->checkpoint( tr("Reset") );
+
mObject->setSize( mObject->naturalSize() );
}
diff --git a/glabels/ObjectEditor.h b/glabels/ObjectEditor.h
index 6e84687..57b380f 100644
--- a/glabels/ObjectEditor.h
+++ b/glabels/ObjectEditor.h
@@ -80,7 +80,7 @@ namespace glabels
void onSettingsChanged();
void onLabelSizeChanged();
void onSelectionChanged();
- void onMergeSourceChanged();
+ void onFieldsAvailableChanged();
void onObjectChanged();
void onObjectMoved();
void onObjectDestroyed();
diff --git a/glabels/PrintView.cpp b/glabels/PrintView.cpp
index a900af3..a6f3f7d 100644
--- a/glabels/PrintView.cpp
+++ b/glabels/PrintView.cpp
@@ -70,6 +70,9 @@ namespace glabels
connect( mModel, SIGNAL(changed()), this, SLOT(onModelChanged()) );
+ copiesSpin->setRange( 1, 100*mModel->frame()->nLabels() );
+ copiesStartSpin->setRange( 1, mModel->frame()->nLabels() );
+
onFormChanged();
}
@@ -79,6 +82,9 @@ namespace glabels
///
void PrintView::onModelChanged()
{
+ copiesSpin->setRange( 1, 100*mModel->frame()->nLabels() );
+ copiesStartSpin->setRange( 1, mModel->frame()->nLabels() );
+
updateView();
}
@@ -88,8 +94,6 @@ namespace glabels
///
void PrintView::updateView()
{
- copiesStartSpin->setRange( 1, mModel->frame()->nLabels() );
-
if ( mRenderer.nPages() == 1 )
{
if ( mRenderer.nItems() == 1 )
diff --git a/glabels/VariablesView.cpp b/glabels/VariablesView.cpp
new file mode 100644
index 0000000..ea13f33
--- /dev/null
+++ b/glabels/VariablesView.cpp
@@ -0,0 +1,254 @@
+/* VariablesView.cpp
+ *
+ * Copyright (C) 2016 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 "VariablesView.h"
+
+#include "EditVariableDialog.h"
+
+#include
+#include
+
+
+namespace
+{
+ enum ICol {
+ I_COL_NAME,
+ I_COL_TYPE,
+ I_COL_VALUE,
+ I_COL_INCREMENT,
+ I_COL_STEP_SIZE,
+ I_COL_DUMMY,
+ N_COLS
+ };
+}
+
+
+namespace glabels
+{
+
+ ///
+ /// Constructor
+ ///
+ VariablesView::VariablesView( QWidget *parent )
+ : QWidget(parent), mModel(nullptr), mUndoRedoModel(nullptr)
+ {
+ setupUi( this );
+
+ titleLabel->setText( QString( "%1" ).arg( tr("Variables") ) );
+
+ table->setColumnCount( N_COLS );
+
+ auto* nameHeaderItem = new QTableWidgetItem( tr("Name") );
+ nameHeaderItem->setFlags( nameHeaderItem->flags() ^ Qt::ItemIsEditable );
+ table->setHorizontalHeaderItem( I_COL_NAME, nameHeaderItem );
+
+ auto* typeHeaderItem = new QTableWidgetItem( tr("Type") );
+ typeHeaderItem->setFlags( typeHeaderItem->flags() ^ Qt::ItemIsEditable );
+ table->setHorizontalHeaderItem( I_COL_TYPE, typeHeaderItem );
+
+ auto* valueHeaderItem = new QTableWidgetItem( tr("Value") );
+ valueHeaderItem->setFlags( valueHeaderItem->flags() ^ Qt::ItemIsEditable );
+ table->setHorizontalHeaderItem( I_COL_VALUE, valueHeaderItem );
+
+ auto* incrementHeaderItem = new QTableWidgetItem( tr("Increment") );
+ incrementHeaderItem->setFlags( incrementHeaderItem->flags() ^ Qt::ItemIsEditable );
+ table->setHorizontalHeaderItem( I_COL_INCREMENT, incrementHeaderItem );
+
+ auto* stepSizeHeaderItem = new QTableWidgetItem( tr("Step Size") );
+ stepSizeHeaderItem->setFlags( stepSizeHeaderItem->flags() ^ Qt::ItemIsEditable );
+ table->setHorizontalHeaderItem( I_COL_STEP_SIZE, stepSizeHeaderItem );
+
+ auto* dummyHeaderItem = new QTableWidgetItem();
+ dummyHeaderItem->setFlags( Qt::NoItemFlags );
+ table->setHorizontalHeaderItem( I_COL_DUMMY, dummyHeaderItem );
+ table->horizontalHeader()->setStretchLastSection( true );
+ }
+
+
+ ///
+ /// Destructor
+ ///
+ VariablesView::~VariablesView()
+ {
+ // empty
+ }
+
+
+ ///
+ /// Set Model
+ ///
+ void VariablesView::setModel( model::Model* model, UndoRedoModel* undoRedoModel )
+ {
+ mModel = model;
+ mUndoRedoModel = undoRedoModel;
+
+ updateControls();
+ loadTable();
+
+ connect( mModel, SIGNAL(variablesChanged()), this, SLOT(onVariablesChanged()) );
+ }
+
+
+ ///
+ /// table Selection Changed
+ ///
+ void VariablesView::onTableSelectionChanged()
+ {
+ updateControls();
+ }
+
+
+ ///
+ /// addButton Clicked
+ ///
+ void VariablesView::onAddButtonClicked()
+ {
+ EditVariableDialog dialog( this );
+
+ model::Variable v( model::Variable::Type::INTEGER,
+ "x",
+ "0",
+ model::Variable::Increment::NEVER,
+ "1" );
+ dialog.setVariable( v );
+ dialog.setWindowTitle( tr("Add Variable") );
+
+ if ( dialog.exec() == QDialog::Accepted )
+ {
+ mModel->variables()->addVariable( dialog.variable() );
+ selectVariable( dialog.variable().name() );
+ }
+ }
+
+
+ ///
+ /// editButton Clicked
+ ///
+ void VariablesView::onEditButtonClicked()
+ {
+ int iRow = table->selectedItems()[0]->row();
+ QString name = table->item( iRow, I_COL_NAME )->text();
+
+ if ( mModel->variables()->hasVariable( name ) )
+ {
+ model::Variable v = mModel->variables()->value( name );
+
+ EditVariableDialog dialog( this );
+ dialog.setVariable( v );
+ dialog.setWindowTitle( tr("Edit Variable") );
+
+ if ( dialog.exec() == QDialog::Accepted )
+ {
+ mModel->variables()->replaceVariable( name, dialog.variable() );
+ selectVariable( dialog.variable().name() );
+ }
+ }
+ }
+
+
+ ///
+ /// deleteButton Clicked
+ ///
+ void VariablesView::onDeleteButtonClicked()
+ {
+ int iRow = table->selectedItems()[0]->row();
+
+ QString name = table->item( iRow, I_COL_NAME )->text();
+ mModel->variables()->deleteVariable( name );
+ }
+
+
+ ///
+ /// Variables Changed
+ ///
+ void VariablesView::onVariablesChanged()
+ {
+ // Reload table from variables
+ loadTable();
+ }
+
+
+ ///
+ /// update controls
+ ///
+ void VariablesView::updateControls()
+ {
+ bool hasSelection = !table->selectedItems().isEmpty();
+
+ editButton->setEnabled( hasSelection );
+ deleteButton->setEnabled( hasSelection );
+ }
+
+
+ ///
+ /// load table from variables
+ ///
+ void VariablesView::loadTable()
+ {
+ table->clearContents();
+ table->setRowCount( mModel->variables()->size() );
+
+ int iRow = 0;
+ for( const auto& v : *mModel->variables() )
+ {
+ auto* typeItem = new QTableWidgetItem( model::Variable::typeToI18nString(v.type()) );
+ typeItem->setFlags( typeItem->flags() ^ Qt::ItemIsEditable );
+ table->setItem( iRow, I_COL_TYPE, typeItem );
+
+ auto* nameItem = new QTableWidgetItem( v.name() );
+ nameItem->setFlags( nameItem->flags() ^ Qt::ItemIsEditable );
+ table->setItem( iRow, I_COL_NAME, nameItem );
+
+ auto* valueItem = new QTableWidgetItem( v.initialValue() );
+ valueItem->setFlags( valueItem->flags() ^ Qt::ItemIsEditable );
+ table->setItem( iRow, I_COL_VALUE, valueItem );
+
+ auto* incrementItem = new QTableWidgetItem( model::Variable::incrementToI18nString(v.increment()) );
+ incrementItem->setFlags( incrementItem->flags() ^ Qt::ItemIsEditable );
+ table->setItem( iRow, I_COL_INCREMENT, incrementItem );
+
+ auto* stepSizeItem = new QTableWidgetItem( v.stepSize() );
+ stepSizeItem->setFlags( stepSizeItem->flags() ^ Qt::ItemIsEditable );
+ table->setItem( iRow, I_COL_STEP_SIZE, stepSizeItem );
+
+ table->showRow( iRow );
+ iRow++;
+ }
+ }
+
+
+ void VariablesView::selectVariable( const QString& name )
+ {
+ int iRow = 0;
+ for( const auto& v : *mModel->variables() )
+ {
+ if ( v.name() == name )
+ {
+ table->setCurrentCell( iRow, 0,
+ (QItemSelectionModel::Select|QItemSelectionModel::Rows) );
+ break;
+ }
+
+ iRow++;
+ }
+ }
+
+
+} // namespace glabels
diff --git a/glabels/VariablesView.h b/glabels/VariablesView.h
new file mode 100644
index 0000000..93dca3d
--- /dev/null
+++ b/glabels/VariablesView.h
@@ -0,0 +1,91 @@
+/* VariablesView.h
+ *
+ * Copyright (C) 2016 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 VariablesView_h
+#define VariablesView_h
+
+
+#include "ui_VariablesView.h"
+
+#include "model/Model.h"
+
+
+namespace glabels
+{
+
+ // Forward references
+ class UndoRedoModel;
+
+
+ ///
+ /// Variables Property Editor Widget
+ ///
+ class VariablesView : public QWidget, public Ui_VariablesView
+ {
+ Q_OBJECT
+
+
+ /////////////////////////////////
+ // Life Cycle
+ /////////////////////////////////
+ public:
+ VariablesView( QWidget *parent = nullptr );
+ ~VariablesView() override;
+
+
+ /////////////////////////////////
+ // Public methods
+ /////////////////////////////////
+ void setModel( model::Model* model, UndoRedoModel* undoRedoModel );
+
+
+ /////////////////////////////////
+ // Slots
+ /////////////////////////////////
+ private slots:
+ void onTableSelectionChanged();
+ void onAddButtonClicked();
+ void onEditButtonClicked();
+ void onDeleteButtonClicked();
+ void onVariablesChanged();
+
+
+ /////////////////////////////////
+ // Private methods
+ /////////////////////////////////
+ private:
+ void updateControls();
+ void loadTable();
+ void selectVariable( const QString& name );
+
+
+ /////////////////////////////////
+ // Private Data
+ /////////////////////////////////
+ private:
+ model::Model* mModel;
+ UndoRedoModel* mUndoRedoModel;
+
+ };
+
+}
+
+
+#endif // VariablesView_h
diff --git a/glabels/icons.qrc b/glabels/icons.qrc
index 8d4f777..faa0f30 100644
--- a/glabels/icons.qrc
+++ b/glabels/icons.qrc
@@ -102,6 +102,7 @@
icons/flat/48x48/glabels-merge.svg
icons/flat/48x48/glabels-print.svg
icons/flat/48x48/glabels-properties.svg
+ icons/flat/48x48/glabels-variables.svg
icons/apps/48x48/glabels.svg
icons/apps/128x128/glabels.svg
diff --git a/glabels/icons/flat/48x48/glabels-variables.svg b/glabels/icons/flat/48x48/glabels-variables.svg
new file mode 100644
index 0000000..9b47813
--- /dev/null
+++ b/glabels/icons/flat/48x48/glabels-variables.svg
@@ -0,0 +1,15 @@
+
diff --git a/glabels/images/checkerboard.png b/glabels/images/checkerboard.png
index c97f40e..575edc3 100644
Binary files a/glabels/images/checkerboard.png and b/glabels/images/checkerboard.png differ
diff --git a/glabels/main.cpp b/glabels/main.cpp
index 1acdf1c..67b9c7c 100644
--- a/glabels/main.cpp
+++ b/glabels/main.cpp
@@ -45,7 +45,7 @@ int main( int argc, char **argv )
QCoreApplication::setOrganizationName( "glabels.org" );
QCoreApplication::setOrganizationDomain( "glabels.org" );
QCoreApplication::setApplicationName( "glabels-qt" );
- QCoreApplication::setApplicationVersion( glabels::model::Version::STRING );
+ QCoreApplication::setApplicationVersion( glabels::model::Version::LONG_STRING );
//
// Setup translators
diff --git a/glabels/ui/EditVariableDialog.ui b/glabels/ui/EditVariableDialog.ui
new file mode 100644
index 0000000..72f8575
--- /dev/null
+++ b/glabels/ui/EditVariableDialog.ui
@@ -0,0 +1,274 @@
+
+
+ EditVariableDialog
+
+
+
+ 0
+ 0
+ 469
+ 297
+
+
+
+ Dialog
+
+
+
+ 12
+
+ -
+
+
+ Increment
+
+
+
-
+
+
-
+
+
+ -
+
+
+ Step size:
+
+
+
+ -
+
+
+
+
+
+
+
+ -
+
+
+ Qt::Vertical
+
+
+
+ 20
+ 40
+
+
+
+
+ -
+
+
+ Variable
+
+
+
-
+
+
-
+
+
+ -
+
+
+ Value:
+
+
+
+ -
+
+
+ Name:
+
+
+
+ -
+
+
+ -
+
+
+ Type:
+
+
+
+ -
+
+
-
+
+
+ -
+
+
+
+
+
+
+
+
+
+
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+ QDialogButtonBox::Cancel|QDialogButtonBox::Ok
+
+
+
+
+
+
+
+ glabels::ColorButton
+ QPushButton
+
+
+ colorChanged()
+
+
+
+
+
+
+ buttonBox
+ accepted()
+ EditVariableDialog
+ accept()
+
+
+ 236
+ 287
+
+
+ 157
+ 236
+
+
+
+
+ buttonBox
+ rejected()
+ EditVariableDialog
+ reject()
+
+
+ 304
+ 287
+
+
+ 286
+ 236
+
+
+
+
+ typeCombo
+ currentIndexChanged(int)
+ EditVariableDialog
+ onTypeComboChanged()
+
+
+ 252
+ 70
+
+
+ 33
+ 161
+
+
+
+
+ incrementCombo
+ currentIndexChanged(int)
+ EditVariableDialog
+ onIncrementComboChanged()
+
+
+ 100
+ 223
+
+
+ 97
+ 176
+
+
+
+
+ stepSizeEdit
+ textChanged(QString)
+ EditVariableDialog
+ onStepSizeEditChanged()
+
+
+ 440
+ 223
+
+
+ 333
+ 166
+
+
+
+
+ nameEdit
+ textChanged(QString)
+ EditVariableDialog
+ onNameEditChanged()
+
+
+ 440
+ 103
+
+
+ 393
+ 165
+
+
+
+
+ valueEdit
+ textChanged(QString)
+ EditVariableDialog
+ onValueEditChanged()
+
+
+ 318
+ 129
+
+
+ 459
+ 157
+
+
+
+
+ colorValueButton
+ colorChanged()
+ EditVariableDialog
+ onColorValueButtonChanged()
+
+
+ 406
+ 114
+
+
+ 458
+ 122
+
+
+
+
+
+ onTypeComboChanged()
+ onValueEditChanged()
+ onIncrementComboChanged()
+ onStepSizeEditChanged()
+ onNameEditChanged()
+ onColorValueButtonChanged()
+
+
diff --git a/glabels/ui/MergeView.ui b/glabels/ui/MergeView.ui
index e73b77a..c7f682a 100644
--- a/glabels/ui/MergeView.ui
+++ b/glabels/ui/MergeView.ui
@@ -11,12 +11,21 @@
- Form
+ Form
-
-
+
+ 12
+
+
+ 12
+
+
+ 12
+
+
12
-
@@ -37,16 +46,9 @@
Source
-
-
-
+
+
-
-
-
-
-
- Location
-
-
-
-
@@ -54,6 +56,27 @@
+ -
+
+
+ -
+
+
-
+
+
+ true
+
+
+
+ -
+
+
+ Browse...
+
+
+
+
+
-
@@ -61,24 +84,8 @@
- -
-
-
- -
-
-
- Qt::Horizontal
-
-
-
- 360
- 20
-
-
-
-
@@ -89,7 +96,11 @@
-
-
+
+
+ Qt::NoFocus
+
+
-
@@ -138,8 +149,8 @@
onSelectAllButtonClicked()
- 63
- 571
+ 97
+ 570
69
@@ -163,22 +174,6 @@
-
- locationButton
- clicked()
- MergeView
- onLocationButtonClicked()
-
-
- 174
- 93
-
-
- 570
- 75
-
-
-
formatCombo
activated(int)
@@ -186,8 +181,8 @@
onFormatComboActivated()
- 162
- 48
+ 257
+ 109
563
@@ -195,11 +190,27 @@
+
+ locationBrowseButton
+ clicked()
+ MergeView
+ onLocationBrowseButtonClicked()
+
+
+ 296
+ 130
+
+
+ 565
+ 149
+
+
+
onSelectAllButtonClicked()
onUnselectAllButtonClicked()
- onLocationButtonClicked()
onFormatComboActivated()
+ onLocationBrowseButtonClicked()
diff --git a/glabels/ui/ObjectEditor.ui b/glabels/ui/ObjectEditor.ui
index 3e0589e..29ca098 100644
--- a/glabels/ui/ObjectEditor.ui
+++ b/glabels/ui/ObjectEditor.ui
@@ -7,7 +7,7 @@
0
0
400
- 640
+ 648
@@ -29,9 +29,9 @@
- Form
+ Form
-
+
-
-
@@ -579,7 +579,11 @@
-
-
+
+
+ Insert field
+
+
-
@@ -729,7 +733,11 @@
-
-
+
+
+ Insert field
+
+
-
@@ -758,14 +766,27 @@
Image
-
-
+
-
+
+
+ Qt::Vertical
+
+
+
+ 20
+ 646
+
+
+
+
+ -
File
-
+
-
-
+
-
@@ -789,68 +810,47 @@
-
-
-
-
-
-
-
- 0
- 0
-
-
-
- Select File...
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
- or
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
-
-
- Select Merge Field...
-
-
-
-
-
+
+
+
+ 0
+ 0
+
+
+
+ Browse...
+
+
+
+
+
+ -
+
+
-
+
+
+ Qt::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
+ -
+
+
+ Use field
+
+
- -
-
-
- Qt::Vertical
-
-
-
- 20
- 646
-
-
-
-
@@ -1202,16 +1202,7 @@
15
-
- 0
-
-
- 0
-
-
- 0
-
-
+
0
-
@@ -1529,14 +1520,6 @@
colorChanged()
-
- glabels::FieldButton
- QComboBox
-
-
- keySelected(QString)
-
-
glabels::BarcodeMenuButton
QPushButton
@@ -1545,6 +1528,14 @@
selectionChanged()
+
+ glabels::FieldButton
+ QPushButton
+
+
+ keySelected(QString)
+
+
@@ -1653,8 +1644,8 @@
onTextControlsChanged()
- 157
- 333
+ 160
+ 332
396
@@ -1669,8 +1660,8 @@
onTextControlsChanged()
- 198
- 333
+ 200
+ 332
398
@@ -1685,8 +1676,8 @@
onTextControlsChanged()
- 238
- 333
+ 240
+ 332
395
@@ -1701,8 +1692,8 @@
onTextControlsChanged()
- 284
- 333
+ 286
+ 332
393
@@ -1717,8 +1708,8 @@
onTextControlsChanged()
- 325
- 333
+ 326
+ 332
396
@@ -1734,7 +1725,7 @@
365
- 333
+ 332
397
@@ -1749,8 +1740,8 @@
onTextControlsChanged()
- 184
- 407
+ 189
+ 404
394
@@ -1766,7 +1757,7 @@
178
- 143
+ 139
392
@@ -1781,8 +1772,8 @@
onLineControlsChanged()
- 137
- 179
+ 136
+ 174
1
@@ -1797,8 +1788,8 @@
onFillControlsChanged()
- 136
- 263
+ 135
+ 256
6
@@ -1813,8 +1804,8 @@
onPositionControlsChanged()
- 159
- 142
+ 160
+ 138
399
@@ -1829,8 +1820,8 @@
onPositionControlsChanged()
- 159
- 179
+ 160
+ 174
325
@@ -1845,8 +1836,8 @@
onRectSizeControlsChanged()
- 159
- 265
+ 160
+ 258
3
@@ -1861,8 +1852,8 @@
onRectSizeControlsChanged()
- 159
- 302
+ 160
+ 294
0
@@ -1877,8 +1868,8 @@
onResetImageSize()
- 210
- 372
+ 213
+ 362
4
@@ -1909,8 +1900,8 @@
onShadowControlsChanged()
- 165
- 142
+ 166
+ 138
398
@@ -1925,8 +1916,8 @@
onShadowControlsChanged()
- 165
- 179
+ 166
+ 174
294
@@ -1941,8 +1932,8 @@
onShadowControlsChanged()
- 142
- 215
+ 141
+ 209
399
@@ -1957,8 +1948,8 @@
onShadowControlsChanged()
- 159
- 252
+ 162
+ 245
399
@@ -1973,8 +1964,8 @@
onLineSizeControlsChanged()
- 174
- 456
+ 177
+ 444
5
@@ -1989,8 +1980,8 @@
onLineSizeControlsChanged()
- 174
- 493
+ 177
+ 480
1
@@ -1999,14 +1990,14 @@
- imageFileButton
+ imageBrowseButton
clicked()
ObjectEditor
onImageFileButtonClicked()
- 133
- 175
+ 367
+ 135
394
@@ -2014,22 +2005,6 @@
-
- imageFieldCombo
- keySelected(QString)
- ObjectEditor
- onImageKeySelected(QString)
-
-
- 302
- 175
-
-
- 397
- 32
-
-
-
textEdit
textChanged()
@@ -2046,22 +2021,6 @@
-
- textInsertFieldCombo
- keySelected(QString)
- ObjectEditor
- onTextInsertFieldKeySelected(QString)
-
-
- 239
- 599
-
-
- 395
- 645
-
-
-
barcodeShowTextCheck
toggled(bool)
@@ -2069,8 +2028,8 @@
onBarcodeControlsChanged()
- 178
- 172
+ 195
+ 167
4
@@ -2085,8 +2044,8 @@
onBarcodeControlsChanged()
- 164
- 204
+ 195
+ 198
1
@@ -2102,7 +2061,7 @@
126
- 239
+ 232
1
@@ -2126,22 +2085,6 @@
-
- barcodeInsertFieldCombo
- keySelected(QString)
- ObjectEditor
- onBarcodeInsertFieldKeySelected(QString)
-
-
- 239
- 400
-
-
- 403
- 625
-
-
-
barcodeStyleButton
selectionChanged()
@@ -2149,8 +2092,8 @@
onBarcodeControlsChanged()
- 178
- 140
+ 195
+ 136
5
@@ -2190,6 +2133,70 @@
+
+ sizeAspectCheck
+ toggled(bool)
+ ObjectEditor
+ onRectSizeControlsChanged()
+
+
+ 231
+ 289
+
+
+ 199
+ 319
+
+
+
+
+ textInsertFieldButton
+ keySelected(QString)
+ ObjectEditor
+ onTextInsertFieldKeySelected(QString)
+
+
+ 191
+ 589
+
+
+ 227
+ 642
+
+
+
+
+ barcodeInsertFieldButton
+ keySelected(QString)
+ ObjectEditor
+ onBarcodeInsertFieldKeySelected(QString)
+
+
+ 208
+ 379
+
+
+ 205
+ 649
+
+
+
+
+ imageFieldButton
+ keySelected(QString)
+ ObjectEditor
+ onImageKeySelected(QString)
+
+
+ 317
+ 160
+
+
+ 331
+ -12
+
+
+
onChanged()
@@ -2206,5 +2213,6 @@
onTextInsertFieldKeySelected(QString)
onBarcodeControlsChanged()
onBarcodeInsertFieldKeySelected(QString)
+ onImageComboChanged()
diff --git a/glabels/ui/PrintView.ui b/glabels/ui/PrintView.ui
index d4ea498..348bada 100644
--- a/glabels/ui/PrintView.ui
+++ b/glabels/ui/PrintView.ui
@@ -6,7 +6,7 @@
0
0
- 759
+ 852
792
@@ -17,7 +17,7 @@
- Form
+ Form
-
@@ -73,21 +73,8 @@
Copies
-
-
-
-
-
-
- 0
- 0
-
-
-
- (Will print a total of xx items on nn pages.)
-
-
-
- -
+
+
-
-
@@ -104,11 +91,17 @@
-
+
+ QAbstractSpinBox::UpDownArrows
+
+
+ true
+
1
- 96
+ 9999
@@ -127,7 +120,7 @@
- -
+
-
-
@@ -183,6 +176,29 @@
+ -
+
+
-
+
+
+
+ 0
+ 0
+
+
+
+
+ 330
+ 0
+
+
+
+ (Will print a total of xxxx items on nnn pages.)
+
+
+
+
+
diff --git a/glabels/ui/PropertiesView.ui b/glabels/ui/PropertiesView.ui
index 60c0632..6481733 100644
--- a/glabels/ui/PropertiesView.ui
+++ b/glabels/ui/PropertiesView.ui
@@ -23,7 +23,7 @@
- Form
+ Form
-
@@ -241,6 +241,12 @@
-
+
+
+ 330
+ 0
+
+
<html><head/><body><p>Select another product for this gLabels project.</p></body></html>
diff --git a/glabels/ui/StartupView.ui b/glabels/ui/StartupView.ui
index 246e5c0..0aca3cb 100644
--- a/glabels/ui/StartupView.ui
+++ b/glabels/ui/StartupView.ui
@@ -11,7 +11,7 @@
- Form
+ Form
-
diff --git a/glabels/ui/TemplateDesignerApplyPage.ui b/glabels/ui/TemplateDesignerApplyPage.ui
index d0ed63b..3b1b913 100644
--- a/glabels/ui/TemplateDesignerApplyPage.ui
+++ b/glabels/ui/TemplateDesignerApplyPage.ui
@@ -23,7 +23,7 @@
- Form
+ Form
diff --git a/glabels/ui/TemplateDesignerCdPage.ui b/glabels/ui/TemplateDesignerCdPage.ui
index f61fa31..a9add20 100644
--- a/glabels/ui/TemplateDesignerCdPage.ui
+++ b/glabels/ui/TemplateDesignerCdPage.ui
@@ -23,7 +23,7 @@
- Form
+ Form
-
diff --git a/glabels/ui/TemplateDesignerContinuousPage.ui b/glabels/ui/TemplateDesignerContinuousPage.ui
index 8960aa6..d3cc112 100644
--- a/glabels/ui/TemplateDesignerContinuousPage.ui
+++ b/glabels/ui/TemplateDesignerContinuousPage.ui
@@ -23,7 +23,7 @@
- Form
+ Form
diff --git a/glabels/ui/TemplateDesignerEllipsePage.ui b/glabels/ui/TemplateDesignerEllipsePage.ui
index 53dec92..0ea9ee5 100644
--- a/glabels/ui/TemplateDesignerEllipsePage.ui
+++ b/glabels/ui/TemplateDesignerEllipsePage.ui
@@ -23,7 +23,7 @@
- Form
+ Form
-
diff --git a/glabels/ui/TemplateDesignerIntroPage.ui b/glabels/ui/TemplateDesignerIntroPage.ui
index 90665ff..9b397cb 100644
--- a/glabels/ui/TemplateDesignerIntroPage.ui
+++ b/glabels/ui/TemplateDesignerIntroPage.ui
@@ -23,7 +23,7 @@
- Form
+ Form
diff --git a/glabels/ui/TemplateDesignerNLayoutsPage.ui b/glabels/ui/TemplateDesignerNLayoutsPage.ui
index df42ffd..e88dd2f 100644
--- a/glabels/ui/TemplateDesignerNLayoutsPage.ui
+++ b/glabels/ui/TemplateDesignerNLayoutsPage.ui
@@ -23,7 +23,7 @@
- Form
+ Form
diff --git a/glabels/ui/TemplateDesignerNamePage.ui b/glabels/ui/TemplateDesignerNamePage.ui
index 9bf0d13..a9ed4d7 100644
--- a/glabels/ui/TemplateDesignerNamePage.ui
+++ b/glabels/ui/TemplateDesignerNamePage.ui
@@ -23,7 +23,7 @@
- Form
+ Form
diff --git a/glabels/ui/TemplateDesignerOneLayoutPage.ui b/glabels/ui/TemplateDesignerOneLayoutPage.ui
index 508cfd4..315266d 100644
--- a/glabels/ui/TemplateDesignerOneLayoutPage.ui
+++ b/glabels/ui/TemplateDesignerOneLayoutPage.ui
@@ -23,7 +23,7 @@
- Form
+ Form
-
diff --git a/glabels/ui/TemplateDesignerPageSizePage.ui b/glabels/ui/TemplateDesignerPageSizePage.ui
index 38c631f..41686e7 100644
--- a/glabels/ui/TemplateDesignerPageSizePage.ui
+++ b/glabels/ui/TemplateDesignerPageSizePage.ui
@@ -23,7 +23,7 @@
- Form
+ Form
-
diff --git a/glabels/ui/TemplateDesignerPathPage.ui b/glabels/ui/TemplateDesignerPathPage.ui
index 2f78452..3b59a4c 100644
--- a/glabels/ui/TemplateDesignerPathPage.ui
+++ b/glabels/ui/TemplateDesignerPathPage.ui
@@ -23,7 +23,7 @@
- Form
+ Form
diff --git a/glabels/ui/TemplateDesignerRectPage.ui b/glabels/ui/TemplateDesignerRectPage.ui
index 7265e8f..a4a4758 100644
--- a/glabels/ui/TemplateDesignerRectPage.ui
+++ b/glabels/ui/TemplateDesignerRectPage.ui
@@ -23,7 +23,7 @@
- Form
+ Form
-
diff --git a/glabels/ui/TemplateDesignerRoundPage.ui b/glabels/ui/TemplateDesignerRoundPage.ui
index c51aa03..2a6651d 100644
--- a/glabels/ui/TemplateDesignerRoundPage.ui
+++ b/glabels/ui/TemplateDesignerRoundPage.ui
@@ -23,7 +23,7 @@
- Form
+ Form
-
diff --git a/glabels/ui/TemplateDesignerShapePage.ui b/glabels/ui/TemplateDesignerShapePage.ui
index 0466fbb..a471d6c 100644
--- a/glabels/ui/TemplateDesignerShapePage.ui
+++ b/glabels/ui/TemplateDesignerShapePage.ui
@@ -23,7 +23,7 @@
- Form
+ Form
-
diff --git a/glabels/ui/TemplateDesignerTwoLayoutPage.ui b/glabels/ui/TemplateDesignerTwoLayoutPage.ui
index d7cc9dc..e3cc62a 100644
--- a/glabels/ui/TemplateDesignerTwoLayoutPage.ui
+++ b/glabels/ui/TemplateDesignerTwoLayoutPage.ui
@@ -23,7 +23,7 @@
- Form
+ Form
-
diff --git a/glabels/ui/VariablesView.ui b/glabels/ui/VariablesView.ui
new file mode 100644
index 0000000..c0953d6
--- /dev/null
+++ b/glabels/ui/VariablesView.ui
@@ -0,0 +1,190 @@
+
+
+ VariablesView
+
+
+
+ 0
+ 0
+ 1105
+ 605
+
+
+
+ Form
+
+
+
+ 21
+
+
+ 21
+
+
+ 21
+
+
+ 21
+
+
-
+
+
+
+ 0
+ 0
+
+
+
+ <html><head/><body><p><span style=" font-size:18pt;">Variables</span></p></body></html>
+
+
+
+ -
+
+
+ Qt::NoFocus
+
+
+ QAbstractItemView::SingleSelection
+
+
+ QAbstractItemView::SelectRows
+
+
+ 0
+
+
+ false
+
+
+ true
+
+
+
+ -
+
+
-
+
+
+ <html><head/><body><p>Add variable</p></body></html>
+
+
+ Add
+
+
+
+ -
+
+
+ <html><head/><body><p>Edit selected variable</p></body></html>
+
+
+ Edit
+
+
+
+ -
+
+
+ <html><head/><body><p>Delete selected variable</p></body></html>
+
+
+ Delete
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
+
+
+
+
+
+
+
+ addButton
+ clicked()
+ VariablesView
+ onAddButtonClicked()
+
+
+ 63
+ 586
+
+
+ 98
+ 598
+
+
+
+
+ editButton
+ clicked()
+ VariablesView
+ onEditButtonClicked()
+
+
+ 167
+ 576
+
+
+ 317
+ 608
+
+
+
+
+ deleteButton
+ clicked()
+ VariablesView
+ onDeleteButtonClicked()
+
+
+ 245
+ 575
+
+
+ 508
+ 613
+
+
+
+
+ table
+ itemSelectionChanged()
+ VariablesView
+ onTableSelectionChanged()
+
+
+ 380
+ 258
+
+
+ 787
+ 610
+
+
+
+
+
+ onSelectAllButtonClicked()
+ onUnselectAllButtonClicked()
+ onLocationButtonClicked()
+ onFormatComboActivated()
+ onAddButtonClicked()
+ onEditButtonClicked()
+ onDeleteButtonClicked()
+ onTableSelectionChanged()
+
+
diff --git a/model/CMakeLists.txt b/model/CMakeLists.txt
index 0edacf8..1690772 100644
--- a/model/CMakeLists.txt
+++ b/model/CMakeLists.txt
@@ -56,6 +56,8 @@ set (Model_sources
Template.cpp
TextNode.cpp
Units.cpp
+ Variable.cpp
+ Variables.cpp
Vendor.cpp
XmlCategoryParser.cpp
XmlLabelCreator.cpp
@@ -80,6 +82,7 @@ set (Model_qobject_headers
ModelTextObject.h
PageRenderer.h
Settings.h
+ Variables.h
)
qt5_wrap_cpp (Model_moc_sources ${Model_qobject_headers})
diff --git a/model/ColorNode.cpp b/model/ColorNode.cpp
index f399a1a..ceee003 100644
--- a/model/ColorNode.cpp
+++ b/model/ColorNode.cpp
@@ -175,30 +175,32 @@ namespace glabels
///
/// Get color, expand if necessary
///
- QColor ColorNode::color( merge::Record* record ) const
+ QColor ColorNode::color( const merge::Record* record,
+ const Variables* variables ) const
{
- if ( mIsField )
+ QColor value = QColor( 192, 192, 192, 128 );
+
+ bool haveRecordField = mIsField && record &&
+ record->contains(mKey) &&
+ !record->value(mKey).isEmpty();
+ bool haveVariable = mIsField && variables &&
+ variables->contains(mKey) &&
+ !(*variables)[mKey].value().isEmpty();
+
+ if ( haveRecordField )
{
- if ( record == nullptr )
- {
- return mColor;
- }
- else
- {
- if ( record->contains( mKey ) )
- {
- return QColor( (*record)[ mKey ] );
- }
- else
- {
- return mColor;
- }
- }
+ value = QColor( record->value(mKey) );
}
- else
+ else if ( haveVariable )
{
- return mColor;
+ value = QColor( (*variables)[mKey].value() );
}
+ else if ( !mIsField )
+ {
+ value = mColor;
+ }
+
+ return value;
}
}
diff --git a/model/ColorNode.h b/model/ColorNode.h
index 89b0201..dab30af 100644
--- a/model/ColorNode.h
+++ b/model/ColorNode.h
@@ -22,6 +22,7 @@
#define model_ColorNode_h
+#include "Variables.h"
#include "merge/Record.h"
#include
@@ -95,7 +96,8 @@ namespace glabels
/////////////////////////////////
public:
uint32_t rgba() const;
- QColor color( merge::Record* record ) const;
+ QColor color( const merge::Record* record,
+ const Variables* variables ) const;
/////////////////////////////////
diff --git a/model/FileUtil.cpp b/model/FileUtil.cpp
index 09e61d2..a3e2bcb 100644
--- a/model/FileUtil.cpp
+++ b/model/FileUtil.cpp
@@ -108,5 +108,17 @@ namespace glabels
return QDir("/");
}
+
+ QString FileUtil::makeRelativeIfInDir( const QDir& dir,
+ const QString& filename )
+ {
+ QString relativeFilePath = dir.relativeFilePath( filename ); // Note: directory separators canonicalized to slash by Qt path methods
+ if ( !relativeFilePath.startsWith( "../" ) )
+ {
+ return relativeFilePath;
+ }
+ return filename;
+ }
+
}
}
diff --git a/model/FileUtil.h b/model/FileUtil.h
index ed76de0..0cac0db 100644
--- a/model/FileUtil.h
+++ b/model/FileUtil.h
@@ -41,6 +41,9 @@ namespace glabels
QDir userTemplatesDir();
QDir translationsDir();
+
+ QString makeRelativeIfInDir( const QDir& dir,
+ const QString& filename );
}
}
diff --git a/model/Model.cpp b/model/Model.cpp
index b0eb83d..4bcf47f 100644
--- a/model/Model.cpp
+++ b/model/Model.cpp
@@ -57,7 +57,18 @@ namespace glabels
Model::Model()
: mUntitledInstance(0), mModified(true), mRotate(false)
{
+ mVariables = new Variables();
mMerge = new merge::None();
+
+ connect( mVariables, SIGNAL(changed()), this, SLOT(onVariablesChanged()) );
+ }
+
+
+ Model::Model( merge::Merge* merge, Variables* variables )
+ : mUntitledInstance(0), mModified(true), mRotate(false)
+ {
+ mVariables = variables; // Shared
+ mMerge = merge; // Shared
}
@@ -66,7 +77,8 @@ namespace glabels
///
Model::~Model()
{
- delete mMerge;
+ qDeleteAll( mObjectList );
+ // Final instance of mMerge and mVariables to be deleted by Model owner
}
@@ -75,7 +87,13 @@ namespace glabels
///
Model* Model::save() const
{
- auto* savedModel = new Model;
+ auto* savedModel = new Model( mMerge, mVariables ); // mMerge and mVariables shared between models
+
+ if ( mFileName.isEmpty() && mUntitledInstance == 0 )
+ {
+ qDebug() << "Model::save: Warning: called before mUntitledInstance has been initialized: untitled names will differ";
+ }
+
savedModel->restore( this );
return savedModel;
@@ -112,18 +130,12 @@ namespace glabels
connect( object, SIGNAL(moved()), this, SLOT(onObjectMoved()) );
}
- delete mMerge;
- mMerge = savedModel->mMerge->clone();
-
// Emit signals based on potential changes
emit changed();
emit selectionChanged();
emit modifiedChanged();
emit nameChanged();
emit sizeChanged();
- emit mergeChanged();
- emit mergeSourceChanged();
- emit mergeSelectionChanged();
}
@@ -276,6 +288,38 @@ namespace glabels
}
+ ///
+ /// Get directory as a QDir.
+ ///
+ QDir Model::dir() const
+ {
+ if ( mFileName.isEmpty() )
+ {
+ return QDir::current();
+ }
+ else
+ {
+ return QFileInfo( mFileName ).absoluteDir();
+ }
+ }
+
+
+ ///
+ /// Get directory as a path.
+ ///
+ QString Model::dirPath() const
+ {
+ if ( mFileName.isEmpty() )
+ {
+ return QDir::currentPath();
+ }
+ else
+ {
+ return QFileInfo( mFileName ).absolutePath();
+ }
+ }
+
+
///
/// Get short name.
///
@@ -302,6 +346,15 @@ namespace glabels
}
+ ///
+ /// Get variables object
+ ///
+ Variables* Model::variables() const
+ {
+ return mVariables;
+ }
+
+
///
/// Get merge object
///
@@ -451,6 +504,17 @@ namespace glabels
}
+ ///
+ /// Variables Changed Slot
+ ///
+ void Model::onVariablesChanged()
+ {
+ setModified();
+ emit changed();
+ emit variablesChanged();
+ }
+
+
///
/// Merge Source Changed Slot
///
@@ -1359,7 +1423,7 @@ namespace glabels
QClipboard *clipboard = QApplication::clipboard();
QByteArray buffer;
- XmlLabelCreator::serializeObjects( getSelection(), buffer );
+ XmlLabelCreator::serializeObjects( getSelection(), this, buffer );
auto *mimeData = new QMimeData;
mimeData->setData( MIME_TYPE, buffer );
@@ -1415,7 +1479,7 @@ namespace glabels
{
// Native objects
QByteArray buffer = mimeData->data( MIME_TYPE );
- QList objects = XmlLabelParser::deserializeObjects( buffer );
+ QList objects = XmlLabelParser::deserializeObjects( buffer, this );
unselectAll();
foreach ( ModelObject* object, objects )
@@ -1452,11 +1516,11 @@ namespace glabels
///
/// Draw label objects
///
- void Model::draw( QPainter* painter, bool inEditor, merge::Record* record ) const
+ void Model::draw( QPainter* painter, bool inEditor, merge::Record* record, Variables* variables ) const
{
foreach ( ModelObject* object, mObjectList )
{
- object->draw( painter, inEditor, record );
+ object->draw( painter, inEditor, record, variables );
}
}
diff --git a/model/Model.h b/model/Model.h
index 992606e..e31574d 100644
--- a/model/Model.h
+++ b/model/Model.h
@@ -24,10 +24,12 @@
#include "Settings.h"
#include "Template.h"
+#include "Variables.h"
#include "merge/Merge.h"
#include "merge/Record.h"
+#include
#include
#include
#include
@@ -57,6 +59,7 @@ namespace glabels
/////////////////////////////////
public:
Model();
+ Model( merge::Merge* merge, Variables* variables );
~Model();
@@ -76,6 +79,7 @@ namespace glabels
void sizeChanged();
void selectionChanged();
void modifiedChanged();
+ void variablesChanged();
void mergeChanged();
void mergeSourceChanged();
void mergeSelectionChanged();
@@ -89,6 +93,8 @@ namespace glabels
void setModified();
void clearModified();
+ QDir dir() const;
+ QString dirPath() const;
QString shortName();
const QString& fileName() const;
void setFileName( const QString &fileName );
@@ -107,6 +113,8 @@ namespace glabels
const QList& objectList() const;
+ Variables* variables() const;
+
merge::Merge* merge() const;
void setMerge( merge::Merge* merge );
@@ -204,7 +212,10 @@ namespace glabels
// Drawing operations
/////////////////////////////////
public:
- void draw( QPainter* painter, bool inEditor = true, merge::Record* record = nullptr ) const;
+ void draw( QPainter* painter,
+ bool inEditor,
+ merge::Record* record,
+ Variables* variables ) const;
/////////////////////////////////
@@ -213,6 +224,7 @@ namespace glabels
private slots:
void onObjectChanged();
void onObjectMoved();
+ void onVariablesChanged();
void onMergeSourceChanged();
void onMergeSelectionChanged();
@@ -229,6 +241,7 @@ namespace glabels
QList mObjectList;
+ Variables* mVariables;
merge::Merge* mMerge;
};
diff --git a/model/ModelBarcodeObject.cpp b/model/ModelBarcodeObject.cpp
index 315632e..ed4f1bf 100644
--- a/model/ModelBarcodeObject.cpp
+++ b/model/ModelBarcodeObject.cpp
@@ -89,13 +89,14 @@ namespace glabels
const Distance& y0,
const Distance& w,
const Distance& h,
+ bool lockAspectRatio,
const barcode::Style& bcStyle,
bool bcTextFlag,
bool bcChecksumFlag,
QString bcData,
const ColorNode& bcColorNode,
const QMatrix& matrix )
- : ModelObject( x0, y0, w, h, matrix )
+ : ModelObject( x0, y0, w, h, lockAspectRatio, matrix )
{
mOutline = new Outline( this );
@@ -311,7 +312,8 @@ namespace glabels
///
void ModelBarcodeObject::drawShadow( QPainter* painter,
bool inEditor,
- merge::Record* record ) const
+ merge::Record* record,
+ Variables* variables ) const
{
// Barcodes don't support shadows.
}
@@ -322,9 +324,10 @@ namespace glabels
///
void ModelBarcodeObject::drawObject( QPainter* painter,
bool inEditor,
- merge::Record* record ) const
+ merge::Record* record,
+ Variables* variables ) const
{
- QColor bcColor = mBcColorNode.color( record );
+ QColor bcColor = mBcColorNode.color( record, variables );
if ( inEditor )
{
@@ -332,7 +335,7 @@ namespace glabels
}
else
{
- drawBc( painter, bcColor, record );
+ drawBc( painter, bcColor, record, variables );
}
}
@@ -450,7 +453,8 @@ namespace glabels
void
ModelBarcodeObject::drawBc( QPainter* painter,
const QColor& color,
- merge::Record* record ) const
+ merge::Record* record,
+ Variables* variables ) const
{
painter->setPen( QPen( color ) );
@@ -458,7 +462,7 @@ namespace glabels
bc->setChecksum(mBcChecksumFlag);
bc->setShowText(mBcTextFlag);
- bc->build( mBcData.expand( record ).toStdString(), mW.pt(), mH.pt() );
+ bc->build( mBcData.expand( record, variables ).toStdString(), mW.pt(), mH.pt() );
glbarcode::QtRenderer renderer(painter);
bc->render( renderer );
diff --git a/model/ModelBarcodeObject.h b/model/ModelBarcodeObject.h
index 4931ddf..2a49304 100644
--- a/model/ModelBarcodeObject.h
+++ b/model/ModelBarcodeObject.h
@@ -51,6 +51,7 @@ namespace glabels
const Distance& y0,
const Distance& w,
const Distance& h,
+ bool lockAspectRatio,
const barcode::Style& bcStyle,
bool bcTextFlag,
bool bcChecksumFlag,
@@ -126,8 +127,16 @@ namespace glabels
// Drawing operations
///////////////////////////////////////////////////////////////
protected:
- void drawShadow( QPainter* painter, bool inEditor, merge::Record* record ) const override;
- void drawObject( QPainter* painter, bool inEditor, merge::Record* record ) const override;
+ void drawShadow( QPainter* painter,
+ bool inEditor,
+ merge::Record* record,
+ Variables* variables ) const override;
+
+ void drawObject( QPainter* painter,
+ bool inEditor,
+ merge::Record* record,
+ Variables* variables ) const override;
+
QPainterPath hoverPath( double scale ) const override;
@@ -139,7 +148,12 @@ namespace glabels
void update();
void drawBcInEditor( QPainter* painter, const QColor& color ) const;
- void drawBc( QPainter* painter, const QColor& color, merge::Record* record ) const;
+
+ void drawBc( QPainter* painter,
+ const QColor& color,
+ merge::Record* record,
+ Variables* variables ) const;
+
void drawPlaceHolder( QPainter* painter, const QColor& color, const QString& text ) const;
diff --git a/model/ModelBoxObject.cpp b/model/ModelBoxObject.cpp
index 94e81d5..4fd66e7 100644
--- a/model/ModelBoxObject.cpp
+++ b/model/ModelBoxObject.cpp
@@ -54,6 +54,7 @@ namespace glabels
const Distance& y0,
const Distance& w,
const Distance& h,
+ bool lockAspectRatio,
const Distance& lineWidth,
const ColorNode& lineColorNode,
const ColorNode& fillColorNode,
@@ -63,7 +64,7 @@ namespace glabels
const Distance& shadowY,
double shadowOpacity,
const ColorNode& shadowColorNode )
- : ModelShapeObject( x0, y0, w, h,
+ : ModelShapeObject( x0, y0, w, h, lockAspectRatio,
lineWidth, lineColorNode, fillColorNode,
matrix,
shadowState, shadowX, shadowY, shadowOpacity, shadowColorNode )
@@ -103,11 +104,14 @@ namespace glabels
///
/// Draw shadow of object
///
- void ModelBoxObject::drawShadow( QPainter* painter, bool inEditor, merge::Record* record ) const
+ void ModelBoxObject::drawShadow( QPainter* painter,
+ bool inEditor,
+ merge::Record* record,
+ Variables* variables ) const
{
- QColor lineColor = mLineColorNode.color( record );
- QColor fillColor = mFillColorNode.color( record );
- QColor shadowColor = mShadowColorNode.color( record );
+ QColor lineColor = mLineColorNode.color( record, variables );
+ QColor fillColor = mFillColorNode.color( record, variables );
+ QColor shadowColor = mShadowColorNode.color( record, variables );
shadowColor.setAlphaF( mShadowOpacity );
@@ -148,10 +152,13 @@ namespace glabels
///
/// Draw object itself
///
- void ModelBoxObject::drawObject( QPainter* painter, bool inEditor, merge::Record* record ) const
+ void ModelBoxObject::drawObject( QPainter* painter,
+ bool inEditor,
+ merge::Record* record,
+ Variables* variables ) const
{
- QColor lineColor = mLineColorNode.color( record );
- QColor fillColor = mFillColorNode.color( record );
+ QColor lineColor = mLineColorNode.color( record, variables );
+ QColor fillColor = mFillColorNode.color( record, variables );
painter->setPen( QPen( lineColor, mLineWidth.pt() ) );
painter->setBrush( fillColor );
diff --git a/model/ModelBoxObject.h b/model/ModelBoxObject.h
index 8705c99..21b5826 100644
--- a/model/ModelBoxObject.h
+++ b/model/ModelBoxObject.h
@@ -47,6 +47,7 @@ namespace glabels
const Distance& y0,
const Distance& w,
const Distance& h,
+ bool lockAspectRatio,
const Distance& lineWidth,
const ColorNode& lineColorNode,
const ColorNode& fillColorNode,
@@ -72,8 +73,16 @@ namespace glabels
// Drawing operations
///////////////////////////////////////////////////////////////
protected:
- void drawShadow( QPainter* painter, bool inEditor, merge::Record* record ) const override;
- void drawObject( QPainter* painter, bool inEditor, merge::Record* record ) const override;
+ void drawShadow( QPainter* painter,
+ bool inEditor,
+ merge::Record* record,
+ Variables* variables ) const override;
+
+ void drawObject( QPainter* painter,
+ bool inEditor,
+ merge::Record* record,
+ Variables* variables ) const override;
+
QPainterPath hoverPath( double scale ) const override;
};
diff --git a/model/ModelEllipseObject.cpp b/model/ModelEllipseObject.cpp
index c3ca82e..7e35791 100644
--- a/model/ModelEllipseObject.cpp
+++ b/model/ModelEllipseObject.cpp
@@ -54,6 +54,7 @@ namespace glabels
const Distance& y0,
const Distance& w,
const Distance& h,
+ bool lockAspectRatio,
const Distance& lineWidth,
const ColorNode& lineColorNode,
const ColorNode& fillColorNode,
@@ -63,7 +64,7 @@ namespace glabels
const Distance& shadowY,
double shadowOpacity,
const ColorNode& shadowColorNode )
- : ModelShapeObject( x0, y0, w, h,
+ : ModelShapeObject( x0, y0, w, h, lockAspectRatio,
lineWidth, lineColorNode, fillColorNode,
matrix,
shadowState, shadowX, shadowY, shadowOpacity, shadowColorNode )
@@ -103,11 +104,14 @@ namespace glabels
///
/// Draw shadow of object
///
- void ModelEllipseObject::drawShadow( QPainter* painter, bool inEditor, merge::Record* record ) const
+ void ModelEllipseObject::drawShadow( QPainter* painter,
+ bool inEditor,
+ merge::Record* record,
+ Variables* variables ) const
{
- QColor lineColor = mLineColorNode.color( record );
- QColor fillColor = mFillColorNode.color( record );
- QColor shadowColor = mShadowColorNode.color( record );
+ QColor lineColor = mLineColorNode.color( record, variables );
+ QColor fillColor = mFillColorNode.color( record, variables );
+ QColor shadowColor = mShadowColorNode.color( record, variables );
shadowColor.setAlphaF( mShadowOpacity );
@@ -148,10 +152,13 @@ namespace glabels
///
/// Draw object itself
///
- void ModelEllipseObject::drawObject( QPainter* painter, bool inEditor, merge::Record* record ) const
+ void ModelEllipseObject::drawObject( QPainter* painter,
+ bool inEditor,
+ merge::Record* record,
+ Variables* variables ) const
{
- QColor lineColor = mLineColorNode.color( record );
- QColor fillColor = mFillColorNode.color( record );
+ QColor lineColor = mLineColorNode.color( record, variables );
+ QColor fillColor = mFillColorNode.color( record, variables );
painter->setPen( QPen( lineColor, mLineWidth.pt() ) );
painter->setBrush( fillColor );
diff --git a/model/ModelEllipseObject.h b/model/ModelEllipseObject.h
index e26e9ba..26ae6d4 100644
--- a/model/ModelEllipseObject.h
+++ b/model/ModelEllipseObject.h
@@ -47,6 +47,7 @@ namespace glabels
const Distance& y0,
const Distance& w,
const Distance& h,
+ bool lockAspectRatio,
const Distance& lineWidth,
const ColorNode& lineColorNode,
const ColorNode& fillColorNode,
@@ -72,8 +73,16 @@ namespace glabels
// Drawing operations
///////////////////////////////////////////////////////////////
protected:
- void drawShadow( QPainter* painter, bool inEditor, merge::Record* record ) const override;
- void drawObject( QPainter* painter, bool inEditor, merge::Record* record ) const override;
+ void drawShadow( QPainter* painter,
+ bool inEditor,
+ merge::Record* record,
+ Variables* variables ) const override;
+
+ void drawObject( QPainter* painter,
+ bool inEditor,
+ merge::Record* record,
+ Variables* variables ) const override;
+
QPainterPath hoverPath( double scale ) const override;
};
diff --git a/model/ModelImageObject.cpp b/model/ModelImageObject.cpp
index 5848625..8bfd0e3 100644
--- a/model/ModelImageObject.cpp
+++ b/model/ModelImageObject.cpp
@@ -20,9 +20,11 @@
#include "ModelImageObject.h"
+#include "Model.h"
#include "Size.h"
#include
+#include
#include
#include
#include
@@ -40,6 +42,17 @@ namespace glabels
QImage* ModelImageObject::smDefaultImage = nullptr;
+ //
+ // Private
+ //
+ namespace
+ {
+ const QColor fillColor = QColor( 224, 224, 224, 255 );
+ const QColor labelColor = QColor( 102, 102, 102, 255 );
+ const Distance pad = Distance::pt(2);
+ }
+
+
///
/// Constructor
///
@@ -70,6 +83,7 @@ namespace glabels
const Distance& y0,
const Distance& w,
const Distance& h,
+ bool lockAspectRatio,
const TextNode& filenameNode,
const QMatrix& matrix,
bool shadowState,
@@ -77,7 +91,7 @@ namespace glabels
const Distance& shadowY,
double shadowOpacity,
const ColorNode& shadowColorNode )
- : ModelObject( x0, y0, w, h,
+ : ModelObject( x0, y0, w, h, lockAspectRatio,
matrix,
shadowState, shadowX, shadowY, shadowOpacity, shadowColorNode )
{
@@ -101,6 +115,8 @@ namespace glabels
mImage = nullptr;
mSvgRenderer = nullptr;
+
+ loadImage();
}
@@ -111,6 +127,7 @@ namespace glabels
const Distance& y0,
const Distance& w,
const Distance& h,
+ bool lockAspectRatio,
const QString& filename,
const QImage& image,
const QMatrix& matrix,
@@ -119,7 +136,7 @@ namespace glabels
const Distance& shadowY,
double shadowOpacity,
const ColorNode& shadowColorNode )
- : ModelObject( x0, y0, w, h,
+ : ModelObject( x0, y0, w, h, lockAspectRatio,
matrix,
shadowState, shadowX, shadowY, shadowOpacity, shadowColorNode )
{
@@ -152,6 +169,7 @@ namespace glabels
const Distance& y0,
const Distance& w,
const Distance& h,
+ bool lockAspectRatio,
const QString& filename,
const QByteArray& svg,
const QMatrix& matrix,
@@ -160,7 +178,7 @@ namespace glabels
const Distance& shadowY,
double shadowOpacity,
const ColorNode& shadowColorNode )
- : ModelObject( x0, y0, w, h,
+ : ModelObject( x0, y0, w, h, lockAspectRatio,
matrix,
shadowState, shadowX, shadowY, shadowOpacity, shadowColorNode )
{
@@ -395,27 +413,58 @@ namespace glabels
///
/// Draw shadow of object
///
- void ModelImageObject::drawShadow( QPainter* painter, bool inEditor, merge::Record* record ) const
+ void ModelImageObject::drawShadow( QPainter* painter,
+ bool inEditor,
+ merge::Record* record,
+ Variables* variables ) const
{
QRectF destRect( 0, 0, mW.pt(), mH.pt() );
- QColor shadowColor = mShadowColorNode.color( record );
+ QColor shadowColor = mShadowColorNode.color( record, variables );
shadowColor.setAlphaF( mShadowOpacity );
if ( mImage && mImage->hasAlphaChannel() && (mImage->depth() == 32) )
{
- QImage* shadowImage = createShadowImage( shadowColor );
+ QImage* shadowImage = createShadowImage( *mImage, shadowColor );
painter->drawImage( destRect, *shadowImage );
delete shadowImage;
}
+ else if ( mImage || mSvgRenderer || inEditor )
+ {
+ painter->setBrush( shadowColor );
+ painter->setPen( QPen( Qt::NoPen ) );
+
+ painter->drawRect( destRect );
+ }
else
{
- if ( mImage || inEditor )
+ QString filename = mFilenameNode.text( record, variables );
+ QImage* image;
+ QSvgRenderer* svgRenderer;
+ QByteArray svg;
+ if ( readImageFile( filename, image, svgRenderer, svg ) )
{
- painter->setBrush( shadowColor );
- painter->setPen( QPen( Qt::NoPen ) );
+ if ( image && image->hasAlphaChannel() && (image->depth() == 32) )
+ {
+ QImage* shadowImage = createShadowImage( *image, shadowColor );
+ painter->drawImage( destRect, *shadowImage );
+ delete shadowImage;
+ }
+ else
+ {
+ painter->setBrush( shadowColor );
+ painter->setPen( QPen( Qt::NoPen ) );
- painter->drawRect( destRect );
+ painter->drawRect( destRect );
+ }
+ if ( image )
+ {
+ delete image;
+ }
+ else
+ {
+ delete svgRenderer;
+ }
}
}
}
@@ -424,16 +473,70 @@ namespace glabels
///
/// Draw object itself
///
- void ModelImageObject::drawObject( QPainter* painter, bool inEditor, merge::Record* record ) const
+ void ModelImageObject::drawObject( QPainter* painter,
+ bool inEditor,
+ merge::Record* record,
+ Variables* variables ) const
{
QRectF destRect( 0, 0, mW.pt(), mH.pt() );
if ( inEditor && (mFilenameNode.isField() || (!mImage && !mSvgRenderer) ) )
{
+ //
+ // Render default place holder image
+ //
painter->save();
painter->setRenderHint( QPainter::SmoothPixmapTransform, false );
painter->drawImage( destRect, *smDefaultImage );
painter->restore();
+
+ //
+ // Print label on top of place holder image, if we have room
+ //
+ if ( (mW > 6*pad) && (mH > 4*pad) )
+ {
+ QString labelText = tr("No image");
+ if ( mFilenameNode.isField() )
+ {
+ labelText = QString( "${%1}" ).arg( mFilenameNode.data() );
+ }
+
+ // Determine font size for labelText
+ QFont font( "Sans" );
+ font.setPointSizeF( 6 );
+
+ QFontMetricsF fm( font );
+ QRectF textRect = fm.boundingRect( labelText );
+
+ double wPts = (mW - 2*pad).pt();
+ double hPts = (mH - 2*pad).pt();
+ if ( (wPts < textRect.width()) || (hPts < textRect.height()) )
+ {
+ double scaleX = wPts / textRect.width();
+ double scaleY = hPts / textRect.height();
+ font.setPointSizeF( 6 * std::min( scaleX, scaleY ) );
+ }
+
+ // Render hole for text (font size may have changed above)
+ fm = QFontMetricsF( font );
+ textRect = fm.boundingRect( labelText );
+
+ QRectF holeRect( (mW.pt() - textRect.width())/2 - pad.pt(),
+ (mH.pt() - textRect.height())/2 - pad.pt(),
+ textRect.width() + 2*pad.pt(),
+ textRect.height() + 2*pad.pt() );
+
+ painter->setPen( Qt::NoPen );
+ painter->setBrush( QBrush( fillColor ) );
+ painter->drawRect( holeRect );
+
+ // Render text
+ painter->setFont( font );
+ painter->setPen( QPen( labelColor ) );
+ painter->drawText( QRectF( 0, 0, mW.pt(), mH.pt() ),
+ Qt::AlignCenter,
+ labelText );
+ }
}
else if ( mImage )
{
@@ -445,7 +548,23 @@ namespace glabels
}
else if ( mFilenameNode.isField() )
{
- // TODO
+ QString filename = mFilenameNode.text( record, variables );
+ QImage* image;
+ QSvgRenderer* svgRenderer;
+ QByteArray svg;
+ if ( readImageFile( filename, image, svgRenderer, svg ) )
+ {
+ if ( image )
+ {
+ painter->drawImage( destRect, *image );
+ delete image;
+ }
+ else
+ {
+ svgRenderer->render( painter, destRect );
+ delete svgRenderer;
+ }
+ }
}
}
@@ -481,59 +600,32 @@ namespace glabels
if ( !mFilenameNode.isField() )
{
QString filename = mFilenameNode.data();
- QFileInfo fileInfo( filename );
-
- if ( fileInfo.isReadable() )
+ if ( readImageFile( filename, mImage, mSvgRenderer, mSvg ) )
{
- if ( (fileInfo.suffix() == "svg") || (fileInfo.suffix() == "SVG") )
+ double aspectRatio = 0;
+ if ( mSvgRenderer )
{
- QFile file( filename );
- if ( file.open( QFile::ReadOnly ) )
- {
- mSvg = file.readAll();
- file.close();
- mSvgRenderer = new QSvgRenderer( mSvg );
- if ( !mSvgRenderer->isValid() )
- {
- mSvgRenderer = nullptr;
- }
- else
- {
- // Adjust size based on aspect ratio of SVG image
- QRectF rect = mSvgRenderer->viewBoxF();
- double aspectRatio = rect.height() / rect.width();
- if ( mH > mW*aspectRatio )
- {
- mH = mW*aspectRatio;
- }
- else
- {
- mW = mH/aspectRatio;
- }
- }
- }
+ // Adjust size based on aspect ratio of SVG image
+ QRectF rect = mSvgRenderer->viewBoxF();
+ aspectRatio = rect.width() ? rect.height() / rect.width() : 0;
}
else
{
- mImage = new QImage( filename );
- if ( mImage->isNull() )
+ // Adjust size based on aspect ratio of image
+ double imageW = mImage->width();
+ double imageH = mImage->height();
+ aspectRatio = imageW ? imageH / imageW : 0;
+ }
+
+ if ( aspectRatio )
+ {
+ if ( mH > mW*aspectRatio )
{
- mImage = nullptr;
+ mH = mW*aspectRatio;
}
else
{
- // Adjust size based on aspect ratio of image
- double imageW = mImage->width();
- double imageH = mImage->height();
- double aspectRatio = imageH / imageW;
- if ( mH > mW*aspectRatio )
- {
- mH = mW*aspectRatio;
- }
- else
- {
- mW = mH/aspectRatio;
- }
+ mW = mH/aspectRatio;
}
}
}
@@ -541,17 +633,75 @@ namespace glabels
}
+ ///
+ /// Read an image or svg file
+ ///
+ bool ModelImageObject::readImageFile( const QString& fileName,
+ QImage*& image,
+ QSvgRenderer*& svgRenderer,
+ QByteArray& svg ) const
+ {
+ image = nullptr;
+ svgRenderer = nullptr;
+ svg.clear();
+
+ if ( !fileName.isEmpty() )
+ {
+ QFileInfo fileInfo( fileName );
+ if ( fileInfo.isRelative() )
+ {
+ // Look for image file relative to project file 1st then CWD 2nd
+ auto* model = dynamic_cast( parent() );
+ QDir::setSearchPaths( "images", {model ? model->dirPath() : "", QDir::currentPath()} );
+ fileInfo.setFile( QString("images:") + fileName );
+ }
+
+ if ( fileInfo.isReadable() )
+ {
+ if ( fileInfo.suffix().toLower() == "svg" )
+ {
+ QFile file( fileInfo.filePath() );
+ if ( file.open( QFile::ReadOnly ) )
+ {
+ svg = file.readAll();
+ file.close();
+ svgRenderer = new QSvgRenderer( svg );
+ if ( !svgRenderer->isValid() )
+ {
+ delete svgRenderer;
+ svgRenderer = nullptr;
+ svg.clear();
+ }
+ }
+ }
+ else
+ {
+ image = new QImage( fileInfo.filePath() );
+ if ( image->isNull() )
+ {
+ delete image;
+ image = nullptr;
+ }
+ }
+ }
+ }
+
+ return image != nullptr || svgRenderer != nullptr;
+ }
+
+
///
/// Create shadow image
///
- QImage* ModelImageObject::createShadowImage( const QColor& color ) const
+ QImage* ModelImageObject::createShadowImage( const QImage& image,
+ const QColor& color ) const
{
int r = color.red();
int g = color.green();
int b = color.blue();
int a = color.alpha();
- auto* shadow = new QImage( *mImage );
+ auto* shadow = new QImage( image );
for ( int iy = 0; iy < shadow->height(); iy++ )
{
auto* scanLine = (QRgb*)shadow->scanLine( iy );
diff --git a/model/ModelImageObject.h b/model/ModelImageObject.h
index ba87078..3e982f5 100644
--- a/model/ModelImageObject.h
+++ b/model/ModelImageObject.h
@@ -49,6 +49,7 @@ namespace glabels
const Distance& y0,
const Distance& w,
const Distance& h,
+ bool lockAspectRatio,
const TextNode& filenameNode,
const QMatrix& matrix = QMatrix(),
bool shadowState = false,
@@ -61,6 +62,7 @@ namespace glabels
const Distance& y0,
const Distance& w,
const Distance& h,
+ bool lockAspectRatio,
const QString& filename,
const QImage& image,
const QMatrix& matrix = QMatrix(),
@@ -74,6 +76,7 @@ namespace glabels
const Distance& y0,
const Distance& w,
const Distance& h,
+ bool lockAspectRatio,
const QString& filename,
const QByteArray& svg,
const QMatrix& matrix = QMatrix(),
@@ -132,8 +135,16 @@ namespace glabels
// Drawing operations
///////////////////////////////////////////////////////////////
protected:
- void drawShadow( QPainter* painter, bool inEditor, merge::Record* record ) const override;
- void drawObject( QPainter* painter, bool inEditor, merge::Record* record ) const override;
+ void drawShadow( QPainter* painter,
+ bool inEditor,
+ merge::Record* record,
+ Variables* variables ) const override;
+
+ void drawObject( QPainter* painter,
+ bool inEditor,
+ merge::Record* record,
+ Variables* variables ) const override;
+
QPainterPath hoverPath( double scale ) const override;
@@ -141,7 +152,14 @@ namespace glabels
// Private
///////////////////////////////////////////////////////////////
void loadImage();
- QImage* createShadowImage( const QColor& color ) const;
+
+ bool readImageFile( const QString& fileName,
+ QImage*& image,
+ QSvgRenderer*& svgRenderer,
+ QByteArray& svg ) const;
+
+ QImage* createShadowImage( const QImage& image,
+ const QColor& color ) const;
///////////////////////////////////////////////////////////////
diff --git a/model/ModelLineObject.cpp b/model/ModelLineObject.cpp
index 5d7b5e1..5bef065 100644
--- a/model/ModelLineObject.cpp
+++ b/model/ModelLineObject.cpp
@@ -68,7 +68,7 @@ namespace glabels
const Distance& shadowY,
double shadowOpacity,
const ColorNode& shadowColorNode )
- : ModelObject( x0, y0, dx, dy,
+ : ModelObject( x0, y0, dx, dy, false /*lockAspectRatio*/,
matrix,
shadowState, shadowX, shadowY, shadowOpacity, shadowColorNode )
{
@@ -186,10 +186,13 @@ namespace glabels
///
/// Draw shadow of object
///
- void ModelLineObject::drawShadow( QPainter* painter, bool inEditor, merge::Record* record ) const
+ void ModelLineObject::drawShadow( QPainter* painter,
+ bool inEditor,
+ merge::Record* record,
+ Variables* variables ) const
{
- QColor lineColor = mLineColorNode.color( record );
- QColor shadowColor = mShadowColorNode.color( record );
+ QColor lineColor = mLineColorNode.color( record, variables );
+ QColor shadowColor = mShadowColorNode.color( record, variables );
shadowColor.setAlphaF( mShadowOpacity );
@@ -204,9 +207,12 @@ namespace glabels
///
/// Draw object itself
///
- void ModelLineObject::drawObject( QPainter* painter, bool inEditor, merge::Record* record ) const
+ void ModelLineObject::drawObject( QPainter* painter,
+ bool inEditor,
+ merge::Record* record,
+ Variables* variables ) const
{
- QColor lineColor = mLineColorNode.color( record );
+ QColor lineColor = mLineColorNode.color( record, variables );
painter->setPen( QPen( lineColor, mLineWidth.pt() ) );
painter->drawLine( 0, 0, mW.pt(), mH.pt() );
diff --git a/model/ModelLineObject.h b/model/ModelLineObject.h
index 16cfdb6..a09670e 100644
--- a/model/ModelLineObject.h
+++ b/model/ModelLineObject.h
@@ -97,8 +97,16 @@ namespace glabels
// Drawing operations
///////////////////////////////////////////////////////////////
protected:
- void drawShadow( QPainter* painter, bool inEditor, merge::Record* record ) const override;
- void drawObject( QPainter* painter, bool inEditor, merge::Record* record ) const override;
+ void drawShadow( QPainter* painter,
+ bool inEditor,
+ merge::Record* record,
+ Variables* variables ) const override;
+
+ void drawObject( QPainter* painter,
+ bool inEditor,
+ merge::Record* record,
+ Variables* variables ) const override;
+
QPainterPath hoverPath( double scale ) const override;
diff --git a/model/ModelObject.cpp b/model/ModelObject.cpp
index 637352c..65ed72a 100644
--- a/model/ModelObject.cpp
+++ b/model/ModelObject.cpp
@@ -51,6 +51,7 @@ namespace glabels
mY0 = 0;
mW = 0;
mH = 0;
+ mLockAspectRatio = false;
mMatrix = QMatrix();
mShadowState = false;
@@ -72,6 +73,7 @@ namespace glabels
const Distance& y0,
const Distance& w,
const Distance& h,
+ bool lockAspectRatio,
const QMatrix& matrix,
bool shadowState,
const Distance& shadowX,
@@ -85,6 +87,7 @@ namespace glabels
mY0 = y0;
mW = w;
mH = h;
+ mLockAspectRatio = lockAspectRatio;
mMatrix = matrix;
mShadowState = shadowState;
@@ -112,6 +115,7 @@ namespace glabels
mY0 = object->mY0;
mW = object->mW;
mH = object->mH;
+ mLockAspectRatio = object->mLockAspectRatio;
mShadowState = object->mShadowState;
mShadowX = object->mShadowX;
@@ -272,6 +276,28 @@ namespace glabels
}
+ ///
+ /// Lock Aspect Ratio Property Getter
+ ///
+ bool ModelObject::lockAspectRatio() const
+ {
+ return mLockAspectRatio;
+ }
+
+
+ ///
+ /// Lock Aspect Ratio Property Setter
+ ///
+ void ModelObject::setLockAspectRatio( bool value )
+ {
+ if ( mLockAspectRatio != value )
+ {
+ mLockAspectRatio = value;
+ emit changed();
+ }
+ }
+
+
///
/// Matrix Property Getter
///
@@ -1200,7 +1226,10 @@ namespace glabels
///
/// Draw object + shadow
///
- void ModelObject::draw( QPainter* painter, bool inEditor, merge::Record* record ) const
+ void ModelObject::draw( QPainter* painter,
+ bool inEditor,
+ merge::Record* record,
+ Variables* variables ) const
{
painter->save();
painter->translate( mX0.pt(), mY0.pt() );
@@ -1210,12 +1239,12 @@ namespace glabels
painter->save();
painter->translate( mShadowX.pt(), mShadowY.pt() );
painter->setMatrix( mMatrix, true );
- drawShadow( painter, inEditor, record );
+ drawShadow( painter, inEditor, record, variables );
painter->restore();
}
painter->setMatrix( mMatrix, true );
- drawObject( painter, inEditor, record );
+ drawObject( painter, inEditor, record, variables );
painter->restore();
}
diff --git a/model/ModelObject.h b/model/ModelObject.h
index 6af51e8..4962ffd 100644
--- a/model/ModelObject.h
+++ b/model/ModelObject.h
@@ -27,6 +27,7 @@
#include "Handles.h"
#include "Outline.h"
#include "TextNode.h"
+#include "Variables.h"
#include "barcode/Style.h"
#include "merge/Record.h"
@@ -64,6 +65,7 @@ namespace glabels
const Distance& y0,
const Distance& w,
const Distance& h,
+ bool lockAspectRatio = false,
const QMatrix& matrix = QMatrix(),
bool shadowState = false,
const Distance& shadowX = 0,
@@ -136,6 +138,13 @@ namespace glabels
void setH( const Distance& value );
+ //
+ // Lock Aspect Ratio Property
+ //
+ bool lockAspectRatio() const;
+ void setLockAspectRatio( bool value );
+
+
//
// Transformation Matrix Property
//
@@ -403,12 +412,24 @@ namespace glabels
// Drawing operations
///////////////////////////////////////////////////////////////
public:
- void draw( QPainter* painter, bool inEditor, merge::Record* record ) const;
+ void draw( QPainter* painter,
+ bool inEditor,
+ merge::Record* record,
+ Variables* variables ) const;
+
void drawSelectionHighlight( QPainter* painter, double scale ) const;
protected:
- virtual void drawShadow( QPainter* painter, bool inEditor, merge::Record* record ) const = 0;
- virtual void drawObject( QPainter* painter, bool inEditor, merge::Record* record ) const = 0;
+ virtual void drawShadow( QPainter* painter,
+ bool inEditor,
+ merge::Record* record,
+ Variables* variables ) const = 0;
+
+ virtual void drawObject( QPainter* painter,
+ bool inEditor,
+ merge::Record* record,
+ Variables* variables ) const = 0;
+
virtual QPainterPath hoverPath( double scale ) const = 0;
virtual void sizeUpdated();
@@ -424,6 +445,7 @@ namespace glabels
Distance mY0;
Distance mW;
Distance mH;
+ bool mLockAspectRatio;
bool mShadowState;
Distance mShadowX;
diff --git a/model/ModelShapeObject.cpp b/model/ModelShapeObject.cpp
index 989f5af..afca487 100644
--- a/model/ModelShapeObject.cpp
+++ b/model/ModelShapeObject.cpp
@@ -58,6 +58,7 @@ namespace glabels
const Distance& y0,
const Distance& w,
const Distance& h,
+ bool lockAspectRatio,
const Distance& lineWidth,
const ColorNode& lineColorNode,
const ColorNode& fillColorNode,
@@ -67,7 +68,7 @@ namespace glabels
const Distance& shadowY,
double shadowOpacity,
const ColorNode& shadowColorNode )
- : ModelObject( x0, y0, w, h,
+ : ModelObject( x0, y0, w, h, lockAspectRatio,
matrix,
shadowState, shadowX, shadowY, shadowOpacity, shadowColorNode )
{
diff --git a/model/ModelShapeObject.h b/model/ModelShapeObject.h
index b33c5a3..888ac03 100644
--- a/model/ModelShapeObject.h
+++ b/model/ModelShapeObject.h
@@ -47,6 +47,7 @@ namespace glabels
const Distance& y0,
const Distance& w,
const Distance& h,
+ bool lockAspectRatio,
const Distance& lineWidth,
const ColorNode& lineColorNode,
const ColorNode& fillColorNode,
diff --git a/model/ModelTextObject.cpp b/model/ModelTextObject.cpp
index 434d48b..bb5c7e6 100644
--- a/model/ModelTextObject.cpp
+++ b/model/ModelTextObject.cpp
@@ -82,6 +82,7 @@ namespace glabels
const Distance& y0,
const Distance& w,
const Distance& h,
+ bool lockAspectRatio,
const QString& text,
const QString& fontFamily,
double fontSize,
@@ -100,7 +101,7 @@ namespace glabels
const Distance& shadowY,
double shadowOpacity,
const ColorNode& shadowColorNode )
- : ModelObject( x0, y0, w, h,
+ : ModelObject( x0, y0, w, h, lockAspectRatio,
matrix,
shadowState, shadowX, shadowY, shadowOpacity, shadowColorNode )
{
@@ -518,13 +519,14 @@ namespace glabels
///
void ModelTextObject::drawShadow( QPainter* painter,
bool inEditor,
- merge::Record* record ) const
+ merge::Record* record,
+ Variables* variables ) const
{
- QColor textColor = mTextColorNode.color( record );
+ QColor textColor = mTextColorNode.color( record, variables );
if ( textColor.alpha() )
{
- QColor shadowColor = mShadowColorNode.color( record );
+ QColor shadowColor = mShadowColorNode.color( record, variables );
shadowColor.setAlphaF( mShadowOpacity );
if ( inEditor )
@@ -533,7 +535,7 @@ namespace glabels
}
else
{
- drawText( painter, shadowColor, record );
+ drawText( painter, shadowColor, record, variables );
}
}
}
@@ -544,9 +546,10 @@ namespace glabels
///
void ModelTextObject::drawObject( QPainter* painter,
bool inEditor,
- merge::Record* record ) const
+ merge::Record* record,
+ Variables* variables ) const
{
- QColor textColor = mTextColorNode.color( record );
+ QColor textColor = mTextColorNode.color( record, variables );
if ( inEditor )
{
@@ -554,7 +557,7 @@ namespace glabels
}
else
{
- drawText( painter, textColor, record );
+ drawText( painter, textColor, record, variables );
}
}
@@ -696,7 +699,8 @@ namespace glabels
void
ModelTextObject::drawText( QPainter* painter,
const QColor& color,
- merge::Record* record ) const
+ merge::Record* record,
+ Variables* variables ) const
{
painter->save();
@@ -704,7 +708,7 @@ namespace glabels
QFont font;
font.setFamily( mFontFamily );
- font.setPointSizeF( mTextAutoShrink ? autoShrinkFontSize( record ) : mFontSize );
+ font.setPointSizeF( mTextAutoShrink ? autoShrinkFontSize( record, variables ) : mFontSize );
font.setWeight( mFontWeight );
font.setItalic( mFontItalicFlag );
font.setUnderline( mFontUnderlineFlag );
@@ -716,7 +720,7 @@ namespace glabels
QFontMetricsF fontMetrics( font );
double dy = fontMetrics.lineSpacing() * mTextLineSpacing;
- QTextDocument document( mText.expand( record ) );
+ QTextDocument document( mText.expand( record, variables ) );
QList layouts;
@@ -790,7 +794,7 @@ namespace glabels
/// Determine auto shrink font size
///
double
- ModelTextObject::autoShrinkFontSize( merge::Record* record ) const
+ ModelTextObject::autoShrinkFontSize( merge::Record* record, Variables* variables ) const
{
QFont font;
font.setFamily( mFontFamily );
@@ -802,7 +806,7 @@ namespace glabels
textOption.setAlignment( mTextHAlign );
textOption.setWrapMode( mTextWrapMode );
- QTextDocument document( mText.expand( record ) );
+ QTextDocument document( mText.expand( record, variables ) );
double candidateSize = mFontSize;
while ( candidateSize > 1.0 )
diff --git a/model/ModelTextObject.h b/model/ModelTextObject.h
index 1ab62c6..0f7d1e9 100644
--- a/model/ModelTextObject.h
+++ b/model/ModelTextObject.h
@@ -50,6 +50,7 @@ namespace glabels
const Distance& y0,
const Distance& w,
const Distance& h,
+ bool lockAspectRatio,
const QString& text,
const QString& fontFamily,
double fontSize,
@@ -185,8 +186,16 @@ namespace glabels
// Drawing operations
///////////////////////////////////////////////////////////////
protected:
- void drawShadow( QPainter* painter, bool inEditor, merge::Record* record ) const override;
- void drawObject( QPainter* painter, bool inEditor, merge::Record* record ) const override;
+ void drawShadow( QPainter* painter,
+ bool inEditor,
+ merge::Record* record,
+ Variables* variables ) const override;
+
+ void drawObject( QPainter* painter,
+ bool inEditor,
+ merge::Record* record,
+ Variables* variables ) const override;
+
QPainterPath hoverPath( double scale ) const override;
@@ -196,10 +205,17 @@ namespace glabels
private:
void sizeUpdated() override;
void update();
- void drawTextInEditor( QPainter* painter, const QColor& color ) const;
- void drawText( QPainter* painter, const QColor&color, merge::Record* record ) const;
- QString expandText( QString text, merge::Record* record ) const;
- double autoShrinkFontSize( merge::Record* record ) const;
+
+ void drawTextInEditor( QPainter* painter,
+ const QColor& color ) const;
+
+ void drawText( QPainter* painter,
+ const QColor& color,
+ merge::Record* record,
+ Variables* variables ) const;
+
+ double autoShrinkFontSize( merge::Record* record,
+ Variables* variables ) const;
///////////////////////////////////////////////////////////////
diff --git a/model/PageRenderer.cpp b/model/PageRenderer.cpp
index b450ff7..78a3383 100644
--- a/model/PageRenderer.cpp
+++ b/model/PageRenderer.cpp
@@ -47,7 +47,7 @@ namespace glabels
PageRenderer::PageRenderer( const Model* model )
- : mModel(nullptr), mMerge(nullptr), mNCopies(0), mStartLabel(0), mLastLabel(0),
+ : mModel(nullptr), mMerge(nullptr), mVariables(nullptr), mNCopies(0), mStartLabel(0), mLastLabel(0),
mPrintOutlines(false), mPrintCropMarks(false), mPrintReverse(false),
mIPage(0), mIsMerge(false), mNPages(0), mNLabelsPerPage(0)
{
@@ -65,6 +65,7 @@ namespace glabels
connect( mModel, SIGNAL(changed()), this, SLOT(onModelChanged()) );
onModelChanged();
+ mVariables = mModel->variables();
}
@@ -246,83 +247,107 @@ namespace glabels
void PageRenderer::printSimplePage( QPainter* painter, int iPage ) const
{
- int iStart = 0;
- int iEnd = mNLabelsPerPage;
-
- if ( iPage == 0 )
- {
- iStart = mStartLabel;
- }
-
- if ( (mLastLabel / mNLabelsPerPage) == iPage )
- {
- iEnd = mLastLabel % mNLabelsPerPage;
- }
-
printCropMarks( painter );
- for ( int i = iStart; i < iEnd; i++ )
+ int iCopy = 0;
+ int iLabel = mStartLabel;
+ int iCurrentPage = 0;
+ mVariables->resetVariables();
+
+ while ( (iCopy < mNCopies) && (iCurrentPage <= iPage) )
{
- painter->save();
+ if ( iCurrentPage == iPage )
+ {
+ int i = iLabel % mNLabelsPerPage;
+
+ painter->save();
- painter->translate( mOrigins[i].x().pt(), mOrigins[i].y().pt() );
+ painter->translate( mOrigins[i].x().pt(), mOrigins[i].y().pt() );
- painter->save();
+ painter->save();
- clipLabel( painter );
- printLabel( painter, nullptr );
+ clipLabel( painter );
+ printLabel( painter, nullptr, mVariables );
- painter->restore(); // From before clip
+ painter->restore(); // From before clip
- printOutline( painter );
+ printOutline( painter );
- painter->restore(); // From before translation
+ painter->restore(); // From before translation
+ }
+
+ iCopy++;
+ iLabel++;
+ iCurrentPage = iLabel / mNLabelsPerPage;
+
+ mVariables->incrementVariablesOnItem();
+ mVariables->incrementVariablesOnCopy();
+ if ( (iLabel % mNLabelsPerPage) == 0 /* starting a new page */ )
+ {
+ mVariables->incrementVariablesOnPage();
+ }
}
}
void PageRenderer::printMergePage( QPainter* painter, int iPage ) const
{
- int iRecord = 0;
- int iStart = 0;
- int iEnd = mNLabelsPerPage;
-
- if ( iPage == 0 )
- {
- iStart = mStartLabel;
- }
-
- if ( (mLastLabel / mNLabelsPerPage) == iPage )
- {
- iEnd = mLastLabel % mNLabelsPerPage;
- }
-
- const QList records = mMerge->selectedRecords();
- if ( records.size() )
- {
- iRecord = (iPage*mNLabelsPerPage + iStart - mStartLabel) % records.size();
- }
-
printCropMarks( painter );
- for ( int i = iStart; i < iEnd; i++ )
+ int iCopy = 0;
+ int iLabel = mStartLabel;
+ int iCurrentPage = 0;
+
+ const QList records = mMerge->selectedRecords();
+ int iRecord = 0;
+ int nRecords = records.size();
+
+ if ( nRecords == 0 )
{
- painter->save();
-
- painter->translate( mOrigins[i].x().pt(), mOrigins[i].y().pt() );
+ return;
+ }
- painter->save();
+ mVariables->resetVariables();
- clipLabel( painter );
- printLabel( painter, records[iRecord] );
+ while ( (iCopy < mNCopies) && (iCurrentPage <= iPage) )
+ {
+ if ( iCurrentPage == iPage )
+ {
+ int i = iLabel % mNLabelsPerPage;
+
+ painter->save();
- painter->restore(); // From before clip
-
- printOutline( painter );
+ painter->translate( mOrigins[i].x().pt(), mOrigins[i].y().pt() );
- painter->restore(); // From before translation
+ painter->save();
- iRecord = (iRecord + 1) % records.size();
+ clipLabel( painter );
+ printLabel( painter, records[iRecord], mVariables );
+
+ painter->restore(); // From before clip
+
+ printOutline( painter );
+
+ painter->restore(); // From before translation
+ }
+
+ iRecord = (iRecord + 1) % nRecords;
+ if ( iRecord == 0 )
+ {
+ iCopy++;
+ }
+ iLabel++;
+ iCurrentPage = iLabel / mNLabelsPerPage;
+
+ mVariables->incrementVariablesOnItem();
+ if ( iRecord == 0 )
+ {
+ mVariables->incrementVariablesOnCopy();
+ }
+ if ( (iLabel % mNLabelsPerPage) == 0 /* starting a new page */ )
+ {
+ mVariables->incrementVariablesOnPage();
+ }
}
}
@@ -408,7 +433,9 @@ namespace glabels
}
- void PageRenderer::printLabel( QPainter* painter, merge::Record* record ) const
+ void PageRenderer::printLabel( QPainter* painter,
+ merge::Record* record,
+ Variables* variables ) const
{
painter->save();
@@ -424,7 +451,7 @@ namespace glabels
painter->scale( -1, 1 );
}
- mModel->draw( painter, false, record );
+ mModel->draw( painter, false, record, variables );
painter->restore();
}
diff --git a/model/PageRenderer.h b/model/PageRenderer.h
index 2db3ae4..08c93a9 100644
--- a/model/PageRenderer.h
+++ b/model/PageRenderer.h
@@ -23,6 +23,7 @@
#include "Point.h"
+#include "Variables.h"
#include "merge/Merge.h"
#include "merge/Record.h"
@@ -100,7 +101,7 @@ namespace glabels
void printCropMarks( QPainter* painter ) const;
void printOutline( QPainter* painter ) const;
void clipLabel( QPainter* painter ) const;
- void printLabel( QPainter* painter, merge::Record* record ) const;
+ void printLabel( QPainter* painter, merge::Record* record, Variables* variables ) const;
/////////////////////////////////
@@ -109,6 +110,7 @@ namespace glabels
private:
const Model* mModel;
const merge::Merge* mMerge;
+ Variables* mVariables;
int mNCopies;
int mStartLabel;
diff --git a/model/RawText.cpp b/model/RawText.cpp
index 08ee6bf..ed4cd29 100644
--- a/model/RawText.cpp
+++ b/model/RawText.cpp
@@ -66,7 +66,7 @@ namespace glabels
///
/// Expand all place holders
///
- QString RawText::expand( merge::Record* record ) const
+ QString RawText::expand( merge::Record* record, Variables* variables ) const
{
QString text;
@@ -74,7 +74,7 @@ namespace glabels
{
if ( token.isField )
{
- text += token.field.evaluate( record );
+ text += token.field.evaluate( record, variables );
}
else
{
diff --git a/model/RawText.h b/model/RawText.h
index 9b19084..2e8ab44 100644
--- a/model/RawText.h
+++ b/model/RawText.h
@@ -52,7 +52,7 @@ namespace glabels
/////////////////////////////////
QString toString() const;
std::string toStdString() const;
- QString expand( merge::Record* record ) const;
+ QString expand( merge::Record* record, Variables* variables ) const;
bool hasPlaceHolders() const;
bool isEmpty() const;
diff --git a/model/SubstitutionField.cpp b/model/SubstitutionField.cpp
index 178b73e..76c4047 100644
--- a/model/SubstitutionField.cpp
+++ b/model/SubstitutionField.cpp
@@ -42,21 +42,33 @@ namespace glabels
}
- QString SubstitutionField::evaluate( const merge::Record* record ) const
+ QString SubstitutionField::evaluate( const merge::Record* record,
+ const Variables* variables ) const
{
QString value = mDefaultValue;
- if ( record && record->contains(mFieldName) && !record->value(mFieldName).isEmpty() )
+ bool haveRecordField = record &&
+ record->contains(mFieldName) &&
+ !record->value(mFieldName).isEmpty();
+ bool haveVariable = variables &&
+ variables->contains(mFieldName) &&
+ !(*variables)[mFieldName].value().isEmpty();
+
+ if ( haveRecordField )
{
value = record->value(mFieldName);
}
+ else if ( haveVariable )
+ {
+ value = (*variables)[mFieldName].value();
+ }
if ( !mFormatType.isNull() )
{
value = formatValue( value );
}
- if ( record && record->contains(mFieldName) && !record->value(mFieldName).isEmpty() && mNewLine )
+ if ( mNewLine && (haveRecordField || haveVariable) )
{
value = "\n" + value;
}
diff --git a/model/SubstitutionField.h b/model/SubstitutionField.h
index ec08a00..baaa255 100644
--- a/model/SubstitutionField.h
+++ b/model/SubstitutionField.h
@@ -21,6 +21,7 @@
#ifndef model_SubstitutionField_h
#define model_SubstitutionField_h
+#include "Variables.h"
#include "merge/Record.h"
@@ -39,7 +40,7 @@ namespace glabels
SubstitutionField();
SubstitutionField( const QString& string );
- QString evaluate( const merge::Record* record ) const;
+ QString evaluate( const merge::Record* record, const Variables* variables ) const;
QString fieldName() const;
QString defaultValue() const;
diff --git a/model/TextNode.cpp b/model/TextNode.cpp
index 332367e..b0e2271 100644
--- a/model/TextNode.cpp
+++ b/model/TextNode.cpp
@@ -105,48 +105,34 @@ namespace glabels
///
/// Get text, expand if necessary
///
- QString TextNode::text( merge::Record* record ) const
+ QString TextNode::text( const merge::Record* record,
+ const Variables* variables ) const
{
- if ( mIsField )
+ QString value("");
+
+ bool haveRecordField = mIsField && record &&
+ record->contains(mData) &&
+ !record->value(mData).isEmpty();
+ bool haveVariable = mIsField && variables &&
+ variables->contains(mData) &&
+ !(*variables)[mData].value().isEmpty();
+
+ if ( haveRecordField )
{
- if ( !record )
- {
- return QString("${%1}").arg( mData );
- }
- else
- {
- if ( record->contains( mData ) )
- {
- return (*record)[ mData ];
- }
- else
- {
- return "";
- }
- }
+ value = record->value(mData);
}
- else
+ else if ( haveVariable )
{
- return mData;
+ value = (*variables)[mData].value();
}
+ else if ( !mIsField )
+ {
+ value = mData;
+ }
+
+ return value;
}
- ///
- /// Is it an empty field
- ///
- bool TextNode::isEmptyField( merge::Record* record ) const
- {
- if ( record && mIsField )
- {
- if ( record->contains( mData ) )
- {
- return (*record)[mData].isEmpty();
- }
- }
-
- return false;
- }
-
}
}
diff --git a/model/TextNode.h b/model/TextNode.h
index 499f863..c7716d7 100644
--- a/model/TextNode.h
+++ b/model/TextNode.h
@@ -22,6 +22,7 @@
#define model_TextNode_h
+#include "Variables.h"
#include "merge/Record.h"
#include
@@ -76,8 +77,8 @@ namespace glabels
/////////////////////////////////
// Misc. Methods
/////////////////////////////////
- QString text( merge::Record* record ) const;
- bool isEmptyField( merge::Record* record ) const;
+ QString text( const merge::Record* record,
+ const Variables* variables ) const;
/////////////////////////////////
diff --git a/model/Variable.cpp b/model/Variable.cpp
new file mode 100644
index 0000000..fa96462
--- /dev/null
+++ b/model/Variable.cpp
@@ -0,0 +1,323 @@
+/* Variable.cpp
+ *
+ * Copyright (C) 2013-2016 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 "Variable.h"
+
+
+namespace glabels
+{
+ namespace model
+ {
+
+ Variable::Variable()
+ : mType(Type::STRING),
+ mIncrement(Increment::NEVER),
+ mStepSize("0"),
+ mIntegerValue(0),
+ mIntegerStep(0),
+ mFloatingPointValue(0),
+ mFloatingPointStep(0)
+ {
+ // empty
+ }
+
+
+ Variable::Variable( Variable::Type type,
+ const QString& name,
+ const QString& initialValue,
+ Variable::Increment increment,
+ const QString& stepSize )
+ : mType(type),
+ mName(name),
+ mInitialValue(initialValue),
+ mIncrement(increment),
+ mStepSize(stepSize),
+ mIntegerValue(0),
+ mIntegerStep(0),
+ mFloatingPointValue(0),
+ mFloatingPointStep(0)
+ {
+ resetValue();
+ }
+
+
+ Variable::Type Variable::type() const
+ {
+ return mType;
+ }
+
+
+ QString Variable::name() const
+ {
+ return mName;
+ }
+
+
+ QString Variable::initialValue() const
+ {
+ return mInitialValue;
+ }
+
+
+ Variable::Increment Variable::increment() const
+ {
+ return mIncrement;
+ }
+
+
+ QString Variable::stepSize() const
+ {
+ return mStepSize;
+ }
+
+
+ void Variable::resetValue()
+ {
+ switch (mType)
+ {
+ case Type::STRING:
+ // do nothing
+ break;
+ case Type::INTEGER:
+ mIntegerValue = mInitialValue.toLongLong();
+ mIntegerStep = mStepSize.toLongLong();
+ break;
+ case Type::FLOATING_POINT:
+ mFloatingPointValue = mInitialValue.toDouble();
+ mFloatingPointStep = mStepSize.toDouble();
+ break;
+ case Type::COLOR:
+ // do nothing
+ break;
+ }
+ }
+
+
+ void Variable::incrementValueOnItem()
+ {
+ if ( mIncrement == Increment::PER_ITEM )
+ {
+ switch (mType)
+ {
+ case Type::STRING:
+ // do nothing
+ break;
+ case Type::INTEGER:
+ mIntegerValue += mIntegerStep;
+ break;
+ case Type::FLOATING_POINT:
+ mFloatingPointValue += mFloatingPointStep;
+ break;
+ case Type::COLOR:
+ // do nothing
+ break;
+ }
+ }
+ }
+
+
+ void Variable::incrementValueOnCopy()
+ {
+ if ( mIncrement == Increment::PER_COPY )
+ {
+ switch (mType)
+ {
+ case Type::STRING:
+ // do nothing
+ break;
+ case Type::INTEGER:
+ mIntegerValue += mIntegerStep;
+ break;
+ case Type::FLOATING_POINT:
+ mFloatingPointValue += mFloatingPointStep;
+ break;
+ case Type::COLOR:
+ // do nothing
+ break;
+ }
+ }
+ }
+
+
+ void Variable::incrementValueOnPage()
+ {
+ if ( mIncrement == Increment::PER_PAGE )
+ {
+ switch (mType)
+ {
+ case Type::STRING:
+ // do nothing
+ break;
+ case Type::INTEGER:
+ mIntegerValue += mIntegerStep;
+ break;
+ case Type::FLOATING_POINT:
+ mFloatingPointValue += mFloatingPointStep;
+ break;
+ case Type::COLOR:
+ // do nothing
+ break;
+ }
+ }
+ }
+
+
+ QString Variable::value() const
+ {
+ switch (mType)
+ {
+ case Type::STRING:
+ return mInitialValue;
+ case Type::INTEGER:
+ return QString::number( mIntegerValue );
+ case Type::FLOATING_POINT:
+ return QString::number( mFloatingPointValue, 'g', 15 );
+ case Type::COLOR:
+ return mInitialValue;
+ default:
+ return mInitialValue;
+ }
+ }
+
+
+ QString Variable::typeToI18nString( Type type )
+ {
+ switch (type)
+ {
+ case Type::STRING:
+ return tr("String");
+ case Type::INTEGER:
+ return tr("Integer");
+ case Type::FLOATING_POINT:
+ return tr("Floating Point");
+ case Type::COLOR:
+ return tr("Color");
+ default:
+ return tr("String");
+ }
+ }
+
+
+ QString Variable::typeToIdString( Type type )
+ {
+ switch (type)
+ {
+ case Type::STRING:
+ return "string";
+ case Type::INTEGER:
+ return "integer";
+ case Type::FLOATING_POINT:
+ return "float";
+ case Type::COLOR:
+ return "color";
+ default:
+ return "string";
+ }
+ }
+
+
+ Variable::Type Variable::idStringToType( const QString& id )
+ {
+ if ( id == "string" )
+ {
+ return Type::STRING;
+ }
+ else if ( id == "integer" )
+ {
+ return Type::INTEGER;
+ }
+ else if ( id == "float" )
+ {
+ return Type::FLOATING_POINT;
+ }
+ if ( id == "color" )
+ {
+ return Type::COLOR;
+ }
+ else
+ {
+ return Type::STRING; // Default
+ }
+ }
+
+
+ QString Variable::incrementToI18nString( Increment increment )
+ {
+ switch (increment)
+ {
+ case Increment::NEVER:
+ return tr("Never");
+ case Increment::PER_ITEM:
+ return tr("Per item");
+ case Increment::PER_COPY:
+ return tr("Per copy");
+ case Increment::PER_PAGE:
+ return tr("Per page");
+ default:
+ return tr("Never");
+ }
+ }
+
+
+ QString Variable::incrementToIdString( Increment increment )
+ {
+ switch (increment)
+ {
+ case Increment::NEVER:
+ return "never";
+ case Increment::PER_ITEM:
+ return "per_item";
+ case Increment::PER_COPY:
+ return "per_copy";
+ case Increment::PER_PAGE:
+ return "per_page";
+ default:
+ return "never";
+ }
+ }
+
+
+ Variable::Increment Variable::idStringToIncrement( const QString& id )
+ {
+ if ( id == "never" )
+ {
+ return Increment::NEVER;
+ }
+ else if ( id == "per_item" )
+ {
+ return Increment::PER_ITEM;
+ }
+ else if ( id == "per_copy" )
+ {
+ return Increment::PER_COPY;
+ }
+ else if ( id == "per_page" )
+ {
+ return Increment::PER_PAGE;
+ }
+ else
+ {
+ return Increment::NEVER; // Default
+ }
+ }
+
+
+ }
+}
diff --git a/model/Variable.h b/model/Variable.h
new file mode 100644
index 0000000..c18f74f
--- /dev/null
+++ b/model/Variable.h
@@ -0,0 +1,107 @@
+/* Variable.h
+ *
+ * Copyright (C) 2019 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 model_Variable_h
+#define model_Variable_h
+
+
+#include
+#include
+
+
+namespace glabels
+{
+ namespace model
+ {
+
+ class Variable
+ {
+ Q_DECLARE_TR_FUNCTIONS(Variable)
+
+ public:
+ enum class Type
+ {
+ STRING,
+ INTEGER,
+ FLOATING_POINT,
+ COLOR
+ };
+
+ enum class Increment
+ {
+ NEVER,
+ PER_ITEM,
+ PER_COPY,
+ PER_PAGE
+ };
+
+
+ public:
+ Variable();
+
+ Variable( Type type,
+ const QString& name,
+ const QString& initialValue,
+ Increment increment = Increment::NEVER,
+ const QString& stepSize = "0" );
+
+ virtual ~Variable() = default;
+
+
+ Type type() const;
+ QString name() const;
+ QString initialValue() const;
+ Increment increment() const;
+ QString stepSize() const;
+
+ void resetValue();
+ void incrementValueOnItem();
+ void incrementValueOnCopy();
+ void incrementValueOnPage();
+ QString value() const;
+
+ static QString typeToI18nString( Type type );
+ static QString typeToIdString( Type type );
+ static Type idStringToType( const QString& string );
+
+ static QString incrementToI18nString( Increment increment );
+ static QString incrementToIdString( Increment increment );
+ static Increment idStringToIncrement( const QString& string );
+
+
+ private:
+ Type mType;
+ QString mName;
+ QString mInitialValue;
+ Increment mIncrement;
+ QString mStepSize;
+
+ long long mIntegerValue;
+ long long mIntegerStep;
+ double mFloatingPointValue;
+ double mFloatingPointStep;
+
+ };
+
+ }
+}
+
+
+#endif // model_Variable_h
diff --git a/model/Variables.cpp b/model/Variables.cpp
new file mode 100644
index 0000000..03fa927
--- /dev/null
+++ b/model/Variables.cpp
@@ -0,0 +1,138 @@
+/* Variables.cpp
+ *
+ * Copyright (C) 2013-2016 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 "Variables.h"
+
+#include
+
+
+namespace glabels
+{
+ namespace model
+ {
+ ///
+ /// Copy constructor
+ ///
+ Variables::Variables( const Variables* variables )
+ : QMap(*variables)
+ {
+ }
+
+
+ ///
+ /// Clone
+ ///
+ Variables* Variables::clone() const
+ {
+ return new Variables( this );
+ }
+
+
+ ///
+ /// Do we have variable?
+ ///
+ bool Variables::hasVariable( const QString& name ) const
+ {
+ return contains(name);
+ }
+
+
+ ///
+ /// Add variable ( will replace if name is the same )
+ ///
+ void Variables::addVariable( const Variable& variable )
+ {
+ insert( variable.name(), variable );
+ emit changed();
+ }
+
+
+ ///
+ /// Delete variable
+ ///
+ void Variables::deleteVariable( const QString& name )
+ {
+ remove( name );
+ emit changed();
+ }
+
+
+ ///
+ /// Replace variable
+ ///
+ void Variables::replaceVariable( const QString& origName, const Variable& variable )
+ {
+ remove( origName );
+ insert( variable.name(), variable );
+ emit changed();
+ }
+
+
+ ///
+ /// Reset variables to their initial values
+ ///
+ void Variables::resetVariables()
+ {
+ for ( auto& v : *this )
+ {
+ v.resetValue();
+ }
+ }
+
+
+ ///
+ /// Increment variables on item
+ ///
+ void Variables::incrementVariablesOnItem()
+ {
+ for ( auto& v : *this )
+ {
+ v.incrementValueOnItem();
+ }
+ }
+
+
+ ///
+ /// Increment variables on copy
+ ///
+ void Variables::incrementVariablesOnCopy()
+ {
+ for ( auto& v : *this )
+ {
+ v.incrementValueOnCopy();
+ }
+ }
+
+
+ ///
+ /// Increment variables on page
+ ///
+ void Variables::incrementVariablesOnPage()
+ {
+ for ( auto& v : *this )
+ {
+ v.incrementValueOnPage();
+ }
+ }
+
+
+ } // namespace model
+
+} // namespace glabels
diff --git a/model/Variables.h b/model/Variables.h
new file mode 100644
index 0000000..379d56f
--- /dev/null
+++ b/model/Variables.h
@@ -0,0 +1,90 @@
+/* Variables.h
+ *
+ * Copyright (C) 2013-2016 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 model_Variables_h
+#define model_Variables_h
+
+
+#include "Variable.h"
+
+#include
+#include
+#include
+
+
+namespace glabels
+{
+ namespace model
+ {
+
+ ///
+ /// Variables Collection
+ ///
+ class Variables : public QObject, public QMap
+ {
+ Q_OBJECT
+
+ /////////////////////////////////
+ // Life Cycle
+ /////////////////////////////////
+ public:
+ Variables() = default;
+ Variables( const Variables* variables );
+
+
+ /////////////////////////////////
+ // Object duplication
+ /////////////////////////////////
+ Variables* clone() const;
+
+
+ /////////////////////////////////
+ // Methods
+ /////////////////////////////////
+ bool hasVariable( const QString& name ) const;
+ void addVariable( const Variable& variable );
+ void deleteVariable( const QString& name );
+ void replaceVariable( const QString& name, const Variable& variable );
+
+ void resetVariables();
+ void incrementVariablesOnItem();
+ void incrementVariablesOnCopy();
+ void incrementVariablesOnPage();
+
+
+ /////////////////////////////////
+ // Signals
+ /////////////////////////////////
+ signals:
+ void changed();
+
+
+ /////////////////////////////////
+ // Private data
+ /////////////////////////////////
+ private:
+
+ };
+
+ }
+}
+
+
+#endif // model_Variables_h
diff --git a/model/Version.h.in b/model/Version.h.in
index b9cf033..0444361 100644
--- a/model/Version.h.in
+++ b/model/Version.h.in
@@ -37,6 +37,7 @@ namespace glabels
const int MICRO = @glabels-qt_VERSION_PATCH@;
const QString STRING = "@VERSION_STRING@";
+ const QString LONG_STRING = "@LONG_VERSION_STRING@";
}
}
diff --git a/model/XmlLabelCreator.cpp b/model/XmlLabelCreator.cpp
index 87b3114..b7f7cc9 100644
--- a/model/XmlLabelCreator.cpp
+++ b/model/XmlLabelCreator.cpp
@@ -29,9 +29,12 @@
#include "ModelImageObject.h"
#include "ModelTextObject.h"
#include "DataCache.h"
+#include "FileUtil.h"
+#include "Variables.h"
#include "XmlTemplateCreator.h"
#include "XmlUtil.h"
+#include "merge/Factory.h"
#include "merge/None.h"
#include
@@ -48,38 +51,41 @@ namespace glabels
{
void
- XmlLabelCreator::writeFile( const Model* label, const QString& fileName )
+ XmlLabelCreator::writeFile( Model* model, const QString& fileName )
{
- QDomDocument doc;
-
- createDoc( doc, label );
- QByteArray buffer = doc.toByteArray( 2 );
-
QFile file( fileName );
-
if ( !file.open( QFile::WriteOnly | QFile::Text) )
{
qWarning() << "Error: Cannot write file " << fileName
<< ": " << file.errorString();
+ return;
}
+ model->setFileName( fileName );
+ model->clearModified();
+
+ QDomDocument doc;
+ createDoc( doc, model );
+
+ QByteArray buffer = doc.toByteArray( 2 );
file.write( buffer.data(), buffer.size() );
}
void
- XmlLabelCreator::writeBuffer( const Model* label, QByteArray& buffer )
+ XmlLabelCreator::writeBuffer( const Model* model, QByteArray& buffer )
{
QDomDocument doc;
- createDoc( doc, label );
+ createDoc( doc, model );
buffer = doc.toByteArray( 2 );
}
void
XmlLabelCreator::serializeObjects( const QList& objects,
- QByteArray& buffer )
+ const Model* model,
+ QByteArray& buffer )
{
QDomDocument doc;
@@ -90,15 +96,15 @@ namespace glabels
doc.appendChild( root );
XmlUtil::setStringAttr( root, "version", "4.0" );
- createDataNode( root, objects );
- createObjectsNode( root, objects, false );
+ createDataNode( root, model, objects );
+ createObjectsNode( root, model, objects, false );
buffer = doc.toByteArray( 2 );
}
void
- XmlLabelCreator::createDoc( QDomDocument& doc, const Model* label )
+ XmlLabelCreator::createDoc( QDomDocument& doc, const Model* model )
{
QDomNode xmlNode( doc.createProcessingInstruction( "xml", "version=\"1.0\"" ) );
doc.appendChild( xmlNode );
@@ -107,21 +113,29 @@ namespace glabels
doc.appendChild( root );
XmlUtil::setStringAttr( root, "version", "4.0" );
- XmlTemplateCreator().createTemplateNode( root, label->tmplate() );
+ XmlTemplateCreator().createTemplateNode( root, model->tmplate() );
- createObjectsNode( root, label->objectList(), label->rotate() );
+ createObjectsNode( root, model, model->objectList(), model->rotate() );
- if ( label->merge() && !dynamic_cast(label->merge()) )
+ if ( model->merge() && !dynamic_cast(model->merge()) )
{
- createMergeNode( root, label );
+ createMergeNode( root, model );
}
- createDataNode( root, label->objectList() );
+ if ( model->variables()->size() != 0 )
+ {
+ createVariablesNode( root, model );
+ }
+
+ createDataNode( root, model, model->objectList() );
}
void
- XmlLabelCreator::createObjectsNode( QDomElement &parent, const QList& objects, bool rotate )
+ XmlLabelCreator::createObjectsNode( QDomElement& parent,
+ const Model* model,
+ const QList& objects,
+ bool rotate )
{
QDomDocument doc = parent.ownerDocument();
QDomElement node = doc.createElement( "Objects" );
@@ -146,7 +160,7 @@ namespace glabels
}
else if ( auto* imageObject = dynamic_cast(object) )
{
- createObjectImageNode( node, imageObject );
+ createObjectImageNode( node, model, imageObject );
}
else if ( auto* barcodeObject = dynamic_cast(object) )
{
@@ -244,7 +258,9 @@ namespace glabels
void
- XmlLabelCreator::createObjectImageNode( QDomElement &parent, const ModelImageObject* object )
+ XmlLabelCreator::createObjectImageNode( QDomElement& parent,
+ const Model* model,
+ const ModelImageObject* object )
{
QDomDocument doc = parent.ownerDocument();
QDomElement node = doc.createElement( "Object-image" );
@@ -263,7 +279,8 @@ namespace glabels
}
else
{
- XmlUtil::setStringAttr( node, "src", object->filenameNode().data() );
+ QString fn = FileUtil::makeRelativeIfInDir( model->dir(), object->filenameNode().data() );
+ XmlUtil::setStringAttr( node, "src", fn );
}
/* affine attrs */
@@ -384,6 +401,7 @@ namespace glabels
{
XmlUtil::setLengthAttr( node, "w", object->w() );
XmlUtil::setLengthAttr( node, "h", object->h() );
+ XmlUtil::setBoolAttr( node, "lock_aspect_ratio", object->lockAspectRatio() );
}
@@ -433,41 +451,99 @@ namespace glabels
void
XmlLabelCreator::createShadowAttrs( QDomElement &node, const ModelObject* object )
{
- if ( object->shadow() )
+ XmlUtil::setBoolAttr( node, "shadow", object->shadow() );
+
+ XmlUtil::setLengthAttr( node, "shadow_x", object->shadowX() );
+ XmlUtil::setLengthAttr( node, "shadow_y", object->shadowY() );
+
+ if ( object->fillColorNode().isField() )
{
- XmlUtil::setBoolAttr( node, "shadow", object->shadow() );
-
- XmlUtil::setLengthAttr( node, "shadow_x", object->shadowX() );
- XmlUtil::setLengthAttr( node, "shadow_y", object->shadowY() );
-
- if ( object->fillColorNode().isField() )
- {
- XmlUtil::setStringAttr( node, "shadow_color_field", object->shadowColorNode().key() );
- }
- else
- {
- XmlUtil::setUIntAttr( node, "shadow_color", object->shadowColorNode().rgba() );
- }
-
- XmlUtil::setDoubleAttr( node, "shadow_opacity", object->shadowOpacity() );
+ XmlUtil::setStringAttr( node, "shadow_color_field", object->shadowColorNode().key() );
}
+ else
+ {
+ XmlUtil::setUIntAttr( node, "shadow_color", object->shadowColorNode().rgba() );
+ }
+
+ XmlUtil::setDoubleAttr( node, "shadow_opacity", object->shadowOpacity() );
}
void
- XmlLabelCreator::createMergeNode( QDomElement &parent, const Model* label )
+ XmlLabelCreator::createMergeNode( QDomElement &parent, const Model* model )
{
QDomDocument doc = parent.ownerDocument();
QDomElement node = doc.createElement( "Merge" );
parent.appendChild( node );
- XmlUtil::setStringAttr( node, "type", label->merge()->id() );
- XmlUtil::setStringAttr( node, "src", label->merge()->source() );
+ QString id = model->merge()->id();
+ QString src = model->merge()->source();
+
+ XmlUtil::setStringAttr( node, "type", id );
+
+ switch ( merge::Factory::idToType( id ) )
+ {
+ case merge::Factory::NONE:
+ case merge::Factory::FIXED:
+ break;
+
+ case merge::Factory::FILE:
+ {
+ QString fn = FileUtil::makeRelativeIfInDir( model->dir(), src );
+ XmlUtil::setStringAttr( node, "src", fn );
+ }
+ break;
+
+ default:
+ qWarning() << "XmlLabelCreator::createMergeNode(): Should not be reached!";
+ break;
+ }
}
void
- XmlLabelCreator::createDataNode( QDomElement &parent, const QList& objects )
+ XmlLabelCreator::createVariablesNode( QDomElement &parent, const Model* model )
+ {
+ QDomDocument doc = parent.ownerDocument();
+ QDomElement node = doc.createElement( "Variables" );
+ parent.appendChild( node );
+
+ for ( const auto& v : *model->variables() )
+ {
+ createVariableNode( node, v );
+ }
+ }
+
+
+ void
+ XmlLabelCreator::createVariableNode( QDomElement &parent, const Variable& v )
+ {
+ QDomDocument doc = parent.ownerDocument();
+ QDomElement node = doc.createElement( "Variable" );
+ parent.appendChild( node );
+
+ XmlUtil::setStringAttr( node, "type", Variable::typeToIdString( v.type() ) );
+ XmlUtil::setStringAttr( node, "name", v.name() );
+ XmlUtil::setStringAttr( node, "initialValue", v.initialValue() );
+
+ if ( (v.type() == Variable::Type::INTEGER) ||
+ (v.type() == Variable::Type::FLOATING_POINT) )
+ {
+ XmlUtil::setStringAttr( node, "increment",
+ Variable::incrementToIdString( v.increment() ) );
+
+ if ( v.increment() != Variable::Increment::NEVER )
+ {
+ XmlUtil::setStringAttr( node, "stepSize", v.stepSize() );
+ }
+ }
+ }
+
+
+ void
+ XmlLabelCreator::createDataNode( QDomElement& parent,
+ const Model* model,
+ const QList& objects )
{
QDomDocument doc = parent.ownerDocument();
QDomElement node = doc.createElement( "Data" );
@@ -477,12 +553,14 @@ namespace glabels
foreach ( QString name, data.imageNames() )
{
- createPngFileNode( node, name, data.getImage( name ) );
+ QString fn = FileUtil::makeRelativeIfInDir( model->dir(), name );
+ createPngFileNode( node, fn, data.getImage( name ) );
}
foreach ( QString name, data.svgNames() )
{
- createSvgFileNode( node, name, data.getSvg( name ) );
+ QString fn = FileUtil::makeRelativeIfInDir( model->dir(), name );
+ createSvgFileNode( node, fn, data.getSvg( name ) );
}
}
@@ -521,7 +599,5 @@ namespace glabels
node.appendChild( doc.createCDATASection( QString( svg ) ) );
}
-
-
}
}
diff --git a/model/XmlLabelCreator.h b/model/XmlLabelCreator.h
index 93c235e..9c765ac 100644
--- a/model/XmlLabelCreator.h
+++ b/model/XmlLabelCreator.h
@@ -40,6 +40,7 @@ namespace glabels
class ModelImageObject;
class ModelBarcodeObject;
class ModelTextObject;
+ class Variable;
///
@@ -50,31 +51,87 @@ namespace glabels
Q_OBJECT
public:
- static void writeFile( const Model* label, const QString& fileName );
- static void writeBuffer( const Model* label, QByteArray& buffer );
- static void serializeObjects( const QList& objects, QByteArray& buffer );
+ static void writeFile( Model* model,
+ const QString& fileName );
+
+ static void writeBuffer( const Model* model,
+ QByteArray& buffer );
+
+ static void serializeObjects( const QList& objects,
+ const Model* model,
+ QByteArray& buffer );
private:
- static void createDoc( QDomDocument& doc, const Model* label );
- static void createRootNode( const Model* label );
- static void createObjectsNode( QDomElement &parent, const QList& objects, bool rotate );
- static void createObjectBoxNode( QDomElement &parent, const ModelBoxObject* object );
- static void createObjectEllipseNode( QDomElement &parent, const ModelEllipseObject* object );
- static void createObjectLineNode( QDomElement &parent, const ModelLineObject* object );
- static void createObjectImageNode( QDomElement &parent, const ModelImageObject* object );
- static void createObjectBarcodeNode( QDomElement &parent, const ModelBarcodeObject* object );
- static void createObjectTextNode( QDomElement &parent, const ModelTextObject* object );
- static void createPNode( QDomElement &parent, const QString& blockText );
- static void createPositionAttrs( QDomElement &node, const ModelObject* object );
- static void createSizeAttrs( QDomElement &node, const ModelObject* object );
- static void createLineAttrs( QDomElement &node, const ModelObject* object );
- static void createFillAttrs( QDomElement &node, const ModelObject* object );
- static void createAffineAttrs( QDomElement &node, const ModelObject* object );
- static void createShadowAttrs( QDomElement &node, const ModelObject* object );
- static void createMergeNode( QDomElement &parent, const Model* label );
- static void createDataNode( QDomElement &parent, const QList& objects );
- static void createPngFileNode( QDomElement &parent, const QString& name, const QImage& image );
- static void createSvgFileNode( QDomElement &parent, const QString& name, const QByteArray& svg );
+ static void createDoc( QDomDocument& doc,
+ const Model* model );
+
+ static void createRootNode( const Model* model );
+
+ static void createObjectsNode( QDomElement& parent,
+ const Model* model,
+ const QList& objects,
+ bool rotate );
+
+ static void createObjectBoxNode( QDomElement& parent,
+ const ModelBoxObject* object );
+
+ static void createObjectEllipseNode( QDomElement& parent,
+ const ModelEllipseObject* object );
+
+ static void createObjectLineNode( QDomElement& parent,
+ const ModelLineObject* object );
+
+ static void createObjectImageNode( QDomElement& parent,
+ const Model* model,
+ const ModelImageObject* object );
+
+ static void createObjectBarcodeNode( QDomElement& parent,
+ const ModelBarcodeObject* object );
+
+ static void createObjectTextNode( QDomElement& parent,
+ const ModelTextObject* object );
+
+ static void createPNode( QDomElement& parent,
+ const QString& blockText );
+
+ static void createPositionAttrs( QDomElement& node,
+ const ModelObject* object );
+
+ static void createSizeAttrs( QDomElement& node,
+ const ModelObject* object );
+
+ static void createLineAttrs( QDomElement& node,
+ const ModelObject* object );
+
+ static void createFillAttrs( QDomElement& node,
+ const ModelObject* object );
+
+ static void createAffineAttrs( QDomElement& node,
+ const ModelObject* object );
+
+ static void createShadowAttrs( QDomElement& node,
+ const ModelObject* object );
+
+ static void createMergeNode( QDomElement& parent,
+ const Model* model );
+
+ static void createVariablesNode( QDomElement& parent,
+ const Model* model );
+
+ static void createVariableNode( QDomElement& parent,
+ const Variable& v );
+
+ static void createDataNode( QDomElement& parent,
+ const Model* model,
+ const QList& objects );
+
+ static void createPngFileNode( QDomElement& parent,
+ const QString& name,
+ const QImage& image );
+
+ static void createSvgFileNode( QDomElement& parent,
+ const QString& name,
+ const QByteArray& svg );
};
diff --git a/model/XmlLabelParser.cpp b/model/XmlLabelParser.cpp
index 779149c..fce0f2d 100644
--- a/model/XmlLabelParser.cpp
+++ b/model/XmlLabelParser.cpp
@@ -105,7 +105,7 @@ namespace glabels
return nullptr;
}
- return parseRootNode( root );
+ return parseRootNode( root, fileName );
}
@@ -132,12 +132,12 @@ namespace glabels
return nullptr;
}
- return parseRootNode( root );
+ return parseRootNode( root, QString() );
}
QList
- XmlLabelParser::deserializeObjects( const QByteArray& buffer )
+ XmlLabelParser::deserializeObjects( const QByteArray& buffer, const Model* model )
{
QList list;
@@ -167,7 +167,7 @@ namespace glabels
{
if ( child.toElement().tagName() == "Data" )
{
- parseDataNode( child.toElement(), data );
+ parseDataNode( child.toElement(), model, data );
}
}
@@ -176,9 +176,10 @@ namespace glabels
{
if ( child.toElement().tagName() == "Objects" )
{
- list = parseObjectsNode( child.toElement(), data );
+ list = parseObjectsNode( child.toElement(), model, data );
}
}
+
return list;
}
@@ -236,16 +237,22 @@ namespace glabels
Model*
- XmlLabelParser::parseRootNode( const QDomElement &node )
+ XmlLabelParser::parseRootNode( const QDomElement &node, const QString& fileName )
{
QString version = XmlUtil::getStringAttr( node, "version", "" );
if ( version != "4.0" )
{
// Attempt to import as version 3.0 format (glabels 2.0 - glabels 3.4)
- return XmlLabelParser_3::parseRootNode(node);
+ auto* model = XmlLabelParser_3::parseRootNode( node );
+ if ( model )
+ {
+ model->setFileName( fileName );
+ }
+ return model;
}
- auto* label = new Model();
+ auto* model = new Model();
+ model->setFileName( fileName );
/* Pass 1, extract data nodes to pre-load cache. */
DataCache data;
@@ -253,7 +260,7 @@ namespace glabels
{
if ( child.toElement().tagName() == "Data" )
{
- parseDataNode( child.toElement(), data );
+ parseDataNode( child.toElement(), model, data );
}
}
@@ -268,23 +275,28 @@ namespace glabels
if ( tmplate == nullptr )
{
qWarning() << "Unable to parse template";
- delete label;
+ delete model;
return nullptr;
}
- label->setTmplate( tmplate );
+ model->setTmplate( tmplate ); // Copies arg
+ delete tmplate;
}
else if ( tagName == "Objects" )
{
- label->setRotate( parseRotateAttr( child.toElement() ) );
- QList list = parseObjectsNode( child.toElement(), data );
+ model->setRotate( parseRotateAttr( child.toElement() ) );
+ auto list = parseObjectsNode( child.toElement(), model, data );
foreach ( ModelObject* object, list )
{
- label->addObject( object );
+ model->addObject( object );
}
}
else if ( tagName == "Merge" )
{
- parseMergeNode( child.toElement(), label );
+ parseMergeNode( child.toElement(), model );
+ }
+ else if ( tagName == "Variables" )
+ {
+ parseVariablesNode( child.toElement(), model );
}
else if ( tagName == "Data" )
{
@@ -296,13 +308,15 @@ namespace glabels
}
}
- label->clearModified();
- return label;
+ model->clearModified();
+ return model;
}
QList
- XmlLabelParser::parseObjectsNode( const QDomElement &node, const DataCache& data )
+ XmlLabelParser::parseObjectsNode( const QDomElement& node,
+ const Model* model,
+ const DataCache& data )
{
QList list;
@@ -328,7 +342,7 @@ namespace glabels
}
else if ( tagName == "Object-image" )
{
- list.append( parseObjectImageNode( child.toElement(), data ) );
+ list.append( parseObjectImageNode( child.toElement(), model, data ) );
}
else if ( tagName == "Object-barcode" )
{
@@ -354,19 +368,20 @@ namespace glabels
/* size attrs */
Distance w = XmlUtil::getLengthAttr( node, "w", 0 );
Distance h = XmlUtil::getLengthAttr( node, "h", 0 );
+ bool lockAspectRatio = XmlUtil::getBoolAttr( node, "lock_aspect_ratio", false );
/* line attrs */
Distance lineWidth = XmlUtil::getLengthAttr( node, "line_width", 1.0 );
QString key = XmlUtil::getStringAttr( node, "line_color_field", "" );
bool field_flag = !key.isEmpty();
- uint32_t color = XmlUtil::getUIntAttr( node, "line_color", 0 );
+ uint32_t color = XmlUtil::getUIntAttr( node, "line_color", 0xFF );
ColorNode lineColorNode( field_flag, color, key );
/* fill attrs */
key = XmlUtil::getStringAttr( node, "fill_color_field", "" );
field_flag = !key.isEmpty();
- color = XmlUtil::getUIntAttr( node, "fill_color", 0 );
+ color = XmlUtil::getUIntAttr( node, "fill_color", 0xFF );
ColorNode fillColorNode( field_flag, color, key );
/* affine attrs */
@@ -386,10 +401,10 @@ namespace glabels
key = XmlUtil::getStringAttr( node, "shadow_color_field", "" );
field_flag = !key.isEmpty();
- color = XmlUtil::getUIntAttr( node, "shadow_color", 0 );
+ color = XmlUtil::getUIntAttr( node, "shadow_color", 0xFF );
ColorNode shadowColorNode( field_flag, color, key );
- return new ModelBoxObject( x0, y0, w, h,
+ return new ModelBoxObject( x0, y0, w, h, lockAspectRatio,
lineWidth, lineColorNode,
fillColorNode,
QMatrix( a[0], a[1], a[2], a[3], a[4], a[5] ),
@@ -407,19 +422,20 @@ namespace glabels
/* size attrs */
Distance w = XmlUtil::getLengthAttr( node, "w", 0 );
Distance h = XmlUtil::getLengthAttr( node, "h", 0 );
+ bool lockAspectRatio = XmlUtil::getBoolAttr( node, "lock_aspect_ratio", false );
/* line attrs */
Distance lineWidth = XmlUtil::getLengthAttr( node, "line_width", 1.0 );
QString key = XmlUtil::getStringAttr( node, "line_color_field", "" );
bool field_flag = !key.isEmpty();
- uint32_t color = XmlUtil::getUIntAttr( node, "line_color", 0 );
+ uint32_t color = XmlUtil::getUIntAttr( node, "line_color", 0xFF );
ColorNode lineColorNode( field_flag, color, key );
/* fill attrs */
key = XmlUtil::getStringAttr( node, "fill_color_field", "" );
field_flag = !key.isEmpty();
- color = XmlUtil::getUIntAttr( node, "fill_color", 0 );
+ color = XmlUtil::getUIntAttr( node, "fill_color", 0xFF );
ColorNode fillColorNode( field_flag, color, key );
/* affine attrs */
@@ -439,10 +455,10 @@ namespace glabels
key = XmlUtil::getStringAttr( node, "shadow_color_field", "" );
field_flag = !key.isEmpty();
- color = XmlUtil::getUIntAttr( node, "shadow_color", 0 );
+ color = XmlUtil::getUIntAttr( node, "shadow_color", 0xFF );
ColorNode shadowColorNode( field_flag, color, key );
- return new ModelEllipseObject( x0, y0, w, h,
+ return new ModelEllipseObject( x0, y0, w, h, lockAspectRatio,
lineWidth, lineColorNode,
fillColorNode,
QMatrix( a[0], a[1], a[2], a[3], a[4], a[5] ),
@@ -466,7 +482,7 @@ namespace glabels
QString key = XmlUtil::getStringAttr( node, "line_color_field", "" );
bool field_flag = !key.isEmpty();
- uint32_t color = XmlUtil::getUIntAttr( node, "line_color", 0 );
+ uint32_t color = XmlUtil::getUIntAttr( node, "line_color", 0xFF );
ColorNode lineColorNode( field_flag, color, key );
/* affine attrs */
@@ -486,7 +502,7 @@ namespace glabels
key = XmlUtil::getStringAttr( node, "shadow_color_field", "" );
field_flag = !key.isEmpty();
- color = XmlUtil::getUIntAttr( node, "shadow_color", 0 );
+ color = XmlUtil::getUIntAttr( node, "shadow_color", 0xFF );
ColorNode shadowColorNode( field_flag, color, key );
return new ModelLineObject( x0, y0, dx, dy,
@@ -497,7 +513,9 @@ namespace glabels
ModelImageObject*
- XmlLabelParser::parseObjectImageNode( const QDomElement &node, const DataCache& data )
+ XmlLabelParser::parseObjectImageNode( const QDomElement& node,
+ const Model* model,
+ const DataCache& data )
{
/* position attrs */
Distance x0 = XmlUtil::getLengthAttr( node, "x", 0.0 );
@@ -506,6 +524,7 @@ namespace glabels
/* size attrs */
Distance w = XmlUtil::getLengthAttr( node, "w", 0 );
Distance h = XmlUtil::getLengthAttr( node, "h", 0 );
+ bool lockAspectRatio = XmlUtil::getBoolAttr( node, "lock_aspect_ratio", false );
/* file attrs */
QString key = XmlUtil::getStringAttr( node, "src_field", "" );
@@ -530,36 +549,42 @@ namespace glabels
key = XmlUtil::getStringAttr( node, "shadow_color_field", "" );
field_flag = !key.isEmpty();
- uint32_t color = XmlUtil::getUIntAttr( node, "shadow_color", 0 );
+ uint32_t color = XmlUtil::getUIntAttr( node, "shadow_color", 0xFF );
ColorNode shadowColorNode( field_flag, color, key );
if ( filenameNode.isField() )
{
- return new ModelImageObject( x0, y0, w, h,
+ return new ModelImageObject( x0, y0, w, h, lockAspectRatio,
filenameNode,
QMatrix( a[0], a[1], a[2], a[3], a[4], a[5] ),
shadowState, shadowX, shadowY, shadowOpacity, shadowColorNode );
}
else
{
- if ( data.hasImage( filename ) )
+ QString fn = QDir::cleanPath( model->dir().absoluteFilePath( filename ) );
+
+ if ( data.hasImage( fn ) )
{
- return new ModelImageObject( x0, y0, w, h,
- filename, data.getImage( filename ),
+ return new ModelImageObject( x0, y0, w, h, lockAspectRatio,
+ filename, data.getImage( fn ),
QMatrix( a[0], a[1], a[2], a[3], a[4], a[5] ),
shadowState, shadowX, shadowY, shadowOpacity, shadowColorNode );
}
- else if ( data.hasSvg( filename ) )
+ else if ( data.hasSvg( fn ) )
{
- return new ModelImageObject( x0, y0, w, h,
- filename, data.getSvg( filename ),
+ return new ModelImageObject( x0, y0, w, h, lockAspectRatio,
+ filename, data.getSvg( fn ),
QMatrix( a[0], a[1], a[2], a[3], a[4], a[5] ),
shadowState, shadowX, shadowY, shadowOpacity, shadowColorNode );
}
else
{
- qWarning() << "Embedded file" << filename << "missing. Trying actual file.";
- return new ModelImageObject( x0, y0, w, h,
+ if ( !filename.isEmpty() )
+ {
+ qWarning() << "Embedded file" << fn << "missing. Trying actual file.";
+ filenameNode.setData( fn );
+ }
+ return new ModelImageObject( x0, y0, w, h, lockAspectRatio,
filenameNode,
QMatrix( a[0], a[1], a[2], a[3], a[4], a[5] ),
shadowState, shadowX, shadowY, shadowOpacity, shadowColorNode );
@@ -578,6 +603,7 @@ namespace glabels
/* size attrs */
Distance w = XmlUtil::getLengthAttr( node, "w", 0 );
Distance h = XmlUtil::getLengthAttr( node, "h", 0 );
+ bool lockAspectRatio = XmlUtil::getBoolAttr( node, "lock_aspect_ratio", false );
/* barcode attrs */
barcode::Style bcStyle = barcode::Backends::style( XmlUtil::getStringAttr( node, "backend", "" ),
@@ -587,7 +613,7 @@ namespace glabels
QString key = XmlUtil::getStringAttr( node, "color_field", "" );
bool field_flag = !key.isEmpty();
- uint32_t color = XmlUtil::getUIntAttr( node, "color", 0 );
+ uint32_t color = XmlUtil::getUIntAttr( node, "color", 0xFF );
ColorNode bcColorNode( field_flag, color, key );
QString bcData = XmlUtil::getStringAttr( node, "data", "" );
@@ -601,7 +627,7 @@ namespace glabels
a[4] = XmlUtil::getDoubleAttr( node, "a4", 0.0 );
a[5] = XmlUtil::getDoubleAttr( node, "a5", 0.0 );
- return new ModelBarcodeObject( x0, y0, w, h,
+ return new ModelBarcodeObject( x0, y0, w, h, lockAspectRatio,
bcStyle, bcTextFlag, bcChecksumFlag, bcData, bcColorNode,
QMatrix( a[0], a[1], a[2], a[3], a[4], a[5] ) );
}
@@ -617,11 +643,12 @@ namespace glabels
/* size attrs */
Distance w = XmlUtil::getLengthAttr( node, "w", 0 );
Distance h = XmlUtil::getLengthAttr( node, "h", 0 );
+ bool lockAspectRatio = XmlUtil::getBoolAttr( node, "lock_aspect_ratio", false );
/* color attr */
QString key = XmlUtil::getStringAttr( node, "color_field", "" );
bool field_flag = !key.isEmpty();
- uint32_t color = XmlUtil::getUIntAttr( node, "color", 0 );
+ uint32_t color = XmlUtil::getUIntAttr( node, "color", 0xFF );
ColorNode textColorNode( field_flag, color, key );
/* font attrs */
@@ -655,7 +682,7 @@ namespace glabels
key = XmlUtil::getStringAttr( node, "shadow_color_field", "" );
field_flag = !key.isEmpty();
- color = XmlUtil::getUIntAttr( node, "shadow_color", 0 );
+ color = XmlUtil::getUIntAttr( node, "shadow_color", 0xFF );
ColorNode shadowColorNode( field_flag, color, key );
/* deserialize contents. */
@@ -682,7 +709,7 @@ namespace glabels
}
QString text = document.toPlainText();
- return new ModelTextObject( x0, y0, w, h,
+ return new ModelTextObject( x0, y0, w, h, lockAspectRatio,
text,
fontFamily, fontSize, fontWeight, fontItalicFlag, fontUnderlineFlag,
textColorNode, textHAlign, textVAlign, textWrapMode, textLineSpacing,
@@ -707,28 +734,45 @@ namespace glabels
void
- XmlLabelParser::parseMergeNode( const QDomElement &node, Model* label )
+ XmlLabelParser::parseMergeNode( const QDomElement &node, Model* model )
{
- QString type = XmlUtil::getStringAttr( node, "type", "None" );
- QString src = XmlUtil::getStringAttr( node, "src", "" );
+ QString id = XmlUtil::getStringAttr( node, "type", "None" );
+ QString src = XmlUtil::getStringAttr( node, "src", "" );
- merge::Merge* merge = merge::Factory::createMerge( type );
- merge->setSource( src );
+ merge::Merge* merge = merge::Factory::createMerge( id );
- label->setMerge( merge );
+ switch ( merge::Factory::idToType( id ) )
+ {
+ case merge::Factory::NONE:
+ case merge::Factory::FIXED:
+ break;
+
+ case merge::Factory::FILE:
+ {
+ QString fn = QDir::cleanPath( model->dir().absoluteFilePath( src ) );
+ merge->setSource( fn );
+ }
+ break;
+
+ default:
+ qWarning() << "XmlLabelParser::parseMergeNode(): Should not be reached!";
+ break;
+ }
+
+ model->setMerge( merge );
}
void
- XmlLabelParser::parseDataNode( const QDomElement &node, DataCache& data )
+ XmlLabelParser::parseVariablesNode( const QDomElement &node, Model* model )
{
for ( QDomNode child = node.firstChild(); !child.isNull(); child = child.nextSibling() )
{
QString tagName = child.toElement().tagName();
- if ( tagName == "File" )
+ if ( tagName == "Variable" )
{
- parseFileNode( child.toElement(), data );
+ parseVariableNode( child.toElement(), model );
}
else if ( !child.isComment() )
{
@@ -739,19 +783,55 @@ namespace glabels
void
- XmlLabelParser::parsePixdataNode( const QDomElement& node, DataCache& data )
+ XmlLabelParser::parseVariableNode( const QDomElement &node, Model* model )
{
- // TODO, compatibility with glabels-3
+ QString typeString = XmlUtil::getStringAttr( node, "type", "string" );
+ QString name = XmlUtil::getStringAttr( node, "name", "unknown" );
+ QString initialValue = XmlUtil::getStringAttr( node, "initialValue", "0" );
+ QString incrementString = XmlUtil::getStringAttr( node, "increment", "never" );
+ QString stepSize = XmlUtil::getStringAttr( node, "stepSize", "0" );
+
+ auto type = Variable::idStringToType( typeString );
+ auto increment = Variable::idStringToIncrement( incrementString );
+
+ Variable v( type, name, initialValue, increment, stepSize );
+ model->variables()->addVariable( v );
}
void
- XmlLabelParser::parseFileNode( const QDomElement& node, DataCache& data )
+ XmlLabelParser::parseDataNode( const QDomElement &node,
+ const Model* model,
+ DataCache& data )
+ {
+ for ( QDomNode child = node.firstChild(); !child.isNull(); child = child.nextSibling() )
+ {
+ QString tagName = child.toElement().tagName();
+
+ if ( tagName == "File" )
+ {
+ parseFileNode( child.toElement(), model, data );
+ }
+ else if ( !child.isComment() )
+ {
+ qWarning() << "Unexpected" << node.tagName() << "child:" << tagName;
+ }
+ }
+ }
+
+
+ void
+ XmlLabelParser::parseFileNode( const QDomElement& node,
+ const Model* model,
+ DataCache& data )
{
QString name = XmlUtil::getStringAttr( node, "name", "" );
QString mimetype = XmlUtil::getStringAttr( node, "mimetype", "image/png" );
QString encoding = XmlUtil::getStringAttr( node, "encoding", "base64" );
+ // Rewrite name as absolute file path
+ QString fn = QDir::cleanPath( model->dir().absoluteFilePath( name ) );
+
if ( mimetype == "image/png" )
{
if ( encoding == "base64" )
@@ -761,7 +841,7 @@ namespace glabels
QImage image;
image.loadFromData( ba, "PNG" );
- data.addImage( name, image );
+ data.addImage( fn, image );
}
else
{
@@ -770,7 +850,7 @@ namespace glabels
}
else if ( mimetype == "image/svg+xml" )
{
- data.addSvg( name, node.text().toUtf8() );
+ data.addSvg( fn, node.text().toUtf8() );
}
}
diff --git a/model/XmlLabelParser.h b/model/XmlLabelParser.h
index f135860..93e90e8 100644
--- a/model/XmlLabelParser.h
+++ b/model/XmlLabelParser.h
@@ -52,25 +52,57 @@ namespace glabels
public:
static Model* readFile( const QString& fileName );
+
static Model* readBuffer( const QByteArray& buffer );
- static QList deserializeObjects( const QByteArray& buffer );
+
+ static QList deserializeObjects( const QByteArray& buffer,
+ const Model* model );
private:
- static void gunzip( const QByteArray& gzippedData, QByteArray& data );
- static Model* parseRootNode( const QDomElement &node );
- static QList parseObjectsNode( const QDomElement &node, const DataCache& data );
- static ModelBoxObject* parseObjectBoxNode( const QDomElement &node );
- static ModelEllipseObject* parseObjectEllipseNode( const QDomElement &node );
- static ModelLineObject* parseObjectLineNode( const QDomElement &node );
- static ModelImageObject* parseObjectImageNode( const QDomElement &node, const DataCache& data );
- static ModelBarcodeObject* parseObjectBarcodeNode( const QDomElement &node );
- static ModelTextObject* parseObjectTextNode( const QDomElement &node );
- static QString parsePNode( const QDomElement &node );
- static bool parseRotateAttr( const QDomElement &node );
- static void parseMergeNode( const QDomElement &node, Model* label );
- static void parseDataNode( const QDomElement &node, DataCache& data );
- static void parsePixdataNode( const QDomElement &node, DataCache& data );
- static void parseFileNode( const QDomElement &node, DataCache& data );
+ static void gunzip( const QByteArray& gzippedData,
+ QByteArray& data );
+
+ static Model* parseRootNode( const QDomElement& node,
+ const QString& fileName );
+
+ static QList parseObjectsNode( const QDomElement& node,
+ const Model* model,
+ const DataCache& data );
+
+ static ModelBoxObject* parseObjectBoxNode( const QDomElement& node );
+
+ static ModelEllipseObject* parseObjectEllipseNode( const QDomElement& node );
+
+ static ModelLineObject* parseObjectLineNode( const QDomElement& node );
+
+ static ModelImageObject* parseObjectImageNode( const QDomElement& node,
+ const Model* model,
+ const DataCache& data );
+
+ static ModelBarcodeObject* parseObjectBarcodeNode( const QDomElement& node );
+
+ static ModelTextObject* parseObjectTextNode( const QDomElement& node );
+
+ static QString parsePNode( const QDomElement& node );
+
+ static bool parseRotateAttr( const QDomElement& node );
+
+ static void parseMergeNode( const QDomElement& node,
+ Model* model );
+
+ static void parseVariablesNode( const QDomElement& node,
+ Model* model );
+
+ static void parseVariableNode( const QDomElement& node,
+ Model* model );
+
+ static void parseDataNode( const QDomElement& node,
+ const Model* model,
+ DataCache& data );
+
+ static void parseFileNode( const QDomElement& node,
+ const Model* model,
+ DataCache& data );
};
diff --git a/model/XmlLabelParser_3.cpp b/model/XmlLabelParser_3.cpp
index e2a442f..fe129d8 100644
--- a/model/XmlLabelParser_3.cpp
+++ b/model/XmlLabelParser_3.cpp
@@ -111,7 +111,8 @@ namespace glabels
delete label;
return nullptr;
}
- label->setTmplate( tmplate );
+ label->setTmplate( tmplate ); // Copies arg
+ delete tmplate;
}
else if ( tagName == "Objects" )
{
@@ -229,7 +230,7 @@ namespace glabels
color = XmlUtil::getUIntAttr( node, "shadow_color", 0 );
const ColorNode shadowColorNode( field_flag, color, key );
- return new ModelBoxObject( x0, y0, w, h,
+ return new ModelBoxObject( x0, y0, w, h, false /*lockAspectRatio*/,
lineWidth, lineColorNode,
fillColorNode,
affineTransformation,
@@ -276,7 +277,7 @@ namespace glabels
color = XmlUtil::getUIntAttr( node, "shadow_color", 0 );
const ColorNode shadowColorNode( field_flag, color, key );
- return new ModelEllipseObject( x0, y0, w, h,
+ return new ModelEllipseObject( x0, y0, w, h, false /*lockAspectRatio*/,
lineWidth, lineColorNode,
fillColorNode,
affineTransformation,
@@ -357,27 +358,27 @@ namespace glabels
if ( filenameNode.isField() )
{
- return new ModelImageObject( x0, y0, w, h,
+ return new ModelImageObject( x0, y0, w, h, false /*lockAspectRatio*/,
filenameNode,
affineTransformation,
shadowState, shadowX, shadowY, shadowOpacity, shadowColorNode );
}
if ( data.hasImage( filename ) )
{
- return new ModelImageObject( x0, y0, w, h,
+ return new ModelImageObject( x0, y0, w, h, false /*lockAspectRatio*/,
filename, data.getImage( filename ),
affineTransformation,
shadowState, shadowX, shadowY, shadowOpacity, shadowColorNode );
}
if ( data.hasSvg( filename ) )
{
- return new ModelImageObject( x0, y0, w, h,
+ return new ModelImageObject( x0, y0, w, h, false /*lockAspectRatio*/,
filename, data.getSvg( filename ),
affineTransformation,
shadowState, shadowX, shadowY, shadowOpacity, shadowColorNode );
}
qWarning() << "Embedded file" << filename << "missing. Trying actual file.";
- return new ModelImageObject( x0, y0, w, h,
+ return new ModelImageObject( x0, y0, w, h, false /*lockAspectRatio*/,
filenameNode,
affineTransformation,
shadowState, shadowX, shadowY, shadowOpacity, shadowColorNode );
@@ -396,10 +397,34 @@ namespace glabels
const Distance h = XmlUtil::getLengthAttr( node, "h", 0 );
/* barcode attrs */
- const auto backend = XmlUtil::getStringAttr( node, "backend", "");
+ auto backend = XmlUtil::getStringAttr( node, "backend", "" );
// one major difference between glabels-3.0.dtd and glabels-4.0.dtd
// is the lowercase of the style names
- const auto style = XmlUtil::getStringAttr( node, "style", "").toLower();
+ auto style = XmlUtil::getStringAttr( node, "style", "" ).toLower();
+
+ if ( backend == "built-in" )
+ {
+ backend = "";
+ }
+ else if ( backend == "libiec16022" )
+ {
+ backend = "";
+ style = "datamatrix";
+ }
+ else if ( backend == "libqrencode" )
+ {
+ if ( barcode::Backends::style( "qrencode", "qrcode" ) != barcode::Backends::defaultStyle() )
+ {
+ backend = "qrencode";
+ style = "qrcode";
+ }
+ else
+ {
+ // Will use defaultStyle if Zint not available
+ backend = "zint";
+ style = "qr";
+ }
+ }
const barcode::Style bcStyle = barcode::Backends::style( backend, style );
const bool bcTextFlag = XmlUtil::getBoolAttr( node, "text", true );
@@ -419,7 +444,7 @@ namespace glabels
/* affine attrs */
const auto affineTransformation = parseAffineTransformation(node);
- return new ModelBarcodeObject( x0, y0, w, h,
+ return new ModelBarcodeObject( x0, y0, w, h, false /*lockAspectRatio*/,
bcStyle, bcTextFlag, bcChecksumFlag, bcData, bcColorNode,
affineTransformation );
}
@@ -554,7 +579,7 @@ namespace glabels
}
const QString text = document.toPlainText();
- auto textNode = new ModelTextObject( x0, y0, w, h, text,
+ auto textNode = new ModelTextObject( x0, y0, w, h, false /*lockAspectRatio*/, text,
fontFamily, fontSize, fontWeight, fontItalicFlag, false,
textColorNode, textHAlign, textVAlign, textWrapMode, textLineSpacing,
textAutoShrink,
diff --git a/model/unit_tests/CMakeLists.txt b/model/unit_tests/CMakeLists.txt
index 5edddd8..21fc314 100644
--- a/model/unit_tests/CMakeLists.txt
+++ b/model/unit_tests/CMakeLists.txt
@@ -16,4 +16,84 @@ if (Qt5Test_FOUND)
target_link_libraries (TestXmlUtil Model Qt5::Test)
add_test (NAME XmlUtil COMMAND TestXmlUtil)
+ #=======================================
+ # Test XmlLabelCreator/Parser classes
+ #=======================================
+ qt5_wrap_cpp (TestXmlLabel_moc_sources TestXmlLabel.h)
+ add_executable (TestXmlLabel TestXmlLabel.cpp ${TestXmlLabel_moc_sources})
+ target_link_libraries (TestXmlLabel Model Qt5::Test)
+ add_test (NAME XmlLabel COMMAND TestXmlLabel)
+
+ #=======================================
+ # Test ColorNode class
+ #=======================================
+ qt5_wrap_cpp (TestColorNode_moc_sources TestColorNode.h)
+ add_executable (TestColorNode TestColorNode.cpp ${TestColorNode_moc_sources})
+ target_link_libraries (TestColorNode Model Qt5::Test)
+ add_test (NAME ColorNode COMMAND TestColorNode)
+
+ #=======================================
+ # Test FileUtil class
+ #=======================================
+ qt5_wrap_cpp (TestFileUtil_moc_sources TestFileUtil.h)
+ add_executable (TestFileUtil TestFileUtil.cpp ${TestFileUtil_moc_sources})
+ target_link_libraries (TestFileUtil Model Qt5::Test)
+ add_test (NAME FileUtil COMMAND TestFileUtil)
+
+ #=======================================
+ # Test Merge classes
+ #=======================================
+ qt5_wrap_cpp (TestMerge_moc_sources TestMerge.h)
+ add_executable (TestMerge TestMerge.cpp ${TestMerge_moc_sources})
+ target_link_libraries (TestMerge Model Qt5::Test)
+ add_test (NAME Merge COMMAND TestMerge)
+
+ #=======================================
+ # Test Model class
+ #=======================================
+ qt5_wrap_cpp (TestModel_moc_sources TestModel.h)
+ add_executable (TestModel TestModel.cpp ${TestModel_moc_sources})
+ target_link_libraries (TestModel Model Qt5::Test)
+ add_test (NAME Model COMMAND TestModel)
+
+ #=======================================
+ # Test ModelImageObject class
+ #=======================================
+ qt5_wrap_cpp (TestModelImageObject_moc_sources TestModelImageObject.h)
+ add_executable (TestModelImageObject TestModelImageObject.cpp ${TestModelImageObject_moc_sources})
+ target_link_libraries (TestModelImageObject Model Qt5::Test)
+ add_test (NAME ModelImageObject COMMAND TestModelImageObject)
+
+ #=======================================
+ # Test RawText class
+ #=======================================
+ qt5_wrap_cpp (TestRawText_moc_sources TestRawText.h)
+ add_executable (TestRawText TestRawText.cpp ${TestRawText_moc_sources})
+ target_link_libraries (TestRawText Model Qt5::Test)
+ add_test (NAME RawText COMMAND TestRawText)
+
+ #=======================================
+ # Test TextNode class
+ #=======================================
+ qt5_wrap_cpp (TestTextNode_moc_sources TestTextNode.h)
+ add_executable (TestTextNode TestTextNode.cpp ${TestTextNode_moc_sources})
+ target_link_libraries (TestTextNode Model Qt5::Test)
+ add_test (NAME TextNode COMMAND TestTextNode)
+
+ #=======================================
+ # Test Variable class
+ #=======================================
+ qt5_wrap_cpp (TestVariable_moc_sources TestVariable.h)
+ add_executable (TestVariable TestVariable.cpp ${TestVariable_moc_sources})
+ target_link_libraries (TestVariable Model Qt5::Test)
+ add_test (NAME Variable COMMAND TestVariable)
+
+ #=======================================
+ # Test Variables class
+ #=======================================
+ qt5_wrap_cpp (TestVariables_moc_sources TestVariables.h)
+ add_executable (TestVariables TestVariables.cpp ${TestVariables_moc_sources})
+ target_link_libraries (TestVariables Model Qt5::Test)
+ add_test (NAME Variables COMMAND TestVariables)
+
endif (Qt5Test_FOUND)
diff --git a/model/unit_tests/TestColorNode.cpp b/model/unit_tests/TestColorNode.cpp
new file mode 100644
index 0000000..251ac97
--- /dev/null
+++ b/model/unit_tests/TestColorNode.cpp
@@ -0,0 +1,177 @@
+/* TestColorNode.cpp
+ *
+ * Copyright (C) 2019 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 "TestColorNode.h"
+
+#include "model/ColorNode.h"
+
+#include
+
+
+QTEST_MAIN(TestColorNode)
+
+using namespace glabels::model;
+using namespace glabels::merge;
+
+
+void TestColorNode::colorNode()
+{
+ uint32_t rgbaBlackTransparent = 0;
+ uint32_t rgbaWhite = 0xFFFFFFFF;
+ uint32_t rgbaRed = 0xFF0000FF; // ColorNode uses RGBA. QColor set alpha to opaque 0xFF by default
+ uint32_t qRgbaRed = 0xFFFF0000; // QColor uses ARGB, ie alpha at top
+ uint32_t qRgbaGreen80 = 0x8000FF00;
+
+ QColor blackTransparent = QColor::fromRgba( rgbaBlackTransparent );
+ QColor white = QColor::fromRgba( rgbaWhite );
+ QColor red = QColor::fromRgba( qRgbaRed );
+ QColor green80 = QColor::fromRgba( qRgbaGreen80 );
+ QColor silver80 = QColor( 192, 192, 192, 128 );
+
+ Record record;
+ Variables vars;
+
+ ColorNode colorNode;
+ QVERIFY( !colorNode.isField() );
+ QCOMPARE( colorNode.color(), blackTransparent );
+ QCOMPARE( colorNode.key(), QString( "" ) );
+ QCOMPARE( colorNode.rgba(), rgbaBlackTransparent );
+ QCOMPARE( colorNode.color( nullptr, nullptr ), blackTransparent );
+ QCOMPARE( colorNode.color( &record, nullptr ), blackTransparent );
+ QCOMPARE( colorNode.color( nullptr, &vars ), blackTransparent );
+ QCOMPARE( colorNode.color( &record, &vars ), blackTransparent );
+
+ colorNode.setField( true );
+ QVERIFY( colorNode.isField() );
+ colorNode.setField( false );
+ QVERIFY( !colorNode.isField() );
+
+ colorNode.setColor( white );
+ QCOMPARE( colorNode.color(), white );
+ QCOMPARE( colorNode.rgba(), rgbaWhite );
+ QCOMPARE( colorNode.color( nullptr, nullptr ), white );
+ QCOMPARE( colorNode.color( &record, nullptr ), white );
+ QCOMPARE( colorNode.color( nullptr, &vars ), white );
+ QCOMPARE( colorNode.color( &record, &vars ), white );
+
+ colorNode.setKey( "key1" );
+ QCOMPARE( colorNode.key(), QString( "key1" ) );
+
+ ///
+ /// Constructors
+ ///
+ ColorNode colorNode2( true, white, QString( "key2" ) );
+ QVERIFY( colorNode2.isField() );
+ QCOMPARE( colorNode2.key(), QString( "key2" ) );
+ QCOMPARE( colorNode2.color(), white );
+
+ QVERIFY( colorNode2 != colorNode );
+ colorNode.setField( true );
+ QVERIFY( colorNode2 != colorNode );
+ colorNode.setKey( "key2" );
+ QVERIFY( colorNode2 == colorNode );
+
+ ColorNode colorNode3( red );
+ QVERIFY( !colorNode3.isField() );
+ QCOMPARE( colorNode3.key(), QString( "" ) );
+ QCOMPARE( colorNode3.color(), red );
+ QCOMPARE( colorNode3.rgba(), rgbaRed );
+
+ QVERIFY( colorNode3 != colorNode );
+ colorNode.setField( false );
+ QVERIFY( colorNode3 != colorNode );
+ colorNode.setKey( "" );
+ QVERIFY( colorNode3 != colorNode );
+ colorNode.setColor( red );
+ QVERIFY( colorNode3 == colorNode );
+
+ ///
+ /// Record
+ ///
+ colorNode = ColorNode( QString( "key1" ) );
+ QVERIFY( colorNode.isField() ); // Defaults to true if given key only
+ QCOMPARE( colorNode.key(), QString( "key1" ) );
+ QCOMPARE( colorNode.color(), blackTransparent );
+ QCOMPARE( colorNode.color( &record, &vars ), silver80 ); // Defaults to silver if given non-matching record/variables
+
+ record["key1"] = "white";
+ QCOMPARE( colorNode.color( &record, nullptr ), white );
+
+ record["key1"] = "red";
+ QCOMPARE( colorNode.color( &record, nullptr ), red );
+
+ record["key1"] = "#FF0000";
+ QCOMPARE( colorNode.color( &record, nullptr ), red );
+
+ record["key1"] = "#FFFF0000"; // ARGB
+ QCOMPARE( colorNode.color( &record, nullptr ), red );
+
+ record["key1"] = "#8000FF00";
+ QCOMPARE( colorNode.color( &record, nullptr ), green80 );
+
+ colorNode.setKey( "key2" );
+ QCOMPARE( colorNode.color( &record, nullptr ), silver80 );
+ record["key2"] = "#8000FF00";
+ QCOMPARE( colorNode.color( &record, nullptr ), green80 );
+
+ ///
+ /// Variable
+ ///
+ colorNode = ColorNode( QString( "c1" ) );
+ QVERIFY( colorNode.isField() ); // Defaults to true if given key only
+ QCOMPARE( colorNode.key(), QString( "c1" ) );
+ QCOMPARE( colorNode.color(), blackTransparent );
+ QCOMPARE( colorNode.color( &record, &vars ), silver80 ); // Defaults to silver if given non-matching record/variables
+
+ {
+ Variable c1( Variable::Type::COLOR, "c1", "white", Variable::Increment::PER_ITEM );
+ vars.addVariable( c1 );
+ }
+ QCOMPARE( colorNode.color( nullptr, &vars ), white );
+ vars.incrementVariablesOnItem();
+ QCOMPARE( colorNode.color( nullptr, &vars ), white );
+
+ {
+ Variable c1( Variable::Type::COLOR, "c1", "red", Variable::Increment::PER_ITEM );
+ vars.addVariable( c1 );
+ }
+ QCOMPARE( colorNode.color( nullptr, &vars ), red );
+
+ {
+ Variable c1( Variable::Type::COLOR, "c1", "#8000FF00", Variable::Increment::PER_ITEM );
+ vars.addVariable( c1 );
+ }
+ QCOMPARE( colorNode.color( nullptr, &vars ), green80 );
+
+ colorNode.setKey( "c2" );
+ QCOMPARE( colorNode.color( &record, nullptr ), silver80 );
+
+ {
+ Variable c2( Variable::Type::COLOR, "c2", "#8000FF00", Variable::Increment::PER_ITEM );
+ vars.addVariable( c2 );
+ }
+ QCOMPARE( colorNode.color( nullptr, &vars ), green80 );
+
+ ///
+ /// Record beats variable
+ ///
+ record["c2"] = "red";
+ QCOMPARE( colorNode.color( &record, &vars ), red );
+}
diff --git a/model/unit_tests/TestColorNode.h b/model/unit_tests/TestColorNode.h
new file mode 100644
index 0000000..4837c5a
--- /dev/null
+++ b/model/unit_tests/TestColorNode.h
@@ -0,0 +1,30 @@
+/* TestColorNode.h
+ *
+ * Copyright (C) 2019 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
+
+
+class TestColorNode : public QObject
+{
+ Q_OBJECT
+
+private slots:
+ void colorNode();
+};
diff --git a/model/unit_tests/TestFileUtil.cpp b/model/unit_tests/TestFileUtil.cpp
new file mode 100644
index 0000000..7625d44
--- /dev/null
+++ b/model/unit_tests/TestFileUtil.cpp
@@ -0,0 +1,104 @@
+/* TestFileUtil.cpp
+ *
+ * Copyright (C) 2019 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 "TestFileUtil.h"
+
+#include "model/FileUtil.h"
+
+#include
+
+
+QTEST_MAIN(TestFileUtil)
+
+using namespace glabels::model;
+
+
+void TestFileUtil::addExtension()
+{
+ QCOMPARE( FileUtil::addExtension( "/tmp/file", ".ext" ), QString( "/tmp/file.ext" ) );
+ QCOMPARE( FileUtil::addExtension( "/tmp/file.ext", ".ext" ), QString( "/tmp/file.ext" ) );
+ QCOMPARE( FileUtil::addExtension( "/tmp/file.ext", ".txt" ), QString( "/tmp/file.ext.txt" ) );
+ QCOMPARE( FileUtil::addExtension( "/tmp/file", "txt" ), QString( "/tmp/filetxt" ) );
+ QCOMPARE( FileUtil::addExtension( "/tmp/filetxt", "txt" ), QString( "/tmp/filetxt" ) );
+}
+
+
+void TestFileUtil::systemTemplatesDir()
+{
+ QDir dir = FileUtil::systemTemplatesDir();
+ QVERIFY( dir.exists() );
+ QVERIFY( dir.isReadable() );
+ QVERIFY( dir.path().endsWith( "templates" ) );
+}
+
+
+void TestFileUtil::manualUserTemplatesDir()
+{
+ QDir dir = FileUtil::manualUserTemplatesDir();
+ QVERIFY( dir.exists() );
+ QVERIFY( dir.isReadable() );
+ QVERIFY( dir.path().endsWith( ".glabels" ) );
+}
+
+
+void TestFileUtil::userTemplatesDir()
+{
+ QDir dir = FileUtil::userTemplatesDir();
+ QVERIFY( dir.exists() );
+ QVERIFY( dir.isReadable() );
+ QFileInfo fileInfo( dir.path() );
+ QVERIFY( fileInfo.isWritable() );
+}
+
+
+void TestFileUtil::translationsDir()
+{
+ QDir dir = FileUtil::translationsDir();
+ QVERIFY( dir.exists() );
+ QVERIFY( dir.isReadable() );
+ QVERIFY( dir.path().endsWith( "translations" ) );
+}
+
+
+void TestFileUtil::makeRelativeIfInDir_data()
+{
+ QTest::addColumn( "dir" );
+ QTest::addColumn( "filename" );
+ QTest::addColumn( "expected" );
+
+ QTest::newRow( "1" ) << "/dir/subdir" << "/dir/subdir/filename" << "filename";
+ QTest::newRow( "2" ) << "/dir/subdir" << "filename" << "filename";
+ QTest::newRow( "3" ) << "/dir" << "subdir/filename" << "subdir/filename";
+ QTest::newRow( "4" ) << "/dir" << "/dir/subdir/subdir/filename" << "subdir/subdir/filename";
+ QTest::newRow( "5" ) << "/dir/subdir" << "/dir/subdir/subdir/filename" << "subdir/filename";
+ QTest::newRow( "6" ) << "/dir/subdir" << "/dir/subdir2/filename" << "/dir/subdir2/filename";
+ QTest::newRow( "7" ) << "/dir2/subdir" << "/dir/subdir/filename" << "/dir/subdir/filename";
+ QTest::newRow( "8" ) << "/dir/subdir" << "/dir/filename" << "/dir/filename";
+}
+
+
+void TestFileUtil::makeRelativeIfInDir()
+{
+ QFETCH( QString, dir );
+ QFETCH( QString, filename );
+ QFETCH( QString, expected );
+
+ QCOMPARE( FileUtil::makeRelativeIfInDir( QDir( dir ), filename ), expected );
+}
diff --git a/model/unit_tests/TestFileUtil.h b/model/unit_tests/TestFileUtil.h
new file mode 100644
index 0000000..50e1e02
--- /dev/null
+++ b/model/unit_tests/TestFileUtil.h
@@ -0,0 +1,36 @@
+/* TestFileUtil.h
+ *
+ * Copyright (C) 2019 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
+
+
+class TestFileUtil : public QObject
+{
+ Q_OBJECT
+
+private slots:
+ void addExtension();
+ void systemTemplatesDir();
+ void manualUserTemplatesDir();
+ void userTemplatesDir();
+ void translationsDir();
+ void makeRelativeIfInDir_data();
+ void makeRelativeIfInDir();
+};
diff --git a/model/unit_tests/TestMerge.cpp b/model/unit_tests/TestMerge.cpp
new file mode 100644
index 0000000..72c9dd3
--- /dev/null
+++ b/model/unit_tests/TestMerge.cpp
@@ -0,0 +1,347 @@
+/* TestMerge.cpp
+ *
+ * Copyright (C) 2019 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 "TestMerge.h"
+
+#include "merge/Factory.h"
+#include "merge/None.h"
+#include "merge/TextCsv.h"
+#include "merge/TextCsvKeys.h"
+#include "merge/TextTsv.h"
+#include "merge/TextTsvKeys.h"
+#include "merge/TextColon.h"
+#include "merge/TextColonKeys.h"
+#include "merge/TextSemicolon.h"
+#include "merge/TextSemicolonKeys.h"
+
+#include "merge/Record.h"
+
+#include
+
+
+QTEST_MAIN(TestMerge)
+
+Q_DECLARE_METATYPE(glabels::merge::Factory::SourceType)
+
+using namespace glabels::merge;
+
+
+void TestMerge::initTestCase()
+{
+ Factory::init();
+}
+
+
+void TestMerge::factory_data()
+{
+ QTest::addColumn( "id" );
+ QTest::addColumn( "name" );
+ QTest::addColumn( "type" );
+ QTest::addColumn( "index" );
+
+ int index = 0;
+ QTest::newRow( "None" ) << None::id() << "None" << Factory::NONE << index++;
+ QTest::newRow( "TextCsv" ) << TextCsv::id() << "Text: Comma Separated Values (CSV)" << Factory::FILE << index++;
+ QTest::newRow( "TextCsvKeys" ) << TextCsvKeys::id() << "Text: Comma Separated Values (CSV), keys on line 1" << Factory::FILE << index++;
+ QTest::newRow( "TextTsv" ) << TextTsv::id() << "Text: Tab Separated Values (TSV)" << Factory::FILE << index++;
+ QTest::newRow( "TextTsvKeys" ) << TextTsvKeys::id() << "Text: Tab Separated Values (TSV), keys on line 1" << Factory::FILE << index++;
+ QTest::newRow( "TextColon" ) << TextColon::id() << "Text: Colon Separated Values" << Factory::FILE << index++;
+ QTest::newRow( "TextColonKeys" ) << TextColonKeys::id() << "Text: Colon Separated Values, keys on line 1" << Factory::FILE << index++;
+ QTest::newRow( "TextSemicolon" ) << TextSemicolon::id() << "Text: Semicolon Separated Values" << Factory::FILE << index++;
+ QTest::newRow( "TextSemicolonKeys" ) << TextSemicolonKeys::id() << "Text: Semicolon Separated Values, keys on line 1" << Factory::FILE << index++;
+}
+
+
+void TestMerge::factory()
+{
+ QFETCH( QString, id );
+ QFETCH( QString, name );
+ QFETCH( Factory::SourceType, type );
+ QFETCH( int, index );
+
+ QVERIFY( Factory::nameList().contains( name ) );
+
+ QString outName = Factory::idToName( id );
+ QCOMPARE( outName, name );
+
+ QString outId = Factory::nameToId( name );
+ QCOMPARE( outId, id );
+
+ Factory::SourceType outType = Factory::idToType( id );
+ QCOMPARE( outType, type );
+
+ outId = Factory::indexToId( index );
+ QCOMPARE( outId, id );
+
+ Merge* merge = Factory::createMerge( id );
+ QVERIFY( merge );
+ QCOMPARE( merge->id(), id );
+
+ Merge* cloneMerge = merge->clone();
+ QCOMPARE( cloneMerge->id(), merge->id() );
+ delete cloneMerge;
+ delete merge;
+}
+
+
+void TestMerge::factoryNotRegistered()
+{
+ QString id( "unregistered" );
+ Merge* merge = Factory::createMerge( id );
+ QVERIFY( merge );
+ QVERIFY( merge->id() != id );
+ QCOMPARE( merge->id(), None::id() );
+ delete merge;
+}
+
+
+void TestMerge::text_data()
+{
+ QTest::addColumn( "id" );
+ QTest::addColumn( "keyed" );
+ QTest::addColumn( "delim" );
+
+ QTest::newRow( "TextCsv" ) << TextCsv::id() << false << ',';
+ QTest::newRow( "TextCsvKeys" ) << TextCsvKeys::id() << true << ',';
+ QTest::newRow( "TextTsv" ) << TextTsv::id() << false << '\t';
+ QTest::newRow( "TextTsvKeys" ) << TextTsvKeys::id() << true << '\t';
+ QTest::newRow( "TextColon" ) << TextColon::id() << false << ':';
+ QTest::newRow( "TextColonKeys" ) << TextColonKeys::id() << true << ':';
+ QTest::newRow( "TextSemicolon" ) << TextSemicolon::id() << false << ';';
+ QTest::newRow( "TextSemicolonKeys" ) << TextSemicolonKeys::id() << true << ';';
+}
+
+
+void TestMerge::text()
+{
+ QFETCH( QString, id );
+ QFETCH( bool, keyed );
+ QFETCH( char, delim );
+
+ QTemporaryFile file;
+ file.open();
+ if ( keyed )
+ {
+ file.write( "header1" );
+ file.putChar( delim );
+ file.write( "\"header 2\"" );
+ file.putChar( delim );
+ file.write( "header3\r\n" );
+ }
+ file.write( " val11" ); // Leading spaces in SIMPLE entry
+ file.putChar( delim );
+ file.write( "\"\"\"val 12\"\"\"" ); // 2DQUOTE at beginning and end of DQUOTE entry
+ file.putChar( delim );
+ file.write( " \"val 13\"\n" ); // Leading spaces before DQUOTE entry, end line with LF only
+
+ file.write( "\" val21\"\"\"" ); // Leading spaces within DQUOTE entry, 2DQUOTE at end
+ file.putChar( delim );
+ file.write( "\"\"\"val 22\"" ); // 2DQUOTE at beginning of DQUOTE entry
+ file.putChar( delim );
+ file.write( "\r\n" ); // Last field blank
+
+ file.write( "\"\"\"\"\"\"" ); // 2 2DQUOTES alone in DQUOTE entry
+ file.putChar( delim );
+ file.write( "val \"32" ); // DQUOTE in SIMPLE entry
+ file.putChar( delim );
+ file.write( "val \"\\\"33\r\n" ); // DQUOTE backslashed-DQUOTE in SIMPLE entry
+
+ file.putChar( delim ); file.putChar( delim ); // All fields blank
+ file.write( "\r\n" );
+
+ file.write( "val\\n \\t \\r \\\\ \\x51" ); // Backslashed-n/-t/-r/-backslash/-x in SIMPLE entry
+ file.putChar( delim );
+ file.write( "\"val\\n \\t \\r \\\\ \\x52\"" ); // Backslashed-n/-t/-r/-backslash/-x in QUOTE entry
+ file.write( "\r\n" ); // No last delim
+
+ file.write( "\"val \"\"61\"" ); // 2DQUOTE in middle of DQUOTE entry
+ file.putChar( delim );
+ file.write( "\"val\"\"" ); file.putChar( delim ); file.write( "\r\n\\\"\u2019\\\\52\"" ); // 2DQUOTE delim CRLF backslashed-DQUOTE U+2019 backslashed-backslash
+ file.putChar( delim );
+ file.write( "\"val63\"" ); // End without CRLF
+ file.close();
+
+ Merge* merge = Factory::createMerge( id );
+ QCOMPARE( merge->id(), id );
+
+ merge->setSource( file.fileName() );
+ QCOMPARE( merge->source(), file.fileName() );
+
+ const QList& recordList = merge->recordList();
+ QCOMPARE( recordList.size(), 6 );
+
+ //
+ // Records
+ //
+ const char* h1 = keyed ? "header1" : "1";
+ const char* h2 = keyed ? "header 2" : "2";
+ const char* h3 = keyed ? "header3" : "3";
+ const Record* record;
+
+ record = recordList[0];
+ QVERIFY( record->contains( h1 ) );
+ QCOMPARE( record->value( h1 ), QString( " val11" ) );
+ QVERIFY( record->contains( h2 ) );
+ QCOMPARE( record->value( h2 ), QString( "\"val 12\"" ) );
+ QVERIFY( record->contains( h3 ) );
+ QCOMPARE( record->value( h3 ), QString( " \"val 13\"" ) ); // NOTE: Treats as unquoted due to leading spaces
+
+ record = recordList[1];
+ QVERIFY( record->contains( h1 ) );
+ QCOMPARE( record->value( h1 ), QString( " val21\"" ) );
+ QVERIFY( record->contains( h2 ) );
+ QCOMPARE( record->value( h2 ), QString( "\"val 22" ) );
+ QVERIFY( record->contains( h3 ) );
+ QCOMPARE( record->value( h3 ), QString( "" ) );
+
+ record = recordList[2];
+ QVERIFY( record->contains( h1 ) );
+ QCOMPARE( record->value( h1 ), QString( "\"\"" ) );
+ QVERIFY( record->contains( h2 ) );
+ QCOMPARE( record->value( h2 ), QString( "val \"32" ) );
+ QVERIFY( record->contains( h3 ) );
+ QCOMPARE( record->value( h3 ), QString( "val \"\"33" ) );
+
+ record = recordList[3];
+ QVERIFY( record->contains( h1 ) );
+ QCOMPARE( record->value( h1 ), QString( "" ) );
+ QVERIFY( record->contains( h2 ) );
+ QCOMPARE( record->value( h2 ), QString( "" ) );
+ QVERIFY( record->contains( h3 ) );
+ QCOMPARE( record->value( h3 ), QString( "" ) );
+
+ record = recordList[4];
+ QVERIFY( record->contains( h1 ) );
+ QCOMPARE( record->value( h1 ), QString( "val\n \t r \\ x51" ) );
+ QVERIFY( record->contains( h2 ) );
+ QCOMPARE( record->value( h2 ), QString( "val\n \t r \\ x52" ) );
+ QVERIFY( !record->contains( h3 ) );
+
+ record = recordList[5];
+ QVERIFY( record->contains( h1 ) );
+ QCOMPARE( record->value( h1 ), QString( "val \"61" ) );
+ QVERIFY( record->contains( h2 ) );
+ QCOMPARE( record->value( h2 ), QString( "val\"" ).append( delim ).append( "\n\"\u2019\\52" ) ); // NOTE: CR missing (QIODevice::Text strips all CRs from stream)
+ QVERIFY( record->contains( h3 ) );
+ QCOMPARE( record->value( h3 ), QString( "val63" ) );
+
+ //
+ // Selection
+ //
+ QCOMPARE( merge->nSelectedRecords(), 6 ); // Initially all selected
+ merge->unselectAll();
+ QCOMPARE( merge->nSelectedRecords(), 0 );
+
+ record = recordList[1];
+ merge->select( (Record*)record );
+ QCOMPARE( merge->nSelectedRecords(), 1 );
+ QCOMPARE( merge->selectedRecords().size(), 1 );
+ QCOMPARE( merge->selectedRecords().first(), record ); // Pointers same
+
+ merge->unselect( (Record*)record );
+ QCOMPARE( merge->nSelectedRecords(), 0 );
+ QCOMPARE( merge->selectedRecords().size(), 0 );
+
+ merge->setSelected( 0 );
+ merge->setSelected( 3 );
+ QCOMPARE( merge->nSelectedRecords(), 2 );
+ QCOMPARE( merge->selectedRecords().size(), 2 );
+ QCOMPARE( merge->selectedRecords().first(), recordList[0] );
+ QCOMPARE( merge->selectedRecords().last(), recordList[3] );
+
+ merge->setSelected( 0, false );
+ QCOMPARE( merge->nSelectedRecords(), 1 );
+ QCOMPARE( merge->selectedRecords().size(), 1 );
+
+ //
+ // Keys
+ //
+ QStringList keys = merge->keys();
+ QCOMPARE( keys.size(), 3 );
+ QCOMPARE( keys[0], QString( h1 ) );
+ QCOMPARE( keys[1], QString( h2 ) );
+ QCOMPARE( keys[2], QString( h3 ) );
+ QCOMPARE( merge->primaryKey(), QString( h1 ) );
+
+ //
+ // Clone
+ //
+ merge->unselectAll();
+ merge->setSelected( 0 );
+ QCOMPARE( merge->nSelectedRecords(), 1 );
+
+ Merge* cloneMerge = merge->clone();
+ QCOMPARE( cloneMerge->id(), merge->id() );
+ QCOMPARE( cloneMerge->source(), merge->source() );
+ QCOMPARE( cloneMerge->recordList().size(), merge->recordList().size() );
+ QCOMPARE( *(cloneMerge->recordList()[0]), *(merge->recordList()[0]) ); // Pointers different
+ QCOMPARE( *(cloneMerge->recordList()[1]), *(merge->recordList()[1]) );
+ QCOMPARE( *(cloneMerge->recordList()[2]), *(merge->recordList()[2]) );
+ QCOMPARE( *(cloneMerge->recordList()[3]), *(merge->recordList()[3]) );
+ QCOMPARE( *(cloneMerge->recordList()[4]), *(merge->recordList()[4]) );
+ QCOMPARE( *(cloneMerge->recordList()[5]), *(merge->recordList()[5]) );
+ QCOMPARE( cloneMerge->nSelectedRecords(), merge->nSelectedRecords() );
+ QCOMPARE( cloneMerge->selectedRecords().size(), merge->selectedRecords().size() );
+ QCOMPARE( *(cloneMerge->selectedRecords()[0]), *(merge->selectedRecords()[0]) );
+ QCOMPARE( cloneMerge->keys(), merge->keys() );
+ QCOMPARE( cloneMerge->primaryKey(), merge->primaryKey() );
+ delete cloneMerge;
+ delete merge;
+}
+
+
+void TestMerge::none()
+{
+ None none;
+ QCOMPARE( none.id(), QString( "None" ) );
+
+ None* cloneNone = none.clone();
+ QCOMPARE( cloneNone->id(), none.id() );
+ QCOMPARE( cloneNone->keys(), none.keys() );
+ QCOMPARE( cloneNone->primaryKey(), none.primaryKey() );
+ delete cloneNone;
+}
+
+
+void TestMerge::record()
+{
+ Record record;
+ QCOMPARE( record.isSelected(), true );
+ record.setSelected( false );
+ QCOMPARE( record.isSelected(), false );
+ record.setSelected( true );
+ QCOMPARE( record.isSelected(), true );
+
+ record["key"] = "val";
+ QVERIFY( record.contains( "key" ) );
+ QCOMPARE( record["key"], QString( "val" ) );
+
+ Record* cloneRecord = record.clone();
+ QCOMPARE( cloneRecord->isSelected(), true );
+ QVERIFY( cloneRecord->contains( "key" ) );
+ QCOMPARE( cloneRecord->value( "key" ), QString( "val" ) );
+ delete cloneRecord;
+
+ record.setSelected( false );
+ Record record2( &record );
+ QCOMPARE( record2.isSelected(), false );
+ QVERIFY( record2.contains( "key" ) );
+ QCOMPARE( record2["key"], QString( "val" ) );
+}
diff --git a/model/unit_tests/TestMerge.h b/model/unit_tests/TestMerge.h
new file mode 100644
index 0000000..5fd43bd
--- /dev/null
+++ b/model/unit_tests/TestMerge.h
@@ -0,0 +1,37 @@
+/* TestMerge.h
+ *
+ * Copyright (C) 2019 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
+
+
+class TestMerge : public QObject
+{
+ Q_OBJECT
+
+private slots:
+ void initTestCase();
+ void factory_data();
+ void factory();
+ void factoryNotRegistered();
+ void text_data();
+ void text();
+ void none();
+ void record();
+};
diff --git a/model/unit_tests/TestModel.cpp b/model/unit_tests/TestModel.cpp
new file mode 100644
index 0000000..f52b4c4
--- /dev/null
+++ b/model/unit_tests/TestModel.cpp
@@ -0,0 +1,496 @@
+/* TestModel.cpp
+ *
+ * Copyright (C) 2019 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 "TestModel.h"
+
+#include "model/Model.h"
+#include "model/ModelBoxObject.h"
+#include "model/ModelEllipseObject.h"
+#include "model/ModelLineObject.h"
+#include "model/ModelTextObject.h"
+#include "model/FrameRect.h"
+#include "model/FrameContinuous.h"
+#include "model/Region.h"
+#include "model/Settings.h"
+
+#include "merge/Factory.h"
+#include "merge/Merge.h"
+#include "merge/None.h"
+#include "merge/TextCsv.h"
+#include "merge/TextCsvKeys.h"
+
+#include
+
+
+QTEST_MAIN(TestModel)
+
+using namespace glabels::model;
+using namespace glabels::merge;
+
+
+void TestModel::initTestCase()
+{
+ Factory::init();
+ Settings::init();
+}
+
+
+void TestModel::model()
+{
+ Model model;
+ QVERIFY( model.isModified() );
+ model.clearModified();
+ QVERIFY( !model.isModified() );
+
+ QVERIFY( model.shortName().contains( QRegExp( "^Untitled[1-9][0-9]*$" ) ) );
+ model.setFileName( "dir/file1.ext" );
+ QCOMPARE( model.fileName(), QString( "dir/file1.ext" ) );
+ QCOMPARE( model.shortName(), QString( "file1" ) );
+ QVERIFY( !model.isModified() );
+
+ QCOMPARE( model.w(), Distance( 0 ) );
+ QCOMPARE( model.h(), Distance( 0 ) );
+
+ Template tmplate( "Test Brand", "part", "desc", "testPaperId", 100, 400 );
+ FrameRect* frame = new FrameRect( 100, 200, 5, 0, 0, "rect1" );
+ QVERIFY( frame->w() != frame->h() );
+ tmplate.addFrame( frame );
+ model.setTmplate( &tmplate ); // Copies
+ QCOMPARE( model.tmplate()->brand(), QString( "Test Brand" ) );
+ QCOMPARE( model.tmplate()->part(), QString( "part" ) );
+ QCOMPARE( model.tmplate()->description(), QString( "desc" ) );
+ QCOMPARE( model.tmplate()->paperId(), QString( "testPaperId" ) );
+ QCOMPARE( model.tmplate()->pageWidth(), Distance( 100 ) );
+ QCOMPARE( model.tmplate()->pageHeight(), Distance( 400 ) );
+ QVERIFY( model.isModified() );
+
+ QVERIFY( model.frame()->id() == frame->id() );
+ QCOMPARE( model.w(), Distance( 100 ) );
+ QCOMPARE( model.h(), Distance( 200 ) );
+ QCOMPARE( model.w(), frame->w() );
+ QCOMPARE( model.h(), frame->h() );
+
+ model.clearModified();
+ QVERIFY( !model.isModified() );
+
+ QVERIFY( !model.rotate() );
+ model.setRotate( false );
+ QVERIFY( !model.rotate() );
+ QVERIFY( !model.isModified() );
+ model.setRotate( true );
+ QVERIFY( model.rotate() );
+ QVERIFY( model.isModified() );
+
+ QCOMPARE( model.w(), frame->h() );
+ QCOMPARE( model.h(), frame->w() );
+
+ model.setRotate( false );
+ QVERIFY( !model.rotate() );
+
+ model.clearModified();
+ QVERIFY( !model.isModified() );
+
+ model.setH( 300 ); // Default does nothing
+ QCOMPARE( model.h(), Distance( 200 ) );
+ QVERIFY( model.isModified() ); // Set anyway
+
+ // Continuous frame implements setH()
+ Template tmplate2( "Test Brand2", "part2", "desc2", "testPaperId2", 100, 400 );
+ FrameContinuous* frame2 = new FrameContinuous( 100, 0, 500, 200, "continuous1" );
+ QCOMPARE( frame2->h(), Distance( 200 ) );
+ tmplate2.addFrame( frame2 );
+ model.setTmplate( &tmplate2 );
+ QVERIFY( model.frame()->id() == frame2->id() );
+ QCOMPARE( model.w(), Distance( 100 ) );
+ QCOMPARE( model.h(), Distance( 200 ) );
+ QCOMPARE( model.w(), frame2->w() );
+ QCOMPARE( model.h(), frame2->h() );
+
+ model.clearModified();
+ QVERIFY( !model.isModified() );
+
+ model.setH( 300 );
+ QCOMPARE( model.h(), Distance( 300 ) );
+ QVERIFY( model.isModified() );
+
+ //
+ // Objects
+ //
+ ColorNode black( Qt::black );
+ ModelObject* ellipse = new ModelEllipseObject( 1, 0, 100, 100, false, 1, black, black );
+ ModelObject* box = new ModelBoxObject( 1, 100, 100, 100, false, 1, black, black );
+ ModelObject* line = new ModelLineObject( 1, 200, 99 /*dx*/, 1 /*dy*/, 1.0, black );
+ ModelObject* text = new ModelTextObject( 1, 201, 100, 30, false, "", "Sans", 10, QFont::Normal, false, false, black, Qt::AlignLeft, Qt::AlignTop, QTextOption::WordWrap, 1, false );
+
+ model.clearModified();
+ QVERIFY( !model.isModified() );
+
+ model.addObject( ellipse );
+ QVERIFY( model.isModified() );
+ model.addObject( box );
+ model.addObject( line );
+ model.addObject( text );
+
+ QCOMPARE( model.objectList().size(), 4 );
+
+ ModelObject* line2 = new ModelLineObject( 1, 231, 100 /*dx*/, 1 /*dy*/, 1.0, black );
+ model.addObject( line2 );
+ QCOMPARE( model.objectList().size(), 5 );
+
+ model.clearModified();
+ QVERIFY( !model.isModified() );
+
+ model.deleteObject( line2 );
+ QCOMPARE( model.objectList().size(), 4 );
+ QVERIFY( model.isModified() );
+
+ ModelObject* object;
+
+ object = model.objectAt( 1 /*scale*/, 1, 200 );
+ QVERIFY( object );
+ QVERIFY( dynamic_cast(object) );
+ QCOMPARE( object->id(), line->id() );
+
+ object = model.objectAt( 1 /*scale*/, 100, 150 );
+ QVERIFY( object );
+ QVERIFY( dynamic_cast(object) );
+ QCOMPARE( object->id(), box->id() );
+
+ object = model.objectAt( 1 /*scale*/, 50, 0 );
+ QVERIFY( object );
+ QVERIFY( dynamic_cast(object) );
+ QCOMPARE( object->id(), ellipse->id() );
+
+ object = model.objectAt( 1 /*scale*/, 1 + 3, 201 + 3 ); // Allow for text offset
+ QVERIFY( object );
+ QVERIFY( dynamic_cast(object) );
+ QCOMPARE( object->id(), text->id() );
+
+ //
+ // Selection
+ //
+ QVERIFY( model.isSelectionEmpty() );
+ QVERIFY( !model.isSelectionAtomic() );
+ QVERIFY( model.getSelection().isEmpty() );
+ QVERIFY( !model.getFirstSelectedObject() );
+
+ QVERIFY( !model.canSelectionText() );
+ QVERIFY( !model.canSelectionFill() );
+ QVERIFY( !model.canSelectionLineColor() );
+ QVERIFY( !model.canSelectionLineWidth() );
+
+ model.selectAll();
+ QVERIFY( !model.isSelectionEmpty() );
+ QVERIFY( !model.isSelectionAtomic() );
+ QVERIFY( !model.getSelection().isEmpty() );
+ QCOMPARE( model.getSelection().size(), 4 );
+ QCOMPARE( model.getSelection().first()->id(), ellipse->id() );
+ QCOMPARE( model.getSelection().at(1)->id(), box->id() );
+ QCOMPARE( model.getSelection().at(2)->id(), line->id() );
+ QCOMPARE( model.getSelection().at(3)->id(), text->id() );
+ QVERIFY( model.getFirstSelectedObject() );
+ QCOMPARE( model.getFirstSelectedObject()->id(), ellipse->id() );
+
+ QVERIFY( model.canSelectionText() );
+ QVERIFY( model.canSelectionFill() );
+ QVERIFY( model.canSelectionLineColor() );
+ QVERIFY( model.canSelectionLineWidth() );
+
+ model.unselectAll();
+ QVERIFY( model.isSelectionEmpty() );
+ QVERIFY( !model.isSelectionAtomic() );
+ QVERIFY( model.getSelection().isEmpty() );
+ QVERIFY( !model.getFirstSelectedObject() );
+
+ model.selectObject( text );
+ QVERIFY( !model.isSelectionEmpty() );
+ QVERIFY( model.isSelectionAtomic() );
+ QCOMPARE( model.getSelection().size(), 1 );
+ QCOMPARE( model.getFirstSelectedObject()->id(), text->id() );
+
+ QVERIFY( model.canSelectionText() );
+ QVERIFY( !model.canSelectionFill() );
+ QVERIFY( !model.canSelectionLineColor() );
+ QVERIFY( !model.canSelectionLineWidth() );
+
+ model.unselectObject( text );
+ QVERIFY( model.isSelectionEmpty() );
+
+ model.selectObject( line );
+ QVERIFY( !model.isSelectionEmpty() );
+ QVERIFY( model.isSelectionAtomic() );
+ QCOMPARE( model.getSelection().size(), 1 );
+ QCOMPARE( model.getFirstSelectedObject()->id(), line->id() );
+
+ QVERIFY( !model.canSelectionText() );
+ QVERIFY( !model.canSelectionFill() );
+ QVERIFY( model.canSelectionLineColor() );
+ QVERIFY( model.canSelectionLineWidth() );
+
+ model.unselectAll();
+ QVERIFY( model.isSelectionEmpty() );
+
+ double margin = 0.5; // Allow 0.5pt margin
+ Region region( 1 - margin, 302 - margin, 101 + margin /*x2*/, 302 + margin /*y2*/ ); // Outside all objects
+ model.selectRegion( region );
+ QVERIFY( model.getSelection().isEmpty() );
+ QVERIFY( model.isSelectionEmpty() );
+
+ region.setY1( 0 - margin ); // Ellipse
+ region.setY2( 100 + margin );
+ model.selectRegion( region );
+ QVERIFY( !model.isSelectionEmpty() );
+ QVERIFY( model.isSelectionAtomic() );
+ QCOMPARE( model.getSelection().size(), 1 );
+ QCOMPARE( model.getFirstSelectedObject()->id(), ellipse->id() );
+
+ QVERIFY( !model.canSelectionText() );
+ QVERIFY( model.canSelectionFill() );
+ QVERIFY( model.canSelectionLineColor() );
+ QVERIFY( model.canSelectionLineWidth() );
+
+ region.setY1( 200 - margin ); // Line
+ region.setY2( 201 + margin );
+ model.selectRegion( region );
+ QVERIFY( !model.isSelectionEmpty() );
+ QVERIFY( !model.isSelectionAtomic() ); // Accumulative
+ QCOMPARE( model.getSelection().size(), 2 );
+ QCOMPARE( model.getSelection().at(0)->id(), ellipse->id() );
+ QCOMPARE( model.getSelection().at(1)->id(), line->id() );
+
+ model.unselectObject( ellipse );
+ QVERIFY( !model.isSelectionEmpty() );
+ QVERIFY( model.isSelectionAtomic() );
+ QCOMPARE( model.getSelection().size(), 1 );
+ QCOMPARE( model.getFirstSelectedObject()->id(), line->id() );
+
+ model.unselectAll();
+ QVERIFY( model.isSelectionEmpty() );
+
+ // TODO: Operations on selections etc
+}
+
+
+void TestModel::saveRestore()
+{
+ Model* model = new Model;
+ QVERIFY( model->isModified() );
+ model->clearModified();
+ QVERIFY( !model->isModified() );
+
+ //
+ // Set template/frame
+ //
+ Template tmplate( "Test Brand", "part", "desc", "testPaperId", 110, 410 );
+ FrameRect* frame = new FrameRect( 120, 220, 5, 0, 0, "rect1" );
+ tmplate.addFrame( frame );
+ model->setTmplate( &tmplate ); // Copies
+ QCOMPARE( model->tmplate()->brand(), QString( "Test Brand" ) );
+ QVERIFY( model->isModified() );
+
+ model->clearModified();
+ QVERIFY( !model->isModified() );
+
+ //
+ // Set merge
+ //
+ Merge* merge = Factory::createMerge( TextCsvKeys::id() );
+ QCOMPARE( merge->id(), TextCsvKeys::id() );
+
+ model->setMerge( merge );
+ QCOMPARE( model->merge(), merge );
+ QVERIFY( model->isModified() );
+
+ //
+ // Add some variables
+ //
+ model->clearModified();
+ QVERIFY( !model->isModified() );
+
+ Variable i( Variable::Type::INTEGER, "i", "2", Variable::Increment::PER_ITEM, "2" );
+ Variable f( Variable::Type::FLOATING_POINT, "f", "6.54", Variable::Increment::PER_COPY, "0.12" );
+ model->variables()->addVariable( i );
+ QVERIFY( model->isModified() );
+ model->variables()->addVariable( f );
+ QVERIFY( model->isModified() );
+
+ model->clearModified();
+ QVERIFY( !model->isModified() );
+
+ QTemporaryFile csv;
+ csv.open();
+ csv.write( "id,text\n1,text1\n2,text2\n3,text3\n" );
+ csv.close();
+
+ merge->setSource( csv.fileName() );
+ QCOMPARE( merge->source(), csv.fileName() );
+ QCOMPARE( merge->recordList().size(), 3 );
+ QVERIFY( model->isModified() );
+
+ model->clearModified();
+ QVERIFY( !model->isModified() );
+
+ //
+ // Add some objects
+ //
+ ColorNode black( Qt::black );
+ ModelObject* object1 = new ModelLineObject( 1, 1, 90, 80, 1.0, black );
+ model->addObject( object1 );
+ QVERIFY( model->isModified() );
+ QCOMPARE( model->objectList().size(), 1 );
+ QCOMPARE( model->objectList().first(), object1 );
+
+ model->clearModified();
+ QVERIFY( !model->isModified() );
+
+ ModelObject* object2 = new ModelTextObject( 2, 2, 70, 30, false, "", "Sans", 10, QFont::Normal, false, false, black, Qt::AlignLeft, Qt::AlignTop, QTextOption::WordWrap, 1, false );
+ model->addObject( object2 );
+ QVERIFY( model->isModified() );
+ QCOMPARE( model->objectList().size(), 2 );
+ QCOMPARE( model->objectList().last(), object2 );
+
+ QString modelShortName = model->shortName(); // If no fileName set then model expects to have have this called before being saved/restored (otherwise get differing untitled names)
+
+ //
+ // Test
+ //
+ Model* saved = model->save();
+ QVERIFY( saved->isModified() );
+ QCOMPARE( saved->merge(), model->merge() ); // Shared
+ QCOMPARE( saved->variables(), model->variables() ); // Shared
+ QCOMPARE( saved->isModified(), model->isModified() );
+ QCOMPARE( saved->shortName(), modelShortName );
+ QCOMPARE( saved->shortName(), model->shortName() );
+ QCOMPARE( saved->fileName(), model->fileName() );
+ QCOMPARE( saved->rotate(), model->rotate() );
+ QCOMPARE( saved->objectList().size(), model->objectList().size() );
+ QVERIFY( saved->objectList().at(0) != object1 ); // Objects copied
+ QVERIFY( saved->objectList().at(1) != object2 ); // Objects copied
+ QCOMPARE( saved->objectList().at(0)->x0(), model->objectList().at(0)->x0() );
+ QCOMPARE( saved->objectList().at(0)->y0(), model->objectList().at(0)->y0() );
+ QCOMPARE( saved->objectList().at(1)->x0(), model->objectList().at(1)->x0() );
+ QCOMPARE( saved->objectList().at(1)->y0(), model->objectList().at(1)->y0() );
+
+ // Modify original
+ Template tmplate2( "Test Brand2", "part2", "desc2", "testPaperId2", 230, 630 );
+ FrameRect* frame2 = new FrameRect( 240, 340, 5, 0, 0, "rect2" );
+ tmplate2.addFrame( frame2 );
+ model->setTmplate( &tmplate2 );
+ QCOMPARE( model->tmplate()->brand(), QString( "Test Brand2" ) );
+ QCOMPARE( model->w(), Distance( 240 ) );
+ QCOMPARE( model->h(), Distance( 340 ) );
+
+ model->setFileName( "dir/file1.ext" );
+ QCOMPARE( model->shortName(), QString( "file1" ) );
+
+ model->setRotate( true );
+ QVERIFY( model->rotate() );
+ QCOMPARE( model->w(), Distance( 340 ) );
+ QCOMPARE( model->h(), Distance( 240 ) );
+
+ model->deleteObject( model->objectList().first() );
+ QCOMPARE( model->objectList().size(), 1 );
+ QCOMPARE( model->objectList().first(), object2 );
+
+ model->objectList().first()->setY0( model->objectList().first()->y0() + 1 );
+
+ Merge* merge2 = Factory::createMerge( TextCsv::id() );
+ QCOMPARE( merge2->id(), TextCsv::id() );
+ QTemporaryFile csv2; csv2.open(); csv2.write( "21,text21\n22,text22\n23,text23\n24,text24\n" ); csv2.close();
+ merge2->setSource( csv2.fileName() );
+ QCOMPARE( merge2->source(), csv2.fileName() );
+ QCOMPARE( merge2->recordList().size(), 4 );
+
+ model->setMerge( merge2 ); // Deletes original so saved->merge() now invalid
+ QCOMPARE( model->merge(), merge2 );
+
+ Model* modified = model->save();
+ QCOMPARE( modified->merge(), merge2 ); // Shared
+
+ Variable c( Variable::Type::COLOR, "c", "blue", Variable::Increment::PER_PAGE );
+ model->variables()->addVariable( c );
+ QCOMPARE( model->variables(), saved->variables() ); // Shared.
+
+ // Verify differences
+ QVERIFY( model->shortName() != modelShortName );
+ QVERIFY( model->shortName() != saved->shortName() );
+ QVERIFY( model->fileName() != saved->fileName() );
+ QVERIFY( model->tmplate()->brand() != saved->tmplate()->brand() );
+ QVERIFY( model->rotate() != saved->rotate() );
+ QVERIFY( model->w() != saved->w() );
+ QVERIFY( model->h() != saved->h() );
+ QVERIFY( model->objectList().size() != saved->objectList().size() );
+ QVERIFY( model->objectList().at(0)->x0() != saved->objectList().at(0)->x0() );
+ QVERIFY( model->objectList().at(0)->y0() != saved->objectList().at(0)->y0() );
+ QCOMPARE( model->objectList().at(0)->x0(), saved->objectList().at(1)->x0() ); // Unchanged
+ QVERIFY( model->objectList().at(0)->y0() != saved->objectList().at(1)->y0() );
+
+ // Restore
+ model->restore( saved );
+ QCOMPARE( model->shortName(), modelShortName );
+ QCOMPARE( model->shortName(), saved->shortName() );
+ QCOMPARE( model->fileName(), saved->fileName() );
+ QCOMPARE( model->tmplate()->brand(), saved->tmplate()->brand() );
+ QCOMPARE( model->rotate(), saved->rotate() );
+ QCOMPARE( model->w(), saved->w() );
+ QCOMPARE( model->h(), saved->h() );
+ QCOMPARE( model->objectList().size(), saved->objectList().size() );
+ QCOMPARE( model->objectList().size(), 2 );
+ QCOMPARE( model->objectList().at(0)->x0(), saved->objectList().at(0)->x0() );
+ QCOMPARE( model->objectList().at(0)->y0(), saved->objectList().at(0)->y0() );
+ QCOMPARE( model->objectList().at(1)->x0(), saved->objectList().at(1)->x0() );
+ QCOMPARE( model->objectList().at(1)->y0(), saved->objectList().at(1)->y0() );
+
+ QCOMPARE( model->merge(), merge2 ); // Unchanged
+ QVERIFY( model->merge() != saved->merge() ); // NOTE saved->merge() now points to deleted object
+ QCOMPARE( model->variables(), saved->variables() ); // Unchanged
+
+ // Unrestore
+ model->restore( modified );
+ QVERIFY( model->shortName() != modelShortName );
+ QVERIFY( model->shortName() != saved->shortName() );
+ QVERIFY( model->fileName() != saved->fileName() );
+ QVERIFY( model->tmplate()->brand() != saved->tmplate()->brand() );
+ QVERIFY( model->rotate() != saved->rotate() );
+ QVERIFY( model->w() != saved->w() );
+ QVERIFY( model->h() != saved->h() );
+ QCOMPARE( model->objectList().size(), 1 );
+ QVERIFY( model->objectList().size() != saved->objectList().size() );
+ QVERIFY( model->objectList().at(0)->x0() != saved->objectList().at(0)->x0() );
+ QVERIFY( model->objectList().at(0)->y0() != saved->objectList().at(0)->y0() );
+ QCOMPARE( model->merge(), merge2 ); // Same
+ QCOMPARE( model->variables(), saved->variables() ); // Same
+
+ QCOMPARE( model->shortName(), modified->shortName() );
+ QCOMPARE( model->fileName(), modified->fileName() );
+ QCOMPARE( model->tmplate()->brand(), modified->tmplate()->brand() );
+ QCOMPARE( model->rotate(), modified->rotate() );
+ QCOMPARE( model->w(), modified->w() );
+ QCOMPARE( model->h(), modified->h() );
+ QCOMPARE( model->objectList().size(), modified->objectList().size() );
+ QCOMPARE( model->objectList().at(0)->x0(), modified->objectList().at(0)->x0() );
+ QCOMPARE( model->objectList().at(0)->y0(), modified->objectList().at(0)->y0() );
+
+ delete model->merge(); // Final instance owned by us
+ delete model->variables(); // Instance owned by us
+ delete model;
+ delete saved;
+ delete modified;
+}
diff --git a/model/unit_tests/TestModel.h b/model/unit_tests/TestModel.h
new file mode 100644
index 0000000..5a7f580
--- /dev/null
+++ b/model/unit_tests/TestModel.h
@@ -0,0 +1,32 @@
+/* TestModel.h
+ *
+ * Copyright (C) 2019 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
+
+
+class TestModel : public QObject
+{
+ Q_OBJECT
+
+private slots:
+ void initTestCase();
+ void model();
+ void saveRestore();
+};
diff --git a/model/unit_tests/TestModelImageObject.cpp b/model/unit_tests/TestModelImageObject.cpp
new file mode 100644
index 0000000..3bcdcb4
--- /dev/null
+++ b/model/unit_tests/TestModelImageObject.cpp
@@ -0,0 +1,252 @@
+/* TestModelImageObject.cpp
+ *
+ * Copyright (C) 2019 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 "TestModelImageObject.h"
+#include "Test_Constants.h"
+
+#include "model/Model.h"
+#include "model/ModelImageObject.h"
+#include "model/Size.h"
+
+#include "merge/Factory.h"
+#include "merge/TextCsvKeys.h"
+#include "merge/Record.h"
+
+#include
+
+
+QTEST_MAIN(TestModelImageObject)
+
+using namespace glabels::model;
+using namespace glabels::merge;
+
+
+void TestModelImageObject::initTestCase()
+{
+ Factory::init();
+}
+
+
+void TestModelImageObject::readImageFile()
+{
+ QByteArray pngArray;
+ QImage png;
+ QString svgTemplate = QDir::tempPath().append( "/TestModelImageObject_XXXXXX.svg" ); // Note: directory separators canonicalized to slash by Qt path methods
+
+ Model model;
+
+ // Needed for relative file names to work
+ QString modelFileName = QDir::tempPath().append( "/TestModelImageObject.glabels" );
+ model.setFileName( modelFileName );
+
+ ModelImageObject object;
+
+ ///
+ /// Merge object, no shadow
+ ///
+ object.setX0( 1 );
+ object.setY0( 1 );
+ object.setSize( 8, 8 );
+ object.setFilenameNode( TextNode( true, "image" ) );
+
+ model.addObject( object.clone() );
+
+ ///
+ /// Variable object, green pgn, gray shadow
+ ///
+ object.setY0( 11 );
+ object.setShadow( true );
+ object.setShadowColorNode( ColorNode( Qt::gray ) );
+ object.setShadowOpacity( 1 );
+ TextNode( true, "var" );
+ object.setFilenameNode( TextNode( true, "var" ) );
+
+ // Green 8x8 square pgn
+ pngArray = QByteArray::fromBase64( glabels::test::green_8x8_png );
+ QVERIFY( png.loadFromData( pngArray, "PNG" ) );
+ QTemporaryFile pngGreen; pngGreen.open(); pngGreen.close(); png.save( pngGreen.fileName(), "PNG" );
+ QFileInfo pngGreenFileInfo( pngGreen.fileName() );
+
+ Variable var( Variable::Type::STRING, "var", pngGreenFileInfo.fileName(), Variable::Increment::PER_ITEM ); // Relative path
+ model.variables()->addVariable( var );
+
+ model.addObject( object.clone() );
+
+ ///
+ /// Variable object 2, magenta svg, yellow shadow
+ ///
+ object.setY0( 21 );
+ object.setShadow( true );
+ object.setShadowColorNode( ColorNode( Qt::yellow ) );
+ object.setShadowOpacity( 1 );
+ object.setFilenameNode( TextNode( true, "var2" ) );
+
+ // Magenta 8x8 square svg
+ QTemporaryFile svgMagenta( svgTemplate ); svgMagenta.open(); svgMagenta.write( glabels::test::magenta_8x8_svg ); svgMagenta.close();
+ QFileInfo svgMagentaFileInfo( svgMagenta.fileName() );
+
+ Variable var2( Variable::Type::STRING, "var2", svgMagentaFileInfo.fileName(), Variable::Increment::PER_ITEM ); // Absolute path
+ model.variables()->addVariable( var2 );
+
+ model.addObject( object.clone() );
+
+ ///
+ /// Filename object, yellow png, cyan shadow
+ ///
+ object.setY0( 31 );
+ object.setShadow( true );
+ object.setShadowColorNode( ColorNode( Qt::cyan ) );
+ object.setShadowOpacity( 1 );
+
+ // Yellow 8x8 square pgn
+ pngArray = QByteArray::fromBase64( glabels::test::yellow_8x8_png );
+ QVERIFY( png.loadFromData( pngArray, "PNG" ) );
+ QTemporaryFile pngYellowFile; pngYellowFile.open(); pngYellowFile.close(); png.save( pngYellowFile.fileName(), "PNG" );
+
+ QFileInfo pngYellowFileInfo( pngYellowFile.fileName() );
+
+ // Need to set object parent for relative paths to work
+ object.setParent( &model );
+
+ object.setFilenameNode( TextNode( false, pngYellowFileInfo.fileName() ) ); // Relative path
+
+ model.addObject( object.clone() );
+
+ ///
+ /// Filename object, cyan svg, magenta shadow
+ ///
+ object.setY0( 41 );
+ object.setSize( 8, 8 );
+ object.setShadow( true );
+ object.setShadowColorNode( ColorNode( Qt::magenta ) );
+ object.setShadowOpacity( 1 );
+
+ // Cyan 8x8 square svg
+ QTemporaryFile svgCyanFile( svgTemplate ); svgCyanFile.open(); svgCyanFile.write( glabels::test::cyan_8x8_svg ); svgCyanFile.close();
+
+ QFileInfo svgCyanFileInfo( svgCyanFile.fileName() );
+ object.setFilenameNode( TextNode( false, svgCyanFileInfo.filePath() ) ); // Absolute path
+
+ model.addObject( object.clone() );
+
+ ///
+ /// Set up merge
+ ///
+
+ // Blue 8x8 square pgn
+ pngArray = QByteArray::fromBase64( glabels::test::blue_8x8_png );
+ QVERIFY( png.loadFromData( pngArray, "PNG" ) );
+ QTemporaryFile png1; png1.open(); png1.close(); png.save( png1.fileName(), "PNG" );
+ QTemporaryFile png2; png2.open(); png2.close(); png.save( png2.fileName(), "PNG" );
+
+ // Red 8x8 square svg
+ QTemporaryFile svg1( svgTemplate ); svg1.open(); svg1.write( glabels::test::red_8x8_svg ); svg1.close();
+ QTemporaryFile svg2( svgTemplate ); svg2.open(); svg2.write( glabels::test::red_8x8_svg ); svg2.close();
+
+ QFileInfo png1FileInfo( png1.fileName() );
+ QFileInfo png2FileInfo( png2.fileName() );
+ QFileInfo svg1FileInfo( svg1.fileName() );
+ QFileInfo svg2FileInfo( svg2.fileName() );
+
+ QTemporaryFile csv;
+ csv.open();
+ csv.write( "id,image,type\n" );
+ csv.write( "1," ); csv.write( png1FileInfo.fileName().toUtf8() ); csv.write( ",png\n" );
+ csv.write( "2," ); csv.write( png1FileInfo.filePath().toUtf8() ); csv.write( ",png\n" );
+ csv.write( "3," ); csv.write( svg1FileInfo.fileName().toUtf8() ); csv.write( ",svg\n" );
+ csv.write( "4," ); csv.write( svg2FileInfo.filePath().toUtf8() ); csv.write( ",svg\n" );
+ csv.write( "5," ); csv.write( svg2FileInfo.fileName().toUtf8() ); csv.write( ",svg\n" );
+ csv.write( "6," ); csv.write( png2FileInfo.fileName().toUtf8() ); csv.write( ",png\n" );
+ csv.write( "7," ); csv.write( svg1FileInfo.filePath().toUtf8() ); csv.write( ",svg\n" );
+ csv.write( "8," ); csv.write( png2FileInfo.filePath().toUtf8() ); csv.write( ",png\n" );
+ csv.close();
+
+ Merge* merge = Factory::createMerge( TextCsvKeys::id() );
+ QVERIFY( merge );
+ QCOMPARE( merge->id(), TextCsvKeys::id() );
+ merge->setSource( csv.fileName() );
+ model.setMerge( merge );
+
+ ///
+ /// Draw
+ ///
+ const QList records = merge->selectedRecords();
+ QCOMPARE( records.size(), 8 );
+
+ QImage paintDevice( 10, 10 * model.objectList().size() * records.size(), QImage::Format_RGB32 );
+ paintDevice.fill( Qt::white );
+ QPainter painter( &paintDevice );
+
+ int i, cnt;
+ int yTranslate = 10 * model.objectList().size();
+ for ( i = 0, cnt = records.size(); i < cnt; i++ )
+ {
+ model.draw( &painter, false, records[i], model.variables() );
+ painter.translate( 0, yTranslate );
+ }
+
+ QColor color, white = Qt::white, grayShadow = Qt::gray, yellowShadow = Qt::yellow, cyanShadow = Qt::cyan, magentaShadow = Qt::magenta;
+ for ( i = 0, cnt = records.size(); i < cnt; i++ )
+ {
+ // Merge
+ qDebug() << "record" << i;
+ color = records[i]->value( "type" ) == "png" ? Qt::blue : Qt::red;
+ QCOMPARE( paintDevice.pixelColor( 1, 0 + i * yTranslate ), white );
+ QCOMPARE( paintDevice.pixelColor( 1, 1 + i * yTranslate ), color );
+ QCOMPARE( paintDevice.pixelColor( 1, 8 + i * yTranslate ), color );
+ QCOMPARE( paintDevice.pixelColor( 1, 9 + i * yTranslate ), white );
+ QCOMPARE( paintDevice.pixelColor( 9, 9 + i * yTranslate ), white ); // No shadow
+
+ // Variable
+ color = Qt::green;
+ QCOMPARE( paintDevice.pixelColor( 1, 10 + i * yTranslate ), white );
+ QCOMPARE( paintDevice.pixelColor( 1, 11 + i * yTranslate ), color );
+ QCOMPARE( paintDevice.pixelColor( 1, 18 + i * yTranslate ), color );
+ QCOMPARE( paintDevice.pixelColor( 1, 19 + i * yTranslate ), white );
+ QCOMPARE( paintDevice.pixelColor( 9, 19 + i * yTranslate ), grayShadow );
+
+ // Variable 2
+ color = Qt::magenta;
+ QCOMPARE( paintDevice.pixelColor( 1, 20 + i * yTranslate ), white );
+ QCOMPARE( paintDevice.pixelColor( 1, 21 + i * yTranslate ), color );
+ QCOMPARE( paintDevice.pixelColor( 1, 28 + i * yTranslate ), color );
+ QCOMPARE( paintDevice.pixelColor( 1, 29 + i * yTranslate ), white );
+ QCOMPARE( paintDevice.pixelColor( 9, 29 + i * yTranslate ), yellowShadow );
+
+ // Filename pgn
+ color = Qt::yellow;
+ QCOMPARE( paintDevice.pixelColor( 1, 30 + i * yTranslate ), white );
+ QCOMPARE( paintDevice.pixelColor( 1, 31 + i * yTranslate ), color );
+ QCOMPARE( paintDevice.pixelColor( 1, 38 + i * yTranslate ), color );
+ QCOMPARE( paintDevice.pixelColor( 1, 39 + i * yTranslate ), white );
+ QCOMPARE( paintDevice.pixelColor( 9, 39 + i * yTranslate ), cyanShadow );
+
+ // Filename svg
+ color = Qt::cyan;
+ QCOMPARE( paintDevice.pixelColor( 1, 40 + i * yTranslate ), white );
+ QCOMPARE( paintDevice.pixelColor( 1, 41 + i * yTranslate ), color );
+ QCOMPARE( paintDevice.pixelColor( 1, 48 + i * yTranslate ), color );
+ QCOMPARE( paintDevice.pixelColor( 1, 49 + i * yTranslate ), white );
+ QCOMPARE( paintDevice.pixelColor( 9, 49 + i * yTranslate ), magentaShadow );
+ }
+
+ delete model.merge();
+ delete model.variables();
+}
diff --git a/model/unit_tests/TestModelImageObject.h b/model/unit_tests/TestModelImageObject.h
new file mode 100644
index 0000000..b508d1d
--- /dev/null
+++ b/model/unit_tests/TestModelImageObject.h
@@ -0,0 +1,31 @@
+/* TestModelImageObject.h
+ *
+ * Copyright (C) 2019 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
+
+
+class TestModelImageObject : public QObject
+{
+ Q_OBJECT
+
+private slots:
+ void initTestCase();
+ void readImageFile();
+};
diff --git a/model/unit_tests/TestRawText.cpp b/model/unit_tests/TestRawText.cpp
new file mode 100644
index 0000000..f523328
--- /dev/null
+++ b/model/unit_tests/TestRawText.cpp
@@ -0,0 +1,94 @@
+/* TestRawText.cpp
+ *
+ * Copyright (C) 2019 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 "TestRawText.h"
+
+#include "model/RawText.h"
+
+#include "merge/Record.h"
+
+#include
+
+
+QTEST_MAIN(TestRawText)
+
+using namespace glabels::model;
+using namespace glabels::merge;
+
+
+void TestRawText::rawText()
+{
+ RawText rawText;
+ Record record;
+
+ QVERIFY( rawText.isEmpty() );
+ QVERIFY( !rawText.hasPlaceHolders() );
+ QCOMPARE( rawText.toString(), QString( "" ) );
+ QCOMPARE( rawText.toStdString(), std::string( "" ) );
+ QCOMPARE( rawText.expand( &record, nullptr ), QString( "" ) );
+
+ rawText = "text";
+ QVERIFY( !rawText.isEmpty() );
+ QVERIFY( !rawText.hasPlaceHolders() );
+ QCOMPARE( rawText.toString(), QString( "text" ) );
+ QCOMPARE( rawText.toStdString(), std::string( "text" ) );
+ QCOMPARE( rawText.expand( &record, nullptr ), QString( "text" ) );
+
+ RawText rawText2( "text" );
+ QVERIFY( !rawText2.isEmpty() );
+ QVERIFY( !rawText2.hasPlaceHolders() );
+ QCOMPARE( rawText2.toString(), QString( "text" ) );
+
+ rawText = "${key1}";
+ QVERIFY( !rawText.isEmpty() );
+ QVERIFY( rawText.hasPlaceHolders() );
+ QCOMPARE( rawText.toString(), QString( "${key1}" ) );
+ QCOMPARE( rawText.toStdString(), std::string( "${key1}" ) );
+ QCOMPARE( rawText.expand( &record, nullptr ), QString( "" ) );
+
+ ///
+ /// Record
+ ///
+ record["key1"] = "val1";
+ QCOMPARE( rawText.expand( &record, nullptr ), QString( "val1" ) );
+
+ rawText = "${key1}${key2}";
+ QVERIFY( rawText.hasPlaceHolders() );
+ QCOMPARE( rawText.expand( &record, nullptr ), QString( "val1" ) );
+
+ record["key2"] = "val2";
+ QCOMPARE( rawText.expand( &record, nullptr ), QString( "val1val2" ) );
+
+ rawText = "${key1}text${key2}";
+ QVERIFY( rawText.hasPlaceHolders() );
+ QCOMPARE( rawText.expand( &record, nullptr ), QString( "val1textval2" ) );
+
+ rawText = "text1${key1}text2${key2}text3";
+ QVERIFY( rawText.hasPlaceHolders() );
+ QCOMPARE( rawText.expand( &record, nullptr ), QString( "text1val1text2val2text3" ) );
+
+ rawText = "${key1}text${key2}${key3}";
+ QVERIFY( rawText.hasPlaceHolders() );
+ QCOMPARE( rawText.expand( &record, nullptr ), QString( "val1textval2" ) );
+
+ rawText = "${key2}${key3}${key1}";
+ QVERIFY( rawText.hasPlaceHolders() );
+ QCOMPARE( rawText.expand( &record, nullptr ), QString( "val2val1" ) );
+}
diff --git a/model/unit_tests/TestRawText.h b/model/unit_tests/TestRawText.h
new file mode 100644
index 0000000..781ecf8
--- /dev/null
+++ b/model/unit_tests/TestRawText.h
@@ -0,0 +1,30 @@
+/* TestRawText.h
+ *
+ * Copyright (C) 2019 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
+
+
+class TestRawText : public QObject
+{
+ Q_OBJECT
+
+private slots:
+ void rawText();
+};
diff --git a/model/unit_tests/TestSubstitutionField.cpp b/model/unit_tests/TestSubstitutionField.cpp
index fa9135a..04476b6 100644
--- a/model/unit_tests/TestSubstitutionField.cpp
+++ b/model/unit_tests/TestSubstitutionField.cpp
@@ -139,6 +139,8 @@ void TestSubstitutionField::simpleEvaluation()
{
using namespace glabels;
+ model::Variables variables;
+
model::SubstitutionField f1( "${1}" );
model::SubstitutionField f2( "${2}" );
model::SubstitutionField f3( "${3}" );
@@ -150,10 +152,10 @@ void TestSubstitutionField::simpleEvaluation()
record1[ "3" ] = "Opqrstu";
record1[ "4" ] = "Vwxyz!@";
- QCOMPARE( f1.evaluate( &record1 ), QString( "Abcdefg" ) );
- QCOMPARE( f2.evaluate( &record1 ), QString( "Hijklmn" ) );
- QCOMPARE( f3.evaluate( &record1 ), QString( "Opqrstu" ) );
- QCOMPARE( f4.evaluate( &record1 ), QString( "Vwxyz!@" ) );
+ QCOMPARE( f1.evaluate( &record1, &variables ), QString( "Abcdefg" ) );
+ QCOMPARE( f2.evaluate( &record1, &variables ), QString( "Hijklmn" ) );
+ QCOMPARE( f3.evaluate( &record1, &variables ), QString( "Opqrstu" ) );
+ QCOMPARE( f4.evaluate( &record1, &variables ), QString( "Vwxyz!@" ) );
merge::Record record2;
record2[ "1" ] = "1234567";
@@ -161,10 +163,10 @@ void TestSubstitutionField::simpleEvaluation()
record2[ "3" ] = "8901234";
record2[ "4" ] = "#$%^&*";
- QCOMPARE( f1.evaluate( &record2 ), QString( "1234567" ) );
- QCOMPARE( f2.evaluate( &record2 ), QString( "FooBar" ) );
- QCOMPARE( f3.evaluate( &record2 ), QString( "8901234" ) );
- QCOMPARE( f4.evaluate( &record2 ), QString( "#$%^&*" ) );
+ QCOMPARE( f1.evaluate( &record2, &variables ), QString( "1234567" ) );
+ QCOMPARE( f2.evaluate( &record2, &variables ), QString( "FooBar" ) );
+ QCOMPARE( f3.evaluate( &record2, &variables ), QString( "8901234" ) );
+ QCOMPARE( f4.evaluate( &record2, &variables ), QString( "#$%^&*" ) );
}
@@ -172,6 +174,8 @@ void TestSubstitutionField::defaultValueEvaluation()
{
using namespace glabels;
+ model::Variables variables;
+
model::SubstitutionField f1( "${1:=foo1}" );
model::SubstitutionField f2( "${2:=foo2}" );
model::SubstitutionField f3( "${3:=foo3}" );
@@ -183,17 +187,17 @@ void TestSubstitutionField::defaultValueEvaluation()
record1[ "3" ] = "Opqrstu";
record1[ "4" ] = "Vwxyz!@";
- QCOMPARE( f1.evaluate( &record1 ), QString( "Abcdefg" ) );
- QCOMPARE( f2.evaluate( &record1 ), QString( "Hijklmn" ) );
- QCOMPARE( f3.evaluate( &record1 ), QString( "Opqrstu" ) );
- QCOMPARE( f4.evaluate( &record1 ), QString( "Vwxyz!@" ) );
+ QCOMPARE( f1.evaluate( &record1, &variables ), QString( "Abcdefg" ) );
+ QCOMPARE( f2.evaluate( &record1, &variables ), QString( "Hijklmn" ) );
+ QCOMPARE( f3.evaluate( &record1, &variables ), QString( "Opqrstu" ) );
+ QCOMPARE( f4.evaluate( &record1, &variables ), QString( "Vwxyz!@" ) );
merge::Record record2; // All fields empty
- QCOMPARE( f1.evaluate( &record2 ), QString( "foo1" ) );
- QCOMPARE( f2.evaluate( &record2 ), QString( "foo2" ) );
- QCOMPARE( f3.evaluate( &record2 ), QString( "foo3" ) );
- QCOMPARE( f4.evaluate( &record2 ), QString( "foo4" ) );
+ QCOMPARE( f1.evaluate( &record2, &variables ), QString( "foo1" ) );
+ QCOMPARE( f2.evaluate( &record2, &variables ), QString( "foo2" ) );
+ QCOMPARE( f3.evaluate( &record2, &variables ), QString( "foo3" ) );
+ QCOMPARE( f4.evaluate( &record2, &variables ), QString( "foo4" ) );
merge::Record record3;
record3[ "1" ] = "xyzzy";
@@ -201,10 +205,10 @@ void TestSubstitutionField::defaultValueEvaluation()
// Field "3" empty
record3[ "4" ] = "plugh";
- QCOMPARE( f1.evaluate( &record3 ), QString( "xyzzy" ) );
- QCOMPARE( f2.evaluate( &record3 ), QString( "foo2" ) );
- QCOMPARE( f3.evaluate( &record3 ), QString( "foo3" ) );
- QCOMPARE( f4.evaluate( &record3 ), QString( "plugh" ) );
+ QCOMPARE( f1.evaluate( &record3, &variables ), QString( "xyzzy" ) );
+ QCOMPARE( f2.evaluate( &record3, &variables ), QString( "foo2" ) );
+ QCOMPARE( f3.evaluate( &record3, &variables ), QString( "foo3" ) );
+ QCOMPARE( f4.evaluate( &record3, &variables ), QString( "plugh" ) );
}
@@ -212,6 +216,8 @@ void TestSubstitutionField::formattedStringEvaluation()
{
using namespace glabels;
+ model::Variables variables;
+
model::SubstitutionField f1( "${1:%10s}" );
model::SubstitutionField f2( "${2:%10s}" );
model::SubstitutionField f3( "${3:%10s}" );
@@ -233,15 +239,15 @@ void TestSubstitutionField::formattedStringEvaluation()
record1[ "7" ] = "-100";
record1[ "8" ] = "3.14";
- QCOMPARE( f1.evaluate( &record1 ), QString( " 0" ) );
- QCOMPARE( f2.evaluate( &record1 ), QString( " 1" ) );
- QCOMPARE( f3.evaluate( &record1 ), QString( " -1" ) );
- QCOMPARE( f4.evaluate( &record1 ), QString( " 3.14" ) );
+ QCOMPARE( f1.evaluate( &record1, &variables ), QString( " 0" ) );
+ QCOMPARE( f2.evaluate( &record1, &variables ), QString( " 1" ) );
+ QCOMPARE( f3.evaluate( &record1, &variables ), QString( " -1" ) );
+ QCOMPARE( f4.evaluate( &record1, &variables ), QString( " 3.14" ) );
- QCOMPARE( f5.evaluate( &record1 ), QString( "0 " ) );
- QCOMPARE( f6.evaluate( &record1 ), QString( "100 " ) );
- QCOMPARE( f7.evaluate( &record1 ), QString( "-100 " ) );
- QCOMPARE( f8.evaluate( &record1 ), QString( "3.14 " ) );
+ QCOMPARE( f5.evaluate( &record1, &variables ), QString( "0 " ) );
+ QCOMPARE( f6.evaluate( &record1, &variables ), QString( "100 " ) );
+ QCOMPARE( f7.evaluate( &record1, &variables ), QString( "-100 " ) );
+ QCOMPARE( f8.evaluate( &record1, &variables ), QString( "3.14 " ) );
}
@@ -249,6 +255,8 @@ void TestSubstitutionField::formattedFloatEvaluation()
{
using namespace glabels;
+ model::Variables variables;
+
model::SubstitutionField f1( "${1:%+5.2f}" );
model::SubstitutionField f2( "${2:%+5.2f}" );
model::SubstitutionField f3( "${3:%+5.2f}" );
@@ -270,15 +278,15 @@ void TestSubstitutionField::formattedFloatEvaluation()
record1[ "7" ] = "-100";
record1[ "8" ] = "3.14";
- QCOMPARE( f1.evaluate( &record1 ), QString( "+0.00" ) );
- QCOMPARE( f2.evaluate( &record1 ), QString( "+1.00" ) );
- QCOMPARE( f3.evaluate( &record1 ), QString( "-1.00" ) );
- QCOMPARE( f4.evaluate( &record1 ), QString( "+3.14" ) );
+ QCOMPARE( f1.evaluate( &record1, &variables ), QString( "+0.00" ) );
+ QCOMPARE( f2.evaluate( &record1, &variables ), QString( "+1.00" ) );
+ QCOMPARE( f3.evaluate( &record1, &variables ), QString( "-1.00" ) );
+ QCOMPARE( f4.evaluate( &record1, &variables ), QString( "+3.14" ) );
- QCOMPARE( f5.evaluate( &record1 ), QString( "+0.00e+00" ) );
- QCOMPARE( f6.evaluate( &record1 ), QString( "+1.00e+02" ) );
- QCOMPARE( f7.evaluate( &record1 ), QString( "-1.00e+02" ) );
- QCOMPARE( f8.evaluate( &record1 ), QString( "+3.14e+00" ) );
+ QCOMPARE( f5.evaluate( &record1, &variables ), QString( "+0.00e+00" ) );
+ QCOMPARE( f6.evaluate( &record1, &variables ), QString( "+1.00e+02" ) );
+ QCOMPARE( f7.evaluate( &record1, &variables ), QString( "-1.00e+02" ) );
+ QCOMPARE( f8.evaluate( &record1, &variables ), QString( "+3.14e+00" ) );
}
@@ -286,6 +294,8 @@ void TestSubstitutionField::formattedIntEvaluation()
{
using namespace glabels;
+ model::Variables variables;
+
model::SubstitutionField f1( "${1:%08d}" );
model::SubstitutionField f2( "${2:%08d}" );
model::SubstitutionField f3( "${3:%08d}" );
@@ -307,15 +317,15 @@ void TestSubstitutionField::formattedIntEvaluation()
record1[ "7" ] = "-1";
record1[ "8" ] = "314";
- QCOMPARE( f1.evaluate( &record1 ), QString( "00000000" ) );
- QCOMPARE( f2.evaluate( &record1 ), QString( "00000001" ) );
- QCOMPARE( f3.evaluate( &record1 ), QString( "-0000001" ) );
- QCOMPARE( f4.evaluate( &record1 ), QString( "00000000" ) ); // Invalid integer value
+ QCOMPARE( f1.evaluate( &record1, &variables ), QString( "00000000" ) );
+ QCOMPARE( f2.evaluate( &record1, &variables ), QString( "00000001" ) );
+ QCOMPARE( f3.evaluate( &record1, &variables ), QString( "-0000001" ) );
+ QCOMPARE( f4.evaluate( &record1, &variables ), QString( "00000000" ) ); // Invalid integer value
- QCOMPARE( f5.evaluate( &record1 ), QString( "00000064" ) ); // 100(decimal) == 64(hex)
- QCOMPARE( f6.evaluate( &record1 ), QString( "00000100" ) );
- QCOMPARE( f7.evaluate( &record1 ), QString( "00000000" ) ); // Invalid unsigned integer
- QCOMPARE( f8.evaluate( &record1 ), QString( "0000013a" ) ); // 314(decimal) == 13a(hex)
+ QCOMPARE( f5.evaluate( &record1, &variables ), QString( "00000064" ) ); // 100(decimal) == 64(hex)
+ QCOMPARE( f6.evaluate( &record1, &variables ), QString( "00000100" ) );
+ QCOMPARE( f7.evaluate( &record1, &variables ), QString( "00000000" ) ); // Invalid unsigned integer
+ QCOMPARE( f8.evaluate( &record1, &variables ), QString( "0000013a" ) ); // 314(decimal) == 13a(hex)
}
@@ -323,6 +333,8 @@ void TestSubstitutionField::newLineEvaluation()
{
using namespace glabels;
+ model::Variables variables;
+
model::SubstitutionField addr2( "${ADDR2:n}" );
QCOMPARE( addr2.fieldName(), QString( "ADDR2" ) );
QCOMPARE( addr2.newLine(), true );
@@ -336,7 +348,7 @@ void TestSubstitutionField::newLineEvaluation()
merge::Record record3;
// ADDR2 not defined
- QCOMPARE( addr2.evaluate( &record1 ), QString( "\nApt. 5B" ) ); // Prepends a newline
- QCOMPARE( addr2.evaluate( &record2 ), QString( "" ) ); // Evaluates empty
- QCOMPARE( addr2.evaluate( &record3 ), QString( "" ) ); // Evaluates empty
+ QCOMPARE( addr2.evaluate( &record1, &variables ), QString( "\nApt. 5B" ) ); // Prepends a newline
+ QCOMPARE( addr2.evaluate( &record2, &variables ), QString( "" ) ); // Evaluates empty
+ QCOMPARE( addr2.evaluate( &record3, &variables ), QString( "" ) ); // Evaluates empty
}
diff --git a/model/unit_tests/TestTextNode.cpp b/model/unit_tests/TestTextNode.cpp
new file mode 100644
index 0000000..19b2532
--- /dev/null
+++ b/model/unit_tests/TestTextNode.cpp
@@ -0,0 +1,124 @@
+/* TestTextNode.cpp
+ *
+ * Copyright (C) 2019 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 "TestTextNode.h"
+
+#include "model/TextNode.h"
+
+#include
+
+
+QTEST_MAIN(TestTextNode)
+
+using namespace glabels::model;
+using namespace glabels::merge;
+
+
+void TestTextNode::textNode()
+{
+ Record record;
+ Variables vars;
+
+ TextNode textNode;
+ QVERIFY( !textNode.isField() );
+ QCOMPARE( textNode.data(), QString( "" ) );
+ QVERIFY( textNode == TextNode() );
+ QVERIFY( !(textNode != TextNode()) );
+ QCOMPARE( textNode.text( nullptr, nullptr ), QString( "" ) );
+ QCOMPARE( textNode.text( &record, nullptr ), QString( "" ) );
+ QCOMPARE( textNode.text( nullptr, &vars ), QString( "" ) );
+ QCOMPARE( textNode.text( &record, &vars ), QString( "" ) );
+
+ textNode.setField( true );
+ QVERIFY( textNode.isField() );
+ QCOMPARE( textNode.text( &record, nullptr ), QString( "" ) );
+
+ textNode.setField( false );
+ QVERIFY( !textNode.isField() );
+
+ textNode.setData( QString( "data1" ) );
+ QCOMPARE( textNode.data(), QString( "data1" ) );
+ QCOMPARE( textNode.text( nullptr, nullptr ), QString( "data1" ) );
+ QCOMPARE( textNode.text( &record, nullptr ), QString( "data1" ) );
+ QCOMPARE( textNode.text( nullptr, &vars ), QString( "data1" ) );
+ QCOMPARE( textNode.text( &record, &vars ), QString( "data1" ) );
+
+ textNode.setField( true );
+ QCOMPARE( textNode.text( nullptr, nullptr ), QString( "" ) );
+ QCOMPARE( textNode.text( &record, nullptr ), QString( "" ) );
+ QCOMPARE( textNode.text( nullptr, &vars ), QString( "" ) );
+ QCOMPARE( textNode.text( &record, &vars ), QString( "" ) );
+
+ ///
+ /// Constructors
+ ///
+ TextNode textNode2( true, "data2" );
+ QVERIFY( textNode2.isField() );
+ QCOMPARE( textNode2.data(), QString( "data2" ) );
+ textNode.setField( false );
+ QVERIFY( !(textNode2 == textNode) );
+ QVERIFY( textNode2 != textNode );
+ textNode.setField( true );
+ QVERIFY( !(textNode2 == textNode) );
+ QVERIFY( textNode2 != textNode );
+ textNode.setData( QString( "data2" ) );
+ QVERIFY( textNode2 == textNode );
+ QVERIFY( !(textNode2 != textNode) );
+
+ ///
+ /// Record
+ ///
+ record["key1"] = "";
+ QCOMPARE( textNode.text( &record, nullptr ), QString( "" ) );
+
+ textNode.setData( QString( "key1" ) );
+ QCOMPARE( textNode.text( &record, nullptr ), QString( "" ) );
+
+ record["key1"] = "val1";
+ QCOMPARE( textNode.text( &record, nullptr ), QString( "val1" ) );
+
+ ///
+ /// Variable
+ ///
+ {
+ Variable key1( Variable::Type::STRING, "key1", "", Variable::Increment::PER_ITEM );
+ vars.addVariable( key1 );
+ }
+ QCOMPARE( textNode.text( nullptr, &vars ), QString( "" ) );
+
+ {
+ Variable key1( Variable::Type::STRING, "key1", "val1", Variable::Increment::PER_ITEM );
+ vars.addVariable( key1 );
+ }
+ QCOMPARE( textNode.text( nullptr, &vars ), QString( "val1" ) );
+
+ {
+ Variable key1( Variable::Type::INTEGER, "key1", "1", Variable::Increment::PER_ITEM, "1" );
+ vars.addVariable( key1 );
+ }
+ QCOMPARE( textNode.text( nullptr, &vars ), QString( "1" ) );
+ vars.incrementVariablesOnItem();
+ QCOMPARE( textNode.text( nullptr, &vars ), QString( "2" ) );
+
+ ///
+ /// Record beats variable
+ ///
+ QCOMPARE( textNode.text( &record, &vars ), QString( "val1" ) );
+}
diff --git a/model/unit_tests/TestTextNode.h b/model/unit_tests/TestTextNode.h
new file mode 100644
index 0000000..76553d3
--- /dev/null
+++ b/model/unit_tests/TestTextNode.h
@@ -0,0 +1,30 @@
+/* TestTextNode.h
+ *
+ * Copyright (C) 2019 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
+
+
+class TestTextNode : public QObject
+{
+ Q_OBJECT
+
+private slots:
+ void textNode();
+};
diff --git a/model/unit_tests/TestVariable.cpp b/model/unit_tests/TestVariable.cpp
new file mode 100644
index 0000000..85efadc
--- /dev/null
+++ b/model/unit_tests/TestVariable.cpp
@@ -0,0 +1,300 @@
+/* TestVariable.cpp
+ *
+ * Copyright (C) 2019 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 "TestVariable.h"
+
+#include "model/Variable.h"
+
+#include
+
+
+QTEST_MAIN(TestVariable)
+
+using namespace glabels::model;
+
+
+void TestVariable::variable()
+{
+ {
+ Variable var;
+
+ QCOMPARE( var.type(), Variable::Type::STRING );
+ QCOMPARE( var.name(), QString() );
+ QCOMPARE( var.initialValue(), QString() );
+ QCOMPARE( var.increment(), Variable::Increment::NEVER );
+ QCOMPARE( var.stepSize(), QString( "0" ) );
+ QCOMPARE( var.value(), QString() );
+
+ var.resetValue();
+ QCOMPARE( var.type(), Variable::Type::STRING );
+ QCOMPARE( var.name(), QString() );
+ QCOMPARE( var.initialValue(), QString() );
+ QCOMPARE( var.increment(), Variable::Increment::NEVER );
+ QCOMPARE( var.stepSize(), QString( "0" ) );
+ QCOMPARE( var.value(), QString() );
+
+ var.incrementValueOnItem();
+ QCOMPARE( var.value(), QString() );
+
+ var.incrementValueOnCopy();
+ QCOMPARE( var.value(), QString() );
+
+ var.incrementValueOnPage();
+ QCOMPARE( var.value(), QString() );
+ }
+ {
+ Variable var( Variable::Type::STRING, "s", "initial", Variable::Increment::PER_ITEM, "2" );
+
+ QCOMPARE( var.type(), Variable::Type::STRING );
+ QCOMPARE( var.name(), QString( "s" ) );
+ QCOMPARE( var.initialValue(), QString( "initial" ) );
+ QCOMPARE( var.increment(), Variable::Increment::PER_ITEM );
+ QCOMPARE( var.stepSize(), QString( "2" ) );
+ QCOMPARE( var.value(), QString( "initial" ) );
+
+ var.resetValue();
+ QCOMPARE( var.name(), QString( "s" ) );
+ QCOMPARE( var.initialValue(), QString( "initial" ) );
+ QCOMPARE( var.increment(), Variable::Increment::PER_ITEM );
+ QCOMPARE( var.stepSize(), QString( "2" ) );
+ QCOMPARE( var.value(), QString( "initial" ) );
+
+ var.incrementValueOnItem();
+ QCOMPARE( var.value(), QString( "initial" ) );
+
+ var.incrementValueOnCopy();
+ QCOMPARE( var.value(), QString( "initial" ) );
+
+ var.incrementValueOnPage();
+ QCOMPARE( var.value(), QString( "initial" ) );
+
+ var.resetValue();
+ QCOMPARE( var.name(), QString( "s" ) );
+ QCOMPARE( var.initialValue(), QString( "initial" ) );
+ QCOMPARE( var.increment(), Variable::Increment::PER_ITEM );
+ QCOMPARE( var.stepSize(), QString( "2" ) );
+ QCOMPARE( var.value(), QString( "initial" ) );
+ }
+ {
+ Variable var( Variable::Type::INTEGER, "i", "123", Variable::Increment::PER_ITEM, "1" );
+
+ QCOMPARE( var.type(), Variable::Type::INTEGER );
+ QCOMPARE( var.name(), QString( "i" ) );
+ QCOMPARE( var.initialValue(), QString( "123" ) );
+ QCOMPARE( var.increment(), Variable::Increment::PER_ITEM );
+ QCOMPARE( var.stepSize(), QString( "1" ) );
+ QCOMPARE( var.value(), QString( "123" ) );
+
+ var.resetValue();
+ QCOMPARE( var.type(), Variable::Type::INTEGER );
+ QCOMPARE( var.name(), QString( "i" ) );
+ QCOMPARE( var.initialValue(), QString( "123" ) );
+ QCOMPARE( var.increment(), Variable::Increment::PER_ITEM );
+ QCOMPARE( var.stepSize(), QString( "1" ) );
+ QCOMPARE( var.value(), QString( "123" ) );
+
+ var.incrementValueOnItem();
+ QCOMPARE( var.value(), QString( "124" ) );
+
+ var.incrementValueOnCopy();
+ QCOMPARE( var.value(), QString( "124" ) );
+
+ var.incrementValueOnPage();
+ QCOMPARE( var.value(), QString( "124" ) );
+
+ var.incrementValueOnItem();
+ QCOMPARE( var.value(), QString( "125" ) );
+
+ var.incrementValueOnCopy();
+ QCOMPARE( var.value(), QString( "125" ) );
+
+ var.incrementValueOnPage();
+ QCOMPARE( var.value(), QString( "125" ) );
+
+ var.resetValue();
+ QCOMPARE( var.type(), Variable::Type::INTEGER );
+ QCOMPARE( var.name(), QString( "i" ) );
+ QCOMPARE( var.initialValue(), QString( "123" ) );
+ QCOMPARE( var.increment(), Variable::Increment::PER_ITEM );
+ QCOMPARE( var.stepSize(), QString( "1" ) );
+ QCOMPARE( var.value(), QString( "123" ) );
+ }
+ {
+ Variable var( Variable::Type::INTEGER, "i", "1", Variable::Increment::PER_PAGE, "2" );
+
+ QCOMPARE( var.type(), Variable::Type::INTEGER );
+ QCOMPARE( var.name(), QString( "i" ) );
+ QCOMPARE( var.initialValue(), QString( "1" ) );
+ QCOMPARE( var.increment(), Variable::Increment::PER_PAGE );
+ QCOMPARE( var.stepSize(), QString( "2" ) );
+ QCOMPARE( var.value(), QString( "1" ) );
+
+ var.resetValue();
+ QCOMPARE( var.type(), Variable::Type::INTEGER );
+ QCOMPARE( var.name(), QString( "i" ) );
+ QCOMPARE( var.initialValue(), QString( "1" ) );
+ QCOMPARE( var.increment(), Variable::Increment::PER_PAGE );
+ QCOMPARE( var.stepSize(), QString( "2" ) );
+ QCOMPARE( var.value(), QString( "1" ) );
+
+ var.incrementValueOnItem();
+ QCOMPARE( var.value(), QString( "1" ) );
+
+ var.incrementValueOnCopy();
+ QCOMPARE( var.value(), QString( "1" ) );
+
+ var.incrementValueOnPage();
+ QCOMPARE( var.value(), QString( "3" ) );
+
+ var.incrementValueOnItem();
+ QCOMPARE( var.value(), QString( "3" ) );
+
+ var.incrementValueOnCopy();
+ QCOMPARE( var.value(), QString( "3" ) );
+
+ var.incrementValueOnPage();
+ QCOMPARE( var.value(), QString( "5" ) );
+
+ var.resetValue();
+ QCOMPARE( var.type(), Variable::Type::INTEGER );
+ QCOMPARE( var.name(), QString( "i" ) );
+ QCOMPARE( var.initialValue(), QString( "1" ) );
+ QCOMPARE( var.increment(), Variable::Increment::PER_PAGE );
+ QCOMPARE( var.stepSize(), QString( "2" ) );
+ QCOMPARE( var.value(), QString( "1" ) );
+ }
+ {
+ Variable var( Variable::Type::FLOATING_POINT, "f", "1.2", Variable::Increment::PER_COPY, "0.2" );
+
+ QCOMPARE( var.type(), Variable::Type::FLOATING_POINT );
+ QCOMPARE( var.name(), QString( "f" ) );
+ QCOMPARE( var.initialValue(), QString( "1.2" ) );
+ QCOMPARE( var.increment(), Variable::Increment::PER_COPY );
+ QCOMPARE( var.stepSize(), QString( "0.2" ) );
+ QCOMPARE( var.value(), QString( "1.2" ) );
+
+ var.resetValue();
+ QCOMPARE( var.type(), Variable::Type::FLOATING_POINT );
+ QCOMPARE( var.name(), QString( "f" ) );
+ QCOMPARE( var.initialValue(), QString( "1.2" ) );
+ QCOMPARE( var.increment(), Variable::Increment::PER_COPY );
+ QCOMPARE( var.stepSize(), QString( "0.2" ) );
+ QCOMPARE( var.value(), QString( "1.2" ) );
+
+ var.incrementValueOnItem();
+ QCOMPARE( var.value(), QString( "1.2" ) );
+
+ var.incrementValueOnCopy();
+ QCOMPARE( var.value(), QString( "1.4" ) );
+
+ var.incrementValueOnPage();
+ QCOMPARE( var.value(), QString( "1.4" ) );
+
+ var.incrementValueOnItem();
+ QCOMPARE( var.value(), QString( "1.4" ) );
+
+ var.incrementValueOnCopy();
+ QCOMPARE( var.value(), QString( "1.6" ) );
+
+ var.incrementValueOnPage();
+ QCOMPARE( var.value(), QString( "1.6" ) );
+
+ var.resetValue();
+ QCOMPARE( var.type(), Variable::Type::FLOATING_POINT );
+ QCOMPARE( var.name(), QString( "f" ) );
+ QCOMPARE( var.initialValue(), QString( "1.2" ) );
+ QCOMPARE( var.increment(), Variable::Increment::PER_COPY );
+ QCOMPARE( var.stepSize(), QString( "0.2" ) );
+ QCOMPARE( var.value(), QString( "1.2" ) );
+ }
+ {
+ Variable var( Variable::Type::COLOR, "c", "white", Variable::Increment::PER_PAGE );
+
+ QCOMPARE( var.type(), Variable::Type::COLOR );
+ QCOMPARE( var.name(), QString( "c" ) );
+ QCOMPARE( var.initialValue(), QString( "white" ) );
+ QCOMPARE( var.increment(), Variable::Increment::PER_PAGE );
+ QCOMPARE( var.stepSize(), QString( "0" ) );
+ QCOMPARE( var.value(), QString( "white" ) );
+
+ var.resetValue();
+ QCOMPARE( var.name(), QString( "c" ) );
+ QCOMPARE( var.initialValue(), QString( "white" ) );
+ QCOMPARE( var.increment(), Variable::Increment::PER_PAGE );
+ QCOMPARE( var.stepSize(), QString( "0" ) );
+ QCOMPARE( var.value(), QString( "white" ) );
+
+ var.incrementValueOnItem();
+ QCOMPARE( var.value(), QString( "white" ) );
+
+ var.incrementValueOnCopy();
+ QCOMPARE( var.value(), QString( "white" ) );
+
+ var.incrementValueOnPage();
+ QCOMPARE( var.value(), QString( "white" ) );
+
+ var.resetValue();
+ QCOMPARE( var.name(), QString( "c" ) );
+ QCOMPARE( var.initialValue(), QString( "white" ) );
+ QCOMPARE( var.increment(), Variable::Increment::PER_PAGE );
+ QCOMPARE( var.stepSize(), QString( "0" ) );
+ QCOMPARE( var.value(), QString( "white" ) );
+ }
+}
+
+
+void TestVariable::statics()
+{
+ QCOMPARE( Variable::typeToI18nString( Variable::Type::STRING ), QString( "String" ) );
+ QCOMPARE( Variable::typeToI18nString( Variable::Type::INTEGER ), QString( "Integer" ) );
+ QCOMPARE( Variable::typeToI18nString( Variable::Type::FLOATING_POINT ), QString( "Floating Point" ) );
+ QCOMPARE( Variable::typeToI18nString( Variable::Type::COLOR ), QString( "Color" ) );
+ QCOMPARE( Variable::typeToI18nString( (Variable::Type)4 ), QString( "String" ) );
+
+ QCOMPARE( Variable::typeToIdString( Variable::Type::STRING ), QString( "string" ) );
+ QCOMPARE( Variable::typeToIdString( Variable::Type::INTEGER ), QString( "integer" ) );
+ QCOMPARE( Variable::typeToIdString( Variable::Type::FLOATING_POINT ), QString( "float" ) );
+ QCOMPARE( Variable::typeToIdString( Variable::Type::COLOR ), QString( "color" ) );
+ QCOMPARE( Variable::typeToIdString( (Variable::Type)4 ), QString( "string" ) );
+
+ QCOMPARE( Variable::idStringToType( "string" ), Variable::Type::STRING );
+ QCOMPARE( Variable::idStringToType( "integer"), Variable::Type::INTEGER );
+ QCOMPARE( Variable::idStringToType( "float" ), Variable::Type::FLOATING_POINT );
+ QCOMPARE( Variable::idStringToType( "color" ), Variable::Type::COLOR );
+ QCOMPARE( Variable::idStringToType( "non_existent" ), Variable::Type::STRING );
+
+ QCOMPARE( Variable::incrementToI18nString( Variable::Increment::NEVER ), QString( "Never" ) );
+ QCOMPARE( Variable::incrementToI18nString( Variable::Increment::PER_ITEM ), QString( "Per item" ) );
+ QCOMPARE( Variable::incrementToI18nString( Variable::Increment::PER_COPY ), QString( "Per copy" ) );
+ QCOMPARE( Variable::incrementToI18nString( Variable::Increment::PER_PAGE ), QString( "Per page" ) );
+ QCOMPARE( Variable::incrementToI18nString( (Variable::Increment)4 ), QString( "Never" ) );
+
+ QCOMPARE( Variable::incrementToIdString( Variable::Increment::NEVER ), QString( "never" ) );
+ QCOMPARE( Variable::incrementToIdString( Variable::Increment::PER_ITEM ), QString( "per_item" ) );
+ QCOMPARE( Variable::incrementToIdString( Variable::Increment::PER_COPY ), QString( "per_copy" ) );
+ QCOMPARE( Variable::incrementToIdString( Variable::Increment::PER_PAGE ), QString( "per_page" ) );
+ QCOMPARE( Variable::incrementToIdString( (Variable::Increment)4 ), QString( "never" ) );
+
+ QCOMPARE( Variable::idStringToIncrement( "never" ), Variable::Increment::NEVER );
+ QCOMPARE( Variable::idStringToIncrement( "per_item" ), Variable::Increment::PER_ITEM );
+ QCOMPARE( Variable::idStringToIncrement( "per_copy" ), Variable::Increment::PER_COPY );
+ QCOMPARE( Variable::idStringToIncrement( "per_page" ), Variable::Increment::PER_PAGE );
+ QCOMPARE( Variable::idStringToIncrement( "non_existent" ), Variable::Increment::NEVER );
+}
diff --git a/model/unit_tests/TestVariable.h b/model/unit_tests/TestVariable.h
new file mode 100644
index 0000000..9cad55d
--- /dev/null
+++ b/model/unit_tests/TestVariable.h
@@ -0,0 +1,31 @@
+/* TestVariable.h
+ *
+ * Copyright (C) 2019 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
+
+
+class TestVariable : public QObject
+{
+ Q_OBJECT
+
+private slots:
+ void variable();
+ void statics();
+};
diff --git a/model/unit_tests/TestVariables.cpp b/model/unit_tests/TestVariables.cpp
new file mode 100644
index 0000000..c7f6ce4
--- /dev/null
+++ b/model/unit_tests/TestVariables.cpp
@@ -0,0 +1,157 @@
+/* TestVariables.cpp
+ *
+ * Copyright (C) 2019 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 "TestVariables.h"
+
+#include "model/Variables.h"
+
+#include
+
+
+QTEST_MAIN(TestVariables)
+
+using namespace glabels::model;
+
+
+void TestVariables::variables()
+{
+ Variables vars;
+
+ Variable i( Variable::Type::INTEGER, "i", "3", Variable::Increment::PER_ITEM, "3" );
+ QCOMPARE( i.value(), QString( "3" ) );
+
+ Variable i2( Variable::Type::INTEGER, "i2", "100", Variable::Increment::PER_COPY, "2" );
+ QCOMPARE( i2.value(), QString( "100" ) );
+
+ Variable f( Variable::Type::FLOATING_POINT, "f", "0.0", Variable::Increment::PER_PAGE, "0.1" );
+ QCOMPARE( f.value(), QString( "0" ) );
+
+ Variable s( Variable::Type::STRING, "s", "initial", Variable::Increment::PER_ITEM, "1" );
+ QCOMPARE( s.value(), QString( "initial" ) );
+
+ Variable c( Variable::Type::COLOR, "c", "white", Variable::Increment::PER_ITEM, "01" );
+ QCOMPARE( c.value(), QString( "white" ) );
+
+ QVERIFY( !vars.hasVariable( "i" ) );
+ QVERIFY( !vars.hasVariable( "i2" ) );
+
+ // Add, delete
+ vars.addVariable( i );
+ QVERIFY( vars.hasVariable( "i" ) );
+ QCOMPARE( vars["i"].value(), i.value() );
+ vars.deleteVariable( "i" );
+ QVERIFY( !vars.hasVariable( "i" ) );
+ QCOMPARE( vars["i"].value(), QString() );
+
+ // Add, replace
+ vars.addVariable( i );
+ QVERIFY( vars.hasVariable( "i" ) );
+ QCOMPARE( vars["i"].value(), i.value() );
+ vars.replaceVariable( "i", i2 );
+ QVERIFY( !vars.hasVariable( "i" ) );
+ QVERIFY( vars.hasVariable( "i2" ) );
+ QCOMPARE( vars["i2"].value(), i2.value() );
+ QCOMPARE( vars["i"].value(), QString() );
+ vars.deleteVariable( "i2" );
+ QVERIFY( !vars.hasVariable( "i2" ) );
+
+ // Increment
+ vars.addVariable( i );
+ vars.addVariable( i2 );
+ vars.addVariable( f );
+ vars.addVariable( s );
+ vars.addVariable( c );
+
+ QVERIFY( vars.hasVariable( "i" ) ); // PER_ITEM
+ QVERIFY( vars.hasVariable( "i2" ) ); // PER_COPY
+ QVERIFY( vars.hasVariable( "f" ) ); // PER_PAGE
+ QVERIFY( vars.hasVariable( "s" ) );
+ QVERIFY( vars.hasVariable( "c" ) );
+
+ QCOMPARE( vars["i"].value(), QString( "3" ) );
+ QCOMPARE( vars["i2"].value(), QString( "100" ) ); // PRE_COPY
+ QCOMPARE( vars["f"].value(), QString( "0" ) ); // PER_PAGE
+ QCOMPARE( vars["s"].value(), QString( "initial" ) );
+ QCOMPARE( vars["c"].value(), QString( "white" ) );
+
+ vars.resetVariables();
+
+ QCOMPARE( vars["i"].value(), QString( "3" ) ); // PER_ITEM
+ QCOMPARE( vars["i2"].value(), QString( "100" ) ); // PRE_COPY
+ QCOMPARE( vars["f"].value(), QString( "0" ) ); // PER_PAGE
+ QCOMPARE( vars["s"].value(), QString( "initial" ) );
+ QCOMPARE( vars["c"].value(), QString( "white" ) );
+
+ vars.incrementVariablesOnItem();
+
+ QCOMPARE( vars["i"].value(), QString( "6" ) ); // PER_ITEM
+ QCOMPARE( vars["i2"].value(), QString( "100" ) ); // PER_COPY
+ QCOMPARE( vars["f"].value(), QString( "0" ) ); // PER_PAGE
+ QCOMPARE( vars["s"].value(), QString( "initial" ) );
+ QCOMPARE( vars["c"].value(), QString( "white" ) );
+
+ vars.incrementVariablesOnItem();
+
+ QCOMPARE( vars["i"].value(), QString( "9" ) ); // PER_ITEM
+ QCOMPARE( vars["i2"].value(), QString( "100" ) ); // PER_COPY
+ QCOMPARE( vars["f"].value(), QString( "0" ) ); // PER_PAGE
+ QCOMPARE( vars["s"].value(), QString( "initial" ) );
+ QCOMPARE( vars["c"].value(), QString( "white" ) );
+
+ vars.incrementVariablesOnCopy();
+
+ QCOMPARE( vars["i"].value(), QString( "9" ) ); // PER_ITEM
+ QCOMPARE( vars["i2"].value(), QString( "102" ) ); // PER_COPY
+ QCOMPARE( vars["f"].value(), QString( "0" ) ); // PER_PAGE
+ QCOMPARE( vars["s"].value(), QString( "initial" ) );
+ QCOMPARE( vars["c"].value(), QString( "white" ) );
+
+ vars.incrementVariablesOnCopy();
+
+ QCOMPARE( vars["i"].value(), QString( "9" ) ); // PER_ITEM
+ QCOMPARE( vars["i2"].value(), QString( "104" ) ); // PER_COPY
+ QCOMPARE( vars["f"].value(), QString( "0" ) ); // PER_PAGE
+ QCOMPARE( vars["s"].value(), QString( "initial" ) );
+ QCOMPARE( vars["c"].value(), QString( "white" ) );
+
+ vars.incrementVariablesOnPage();
+
+ QCOMPARE( vars["i"].value(), QString( "9" ) ); // PER_ITEM
+ QCOMPARE( vars["i2"].value(), QString( "104" ) ); // PER_COPY
+ QCOMPARE( vars["f"].value(), QString( "0.1" ) ); // PER_PAGE
+ QCOMPARE( vars["s"].value(), QString( "initial" ) );
+ QCOMPARE( vars["c"].value(), QString( "white" ) );
+
+ vars.incrementVariablesOnPage();
+
+ QCOMPARE( vars["i"].value(), QString( "9" ) ); // PER_ITEM
+ QCOMPARE( vars["i2"].value(), QString( "104" ) ); // PER_COPY
+ QCOMPARE( vars["f"].value(), QString( "0.2" ) ); // PER_PAGE
+ QCOMPARE( vars["s"].value(), QString( "initial" ) );
+ QCOMPARE( vars["c"].value(), QString( "white" ) );
+
+ vars.resetVariables();
+
+ QCOMPARE( vars["i"].value(), QString( "3" ) ); // PER_ITEM
+ QCOMPARE( vars["i2"].value(), QString( "100" ) ); // PRE_COPY
+ QCOMPARE( vars["f"].value(), QString( "0" ) ); // PER_PAGE
+ QCOMPARE( vars["s"].value(), QString( "initial" ) );
+ QCOMPARE( vars["c"].value(), QString( "white" ) );
+}
diff --git a/model/unit_tests/TestVariables.h b/model/unit_tests/TestVariables.h
new file mode 100644
index 0000000..93b56b4
--- /dev/null
+++ b/model/unit_tests/TestVariables.h
@@ -0,0 +1,30 @@
+/* TestVariables.h
+ *
+ * Copyright (C) 2019 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
+
+
+class TestVariables : public QObject
+{
+ Q_OBJECT
+
+private slots:
+ void variables();
+};
diff --git a/model/unit_tests/TestXmlLabel.cpp b/model/unit_tests/TestXmlLabel.cpp
new file mode 100644
index 0000000..e70221f
--- /dev/null
+++ b/model/unit_tests/TestXmlLabel.cpp
@@ -0,0 +1,703 @@
+/* TestXmlLabel.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 "TestXmlLabel.h"
+#include "Test_Constants.h"
+
+#include "model/XmlLabelCreator.h"
+#include "model/XmlLabelParser.h"
+
+#include "barcode/Backends.h"
+#include "model/ColorNode.h"
+#include "model/FrameRect.h"
+#include "model/Markup.h"
+#include "model/Model.h"
+#include "model/PageRenderer.h"
+#include "model/Size.h"
+
+#include "model/ModelBarcodeObject.h"
+#include "model/ModelBoxObject.h"
+#include "model/ModelEllipseObject.h"
+#include "model/ModelLineObject.h"
+#include "model/ModelImageObject.h"
+#include "model/ModelTextObject.h"
+
+#include "model/Db.h"
+#include "merge/Factory.h"
+#include "merge/Merge.h"
+#include "merge/TextCsvKeys.h"
+
+#include
+
+
+QTEST_MAIN(TestXmlLabel)
+
+using namespace glabels::model;
+using namespace glabels::barcode;
+using namespace glabels::merge;
+
+
+namespace
+{
+ const double FONT_SCALE_FACTOR {0.75};
+}
+
+
+void TestXmlLabel::initTestCase()
+{
+ Settings::init();
+ Db::init();
+ Factory::init();
+ Backends::init();
+}
+
+
+void TestXmlLabel::serializeDeserialize()
+{
+ Model* model = new Model();
+
+ QList objects, outObjects;
+ QByteArray buffer, outBuffer;
+
+ //
+ // Empty object list
+ //
+ QCOMPARE( objects.count(), 0 );
+ XmlLabelCreator::serializeObjects( objects, model, buffer );
+ outObjects = XmlLabelParser::deserializeObjects( buffer, model );
+ QCOMPARE( objects.count(), outObjects.count() );
+ QCOMPARE( objects, outObjects );
+ XmlLabelCreator::serializeObjects( outObjects, model, outBuffer );
+ QCOMPARE( buffer, outBuffer );
+
+ //
+ // All objects list
+ //
+ QImage png;
+ QVERIFY( png.loadFromData( QByteArray::fromBase64( glabels::test::blue_8x8_png ), "PNG" ) );
+
+ QString svgTemplate = QDir::tempPath().append( "/TestXmlLabel_XXXXXX.svg" ); // Note: directory separators canonicalized to slash by Qt path methods
+ QTemporaryFile svgRelative( svgTemplate ); svgRelative.open(); svgRelative.write( glabels::test::cyan_8x8_svg ); svgRelative.close();
+
+ bool lock = true, noLock = false, shadow = true, noShadow = false;
+ ColorNode black( Qt::black ), white( Qt::white ), red( Qt::red ), green( Qt::green ), blue( Qt::blue );
+ QMatrix tMatrix( 1, 0, 0, 1, 50.0, 50.0 ), sMatrix( 0.5, 0, 0, 1.0, 0, 0 );
+ Style bcStyle = Backends::defaultStyle();
+
+ objects << new ModelBoxObject( 0, 1, 10, 20, lock, 2, red, green, tMatrix, shadow, 1, 2, 0.7, black );
+ objects << new ModelEllipseObject( 1, 2, 30, 40, noLock, 3, black, white, sMatrix, shadow, 2, 3, 0.8, blue );
+ objects << new ModelImageObject( 2, 3, 50, 50, lock, TextNode( false, "" ), tMatrix, noShadow, 3, 4, 0.9, white );
+ objects << new ModelImageObject( 3, 4, 60, 70, noLock, "image3.png", png, sMatrix, shadow, 6, 4, 0.9, black );
+ objects << new ModelImageObject( 4, 5, 70, 80, lock, "image4.svg", glabels::test::red_8x8_svg );
+ objects << new ModelImageObject( 5, 6, 80, 90, noLock, TextNode( true, "${key}" ), tMatrix, shadow );
+ objects << new ModelImageObject( 6, 7, 90, 100, lock, TextNode( false, "image6.jpg" ) ); // Will give warning on parse that embedded file missing
+ objects << new ModelLineObject( 7, 8, 100, 110, 4, green, sMatrix, shadow, 5, 5, 0.5, red );
+ objects << new ModelTextObject( 8, 9, 110, 120, lock, "text", "Serif", 12, QFont::Bold, true, true, red,
+ Qt::AlignHCenter, Qt::AlignBottom, QTextOption::NoWrap, 1.3, false, sMatrix, shadow, 5, 5, 0.5, red );
+ objects << new ModelBarcodeObject( 9, 10, 50, 50, noLock, bcStyle, true, true, QString("1234"), black, tMatrix );
+ objects << new ModelImageObject( 10, 11, 8, 8, lock, TextNode( false, svgRelative.fileName() ) );
+
+ QCOMPARE( objects.count(), 11 );
+
+ buffer.clear();
+ XmlLabelCreator::serializeObjects( objects, model, buffer );
+
+ QVERIFY( svgRelative.remove() ); // Delete to make sure it's not read from file on parse
+
+ QTest::ignoreMessage( QtWarningMsg, QRegularExpression( "^Embedded file \"[^\"]+image6.jpg\" missing\\. Trying actual file\\.$" ) );
+ outObjects = XmlLabelParser::deserializeObjects( buffer, model );
+ QCOMPARE( objects.count(), outObjects.count() );
+
+ QString modelDirPath = model->dir().path() + "/";
+
+ for ( int i = 0; i < objects.count(); i++ )
+ {
+ qDebug() << "object" << i;
+ QVERIFY( objects.at(i)->id() != outObjects.at(i)->id() ); // Ids are generated and unique
+ QCOMPARE( objects.at(i)->x0(), outObjects.at(i)->x0() );
+ QCOMPARE( objects.at(i)->x0().pt(), (double)i );
+ QCOMPARE( objects.at(i)->y0(), outObjects.at(i)->y0() );
+ QCOMPARE( objects.at(i)->y0().pt(), (double)(i + 1) );
+ QCOMPARE( objects.at(i)->w().pt(), outObjects.at(i)->w().pt() ); // Use `pt()` so invoke `qFuzzyCompare(double, double)` otherwise get rounding difference for Barcode
+ QCOMPARE( objects.at(i)->h().pt(), outObjects.at(i)->h().pt() ); // Fuzzy
+ QCOMPARE( objects.at(i)->lockAspectRatio(), outObjects.at(i)->lockAspectRatio() );
+ QCOMPARE( objects.at(i)->lockAspectRatio(), (bool)((i + 1) % 2) );
+ QCOMPARE( objects.at(i)->matrix(), outObjects.at(i)->matrix() );
+ QCOMPARE( objects.at(i)->shadow(), outObjects.at(i)->shadow() );
+ QCOMPARE( objects.at(i)->shadowX(), outObjects.at(i)->shadowX() );
+ QCOMPARE( objects.at(i)->shadowY(), outObjects.at(i)->shadowY() );
+ QCOMPARE( objects.at(i)->shadowOpacity(), outObjects.at(i)->shadowOpacity() );
+ QVERIFY( objects.at(i)->shadowColorNode() == outObjects.at(i)->shadowColorNode() );
+ QCOMPARE( objects.at(i)->naturalSize().w().pt(), outObjects.at(i)->naturalSize().w().pt() ); // Fuzzy
+ QCOMPARE( objects.at(i)->naturalSize().h().pt(), outObjects.at(i)->naturalSize().h().pt() ); // Fuzzy
+
+ QCOMPARE( objects.at(i)->text(), outObjects.at(i)->text() );
+ QCOMPARE( objects.at(i)->fontFamily(), outObjects.at(i)->fontFamily() );
+ QCOMPARE( objects.at(i)->fontSize(), outObjects.at(i)->fontSize() );
+ QCOMPARE( objects.at(i)->fontWeight(), outObjects.at(i)->fontWeight() );
+ QCOMPARE( objects.at(i)->fontItalicFlag(), outObjects.at(i)->fontItalicFlag() );
+ QCOMPARE( objects.at(i)->fontUnderlineFlag(), outObjects.at(i)->fontUnderlineFlag() );
+ QVERIFY( objects.at(i)->textColorNode() == outObjects.at(i)->textColorNode() );
+ QCOMPARE( objects.at(i)->textHAlign(), outObjects.at(i)->textHAlign() );
+ QCOMPARE( objects.at(i)->textVAlign(), outObjects.at(i)->textVAlign() );
+ QCOMPARE( objects.at(i)->textWrapMode(), outObjects.at(i)->textWrapMode() );
+ QCOMPARE( objects.at(i)->textLineSpacing(), outObjects.at(i)->textLineSpacing() );
+ QCOMPARE( objects.at(i)->textAutoShrink(), outObjects.at(i)->textAutoShrink() );
+
+ QCOMPARE( objects.at(i)->filenameNode().isField(), outObjects.at(i)->filenameNode().isField() );
+ if ( i == 6 /*image6.jpg*/ )
+ {
+ // Not in data so absolute path set
+ QCOMPARE( modelDirPath + objects.at(i)->filenameNode().data(), outObjects.at(i)->filenameNode().data() );
+ }
+ else
+ {
+ QCOMPARE( objects.at(i)->filenameNode().data(), outObjects.at(i)->filenameNode().data() );
+ }
+
+ if ( objects.at(i)->image() )
+ {
+ QCOMPARE( *(objects.at(i)->image()), *(outObjects.at(i)->image()) );
+ }
+ else
+ {
+ QCOMPARE( objects.at(i)->image(), outObjects.at(i)->image() );
+ }
+ QCOMPARE( objects.at(i)->svg(), outObjects.at(i)->svg() );
+
+ QCOMPARE( objects.at(i)->lineWidth(), outObjects.at(i)->lineWidth() );
+ QVERIFY( objects.at(i)->lineColorNode() == outObjects.at(i)->lineColorNode() );
+ QVERIFY( objects.at(i)->fillColorNode() == outObjects.at(i)->fillColorNode() );
+
+ QCOMPARE( objects.at(i)->bcData(), outObjects.at(i)->bcData() );
+ QCOMPARE( objects.at(i)->bcTextFlag(), outObjects.at(i)->bcTextFlag() );
+ QCOMPARE( objects.at(i)->bcChecksumFlag(), outObjects.at(i)->bcChecksumFlag() );
+ QVERIFY( objects.at(i)->bcColorNode() == outObjects.at(i)->bcColorNode() );
+ QVERIFY( !( objects.at(i)->bcStyle() != outObjects.at(i)->bcStyle() ) ); // Only != operator
+ QCOMPARE( objects.at(i)->bcFormatDigits(), outObjects.at(i)->bcFormatDigits() );
+
+ QCOMPARE( objects.at(i)->canText(), outObjects.at(i)->canText() );
+ QCOMPARE( objects.at(i)->canFill(), outObjects.at(i)->canFill() );
+ QCOMPARE( objects.at(i)->canLineColor(), outObjects.at(i)->canLineColor() );
+ QCOMPARE( objects.at(i)->canLineWidth(), outObjects.at(i)->canLineWidth() );
+ }
+
+ outBuffer.clear();
+ XmlLabelCreator::serializeObjects( outObjects, model, outBuffer );
+
+ QCOMPARE( buffer, outBuffer );
+
+ delete model->merge();
+ delete model->variables();
+ delete model;
+}
+
+
+void TestXmlLabel::writeReadFile()
+{
+ Model* model = new Model();
+
+ // Make subdir in temp dir to use as model dir
+ QTemporaryDir subDir;
+ QVERIFY( subDir.isValid() );
+
+ QString glabelsTemplate = subDir.path().append( "/TestXmlLabel_XXXXXX.glabels" ); // Note: directory separators canonicalized to slash by Qt path methods
+ QTemporaryFile glabels( glabelsTemplate );
+ glabels.open(); glabels.close();
+
+ model->setFileName( glabels.fileName() );
+
+ // Make subdir in subdir
+ QString subSubTemplate = subDir.path().append( "/TestXmlLabel_XXXXXX" );
+ QTemporaryDir subSubDir( subSubTemplate );
+ QVERIFY( subSubDir.isValid() );
+
+ QString relPath = model->dir().relativeFilePath( subSubDir.path() );
+ QVERIFY( !relPath.contains( '/' ) ); // Make sure subdir of model dir
+
+ QImage png;
+ QVERIFY( png.loadFromData( QByteArray::fromBase64( glabels::test::blue_8x8_png ), "PNG" ) );
+
+ // Make png file in temp dir (ie not in model dir)
+ QImage pngAbsoluteImage;
+ QVERIFY( pngAbsoluteImage.loadFromData( QByteArray::fromBase64( glabels::test::green_8x8_png ), "PNG" ) );
+ QTemporaryFile pngAbsolute; pngAbsolute.open(); pngAbsolute.close(); pngAbsoluteImage.save( pngAbsolute.fileName(), "PNG" );
+
+ // Make png file in model dir
+ QImage pngRelativeImage;
+ QVERIFY( pngRelativeImage.loadFromData( QByteArray::fromBase64( glabels::test::yellow_8x8_png ), "PNG" ) );
+ QString pngTemplate = model->dir().path().append( "/TestXmlLabel_XXXXXX.png" );
+ QTemporaryFile pngRelative( pngTemplate ); pngRelative.open(); pngRelative.close(); pngRelativeImage.save( pngRelative.fileName(), "PNG" );
+
+ // Make svg file in subdir of model dir
+ QString svgTemplate = subSubDir.path().append( "/TestXmlLabel_XXXXXX.svg" );
+ QTemporaryFile svgRelative( svgTemplate ); svgRelative.open(); svgRelative.write( glabels::test::cyan_8x8_svg ); svgRelative.close();
+
+ bool lock = true, noLock = false, shadow = true, noShadow = false;
+ ColorNode black( Qt::black ), white( Qt::white ), red( Qt::red ), green( Qt::green ), blue( Qt::blue );
+ QMatrix tMatrix( 1, 0, 0, 1, 50.0, 50.0 ), sMatrix( 0.5, 0, 0, 1.0, 0, 0 );
+ Style bcStyle = Backends::defaultStyle();
+
+ ///
+ /// Add objects
+ ///
+ model->addObject( new ModelBoxObject( 0, 1, 10, 20, noLock, 2, red, green, tMatrix, shadow, 1, 2, 0.7, black ) );
+ model->addObject( new ModelEllipseObject( 1, 2, 30, 40, lock, 3, black, white, sMatrix, shadow, 2, 3, 0.8, blue ) );
+ model->addObject( new ModelImageObject( 2, 3, 50, 50, noLock, TextNode( false, "" ), tMatrix, noShadow, 3, 4, 0.9, white ) );
+ model->addObject( new ModelImageObject( 3, 4, 60, 70, lock, "image3.png", png, sMatrix, shadow, 6, 4, 0.9, black ) );
+ model->addObject( new ModelImageObject( 4, 5, 70, 80, noLock, "image4.svg", glabels::test::red_8x8_svg ) );
+ model->addObject( new ModelImageObject( 5, 6, 80, 90, lock, TextNode( true, "${key}" ), tMatrix, shadow ) );
+ model->addObject( new ModelImageObject( 6, 7, 90, 100, noLock, TextNode( false, "image6.jpg" ) ) ); // Will give warning on parse that embedded file missing
+ model->addObject( new ModelTextObject( 7, 8, 110, 120, lock, "text", "Serif", 12, QFont::Bold, true, true, red,
+ Qt::AlignHCenter, Qt::AlignBottom, QTextOption::NoWrap, 1.3, false, sMatrix, shadow, 5, 5, 0.5, red ) );
+ model->addObject( new ModelLineObject( 8, 9, 100, 110, 4, green, sMatrix, shadow, 5, 5, 0.5, red ) );
+ model->addObject( new ModelBarcodeObject( 9, 10, 50, 50, lock, bcStyle, true, true, QString("1234"), black, tMatrix ) );
+ model->addObject( new ModelImageObject( 10, 11, 8, 8, noLock, TextNode( false, pngAbsolute.fileName() ) ) );
+ model->addObject( new ModelImageObject( 11, 12, 8, 8, lock, TextNode( false, pngRelative.fileName() ) ) );
+ model->addObject( new ModelImageObject( 12, 13, 8, 8, noLock, TextNode( false, svgRelative.fileName() ) ) );
+
+ QCOMPARE( model->objectList().size(), 13 );
+
+ ///
+ /// Add template
+ ///
+ Template tmplate( "Test Brand", "part", "desc", "testPaperId", 110, 410 );
+ FrameRect* frame = new FrameRect( 120, 220, 5, 0, 0, "rect1" );
+ tmplate.addFrame( frame );
+ model->setTmplate( &tmplate ); // Copies
+
+ ///
+ /// Add variables
+ ///
+ Variables vars;
+ Variable s( Variable::Type::STRING, "s", "initial", Variable::Increment::NEVER );
+ Variable c( Variable::Type::COLOR, "c", "red", Variable::Increment::PER_COPY );
+ Variable i( Variable::Type::INTEGER, "i", "123", Variable::Increment::PER_ITEM, "1" );
+ Variable f( Variable::Type::FLOATING_POINT, "f", "12.3", Variable::Increment::PER_PAGE, "0.2" );
+ model->variables()->addVariable( s );
+ model->variables()->addVariable( c );
+ model->variables()->addVariable( i );
+ model->variables()->addVariable( f );
+ QCOMPARE( model->variables()->size(), 4 );
+
+ //
+ // Add merge
+ //
+ Merge* merge = Factory::createMerge( TextCsvKeys::id() );
+ QCOMPARE( merge->id(), TextCsvKeys::id() );
+
+ model->setMerge( merge );
+ QCOMPARE( model->merge(), merge );
+
+ QString csvTemplate = subDir.path().append( "/TestXmlLabel_XXXXXX.csv" );
+ QTemporaryFile csv( csvTemplate );
+ csv.open();
+ csv.write( "id,text\n1,text1\n2,text2\n3,text3\n" );
+ csv.close();
+
+ merge->setSource( csv.fileName() );
+ QCOMPARE( merge->source(), csv.fileName() );
+
+ QCOMPARE( merge->recordList().size(), 3 );
+
+ model->setRotate( true );
+ QVERIFY( model->rotate() );
+
+ ///
+ /// Write to file and read
+ ///
+ XmlLabelCreator::writeFile( model, glabels.fileName() );
+
+ QCOMPARE( model->dir(), QFileInfo( glabels.fileName() ).dir() );
+
+ // Copy before deletion else nulled
+ QString pngAbsoluteFileName = pngAbsolute.fileName();
+ QString pngRelativeFileName = model->dir().relativeFilePath( pngRelative.fileName() );
+ QString svgRelativeFileName = model->dir().relativeFilePath( svgRelative.fileName() );
+
+ QFileInfo pngAbsoluteFileInfo( pngAbsoluteFileName );
+ QVERIFY( pngAbsoluteFileInfo.isAbsolute() );
+ QFileInfo pngRelativeFileInfo( pngRelativeFileName );
+ QVERIFY( pngRelativeFileInfo.isRelative() );
+ QFileInfo svgRelativeFileInfo( svgRelativeFileName );
+ QVERIFY( svgRelativeFileInfo.isRelative() );
+
+ // Delete to make sure they're not read from file on parse
+ QVERIFY( pngAbsolute.remove() );
+ QVERIFY( pngRelative.remove() );
+ QVERIFY( svgRelative.remove() );
+
+ QTest::ignoreMessage( QtWarningMsg, QRegularExpression( "^Embedded file \"[^\"]+image6.jpg\" missing\\. Trying actual file\\.$" ) );
+ Model* readModel = XmlLabelParser::readFile( glabels.fileName() );
+ QVERIFY( readModel );
+ QCOMPARE( readModel->dir(), model->dir() );
+ QCOMPARE( readModel->fileName(), model->fileName() );
+
+ QCOMPARE( readModel->tmplate()->brand(), model->tmplate()->brand() );
+ QCOMPARE( readModel->tmplate()->part(), model->tmplate()->part() );
+ QCOMPARE( readModel->tmplate()->description(), model->tmplate()->description() );
+ QCOMPARE( readModel->tmplate()->paperId(), model->tmplate()->paperId() );
+ QCOMPARE( readModel->tmplate()->pageWidth().pt(), model->tmplate()->pageWidth().pt() );
+ QCOMPARE( readModel->tmplate()->pageHeight().pt(), model->tmplate()->pageHeight().pt() );
+
+ QCOMPARE( readModel->frame()->id(), model->frame()->id() );
+ QCOMPARE( readModel->frame()->w().pt(), model->frame()->w().pt() );
+ QCOMPARE( readModel->frame()->h().pt(), model->frame()->h().pt() );
+
+ QCOMPARE( readModel->rotate(), model->rotate() );
+ QCOMPARE( readModel->w(), model->w() );
+ QCOMPARE( readModel->h(), model->h() );
+
+ const QList& readObjects = readModel->objectList();
+ const QList& modelObjects = model->objectList();
+ QCOMPARE( readObjects.size(), modelObjects.size() );
+
+ QString modelDirPath = model->dir().path() + "/";
+
+ for ( int i = 0; i < readObjects.count(); i++ )
+ {
+ qDebug() << "object" << i;
+ QVERIFY( readObjects.at(i)->id() != modelObjects.at(i)->id() ); // Ids are generated and unique
+ QCOMPARE( readObjects.at(i)->x0(), modelObjects.at(i)->x0() );
+ QCOMPARE( readObjects.at(i)->x0().pt(), (double)i );
+ QCOMPARE( readObjects.at(i)->y0(), modelObjects.at(i)->y0() );
+ QCOMPARE( readObjects.at(i)->y0().pt(), (double)(i + 1) );
+ QCOMPARE( readObjects.at(i)->w().pt(), modelObjects.at(i)->w().pt() ); // Use `pt()` so invoke `qFuzzyCompare(double, double)` otherwise get rounding difference for Barcode
+ QCOMPARE( readObjects.at(i)->h().pt(), modelObjects.at(i)->h().pt() ); // Fuzzy
+ QCOMPARE( readObjects.at(i)->lockAspectRatio(), modelObjects.at(i)->lockAspectRatio() );
+ QCOMPARE( readObjects.at(i)->lockAspectRatio(), (bool)(i % 2) );
+ QCOMPARE( readObjects.at(i)->matrix(), modelObjects.at(i)->matrix() );
+ QCOMPARE( readObjects.at(i)->shadow(), modelObjects.at(i)->shadow() );
+ QCOMPARE( readObjects.at(i)->shadowX(), modelObjects.at(i)->shadowX() );
+ QCOMPARE( readObjects.at(i)->shadowY(), modelObjects.at(i)->shadowY() );
+ QCOMPARE( readObjects.at(i)->shadowOpacity(), modelObjects.at(i)->shadowOpacity() );
+ QVERIFY( readObjects.at(i)->shadowColorNode() == modelObjects.at(i)->shadowColorNode() );
+ QCOMPARE( readObjects.at(i)->naturalSize().w().pt(), modelObjects.at(i)->naturalSize().w().pt() ); // Fuzzy
+ QCOMPARE( readObjects.at(i)->naturalSize().h().pt(), modelObjects.at(i)->naturalSize().h().pt() ); // Fuzzy
+
+ QCOMPARE( readObjects.at(i)->text(), modelObjects.at(i)->text() );
+ QCOMPARE( readObjects.at(i)->fontFamily(), modelObjects.at(i)->fontFamily() );
+ QCOMPARE( readObjects.at(i)->fontSize(), modelObjects.at(i)->fontSize() );
+ QCOMPARE( readObjects.at(i)->fontWeight(), modelObjects.at(i)->fontWeight() );
+ QCOMPARE( readObjects.at(i)->fontItalicFlag(), modelObjects.at(i)->fontItalicFlag() );
+ QCOMPARE( readObjects.at(i)->fontUnderlineFlag(), modelObjects.at(i)->fontUnderlineFlag() );
+ QVERIFY( readObjects.at(i)->textColorNode() == modelObjects.at(i)->textColorNode() );
+ QCOMPARE( readObjects.at(i)->textHAlign(), modelObjects.at(i)->textHAlign() );
+ QCOMPARE( readObjects.at(i)->textVAlign(), modelObjects.at(i)->textVAlign() );
+ QCOMPARE( readObjects.at(i)->textWrapMode(), modelObjects.at(i)->textWrapMode() );
+ QCOMPARE( readObjects.at(i)->textLineSpacing(), modelObjects.at(i)->textLineSpacing() );
+ QCOMPARE( readObjects.at(i)->textAutoShrink(), modelObjects.at(i)->textAutoShrink() );
+
+ QCOMPARE( readObjects.at(i)->filenameNode().isField(), modelObjects.at(i)->filenameNode().isField() );
+ if ( i == 6 /*image6.jpg*/ )
+ {
+ // Not in data so absolute path set
+ QCOMPARE( readObjects.at(i)->filenameNode().data(), modelDirPath + modelObjects.at(i)->filenameNode().data() );
+ }
+ else if ( modelObjects.at(i)->filenameNode().data().startsWith( modelDirPath ) )
+ {
+ // Made relative to model dir
+ QCOMPARE( modelDirPath + readObjects.at(i)->filenameNode().data(), modelObjects.at(i)->filenameNode().data() );
+ }
+ else
+ {
+ QCOMPARE( readObjects.at(i)->filenameNode().data(), modelObjects.at(i)->filenameNode().data() );
+ }
+
+ if ( readObjects.at(i)->image() )
+ {
+ QCOMPARE( *(readObjects.at(i)->image()), *(modelObjects.at(i)->image()) );
+ }
+ else
+ {
+ QCOMPARE( readObjects.at(i)->image(), modelObjects.at(i)->image() );
+ }
+ QCOMPARE( readObjects.at(i)->svg(), modelObjects.at(i)->svg() );
+
+ QCOMPARE( readObjects.at(i)->lineWidth(), modelObjects.at(i)->lineWidth() );
+ QVERIFY( readObjects.at(i)->lineColorNode() == modelObjects.at(i)->lineColorNode() );
+ QVERIFY( readObjects.at(i)->fillColorNode() == modelObjects.at(i)->fillColorNode() );
+
+ QCOMPARE( readObjects.at(i)->bcData(), modelObjects.at(i)->bcData() );
+ QCOMPARE( readObjects.at(i)->bcTextFlag(), modelObjects.at(i)->bcTextFlag() );
+ QCOMPARE( readObjects.at(i)->bcChecksumFlag(), modelObjects.at(i)->bcChecksumFlag() );
+ QVERIFY( readObjects.at(i)->bcColorNode() == modelObjects.at(i)->bcColorNode() );
+ QVERIFY( !( readObjects.at(i)->bcStyle() != modelObjects.at(i)->bcStyle() ) ); // Only != operator
+ QCOMPARE( readObjects.at(i)->bcFormatDigits(), modelObjects.at(i)->bcFormatDigits() );
+
+ QCOMPARE( readObjects.at(i)->canText(), modelObjects.at(i)->canText() );
+ QCOMPARE( readObjects.at(i)->canFill(), modelObjects.at(i)->canFill() );
+ QCOMPARE( readObjects.at(i)->canLineColor(), modelObjects.at(i)->canLineColor() );
+ QCOMPARE( readObjects.at(i)->canLineWidth(), modelObjects.at(i)->canLineWidth() );
+ }
+
+ QCOMPARE( readObjects[10]->filenameNode().data(), pngAbsoluteFileName );
+ QCOMPARE( readObjects[11]->filenameNode().data(), pngRelativeFileName );
+ QCOMPARE( readObjects[12]->filenameNode().data(), svgRelativeFileName );
+
+ QCOMPARE( readModel->variables()->size(), model->variables()->size() );
+ for ( const auto& modelV : *model->variables() )
+ {
+ QVERIFY( readModel->variables()->hasVariable( modelV.name() ) );
+ const auto& readV = readModel->variables()->value( modelV.name() );
+ QCOMPARE( readV.type(), modelV.type() );
+ QCOMPARE( readV.initialValue(), modelV.initialValue() );
+ if ( readV.type() == Variable::Type::INTEGER || readV.type() == Variable::Type::FLOATING_POINT )
+ {
+ QCOMPARE( readV.stepSize(), modelV.stepSize() );
+ QCOMPARE( readV.increment(), modelV.increment() );
+ }
+ QCOMPARE( readV.value(), modelV.value() );
+ }
+
+ QCOMPARE( readModel->merge()->id(), model->merge()->id() );
+ QCOMPARE( readModel->merge()->source(), model->merge()->source() );
+ QCOMPARE( readModel->merge()->recordList().size(), model->merge()->recordList().size() );
+ for ( int i = 0; i < readModel->merge()->recordList().size(); i++ )
+ {
+ QCOMPARE( readModel->merge()->recordList().at(i)->keys(), model->merge()->recordList().at(i)->keys() );
+ QCOMPARE( readModel->merge()->recordList().at(i)->values(), model->merge()->recordList().at(i)->values() );
+ }
+
+ delete readModel->merge();
+ delete readModel->variables();
+ delete readModel;
+
+ delete model->merge();
+ delete model->variables();
+ delete model;
+}
+
+
+void TestXmlLabel::parser_3ReadFile()
+{
+ // Current path is "build/model/unit_tests" so go up 3 levels
+ QFileInfo glabelsFileInfo( "../../../model/unit_tests/data/glabels-3/crew-orientation-name-tags-7.glabels" );
+ QVERIFY( glabelsFileInfo.isReadable() );
+
+ Model* model = XmlLabelParser::readFile( glabelsFileInfo.filePath() );
+ QVERIFY( model );
+
+ QCOMPARE( model->fileName(), glabelsFileInfo.filePath() );
+
+ QCOMPARE( model->tmplate()->brand(), QString( "Avery" ) );
+ QCOMPARE( model->tmplate()->part(), QString( "5395" ) );
+ QCOMPARE( model->tmplate()->description(), QString( "Name Badge Labels" ) );
+ QCOMPARE( model->tmplate()->paperId(), QString( "US-Letter" ) );
+ QCOMPARE( model->tmplate()->pageWidth().in(), 8.5 );
+ QCOMPARE( model->tmplate()->pageHeight().in(), 11.0 );
+
+ QCOMPARE( model->frame()->id(), QString( "0" ) );
+ const FrameRect* frameRect = dynamic_cast( model->frame() );
+ QVERIFY( frameRect );
+ QCOMPARE( frameRect->w().in(), 3.375 );
+ QCOMPARE( frameRect->h().in(), 2.33333 );
+ QCOMPARE( frameRect->r().in(), 0.1875 );
+ QCOMPARE( frameRect->xWaste().in(), 0.0625 );
+ QCOMPARE( frameRect->yWaste().in(), 0.0625 );
+
+ QCOMPARE( model->frame()->markups().size(), 1 );
+ MarkupMargin* markupMargin = dynamic_cast( model->frame()->markups()[0] );
+ QVERIFY( markupMargin );
+ QCOMPARE( markupMargin->xSize().in(), 0.0625 );
+ QCOMPARE( markupMargin->ySize().in(), 0.0625 );
+
+ QCOMPARE( model->frame()->layouts().size(), 1 );
+ QCOMPARE( model->frame()->layouts()[0].nx(), 2 );
+ QCOMPARE( model->frame()->layouts()[0].ny(), 4 );
+ QCOMPARE( model->frame()->layouts()[0].x0().in(), 0.6875 );
+ QCOMPARE( model->frame()->layouts()[0].y0().in(), 0.583333 );
+ QCOMPARE( model->frame()->layouts()[0].dx().in(), 3.75 );
+ QCOMPARE( model->frame()->layouts()[0].dy().in(), 2.5 );
+
+ QCOMPARE( model->rotate(), false );
+
+ QCOMPARE( model->objectList().size(), 4 );
+
+ ModelTextObject* modelTextObject0 = dynamic_cast( model->objectList()[0] );
+ QVERIFY( modelTextObject0 );
+ QCOMPARE( modelTextObject0->x0().in(), 0.150603 );
+ QCOMPARE( modelTextObject0->y0().in(), 0.2625 );
+ // Width and height set to naturalSize()
+ QCOMPARE( modelTextObject0->lockAspectRatio(), false );
+ QCOMPARE( modelTextObject0->matrix(), QMatrix( 1, 0, 0, 1, 0, 0 ) );
+ QCOMPARE( modelTextObject0->shadow(), false );
+ QCOMPARE( modelTextObject0->text(), QString( "Hello, my name is" ) );
+ QCOMPARE( modelTextObject0->fontFamily(), QString( "Sans" ) );
+ QCOMPARE( modelTextObject0->fontSize(), 16 * FONT_SCALE_FACTOR );
+ QCOMPARE( modelTextObject0->fontWeight(), QFont::Bold );
+ QCOMPARE( modelTextObject0->fontItalicFlag(), false );
+ QCOMPARE( modelTextObject0->textLineSpacing(), 1.0 );
+ QCOMPARE( modelTextObject0->textAutoShrink(), false );
+ QCOMPARE( modelTextObject0->textColorNode().color(), QColor::fromRgba( 0xff3366ff ) ); // QColor uses ARGB
+ QCOMPARE( modelTextObject0->textHAlign(), Qt::AlignLeft );
+
+ ModelTextObject* modelTextObject1 = dynamic_cast( model->objectList()[1] );
+ QVERIFY( modelTextObject1 );
+ QCOMPARE( modelTextObject1->x0().in(), 0.150603 );
+ QCOMPARE( modelTextObject1->y0().in(), 0.645 );
+ // Width and height set to naturalSize()
+ QCOMPARE( modelTextObject1->lockAspectRatio(), false );
+ QCOMPARE( modelTextObject1->matrix(), QMatrix( 1, 0, 0, 1, 0, 0 ) );
+ QCOMPARE( modelTextObject1->shadow(), false );
+ QCOMPARE( modelTextObject1->text(), QString( "${Name}" ) );
+ QCOMPARE( modelTextObject1->fontFamily(), QString( "Sans" ) );
+ QCOMPARE( modelTextObject1->fontSize(), 20 * FONT_SCALE_FACTOR );
+ QCOMPARE( modelTextObject1->fontWeight(), QFont::Normal );
+ QCOMPARE( modelTextObject1->fontItalicFlag(), false );
+ QCOMPARE( modelTextObject1->textLineSpacing(), 1.0 );
+ QCOMPARE( modelTextObject1->textAutoShrink(), false );
+ QCOMPARE( modelTextObject1->textColorNode().color(), QColor::fromRgba( 0xff000000 ) );
+ QCOMPARE( modelTextObject1->textHAlign(), Qt::AlignLeft );
+
+ ModelTextObject* modelTextObject2 = dynamic_cast( model->objectList()[2] );
+ QVERIFY( modelTextObject2 );
+ QCOMPARE( modelTextObject2->x0().in(), 0.150603 );
+ QCOMPARE( modelTextObject2->y0().in(), 1.14 );
+ // Width and height set to naturalSize()
+ QCOMPARE( modelTextObject2->lockAspectRatio(), false );
+ QCOMPARE( modelTextObject2->matrix(), QMatrix( 1, 0, 0, 1, 0, 0 ) );
+ QCOMPARE( modelTextObject2->shadow(), false );
+ QCOMPARE( modelTextObject2->text(), QString( "Department: ${Department}" ) );
+ QCOMPARE( modelTextObject2->fontFamily(), QString( "Sans" ) );
+ QCOMPARE( modelTextObject2->fontSize(), 11 * FONT_SCALE_FACTOR );
+ QCOMPARE( modelTextObject2->fontWeight(), QFont::Normal );
+ QCOMPARE( modelTextObject2->fontItalicFlag(), false );
+ QCOMPARE( modelTextObject2->textLineSpacing(), 1.0 );
+ QCOMPARE( modelTextObject2->textAutoShrink(), false );
+ QCOMPARE( modelTextObject2->textColorNode().color(), QColor::fromRgba( 0xff000000 ) );
+ QCOMPARE( modelTextObject2->textHAlign(), Qt::AlignLeft );
+
+ ModelBarcodeObject* modelBarcodeObject3 = dynamic_cast( model->objectList()[3] );
+ QVERIFY( modelBarcodeObject3 );
+ QCOMPARE( modelBarcodeObject3->x0().in(), 0.150603 );
+ QCOMPARE( modelBarcodeObject3->y0().in(), 1.395 );
+ QCOMPARE( modelBarcodeObject3->w().in(), 3.06944 );
+ QCOMPARE( modelBarcodeObject3->h().in(), 0.847222 );
+ QCOMPARE( modelBarcodeObject3->lockAspectRatio(), false );
+ QCOMPARE( modelBarcodeObject3->matrix(), QMatrix( 1, 0, 0, 1, 0, 0 ) );
+ QCOMPARE( modelBarcodeObject3->shadow(), false );
+
+ QCOMPARE( modelBarcodeObject3->bcData(), QString( "${SN}" ) );
+ QVERIFY( modelBarcodeObject3->bcTextFlag() );
+ QVERIFY( modelBarcodeObject3->bcChecksumFlag() );
+ QCOMPARE( modelBarcodeObject3->bcColorNode().color(), QColor::fromRgba( 0xff000000 ) );
+ QCOMPARE( modelBarcodeObject3->bcStyle().fullId(), QString( "code39" ) );
+ QCOMPARE( modelBarcodeObject3->bcFormatDigits(), 10 );
+
+ QVERIFY( model->merge() );
+ QVERIFY( !model->merge()->source().isEmpty() ); // Merge source hacked to work relatively so not realistic
+ QCOMPARE( model->merge()->recordList().size(), 4 );
+
+ QCOMPARE( model->merge()->recordList()[0]->keys().size(), 3 );
+ QList keys, values0, values1, values2, values3;
+ keys << "Department" << "Name" << "SN";
+ values0 << "Management" << "Jim Kirk" << "SC937-0176 CEC";
+ values1 << "Sciences" << "Mr. Spock" << "S179-276SP";
+ values2 << "Medicine" << "Leonard McCoy" << "unknown";
+ values3 << "Engineering" << "Montgomery Scott" << "SE-197-54T";
+
+ QCOMPARE( model->merge()->recordList()[0]->keys(), keys );
+ QCOMPARE( model->merge()->recordList()[0]->values(), values0 );
+ QCOMPARE( model->merge()->recordList()[1]->keys(), keys );
+ QCOMPARE( model->merge()->recordList()[1]->values(), values1 );
+ QCOMPARE( model->merge()->recordList()[2]->keys(), keys );
+ QCOMPARE( model->merge()->recordList()[2]->values(), values2 );
+ QCOMPARE( model->merge()->recordList()[3]->keys(), keys );
+ QCOMPARE( model->merge()->recordList()[3]->values(), values3 );
+
+ delete model->merge();
+ delete model->variables();
+ delete model;
+}
+
+
+void TestXmlLabel::parser_3Barcode()
+{
+ QTemporaryFile glabels( "TestXmlLabel_XXXXXX.glabels" );
+ glabels.open();
+ glabels.write( "" );
+ glabels.write( "" );
+ glabels.write( "" );
+ glabels.write( "" );
+ glabels.write( "" );
+ glabels.write( "" );
+ glabels.write( "" );
+ glabels.write( "" );
+ glabels.write( "" );
+ glabels.write( "" );
+ glabels.close();
+
+ Model* model = XmlLabelParser::readFile( glabels.fileName() );
+ QVERIFY( model );
+
+ QCOMPARE( model->objectList().size(), 5 );
+
+ ModelBarcodeObject* modelBarcodeObject;
+
+ modelBarcodeObject = dynamic_cast( model->objectList()[0] );
+ QVERIFY( modelBarcodeObject );
+ QCOMPARE( modelBarcodeObject->bcStyle().fullId(), QString( "code39ext" ) );
+
+ modelBarcodeObject = dynamic_cast( model->objectList()[1] );
+ QVERIFY( modelBarcodeObject );
+ QCOMPARE( modelBarcodeObject->bcStyle().fullId(), QString( "datamatrix" ) );
+
+ modelBarcodeObject = dynamic_cast( model->objectList()[2] );
+ QVERIFY( modelBarcodeObject );
+ if ( Backends::style( "qrencode", "qrcode" ) != Backends::defaultStyle() )
+ {
+ QCOMPARE( modelBarcodeObject->bcStyle().fullId(), QString( "qrencode::qrcode" ) );
+ }
+ else if ( Backends::style( "zint", "qr" ) != Backends::defaultStyle() )
+ {
+ QCOMPARE( modelBarcodeObject->bcStyle().fullId(), QString( "zint::qr" ) );
+ }
+ else
+ {
+ QCOMPARE( modelBarcodeObject->bcStyle().fullId(), QString( "code39" ) );
+ }
+
+ modelBarcodeObject = dynamic_cast( model->objectList()[3] );
+ QVERIFY( modelBarcodeObject );
+ if ( Backends::style( "gnu-barcode", "upc-a+2" ) != Backends::defaultStyle() )
+ {
+ QCOMPARE( modelBarcodeObject->bcStyle().fullId(), QString( "gnu-barcode::upc-a+2" ) );
+ }
+ else
+ {
+ QCOMPARE( modelBarcodeObject->bcStyle().fullId(), QString( "code39" ) );
+ }
+
+ modelBarcodeObject = dynamic_cast( model->objectList()[4] );
+ QVERIFY( modelBarcodeObject );
+ if ( Backends::style( "zint", "gs1-128" ) != Backends::defaultStyle() )
+ {
+ QCOMPARE( modelBarcodeObject->bcStyle().fullId(), QString( "zint::gs1-128" ) );
+ }
+ else
+ {
+ QCOMPARE( modelBarcodeObject->bcStyle().fullId(), QString( "code39" ) );
+ }
+
+ delete model->merge();
+ delete model->variables();
+ delete model;
+}
diff --git a/model/unit_tests/TestXmlLabel.h b/model/unit_tests/TestXmlLabel.h
new file mode 100644
index 0000000..57464ed
--- /dev/null
+++ b/model/unit_tests/TestXmlLabel.h
@@ -0,0 +1,36 @@
+/* TestXmlLabel.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 .
+ */
+
+#include
+
+
+class TestXmlLabel : public QObject
+{
+ Q_OBJECT
+
+private slots:
+ void initTestCase();
+ void serializeDeserialize();
+ void writeReadFile();
+ void parser_3ReadFile();
+ void parser_3Barcode();
+};
+
+
diff --git a/model/unit_tests/Test_Constants.h b/model/unit_tests/Test_Constants.h
new file mode 100644
index 0000000..f57b640
--- /dev/null
+++ b/model/unit_tests/Test_Constants.h
@@ -0,0 +1,41 @@
+/* Test_Constants.h
+ *
+ * Copyright (C) 2019 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 test_Constants_h
+#define test_Constants_h
+
+
+namespace glabels
+{
+ namespace test
+ {
+
+ const char* blue_8x8_png = "iVBORw0KGgoAAAANSUhEUgAAAAgAAAAICAYAAADED76LAAABhGlDQ1BJQ0MgcHJvZmlsZQAAKJF9kT1Iw1AUhU9TpVIqDhYRcchQnSyIijhqFYpQIdQKrTqYvPQPmjQkKS6OgmvBwZ/FqoOLs64OroIg+APi4uqk6CIl3pcUWsR44fE+zrvn8N59gNCoMM3qGgc03TbTyYSYza2KoVeEEMYAAhBkZhlzkpSCb33dUx/VXZxn+ff9Wb1q3mJAQCSeZYZpE28QT2/aBud94igrySrxOfGYSRckfuS64vEb56LLAs+Mmpn0PHGUWCx2sNLBrGRqxFPEMVXTKV/Ieqxy3uKsVWqsdU/+wkheX1nmOq1hJLGIJUgQoaCGMiqwEaddJ8VCms4TPv4h1y+RSyFXGYwcC6hCg+z6wf/g92ytwuSElxRJAN0vjvMxAoR2gWbdcb6PHad5AgSfgSu97a82gJlP0uttLXYE9G0DF9dtTdkDLneAwSdDNmVXCtISCgXg/Yy+KQf03wLhNW9urXOcPgAZmlXqBjg4BEaLlL3u8+6ezrn929Oa3w/Q2XJm1/XlIwAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAAuIwAALiMBeKU/dgAAAAd0SU1FB+MHChYzAoNXJCYAAAAWSURBVBjTY2Rg+P+fAQ9gYiAAhocCABBdAg7zMxsKAAAAAElFTkSuQmCC";
+ const char* green_8x8_png = "iVBORw0KGgoAAAANSUhEUgAAAAgAAAAICAYAAADED76LAAABhGlDQ1BJQ0MgcHJvZmlsZQAAKJF9kTtIw1AUhv+mikUqDlYQcchQnSz4Qhy1CkWoEGqFVh1MbvqCJg1Jiouj4Fpw8LFYdXBx1tXBVRAEHyAurk6KLlLiuUmhRYwXDvfjv/f/OfdcQKiXmWZ1jAGabpupRFzMZFfFrleE0E81jpDMLGNOkpLwXV/3CPD9Lsaz/O/9uXrUnMWAgEg8ywzTJt4gnt60Dc77xBFWlFXic+JRkxokfuS64vEb54LLAs+MmOnUPHGEWCy0sdLGrGhqxFPEUVXTKV/IeKxy3uKslaus2Sd/YTinryxznWoICSxiCRJEKKiihDJsxGjXSbGQovO4j3/Q9UvkUshVAiPHAirQILt+8D/4PVsrPznhJYXjQOeL43wMA127QKPmON/HjtM4AYLPwJXe8lfqwMwn6bWWFj0CereBi+uWpuwBlzvAwJMhm7IrBamEfB54P6NvygJ9t0D3mje35jlOH4A0zSp5AxwcAiMFyl73eXeofW7/3mnO7wdSvnKatbS90wAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAAOxAAADsQBlSsOGwAAAAd0SU1FB+MIFQovFXnldrAAAAAWSURBVBjTY2T4z/CfAQ9gYiAAhocCABFcAg5KXrI7AAAAAElFTkSuQmCC";
+ const char* yellow_8x8_png = "iVBORw0KGgoAAAANSUhEUgAAAAgAAAAICAYAAADED76LAAABhGlDQ1BJQ0MgcHJvZmlsZQAAKJF9kT1Iw0AcxV9TpUUqIhYs4pChOlkQFXHUKhShQqgVWnUwufQLmjQkLS6OgmvBwY/FqoOLs64OroIg+AHi4uqk6CIl/i8ptIjx4Lgf7+497t4BQqPMNKtrHND0qplKxMVMdlUMvCKIQfjRj4jMLGNOkpLwHF/38PH1LsazvM/9OXrVnMUAn0g8ywyzSrxBPL1ZNTjvE4dZUVaJz4nHTLog8SPXFZffOBccFnhm2Eyn5onDxGKhg5UOZkVTI54ijqqaTvlCxmWV8xZnrVxjrXvyF4Zy+soy12kOI4FFLEGCCAU1lFBGFTFadVIspGg/7uEfcvwSuRRylcDIsYAKNMiOH/wPfndr5Scn3KRQHOh+se2PESCwCzTrtv19bNvNE8D/DFzpbX+lAcx8kl5va9EjoG8buLhua8oecLkDRJ4M2ZQdyU9TyOeB9zP6piwwcAv0rLm9tfZx+gCkqavkDXBwCIwWKHvd493Bzt7+PdPq7wcjL3KHuPu4MgAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAAOxAAADsQBlSsOGwAAAAd0SU1FB+MIFwMyBT7m+cwAAAAWSURBVBjTY/z/n+E/Ax7AxEAADA8FABdkAw08uCaCAAAAAElFTkSuQmCC";
+ const char* red_8x8_svg = "";
+ const char* cyan_8x8_svg = "";
+ const char* magenta_8x8_svg = "";
+
+ }
+}
+
+
+#endif // test_Constants_h
diff --git a/model/unit_tests/data/glabels-3/crew-orientation-list.csv b/model/unit_tests/data/glabels-3/crew-orientation-list.csv
new file mode 100644
index 0000000..1af4b38
--- /dev/null
+++ b/model/unit_tests/data/glabels-3/crew-orientation-list.csv
@@ -0,0 +1,5 @@
+Name,Department,SN
+"Jim Kirk",Management,"SC937-0176 CEC"
+"Mr. Spock",Sciences,S179-276SP
+"Leonard McCoy",Medicine,unknown
+"Montgomery Scott",Engineering,SE-197-54T
diff --git a/model/unit_tests/data/glabels-3/crew-orientation-name-tags-7.glabels b/model/unit_tests/data/glabels-3/crew-orientation-name-tags-7.glabels
new file mode 100644
index 0000000..29546fa
--- /dev/null
+++ b/model/unit_tests/data/glabels-3/crew-orientation-name-tags-7.glabels
@@ -0,0 +1,25 @@
+
+
+
+
+
+
+
+
+
+
+ Hello, my name is
+
+
+
+
+
+
+
+ Department:
+
+
+
+
+
+
diff --git a/templates/glabels-4.0.dtd b/templates/glabels-4.0.dtd
index 5834460..5a584b2 100644
--- a/templates/glabels-4.0.dtd
+++ b/templates/glabels-4.0.dtd
@@ -87,6 +87,10 @@
iec16022)"
-->
+
+
+
+
@@ -139,7 +143,7 @@
-
+
+
+
+
+
+
+
+
+
diff --git a/templates/herma-iso-templates.xml b/templates/herma-iso-templates.xml
index ad88d03..002abdf 100644
--- a/templates/herma-iso-templates.xml
+++ b/templates/herma-iso-templates.xml
@@ -223,6 +223,18 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/templates/online-templates.xml b/templates/online-templates.xml
index 0b296ac..ca81061 100644
--- a/templates/online-templates.xml
+++ b/templates/online-templates.xml
@@ -332,6 +332,16 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/translations/glabels_C.ts b/translations/glabels_C.ts
index 4c4c4b6..324c779 100644
--- a/translations/glabels_C.ts
+++ b/translations/glabels_C.ts
@@ -178,6 +178,37 @@
+
+ EditVariableDialog
+
+ Dialog
+
+
+
+ Name:
+
+
+
+ Step size:
+
+
+
+ Increment
+
+
+
+ Variable
+
+
+
+ Type:
+
+
+
+ Value:
+
+
+
Factory
@@ -251,18 +282,10 @@
MergeView
-
- Form
-
-
Source
-
- Location
-
-
Format:
@@ -283,11 +306,15 @@
Unselect all
+
+ Browse...
+
+
ObjectEditor
- Form
+ Object properties
@@ -314,6 +341,14 @@
Word
+
+ Anywhere
+
+
+
+ None
+
+
Allow printing to shrink text to fit object
@@ -375,23 +410,7 @@
- None
-
-
-
- Anywhere
-
-
-
- Select File...
-
-
-
- or
-
-
-
- Select Merge Field...
+ Browse...
@@ -470,10 +489,6 @@
Opacity:
-
- Object properties
-
-
PreferencesDialog
@@ -516,22 +531,6 @@
PrintView
-
- Form
-
-
-
- Page
-
-
-
- of
-
-
-
- nn
-
-
Copies
@@ -568,13 +567,21 @@
Print
+
+ Page
+
+
+
+ of
+
+
+
+ nn
+
+
PropertiesView
-
- Form
-
-
Product
@@ -615,6 +622,14 @@
Change product
+
+ Adjustable Parameters
+
+
+
+ Label length:
+
+
Orientation
@@ -635,14 +650,6 @@
Similar Products
-
- Adjustable Parameters
-
-
-
- Label length:
-
-
ReportBugDialog
@@ -724,10 +731,6 @@
StartupView
-
- Form
-
-
Welcome to gLabels. Let's get started:
@@ -751,10 +754,6 @@
TemplateDesignerApplyPage
-
- Form
-
-
You have completed the gLabels Product Template Designer. If you wish to accept and save your product template, click "Save."
@@ -767,7 +766,11 @@
TemplateDesignerCdPage
- Form
+ 6. Margin:
+
+
+
+ 1. Outer radius:
@@ -779,28 +782,16 @@
- 1. Outer radius:
+ 3. Clipping width:
5. Waste:
-
- 3. Clipping width:
-
-
-
- 6. Margin:
-
-
TemplateDesignerContinuousPage
-
- Form
-
-
<html><head/><body><p>Click "Cancel" to quit, or click "Back" to begin with a different product.</p></body></html>
@@ -808,14 +799,6 @@
TemplateDesignerEllipsePage
-
- Form
-
-
-
- 3. Waste:
-
-
2. Height:
@@ -824,6 +807,10 @@
1. Width:
+
+ 3. Waste:
+
+
4. Margin:
@@ -831,10 +818,6 @@
TemplateDesignerIntroPage
-
- Form
-
-
<html><head/><body><p>This dialog will help you create a custom product template. Let's get started:</p></body></html>
@@ -858,10 +841,6 @@
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.
@@ -890,40 +869,32 @@
TemplateDesignerNamePage
- Form
+ (e.g. "Mailing Labels," "Business Cards," ...)
Brand:
-
- (e.g. Avery, Acme, ...)
-
-
Part #:
-
- (e.g. 8163A)
-
-
Description:
- (e.g. "Mailing Labels," "Business Cards," ...)
+ (e.g. 8163A)
+
+
+
+ (e.g. Avery, Acme, ...)
TemplateDesignerOneLayoutPage
-
- Form
-
-
Number across (nx):
@@ -956,15 +927,7 @@
TemplateDesignerPageSizePage
- Form
-
-
-
- Page size:
-
-
-
- Width:
+ Roll width:
@@ -972,16 +935,16 @@
- Roll width:
+ Width:
+
+
+
+ Page size:
TemplateDesignerPathPage
-
- Form
-
-
<html><head/><body><p>Click "Cancel" to quit, or click "Back" to begin with a different product.</p></body></html>
@@ -990,15 +953,7 @@
TemplateDesignerRectPage
- Form
-
-
-
- 1. Width:
-
-
-
- 2. Height:
+ 4. Horizontal waste:
@@ -1006,13 +961,17 @@
- 4. Horizontal waste:
+ 1. Width:
5. Vertical waste:
+
+ 2. Height:
+
+
6. Margin (X):
@@ -1029,11 +988,7 @@
TemplateDesignerRoundPage
- Form
-
-
-
- 2. Waste:
+ 3. Margin
@@ -1041,16 +996,12 @@
- 3. Margin
+ 2. Waste:
TemplateDesignerShapePage
-
- Form
-
-
Rectangular or square (can have rounded corners)
@@ -1070,10 +1021,6 @@
TemplateDesignerTwoLayoutPage
-
- Form
-
-
Distance from left edge (x0):
@@ -1126,6 +1073,68 @@
+
+ Variable
+
+ String
+
+
+
+ Integer
+
+
+
+ Floating Point
+
+
+
+ Never
+
+
+
+ Per item
+
+
+
+ Per copy
+
+
+
+ Per page
+
+
+
+ Color
+
+
+
+
+ VariablesView
+
+ <html><head/><body><p>Add variable</p></body></html>
+
+
+
+ Add
+
+
+
+ <html><head/><body><p>Edit selected variable</p></body></html>
+
+
+
+ Edit
+
+
+
+ <html><head/><body><p>Delete selected variable</p></body></html>
+
+
+
+ Delete
+
+
+
glabels::AboutDialog
@@ -1145,14 +1154,25 @@
+
+ glabels::ColorHistory
+
+ color %1
+
+
+
glabels::ColorPaletteDialog
- Custom color...
+ Standard Colors
- Merge key...
+ Recent Colors
+
+
+
+ Custom color...
@@ -1160,7 +1180,30 @@
- Custom color #%1
+ Custom Color %1
+ %1 = color specification in hex. String must not contain a colon (:).
+
+
+
+ Use substitution field
+
+
+
+
+ glabels::EditVariableDialog
+
+ Default
+
+
+
+
+ glabels::FieldButton
+
+ Merge fields
+
+
+
+ Variables
@@ -1209,6 +1252,10 @@
Delete
+
+ Resize
+
+
glabels::MainWindow
@@ -1216,6 +1263,10 @@
Welcome
+
+ Edit
+
+
Properties
@@ -1225,11 +1276,11 @@
- Print
+ Variables
- Edit
+ Print
@@ -1288,6 +1339,14 @@
Select project Merge mode
+
+ &Variables
+
+
+
+ Select project Variables mode
+
+
&Print
@@ -1740,6 +1799,14 @@
Quick Access Toolbar
+
+ Undo %1
+
+
+
+ Redo %1
+
+
glabels::MergeView
@@ -1770,14 +1837,6 @@
Default
-
- Insert Field
-
-
-
- Key
-
-
Original size
@@ -1898,10 +1957,6 @@
Set image
-
- Move
-
-
Size
@@ -1914,6 +1969,26 @@
Shadow
+
+ Position
+
+
+
+ Barcode
+
+
+
+ Reset
+
+
+
+ Insert substitution field
+
+
+
+ Use substitution field
+
+
glabels::PrintView
@@ -1982,11 +2057,11 @@
- Copy
+ Roll
- Roll
+ Copy
@@ -2164,6 +2239,41 @@
+
+ glabels::VariablesView
+
+ Variables
+
+
+
+ Name
+
+
+
+ Type
+
+
+
+ Increment
+
+
+
+ Step Size
+
+
+
+ Add Variable
+
+
+
+ Edit Variable
+
+
+
+ Value
+
+
+
glabels::barcode::Backends
@@ -2302,6 +2412,10 @@
IEC18004 (QRCode)
+
+ Australia Post Standard
+
+
Australia Post Reply Paid
@@ -2354,10 +2468,6 @@
Code 49
-
- Australia Post Standard
-
-
Code 128 (Mode C suppression)
@@ -2545,6 +2655,13 @@
+
+ glabels::model::ModelImageObject
+
+ No image
+
+
+
glabels::model::ModelTextObject
diff --git a/translations/templates_C.ts b/translations/templates_C.ts
index 5670957..1ace3df 100644
--- a/translations/templates_C.ts
+++ b/translations/templates_C.ts
@@ -427,5 +427,9 @@
Postage stamp labels
+
+ CD/DVD spine labels
+
+
diff --git a/user-docs/_build/man/glabels-batch-qt.1 b/user-docs/_build/man/glabels-batch-qt.1
index 069178f..ce4b77f 100644
--- a/user-docs/_build/man/glabels-batch-qt.1
+++ b/user-docs/_build/man/glabels-batch-qt.1
@@ -1,6 +1,6 @@
.\" Man page generated from reStructuredText.
.
-.TH "GLABELS-BATCH-QT" "1" "Apr 29, 2019" "" "gLabels"
+.TH "GLABELS-BATCH-QT" "1" "May 05, 2019" "" "gLabels"
.SH NAME
glabels-batch-qt \- batch creation of labels and business cards
.
@@ -110,7 +110,7 @@ Directory for manually created product templates.
.UNINDENT
.SH BUGS
.sp
-Bugs and featue requests can be reported via the gLabels issue tracking system at GitHub (<\fI\%https://github.com/jimevins/glabels\-qt/issues\fP>). You will need a GitHub account to submit new issues or to comment on existing issues.
+Bugs and feature requests can be reported via the gLabels issue tracking system at GitHub (<\fI\%https://github.com/jimevins/glabels\-qt/issues\fP>). You will need a GitHub account to submit new issues or to comment on existing issues.
.SH SEE ALSO
.sp
\fBglabels\-qt(1)\fP
diff --git a/user-docs/_build/man/glabels-qt.1 b/user-docs/_build/man/glabels-qt.1
index d90c351..f68653b 100644
--- a/user-docs/_build/man/glabels-qt.1
+++ b/user-docs/_build/man/glabels-qt.1
@@ -1,6 +1,6 @@
.\" Man page generated from reStructuredText.
.
-.TH "GLABELS-QT" "1" "Apr 29, 2019" "" "gLabels"
+.TH "GLABELS-QT" "1" "May 05, 2019" "" "gLabels"
.SH NAME
glabels-qt \- create labels and business cards
.
@@ -69,7 +69,7 @@ Directory for manually created product templates.
.UNINDENT
.SH BUGS
.sp
-Bugs and featue requests can be reported via the gLabels issue tracking system at GitHub (<\fI\%https://github.com/jimevins/glabels\-qt/issues\fP>). You will need a GitHub account to submit new issues or to comment on existing issues.
+Bugs and feature requests can be reported via the gLabels issue tracking system at GitHub (<\fI\%https://github.com/jimevins/glabels\-qt/issues\fP>). You will need a GitHub account to submit new issues or to comment on existing issues.
.SH SEE ALSO
.sp
\fBglabels\-batch\-qt(1)\fP