Restructuring directory layout. Move towards "Modern CMake" usage.

This commit is contained in:
Jim Evins
2017-11-23 22:15:24 -05:00
parent 8bec3594ec
commit b8ee5e1f73
198 changed files with 4509 additions and 5324 deletions
+106
View File
@@ -0,0 +1,106 @@
project (Model LANGUAGES CXX)
#=======================================
# Sources
#=======================================
# Auto-generated files
configure_file (Version.h.in ${CMAKE_CURRENT_BINARY_DIR}/Version.h @ONLY)
configure_file (Config.h.in ${CMAKE_CURRENT_BINARY_DIR}/Config.h @ONLY)
set (Model_sources
Category.cpp
ColorNode.cpp
DataCache.cpp
Db.cpp
Distance.cpp
FileUtil.cpp
Frame.cpp
FrameCd.cpp
FrameEllipse.cpp
FrameRect.cpp
FrameRound.cpp
Handles.cpp
Layout.cpp
Markup.cpp
Model.cpp
ModelObject.cpp
ModelBarcodeObject.cpp
ModelBoxObject.cpp
ModelEllipseObject.cpp
ModelImageObject.cpp
ModelLineObject.cpp
ModelShapeObject.cpp
ModelTextObject.cpp
Outline.cpp
PageRenderer.cpp
Paper.cpp
Point.cpp
RawText.cpp
Region.cpp
Settings.cpp
Size.cpp
StrUtil.cpp
SubstitutionField.cpp
Template.cpp
TextNode.cpp
Units.cpp
Vendor.cpp
XmlCategoryParser.cpp
XmlLabelCreator.cpp
XmlLabelParser.cpp
XmlPaperParser.cpp
XmlTemplateCreator.cpp
XmlTemplateParser.cpp
XmlUtil.cpp
XmlVendorParser.cpp
)
set (Model_qobject_headers
Model.h
ModelObject.h
ModelBarcodeObject.h
ModelBoxObject.h
ModelEllipseObject.h
ModelImageObject.h
ModelLineObject.h
ModelShapeObject.h
ModelTextObject.h
PageRenderer.h
Settings.h
)
qt5_wrap_cpp (Model_moc_sources ${Model_qobject_headers})
#=====================================
# Target
#=====================================
add_library (Model STATIC
${Model_sources}
${Model_moc_sources}
)
target_compile_features (Model
PUBLIC cxx_std_11
)
target_include_directories (Model
PUBLIC .. ${CMAKE_CURRENT_BINARY_DIR}/..
PRIVATE ${CMAKE_CURRENT_BINARY_DIR}
)
target_link_libraries (Model
Barcode
Merge
Qt5::Widgets
Qt5::PrintSupport
Qt5::Xml
Qt5::Svg
ZLIB::ZLIB
)
#=======================================
# Subdirectories
#=======================================
add_subdirectory (unit_tests)
+45
View File
@@ -0,0 +1,45 @@
/* Category.cpp
*
* Copyright (C) 2013-2016 Jim Evins <evins@snaught.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "Category.h"
namespace glabels::model
{
Category::Category( const QString &id, const QString &name )
: mId(id), mName(name)
{
// empty
}
QString Category::id() const
{
return mId;
}
QString Category::name() const
{
return mName;
}
} // namespace glabels::model
+50
View File
@@ -0,0 +1,50 @@
/* Category.h
*
* Copyright (C) 2013-2016 Jim Evins <evins@snaught.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef model_Category_h
#define model_Category_h
#include <QString>
namespace glabels::model
{
class Category
{
public:
Category( const QString& id, const QString& name );
QString id() const;
QString name() const;
private:
QString mId;
QString mName;
};
}
#endif // model_Category_h
+202
View File
@@ -0,0 +1,202 @@
/* ColorNode.cpp
*
* Copyright (C) 2017 Jim Evins <evins@snaught.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "ColorNode.h"
#include "merge/Record.h"
namespace glabels::model
{
///
/// Default Constructor
///
ColorNode::ColorNode()
: mIsField(false), mColor(QColor::fromRgba(0x00000000)), mKey("")
{
// empty
}
///
/// Constructor From Data
///
ColorNode::ColorNode( bool isField, const QColor& color, const QString& key )
: mIsField(isField), mColor(color), mKey(key)
{
// empty
}
///
/// Constructor From Data
///
ColorNode::ColorNode( bool isField, uint32_t rgba, const QString& key )
: mIsField(isField), mKey(key)
{
mColor = QColor( (rgba >> 24) & 0xFF,
(rgba >> 16) & 0xFF,
(rgba >> 8) & 0xFF,
(rgba ) & 0xFF );
}
///
/// Constructor From Color
///
ColorNode::ColorNode( const QColor& color )
: mIsField(false), mColor(color), mKey("")
{
// empty
}
///
/// Constructor From Key
///
ColorNode::ColorNode( const QString& key )
: mIsField(true), mColor(QColor::fromRgba(0x00000000)), mKey(key)
{
// empty
}
///
/// == Operator
///
bool ColorNode::operator==( const ColorNode& cn )
{
return (mIsField == cn.mIsField) &&
(mColor == cn.mColor) &&
(mKey == cn.mKey);
}
///
/// != Operator
///
bool ColorNode::operator!=( const ColorNode& cn )
{
return (mIsField != cn.mIsField) ||
(mColor != cn.mColor) ||
(mKey != cn.mKey);
}
///
/// Field Flag Property Getter
///
bool ColorNode::isField() const
{
return mIsField;
}
///
/// Field Flag Property Setter
///
void ColorNode::setField( bool isField )
{
mIsField = isField;
}
///
/// Color Property Getter
///
const QColor& ColorNode::color() const
{
return mColor;
}
///
/// Color Property Setter
///
void ColorNode::setColor( const QColor& color )
{
mColor = color;
}
///
/// Key Property Getter
///
const QString& ColorNode::key() const
{
return mKey;
}
///
/// Key Property Setter
///
void ColorNode::setKey( const QString& key )
{
mKey = key;
}
///
/// Get color encoded as an RGBA 32-bit number
///
uint32_t ColorNode::rgba() const
{
uint32_t c =
mColor.red() << 24 |
mColor.green() << 16 |
mColor.blue() << 8 |
mColor.alpha();
return c;
}
///
/// Get color, expand if necessary
///
QColor ColorNode::color( merge::Record* record ) const
{
if ( mIsField )
{
if ( record == nullptr )
{
return mColor;
}
else
{
if ( record->contains( mKey ) )
{
return QColor( (*record)[ mKey ] );
}
else
{
return mColor;
}
}
}
else
{
return mColor;
}
}
} // namespace glabels::model
+112
View File
@@ -0,0 +1,112 @@
/* ColorNode.h
*
* Copyright (C) 2017 Jim Evins <evins@snaught.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef model_ColorNode_h
#define model_ColorNode_h
#include "merge/Record.h"
#include <QString>
#include <QColor>
#include <cstdint>
namespace glabels::model
{
///
/// Color Node Type
///
struct ColorNode
{
/////////////////////////////////
// Life Cycle
/////////////////////////////////
public:
ColorNode();
ColorNode( bool isField, const QColor& color, const QString& key );
ColorNode( bool isField, uint32_t rgba, const QString& key );
ColorNode( const QColor& color );
ColorNode( const QString& key );
/////////////////////////////////
// Operators
/////////////////////////////////
public:
bool operator==( const ColorNode& cn );
bool operator!=( const ColorNode& cn );
/////////////////////////////////
// Properties
/////////////////////////////////
public:
//
// Field Flag Property
//
bool isField() const;
void setField( bool isField );
//
// Color Property
//
const QColor& color() const;
void setColor( const QColor& color );
//
// Key Property
//
const QString& key() const;
void setKey( const QString& key );
/////////////////////////////////
// Misc. Methods
/////////////////////////////////
public:
uint32_t rgba() const;
QColor color( merge::Record* record ) const;
/////////////////////////////////
// Private Data
/////////////////////////////////
private:
bool mIsField;
QColor mColor;
QString mKey;
};
}
#endif // model_ColorNode_h
+37
View File
@@ -0,0 +1,37 @@
/* Config.h
*
* Copyright (C) 2013-2016 Jim Evins <evins@snaught.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef model_Config_h
#define model_Config_h
namespace glabels::model
{
namespace Config
{
const QString PROJECT_SOURCE_DIR = "@glabels-qt_SOURCE_DIR@";
const QString PROJECT_BUILD_DIR = "@glabels-qt_BINARY_DIR@";
}
}
#endif // model_Config_h
+37
View File
@@ -0,0 +1,37 @@
/* Constants.h
*
* Copyright (C) 2016 Jim Evins <evins@snaught.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef model_Constants_h
#define model_Constants_h
namespace glabels::model
{
const double PTS_PER_PT = 1.0;
const double PTS_PER_INCH = 72.0;
const double PTS_PER_MM = 2.83464566929;
const double PTS_PER_CM = (10.0*PTS_PER_MM);
const double PTS_PER_PICA = 12.0;
const Distance EPSILON( 0.5, Units::PT );
}
#endif // model_Constants_h
+110
View File
@@ -0,0 +1,110 @@
/* DataCache.cpp
*
* Copyright (C) 2017 Jim Evins <evins@snaught.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "DataCache.h"
#include "ModelImageObject.h"
namespace glabels::model
{
DataCache::DataCache()
{
// empty
}
DataCache::DataCache( const QList<ModelObject*>& objects )
{
foreach( ModelObject* object, objects )
{
if ( ModelImageObject* imageObject = dynamic_cast<ModelImageObject*>(object) )
{
TextNode filenameNode = imageObject->filenameNode();
if ( !filenameNode.isField() )
{
if ( const QImage* image = imageObject->image() )
{
addImage( filenameNode.data(), *image );
}
else
{
QByteArray svg = imageObject->svg();
if ( !svg.isEmpty() )
{
addSvg( filenameNode.data(), svg );
}
}
}
}
}
}
bool DataCache::hasImage( const QString& name ) const
{
return mImageMap.contains( name );
}
QImage DataCache::getImage( const QString& name ) const
{
return mImageMap[ name ];
}
void DataCache::addImage( const QString& name, const QImage& image )
{
mImageMap[ name ] = image;
}
QList<QString> DataCache::imageNames() const
{
return mImageMap.keys();
}
bool DataCache::hasSvg( const QString& name ) const
{
return mSvgMap.contains( name );
}
QByteArray DataCache::getSvg( const QString& name ) const
{
return mSvgMap[ name ];
}
void DataCache::addSvg( const QString& name, const QByteArray& svg )
{
mSvgMap[ name ] = svg;
}
QList<QString> DataCache::svgNames() const
{
return mSvgMap.keys();
}
} // namespace glabels::model
+58
View File
@@ -0,0 +1,58 @@
/* DataCache.h
*
* Copyright (C) 2017 Jim Evins <evins@snaught.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef model_DataCache_h
#define model_DataCache_h
#include "Model.h"
namespace glabels::model
{
class DataCache
{
public:
DataCache();
DataCache( const QList<ModelObject*>& objects );
bool hasImage( const QString& name ) const;
QImage getImage( const QString& name ) const;
void addImage( const QString& name, const QImage& image );
QList<QString> imageNames() const;
bool hasSvg( const QString& name ) const;
QByteArray getSvg( const QString& name ) const;
void addSvg( const QString& name, const QByteArray& svg );
QList<QString> svgNames() const;
private:
QMap<QString,QImage> mImageMap;
QMap<QString,QByteArray> mSvgMap;
};
}
#endif // model_DataCache_h
+689
View File
@@ -0,0 +1,689 @@
/* Db.cpp
*
* Copyright (C) 2013-2016 Jim Evins <evins@snaught.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "Db.h"
#include "Config.h"
#include "StrUtil.h"
#include "FileUtil.h"
#include "XmlCategoryParser.h"
#include "XmlPaperParser.h"
#include "XmlTemplateParser.h"
#include "XmlVendorParser.h"
#include <QtDebug>
#include <QtGlobal>
#include <algorithm>
namespace glabels::model
{
//
// Private
//
namespace
{
const QString empty = "";
bool partNameLessThan( const Template *a, const Template *b )
{
return StrUtil::comparePartNames( a->name(), b->name() ) < 0;
}
}
//
// Static data
//
QList<Paper*> Db::mPapers;
QStringList Db::mPaperIds;
QStringList Db::mPaperNames;
QList<Category*> Db::mCategories;
QStringList Db::mCategoryIds;
QStringList Db::mCategoryNames;
QList<Vendor*> Db::mVendors;
QStringList Db::mVendorNames;
QList<Template*> Db::mTemplates;
QString Db::mPaperNameOther;
Db::Db()
{
mPaperNameOther = tr("Other");
readPapers();
readCategories();
readVendors();
readTemplates();
}
void Db::init()
{
instance();
}
Db* Db::instance()
{
static Db* db = new Db();
return db;
}
const QList<Paper*>& Db::papers()
{
return mPapers;
}
const QStringList& Db::paperIds()
{
return mPaperIds;
}
const QStringList& Db::paperNames()
{
return mPaperNames;
}
const QList<Category*>& Db::categories()
{
return mCategories;
}
const QStringList& Db::categoryIds()
{
return mCategoryIds;
}
const QStringList& Db::categoryNames()
{
return mCategoryNames;
}
const QList<Vendor*>& Db::vendors()
{
return mVendors;
}
const QStringList& Db::vendorNames()
{
return mVendorNames;
}
const QList<Template*>& Db::templates()
{
return mTemplates;
}
void Db::registerPaper( Paper *paper )
{
if ( !isPaperIdKnown( paper->id() ) )
{
mPapers << paper;
mPaperIds << paper->id();
mPaperNames << paper->name();
}
else
{
qWarning() << "Duplicate paper ID: " << paper->id();
}
}
const Paper *Db::lookupPaperFromName( const QString& name )
{
if ( name.isNull() || name.isEmpty() )
{
qWarning() << "NULL paper name.";
return mPapers.first();
}
foreach ( Paper *paper, mPapers )
{
if ( paper->name() == name )
{
return paper;
}
}
qWarning() << "Unknown paper name: " << name;
return nullptr;
}
const Paper *Db::lookupPaperFromId( const QString& id )
{
if ( id.isNull() || id.isEmpty() )
{
qWarning() << "NULL paper ID.";
return mPapers.first();
}
foreach ( Paper *paper, mPapers )
{
if ( paper->id() == id )
{
return paper;
}
}
qWarning() << "Unknown paper ID: " << id;
return nullptr;
}
QString Db::lookupPaperIdFromName( const QString& name )
{
if ( !name.isNull() && !name.isEmpty() )
{
const Paper *paper = lookupPaperFromName( name );
if ( paper != nullptr )
{
return paper->id();
}
}
qWarning() << "Unknown paper name: " << name;
return empty;
}
QString Db::lookupPaperNameFromId( const QString& id )
{
if ( !id.isNull() && !id.isEmpty() )
{
if ( isPaperIdOther( id ) )
{
return mPaperNameOther;
}
const Paper *paper = lookupPaperFromId( id );
if ( paper != nullptr )
{
return paper->name();
}
}
qWarning() << "Unknown paper id: " << id;
return empty;
}
bool Db::isPaperIdKnown( const QString& id )
{
foreach ( Paper *paper, mPapers )
{
if ( paper->id() == id )
{
return true;
}
}
return false;
}
bool Db::isPaperIdOther( const QString& id )
{
return ( id == "Other" );
}
void Db::registerCategory( Category *category )
{
if ( !isCategoryIdKnown( category->id() ) )
{
mCategories << category;
mCategoryIds << category->id();
mCategoryNames << category->name();
}
else
{
qWarning() << "Duplicate category ID: " << category->id();
}
}
const Category *Db::lookupCategoryFromName( const QString& name )
{
if ( name.isNull() || name.isEmpty() )
{
qWarning() << "NULL category name.";
return mCategories.first();
}
foreach ( Category *category, mCategories )
{
if ( category->name() == name )
{
return category;
}
}
qWarning() << "Unknown category name: \"%s\"." << name;
return nullptr;
}
const Category *Db::lookupCategoryFromId( const QString& id )
{
if ( id.isNull() || id.isEmpty() )
{
qDebug() << "NULL category ID.";
return mCategories.first();
}
foreach ( Category *category, mCategories )
{
if ( category->id() == id )
{
return category;
}
}
qWarning() << "Unknown category ID: " << id;
return nullptr;
}
QString Db::lookupCategoryIdFromName( const QString& name )
{
if ( !name.isNull() && !name.isEmpty() )
{
const Category *category = lookupCategoryFromName( name );
if ( category != nullptr )
{
return category->id();
}
}
qWarning() << "Unknown category name: " << name;
return empty;
}
QString Db::lookupCategoryNameFromId( const QString& id )
{
if ( !id.isNull() && !id.isEmpty() )
{
const Category *category = lookupCategoryFromId( id );
if ( category != nullptr )
{
return category->name();
}
}
qWarning() << "Unknown category id: " << id;
return empty;
}
bool Db::isCategoryIdKnown( const QString& id )
{
foreach ( Category *category, mCategories )
{
if ( category->id() == id )
{
return true;
}
}
return false;
}
void Db::registerVendor( Vendor *vendor )
{
if ( !isVendorNameKnown( vendor->name() ) )
{
mVendors << vendor;
mVendorNames << vendor->name();
}
else
{
qWarning() << "Duplicate vendor name: " << vendor->name();
}
}
const Vendor *Db::lookupVendorFromName( const QString& name )
{
if ( name.isNull() || name.isEmpty() )
{
qWarning() << "NULL vendor name.";
return mVendors.first();
}
foreach ( Vendor *vendor, mVendors )
{
if ( vendor->name() == name )
{
return vendor;
}
}
qWarning() << "Unknown vendor name: " << name;
return nullptr;
}
QString Db::lookupVendorUrlFromName( const QString& name )
{
if ( !name.isNull() && !name.isEmpty() )
{
const Vendor *vendor = lookupVendorFromName( name );
if ( vendor != nullptr )
{
return vendor->url();
}
}
qWarning() << "Unknown vendor name: " << name;
return empty;
}
bool Db::isVendorNameKnown( const QString& name )
{
foreach ( Vendor *vendor, mVendors )
{
if ( vendor->name() == name )
{
return true;
}
}
return false;
}
void Db::registerTemplate( Template *tmplate )
{
if ( !isTemplateKnown( tmplate->brand(), tmplate->part() ) )
{
mTemplates << tmplate;
}
else
{
qWarning() << "Duplicate template name: " << tmplate->name();
}
}
const Template *Db::lookupTemplateFromName( const QString& name )
{
if ( name.isNull() || name.isEmpty() )
{
qWarning() << "NULL template name.";
return mTemplates.first();
}
foreach ( Template *tmplate, mTemplates )
{
if ( tmplate->name() == name )
{
return tmplate;
}
}
qWarning() << "Unknown template name: " << name;
return nullptr;
}
const Template *Db::lookupTemplateFromBrandPart( const QString& brand, const QString& part )
{
if ( brand.isNull() || brand.isEmpty() || part.isNull() || part.isEmpty() )
{
qWarning() << "NULL template brand and/or part.";
return mTemplates.first();
}
foreach ( Template *tmplate, mTemplates )
{
if ( (tmplate->brand() == brand) && (tmplate->part() == part) )
{
return tmplate;
}
}
qWarning() << "Unknown template brand, part: " << brand << ", " << part;
return nullptr;
}
bool Db::isTemplateKnown( const QString& brand, const QString& part )
{
foreach ( Template *tmplate, mTemplates )
{
if ( (tmplate->brand() == brand) && (tmplate->part() == part) )
{
return true;
}
}
return false;
}
QStringList Db::getNameListOfSimilarTemplates( const QString& name )
{
QStringList list;
const Template *tmplate1 = lookupTemplateFromName( name );
if ( tmplate1 == nullptr )
{
qWarning() << "Unknown template name: " << name;
return list;
}
foreach (const Template *tmplate2, mTemplates )
{
if ( tmplate1->name() != tmplate2->name() )
{
if ( tmplate1->isSimilarTo( tmplate2 ) )
{
list << tmplate2->name();
}
}
}
return list;
}
void Db::registerUserTemplate( Template *templat )
{
// TODO
}
void Db::deleteUserTemplateByName( const QString& name )
{
// TODO
}
void Db::deleteUserTemplateByBrandPart( const QString& brand, const QString& part )
{
// TODO
}
void Db::printKnownPapers()
{
qDebug() << "KNOWN PAPERS:";
foreach ( Paper *paper, mPapers )
{
qDebug() << "paper "
<< "id=" << paper->id() << ", "
<< "name=" << paper->name() << ", "
<< "width=" << paper->width().pt() << "pts, "
<< "height=" << paper->height().pt() << "pts, "
<< "pwg_size=" << paper->pwgSize();
}
qDebug();
}
void Db::printKnownCategories()
{
qDebug() << "KNOWN CATEGORIES:";
foreach ( Category *category, mCategories )
{
qDebug() << "category "
<< "id=" << category->id() << ", "
<< "name=" << category->name();
}
qDebug();
}
void Db::printKnownVendors()
{
qDebug() << "KNOWN VENDORS:";
foreach ( Vendor *vendor, mVendors )
{
qDebug() << "vendor "
<< "name='" << vendor->name() << ", "
<< "url='" << vendor->url();
}
qDebug();
}
void Db::printKnownTemplates()
{
qDebug() << "KNOWN TEMPLATES:";
foreach ( Template *tmplate, mTemplates )
{
qDebug() << "template "
<< "brand=" << tmplate->brand() << ", "
<< "part=" << tmplate->part() << ", "
<< "description=" << tmplate->description();
}
qDebug();
}
void Db::readPapers()
{
readPapersFromDir( FileUtil::systemTemplatesDir() );
}
void Db::readPapersFromDir( const QDir& dir )
{
XmlPaperParser parser;
foreach ( QString fileName, dir.entryList( QDir::Files ) )
{
if ( fileName == "paper-sizes.xml" )
{
parser.readFile( dir.absoluteFilePath( fileName ) );
}
}
}
void Db::readCategories()
{
readCategoriesFromDir( FileUtil::systemTemplatesDir() );
}
void Db::readCategoriesFromDir( const QDir& dir )
{
XmlCategoryParser parser;
foreach ( QString fileName, dir.entryList( QDir::Files ) )
{
if ( fileName == "categories.xml" )
{
parser.readFile( dir.absoluteFilePath( fileName ) );
}
}
}
void Db::readVendors()
{
readVendorsFromDir( FileUtil::systemTemplatesDir() );
}
void Db::readVendorsFromDir( const QDir& dir )
{
XmlVendorParser parser;
foreach ( QString fileName, dir.entryList( QDir::Files ) )
{
if ( fileName == "vendors.xml" )
{
parser.readFile( dir.absoluteFilePath( fileName ) );
}
}
}
void Db::readTemplates()
{
readTemplatesFromDir( FileUtil::systemTemplatesDir() );
// TODO: Read user directories
std::stable_sort( mTemplates.begin(), mTemplates.end(), partNameLessThan );
}
void Db::readTemplatesFromDir( const QDir& dir )
{
QStringList filters;
filters << "*-templates.xml" << "*.template";
XmlTemplateParser parser;
foreach ( QString fileName, dir.entryList( filters, QDir::Files ) )
{
parser.readFile( dir.absoluteFilePath( fileName ) );
}
}
} // namespace glabels::model
+141
View File
@@ -0,0 +1,141 @@
/* Db.h
*
* Copyright (C) 2013-2016 Jim Evins <evins@snaught.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef model_Db_h
#define model_Db_h
#include "Category.h"
#include "Paper.h"
#include "Template.h"
#include "Vendor.h"
#include <QCoreApplication>
#include <QDir>
#include <QList>
#include <QString>
namespace glabels::model
{
class Db
{
Q_DECLARE_TR_FUNCTIONS(Db)
private:
Db();
public:
static void init();
static Db* instance();
static const QList<Paper*>& papers();
static const QStringList& paperIds();
static const QStringList& paperNames();
static const QList<Category*>& categories();
static const QStringList& categoryIds();
static const QStringList& categoryNames();
static const QList<Vendor*>& vendors();
static const QStringList& vendorNames();
static const QList<Template*>& templates();
static void registerPaper( Paper *paper );
static const Paper *lookupPaperFromName( const QString& name );
static const Paper *lookupPaperFromId( const QString& id );
static QString lookupPaperIdFromName( const QString& name );
static QString lookupPaperNameFromId( const QString& id );
static bool isPaperIdKnown( const QString& id );
static bool isPaperIdOther( const QString& id );
static void registerCategory( Category *category );
static const Category *lookupCategoryFromName( const QString& name );
static const Category *lookupCategoryFromId( const QString& id );
static QString lookupCategoryIdFromName( const QString& name );
static QString lookupCategoryNameFromId( const QString& id );
static bool isCategoryIdKnown( const QString& id );
static void registerVendor( Vendor *vendor );
static const Vendor *lookupVendorFromName( const QString& name );
static QString lookupVendorUrlFromName( const QString& name );
static bool isVendorNameKnown( const QString& id );
static void registerTemplate( Template *tmplate );
static const Template *lookupTemplateFromName( const QString& name );
static const Template *lookupTemplateFromBrandPart( const QString& brand,
const QString& part );
static bool isTemplateKnown( const QString& brand, const QString& part );
static QStringList getNameListOfSimilarTemplates( const QString& name );
static void registerUserTemplate( Template *tmplate );
static void deleteUserTemplateByName( const QString& name );
static void deleteUserTemplateByBrandPart( const QString& brand,
const QString& part );
static void printKnownPapers();
static void printKnownCategories();
static void printKnownVendors();
static void printKnownTemplates();
private:
static QDir systemTemplatesDir();
static void readPapers();
static void readPapersFromDir( const QDir& dir );
static void readCategories();
static void readCategoriesFromDir( const QDir& dir );
static void readVendors();
static void readVendorsFromDir( const QDir& dir );
static void readTemplates();
static void readTemplatesFromDir( const QDir& dir );
private:
static QList<Paper*> mPapers;
static QStringList mPaperIds;
static QStringList mPaperNames;
static QList<Category*> mCategories;
static QStringList mCategoryIds;
static QStringList mCategoryNames;
static QList<Vendor*> mVendors;
static QStringList mVendorNames;
static QList<Template*> mTemplates;
static QString mPaperNameOther;
};
}
#endif // model_Db_h
+207
View File
@@ -0,0 +1,207 @@
/* Distance.cpp
*
* Copyright (C) 2016 Jim Evins <evins@snaught.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "Distance.h"
#include <QTextStream>
#include <QtDebug>
namespace glabels::model
{
Distance::Distance( double d, Units::Enum unitsEnum )
{
switch (unitsEnum)
{
case Units::PT:
mDPts = d;
break;
case Units::IN:
mDPts = d * PTS_PER_INCH;
break;
case Units::MM:
mDPts = d * PTS_PER_MM;
break;
case Units::CM:
mDPts = d * PTS_PER_CM;
break;
case Units::PC:
mDPts = d * PTS_PER_PICA;
break;
default:
mDPts = d;
break;
}
}
Distance::Distance( double d, const Units& units )
{
switch (units.toEnum())
{
case Units::PT:
mDPts = d;
break;
case Units::IN:
mDPts = d * PTS_PER_INCH;
break;
case Units::MM:
mDPts = d * PTS_PER_MM;
break;
case Units::CM:
mDPts = d * PTS_PER_CM;
break;
case Units::PC:
mDPts = d * PTS_PER_PICA;
break;
default:
mDPts = d;
break;
}
}
Distance::Distance( double d, const QString& unitsId )
{
Units units = Units( unitsId );
switch (units.toEnum())
{
case Units::PT:
mDPts = d;
break;
case Units::IN:
mDPts = d * PTS_PER_INCH;
break;
case Units::MM:
mDPts = d * PTS_PER_MM;
break;
case Units::CM:
mDPts = d * PTS_PER_CM;
break;
case Units::PC:
mDPts = d * PTS_PER_PICA;
break;
default:
mDPts = d;
break;
}
}
Distance Distance::fromString( const QString& string )
{
QString stringCopy = string;
QTextStream valueStream( &stringCopy, QIODevice::ReadOnly );
double value;
QString unitsString;
valueStream >> value >> unitsString;
if ( !unitsString.isEmpty() && !Units::isIdValid( unitsString ) )
{
qWarning() << "Invalid Units in string: \"" << string << "\"";
}
return Distance( value, unitsString );
}
double Distance::inUnits( const Units& units ) const
{
double d;
switch (units.toEnum())
{
case Units::PT:
d = pt();
break;
case Units::IN:
d = in();
break;
case Units::MM:
d = mm();
break;
case Units::CM:
d = cm();
break;
case Units::PC:
d = pc();
break;
}
return d;
}
double Distance::inUnits( Units::Enum unitsEnum ) const
{
double d;
switch (unitsEnum)
{
case Units::PT:
d = pt();
break;
case Units::IN:
d = in();
break;
case Units::MM:
d = mm();
break;
case Units::CM:
d = cm();
break;
case Units::PC:
d = pc();
break;
}
return d;
}
double Distance::inUnits( const QString& unitsId ) const
{
return inUnits( Units( unitsId ) );
}
QString Distance::toString( const Units& units ) const
{
return QString::number( inUnits(units) ) + units.toIdString();
}
QString Distance::toString( Units::Enum unitsEnum ) const
{
Units units(unitsEnum);
return QString::number( inUnits(units) ) + units.toIdString();
}
QString Distance::toString( const QString& unitsId ) const
{
Units units(unitsId);
return QString::number( inUnits(units) ) + units.toIdString();
}
} // namespace glabels::model
+302
View File
@@ -0,0 +1,302 @@
/* Distance.h
*
* Copyright (C) 2016 Jim Evins <evins@snaught.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef model_Distance_h
#define model_Distance_h
#include "Units.h"
#include <QCoreApplication>
#include <QString>
#include <QtMath>
namespace glabels::model
{
class Distance
{
Q_DECLARE_TR_FUNCTIONS(Distance)
public:
Distance();
Distance( double d, Units::Enum unitsEnum = Units::PT );
Distance( double d, const Units& units );
Distance( double d, const QString& unitsId );
static Distance pt( double dPts );
static Distance in( double dInches );
static Distance mm( double dMm );
static Distance cm( double dCm );
static Distance pc( double dPicas );
static Distance fromString( const QString& string );
double pt() const;
double in() const;
double mm() const;
double cm() const;
double pc() const;
double inUnits( const Units& units ) const;
double inUnits( Units::Enum unitsEnum ) const;
double inUnits( const QString& unitsId ) const;
QString toString( const Units& units ) const;
QString toString( Units::Enum unitsEnum ) const;
QString toString( const QString& unitsId ) const;
Distance& operator+=( const Distance& d );
Distance& operator-=( const Distance& d );
Distance operator-();
friend inline Distance operator+( const Distance& d1, const Distance& d2 );
friend inline Distance operator-( const Distance& d1, const Distance& d2 );
friend inline Distance operator*( double x, const Distance& d );
friend inline Distance operator*( const Distance& d, double x );
friend inline double operator/( const Distance& d1, const Distance& d2 );
friend inline Distance operator/( const Distance& d, double x );
friend inline bool operator<( const Distance& d1, const Distance& d2 );
friend inline bool operator<=( const Distance& d1, const Distance& d2 );
friend inline bool operator>( const Distance& d1, const Distance& d2 );
friend inline bool operator>=( const Distance& d1, const Distance& d2 );
friend inline bool operator==( const Distance& d1, const Distance& d2 );
friend inline bool operator!=( const Distance& d1, const Distance& d2 );
friend inline Distance fabs( const Distance& d );
friend inline Distance min( const Distance& d1, const Distance& d2 );
friend inline Distance max( const Distance& d1, const Distance& d2 );
friend inline Distance fmod( const Distance& d1, const Distance& d2 );
private:
double mDPts;
};
}
//
// Inline methods
//
#include "Constants.h"
namespace glabels::model
{
inline Distance::Distance() : mDPts(0)
{
}
inline Distance Distance::pt( double dPts )
{
Distance d;
d.mDPts = dPts;
return d;
}
inline Distance Distance::in( double dInches )
{
Distance d;
d.mDPts = dInches * PTS_PER_INCH;
return d;
}
inline Distance Distance::mm( double dMm )
{
Distance d;
d.mDPts = dMm * PTS_PER_MM;
return d;
}
inline Distance Distance::cm( double dCm )
{
Distance d;
d.mDPts = dCm * PTS_PER_CM;
return d;
}
inline Distance Distance::pc( double dPicas )
{
Distance d;
d.mDPts = dPicas * PTS_PER_PICA;
return d;
}
inline double Distance::pt() const
{
return mDPts;
}
inline double Distance::in() const
{
return mDPts / PTS_PER_INCH;
}
inline double Distance::mm() const
{
return mDPts / PTS_PER_MM;
}
inline double Distance::cm() const
{
return mDPts / PTS_PER_CM;
}
inline double Distance::pc() const
{
return mDPts / PTS_PER_PICA;
}
inline Distance& Distance::operator+=( const Distance& d )
{
mDPts += d.mDPts;
return *this;
}
inline Distance& Distance::operator-=( const Distance& d )
{
mDPts -= d.mDPts;
return *this;
}
inline Distance Distance::operator-()
{
return Distance::pt( -mDPts );
}
inline Distance operator+( const Distance& d1, const Distance& d2 )
{
return Distance::pt( d1.mDPts + d2.mDPts );
}
inline Distance operator-( const Distance& d1, const Distance& d2 )
{
return Distance::pt( d1.mDPts - d2.mDPts );
}
inline Distance operator*( double x, const Distance& d )
{
return Distance::pt( x * d.mDPts );
}
inline Distance operator*( const Distance& d, double x )
{
return Distance::pt( d.mDPts * x );
}
inline double operator/( const Distance& d1, const Distance& d2 )
{
return d1.mDPts / d2.mDPts;
}
inline Distance operator/( const Distance& d, double x )
{
return Distance::pt( d.mDPts / x );
}
inline bool operator<( const Distance& d1, const Distance& d2 )
{
return d1.mDPts < d2.mDPts;
}
inline bool operator<=( const Distance& d1, const Distance& d2 )
{
return d1.mDPts <= d2.mDPts;
}
inline bool operator>( const Distance& d1, const Distance& d2 )
{
return d1.mDPts > d2.mDPts;
}
inline bool operator>=( const Distance& d1, const Distance& d2 )
{
return d1.mDPts >= d2.mDPts;
}
inline bool operator==( const Distance& d1, const Distance& d2 )
{
return d1.mDPts == d2.mDPts;
}
inline bool operator!=( const Distance& d1, const Distance& d2 )
{
return d1.mDPts != d2.mDPts;
}
inline Distance fabs( const Distance& d )
{
return Distance::pt( qFabs( d.mDPts ) );
}
inline Distance min( const Distance& d1, const Distance& d2 )
{
return (d1.mDPts < d2.mDPts) ? d1 : d2;
}
inline Distance max( const Distance& d1, const Distance& d2 )
{
return (d1.mDPts > d2.mDPts) ? d1 : d2;
}
inline Distance fmod( const Distance& d1, const Distance& d2 )
{
return Distance::pt( std::fmod( d1.mDPts, d2.mDPts ) );
}
}
#endif // model_Distance_h
+87
View File
@@ -0,0 +1,87 @@
/* FileUtil.cpp
*
* Copyright (C) 2015 Jim Evins <evins@snaught.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "FileUtil.h"
#include "Config.h"
#include <QApplication>
namespace glabels::model
{
QString FileUtil::addExtension( const QString& rawFilename, const QString& extension )
{
if ( rawFilename.endsWith( extension ) )
{
return rawFilename;
}
return rawFilename + extension;
}
QDir FileUtil::systemTemplatesDir()
{
QDir dir;
// First, try finding templates directory relative to application path
dir.cd( QApplication::applicationDirPath() );
if ( (dir.dirName() == "bin") &&
dir.cdUp() && dir.cd( "share" ) && dir.cd( "glabels-qt" ) && dir.cd( "templates" ) )
{
return dir;
}
// Next, try running out of the source directory.
if ( dir.cd( Config::PROJECT_SOURCE_DIR ) && dir.cd( "templates" ) )
{
return dir;
}
qFatal( "Cannot locate system template directory!" );
return QDir("/");
}
QDir FileUtil::translationsDir()
{
QDir dir;
// First, try finding translations directory relative to application path
dir.cd( QApplication::applicationDirPath() );
if ( (dir.dirName() == "bin") &&
dir.cdUp() && dir.cd( "share" ) && dir.cd( "glabels-qt" ) && dir.cd( "translations" ) )
{
return dir;
}
// Next, try running out of the source directory.
if ( dir.cd( Config::PROJECT_BUILD_DIR ) && dir.cd( "translations" ) )
{
return dir;
}
qFatal( "Cannot locate system template directory!" );
return QDir("/");
}
} // namespace glabels::model
+46
View File
@@ -0,0 +1,46 @@
/* FileUtil.h
*
* Copyright (C) 2015 Jim Evins <evins@snaught.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef model_FileUtil_h
#define model_FileUtil_h
#include <QString>
#include <QDir>
namespace glabels::model
{
namespace FileUtil
{
QString addExtension( const QString& rawFilename, const QString& extension );
QDir systemTemplatesDir();
QDir userTemplatesDir();
QDir translationsDir();
}
}
#endif // model_FileUtil_h
+138
View File
@@ -0,0 +1,138 @@
/* Frame.cpp
*
* Copyright (C) 2013-2016 Jim Evins <evins@snaught.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "Frame.h"
#include "Markup.h"
#include <algorithm>
namespace glabels::model
{
Frame::Frame( const QString& id )
: mId(id), mNLabels(0), mLayoutDescription("")
{
// empty
}
Frame::Frame( const Frame& other )
{
mId = other.mId;
mNLabels = 0;
foreach ( Layout *layout, mLayouts )
{
addLayout( layout->dup() );
}
foreach ( Markup *markup, mMarkups )
{
addMarkup( markup->dup() );
}
}
QString Frame::id() const
{
return mId;
}
int Frame::nLabels() const
{
return mNLabels;
}
QString Frame::layoutDescription() const
{
return mLayoutDescription;
}
const QList<Layout*>& Frame::layouts() const
{
return mLayouts;
}
const QList<Markup*>& Frame::markups() const
{
return mMarkups;
}
QVector<Point> Frame::getOrigins() const
{
QVector<Point> origins( nLabels() );
int i = 0;
foreach ( Layout *layout, mLayouts )
{
for ( int iy = 0; iy < layout->ny(); iy++ )
{
for ( int ix = 0; ix < layout->nx(); ix++ )
{
origins[i++] = Point( ix*layout->dx() + layout->x0(), iy*layout->dy() + layout->y0() );
}
}
}
std::stable_sort( origins.begin(), origins.end() );
return origins;
}
void Frame::addLayout( Layout *layout )
{
mLayouts << layout;
// Update total number of labels
mNLabels += layout->nx() * layout->ny();
// Update layout description
if ( mLayouts.size() == 1 )
{
/*
* Translators: %1 = number of labels across a page,
* %2 = number of labels down a page,
* %3 = total number of labels on a page (sheet).
*/
mLayoutDescription = QString( tr("%1 x %2 (%3 per sheet)") )
.arg(layout->nx()).arg(layout->ny()).arg(mNLabels);
}
else
{
/* Translators: %1 is the total number of labels on a page (sheet). */
mLayoutDescription = QString( tr("%1 per sheet") ).arg(mNLabels);
}
}
void Frame::addMarkup( Markup *markup )
{
mMarkups << markup;
}
} // namespace glabels::model
+88
View File
@@ -0,0 +1,88 @@
/* Frame.h
*
* Copyright (C) 2013-2016 Jim Evins <evins@snaught.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef model_Frame_h
#define model_Frame_h
#include "Distance.h"
#include "Layout.h"
#include "Point.h"
#include <QCoreApplication>
#include <QList>
#include <QPainterPath>
#include <QString>
#include <QVector>
namespace glabels::model
{
// Forward references
class Markup;
class Frame
{
Q_DECLARE_TR_FUNCTIONS(Frame)
protected:
Frame( const QString& id = "0" );
Frame( const Frame& other );
public:
virtual Frame* dup() const = 0;
QString id() const;
int nLabels() const;
QString layoutDescription() const;
const QList<Layout*>& layouts() const;
const QList<Markup*>& markups() const;
QVector<Point> getOrigins() const;
void addLayout( Layout* layout );
void addMarkup( Markup* markup );
virtual Distance w() const = 0;
virtual Distance h() const = 0;
virtual QString sizeDescription( const Units& units ) const = 0;
virtual bool isSimilarTo( Frame* other ) const = 0;
virtual const QPainterPath& path() const = 0;
virtual const QPainterPath& clipPath() const = 0;
virtual QPainterPath marginPath( const Distance& size ) const = 0;
private:
QString mId;
int mNLabels;
QString mLayoutDescription;
QList<Layout*> mLayouts;
QList<Markup*> mMarkups;
};
}
#endif // model_Frame_h
+218
View File
@@ -0,0 +1,218 @@
/* FrameCd.cpp
*
* Copyright (C) 2013-2016 Jim Evins <evins@snaught.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "FrameCd.h"
#include "Constants.h"
#include "StrUtil.h"
#include <QtDebug>
namespace glabels::model
{
FrameCd::FrameCd( const Distance& r1,
const Distance& r2,
const Distance& w,
const Distance& h,
const Distance& waste,
const QString& id )
: Frame(id), mR1(r1), mR2(r2), mW(w), mH(h), mWaste(waste)
{
Distance wReal = (mW == 0) ? 2*mR1 : mW;
Distance hReal = (mH == 0) ? 2*mR1 : mH;
//
// Create path
//
{
/*
* Construct outer subpath (may be clipped if it's a business card CD)
*/
QPainterPath outerPath;
outerPath.addEllipse( (wReal/2 - r1).pt(), (hReal/2 - r1).pt(), 2*r1.pt(), 2*r1.pt() );
QPainterPath clipPath;
clipPath.addRect( 0, 0, wReal.pt(), hReal.pt() );
mPath.addPath( outerPath & clipPath );
mPath.closeSubpath();
/*
* Add inner subpath
*/
mPath.addEllipse( (wReal/2 - r2).pt(), (hReal/2 - r2).pt(), 2*r2.pt(), 2*r2.pt() );
}
//
// Create clip path
//
{
Distance r1Clip = mR1 + mWaste;
Distance r2Clip = mR2 - mWaste;
Distance wClip = (mW == 0) ? 2*r1Clip : mW + 2*mWaste;
Distance hClip = (mH == 0) ? 2*r1Clip : mH + 2*mWaste;
/*
* Construct outer subpath (may be clipped if it's a business card CD)
*/
QPainterPath outerPath;
outerPath.addEllipse( (wReal/2 - r1Clip).pt(), (hReal/2 - r1Clip).pt(), 2*r1Clip.pt(), 2*r1Clip.pt() );
QPainterPath clipPath;
clipPath.addRect( -mWaste.pt(), -mWaste.pt(), wClip.pt(), hClip.pt() );
mClipPath.addPath( outerPath & clipPath );
mClipPath.closeSubpath();
/*
* Add inner subpath
*/
mClipPath.addEllipse( (wReal/2 - r2Clip).pt(), (hReal/2 - r2Clip).pt(), 2*r2Clip.pt(), 2*r2Clip.pt() );
}
}
FrameCd::FrameCd( const FrameCd& other )
: Frame(other),
mR1(other.mR1), mR2(other.mR2), mW(other.mW), mH(other.mH), mWaste(other.mWaste),
mPath(other.mPath)
{
// empty
}
Frame* FrameCd::dup() const
{
return new FrameCd( *this );
}
Distance FrameCd::w() const
{
return (mW == 0) ? 2*mR1 : mW;
}
Distance FrameCd::h() const
{
return (mH == 0) ? 2*mR1 : mH;
}
Distance FrameCd::r1() const
{
return mR1;
}
Distance FrameCd::r2() const
{
return mR2;
}
Distance FrameCd::waste() const
{
return mWaste;
}
QString FrameCd::sizeDescription( const Units& units ) const
{
if ( units.toEnum() == Units::IN )
{
QString dStr = StrUtil::formatFraction( 2 * mR1.in() );
return QString().sprintf( "%s %s %s",
qPrintable(dStr),
qPrintable(units.toTrName()),
qPrintable(tr("diameter")) );
}
else
{
return QString().sprintf( "%.5g %s %s",
2 * mR1.inUnits(units),
qPrintable(units.toTrName()),
qPrintable(tr("diameter")) );
}
}
bool FrameCd::isSimilarTo( Frame* other ) const
{
if ( FrameCd *otherCd = dynamic_cast<FrameCd*>(other) )
{
if ( (fabs( mW - otherCd->mW ) <= EPSILON) &&
(fabs( mH - otherCd->mH ) <= EPSILON) &&
(fabs( mR1 - otherCd->mR1 ) <= EPSILON) &&
(fabs( mR2 - otherCd->mR2 ) <= EPSILON) )
{
return true;
}
}
return false;
}
const QPainterPath& FrameCd::path() const
{
return mPath;
}
const QPainterPath& FrameCd::clipPath() const
{
return mClipPath;
}
QPainterPath FrameCd::marginPath( const Distance& size ) const
{
Distance wReal = (mW == 0) ? 2*mR1 : mW;
Distance hReal = (mH == 0) ? 2*mR1 : mH;
Distance r1 = mR1 - size;
Distance r2 = mR2 + size;
QPainterPath path;
/*
* Construct outer subpath (may be clipped if it's a business card CD)
*/
QPainterPath outerPath;
outerPath.addEllipse( (wReal/2 - r1).pt(), (hReal/2 - r1).pt(), 2*r1.pt(), 2*r1.pt() );
QPainterPath clipPath;
clipPath.addRect( size.pt(), size.pt(), (wReal-2*size).pt(), (hReal-2*size).pt() );
path.addPath( outerPath & clipPath );
path.closeSubpath();
/*
* Add inner subpath
*/
path.addEllipse( (wReal/2 - r2).pt(), (hReal/2 - r2).pt(), 2*r2.pt(), 2*r2.pt() );
return path;
}
} // namespace glabels::model
+77
View File
@@ -0,0 +1,77 @@
/* FrameCd.h
*
* Copyright (C) 2013-2016 Jim Evins <evins@snaught.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef model_FrameCd_h
#define model_FrameCd_h
#include "Frame.h"
namespace glabels::model
{
class FrameCd : public Frame
{
Q_DECLARE_TR_FUNCTIONS(FrameCd)
public:
FrameCd( const Distance& r1,
const Distance& r2,
const Distance& w,
const Distance& h,
const Distance& waste,
const QString& id = "0" );
FrameCd( const FrameCd &other );
Frame *dup() const override;
Distance r1() const;
Distance r2() const;
Distance waste() const;
Distance w() const override;
Distance h() const override;
QString sizeDescription( const Units& units ) const override;
bool isSimilarTo( Frame* other ) const override;
const QPainterPath& path() const override;
const QPainterPath& clipPath() const override;
QPainterPath marginPath( const Distance& size ) const override;
private:
Distance mR1;
Distance mR2;
Distance mW;
Distance mH;
Distance mWaste;
QPainterPath mPath;
QPainterPath mClipPath;
};
}
#endif // model_FrameCd_h
+130
View File
@@ -0,0 +1,130 @@
/* FrameEllipse.cpp
*
* Copyright (C) 2013-2016 Jim Evins <evins@snaught.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "FrameEllipse.h"
#include "Constants.h"
#include "StrUtil.h"
namespace glabels::model
{
FrameEllipse::FrameEllipse( const Distance& w,
const Distance& h,
const Distance& waste,
const QString& id )
: Frame(id), mW(w), mH(h), mWaste(waste)
{
mPath.addEllipse( 0, 0, mW.pt(), mH.pt() );
mClipPath.addEllipse( -mWaste.pt(), -mWaste.pt(), (mW+2*mWaste).pt(), (mH+2*mWaste).pt() );
}
FrameEllipse::FrameEllipse( const FrameEllipse& other )
: Frame(other), mW(other.mW), mH(other.mH), mWaste(other.mWaste), mPath(other.mPath)
{
// empty
}
Frame* FrameEllipse::dup() const
{
return new FrameEllipse( *this );
}
Distance FrameEllipse::w() const
{
return mW;
}
Distance FrameEllipse::h() const
{
return mH;
}
Distance FrameEllipse::waste() const
{
return mWaste;
}
QString FrameEllipse::sizeDescription( const Units& units ) const
{
if ( units.toEnum() == Units::IN )
{
QString wStr = StrUtil::formatFraction( mW.in() );
QString hStr = StrUtil::formatFraction( mH.in() );
return QString().sprintf( "%s x %s %s",
qPrintable(wStr),
qPrintable(hStr),
qPrintable(units.toTrName()) );
}
else
{
return QString().sprintf( "%.5g x %.5g %s",
mW.inUnits(units),
mH.inUnits(units),
qPrintable(units.toTrName()) );
}
}
bool FrameEllipse::isSimilarTo( Frame* other ) const
{
if ( FrameEllipse* otherEllipse = dynamic_cast<FrameEllipse*>(other) )
{
if ( (fabs( mW - otherEllipse->mW ) <= EPSILON) &&
(fabs( mH - otherEllipse->mH ) <= EPSILON) )
{
return true;
}
}
return false;
}
const QPainterPath& FrameEllipse::path() const
{
return mPath;
}
const QPainterPath& FrameEllipse::clipPath() const
{
return mClipPath;
}
QPainterPath FrameEllipse::marginPath( const Distance& size ) const
{
Distance w = mW - 2*size;
Distance h = mH - 2*size;
QPainterPath path;
path.addEllipse( size.pt(), size.pt(), w.pt(), h.pt() );
return path;
}
} // namespace glabels::model
+71
View File
@@ -0,0 +1,71 @@
/* FrameEllipse.h
*
* Copyright (C) 2013-2016 Jim Evins <evins@snaught.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef model_FrameEllipse_h
#define model_FrameEllipse_h
#include "Frame.h"
namespace glabels::model
{
class FrameEllipse : public Frame
{
Q_DECLARE_TR_FUNCTIONS(FrameEllipse)
public:
FrameEllipse( const Distance& w,
const Distance& h,
const Distance& waste,
const QString& id = "0" );
FrameEllipse( const FrameEllipse& other );
Frame* dup() const override;
Distance waste() const;
Distance w() const override;
Distance h() const override;
QString sizeDescription( const Units& units ) const override;
bool isSimilarTo( Frame* other ) const override;
const QPainterPath& path() const override;
const QPainterPath& clipPath() const override;
QPainterPath marginPath( const Distance& size ) const override;
private:
Distance mW;
Distance mH;
Distance mWaste;
QPainterPath mPath;
QPainterPath mClipPath;
};
}
#endif // model_FrameEllipse_h
+152
View File
@@ -0,0 +1,152 @@
/* FrameRect.cpp
*
* Copyright (C) 2013-2016 Jim Evins <evins@snaught.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "FrameRect.h"
#include "Constants.h"
#include "StrUtil.h"
namespace glabels::model
{
FrameRect::FrameRect( const Distance& w,
const Distance& h,
const Distance& r,
const Distance& xWaste,
const Distance& yWaste,
const QString& id )
: Frame(id), mW(w), mH(h), mR(r), mXWaste(xWaste), mYWaste(yWaste)
{
mPath.addRoundedRect( 0, 0, mW.pt(), mH.pt(), mR.pt(), mR.pt() );
mClipPath.addRoundedRect( -mXWaste.pt(), -mYWaste.pt(),
mW.pt() + 2*mXWaste.pt(), mH.pt() + 2*mYWaste.pt(),
mR.pt(), mR.pt() );
}
FrameRect::FrameRect( const FrameRect &other )
: Frame(other),
mW(other.mW), mH(other.mH), mR(other.mR), mXWaste(other.mXWaste),
mYWaste(other.mYWaste), mPath(other.mPath)
{
// empty
}
Frame* FrameRect::dup() const
{
return new FrameRect( *this );
}
Distance FrameRect::w() const
{
return mW;
}
Distance FrameRect::h() const
{
return mH;
}
Distance FrameRect::r() const
{
return mR;
}
Distance FrameRect::xWaste() const
{
return mXWaste;
}
Distance FrameRect::yWaste() const
{
return mYWaste;
}
QString FrameRect::sizeDescription( const Units& units ) const
{
if ( units.toEnum() == Units::IN )
{
QString wStr = StrUtil::formatFraction( mW.in() );
QString hStr = StrUtil::formatFraction( mH.in() );
return QString().sprintf( "%s x %s %s",
qPrintable(wStr),
qPrintable(hStr),
qPrintable(units.toTrName()) );
}
else
{
return QString().sprintf( "%.5g x %.5g %s",
mW.inUnits(units),
mH.inUnits(units),
qPrintable(units.toTrName()) );
}
}
bool FrameRect::isSimilarTo( Frame* other ) const
{
if ( FrameRect *otherRect = dynamic_cast<FrameRect*>(other) )
{
if ( (fabs( mW - otherRect->mW ) <= EPSILON) &&
(fabs( mH - otherRect->mH ) <= EPSILON) )
{
return true;
}
}
return false;
}
const QPainterPath& FrameRect::path() const
{
return mPath;
}
const QPainterPath& FrameRect::clipPath() const
{
return mClipPath;
}
QPainterPath FrameRect::marginPath( const Distance& size ) const
{
Distance w = mW - 2*size;
Distance h = mH - 2*size;
Distance r = std::max( mR - size, Distance(0.0) );
QPainterPath path;
path.addRoundedRect( size.pt(), size.pt(), w.pt(), h.pt(), r.pt(), r.pt() );
return path;
}
} // namespace glabels::model
+78
View File
@@ -0,0 +1,78 @@
/* FrameRect.h
*
* Copyright (C) 2013-2016 Jim Evins <evins@snaught.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef model_FrameRect_h
#define model_FrameRect_h
#include "Frame.h"
namespace glabels::model
{
class FrameRect : public Frame
{
Q_DECLARE_TR_FUNCTIONS(FrameRect)
public:
FrameRect( const Distance& w,
const Distance& h,
const Distance& r,
const Distance& xWaste,
const Distance& yWaste,
const QString& id = "0" );
FrameRect( const FrameRect& other );
Frame* dup() const override;
Distance r() const;
Distance xWaste() const;
Distance yWaste() const;
Distance w() const override;
Distance h() const override;
QString sizeDescription( const Units& units ) const override;
bool isSimilarTo( Frame* other ) const override;
const QPainterPath& path() const override;
const QPainterPath& clipPath() const override;
QPainterPath marginPath( const Distance& size ) const override;
private:
Distance mW;
Distance mH;
Distance mR;
Distance mXWaste;
Distance mYWaste;
QPainterPath mPath;
QPainterPath mClipPath;
};
}
#endif // model_FrameRect_h
+134
View File
@@ -0,0 +1,134 @@
/* FrameRound.cpp
*
* Copyright (C) 2013-2016 Jim Evins <evins@snaught.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "FrameRound.h"
#include "Constants.h"
#include "StrUtil.h"
namespace glabels::model
{
FrameRound::FrameRound( const Distance& r,
const Distance& waste,
const QString& id )
: Frame(id), mR(r), mWaste(waste)
{
mPath.addEllipse( 0, 0, 2*mR.pt(), 2*mR.pt() );
mClipPath.addEllipse( -mWaste.pt(), -mWaste.pt(),
2*(mR+mWaste).pt(), 2*(mR+mWaste).pt() );
}
FrameRound::FrameRound( const FrameRound& other )
: Frame(other), mR(other.mR), mWaste(other.mWaste), mPath(other.mPath)
{
// empty
}
Frame* FrameRound::dup() const
{
return new FrameRound( *this );
}
Distance FrameRound::w() const
{
return 2*mR;
}
Distance FrameRound::h() const
{
return 2*mR;
}
Distance FrameRound::r() const
{
return mR;
}
Distance FrameRound::waste() const
{
return mWaste;
}
QString FrameRound::sizeDescription( const Units& units ) const
{
if ( units.toEnum() == Units::IN )
{
QString dStr = StrUtil::formatFraction( 2 * mR.in() );
return QString().sprintf( "%s %s %s",
qPrintable(dStr),
qPrintable(units.toTrName()),
qPrintable(tr("diameter")) );
}
else
{
return QString().sprintf( "%.5g %s %s",
2 * mR.inUnits(units),
qPrintable(units.toTrName()),
qPrintable(tr("diameter")) );
}
}
bool FrameRound::isSimilarTo( Frame* other ) const
{
if ( FrameRound *otherRound = dynamic_cast<FrameRound*>(other) )
{
if ( fabs( mR - otherRound->mR ) <= EPSILON )
{
return true;
}
}
return false;
}
const QPainterPath& FrameRound::path() const
{
return mPath;
}
const QPainterPath& FrameRound::clipPath() const
{
return mClipPath;
}
QPainterPath FrameRound::marginPath( const Distance& size ) const
{
Distance r = mR - size;
QPainterPath path;
path.addEllipse( size.pt(), size.pt(), 2*r.pt(), 2*r.pt() );
return path;
}
} // namespace glabels::model
+70
View File
@@ -0,0 +1,70 @@
/* FrameRound.h
*
* Copyright (C) 2013-2016 Jim Evins <evins@snaught.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef model_FrameRound_h
#define model_FrameRound_h
#include "Frame.h"
namespace glabels::model
{
class FrameRound : public Frame
{
Q_DECLARE_TR_FUNCTIONS(FrameRound)
public:
FrameRound( const Distance& r,
const Distance& waste,
const QString& id = "0" );
FrameRound( const FrameRound &other );
Frame *dup() const override;
Distance r() const;
Distance waste() const;
Distance w() const override;
Distance h() const override;
QString sizeDescription( const Units& units ) const override;
bool isSimilarTo( Frame* other ) const override;
const QPainterPath& path() const override;
const QPainterPath& clipPath() const override;
QPainterPath marginPath( const Distance& size ) const override;
private:
Distance mR;
Distance mWaste;
QPainterPath mPath;
QPainterPath mClipPath;
};
}
#endif // model_FrameRound_h
+588
View File
@@ -0,0 +1,588 @@
/* Handles.cpp
*
* Copyright (C) 2013 Jim Evins <evins@snaught.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "Handles.h"
#include "ModelObject.h"
#include <QColor>
#include <QtDebug>
namespace glabels::model
{
//
// Private
//
namespace
{
const double handlePixels = 7;
const double handleOutlineWidthPixels = 1;
const QColor handleFillColor( 0, 192, 0, 96 );
const QColor originHandleFillColor( 192, 0, 0, 96 );
const QColor handleOutlineColor( 0, 0, 0, 192 );
}
///
/// Handle Constructor
///
Handle::Handle( ModelObject* owner, Location location )
: mOwner(owner), mLocation(location)
{
// empty
}
///
/// Handle Destructor
///
Handle::~Handle()
{
// empty
}
///
/// Handle owner
///
ModelObject* Handle::owner() const
{
return mOwner;
}
///
/// Handle location
///
Handle::Location Handle::location() const
{
return mLocation;
}
///
/// Draw Handle at x,y
///
void Handle::drawAt( QPainter* painter,
double scale,
const Distance& x,
const Distance& y,
QColor color ) const
{
painter->save();
painter->translate( x.pt(), y.pt() );
double s = 1.0 / scale;
QPen pen( handleOutlineColor );
pen.setCosmetic( true );
pen.setWidth( handleOutlineWidthPixels );
painter->setPen( pen );
painter->setBrush( color );
painter->drawRect( QRectF( -s*handlePixels/2.0, -s*handlePixels/2.0,
s*handlePixels, s*handlePixels ) );
painter->restore();
}
///
/// Create Handle path at x,y
///
QPainterPath Handle::pathAt( double scale,
const Distance& x,
const Distance& y ) const
{
QPainterPath path;
double s = 1/scale;
path.addRect( -s*handlePixels/2, -s*handlePixels/2, s*handlePixels, s*handlePixels );
path.translate( x.pt(), y.pt() );
return path;
}
///
/// HandleNorth Constructor
///
HandleNorth::HandleNorth( ModelObject* owner )
: Handle( owner, N )
{
// empty
}
///
/// HandleNorth Destructor
///
HandleNorth::~HandleNorth()
{
// empty
}
///
/// HandleNorth Clone
///
HandleNorth* HandleNorth::clone( ModelObject* newOwner ) const
{
return new HandleNorth( newOwner );
}
///
/// Draw HandleNorth
///
void HandleNorth::draw( QPainter* painter, double scale ) const
{
drawAt( painter, scale, mOwner->w()/2, 0, handleFillColor );
}
///
/// HandleNorth Path
///
QPainterPath HandleNorth::path( double scale ) const
{
return pathAt( scale, mOwner->w()/2, 0 );
}
///
/// HandleNorthEast Constructor
///
HandleNorthEast::HandleNorthEast( ModelObject* owner )
: Handle( owner, NE )
{
// empty
}
///
/// HandleNorthEast Destructor
///
HandleNorthEast::~HandleNorthEast()
{
// empty
}
///
/// HandleNorthEast Clone
///
HandleNorthEast* HandleNorthEast::clone( ModelObject* newOwner ) const
{
return new HandleNorthEast( newOwner );
}
///
/// Draw HandleNorthEast
///
void HandleNorthEast::draw( QPainter* painter, double scale ) const
{
drawAt( painter, scale, mOwner->w(), 0, handleFillColor );
}
///
/// HandleNorthEast Path
///
QPainterPath HandleNorthEast::path( double scale ) const
{
return pathAt( scale, mOwner->w(), 0 );
}
///
/// HandleEast Constructor
///
HandleEast::HandleEast( ModelObject* owner )
: Handle( owner, E )
{
// empty
}
///
/// HandleEast Destructor
///
HandleEast::~HandleEast()
{
// empty
}
///
/// HandleEast Clone
///
HandleEast* HandleEast::clone( ModelObject* newOwner ) const
{
return new HandleEast( newOwner );
}
///
/// Draw HandleEast
///
void HandleEast::draw( QPainter* painter, double scale ) const
{
drawAt( painter, scale, mOwner->w(), mOwner->h()/2, handleFillColor );
}
///
/// HandleEast Path
///
QPainterPath HandleEast::path( double scale ) const
{
return pathAt( scale, mOwner->w(), mOwner->h()/2 );
}
///
/// HandleSouthEast Constructor
///
HandleSouthEast::HandleSouthEast( ModelObject* owner )
: Handle( owner, SE )
{
// empty
}
///
/// HandleSouthEast Destructor
///
HandleSouthEast::~HandleSouthEast()
{
// empty
}
///
/// HandleSouthEast Clone
///
HandleSouthEast* HandleSouthEast::clone( ModelObject* newOwner ) const
{
return new HandleSouthEast( newOwner );
}
///
/// Draw HandleSouthEast
///
void HandleSouthEast::draw( QPainter* painter, double scale ) const
{
drawAt( painter, scale, mOwner->w(), mOwner->h(), handleFillColor );
}
///
/// HandleSouthEast Path
///
QPainterPath HandleSouthEast::path( double scale ) const
{
return pathAt( scale, mOwner->w(), mOwner->h() );
}
///
/// HandleSouth Constructor
///
HandleSouth::HandleSouth( ModelObject* owner )
: Handle( owner, S )
{
// empty
}
///
/// HandleSouth Destructor
///
HandleSouth::~HandleSouth()
{
// empty
}
///
/// HandleSouth Clone
///
HandleSouth* HandleSouth::clone( ModelObject* newOwner ) const
{
return new HandleSouth( newOwner );
}
///
/// Draw HandleSouth
///
void HandleSouth::draw( QPainter* painter, double scale ) const
{
drawAt( painter, scale, mOwner->w()/2, mOwner->h(), handleFillColor );
}
///
/// HandleSouth Path
///
QPainterPath HandleSouth::path( double scale ) const
{
return pathAt( scale, mOwner->w()/2, mOwner->h() );
}
///
/// HandleSouthWest Constructor
///
HandleSouthWest::HandleSouthWest( ModelObject* owner )
: Handle( owner, SW )
{
// empty
}
///
/// HandleSouthWest Destructor
///
HandleSouthWest::~HandleSouthWest()
{
// empty
}
///
/// HandleSouthWest Clone
///
HandleSouthWest* HandleSouthWest::clone( ModelObject* newOwner ) const
{
return new HandleSouthWest( newOwner );
}
///
/// Draw HandleSouthWest
///
void HandleSouthWest::draw( QPainter* painter, double scale ) const
{
drawAt( painter, scale, 0, mOwner->h(), handleFillColor );
}
///
/// HandleSouthWest Path
///
QPainterPath HandleSouthWest::path( double scale ) const
{
return pathAt( scale, 0, mOwner->h() );
}
///
/// HandleWest Constructor
///
HandleWest::HandleWest( ModelObject* owner )
: Handle( owner, W )
{
// empty
}
///
/// HandleWest Destructor
///
HandleWest::~HandleWest()
{
// empty
}
///
/// HandleWest Clone
///
HandleWest* HandleWest::clone( ModelObject* newOwner ) const
{
return new HandleWest( newOwner );
}
///
/// Draw HandleWest
///
void HandleWest::draw( QPainter* painter, double scale ) const
{
drawAt( painter, scale, 0, mOwner->h()/2, handleFillColor );
}
///
/// HandleWest Path
///
QPainterPath HandleWest::path( double scale ) const
{
return pathAt( scale, 0, mOwner->h()/2 );
}
///
/// HandleNorthWest Constructor
///
HandleNorthWest::HandleNorthWest( ModelObject* owner )
: Handle( owner, NW )
{
// empty
}
///
/// HandleNorthWest Destructor
///
HandleNorthWest::~HandleNorthWest()
{
// empty
}
///
/// HandleNorthWest Clone
///
HandleNorthWest* HandleNorthWest::clone( ModelObject* newOwner ) const
{
return new HandleNorthWest( newOwner );
}
///
/// Draw HandleNorthWest
///
void HandleNorthWest::draw( QPainter* painter, double scale ) const
{
drawAt( painter, scale, 0, 0, originHandleFillColor );
}
///
/// HandleNorthWest Path
///
QPainterPath HandleNorthWest::path( double scale ) const
{
return pathAt( scale, 0, 0 );
}
///
/// HandleP1 Constructor
///
HandleP1::HandleP1( ModelObject* owner )
: Handle( owner, P1 )
{
// empty
}
///
/// HandleP1 Destructor
///
HandleP1::~HandleP1()
{
// empty
}
///
/// HandleP1 Clone
///
HandleP1* HandleP1::clone( ModelObject* newOwner ) const
{
return new HandleP1( newOwner );
}
///
/// Draw HandleP1
///
void HandleP1::draw( QPainter* painter, double scale ) const
{
drawAt( painter, scale, 0, 0, originHandleFillColor );
}
///
/// HandleP1 Path
///
QPainterPath HandleP1::path( double scale ) const
{
return pathAt( scale, 0, 0 );
}
///
/// HandleP2 Constructor
///
HandleP2::HandleP2( ModelObject* owner )
: Handle( owner, P2 )
{
// empty
}
///
/// HandleP2 Destructor
///
HandleP2::~HandleP2()
{
// empty
}
///
/// HandleP2 Clone
///
HandleP2* HandleP2::clone( ModelObject* newOwner ) const
{
return new HandleP2( newOwner );
}
///
/// Draw HandleP2
///
void HandleP2::draw( QPainter* painter, double scale ) const
{
drawAt( painter, scale, mOwner->w(), mOwner->h(), handleFillColor );
}
///
/// HandleP2 Path
///
QPainterPath HandleP2::path( double scale ) const
{
return pathAt( scale, mOwner->w(), mOwner->h() );
}
} // namespace glabels::model
+336
View File
@@ -0,0 +1,336 @@
/* Handles.h
*
* Copyright (C) 2013 Jim Evins <evins@snaught.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef model_Handles_h
#define model_Handles_h
#include "Distance.h"
#include <QPainter>
#include <QPainterPath>
namespace glabels::model
{
// Forward References
class ModelObject;
///
/// Handle Base Class
///
class Handle
{
////////////////////////////
// Location enumeration
////////////////////////////
public:
enum Location { NW, N, NE, E, SE, S, SW, W, P1, P2 };
////////////////////////////
// Lifecycle Methods
////////////////////////////
protected:
Handle( ModelObject* owner, Location location );
public:
virtual ~Handle();
////////////////////////////
// Duplication
////////////////////////////
virtual Handle* clone( ModelObject* newOwner ) const = 0;
////////////////////////////
// Attribue Methods
////////////////////////////
ModelObject* owner() const;
Location location() const;
////////////////////////////
// Drawing Methods
////////////////////////////
public:
virtual void draw( QPainter* painter, double scale ) const = 0;
virtual QPainterPath path( double scale ) const = 0;
protected:
void drawAt( QPainter* painter,
double scale,
const Distance& x,
const Distance& y,
QColor color ) const;
QPainterPath pathAt( double scale,
const Distance& x,
const Distance& y ) const;
////////////////////////////
// Protected Data
////////////////////////////
protected:
ModelObject* mOwner;
Location mLocation;
};
///
/// HandleNorth Class
///
class HandleNorth : public Handle
{
////////////////////////////
// Lifecycle Methods
////////////////////////////
public:
HandleNorth( ModelObject* owner );
~HandleNorth() override;
HandleNorth* clone( ModelObject* newOwner ) const override;
////////////////////////////
// Drawing Methods
////////////////////////////
public:
void draw( QPainter* painter, double scale ) const override;
QPainterPath path( double scale ) const override;
};
///
/// HandleNorthEast Class
///
class HandleNorthEast : public Handle
{
////////////////////////////
// Lifecycle Methods
////////////////////////////
public:
HandleNorthEast( ModelObject* owner );
~HandleNorthEast() override;
HandleNorthEast* clone( ModelObject* newOwner ) const override;
////////////////////////////
// Drawing Methods
////////////////////////////
public:
void draw( QPainter* painter, double scale ) const override;
QPainterPath path( double scale ) const override;
};
///
/// HandleEast Class
///
class HandleEast : public Handle
{
////////////////////////////
// Lifecycle Methods
////////////////////////////
public:
HandleEast( ModelObject* owner );
~HandleEast() override;
HandleEast* clone( ModelObject* newOwner ) const override;
////////////////////////////
// Drawing Methods
////////////////////////////
public:
void draw( QPainter* painter, double scale ) const override;
QPainterPath path( double scale ) const override;
};
///
/// HandleSouthEast Class
///
class HandleSouthEast : public Handle
{
////////////////////////////
// Lifecycle Methods
////////////////////////////
public:
HandleSouthEast( ModelObject* owner );
~HandleSouthEast() override;
HandleSouthEast* clone( ModelObject* newOwner ) const override;
////////////////////////////
// Drawing Methods
////////////////////////////
public:
void draw( QPainter* painter, double scale ) const override;
QPainterPath path( double scale ) const override;
};
///
/// HandleSouth Class
///
class HandleSouth : public Handle
{
////////////////////////////
// Lifecycle Methods
////////////////////////////
public:
HandleSouth( ModelObject* owner );
~HandleSouth() override;
HandleSouth* clone( ModelObject* newOwner ) const override;
////////////////////////////
// Drawing Methods
////////////////////////////
public:
void draw( QPainter* painter, double scale ) const override;
QPainterPath path( double scale ) const override;
};
///
/// HandleSouthWest Class
///
class HandleSouthWest : public Handle
{
////////////////////////////
// Lifecycle Methods
////////////////////////////
public:
HandleSouthWest( ModelObject* owner );
~HandleSouthWest() override;
HandleSouthWest* clone( ModelObject* newOwner ) const override;
////////////////////////////
// Drawing Methods
////////////////////////////
public:
void draw( QPainter* painter, double scale ) const override;
QPainterPath path( double scale ) const override;
};
///
/// HandleWest Class
///
class HandleWest : public Handle
{
////////////////////////////
// Lifecycle Methods
////////////////////////////
public:
HandleWest( ModelObject* owner );
~HandleWest() override;
HandleWest* clone( ModelObject* newOwner ) const override;
////////////////////////////
// Drawing Methods
////////////////////////////
public:
void draw( QPainter* painter, double scale ) const override;
QPainterPath path( double scale ) const override;
};
///
/// HandleNorthWest Class
///
class HandleNorthWest : public Handle
{
////////////////////////////
// Lifecycle Methods
////////////////////////////
public:
HandleNorthWest( ModelObject* owner );
~HandleNorthWest() override;
HandleNorthWest* clone( ModelObject* newOwner ) const override;
////////////////////////////
// Drawing Methods
////////////////////////////
public:
void draw( QPainter* painter, double scale ) const override;
QPainterPath path( double scale ) const override;
};
///
/// HandleP1 Class
///
class HandleP1 : public Handle
{
////////////////////////////
// Lifecycle Methods
////////////////////////////
public:
HandleP1( ModelObject* owner );
~HandleP1() override;
HandleP1* clone( ModelObject* newOwner ) const override;
////////////////////////////
// Drawing Methods
////////////////////////////
public:
void draw( QPainter* painter, double scale ) const override;
QPainterPath path( double scale ) const override;
};
///
/// HandleP2 Class
///
class HandleP2 : public Handle
{
////////////////////////////
// Lifecycle Methods
////////////////////////////
public:
HandleP2( ModelObject* owner );
~HandleP2() override;
////////////////////////////
// Duplication
////////////////////////////
HandleP2* clone( ModelObject* newOwner ) const override;
////////////////////////////
// Drawing Methods
////////////////////////////
public:
void draw( QPainter* painter, double scale ) const override;
QPainterPath path( double scale ) const override;
};
}
#endif // model_Handles_h
+104
View File
@@ -0,0 +1,104 @@
/* Layout.cpp
*
* Copyright (C) 2013-2016 Jim Evins <evins@snaught.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "Layout.h"
#include "Constants.h"
#include <cmath>
namespace glabels::model
{
Layout::Layout( int nx,
int ny,
const Distance& x0,
const Distance& y0,
const Distance& dx,
const Distance& dy )
: mNx(nx), mNy(ny), mX0(x0), mY0(y0), mDx(dx), mDy(dy)
{
// empty
}
Layout::Layout( const Layout& other )
: mNx(other.mNx), mNy(other.mNy), mX0(other.mX0), mY0(other.mY0),
mDx(other.mDx), mDy(other.mDy)
{
// empty
}
int Layout::nx() const
{
return mNx;
}
int Layout::ny() const
{
return mNy;
}
Distance Layout::x0() const
{
return mX0;
}
Distance Layout::y0() const
{
return mY0;
}
Distance Layout::dx() const
{
return mDx;
}
Distance Layout::dy() const
{
return mDy;
}
bool Layout::isSimilarTo( const Layout *other )
{
return ( (mNx == other->mNx) &&
(mNy == other->mNy) &&
(fabs(mX0 - other->mX0) < EPSILON) &&
(fabs(mY0 - other->mY0) < EPSILON) &&
(fabs(mDx - other->mDx) < EPSILON) &&
(fabs(mDy - other->mDy) < EPSILON) );
}
Layout* Layout::dup() const
{
Layout *other = new Layout( *this );
return other;
}
} // namespace glabels::model
+71
View File
@@ -0,0 +1,71 @@
/* Layout.h
*
* Copyright (C) 2013-2016 Jim Evins <evins@snaught.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef model_Layout_h
#define model_Layout_h
#include "Distance.h"
namespace glabels::model
{
class Layout
{
public:
Layout( int nx,
int ny,
const Distance& x0,
const Distance& y0,
const Distance& dx,
const Distance& dy );
Layout( const Layout &other );
int nx() const;
int ny() const;
Distance x0() const;
Distance y0() const;
Distance dx() const;
Distance dy() const;
bool isSimilarTo( const Layout *other );
Layout* dup() const;
private:
int mNx;
int mNy;
Distance mX0;
Distance mY0;
Distance mDx;
Distance mDy;
};
}
#endif // model_Layout_h
+212
View File
@@ -0,0 +1,212 @@
/* Markup.cpp
*
* Copyright (C) 2013-2016 Jim Evins <evins@snaught.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "Markup.h"
namespace glabels::model
{
const QPainterPath& Markup::path() const
{
return mPath;
}
MarkupMargin::MarkupMargin( const Frame* frame,
const Distance& size )
: mFrame(frame), mSize(size)
{
mPath = frame->marginPath( size );
}
Markup* MarkupMargin::dup() const
{
return new MarkupMargin( mFrame, mSize );
}
Distance MarkupMargin::size() const
{
return mSize;
}
MarkupLine::MarkupLine( const Distance& x1,
const Distance& y1,
const Distance& x2,
const Distance& y2 )
: mX1(x1), mY1(y1), mX2(x2), mY2(y2)
{
mPath.moveTo( x1.pt(), y1.pt() );
mPath.lineTo( x2.pt(), y2.pt() );
}
Markup* MarkupLine::dup() const
{
return new MarkupLine( mX1, mY1, mX2, mY2 );
}
Distance MarkupLine::x1() const
{
return mX1;
}
Distance MarkupLine::y1() const
{
return mY1;
}
Distance MarkupLine::x2() const
{
return mX2;
}
Distance MarkupLine::y2() const
{
return mY2;
}
MarkupRect::MarkupRect( const Distance& x1,
const Distance& y1,
const Distance& w,
const Distance& h,
const Distance& r )
: mX1(x1), mY1(y1), mW(w), mH(h), mR(r)
{
mPath.addRoundedRect( x1.pt(), y1.pt(), w.pt(), h.pt(), r.pt(), r.pt() );
}
Markup* MarkupRect::dup() const
{
return new MarkupRect( mX1, mY1, mW, mH, mR );
}
Distance MarkupRect::x1() const
{
return mX1;
}
Distance MarkupRect::y1() const
{
return mY1;
}
Distance MarkupRect::w() const
{
return mW;
}
Distance MarkupRect::h() const
{
return mH;
}
Distance MarkupRect::r() const
{
return mR;
}
MarkupEllipse::MarkupEllipse( const Distance& x1,
const Distance& y1,
const Distance& w,
const Distance& h )
: mX1(x1), mY1(y1), mW(w), mH(h)
{
mPath.addEllipse( x1.pt(), y1.pt(), w.pt(), h.pt() );
}
Markup* MarkupEllipse::dup() const
{
return new MarkupEllipse( mX1, mY1, mW, mH );
}
Distance MarkupEllipse::x1() const
{
return mX1;
}
Distance MarkupEllipse::y1() const
{
return mY1;
}
Distance MarkupEllipse::w() const
{
return mW;
}
Distance MarkupEllipse::h() const
{
return mH;
}
MarkupCircle::MarkupCircle( const Distance& x0,
const Distance& y0,
const Distance& r )
: mX0(x0), mY0(y0), mR(r)
{
mPath.addEllipse( (x0-r).pt(), (y0-r).pt(), 2*r.pt(), 2*r.pt() );
}
Markup* MarkupCircle::dup() const
{
return new MarkupCircle( mX0, mY0, mR );
}
Distance MarkupCircle::x0() const
{
return mX0;
}
Distance MarkupCircle::y0() const
{
return mY0;
}
Distance MarkupCircle::r() const
{
return mR;
}
} // namespace glabels::model
+156
View File
@@ -0,0 +1,156 @@
/* Markup.h
*
* Copyright (C) 2013-2016 Jim Evins <evins@snaught.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef model_Markup_h
#define model_Markup_h
#include "Frame.h"
#include <QPainterPath>
namespace glabels::model
{
class Markup
{
public:
virtual Markup* dup() const = 0;
const QPainterPath& path() const;
protected:
QPainterPath mPath;
};
class MarkupMargin : public Markup
{
public:
MarkupMargin( const Frame* frame,
const Distance& size );
Distance size() const;
Markup* dup() const override;
private:
const Frame* mFrame;
Distance mSize;
};
class MarkupLine : public Markup
{
public:
MarkupLine( const Distance& x1,
const Distance& y1,
const Distance& x2,
const Distance& y2 );
Distance x1() const;
Distance y1() const;
Distance x2() const;
Distance y2() const;
Markup* dup() const override;
private:
Distance mX1;
Distance mY1;
Distance mX2;
Distance mY2;
};
class MarkupRect : public Markup
{
public:
MarkupRect( const Distance& x1,
const Distance& y1,
const Distance& w,
const Distance& h,
const Distance& r );
Distance x1() const;
Distance y1() const;
Distance w() const;
Distance h() const;
Distance r() const;
Markup* dup() const override;
private:
Distance mX1;
Distance mY1;
Distance mW;
Distance mH;
Distance mR;
};
class MarkupEllipse : public Markup
{
public:
MarkupEllipse( const Distance& x1,
const Distance& y1,
const Distance& w,
const Distance& h );
Distance x1() const;
Distance y1() const;
Distance w() const;
Distance h() const;
Markup* dup() const override;
private:
Distance mX1;
Distance mY1;
Distance mW;
Distance mH;
};
class MarkupCircle : public Markup
{
public:
MarkupCircle( const Distance& x0,
const Distance& y0,
const Distance& r );
Distance x0() const;
Distance y0() const;
Distance r() const;
Markup* dup() const override;
private:
Distance mX0;
Distance mY0;
Distance mR;
};
}
#endif // model_Markup_h
+1444
View File
File diff suppressed because it is too large Load Diff
+239
View File
@@ -0,0 +1,239 @@
/* Model.h
*
* Copyright (C) 2013-2016 Jim Evins <evins@snaught.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef model_Model_h
#define model_Model_h
#include "Settings.h"
#include "Template.h"
#include "merge/Merge.h"
#include "merge/Record.h"
#include <QList>
#include <QObject>
#include <QPainter>
namespace glabels::model
{
// Forward References
class ColorNode;
class Handle;
class ModelObject;
class Region;
///
/// Model
///
class Model : public QObject
{
Q_OBJECT
/////////////////////////////////
// Lifecycle
/////////////////////////////////
public:
Model();
~Model() override {}
/////////////////////////////////
// Save/restore model state
/////////////////////////////////
Model* save() const;
void restore( const Model *savedModel );
/////////////////////////////////
// Signals
/////////////////////////////////
signals:
void changed();
void nameChanged();
void sizeChanged();
void selectionChanged();
void modifiedChanged();
void mergeChanged();
void mergeSourceChanged();
void mergeSelectionChanged();
/////////////////////////////////
// Properties
/////////////////////////////////
public:
bool isModified() const;
void setModified();
void clearModified();
QString shortName();
const QString& fileName() const;
void setFileName( const QString &fileName );
int compressionLevel() const;
void setCompressionLevel( int compressionLevel );
const Template* tmplate() const;
const Frame* frame() const;
void setTmplate( const Template* tmplate );
bool rotate() const;
void setRotate( bool rotate );
Distance w() const;
Distance h() const;
const QList<ModelObject*>& objectList() const;
merge::Merge* merge() const;
void setMerge( merge::Merge* merge );
/////////////////////////////////
// Manage objects
/////////////////////////////////
public:
void addObject( ModelObject* object );
void deleteObject( ModelObject* object );
ModelObject* objectAt( double scale,
const Distance& x,
const Distance& y ) const;
Handle* handleAt( double scale,
const Distance& x,
const Distance& y ) const;
/////////////////////////////////
// Manipulate selection
/////////////////////////////////
public:
void selectObject( ModelObject* object );
void unselectObject( ModelObject* object );
void selectAll();
void unselectAll();
void selectRegion( const Region& region );
bool isSelectionEmpty();
bool isSelectionAtomic();
/////////////////////////////////
// Get selected objects
/////////////////////////////////
public:
QList<ModelObject*> getSelection();
ModelObject* getFirstSelectedObject();
/////////////////////////////////
// Query selection capabilities
/////////////////////////////////
public:
bool canSelectionText();
bool canSelectionFill();
bool canSelectionLineColor();
bool canSelectionLineWidth();
/////////////////////////////////
// Operations on selections
/////////////////////////////////
public:
void deleteSelection();
void raiseSelectionToTop();
void lowerSelectionToBottom();
void rotateSelection( double thetaDegs );
void rotateSelectionLeft();
void rotateSelectionRight();
void flipSelectionHoriz();
void flipSelectionVert();
void alignSelectionLeft();
void alignSelectionRight();
void alignSelectionHCenter();
void alignSelectionTop();
void alignSelectionBottom();
void alignSelectionVCenter();
void centerSelectionHoriz();
void centerSelectionVert();
void moveSelection( const Distance& dx, const Distance& dy );
void setSelectionFontFamily( const QString& fontFamily );
void setSelectionFontSize( double fontSize );
void setSelectionFontWeight( QFont::Weight fontWeight );
void setSelectionFontItalicFlag( bool fontItalicFlag );
void setSelectionTextHAlign( Qt::Alignment textHAlign );
void setSelectionTextVAlign( Qt::Alignment textVAlign );
void setSelectionTextLineSpacing( double textLineSpacing );
void setSelectionTextColorNode( ColorNode textColorNode );
void setSelectionLineWidth( const Distance& lineWidth );
void setSelectionLineColorNode( ColorNode lineColorNode );
void setSelectionFillColorNode( ColorNode fillColorNode );
/////////////////////////////////
// Clipboard operations
/////////////////////////////////
void copySelection();
void cutSelection();
bool canPaste();
void paste();
/////////////////////////////////
// Drawing operations
/////////////////////////////////
public:
void draw( QPainter* painter, bool inEditor = true, merge::Record* record = nullptr ) const;
/////////////////////////////////
// Slots
/////////////////////////////////
private slots:
void onObjectChanged();
void onObjectMoved();
void onMergeSourceChanged();
void onMergeSelectionChanged();
/////////////////////////////////
// Private data
/////////////////////////////////
private:
int mUntitledInstance;
bool mModified;
QString mFileName;
int mCompressionLevel;
const Template* mTmplate;
const Frame* mFrame;
bool mRotate;
QList<ModelObject*> mObjectList;
merge::Merge* mMerge;
};
}
#endif // model_Model_h
+531
View File
@@ -0,0 +1,531 @@
/* ModelBarcodeObject.cpp
*
* Copyright (C) 2017 Jim Evins <evins@snaught.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "ModelBarcodeObject.h"
#include "Size.h"
#include "barcode/Backends.h"
#include "glbarcode/Factory.h"
#include "glbarcode/QtRenderer.h"
#include <QBrush>
#include <QPen>
#include <QTextDocument>
#include <QTextBlock>
#include <QRegularExpression>
#include <QtDebug>
namespace glabels::model
{
//
// Private
//
namespace
{
const QColor fillColor = QColor( 224, 224, 224, 255 );
const Distance pad = Distance::pt(4);
const Distance minW = Distance::pt(18);
const Distance minH = Distance::pt(18);
}
///
/// Constructor
///
ModelBarcodeObject::ModelBarcodeObject()
{
mOutline = new Outline( this );
mHandles << new HandleNorthWest( this );
mHandles << new HandleNorth( this );
mHandles << new HandleNorthEast( this );
mHandles << new HandleEast( this );
mHandles << new HandleSouthEast( this );
mHandles << new HandleSouth( this );
mHandles << new HandleSouthWest( this );
mHandles << new HandleWest( this );
mBcStyle = barcode::Backends::defaultStyle();
mBcTextFlag = mBcStyle.canText();
mBcChecksumFlag = mBcStyle.canChecksum();
mBcFormatDigits = mBcStyle.preferedN();
mBcData = "";
mBcColorNode = ColorNode( Qt::black );
mEditorBarcode = nullptr;
mEditorDefaultBarcode = nullptr;
update(); // Initialize cached editor layouts
}
///
/// Constructor
///
ModelBarcodeObject::ModelBarcodeObject( const Distance& x0,
const Distance& y0,
const Distance& w,
const Distance& h,
const barcode::Style& bcStyle,
bool bcTextFlag,
bool bcChecksumFlag,
QString bcData,
const ColorNode& bcColorNode,
const QMatrix& matrix )
: ModelObject( x0, y0, w, h, matrix )
{
mOutline = new Outline( this );
mHandles << new HandleNorthWest( this );
mHandles << new HandleNorth( this );
mHandles << new HandleNorthEast( this );
mHandles << new HandleEast( this );
mHandles << new HandleSouthEast( this );
mHandles << new HandleSouth( this );
mHandles << new HandleSouthWest( this );
mHandles << new HandleWest( this );
mBcStyle = bcStyle;
mBcTextFlag = bcTextFlag;
mBcChecksumFlag = bcChecksumFlag;
mBcData = bcData;
mBcColorNode = bcColorNode;
mEditorBarcode = nullptr;
mEditorDefaultBarcode = nullptr;
update(); // Initialize cached editor layouts
}
///
/// Copy constructor
///
ModelBarcodeObject::ModelBarcodeObject( const ModelBarcodeObject* object )
: ModelObject(object)
{
mBcStyle = object->mBcStyle;
mBcTextFlag = object->mBcTextFlag;
mBcChecksumFlag = object->mBcChecksumFlag;
mBcFormatDigits = object->mBcFormatDigits;
mBcData = object->mBcData;
mBcColorNode = object->mBcColorNode;
mEditorBarcode = nullptr;
mEditorDefaultBarcode = nullptr;
update(); // Initialize cached editor layouts
}
///
/// Destructor
///
ModelBarcodeObject::~ModelBarcodeObject()
{
delete mOutline;
foreach( Handle* handle, mHandles )
{
delete handle;
}
mHandles.clear();
delete mEditorBarcode;
}
///
/// Clone
///
ModelBarcodeObject* ModelBarcodeObject::clone() const
{
return new ModelBarcodeObject( this );
}
///
/// bcData Property Getter
///
QString ModelBarcodeObject::bcData() const
{
return mBcData.toString();
}
///
/// bcData Property Setter
///
void ModelBarcodeObject::setBcData( const QString& value )
{
if ( mBcData.toString() != value )
{
mBcData = value;
update();
emit changed();
}
}
///
/// bcTextFlag Property Getter
///
bool ModelBarcodeObject::bcTextFlag() const
{
return mBcTextFlag;
}
///
/// bcTextFlag Property Setter
///
void ModelBarcodeObject::setBcTextFlag( bool value )
{
if ( mBcTextFlag != value )
{
mBcTextFlag = value;
update();
emit changed();
}
}
///
/// bcChecksumFlag Property Getter
///
bool ModelBarcodeObject::bcChecksumFlag() const
{
return mBcChecksumFlag;
}
///
/// bcChecksumFlag Property Setter
///
void ModelBarcodeObject::setBcChecksumFlag( bool value )
{
if ( mBcChecksumFlag != value )
{
mBcChecksumFlag = value;
update();
emit changed();
}
}
///
/// Barcode Color Node Property Getter
///
ColorNode ModelBarcodeObject::bcColorNode() const
{
return mBcColorNode;
}
///
/// Barcode Color Node Property Setter
///
void ModelBarcodeObject::setBcColorNode( const ColorNode& value )
{
if ( mBcColorNode != value )
{
mBcColorNode = value;
update();
emit changed();
}
}
///
/// Barcode Style Property Getter
///
barcode::Style ModelBarcodeObject::bcStyle() const
{
return mBcStyle;
}
///
/// Barcode Style Property Setter
///
void ModelBarcodeObject::setBcStyle( const barcode::Style& value )
{
if ( mBcStyle != value )
{
mBcStyle = value;
update();
emit changed();
}
}
///
/// Barcode Format Digits Property Getter
///
int ModelBarcodeObject::bcFormatDigits() const
{
return mBcFormatDigits;
}
///
/// Barcode Format Digits Property Setter
///
void ModelBarcodeObject::setBcFormatDigits( int value )
{
if ( mBcFormatDigits != value )
{
mBcFormatDigits = value;
update();
emit changed();
}
}
///
/// Draw shadow of object
///
void ModelBarcodeObject::drawShadow( QPainter* painter,
bool inEditor,
merge::Record* record ) const
{
// Barcodes don't support shadows.
}
///
/// Draw object itself
///
void ModelBarcodeObject::drawObject( QPainter* painter,
bool inEditor,
merge::Record* record ) const
{
QColor bcColor = mBcColorNode.color( record );
if ( inEditor )
{
drawBcInEditor( painter, bcColor );
}
else
{
drawBc( painter, bcColor, record );
}
}
///
/// Path to test for hover condition
///
QPainterPath ModelBarcodeObject::hoverPath( double scale ) const
{
return mHoverPath;
}
///
/// Size updated
///
void ModelBarcodeObject::sizeUpdated()
{
update();
}
///
/// Update cached information for editor view
///
void ModelBarcodeObject::update()
{
//
// Build barcode from data
//
if ( mEditorBarcode )
{
delete mEditorBarcode;
}
mEditorBarcode = glbarcode::Factory::createBarcode( mBcStyle.fullId().toStdString() );
if ( !mEditorBarcode )
{
qWarning() << "Invalid barcode style" << mBcStyle.fullId() << "using \"code39\".";
mBcStyle = barcode::Backends::defaultStyle();
mEditorBarcode = glbarcode::Factory::createBarcode( mBcStyle.id().toStdString() );
}
mEditorBarcode->setChecksum(mBcChecksumFlag);
mEditorBarcode->setShowText(mBcTextFlag);
mEditorBarcode->build( mBcData.toStdString(), mW.pt(), mH.pt() );
//
// Build a place holder barcode to display in editor, if cannot display actual barcode
//
if ( mEditorDefaultBarcode )
{
delete mEditorDefaultBarcode;
}
mEditorDefaultBarcode = glbarcode::Factory::createBarcode( mBcStyle.fullId().toStdString() );
if ( !mEditorDefaultBarcode )
{
qWarning() << "Invalid barcode style" << mBcStyle.fullId() << "using \"code39\".";
mBcStyle = barcode::Backends::defaultStyle();
mEditorDefaultBarcode = glbarcode::Factory::createBarcode( mBcStyle.id().toStdString() );
}
mEditorDefaultBarcode->setChecksum(mBcChecksumFlag);
mEditorDefaultBarcode->setShowText(mBcTextFlag);
mEditorDefaultBarcode->build( mBcStyle.defaultDigits().toStdString(), mW.pt(), mH.pt() );
//
// Adjust size
//
if ( mEditorBarcode->isDataValid() )
{
mW = Distance::pt( mEditorBarcode->width() );
mH = Distance::pt( mEditorBarcode->height() );
}
else
{
mW = Distance::pt( mEditorDefaultBarcode->width() );
mH = Distance::pt( mEditorDefaultBarcode->height() );
}
QPainterPath path;
path.addRect( 0, 0, mW.pt(), mH.pt() );
mHoverPath = path;
}
///
/// Draw barcode in editor from cached information
///
void ModelBarcodeObject::drawBcInEditor( QPainter* painter, const QColor& color ) const
{
if ( mBcData.isEmpty() )
{
drawPlaceHolder( painter, color, tr("No barcode data") );
}
else if ( mBcData.hasPlaceHolders() )
{
drawPlaceHolder( painter, color, mBcData.toString() );
}
else if ( mEditorBarcode->isDataValid() )
{
painter->setPen( QPen( color ) );
glbarcode::QtRenderer renderer(painter);
mEditorBarcode->render( renderer );
}
else
{
drawPlaceHolder( painter, color, tr("Invalid barcode data") );
}
}
///
/// Draw barcode in final printout or preview
///
void
ModelBarcodeObject::drawBc( QPainter* painter,
const QColor& color,
merge::Record* record ) const
{
painter->setPen( QPen( color ) );
glbarcode::Barcode* bc = glbarcode::Factory::createBarcode( mBcStyle.fullId().toStdString() );
bc->setChecksum(mBcChecksumFlag);
bc->setShowText(mBcTextFlag);
bc->build( mBcData.toStdString(), mW.pt(), mH.pt() );
glbarcode::QtRenderer renderer(painter);
bc->render( renderer );
}
///
/// Draw barcode place holder in editor
///
void
ModelBarcodeObject::drawPlaceHolder( QPainter* painter,
const QColor& color,
const QString& text ) const
{
QString shortText = text.left( 32 ); // Don't let the text get out of hand
//
// Render box
//
painter->setPen( Qt::NoPen );
painter->setBrush( QBrush( fillColor ) );
painter->drawRect( QRectF( 0, 0, mW.pt(), mH.pt() ) );
//
// Render default barcode
//
painter->setPen( QPen( color ) );
glbarcode::QtRenderer renderer(painter);
mEditorDefaultBarcode->render( renderer );
//
// Determine font size for text
//
QFont font( "Sans" );
font.setPointSizeF( 6 );
QFontMetricsF fm( font );
QRectF textRect = fm.boundingRect( shortText );
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( shortText );
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( color ) );
painter->drawText( QRectF( 0, 0, mW.pt(), mH.pt() ), Qt::AlignCenter, shortText );
}
} // namespace glabels::model
+166
View File
@@ -0,0 +1,166 @@
/* ModelBarcodeObject.h
*
* Copyright (C) 2017 Jim Evins <evins@snaught.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef model_ModelBarcodeObject_h
#define model_ModelBarcodeObject_h
#include "ModelObject.h"
#include "RawText.h"
#include "glbarcode/Barcode.h"
namespace glabels::model
{
///
/// Label Model Line Object
///
class ModelBarcodeObject : public ModelObject
{
Q_OBJECT
///////////////////////////////////////////////////////////////
// Lifecycle Methods
///////////////////////////////////////////////////////////////
public:
ModelBarcodeObject();
ModelBarcodeObject( const Distance& x0,
const Distance& y0,
const Distance& w,
const Distance& h,
const barcode::Style& bcStyle,
bool bcTextFlag,
bool bcChecksumFlag,
QString bcData,
const ColorNode& bcColorNode,
const QMatrix& matrix = QMatrix() );
ModelBarcodeObject( const ModelBarcodeObject* object );
~ModelBarcodeObject() override;
///////////////////////////////////////////////////////////////
// Object duplication
///////////////////////////////////////////////////////////////
ModelBarcodeObject* clone() const override;
///////////////////////////////////////////////////////////////
// Property Implementations
///////////////////////////////////////////////////////////////
public:
//
// Barcode Property: bcData
//
QString bcData() const override;
void setBcData( const QString &value ) override;
//
// Barcode Property: bcTextFlag
//
bool bcTextFlag() const override;
void setBcTextFlag( bool value ) override;
//
// Barcode Property: bcChecksumFlag
//
bool bcChecksumFlag() const override;
void setBcChecksumFlag( bool value ) override;
//
// Barcode Property: bcColorNode
//
ColorNode bcColorNode() const override;
void setBcColorNode( const ColorNode &value ) override;
//
// Barcode Property: bcStyle
//
barcode::Style bcStyle() const override;
void setBcStyle( const barcode::Style &value ) override;
//
// Barcode Property: bcFormatDigits
//
int bcFormatDigits() const override;
void setBcFormatDigits( int value ) override;
///////////////////////////////////////////////////////////////
// Capability Implementations
///////////////////////////////////////////////////////////////
public:
///////////////////////////////////////////////////////////////
// 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;
QPainterPath hoverPath( double scale ) const override;
///////////////////////////////////////////////////////////////
// Private methods
///////////////////////////////////////////////////////////////
private:
void sizeUpdated() override;
void update();
void drawBcInEditor( QPainter* painter, const QColor& color ) const;
void drawBc( QPainter* painter, const QColor& color, merge::Record* record ) const;
void drawPlaceHolder( QPainter* painter, const QColor& color, const QString& text ) const;
///////////////////////////////////////////////////////////////
// Private Members
///////////////////////////////////////////////////////////////
private:
barcode::Style mBcStyle;
bool mBcTextFlag;
bool mBcChecksumFlag;
int mBcFormatDigits;
RawText mBcData;
ColorNode mBcColorNode;
glbarcode::Barcode* mEditorBarcode;
glbarcode::Barcode* mEditorDefaultBarcode;
QPainterPath mHoverPath;
};
}
#endif // model_ModelBarcodeObject_h
+194
View File
@@ -0,0 +1,194 @@
/* ModelBoxObject.cpp
*
* Copyright (C) 2013-2016 Jim Evins <evins@snaught.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "ModelBoxObject.h"
#include <QBrush>
#include <QPen>
namespace glabels::model
{
//
// Private
//
namespace
{
const double slopPixels = 2;
}
///
/// Constructor
///
ModelBoxObject::ModelBoxObject()
{
// empty
}
///
/// Constructor
///
ModelBoxObject::ModelBoxObject( const Distance& x0,
const Distance& y0,
const Distance& w,
const Distance& h,
const Distance& lineWidth,
const ColorNode& lineColorNode,
const ColorNode& fillColorNode,
const QMatrix& matrix,
bool shadowState,
const Distance& shadowX,
const Distance& shadowY,
double shadowOpacity,
const ColorNode& shadowColorNode )
: ModelShapeObject( x0, y0, w, h,
lineWidth, lineColorNode, fillColorNode,
matrix,
shadowState, shadowX, shadowY, shadowOpacity, shadowColorNode )
{
// empty
}
///
/// Copy constructor
///
ModelBoxObject::ModelBoxObject( const ModelBoxObject* object )
: ModelShapeObject( object )
{
// empty
}
///
/// Destructor
///
ModelBoxObject::~ModelBoxObject()
{
// empty
}
///
/// Clone
///
ModelBoxObject* ModelBoxObject::clone() const
{
return new ModelBoxObject( this );
}
///
/// Draw shadow of object
///
void ModelBoxObject::drawShadow( QPainter* painter, bool inEditor, merge::Record* record ) const
{
QColor lineColor = mLineColorNode.color( record );
QColor fillColor = mFillColorNode.color( record );
QColor shadowColor = mShadowColorNode.color( record );
shadowColor.setAlphaF( mShadowOpacity );
if ( fillColor.alpha() )
{
painter->setPen( Qt::NoPen );
painter->setBrush( shadowColor );
if ( lineColor.alpha() )
{
/* Has FILL and OUTLINE: adjust size to account for line width. */
painter->drawRect( QRectF( -mLineWidth.pt()/2,
-mLineWidth.pt()/2,
(mW + mLineWidth).pt(),
(mH + mLineWidth).pt() ) );
}
else
{
/* Has FILL, but no OUTLINE. */
painter->drawRect( QRectF( 0, 0, mW.pt(), mH.pt() ) );
}
}
else
{
if ( lineColor.alpha() )
{
/* Has only OUTLINE. */
painter->setPen( QPen( shadowColor, mLineWidth.pt() ) );
painter->setBrush( Qt::NoBrush );
painter->drawRect( QRectF( 0, 0, mW.pt(), mH.pt() ) );
}
}
}
///
/// Draw object itself
///
void ModelBoxObject::drawObject( QPainter* painter, bool inEditor, merge::Record* record ) const
{
QColor lineColor = mLineColorNode.color( record );
QColor fillColor = mFillColorNode.color( record );
painter->setPen( QPen( lineColor, mLineWidth.pt() ) );
painter->setBrush( fillColor );
painter->drawRect( QRectF( 0, 0, mW.pt(), mH.pt() ) );
}
///
/// Path to test for hover condition
///
QPainterPath ModelBoxObject::hoverPath( double scale ) const
{
double s = 1 / scale;
QPainterPath path;
if ( mFillColorNode.color().alpha() && mLineColorNode.color().alpha() )
{
path.addRect( -mLineWidth.pt()/2, -mLineWidth.pt()/2, (mW+mLineWidth).pt(), (mH+mLineWidth).pt() );
}
else if ( mFillColorNode.color().alpha() && !(mLineColorNode.color().alpha()) )
{
path.addRect( 0, 0, mW.pt(), mH.pt() );
}
else if ( mLineColorNode.color().alpha() )
{
path.addRect( (-mLineWidth.pt()/2) - s*slopPixels,
(-mLineWidth.pt()/2) - s*slopPixels,
(mW + mLineWidth).pt() + s*2*slopPixels,
(mH + mLineWidth).pt() + s*2*slopPixels );
path.closeSubpath();
path.addRect( mLineWidth.pt()/2 + s*slopPixels,
mLineWidth.pt()/2 + s*slopPixels,
(mW - mLineWidth).pt() - s*2*slopPixels,
(mH - mLineWidth).pt() - s*2*slopPixels );
}
return path;
}
} // namespace glabels::model
+82
View File
@@ -0,0 +1,82 @@
/* ModelBoxObject.h
*
* Copyright (C) 2013-2016 Jim Evins <evins@snaught.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef model_ModelBoxObject_h
#define model_ModelBoxObject_h
#include "ModelShapeObject.h"
namespace glabels::model
{
///
/// Label Model Box Object
///
class ModelBoxObject : public ModelShapeObject
{
Q_OBJECT
///////////////////////////////////////////////////////////////
// Lifecycle Methods
///////////////////////////////////////////////////////////////
public:
ModelBoxObject();
ModelBoxObject( const Distance& x0,
const Distance& y0,
const Distance& w,
const Distance& h,
const Distance& lineWidth,
const ColorNode& lineColorNode,
const ColorNode& fillColorNode,
const QMatrix& matrix = QMatrix(),
bool shadowState = false,
const Distance& shadowX = 0,
const Distance& shadowY = 0,
double shadowOpacity = 1.0,
const ColorNode& shadowColorNode = ColorNode() );
ModelBoxObject( const ModelBoxObject* object );
~ModelBoxObject() override;
///////////////////////////////////////////////////////////////
// Object duplication
///////////////////////////////////////////////////////////////
ModelBoxObject* clone() const override;
///////////////////////////////////////////////////////////////
// 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;
QPainterPath hoverPath( double scale ) const override;
};
}
#endif // model_ModelBoxObject_h
+194
View File
@@ -0,0 +1,194 @@
/* ModelEllipseObject.cpp
*
* Copyright (C) 2013-2016 Jim Evins <evins@snaught.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "ModelEllipseObject.h"
#include <QBrush>
#include <QPen>
namespace glabels::model
{
//
// Private
//
namespace
{
const double slopPixels = 2;
}
///
/// Constructor
///
ModelEllipseObject::ModelEllipseObject()
{
// empty
}
///
/// Constructor
///
ModelEllipseObject::ModelEllipseObject( const Distance& x0,
const Distance& y0,
const Distance& w,
const Distance& h,
const Distance& lineWidth,
const ColorNode& lineColorNode,
const ColorNode& fillColorNode,
const QMatrix& matrix,
bool shadowState,
const Distance& shadowX,
const Distance& shadowY,
double shadowOpacity,
const ColorNode& shadowColorNode )
: ModelShapeObject( x0, y0, w, h,
lineWidth, lineColorNode, fillColorNode,
matrix,
shadowState, shadowX, shadowY, shadowOpacity, shadowColorNode )
{
// empty
}
///
/// Copy constructor
///
ModelEllipseObject::ModelEllipseObject( const ModelEllipseObject* object )
: ModelShapeObject( object )
{
// empty
}
///
/// Destructor
///
ModelEllipseObject::~ModelEllipseObject()
{
// empty
}
///
/// Clone
///
ModelEllipseObject* ModelEllipseObject::clone() const
{
return new ModelEllipseObject( this );
}
///
/// Draw shadow of object
///
void ModelEllipseObject::drawShadow( QPainter* painter, bool inEditor, merge::Record* record ) const
{
QColor lineColor = mLineColorNode.color( record );
QColor fillColor = mFillColorNode.color( record );
QColor shadowColor = mShadowColorNode.color( record );
shadowColor.setAlphaF( mShadowOpacity );
if ( fillColor.alpha() )
{
painter->setPen( Qt::NoPen );
painter->setBrush( shadowColor );
if ( lineColor.alpha() )
{
/* Has FILL and OUTLINE: adjust size to account for line width. */
painter->drawEllipse( QRectF( -mLineWidth.pt()/2,
-mLineWidth.pt()/2,
(mW + mLineWidth).pt(),
(mH + mLineWidth).pt() ) );
}
else
{
/* Has FILL, but no OUTLINE. */
painter->drawEllipse( QRectF( 0, 0, mW.pt(), mH.pt() ) );
}
}
else
{
if ( lineColor.alpha() )
{
/* Has only OUTLINE. */
painter->setPen( QPen( shadowColor, mLineWidth.pt() ) );
painter->setBrush( Qt::NoBrush );
painter->drawEllipse( QRectF( 0, 0, mW.pt(), mH.pt() ) );
}
}
}
///
/// Draw object itself
///
void ModelEllipseObject::drawObject( QPainter* painter, bool inEditor, merge::Record* record ) const
{
QColor lineColor = mLineColorNode.color( record );
QColor fillColor = mFillColorNode.color( record );
painter->setPen( QPen( lineColor, mLineWidth.pt() ) );
painter->setBrush( fillColor );
painter->drawEllipse( QRectF( 0, 0, mW.pt(), mH.pt() ) );
}
///
/// Path to test for hover condition
///
QPainterPath ModelEllipseObject::hoverPath( double scale ) const
{
double s = 1 / scale;
QPainterPath path;
if ( mFillColorNode.color().alpha() && mLineColorNode.color().alpha() )
{
path.addEllipse( -mLineWidth.pt()/2, -mLineWidth.pt()/2, (mW+mLineWidth).pt(), (mH+mLineWidth).pt() );
}
else if ( mFillColorNode.color().alpha() && !(mLineColorNode.color().alpha()) )
{
path.addEllipse( 0, 0, mW.pt(), mH.pt() );
}
else if ( mLineColorNode.color().alpha() )
{
path.addEllipse( (-mLineWidth.pt()/2) - s*slopPixels,
(-mLineWidth.pt()/2) - s*slopPixels,
(mW + mLineWidth).pt() + s*2*slopPixels,
(mH + mLineWidth).pt() + s*2*slopPixels );
path.closeSubpath();
path.addEllipse( mLineWidth.pt()/2 + s*slopPixels,
mLineWidth.pt()/2 + s*slopPixels,
(mW - mLineWidth).pt() - s*2*slopPixels,
(mH - mLineWidth).pt() - s*2*slopPixels );
}
return path;
}
} // namespace glabels::model
+82
View File
@@ -0,0 +1,82 @@
/* ModelEllipseObject.h
*
* Copyright (C) 2013-2016 Jim Evins <evins@snaught.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef model_ModelEllipseObject_h
#define model_ModelEllipseObject_h
#include "ModelShapeObject.h"
namespace glabels::model
{
///
/// Label Model Ellipse Object
///
class ModelEllipseObject : public ModelShapeObject
{
Q_OBJECT
///////////////////////////////////////////////////////////////
// Lifecycle Methods
///////////////////////////////////////////////////////////////
public:
ModelEllipseObject();
ModelEllipseObject( const Distance& x0,
const Distance& y0,
const Distance& w,
const Distance& h,
const Distance& lineWidth,
const ColorNode& lineColorNode,
const ColorNode& fillColorNode,
const QMatrix& matrix = QMatrix(),
bool shadowState = false,
const Distance& shadowX = 0,
const Distance& shadowY = 0,
double shadowOpacity = 1.0,
const ColorNode& shadowColorNode = ColorNode() );
ModelEllipseObject( const ModelEllipseObject* object );
~ModelEllipseObject() override;
///////////////////////////////////////////////////////////////
// Object duplication
///////////////////////////////////////////////////////////////
ModelEllipseObject* clone() const override;
///////////////////////////////////////////////////////////////
// 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;
QPainterPath hoverPath( double scale ) const override;
};
}
#endif // model_ModelEllipseObject_h
+566
View File
@@ -0,0 +1,566 @@
/* ModelImageObject.cpp
*
* Copyright (C) 2013-2016 Jim Evins <evins@snaught.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "ModelImageObject.h"
#include "Size.h"
#include <QBrush>
#include <QFileInfo>
#include <QImage>
#include <QPen>
#include <QtDebug>
namespace glabels::model
{
///
/// Static data
///
QImage* ModelImageObject::smDefaultImage = nullptr;
///
/// Constructor
///
ModelImageObject::ModelImageObject() : mImage(nullptr), mSvgRenderer(nullptr)
{
mOutline = new Outline( this );
mHandles << new HandleNorthWest( this );
mHandles << new HandleNorth( this );
mHandles << new HandleNorthEast( this );
mHandles << new HandleEast( this );
mHandles << new HandleSouthEast( this );
mHandles << new HandleSouth( this );
mHandles << new HandleSouthWest( this );
mHandles << new HandleWest( this );
if ( smDefaultImage == nullptr )
{
smDefaultImage = new QImage( ":images/checkerboard.png" );
}
}
///
/// Constructor
///
ModelImageObject::ModelImageObject( const Distance& x0,
const Distance& y0,
const Distance& w,
const Distance& h,
const TextNode& filenameNode,
const QMatrix& matrix,
bool shadowState,
const Distance& shadowX,
const Distance& shadowY,
double shadowOpacity,
const ColorNode& shadowColorNode )
: ModelObject( x0, y0, w, h,
matrix,
shadowState, shadowX, shadowY, shadowOpacity, shadowColorNode )
{
mOutline = new Outline( this );
mHandles << new HandleNorthWest( this );
mHandles << new HandleNorth( this );
mHandles << new HandleNorthEast( this );
mHandles << new HandleEast( this );
mHandles << new HandleSouthEast( this );
mHandles << new HandleSouth( this );
mHandles << new HandleSouthWest( this );
mHandles << new HandleWest( this );
if ( smDefaultImage == nullptr )
{
smDefaultImage = new QImage( ":images/checkerboard.png" );
}
mFilenameNode = filenameNode;
mImage = nullptr;
mSvgRenderer = nullptr;
}
///
/// Constructor
///
ModelImageObject::ModelImageObject( const Distance& x0,
const Distance& y0,
const Distance& w,
const Distance& h,
const QString& filename,
const QImage& image,
const QMatrix& matrix,
bool shadowState,
const Distance& shadowX,
const Distance& shadowY,
double shadowOpacity,
const ColorNode& shadowColorNode )
: ModelObject( x0, y0, w, h,
matrix,
shadowState, shadowX, shadowY, shadowOpacity, shadowColorNode )
{
mOutline = new Outline( this );
mHandles << new HandleNorthWest( this );
mHandles << new HandleNorth( this );
mHandles << new HandleNorthEast( this );
mHandles << new HandleEast( this );
mHandles << new HandleSouthEast( this );
mHandles << new HandleSouth( this );
mHandles << new HandleSouthWest( this );
mHandles << new HandleWest( this );
if ( smDefaultImage == nullptr )
{
smDefaultImage = new QImage( ":images/checkerboard.png" );
}
mImage = new QImage(image);
mFilenameNode = TextNode( false, filename );
mSvgRenderer = nullptr;
}
///
/// Constructor
///
ModelImageObject::ModelImageObject( const Distance& x0,
const Distance& y0,
const Distance& w,
const Distance& h,
const QString& filename,
const QByteArray& svg,
const QMatrix& matrix,
bool shadowState,
const Distance& shadowX,
const Distance& shadowY,
double shadowOpacity,
const ColorNode& shadowColorNode )
: ModelObject( x0, y0, w, h,
matrix,
shadowState, shadowX, shadowY, shadowOpacity, shadowColorNode )
{
mOutline = new Outline( this );
mHandles << new HandleNorthWest( this );
mHandles << new HandleNorth( this );
mHandles << new HandleNorthEast( this );
mHandles << new HandleEast( this );
mHandles << new HandleSouthEast( this );
mHandles << new HandleSouth( this );
mHandles << new HandleSouthWest( this );
mHandles << new HandleWest( this );
if ( smDefaultImage == nullptr )
{
smDefaultImage = new QImage( ":images/checkerboard.png" );
}
mSvg = svg;
mSvgRenderer = new QSvgRenderer( mSvg );
mFilenameNode = TextNode( false, filename );
mImage = nullptr;
}
///
/// Copy constructor
///
ModelImageObject::ModelImageObject( const ModelImageObject* object ) : ModelObject(object)
{
mFilenameNode = object->mFilenameNode;
if ( object->mImage )
{
mImage = new QImage( *object->mImage );
}
else
{
mImage = nullptr;
}
if ( object->mSvgRenderer )
{
mSvgRenderer = new QSvgRenderer( object->mSvg );
}
else
{
mSvgRenderer = nullptr;
}
mSvg = object->mSvg;
}
///
/// Destructor
///
ModelImageObject::~ModelImageObject()
{
delete mOutline;
foreach( Handle* handle, mHandles )
{
delete handle;
}
mHandles.clear();
if ( mImage )
{
delete mImage;
}
if ( mSvgRenderer )
{
delete mSvgRenderer;
}
}
///
/// Clone
///
ModelImageObject* ModelImageObject::clone() const
{
return new ModelImageObject( this );
}
///
/// Image filenameNode Property Getter
///
TextNode ModelImageObject::filenameNode() const
{
return mFilenameNode;
}
///
/// Image filenameNode Property Setter
///
void ModelImageObject::setFilenameNode( const TextNode& value )
{
if ( mFilenameNode != value )
{
mFilenameNode = value;
loadImage();
emit changed();
}
}
///
/// Image image Property Getter
///
const QImage* ModelImageObject::image() const
{
return mImage;
}
///
/// Image Property Setter
///
void ModelImageObject::setImage( const QImage& value )
{
if ( !value.isNull() )
{
if ( mImage )
{
delete mImage;
mImage = nullptr;
}
if ( mSvgRenderer )
{
delete mSvgRenderer;
mSvgRenderer = nullptr;
}
mImage = new QImage(value);
quint16 cs = qChecksum( (const char*)mImage->constBits(), mImage->byteCount() );
mFilenameNode = TextNode( false, QString("%image_%1%").arg( cs ) );
emit changed();
}
}
///
/// Image Property Setter
///
void ModelImageObject::setImage( const QString& name, const QImage& value )
{
if ( !value.isNull() )
{
if ( mImage )
{
delete mImage;
mImage = nullptr;
}
if ( mSvgRenderer )
{
delete mSvgRenderer;
mSvgRenderer = nullptr;
}
mImage = new QImage(value);
mFilenameNode = TextNode( false, name );
emit changed();
}
}
///
/// Image svg Property Getter
///
QByteArray ModelImageObject::svg() const
{
return mSvg;
}
///
/// Image svgSource Property Setter
///
void ModelImageObject::setSvg( const QString& name, const QByteArray& value )
{
if ( !value.isEmpty() )
{
if ( mImage )
{
delete mImage;
mImage = nullptr;
}
if ( mSvgRenderer )
{
delete mSvgRenderer;
mSvgRenderer = nullptr;
}
mSvg = value;
mSvgRenderer = new QSvgRenderer( mSvg );
mFilenameNode = TextNode( false, name );
emit changed();
}
}
///
/// naturalSize Property Getter (assumes 72 DPI, i.e. 1pixel == 1pt)
///
Size ModelImageObject::naturalSize() const
{
Size size( Distance::pt(72), Distance::pt(72) );
if ( mImage )
{
QSize qsize = mImage->size();
size.setW( Distance::pt( qsize.width() ) );
size.setH( Distance::pt( qsize.height() ) );
}
else if ( mSvgRenderer )
{
QSize qsize = mSvgRenderer->defaultSize();
size.setW( Distance::pt( qsize.width() ) );
size.setH( Distance::pt( qsize.height() ) );
}
return size;
}
///
/// Draw shadow of object
///
void ModelImageObject::drawShadow( QPainter* painter, bool inEditor, merge::Record* record ) const
{
QRectF destRect( 0, 0, mW.pt(), mH.pt() );
QColor shadowColor = mShadowColorNode.color( record );
shadowColor.setAlphaF( mShadowOpacity );
if ( mImage && mImage->hasAlphaChannel() && (mImage->depth() == 32) )
{
QImage* shadowImage = createShadowImage( shadowColor );
painter->drawImage( destRect, *shadowImage );
delete shadowImage;
}
else
{
if ( mImage || inEditor )
{
painter->setBrush( shadowColor );
painter->setPen( QPen( Qt::NoPen ) );
painter->drawRect( destRect );
}
}
}
///
/// Draw object itself
///
void ModelImageObject::drawObject( QPainter* painter, bool inEditor, merge::Record* record ) const
{
QRectF destRect( 0, 0, mW.pt(), mH.pt() );
if ( inEditor && (mFilenameNode.isField() || (!mImage && !mSvgRenderer) ) )
{
painter->save();
painter->setRenderHint( QPainter::SmoothPixmapTransform, false );
painter->drawImage( destRect, *smDefaultImage );
painter->restore();
}
else if ( mImage )
{
painter->drawImage( destRect, *mImage );
}
else if ( mSvgRenderer )
{
mSvgRenderer->render( painter, destRect );
}
else if ( mFilenameNode.isField() )
{
// TODO
}
}
///
/// Path to test for hover condition
///
QPainterPath ModelImageObject::hoverPath( double scale ) const
{
QPainterPath path;
path.addRect( 0, 0, mW.pt(), mH.pt() );
return path;
}
///
/// Load image
///
void ModelImageObject::loadImage()
{
if ( mImage )
{
delete mImage;
mImage = nullptr;
}
if ( mSvgRenderer )
{
delete mSvgRenderer;
mSvgRenderer = nullptr;
}
if ( !mFilenameNode.isField() )
{
QString filename = mFilenameNode.data();
QFileInfo fileInfo( filename );
if ( fileInfo.isReadable() )
{
if ( (fileInfo.suffix() == "svg") || (fileInfo.suffix() == "SVG") )
{
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;
}
}
}
}
else
{
mImage = new QImage( filename );
if ( mImage->isNull() )
{
mImage = nullptr;
}
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;
}
}
}
}
}
}
///
/// Create shadow image
///
QImage* ModelImageObject::createShadowImage( const QColor& color ) const
{
int r = color.red();
int g = color.green();
int b = color.blue();
int a = color.alpha();
QImage* shadow = new QImage( *mImage );
for ( int iy = 0; iy < shadow->height(); iy++ )
{
QRgb* scanLine = (QRgb*)shadow->scanLine( iy );
for ( int ix = 0; ix < shadow->width(); ix++ )
{
scanLine[ix] = qRgba( r, g, b, (a*qAlpha(scanLine[ix]))/255 );
}
}
return shadow;
}
} // namespace glabels::model
+161
View File
@@ -0,0 +1,161 @@
/* ModelImageObject.h
*
* Copyright (C) 2013-2016 Jim Evins <evins@snaught.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef model_ModelImageObject_h
#define model_ModelImageObject_h
#include "ModelObject.h"
#include <QSvgRenderer>
namespace glabels::model
{
///
/// Label Model Image Object
///
class ModelImageObject : public ModelObject
{
Q_OBJECT
///////////////////////////////////////////////////////////////
// Lifecycle Methods
///////////////////////////////////////////////////////////////
public:
ModelImageObject();
ModelImageObject( const Distance& x0,
const Distance& y0,
const Distance& w,
const Distance& h,
const TextNode& filenameNode,
const QMatrix& matrix = QMatrix(),
bool shadowState = false,
const Distance& shadowX = 0,
const Distance& shadowY = 0,
double shadowOpacity = 1.0,
const ColorNode& shadowColorNode = ColorNode() );
ModelImageObject( const Distance& x0,
const Distance& y0,
const Distance& w,
const Distance& h,
const QString& filename,
const QImage& image,
const QMatrix& matrix = QMatrix(),
bool shadowState = false,
const Distance& shadowX = 0,
const Distance& shadowY = 0,
double shadowOpacity = 1.0,
const ColorNode& shadowColorNode = ColorNode() );
ModelImageObject( const Distance& x0,
const Distance& y0,
const Distance& w,
const Distance& h,
const QString& filename,
const QByteArray& svg,
const QMatrix& matrix = QMatrix(),
bool shadowState = false,
const Distance& shadowX = 0,
const Distance& shadowY = 0,
double shadowOpacity = 1.0,
const ColorNode& shadowColorNode = ColorNode() );
ModelImageObject( const ModelImageObject* object );
~ModelImageObject() override;
///////////////////////////////////////////////////////////////
// Object duplication
///////////////////////////////////////////////////////////////
ModelImageObject* clone() const override;
///////////////////////////////////////////////////////////////
// Property Implementations
///////////////////////////////////////////////////////////////
public:
//
// Image Property: filenameNode
//
TextNode filenameNode() const override;
void setFilenameNode( const TextNode& value ) override;
//
// Image Property: image
//
const QImage* image() const override;
void setImage( const QImage& value ) override;
void setImage( const QString& name, const QImage& value ) override;
//
// Image Property: svg
//
QByteArray svg() const override;
void setSvg( const QString& name, const QByteArray& value ) override;
//
// Property: naturalSize
//
Size naturalSize() const override;
///////////////////////////////////////////////////////////////
// Capability Implementations
///////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////
// 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;
QPainterPath hoverPath( double scale ) const override;
///////////////////////////////////////////////////////////////
// Private
///////////////////////////////////////////////////////////////
void loadImage();
QImage* createShadowImage( const QColor& color ) const;
///////////////////////////////////////////////////////////////
// Private Members
///////////////////////////////////////////////////////////////
protected:
TextNode mFilenameNode;
QImage* mImage;
QSvgRenderer* mSvgRenderer;
QByteArray mSvg;
static QImage* smDefaultImage;
};
}
#endif // model_ModelImageObject_h
+243
View File
@@ -0,0 +1,243 @@
/* ModelLineObject.cpp
*
* Copyright (C) 2013-2016 Jim Evins <evins@snaught.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "ModelLineObject.h"
#include <QBrush>
#include <QPen>
namespace glabels::model
{
//
// Private
//
namespace
{
const double slopPixels = 2;
}
///
/// Constructor
///
ModelLineObject::ModelLineObject()
{
mOutline = nullptr;
mHandles << new HandleP1( this );
mHandles << new HandleP2( this );
mLineWidth = 1.0;
mLineColorNode = ColorNode( QColor( 0, 0, 0 ) );
}
///
/// Constructor
///
ModelLineObject::ModelLineObject( const Distance& x0,
const Distance& y0,
const Distance& dx,
const Distance& dy,
const Distance& lineWidth,
const ColorNode& lineColorNode,
const QMatrix& matrix,
bool shadowState,
const Distance& shadowX,
const Distance& shadowY,
double shadowOpacity,
const ColorNode& shadowColorNode )
: ModelObject( x0, y0, dx, dy,
matrix,
shadowState, shadowX, shadowY, shadowOpacity, shadowColorNode )
{
mOutline = new Outline( this );
mHandles << new HandleNorthWest( this );
mHandles << new HandleNorth( this );
mHandles << new HandleNorthEast( this );
mHandles << new HandleEast( this );
mHandles << new HandleSouthEast( this );
mHandles << new HandleSouth( this );
mHandles << new HandleSouthWest( this );
mHandles << new HandleWest( this );
mLineWidth = lineWidth;
mLineColorNode = lineColorNode;
}
///
/// Copy constructor
///
ModelLineObject::ModelLineObject( const ModelLineObject* object )
: ModelObject(object)
{
mLineWidth = object->mLineWidth;
mLineColorNode = object->mLineColorNode;
}
///
/// Destructor
///
ModelLineObject::~ModelLineObject()
{
foreach( Handle* handle, mHandles )
{
delete handle;
}
mHandles.clear();
}
///
/// Clone
///
ModelLineObject* ModelLineObject::clone() const
{
return new ModelLineObject( this );
}
///
/// Line Width Property Getter
///
Distance ModelLineObject::lineWidth() const
{
return mLineWidth;
}
///
/// Line Width Property Setter
///
void ModelLineObject::setLineWidth( const Distance& value )
{
if ( mLineWidth != value )
{
mLineWidth = value;
emit changed();
}
}
///
/// Line Color Node Property Getter
///
ColorNode ModelLineObject::lineColorNode() const
{
return mLineColorNode;
}
///
/// Line Color Node Property Setter
///
void ModelLineObject::setLineColorNode( const ColorNode& value )
{
if ( mLineColorNode != value )
{
mLineColorNode = value;
emit changed();
}
}
///
/// Can Line Color Capability Implementation
///
bool ModelLineObject::canLineColor()
{
return true;
}
///
/// Can Line Width Capability Implementation
///
bool ModelLineObject::canLineWidth()
{
return true;
}
///
/// Draw shadow of object
///
void ModelLineObject::drawShadow( QPainter* painter, bool inEditor, merge::Record* record ) const
{
QColor lineColor = mLineColorNode.color( record );
QColor shadowColor = mShadowColorNode.color( record );
shadowColor.setAlphaF( mShadowOpacity );
if ( lineColor.alpha() )
{
painter->setPen( QPen( shadowColor, mLineWidth.pt() ) );
painter->drawLine( 0, 0, mW.pt(), mH.pt() );
}
}
///
/// Draw object itself
///
void ModelLineObject::drawObject( QPainter* painter, bool inEditor, merge::Record* record ) const
{
QColor lineColor = mLineColorNode.color( record );
painter->setPen( QPen( lineColor, mLineWidth.pt() ) );
painter->drawLine( 0, 0, mW.pt(), mH.pt() );
}
///
/// Path to test for hover condition
///
QPainterPath ModelLineObject::hoverPath( double scale ) const
{
QPainterPath path;
if ( mLineColorNode.color().alpha() )
{
//
// Build a thin rectangle representing line
//
double rPts = mLineWidth.pt()/2 + slopPixels / scale;
double lengthPts = sqrt( mW.pt()*mW.pt() + mH.pt()*mH.pt() );
double dx = mH.pt() / lengthPts; // horizontal pitch of perpendicular line
double dy = mW.pt() / lengthPts; // vertical pitch of perpendicular line
path.moveTo( rPts*dx, - rPts*dy );
path.lineTo( mW.pt() + rPts*dx, mH.pt() - rPts*dy );
path.lineTo( mW.pt() - rPts*dx, mH.pt() + rPts*dy );
path.lineTo( - rPts*dx, rPts*dy );
path.closeSubpath();
}
return path;
}
} // namespace glabels::model
+115
View File
@@ -0,0 +1,115 @@
/* ModelLineObject.h
*
* Copyright (C) 2013-2016 Jim Evins <evins@snaught.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef model_ModelLineObject_h
#define model_ModelLineObject_h
#include "ModelObject.h"
namespace glabels::model
{
///
/// Label Model Line Object
///
class ModelLineObject : public ModelObject
{
Q_OBJECT
///////////////////////////////////////////////////////////////
// Lifecycle Methods
///////////////////////////////////////////////////////////////
public:
ModelLineObject();
ModelLineObject( const Distance& x0,
const Distance& y0,
const Distance& w,
const Distance& h,
const Distance& lineWidth,
const ColorNode& lineColorNode,
const QMatrix& matrix = QMatrix(),
bool shadowState = false,
const Distance& shadowX = 0,
const Distance& shadowY = 0,
double shadowOpacity = 1.0,
const ColorNode& shadowColorNode = ColorNode() );
ModelLineObject( const ModelLineObject* object );
~ModelLineObject() override;
///////////////////////////////////////////////////////////////
// Object duplication
///////////////////////////////////////////////////////////////
ModelLineObject* clone() const override;
///////////////////////////////////////////////////////////////
// Property Implementations
///////////////////////////////////////////////////////////////
public:
//
// Line Property: lineWidth
//
Distance lineWidth() const override;
void setLineWidth( const Distance& value ) override;
//
// Line Property: lineColorNode
//
ColorNode lineColorNode() const override;
void setLineColorNode( const ColorNode& value ) override;
///////////////////////////////////////////////////////////////
// Capability Implementations
///////////////////////////////////////////////////////////////
public:
virtual bool canLineColor();
virtual bool canLineWidth();
///////////////////////////////////////////////////////////////
// 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;
QPainterPath hoverPath( double scale ) const override;
///////////////////////////////////////////////////////////////
// Private Members
///////////////////////////////////////////////////////////////
protected:
Distance mLineWidth;
ColorNode mLineColorNode;
};
}
#endif // model_ModelLineObject_h
File diff suppressed because it is too large Load Diff
+436
View File
@@ -0,0 +1,436 @@
/* ModelObject.h
*
* Copyright (C) 2013-2016 Jim Evins <evins@snaught.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef model_ModelObject_h
#define model_ModelObject_h
#include "ColorNode.h"
#include "Distance.h"
#include "Handles.h"
#include "Outline.h"
#include "TextNode.h"
#include "barcode/Style.h"
#include "merge/Record.h"
#include <QObject>
#include <QFont>
#include <QMatrix>
#include <QPainter>
namespace glabels::model
{
// Forward References
class Region;
class Size;
///
/// Label Model Object Base Class
///
class ModelObject : public QObject
{
Q_OBJECT
///////////////////////////////////////////////////////////////
// Lifecycle Methods
///////////////////////////////////////////////////////////////
protected:
ModelObject();
ModelObject( const Distance& x0,
const Distance& y0,
const Distance& w,
const Distance& h,
const QMatrix& matrix = QMatrix(),
bool shadowState = false,
const Distance& shadowX = 0,
const Distance& shadowY = 0,
double shadowOpacity = 1.0,
const ColorNode& shadowColorNode = ColorNode() );
ModelObject( const ModelObject* object );
public:
~ModelObject() override;
///////////////////////////////////////////////////////////////
// Object duplication
///////////////////////////////////////////////////////////////
virtual ModelObject* clone() const = 0;
///////////////////////////////////////////////////////////////
// Signals
///////////////////////////////////////////////////////////////
signals:
void moved();
void changed();
///////////////////////////////////////////////////////////////
// Common Properties
///////////////////////////////////////////////////////////////
public:
//
// ID Property.
//
int id() const;
//
// Selected Property.
//
bool isSelected() const;
void select( bool value = true );
void unselect();
//
// x0 Property ( x coordinate of origin )
//
Distance x0() const;
void setX0( const Distance& value );
//
// y0 Property ( y coordinate of origin )
//
Distance y0() const;
void setY0( const Distance& value );
//
// w Property ( width of bounding box )
//
Distance w() const;
void setW( const Distance& value );
//
// h Property ( height of bounding box )
//
Distance h() const;
void setH( const Distance& value );
//
// Transformation Matrix Property
//
QMatrix matrix() const;
void setMatrix( const QMatrix& value );
//
// Shadow State Property
//
bool shadow() const;
void setShadow( bool value );
//
// Shadow x Offset Property
//
Distance shadowX() const;
void setShadowX( const Distance& value );
//
// Shadow y Offset Property
//
Distance shadowY() const;
void setShadowY( const Distance& value );
//
// Shadow opacity Property
//
double shadowOpacity() const;
void setShadowOpacity( double value );
//
// Shadow Color Property
//
ColorNode shadowColorNode() const;
void setShadowColorNode( const ColorNode& value );
//
// Natural Size Property (read-only)
//
virtual Size naturalSize() const;
///////////////////////////////////////////////////////////////
// Text Properties Virtual Interface
///////////////////////////////////////////////////////////////
public:
//
// Virtual Text Property: text
//
virtual QString text() const;
virtual void setText( const QString &value );
//
// Virtual Text Property: fontFamily
//
virtual QString fontFamily() const;
virtual void setFontFamily( const QString &value );
//
// Virtual Text Property: fontSize
//
virtual double fontSize() const;
virtual void setFontSize( double value );
//
// Virtual Text Property: fontWeight
//
virtual QFont::Weight fontWeight() const;
virtual void setFontWeight( QFont::Weight value );
//
// Virtual Text Property: fontItalicFlag
//
virtual bool fontItalicFlag() const;
virtual void setFontItalicFlag( bool value );
//
// Virtual Text Property: fontUnderlineFlag
//
virtual bool fontUnderlineFlag() const;
virtual void setFontUnderlineFlag( bool value );
//
// Virtual Text Property: textColorNode
//
virtual ColorNode textColorNode() const;
virtual void setTextColorNode( const ColorNode &value );
//
// Virtual Text Property: textHAlign
//
virtual Qt::Alignment textHAlign() const;
virtual void setTextHAlign( Qt::Alignment value );
//
// Virtual Text Property: textVAlign
//
virtual Qt::Alignment textVAlign() const;
virtual void setTextVAlign( Qt::Alignment value );
//
// Virtual Text Property: textLineSpacing
//
virtual double textLineSpacing() const;
virtual void setTextLineSpacing( double value );
///////////////////////////////////////////////////////////////
// Image Properties Virtual Interface
///////////////////////////////////////////////////////////////
public:
//
// Virtual Image Property: filenameNode
//
virtual TextNode filenameNode() const;
virtual void setFilenameNode( const TextNode &value );
//
// Virtual Image Property: image
//
virtual const QImage* image() const;
virtual void setImage( const QImage& value );
virtual void setImage( const QString& name, const QImage& value );
//
// Virtual Image Property: svg
//
virtual QByteArray svg() const;
virtual void setSvg( const QString& name, const QByteArray& value );
///////////////////////////////////////////////////////////////
// Shape Properties Virtual Interface
///////////////////////////////////////////////////////////////
public:
//
// Virtual Shape Property: lineWidth
//
virtual Distance lineWidth() const;
virtual void setLineWidth( const Distance& value );
//
// Virtual Shape Property: lineColorNode
//
virtual ColorNode lineColorNode() const;
virtual void setLineColorNode( const ColorNode &value );
//
// Virtual Shape Property: fillColorNode
//
virtual ColorNode fillColorNode() const;
virtual void setFillColorNode( const ColorNode &value );
///////////////////////////////////////////////////////////////
// Barcode Properties Virtual Interface
///////////////////////////////////////////////////////////////
public:
//
// Virtual Barcode Property: bcData
//
virtual QString bcData() const;
virtual void setBcData( const QString& value );
//
// Virtual Barcode Property: bcTextFlag
//
virtual bool bcTextFlag() const;
virtual void setBcTextFlag( bool value );
//
// Virtual Barcode Property: bcChecksumFlag
//
virtual bool bcChecksumFlag() const;
virtual void setBcChecksumFlag( bool value );
//
// Virtual Barcode Property: bcColorNode
//
virtual ColorNode bcColorNode() const;
virtual void setBcColorNode( const ColorNode &value );
//
// Virtual Barcode Property: bcStyle
//
virtual barcode::Style bcStyle() const;
virtual void setBcStyle( const barcode::Style &value );
//
// Virtual Barcode Property: bcFormatDigits
//
virtual int bcFormatDigits() const;
virtual void setBcFormatDigits( int value );
///////////////////////////////////////////////////////////////
// Capabilities (Overridden by concrete classes.)
///////////////////////////////////////////////////////////////
public:
virtual bool canText() const;
virtual bool canFill() const;
virtual bool canLineColor() const;
virtual bool canLineWidth() const;
///////////////////////////////////////////////////////////////
// Position and Size methods
///////////////////////////////////////////////////////////////
public:
void setPosition( const Distance& x0, const Distance& y0 );
void setPositionRelative( const Distance& dx, const Distance& dy );
Size size() const;
void setSize( const Distance& w, const Distance& h );
void setSize( const Size& size );
void setSizeHonorAspect( const Distance& w, const Distance& h );
void setWHonorAspect( const Distance& w );
void setHHonorAspect( const Distance& h );
Region getExtent();
void rotate( double thetaDegs );
void flipHoriz();
void flipVert();
bool isLocatedAt( double scale, const Distance& x, const Distance& y ) const;
Handle* handleAt( double scale, const Distance& x, const Distance& y ) const;
///////////////////////////////////////////////////////////////
// Drawing operations
///////////////////////////////////////////////////////////////
public:
void draw( QPainter* painter, bool inEditor, merge::Record* record ) 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 QPainterPath hoverPath( double scale ) const = 0;
virtual void sizeUpdated();
///////////////////////////////////////////////////////////////
// Protected Members
///////////////////////////////////////////////////////////////
protected:
bool mSelectedFlag;
Distance mX0;
Distance mY0;
Distance mW;
Distance mH;
bool mShadowState;
Distance mShadowX;
Distance mShadowY;
double mShadowOpacity;
ColorNode mShadowColorNode;
QList<Handle*> mHandles;
Outline* mOutline;
///////////////////////////////////////////////////////////////
// Private Members
///////////////////////////////////////////////////////////////
private:
static int msNextId;
int mId;
QMatrix mMatrix;
};
}
#endif // model_ModelObject_h
+207
View File
@@ -0,0 +1,207 @@
/* ModelShapeObject.cpp
*
* Copyright (C) 2013-2016 Jim Evins <evins@snaught.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "ModelShapeObject.h"
#include <QBrush>
#include <QPen>
namespace glabels::model
{
///
/// Constructor
///
ModelShapeObject::ModelShapeObject()
{
mOutline = new Outline( this );
mHandles << new HandleNorthWest( this );
mHandles << new HandleNorth( this );
mHandles << new HandleNorthEast( this );
mHandles << new HandleEast( this );
mHandles << new HandleSouthEast( this );
mHandles << new HandleSouth( this );
mHandles << new HandleSouthWest( this );
mHandles << new HandleWest( this );
mLineWidth = 1.0;
mLineColorNode = ColorNode( QColor( 0, 0, 0 ) );
mFillColorNode = ColorNode( QColor( 0, 255, 0 ) );
}
///
/// Constructor
///
ModelShapeObject::ModelShapeObject( const Distance& x0,
const Distance& y0,
const Distance& w,
const Distance& h,
const Distance& lineWidth,
const ColorNode& lineColorNode,
const ColorNode& fillColorNode,
const QMatrix& matrix,
bool shadowState,
const Distance& shadowX,
const Distance& shadowY,
double shadowOpacity,
const ColorNode& shadowColorNode )
: ModelObject( x0, y0, w, h,
matrix,
shadowState, shadowX, shadowY, shadowOpacity, shadowColorNode )
{
mOutline = new Outline( this );
mHandles << new HandleNorthWest( this );
mHandles << new HandleNorth( this );
mHandles << new HandleNorthEast( this );
mHandles << new HandleEast( this );
mHandles << new HandleSouthEast( this );
mHandles << new HandleSouth( this );
mHandles << new HandleSouthWest( this );
mHandles << new HandleWest( this );
mLineWidth = lineWidth;
mLineColorNode = lineColorNode;
mFillColorNode = fillColorNode;
}
///
/// Copy constructor
///
ModelShapeObject::ModelShapeObject( const ModelShapeObject* object ) : ModelObject(object)
{
mLineWidth = object->mLineWidth;
mLineColorNode = object->mLineColorNode;
mFillColorNode = object->mFillColorNode;
}
///
/// Destructor
///
ModelShapeObject::~ModelShapeObject()
{
delete mOutline;
foreach( Handle* handle, mHandles )
{
delete handle;
}
mHandles.clear();
}
///
/// Line Width Property Getter
///
Distance ModelShapeObject::lineWidth() const
{
return mLineWidth;
}
///
/// Line Width Property Setter
///
void ModelShapeObject::setLineWidth( const Distance& value )
{
if ( mLineWidth != value )
{
mLineWidth = value;
emit changed();
}
}
///
/// Line Color Node Property Getter
///
ColorNode ModelShapeObject::lineColorNode() const
{
return mLineColorNode;
}
///
/// Line Color Node Property Setter
///
void ModelShapeObject::setLineColorNode( const ColorNode& value )
{
if ( mLineColorNode != value )
{
mLineColorNode = value;
emit changed();
}
}
///
/// Fill Color Node Property Getter
///
ColorNode ModelShapeObject::fillColorNode() const
{
return mFillColorNode;
}
///
/// Fill Color Node Property Setter
///
void ModelShapeObject::setFillColorNode( const ColorNode& value )
{
if ( mFillColorNode != value )
{
mFillColorNode = value;
emit changed();
}
}
///
/// Can Fill Capability Implementation
///
bool ModelShapeObject::canFill()
{
return true;
}
///
/// Can Line Color Capability Implementation
///
bool ModelShapeObject::canLineColor()
{
return true;
}
///
/// Can Line Width Capability Implementation
///
bool ModelShapeObject::canLineWidth()
{
return true;
}
} // namespace glabels::model
+110
View File
@@ -0,0 +1,110 @@
/* ModelShapeObject.h
*
* Copyright (C) 2013-2016 Jim Evins <evins@snaught.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef model_ModelShapeObject_h
#define model_ModelShapeObject_h
#include "ModelObject.h"
namespace glabels::model
{
///
/// Label Model Shape Object (Box or Ellipse)
///
class ModelShapeObject : public ModelObject
{
Q_OBJECT
///////////////////////////////////////////////////////////////
// Lifecycle Methods
///////////////////////////////////////////////////////////////
protected:
ModelShapeObject();
ModelShapeObject( const Distance& x0,
const Distance& y0,
const Distance& w,
const Distance& h,
const Distance& lineWidth,
const ColorNode& lineColorNode,
const ColorNode& fillColorNode,
const QMatrix& matrix,
bool shadowState,
const Distance& shadowX,
const Distance& shadowY,
double shadowOpacity,
const ColorNode& shadowColorNode );
ModelShapeObject( const ModelShapeObject* object );
public:
~ModelShapeObject() override;
///////////////////////////////////////////////////////////////
// Property Implementations
///////////////////////////////////////////////////////////////
public:
//
// Shape Property: lineWidth
//
Distance lineWidth() const override;
void setLineWidth( const Distance& value ) override;
//
// Shape Property: lineColorNode
//
ColorNode lineColorNode() const override;
void setLineColorNode( const ColorNode& value ) override;
//
// Shape Property: fillColorNode
//
ColorNode fillColorNode() const override;
void setFillColorNode( const ColorNode& value ) override;
///////////////////////////////////////////////////////////////
// Capability Implementations
///////////////////////////////////////////////////////////////
public:
virtual bool canFill();
virtual bool canLineColor();
virtual bool canLineWidth();
///////////////////////////////////////////////////////////////
// Private Members
///////////////////////////////////////////////////////////////
protected:
Distance mLineWidth;
ColorNode mLineColorNode;
ColorNode mFillColorNode;
};
}
#endif // model_ModelShapeObject_h
+720
View File
@@ -0,0 +1,720 @@
/* ModelTextObject.cpp
*
* Copyright (C) 2013-2016 Jim Evins <evins@snaught.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "ModelTextObject.h"
#include "Size.h"
#include <QBrush>
#include <QPen>
#include <QTextDocument>
#include <QTextBlock>
#include <QRegularExpression>
#include <QtDebug>
namespace glabels::model
{
//
// Private
//
namespace
{
const double marginPts = 3;
}
///
/// Constructor
///
ModelTextObject::ModelTextObject()
{
mOutline = new Outline( this );
mHandles << new HandleNorthWest( this );
mHandles << new HandleNorth( this );
mHandles << new HandleNorthEast( this );
mHandles << new HandleEast( this );
mHandles << new HandleSouthEast( this );
mHandles << new HandleSouth( this );
mHandles << new HandleSouthWest( this );
mHandles << new HandleWest( this );
mText = "";
mFontFamily = "Sans";
mFontSize = 10;
mFontWeight = QFont::Normal;
mFontItalicFlag = false;
mFontUnderlineFlag = false;
mTextColorNode = ColorNode( QColor( 0, 0, 0 ) );
mTextHAlign = Qt::AlignLeft;
mTextVAlign = Qt::AlignTop;
mTextLineSpacing = 1;
}
///
/// Constructor
///
ModelTextObject::ModelTextObject( const Distance& x0,
const Distance& y0,
const Distance& w,
const Distance& h,
const QString& text,
const QString& fontFamily,
double fontSize,
QFont::Weight fontWeight,
bool fontItalicFlag,
bool fontUnderlineFlag,
ColorNode textColorNode,
Qt::Alignment textHAlign,
Qt::Alignment textVAlign,
double textLineSpacing,
const QMatrix& matrix,
bool shadowState,
const Distance& shadowX,
const Distance& shadowY,
double shadowOpacity,
const ColorNode& shadowColorNode )
: ModelObject( x0, y0, w, h,
matrix,
shadowState, shadowX, shadowY, shadowOpacity, shadowColorNode )
{
mOutline = new Outline( this );
mHandles << new HandleNorthWest( this );
mHandles << new HandleNorth( this );
mHandles << new HandleNorthEast( this );
mHandles << new HandleEast( this );
mHandles << new HandleSouthEast( this );
mHandles << new HandleSouth( this );
mHandles << new HandleSouthWest( this );
mHandles << new HandleWest( this );
mText = text;
mFontFamily = fontFamily;
mFontSize = fontSize;
mFontWeight = fontWeight;
mFontItalicFlag = fontItalicFlag;
mFontUnderlineFlag = fontUnderlineFlag;
mTextColorNode = textColorNode;
mTextHAlign = textHAlign;
mTextVAlign = textVAlign;
mTextLineSpacing = textLineSpacing;
update(); // Initialize cached editor layouts
}
///
/// Copy constructor
///
ModelTextObject::ModelTextObject( const ModelTextObject* object )
: ModelObject(object)
{
mText = object->mText;
mFontFamily = object->mFontFamily;
mFontSize = object->mFontSize;
mFontWeight = object->mFontWeight;
mFontItalicFlag = object->mFontItalicFlag;
mFontUnderlineFlag = object->mFontUnderlineFlag;
mTextColorNode = object->mTextColorNode;
mTextHAlign = object->mTextHAlign;
mTextVAlign = object->mTextVAlign;
mTextLineSpacing = object->mTextLineSpacing;
update(); // Initialize cached editor layouts
}
///
/// Destructor
///
ModelTextObject::~ModelTextObject()
{
delete mOutline;
foreach( Handle* handle, mHandles )
{
delete handle;
}
mHandles.clear();
}
///
/// Clone
///
ModelTextObject* ModelTextObject::clone() const
{
return new ModelTextObject( this );
}
///
/// Text Property Getter
///
QString ModelTextObject::text() const
{
return mText.toString();
}
///
/// Text Property Setter
///
void ModelTextObject::setText( const QString& value )
{
if ( mText.toString() != value )
{
mText = value;
update();
emit changed();
}
}
///
/// FontFamily Property Getter
///
QString ModelTextObject::fontFamily() const
{
return mFontFamily;
}
///
/// FontFamily Property Setter
///
void ModelTextObject::setFontFamily( const QString& value )
{
if ( mFontFamily != value )
{
mFontFamily = value;
update();
emit changed();
}
}
///
/// FontSize Property Getter
///
double ModelTextObject::fontSize() const
{
return mFontSize;
}
///
/// FontSize Property Setter
///
void ModelTextObject::setFontSize( double value )
{
if ( mFontSize != value )
{
mFontSize = value;
update();
emit changed();
}
}
///
/// FontWeight Property Getter
///
QFont::Weight ModelTextObject::fontWeight() const
{
return mFontWeight;
}
///
/// FontWeight Property Setter
///
void ModelTextObject::setFontWeight( QFont::Weight value )
{
if ( mFontWeight != value )
{
mFontWeight = value;
update();
emit changed();
}
}
///
/// FontItalicFlag Property Getter
///
bool ModelTextObject::fontItalicFlag() const
{
return mFontItalicFlag;
}
///
/// FontItalicFlag Property Setter
///
void ModelTextObject::setFontItalicFlag( bool value )
{
if ( mFontItalicFlag != value )
{
mFontItalicFlag = value;
update();
emit changed();
}
}
///
/// FontUnderlineFlag Property Getter
///
bool ModelTextObject::fontUnderlineFlag() const
{
return mFontUnderlineFlag;
}
///
/// FontUnderlineFlag Property Setter
///
void ModelTextObject::setFontUnderlineFlag( bool value )
{
if ( mFontUnderlineFlag != value )
{
mFontUnderlineFlag = value;
update();
emit changed();
}
}
///
/// Text Color Node Property Getter
///
ColorNode ModelTextObject::textColorNode() const
{
return mTextColorNode;
}
///
/// Text Color Node Property Setter
///
void ModelTextObject::setTextColorNode( const ColorNode& value )
{
if ( mTextColorNode != value )
{
mTextColorNode = value;
update();
emit changed();
}
}
///
/// TextHAlign Property Getter
///
Qt::Alignment ModelTextObject::textHAlign() const
{
return mTextHAlign;
}
///
/// TextHAlign Property Setter
///
void ModelTextObject::setTextHAlign( Qt::Alignment value )
{
if ( mTextHAlign != value )
{
mTextHAlign = value;
update();
emit changed();
}
}
///
/// TextVAlign Property Getter
///
Qt::Alignment ModelTextObject::textVAlign() const
{
return mTextVAlign;
}
///
/// TextVAlign Property Setter
///
void ModelTextObject::setTextVAlign( Qt::Alignment value )
{
if ( mTextVAlign != value )
{
mTextVAlign = value;
update();
emit changed();
}
}
///
/// TextLineSpacing Property Getter
///
double ModelTextObject::textLineSpacing() const
{
return mTextLineSpacing;
}
///
/// TextLineSpacing Property Setter
///
void ModelTextObject::setTextLineSpacing( double value )
{
if ( mTextLineSpacing != value )
{
mTextLineSpacing = value;
update();
emit changed();
}
}
///
/// NaturalSize Property Getter
///
Size ModelTextObject::naturalSize() const
{
QFont font;
font.setFamily( mFontFamily );
font.setPointSizeF( mFontSize );
font.setWeight( mFontWeight );
font.setItalic( mFontItalicFlag );
font.setUnderline( mFontUnderlineFlag );
QTextOption textOption;
textOption.setAlignment( mTextHAlign );
textOption.setWrapMode( QTextOption::WordWrap );
QFontMetricsF fontMetrics( font );
double dy = fontMetrics.lineSpacing() * mTextLineSpacing;
QString displayText = mText.isEmpty() ? tr("Text") : mText.toString();
QTextDocument document( displayText );
// Do layouts
double x = 0;
double y = 0;
QRectF boundingRect;
for ( int i = 0; i < document.blockCount(); i++ )
{
QTextLayout* layout = new QTextLayout( document.findBlockByNumber(i).text() );
layout->setFont( font );
layout->setTextOption( textOption );
layout->setCacheEnabled(true);
layout->beginLayout();
for ( QTextLine l = layout->createLine(); l.isValid(); l = layout->createLine() )
{
l.setPosition( QPointF( x, y ) );
y += dy;
}
layout->endLayout();
boundingRect = layout->boundingRect().united( boundingRect );
}
return Size( boundingRect.width() + 2*marginPts, boundingRect.height() + 2*marginPts );
}
///
/// Can Text Capability Implementation
///
bool ModelTextObject::canText()
{
return true;
}
///
/// Draw shadow of object
///
void ModelTextObject::drawShadow( QPainter* painter,
bool inEditor,
merge::Record* record ) const
{
QColor textColor = mTextColorNode.color( record );
if ( textColor.alpha() )
{
QColor shadowColor = mShadowColorNode.color( record );
shadowColor.setAlphaF( mShadowOpacity );
if ( inEditor )
{
drawTextInEditor( painter, shadowColor );
}
else
{
drawText( painter, shadowColor, record );
}
}
}
///
/// Draw object itself
///
void ModelTextObject::drawObject( QPainter* painter,
bool inEditor,
merge::Record* record ) const
{
QColor textColor = mTextColorNode.color( record );
if ( inEditor )
{
drawTextInEditor( painter, textColor );
}
else
{
drawText( painter, textColor, record );
}
}
///
/// Path to test for hover condition
///
QPainterPath ModelTextObject::hoverPath( double scale ) const
{
return mHoverPath;
}
///
/// Size updated
///
void ModelTextObject::sizeUpdated()
{
update();
}
///
/// Update cached information for editor view
///
void ModelTextObject::update()
{
QFont font;
font.setFamily( mFontFamily );
font.setPointSizeF( mFontSize );
font.setWeight( mFontWeight );
font.setItalic( mFontItalicFlag );
font.setUnderline( mFontUnderlineFlag );
QTextOption textOption;
textOption.setAlignment( mTextHAlign );
textOption.setWrapMode( QTextOption::WordWrap );
QFontMetricsF fontMetrics( font );
double dy = fontMetrics.lineSpacing() * mTextLineSpacing;
QString displayText = mText.isEmpty() ? tr("Text") : mText.toString();
QTextDocument document( displayText );
qDeleteAll( mEditorLayouts );
mEditorLayouts.clear();
// Pass #1 -- do initial layouts
double x = 0;
double y = 0;
QRectF boundingRect;
for ( int i = 0; i < document.blockCount(); i++ )
{
QTextLayout* layout = new QTextLayout( document.findBlockByNumber(i).text() );
layout->setFont( font );
layout->setTextOption( textOption );
layout->setCacheEnabled(true);
layout->beginLayout();
for ( QTextLine l = layout->createLine(); l.isValid(); l = layout->createLine() )
{
l.setLineWidth( mW.pt() - 2*marginPts );
l.setPosition( QPointF( x, y ) );
y += dy;
}
layout->endLayout();
mEditorLayouts.append( layout );
boundingRect = layout->boundingRect().united( boundingRect );
}
double h = boundingRect.height();
// Pass #2 -- adjust layout positions for vertical alignment and create hover path
x = marginPts;
switch ( mTextVAlign )
{
case Qt::AlignVCenter:
y = mH.pt()/2 - h/2;
break;
case Qt::AlignBottom:
y = mH.pt() - h - marginPts;
break;
default:
y = marginPts;
break;
}
QPainterPath hoverPath; // new empty hover path
foreach ( QTextLayout* layout, mEditorLayouts )
{
for ( int j = 0; j < layout->lineCount(); j++ )
{
QTextLine l = layout->lineAt(j);
l.setPosition( QPointF( x, y ) );
y += dy;
hoverPath.addRect( l.naturalTextRect() ); // add to new hover path
}
}
mHoverPath = hoverPath; // save new hover path
}
///
/// Draw text in editor from cached information
///
void ModelTextObject::drawTextInEditor( QPainter* painter, const QColor& color ) const
{
if ( mText.isEmpty() )
{
QColor mutedColor = color;
mutedColor.setAlphaF( 0.5 * color.alphaF() );
painter->setPen( QPen( mutedColor ) );
}
else
{
painter->setPen( QPen( color ) );
}
foreach ( QTextLayout* layout, mEditorLayouts )
{
layout->draw( painter, QPointF( 0, 0 ) );
}
}
///
/// Draw text in final printout or preview
///
void
ModelTextObject::drawText( QPainter* painter,
const QColor& color,
merge::Record* record ) const
{
QFont font;
font.setFamily( mFontFamily );
font.setPointSizeF( mFontSize );
font.setWeight( mFontWeight );
font.setItalic( mFontItalicFlag );
font.setUnderline( mFontUnderlineFlag );
QTextOption textOption;
textOption.setAlignment( mTextHAlign );
textOption.setWrapMode( QTextOption::WordWrap );
QFontMetricsF fontMetrics( font );
double dy = fontMetrics.lineSpacing() * mTextLineSpacing;
QTextDocument document( mText.expand( record ) );
QList<QTextLayout*> layouts;
// Pass #1 -- do initial layouts
double x = 0;
double y = 0;
QRectF boundingRect;
for ( int i = 0; i < document.blockCount(); i++ )
{
QTextLayout* layout = new QTextLayout( document.findBlockByNumber(i).text() );
layout->setFont( font );
layout->setTextOption( textOption );
layout->setCacheEnabled(true);
layout->beginLayout();
for ( QTextLine l = layout->createLine(); l.isValid(); l = layout->createLine() )
{
l.setLineWidth( mW.pt() - 2*marginPts );
l.setPosition( QPointF( x, y ) );
y += dy;
}
layout->endLayout();
layouts.append( layout );
boundingRect = layout->boundingRect().united( boundingRect );
}
double h = boundingRect.height();
// Pass #2 -- adjust layout positions for vertical alignment and create hover path
x = marginPts;
switch ( mTextVAlign )
{
case Qt::AlignVCenter:
y = mH.pt()/2 - h/2;
break;
case Qt::AlignBottom:
y = mH.pt() - h - marginPts;
break;
default:
y = marginPts;
break;
}
foreach ( QTextLayout* layout, layouts )
{
for ( int j = 0; j < layout->lineCount(); j++ )
{
QTextLine l = layout->lineAt(j);
l.setPosition( QPointF( x, y ) );
y += dy;
}
}
// Draw layouts
painter->setPen( QPen( color ) );
foreach ( QTextLayout* layout, layouts )
{
layout->draw( painter, QPointF( 0, 0 ) );
}
// Cleanup
qDeleteAll( layouts );
}
} // namespace glabels::model
+209
View File
@@ -0,0 +1,209 @@
/* ModelTextObject.h
*
* Copyright (C) 2013-2016 Jim Evins <evins@snaught.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef model_ModelTextObject_h
#define model_ModelTextObject_h
#include "ModelObject.h"
#include "RawText.h"
#include <QTextLayout>
namespace glabels::model
{
///
/// Label Model Line Object
///
class ModelTextObject : public ModelObject
{
Q_OBJECT
///////////////////////////////////////////////////////////////
// Lifecycle Methods
///////////////////////////////////////////////////////////////
public:
ModelTextObject();
ModelTextObject( const Distance& x0,
const Distance& y0,
const Distance& w,
const Distance& h,
const QString& text,
const QString& fontFamily,
double fontSize,
QFont::Weight fontWeight,
bool fontItalicFlag,
bool fontUnderlineFlag,
ColorNode textColorNode,
Qt::Alignment textHAlign,
Qt::Alignment textVAlign,
double textLineSpacing,
const QMatrix& matrix = QMatrix(),
bool shadowState = false,
const Distance& shadowX = 0,
const Distance& shadowY = 0,
double shadowOpacity = 1.0,
const ColorNode& shadowColorNode = ColorNode() );
ModelTextObject( const ModelTextObject* object );
~ModelTextObject() override;
///////////////////////////////////////////////////////////////
// Object duplication
///////////////////////////////////////////////////////////////
ModelTextObject* clone() const override;
///////////////////////////////////////////////////////////////
// Property Implementations
///////////////////////////////////////////////////////////////
public:
//
// Text Property: text
//
QString text() const override;
void setText( const QString &value ) override;
//
// Text Property: fontFamily
//
QString fontFamily() const override;
void setFontFamily( const QString &value ) override;
//
// Text Property: fontSize
//
double fontSize() const override;
void setFontSize( double value ) override;
//
// Text Property: fontWeight
//
QFont::Weight fontWeight() const override;
void setFontWeight( QFont::Weight value ) override;
//
// Text Property: fontItalicFlag
//
bool fontItalicFlag() const override;
void setFontItalicFlag( bool value ) override;
//
// Text Property: fontUnderlineFlag
//
bool fontUnderlineFlag() const override;
void setFontUnderlineFlag( bool value ) override;
//
// Text Property: textColorNode
//
ColorNode textColorNode() const override;
void setTextColorNode( const ColorNode &value ) override;
//
// Text Property: textHAlign
//
Qt::Alignment textHAlign() const override;
void setTextHAlign( Qt::Alignment value ) override;
//
// Text Property: textVAlign
//
Qt::Alignment textVAlign() const override;
void setTextVAlign( Qt::Alignment value ) override;
//
// Text Property: textLineSpacing
//
double textLineSpacing() const override;
void setTextLineSpacing( double value ) override;
//
// Property: naturalSize
//
Size naturalSize() const override;
///////////////////////////////////////////////////////////////
// Capability Implementations
///////////////////////////////////////////////////////////////
public:
virtual bool canText();
///////////////////////////////////////////////////////////////
// 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;
QPainterPath hoverPath( double scale ) const override;
///////////////////////////////////////////////////////////////
// Private methods
///////////////////////////////////////////////////////////////
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;
///////////////////////////////////////////////////////////////
// Private Members
///////////////////////////////////////////////////////////////
private:
RawText mText;
QString mFontFamily;
double mFontSize;
QFont::Weight mFontWeight;
bool mFontItalicFlag;
bool mFontUnderlineFlag;
ColorNode mTextColorNode;
Qt::Alignment mTextHAlign;
Qt::Alignment mTextVAlign;
double mTextLineSpacing;
QList<QTextLayout*> mEditorLayouts;
QPainterPath mHoverPath;
};
}
#endif // model_ModelTextObject_h
+135
View File
@@ -0,0 +1,135 @@
/* Outline.cpp
*
* Copyright (C) 2013-2016 Jim Evins <evins@snaught.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "Outline.h"
#include "ModelObject.h"
#include <QColor>
namespace glabels::model
{
//
// Private
//
namespace
{
const qreal dashSize = 2;
const double slopPixels = 2;
const double outlineWidthPixels = 1;
const QColor outlineColor1( 0, 0, 0 );
const QColor outlineColor2( 255, 255, 255 );
}
///
/// Outline Constructor
///
Outline::Outline( ModelObject* owner )
: mOwner(owner)
{
mDashes << dashSize << dashSize;
mPen1.setColor( outlineColor1 );
mPen1.setWidth( outlineWidthPixels );
mPen1.setCosmetic( true );
mPen1.setCapStyle( Qt::FlatCap );
mPen1.setDashPattern( mDashes );
mPen2.setColor( outlineColor2 );
mPen2.setWidth( outlineWidthPixels );
mPen2.setCosmetic( true );
mPen2.setCapStyle( Qt::FlatCap );
mPen2.setDashPattern( mDashes );
mPen2.setDashOffset( dashSize );
}
///
/// Outline Copy constructor
///
Outline::Outline( const Outline* outline, ModelObject* newOwner )
: mOwner(newOwner)
{
mDashes = outline->mDashes;
mPen1 = outline->mPen1;
mPen2 = outline->mPen2;
}
///
/// Outline Destructor
///
Outline::~Outline()
{
// empty
}
///
/// Clone Outline
///
Outline* Outline::clone( ModelObject* newOwner ) const
{
return new Outline( this, newOwner );
}
///
/// Draw Outline
///
void Outline::draw( QPainter* painter ) const
{
painter->save();
painter->setBrush( Qt::NoBrush );
painter->setPen( mPen1 );
painter->drawRect( QRectF( 0, 0, mOwner->w().pt(), mOwner->h().pt() ) );
painter->setPen( mPen2 );
painter->drawRect( QRectF( 0, 0, mOwner->w().pt(), mOwner->h().pt() ) );
painter->restore();
}
///
/// Create path for testing for hover condition
///
QPainterPath Outline::hoverPath( double scale ) const
{
double s = 1 / scale;
QPainterPath path;
path.addRect( -s*slopPixels, -s*slopPixels,
mOwner->w().pt()+s*2*slopPixels, mOwner->h().pt()+s*2*slopPixels );
path.closeSubpath();
path.addRect( s*slopPixels, s*slopPixels,
mOwner->w().pt()-s*2*slopPixels, mOwner->h().pt()-s*2*slopPixels );
return path;
}
} // namespace glabels::model
+79
View File
@@ -0,0 +1,79 @@
/* Outline.h
*
* Copyright (C) 2013-2016 Jim Evins <evins@snaught.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef model_Outline_h
#define model_Outline_h
#include <QPainter>
#include <QPainterPath>
namespace glabels::model
{
// Forward references
class ModelObject;
///
/// Outline Base Class
///
class Outline
{
////////////////////////////
// Lifecycle Methods
////////////////////////////
public:
Outline( ModelObject* owner );
Outline( const Outline* outline, ModelObject* newOwner );
virtual ~Outline();
////////////////////////////
// Duplication
////////////////////////////
Outline* clone( ModelObject* newOwner ) const;
////////////////////////////
// Drawing Methods
////////////////////////////
public:
void draw( QPainter* painter ) const;
QPainterPath hoverPath( double scale ) const;
////////////////////////////
// Private Data
////////////////////////////
private:
ModelObject* mOwner;
QVector<qreal> mDashes;
QPen mPen1;
QPen mPen2;
};
}
#endif // model_Outline_h
+429
View File
@@ -0,0 +1,429 @@
/* PageRenderer.cpp
*
* Copyright (C) 2013-2016 Jim Evins <evins@snaught.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "PageRenderer.h"
#include "Model.h"
#include "merge/Merge.h"
#include "merge/None.h"
#include "merge/Record.h"
#include <QtDebug>
namespace glabels::model
{
//
// Private
//
namespace
{
const QColor labelOutlineColor( 0, 0, 0 );
const double labelOutlineWidth = 0.25;
const double tickOffset = 2.25;
const double tickLength = 18;
}
PageRenderer::PageRenderer( const Model* model )
: mModel(nullptr), mNCopies(0), mStartLabel(0),
mPrintOutlines(false), mPrintCropMarks(false), mPrintReverse(false),
mIPage(0), mIsMerge(false), mNPages(0)
{
if ( model )
{
setModel( model );
}
}
void PageRenderer::setModel( const Model* model )
{
mModel = model;
connect( mModel, SIGNAL(changed()), this, SLOT(onModelChanged()) );
onModelChanged();
}
const Model* PageRenderer::model() const
{
return mModel;
}
void PageRenderer::onModelChanged()
{
mMerge = mModel->merge();
mOrigins = mModel->frame()->getOrigins();
mNLabelsPerPage = mModel->frame()->nLabels();
mIsMerge = ( dynamic_cast<const merge::None*>(mMerge) == nullptr );
updateNPages();
emit changed();
}
void PageRenderer::setNCopies( int nCopies )
{
mNCopies = nCopies;
updateNPages();
emit changed();
}
void PageRenderer::setStartLabel( int startLabel )
{
mStartLabel = startLabel;
updateNPages();
emit changed();
}
void PageRenderer::setPrintOutlines( bool printOutlinesFlag )
{
mPrintOutlines = printOutlinesFlag;
emit changed();
}
void PageRenderer::setPrintCropMarks( bool printCropMarksFlag )
{
mPrintCropMarks = printCropMarksFlag;
emit changed();
}
void PageRenderer::setPrintReverse( bool printReverseFlag )
{
mPrintReverse = printReverseFlag;
emit changed();
}
void PageRenderer::setIPage( int iPage )
{
mIPage = iPage;
emit changed();
}
int PageRenderer::nItems() const
{
return mLastLabel - mStartLabel;
}
int PageRenderer::nPages() const
{
return mNPages;
}
QRectF PageRenderer::pageRect() const
{
if ( mModel )
{
return QRectF( 0, 0, mModel->tmplate()->pageWidth().pt(), mModel->tmplate()->pageHeight().pt() );
}
else
{
return QRectF( 0, 0, 0, 0 );
}
}
void PageRenderer::updateNPages()
{
if ( mModel )
{
if ( mIsMerge )
{
mLastLabel = mStartLabel + mNCopies*mMerge->nSelectedRecords();
}
else
{
mLastLabel = mStartLabel + mNCopies;
}
mNPages = mLastLabel / mNLabelsPerPage;
if ( mLastLabel % mNLabelsPerPage )
{
mNPages++;
}
}
else
{
mNPages = 0;
}
}
///
/// Print
///
void PageRenderer::print( QPrinter* printer ) const
{
QSizeF pageSize( mModel->tmplate()->pageWidth().pt(), mModel->tmplate()->pageHeight().pt() );
printer->setPageSize( QPageSize(pageSize, QPageSize::Point) );
printer->setFullPage( true );
printer->setPageMargins( 0, 0, 0, 0, QPrinter::Point );
QPainter painter( printer );
QRectF rectPx = printer->paperRect( QPrinter::DevicePixel );
QRectF rectPts = printer->paperRect( QPrinter::Point );
painter.scale( rectPx.width()/rectPts.width(), rectPx.height()/rectPts.height() );
for ( int iPage = 0; iPage < mNPages; iPage++ )
{
if ( iPage )
{
printer->newPage();
}
printPage( &painter, iPage );
}
}
///
/// Print page using persistent page number
///
void PageRenderer::printPage( QPainter* painter ) const
{
printPage( painter, mIPage );
}
///
/// Print page
///
void PageRenderer::printPage( QPainter* painter, int iPage ) const
{
if ( mModel )
{
if ( mIsMerge )
{
printMergePage( painter, iPage );
}
else
{
printSimplePage( painter, iPage );
}
}
}
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++ )
{
painter->save();
painter->translate( mOrigins[i].x().pt(), mOrigins[i].y().pt() );
painter->save();
clipLabel( painter );
printLabel( painter, nullptr );
painter->restore(); // From before clip
printOutline( painter );
painter->restore(); // From before translation
}
}
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<merge::Record*> records = mMerge->selectedRecords();
if ( records.size() )
{
iRecord = (iPage*mNLabelsPerPage + iStart - mStartLabel) % records.size();
}
printCropMarks( painter );
for ( int i = iStart; i < iEnd; i++ )
{
painter->save();
painter->translate( mOrigins[i].x().pt(), mOrigins[i].y().pt() );
painter->save();
clipLabel( painter );
printLabel( painter, records[iRecord] );
painter->restore(); // From before clip
printOutline( painter );
painter->restore(); // From before translation
iRecord = (iRecord + 1) % records.size();
}
}
void PageRenderer::printCropMarks( QPainter* painter ) const
{
if ( mPrintCropMarks )
{
painter->save();
painter->setBrush( QBrush( Qt::NoBrush ) );
painter->setPen( QPen( labelOutlineColor, labelOutlineWidth ) );
Distance w = mModel->frame()->w();
Distance h = mModel->frame()->h();
foreach ( Layout* layout, mModel->frame()->layouts() )
{
Distance xMin = layout->x0();
Distance yMin = layout->y0();
Distance xMax = layout->x0() + layout->dx()*(layout->nx()-1) + w;
Distance yMax = layout->y0() + layout->dy()*(layout->ny()-1) + h;
for ( int ix = 0; ix < layout->nx(); ix++ )
{
Distance x1 = xMin + ix*layout->dx();
Distance x2 = x1 + w;
Distance y1 = max( yMin-tickOffset, Distance::pt(0) );
Distance y2 = max( y1-tickLength, Distance::pt(0) );
Distance y3 = min( yMax+tickOffset, mModel->tmplate()->pageHeight() );
Distance y4 = min( y3+tickLength, mModel->tmplate()->pageHeight() );
painter->drawLine( x1.pt(), y1.pt(), x1.pt(), y2.pt() );
painter->drawLine( x2.pt(), y1.pt(), x2.pt(), y2.pt() );
painter->drawLine( x1.pt(), y3.pt(), x1.pt(), y4.pt() );
painter->drawLine( x2.pt(), y3.pt(), x2.pt(), y4.pt() );
}
for ( int iy = 0; iy < layout->ny(); iy++ )
{
Distance y1 = yMin + iy*layout->dy();
Distance y2 = y1 + h;
Distance x1 = max( xMin-tickOffset, Distance::pt(0) );
Distance x2 = max( x1-tickLength, Distance::pt(0) );
Distance x3 = min( xMax+tickOffset, mModel->tmplate()->pageWidth() );
Distance x4 = min( x3+tickLength, mModel->tmplate()->pageWidth() );
painter->drawLine( x1.pt(), y1.pt(), x2.pt(), y1.pt() );
painter->drawLine( x1.pt(), y2.pt(), x2.pt(), y2.pt() );
painter->drawLine( x3.pt(), y1.pt(), x4.pt(), y1.pt() );
painter->drawLine( x3.pt(), y2.pt(), x4.pt(), y2.pt() );
}
}
painter->restore();
}
}
void PageRenderer::printOutline( QPainter* painter ) const
{
if ( mPrintOutlines )
{
painter->save();
painter->setBrush( QBrush( Qt::NoBrush ) );
painter->setPen( QPen( labelOutlineColor, labelOutlineWidth ) );
painter->drawPath( mModel->frame()->path() );
painter->restore();
}
}
void PageRenderer::clipLabel( QPainter* painter ) const
{
painter->setClipPath( mModel->frame()->clipPath() );
}
void PageRenderer::printLabel( QPainter* painter, merge::Record* record ) const
{
painter->save();
if ( mModel->rotate() )
{
painter->rotate( -90.0 );
painter->translate( -mModel->w().pt(), 0 );
}
if ( mPrintReverse )
{
painter->translate( mModel->w().pt(), 0 );
painter->scale( -1, 1 );
}
mModel->draw( painter, false, record );
painter->restore();
}
} // namespace glabels::model
+129
View File
@@ -0,0 +1,129 @@
/* PageRenderer.h
*
* Copyright (C) 2013-2016 Jim Evins <evins@snaught.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef model_PageRenderer_h
#define model_PageRenderer_h
#include "Point.h"
#include "merge/Merge.h"
#include "merge/Record.h"
#include <QPainter>
#include <QPrinter>
#include <QRect>
#include <QVector>
namespace glabels::model
{
// Forward references
class Model;
///
/// PageRenderer Widget
///
class PageRenderer : public QObject
{
Q_OBJECT
/////////////////////////////////
// Life Cycle
/////////////////////////////////
public:
PageRenderer( const Model* model = nullptr );
/////////////////////////////////
// Public Methods
/////////////////////////////////
public:
void setModel( const Model* model );
const Model* model() const;
void setNCopies( int nCopies );
void setStartLabel( int startLabel );
void setPrintOutlines( bool printOutlinesFlag );
void setPrintCropMarks( bool printCropMarksFlag );
void setPrintReverse( bool printReverseFlag );
void setIPage( int iPage );
int nItems() const;
int nPages() const;
QRectF pageRect() const;
void print( QPrinter* printer ) const;
void printPage( QPainter* painter ) const;
void printPage( QPainter* painter, int iPage ) const;
/////////////////////////////////
// Signals
/////////////////////////////////
signals:
void changed();
/////////////////////////////////
// Private slots
/////////////////////////////////
private slots:
void onModelChanged();
/////////////////////////////////
// Internal Methods
/////////////////////////////////
private:
void updateNPages();
void printSimplePage( QPainter* painter, int iPage ) const;
void printMergePage( QPainter* painter, int iPage ) const;
void printCropMarks( QPainter* painter ) const;
void printOutline( QPainter* painter ) const;
void clipLabel( QPainter* painter ) const;
void printLabel( QPainter* painter, merge::Record* record ) const;
/////////////////////////////////
// Private Data
/////////////////////////////////
private:
const Model* mModel;
const merge::Merge* mMerge;
int mNCopies;
int mStartLabel;
int mLastLabel;
bool mPrintOutlines;
bool mPrintCropMarks;
bool mPrintReverse;
int mIPage;
bool mIsMerge;
int mNPages;
int mNLabelsPerPage;
QVector<Point> mOrigins;
};
}
#endif // model_PageRenderer_h
+79
View File
@@ -0,0 +1,79 @@
/* Paper.cpp
*
* Copyright (C) 2013-2016 Jim Evins <evins@snaught.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "Paper.h"
namespace glabels::model
{
Paper::Paper( const QString& id,
const QString& name,
const Distance& width,
const Distance& height,
const QString& pwgSize )
: mId(id), mName(name), mWidth(width), mHeight(height), mPwgSize(pwgSize)
{
// empty
}
QString Paper::id() const
{
return mId;
}
QString Paper::name() const
{
return mName;
}
Distance Paper::width() const
{
return mWidth;
}
Distance Paper::height() const
{
return mHeight;
}
QString Paper::pwgSize() const
{
return mPwgSize;
}
bool Paper::isSizeIso() const
{
return mPwgSize.startsWith( "iso_" );
}
bool Paper::isSizeUs() const
{
return mPwgSize.startsWith( "na_" );
}
} // namespace glabels::model
+68
View File
@@ -0,0 +1,68 @@
/* Paper.h
*
* Copyright (C) 2013-2016 Jim Evins <evins@snaught.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef model_Paper_h
#define model_Paper_h
#include "Distance.h"
#include <QString>
namespace glabels::model
{
class Paper
{
public:
Paper( const QString& id,
const QString& name,
const Distance& width,
const Distance& height,
const QString& pwgSize );
QString id() const;
QString name() const;
/* Width */
Distance width() const;
/* Height */
Distance height() const;
/* PWG 5101.1-2002 size name */
QString pwgSize() const;
bool isSizeIso() const;
bool isSizeUs() const;
private:
QString mId;
QString mName;
Distance mWidth;
Distance mHeight;
QString mPwgSize;
};
}
#endif // model_Paper_h
+64
View File
@@ -0,0 +1,64 @@
/* Point.cpp
*
* Copyright (C) 2013-2016 Jim Evins <evins@snaught.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "Point.h"
namespace glabels::model
{
Point::Point() : mX(Distance(0)), mY(Distance(0))
{
// empty
}
Point::Point( Distance x, Distance y ) : mX(x), mY(y)
{
// empty
}
Distance Point::x() const
{
return mX;
}
Distance Point::y() const
{
return mY;
}
bool Point::operator<( const Point &other ) const
{
if ( mY < other.mY )
{
return true;
}
else if ( mY == other.mY )
{
return mX < other.mX;
}
return false;
}
} // namespace glabels::model
+52
View File
@@ -0,0 +1,52 @@
/* Point.h
*
* Copyright (C) 2013-2016 Jim Evins <evins@snaught.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef model_Point_h
#define model_Point_h
#include "Distance.h"
namespace glabels::model
{
class Point
{
public:
Point();
Point( Distance x, Distance y );
Distance x() const;
Distance y() const;
bool operator<( const Point &other ) const;
private:
Distance mX;
Distance mY;
};
}
#endif // model_Point_h
+149
View File
@@ -0,0 +1,149 @@
/* RawText.cpp
*
* Copyright (C) 2017 Jim Evins <evins@snaught.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "RawText.h"
#include <QRegularExpression>
namespace glabels::model
{
///
/// Constructor from QString
///
RawText::RawText( const QString& string ) : mString(string)
{
tokenize();
}
///
/// Constructor from C string operator
///
RawText::RawText( const char* cString ) : mString(QString(cString))
{
tokenize();
}
///
/// Access as QString
///
QString RawText::toString() const
{
return mString;
}
///
/// Access as std::string
///
std::string RawText::toStdString() const
{
return mString.toStdString();
}
///
/// Expand all place holders
///
QString RawText::expand( merge::Record* record ) const
{
QString text;
foreach ( const Token& token, mTokens )
{
if ( token.isField )
{
text += token.field.evaluate( record );
}
else
{
text += token.text;
}
}
return text;
}
///
/// Does raw text contain place holders?
///
bool RawText::hasPlaceHolders() const
{
QRegularExpression re("\\${\\w+}");
return mString.contains( re );
}
///
/// Is raw text empty?
///
bool RawText::isEmpty() const
{
return mString.isEmpty();
}
///
/// Tokenize string
///
void RawText::tokenize()
{
Token token;
QStringRef s = &mString;
while ( s.size() )
{
SubstitutionField field;
if ( SubstitutionField::parse( s, field ) )
{
// Finalize current text token, if apropos
if ( !token.text.isEmpty() )
{
token.isField = false;
mTokens.append( token );
}
// Create and finalize field token
token.isField = true;
token.text = "";
token.field = field;
mTokens.append( token );
}
else
{
token.text += s[0];
s = s.mid(1);
}
}
// Finalize last text token, if apropos
if ( !token.text.isEmpty() )
{
token.isField = false;
mTokens.append( token );
}
}
} // namespace glabels::model
+84
View File
@@ -0,0 +1,84 @@
/* RawText.h
*
* Copyright (C) 2017 Jim Evins <evins@snaught.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef model_RawText_h
#define model_RawText_h
#include "SubstitutionField.h"
#include <QString>
namespace glabels::model
{
///
/// Raw Text Type
///
struct RawText
{
/////////////////////////////////
// Life Cycle
/////////////////////////////////
public:
RawText() = default;
RawText( const QString& string );
RawText( const char* cString );
/////////////////////////////////
// Misc. Methods
/////////////////////////////////
QString toString() const;
std::string toStdString() const;
QString expand( merge::Record* record ) const;
bool hasPlaceHolders() const;
bool isEmpty() const;
/////////////////////////////////
// Private Methods
/////////////////////////////////
private:
void tokenize();
/////////////////////////////////
// Private Data
/////////////////////////////////
private:
QString mString;
struct Token
{
bool isField;
QString text;
SubstitutionField field;
};
QList<Token> mTokens;
};
}
#endif // model_RawText_h
+134
View File
@@ -0,0 +1,134 @@
/* Region.cpp
*
* Copyright (C) 2013-2016 Jim Evins <evins@snaught.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "Region.h"
namespace glabels::model
{
///
/// Constructor
///
Region::Region() : mX1(0), mY1(0), mX2(0), mY2(0)
{
// empty
}
///
/// Constructor
///
Region::Region( const Distance& x1, const Distance& y1,
const Distance& x2, const Distance& y2 )
: mX1(x1), mY1(y1), mX2(x2), mY2(y2)
{
// empty
}
///
/// Get x1
///
Distance Region::x1() const
{
return mX1;
}
///
/// Set x1
///
void Region::setX1( const Distance& value )
{
mX1 = value;
}
///
/// Get y1
///
Distance Region::y1() const
{
return mY1;
}
///
/// Set y1
///
void Region::setY1( const Distance& value )
{
mY1 = value;
}
///
/// Get x2
///
Distance Region::x2() const
{
return mX2;
}
///
/// Set x2
///
void Region::setX2( const Distance& value )
{
mX2 = value;
}
///
/// Get y2
///
Distance Region::y2() const
{
return mY2;
}
///
/// Set y2
///
void Region::setY2( const Distance& value )
{
mY2 = value;
}
///
/// Convert to a QRectF
///
QRectF Region::rect() const
{
QRectF r;
r.setX( min( mX1, mX2 ).pt() );
r.setY( min( mY1, mY2 ).pt() );
r.setWidth( fabs( mX2 - mX1 ).pt() );
r.setHeight( fabs( mY2 - mY1 ).pt() );
return r;
}
} // namespace glabels::model
+101
View File
@@ -0,0 +1,101 @@
/* Region.h
*
* Copyright (C) 2013 Jim Evins <evins@snaught.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef model_Region_h
#define model_Region_h
#include "Distance.h"
#include <QRectF>
namespace glabels::model
{
///
/// Label Region Type
///
struct Region
{
/////////////////////////////////
// Constructors
/////////////////////////////////
public:
Region();
Region( const Distance& x1, const Distance& y1,
const Distance& x2, const Distance& y2 );
/////////////////////////////////
// Properties
/////////////////////////////////
public:
//
// X1 Property
//
Distance x1() const;
void setX1( const Distance& value );
//
// Y1 Property
//
Distance y1() const;
void setY1( const Distance& value );
//
// X2 Property
//
Distance x2() const;
void setX2( const Distance& value );
//
// Y2 Property
//
Distance y2() const;
void setY2( const Distance& value );
/////////////////////////////////
// Methods
/////////////////////////////////
public:
QRectF rect() const;
/////////////////////////////////
// Private Data
/////////////////////////////////
private:
Distance mX1;
Distance mY1;
Distance mX2;
Distance mY2;
};
}
#endif // model_Region_h
+261
View File
@@ -0,0 +1,261 @@
/* Settings.cpp
*
* Copyright (C) 2016 Jim Evins <evins@snaught.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "Settings.h"
#include <QLocale>
#include <QString>
#include <QtDebug>
namespace glabels::model
{
//
// Static data
//
Settings* Settings::mInstance = nullptr;
Settings::Settings()
{
// empty
}
void Settings::init()
{
if ( mInstance == nullptr )
{
mInstance = new Settings();
}
}
Settings* Settings::instance()
{
init();
return mInstance;
}
Units Settings::units()
{
// Guess at a suitable default
QString defaultIdString;
if ( QLocale::system().measurementSystem() == QLocale::ImperialSystem )
{
defaultIdString = Units(Units::IN).toIdString();
}
else
{
defaultIdString = Units(Units::MM).toIdString();
}
mInstance->beginGroup( "Locale" );
QString idString = mInstance->value( "units", defaultIdString ).toString();
mInstance->endGroup();
return Units( idString );
}
void Settings::setUnits( const Units& units )
{
QString idString = units.toIdString();
mInstance->beginGroup( "Locale" );
mInstance->setValue( "units", idString );
mInstance->endGroup();
emit mInstance->changed();
}
bool Settings::searchIsoPaperSizes()
{
// Guess at a suitable default
bool defaultValue;
switch (QLocale::system().country())
{
case QLocale::UnitedStates:
case QLocale::Canada:
defaultValue = false;
break;
default:
defaultValue = true;
break;
}
mInstance->beginGroup( "Search" );
bool returnValue = mInstance->value( "isoPaperSizes", defaultValue ).toBool();
mInstance->endGroup();
return returnValue;
}
void Settings::setSearchIsoPaperSizes( bool searchIsoPaperSizes )
{
mInstance->beginGroup( "Search" );
mInstance->setValue( "isoPaperSizes", searchIsoPaperSizes );
mInstance->endGroup();
emit mInstance->changed();
}
bool Settings::searchUsPaperSizes()
{
// Guess at a suitable default
bool defaultValue;
switch (QLocale::system().country())
{
case QLocale::UnitedStates:
case QLocale::Canada:
defaultValue = true;
break;
default:
defaultValue = false;
break;
}
mInstance->beginGroup( "Search" );
bool returnValue = mInstance->value( "usPaperSizes", defaultValue ).toBool();
mInstance->endGroup();
return returnValue;
}
void Settings::setSearchUsPaperSizes( bool searchUsPaperSizes )
{
mInstance->beginGroup( "Search" );
mInstance->setValue( "usPaperSizes", searchUsPaperSizes );
mInstance->endGroup();
emit mInstance->changed();
}
bool Settings::searchOtherPaperSizes()
{
// Guess at a suitable default
bool defaultValue = true;
mInstance->beginGroup( "Search" );
bool returnValue = mInstance->value( "otherPaperSizes", defaultValue ).toBool();
mInstance->endGroup();
return returnValue;
}
void Settings::setSearchOtherPaperSizes( bool searchOtherPaperSizes )
{
mInstance->beginGroup( "Search" );
mInstance->setValue( "otherPaperSizes", searchOtherPaperSizes );
mInstance->endGroup();
emit mInstance->changed();
}
bool Settings::searchAllCategories()
{
// Guess at a suitable default
bool defaultValue = true;
mInstance->beginGroup( "Search" );
bool returnValue = mInstance->value( "allCategories", defaultValue ).toBool();
mInstance->endGroup();
return returnValue;
}
void Settings::setSearchAllCategories( bool searchAllCategories )
{
mInstance->beginGroup( "Search" );
mInstance->setValue( "allCategories", searchAllCategories );
mInstance->endGroup();
emit mInstance->changed();
}
QStringList Settings::searchCategoryList()
{
QStringList defaultList;
mInstance->beginGroup( "Search" );
QStringList returnList = mInstance->value( "categoryList", defaultList ).toStringList();
mInstance->endGroup();
return returnList;
}
void Settings::setSearchCategoryList( const QStringList& searchCategoryList )
{
mInstance->beginGroup( "Search" );
mInstance->setValue( "categoryList", searchCategoryList );
mInstance->endGroup();
emit mInstance->changed();
}
QStringList Settings::recentTemplateList()
{
QStringList defaultList;
mInstance->beginGroup( "Recent" );
QStringList returnList = mInstance->value( "templates", defaultList ).toStringList();
mInstance->endGroup();
return returnList;
}
void Settings::addToRecentTemplateList( const QString& name )
{
mInstance->beginGroup( "Recent" );
QStringList list = mInstance->value( "templates" ).toStringList();
list.removeAll( name );
list.prepend( name );
while ( list.count() > 10 )
{
list.removeLast();
}
mInstance->setValue( "templates", list );
mInstance->endGroup();
emit mInstance->changed();
}
} // namespace glabels::model
+97
View File
@@ -0,0 +1,97 @@
/* Settings.h
*
* Copyright (C) 2016 Jim Evins <evins@snaught.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef model_Settings_h
#define model_Settings_h
#include "Distance.h"
#include <QSettings>
#include <QStringList>
namespace glabels::model
{
///
/// Settings Singleton Class
///
class Settings : public QSettings
{
Q_OBJECT
public:
enum class PageSizeFamilty { ISO, US, };
/////////////////////////////////
// Life Cycle
/////////////////////////////////
private:
Settings();
public:
static void init();
static Settings* instance();
/////////////////////////////////
// Signals
/////////////////////////////////
signals:
void changed();
/////////////////////////////////
// Accessors
/////////////////////////////////
public:
static Units units();
static void setUnits( const Units& units );
static bool searchIsoPaperSizes();
static void setSearchIsoPaperSizes( bool searchIsoPaperSizes );
static bool searchUsPaperSizes();
static void setSearchUsPaperSizes( bool searchUsPaperSizes );
static bool searchOtherPaperSizes();
static void setSearchOtherPaperSizes( bool searchOtherPaperSizes );
static bool searchAllCategories();
static void setSearchAllCategories( bool searchAllCategories );
static QStringList searchCategoryList();
static void setSearchCategoryList( const QStringList& searchCategoryList );
static QStringList recentTemplateList();
static void addToRecentTemplateList( const QString& name );
private:
static Settings* mInstance;
};
}
#endif // model_Settings_h
+94
View File
@@ -0,0 +1,94 @@
/* Size.cpp
*
* Copyright (C) 2013-2016 Jim Evins <evins@snaught.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "Size.h"
namespace glabels::model
{
///
/// Constructor
///
Size::Size() : mW(0), mH(0)
{
// empty
}
///
/// Constructor
///
Size::Size( const Distance& w, const Distance& h ) : mW(w), mH(h)
{
// empty
}
///
/// Get w
///
Distance Size::w() const
{
return mW;
}
///
/// Set w
///
void Size::setW( const Distance& value )
{
mW = value;
}
///
/// Get h
///
Distance Size::h() const
{
return mH;
}
///
/// Set h
///
void Size::setH( const Distance& value )
{
mH = value;
}
///
/// Convert to a QSizeF
///
QSizeF Size::qSizeF() const
{
QSizeF s;
s.setWidth( mW.pt() );
s.setHeight( mH.pt() );
return s;
}
} // namespace glabels::model
+84
View File
@@ -0,0 +1,84 @@
/* Size.h
*
* Copyright (C) 2017 Jim Evins <evins@snaught.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef model_Size_h
#define model_Size_h
#include "Distance.h"
#include <QSizeF>
namespace glabels::model
{
///
/// Size Type
///
class Size
{
/////////////////////////////////
// Constructors
/////////////////////////////////
public:
Size();
Size( const Distance& w, const Distance& h );
/////////////////////////////////
// Properties
/////////////////////////////////
public:
//
// w Property
//
Distance w() const;
void setW( const Distance& value );
//
// H Property
//
Distance h() const;
void setH( const Distance& value );
/////////////////////////////////
// Methods
/////////////////////////////////
public:
QSizeF qSizeF() const;
/////////////////////////////////
// Private Data
/////////////////////////////////
private:
Distance mW;
Distance mH;
};
}
#endif // model_Size_h
+211
View File
@@ -0,0 +1,211 @@
/* StrUtil.cpp
*
* Copyright (C) 2013-2016 Jim Evins <evins@snaught.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "StrUtil.h"
#include <QtMath>
namespace glabels::model
{
//
// Private
//
namespace
{
const double FRAC_EPSILON = 0.00005;
const double denom[] = { 1.0, 2.0, 3.0, 4.0, 8.0, 16.0, 32.0, 0.0 };
const char* denom_string[] = { "1", "", "", "", "", "₁₆", "₃₂", nullptr };
const char* num_string[] = { "", "¹", "²", "³", "", "", "", "", "", "",
"¹⁰", "¹¹", "¹²", "¹³", "¹⁴", "¹⁵", "¹⁶", "¹⁷", "¹⁸", "¹⁹",
"²⁰", "²¹", "²²", "²³", "²⁴", "²⁵", "²⁶", "²⁷", "²⁸", "²⁹",
"³⁰", "³¹" };
}
namespace StrUtil
{
QString formatFraction( double x )
{
int i;
double product, remainder;
for ( i=0; denom[i] != 0.0; i++ )
{
product = x * denom[i];
remainder = qFabs(product - ((int)(product+0.5)));
if ( remainder < FRAC_EPSILON ) break;
}
if ( denom[i] == 0.0 )
{
/* None of our denominators work. */
return QString().sprintf( "%.5g", x );
}
if ( denom[i] == 1.0 )
{
/* Simple integer. */
return QString().sprintf( "%.0f", x );
}
int n = (int)( x * denom[i] + 0.5 );
int d = (int)denom[i];
if ( n > d )
{
return QString::number(n/d) +
QString::fromUtf8(num_string[n%d]) + "/" + QString::fromUtf8(denom_string[i]);
}
else
{
return QString::fromUtf8(num_string[n%d]) + "/" + QString::fromUtf8(denom_string[i]);
}
}
QString spanDigits( const QString &s, int *i )
{
QString chunk;
for ( int j = *i; (j < s.size()) && s.at(j).isNumber(); j++ )
{
chunk.append( s.at(j) );
*i = j+1; /* only advance i, if character is used. */
}
return chunk;
}
QString spanNonDigits( const QString &s, int *i )
{
QString chunk;
for ( int j = *i; (j < s.size()) && !s.at(j).isNumber(); j++ )
{
chunk.append( s.at(j) );
*i = j+1; /* only advance i, if character is used. */
}
return chunk;
}
/**
* Compare part names
* @s1: string to compare with s2.
* @s2: string to compare with s1.
*
* Compare two strings representing part names or numbers. This function
* uses a natural sort order:
*
* - Ignores case.
*
* - Strings are divided into chunks (numeric and non-numeric)
*
* - Non-numeric chunks are compared character by character
*
* - Numerical chunks are compared numerically, so that "20" precedes "100".
*
* - Comparison of chunks is performed left to right until the first difference
* is encountered or all chunks evaluate as equal.
*
* Numeric chunks are converted to 64 bit unsigned integers for comparison,
* so the behaviour may be unpredictable for numeric chunks that exceed
* 18446744073709551615.
*
* Returns: 0 if the strings match, a negative value if s1 < s2,
* or a positive value if s1 > s2.
*
*/
int comparePartNames( const QString &s1, const QString &s2 )
{
if ( s1 == s2 ) return 0;
if ( s1 == "" ) return -1;
if ( s2 == "" ) return 1;
QString folded_s1 = s1.toUpper();
QString folded_s2 = s2.toUpper();
int i1 = 0;
int i2 = 0;
int result = 0;
bool done = false;
while ( (result == 0) && !done )
{
QString chunk1, chunk2;
bool isnum1, isnum2;
if ( (i1 < folded_s1.size()) && folded_s1.at( i1 ).isNumber() )
{
chunk1 = spanDigits( folded_s1, &i1 );
isnum1 = true;
}
else
{
chunk1 = spanNonDigits( folded_s1, &i1 );
isnum1 = false;
}
if ( (i2 < folded_s2.size()) && folded_s2.at( i2 ).isNumber() )
{
chunk2 = spanDigits( folded_s2, &i2 );
isnum2 = true;
}
else
{
chunk2 = spanNonDigits( folded_s2, &i2 );
isnum2 = false;
}
if ( ( chunk1 == "" ) && ( chunk2 == "" ) )
{
/* Case 1: Both are empty. */
done = true;
}
else if ( isnum1 && isnum2 )
{
/* Case 2: They both contain numbers */
qlonglong n1 = chunk1.toLongLong();
qlonglong n2 = chunk2.toLongLong();
if ( n1 < n2 ) result = -1;
else if ( n1 > n2 ) result = 1;
}
else
{
/* Case 3: One or both do not contain numbers */
if ( chunk1 < chunk2 ) result = -1;
else if( chunk1 > chunk2 ) result = 1;
}
}
return result;
}
}
} // namespace glabels::model
+43
View File
@@ -0,0 +1,43 @@
/* StrUtil.h
*
* Copyright (C) 2013-2016 Jim Evins <evins@snaught.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef model_StrUtil_h
#define model_StrUtil_h
#include <QString>
namespace glabels::model
{
namespace StrUtil
{
QString formatFraction( double x );
int comparePartNames( const QString &s1, const QString &s2 );
}
}
#endif // model_StrUtil_h
+331
View File
@@ -0,0 +1,331 @@
/* SubstitutionField.cpp
*
* Copyright (C) 2017 Jim Evins <evins@snaught.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "SubstitutionField.h"
#include <QTextStream>
namespace glabels::model
{
SubstitutionField::SubstitutionField()
: mNewLine(false), mFormatType(0)
{
}
SubstitutionField::SubstitutionField( const QString& string )
: mNewLine(false), mFormatType(0)
{
QStringRef s(&string);
parse( s, *this );
}
QString SubstitutionField::evaluate( const merge::Record* record ) const
{
QString value = mDefaultValue;
if ( record && record->contains(mFieldName) && !record->value(mFieldName).isEmpty() )
{
value = record->value(mFieldName);
}
if ( !mFormatType.isNull() )
{
value = formatValue( value );
}
if ( record && record->contains(mFieldName) && !record->value(mFieldName).isEmpty() && mNewLine )
{
value = "\n" + value;
}
return value;
}
QString SubstitutionField::fieldName() const
{
return mFieldName;
}
QString SubstitutionField::defaultValue() const
{
return mDefaultValue;
}
QString SubstitutionField::format() const
{
return mFormat;
}
QChar SubstitutionField::formatType() const
{
return mFormatType;
}
bool SubstitutionField::newLine() const
{
return mNewLine;
}
bool SubstitutionField::parse( QStringRef& s, SubstitutionField& field )
{
QStringRef sTmp = s;
if ( sTmp.startsWith( "${" ) )
{
sTmp = sTmp.mid(2);
if ( parseFieldName( sTmp, field ) )
{
while ( sTmp.size() && sTmp[0] == ':' )
{
sTmp = sTmp.mid(1);
if ( !parseModifier( sTmp, field ) )
{
return false;
}
}
if ( sTmp.size() && sTmp[0] == '}' )
{
sTmp = sTmp.mid(1);
// Success. Update s.
s = sTmp;
return true;
}
}
}
return false;
}
bool SubstitutionField::parseFieldName( QStringRef& s, SubstitutionField& field )
{
bool success = false;
while ( s.size() && (s[0].isDigit() || s[0].isLetter() || s[0] == '_' || s[0] == '-') )
{
field.mFieldName.append( s[0] );
s = s.mid(1);
success = true;
}
return success;
}
bool SubstitutionField::parseModifier( QStringRef& s, SubstitutionField& field )
{
bool success = false;
if ( s.size() && s[0] == '%' )
{
s = s.mid(1);
success = parseFormatModifier( s, field );
}
else if ( s.size() && s[0] == '=' )
{
s = s.mid(1);
success = parseDefaultValueModifier( s, field );
}
else if ( s.size() && s[0] == 'n' )
{
s = s.mid(1);
success = parseNewLineModifier( s, field );
}
return success;
}
bool SubstitutionField::parseDefaultValueModifier( QStringRef& s, SubstitutionField& field )
{
field.mDefaultValue.clear();
while ( s.size() && !QString( ":}" ).contains( s[0] ) )
{
if ( s[0] == '\\' )
{
s = s.mid(1); // Skip escape
if ( s.size() )
{
field.mDefaultValue.append( s[0] );
s = s.mid(1);
}
}
else
{
field.mDefaultValue.append( s[0] );
s = s.mid(1);
}
}
return true;
}
bool SubstitutionField::parseFormatModifier( QStringRef& s, SubstitutionField& field )
{
bool success = false;
field.mFormat = "%";
parseFormatFlags( s, field );
parseFormatWidth( s, field );
if ( s.size() && s[0] == '.' )
{
field.mFormat += ".";
s = s.mid(1);
parseFormatPrecision( s, field );
}
parseFormatType( s, field );
return true; // Don't let invalid formats kill entire SubstitutionField
}
bool SubstitutionField::parseFormatFlags( QStringRef& s, SubstitutionField& field )
{
while ( s.size() && QString( "-+ 0" ).contains( s[0] ) )
{
field.mFormat += s[0];
s = s.mid(1);
}
return true;
}
bool SubstitutionField::parseFormatWidth( QStringRef& s, SubstitutionField& field )
{
return parseNaturalInteger( s, field );
}
bool SubstitutionField::parseFormatPrecision( QStringRef& s, SubstitutionField& field )
{
return parseNaturalInteger( s, field );
}
bool SubstitutionField::parseFormatType( QStringRef& s, SubstitutionField& field )
{
bool success = false;
if ( s.size() && QString( "diufFeEgGxXos" ).contains( s[0] ) )
{
field.mFormatType = s[0];
field.mFormat += s[0];
s = s.mid(1);
success = true;
}
return success;
}
bool SubstitutionField::parseNaturalInteger( QStringRef& s, SubstitutionField& field )
{
bool success = false;
if ( s.size() && s[0] >= '1' && s[0] <= '9' )
{
field.mFormat += s[0];
s = s.mid(1);
while ( s.size() && s[0].isDigit() )
{
field.mFormat += s[0];
s = s.mid(1);
}
success = true;
}
return success;
}
bool SubstitutionField::parseNewLineModifier( QStringRef& s, SubstitutionField& field )
{
field.mNewLine = true;
return true;
}
QString SubstitutionField::formatValue( const QString& value ) const
{
switch (mFormatType.unicode())
{
case 'd':
case 'i':
return QString::asprintf( mFormat.toStdString().c_str(),
value.toLongLong(nullptr,0) );
break;
case 'u':
case 'x':
case 'X':
case 'o':
return QString::asprintf( mFormat.toStdString().c_str(),
value.toULongLong(nullptr,0) );
break;
case 'f':
case 'F':
case 'e':
case 'E':
case 'g':
case 'G':
return QString::asprintf( mFormat.toStdString().c_str(),
value.toDouble() );
break;
case 's':
return QString::asprintf( mFormat.toStdString().c_str(),
value.toStdString().c_str() );
break;
default:
// Invalid format
return "";
break;
}
}
} // namespace glabels::model
+77
View File
@@ -0,0 +1,77 @@
/* SubstitutionField.h
*
* Copyright (C) 2017 Jim Evins <evins@snaught.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef model_SubstitutionField_h
#define model_SubstitutionField_h
#include "merge/Record.h"
#include <QString>
#include <QStringRef>
namespace glabels::model
{
class SubstitutionField
{
public:
SubstitutionField();
SubstitutionField( const QString& string );
QString evaluate( const merge::Record* record ) const;
QString fieldName() const;
QString defaultValue() const;
QString format() const;
QChar formatType() const;
bool newLine() const;
static bool parse( QStringRef& s, SubstitutionField& field );
private:
static bool parseFieldName( QStringRef& s, SubstitutionField& field );
static bool parseModifier( QStringRef& s, SubstitutionField& field );
static bool parseDefaultValueModifier( QStringRef& s, SubstitutionField& field );
static bool parseFormatModifier( QStringRef& s, SubstitutionField& field );
static bool parseFormatFlags( QStringRef& s, SubstitutionField& field );
static bool parseFormatWidth( QStringRef& s, SubstitutionField& field );
static bool parseFormatPrecision( QStringRef& s, SubstitutionField& field );
static bool parseFormatType( QStringRef& s, SubstitutionField& field );
static bool parseNaturalInteger( QStringRef& s, SubstitutionField& field );
static bool parseNewLineModifier( QStringRef& s, SubstitutionField& field );
QString formatValue( const QString& value ) const;
QString mFieldName;
QString mDefaultValue;
QString mFormat;
QChar mFormatType;
bool mNewLine;
};
}
#endif // model_SubstitutionField_h
+288
View File
@@ -0,0 +1,288 @@
/* Template.cpp
*
* Copyright (C) 2013-2016 Jim Evins <evins@snaught.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "Template.h"
#include "Db.h"
#include <QtDebug>
namespace glabels::model
{
Template::Template( const QString& brand,
const QString& part,
const QString& description,
const QString& paperId,
const Distance& pageWidth,
const Distance& pageHeight )
: mBrand(brand),
mPart(part),
mDescription(description),
mPaperId(paperId),
mPageWidth(pageWidth),
mPageHeight(pageHeight),
mIsSizeIso(false),
mIsSizeUs(false),
mName("")
{
mName.append( brand ).append( " " ).append( part );
if ( Db::isPaperIdKnown( paperId ) )
{
const Paper* paper = Db::lookupPaperFromId( paperId );
mIsSizeIso = paper->isSizeIso();
mIsSizeUs = paper->isSizeUs();
}
}
Template::Template( const Template& other )
{
mBrand = other.mBrand;
mPart = other.mPart;
mDescription = other.mDescription;
mPaperId = other.mPaperId;
mPageWidth = other.mPageWidth;
mPageHeight = other.mPageHeight;
mIsSizeIso = other.mIsSizeIso;
mIsSizeUs = other.mIsSizeUs;
mEquivPart = other.mEquivPart;
mName = other.mName;
mProductUrl = other.mProductUrl;
foreach ( Frame* frame, other.mFrames )
{
addFrame( frame );
}
foreach ( QString categoryId, other.mCategoryIds )
{
addCategory( categoryId );
}
}
Template* Template::dup() const
{
return new Template( *this );
}
// Generic full page template
Template* Template::fullPage( const QString& paperId )
{
// TODO
return nullptr;
}
// From equivalent part number
Template* Template::fromEquiv( const QString& brand,
const QString& part,
const QString& equivPart )
{
const Template* other = Db::lookupTemplateFromBrandPart( brand, equivPart );
if ( other != nullptr )
{
Template* tmplate = other->dup();
tmplate->mPart = part;
tmplate->mEquivPart = equivPart;
tmplate->mName = "";
tmplate->mName.append( brand ).append( " " ).append( part );
return tmplate;
}
else
{
qWarning() << "Error: cannot create equivalent template for "
<< brand << ", " << equivPart
<< ". Forward references not supported.";
return nullptr;
}
}
QString Template::brand() const
{
return mBrand;
}
QString Template::part() const
{
return mPart;
}
QString Template::description() const
{
return mDescription;
}
QString Template::paperId() const
{
return mPaperId;
}
Distance Template::pageWidth() const
{
return mPageWidth;
}
Distance Template::pageHeight() const
{
return mPageHeight;
}
bool Template::isSizeIso() const
{
return mIsSizeIso;
}
bool Template::isSizeUs() const
{
return mIsSizeUs;
}
bool Template::isSizeOther() const
{
return !mIsSizeIso && !mIsSizeUs;
}
QString Template::equivPart() const
{
return mEquivPart;
}
void Template::setEquivPart( const QString& value )
{
mEquivPart = value;
}
QString Template::productUrl() const
{
return mProductUrl;
}
void Template::setProductUrl( const QString& value )
{
mProductUrl = value;
}
QString Template::name() const
{
return mName;
}
const QList<Frame*>& Template::frames() const
{
return mFrames;
}
void Template::addCategory( const QString& categoryId )
{
mCategoryIds << categoryId;
}
void Template::addFrame( Frame* frame )
{
mFrames << frame;
}
bool Template::operator==( const Template& other ) const
{
return (mBrand == other.mBrand) && (mPart == other.mPart);
}
bool Template::hasCategory( const QString& categoryId ) const
{
foreach ( QString testCategoryId, mCategoryIds )
{
if ( categoryId == testCategoryId )
{
return true;
}
}
return false;
}
bool Template::isSimilarTo( const Template* other ) const
{
// Does page size match?
if ( (mPaperId != other->mPaperId) ||
(mPageWidth != other->mPageWidth ) ||
(mPageHeight != other->mPageHeight ) )
{
return false;
}
// Are frames similar
Frame* frame1 = mFrames.first();
Frame* frame2 = other->mFrames.first();
if ( !frame1->isSimilarTo( frame2 ) )
{
return false;
}
// Are they layed out similarly?
foreach ( Layout* layout1, frame1->layouts() )
{
bool matchFound = false;
foreach ( Layout* layout2, frame2->layouts() )
{
if ( layout1->isSimilarTo(layout2) )
{
matchFound = true;
break;
}
}
if ( !matchFound )
{
return false;
}
}
return true;
}
} // namespace glabels::model
+117
View File
@@ -0,0 +1,117 @@
/* Template.h
*
* Copyright (C) 2013-2016 Jim Evins <evins@snaught.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef model_Template_h
#define model_Template_h
#include "Distance.h"
#include "Frame.h"
#include "Point.h"
#include <QCoreApplication>
#include <QString>
#include <QStringList>
#include <QList>
namespace glabels::model
{
class Template
{
Q_DECLARE_TR_FUNCTIONS(Template)
public:
Template( const QString& brand,
const QString& part,
const QString& description,
const QString& paperId,
const Distance& pageWidth,
const Distance& pageHeight );
Template( const Template& other );
Template* dup() const;
// Generic full page template
static Template* fullPage( const QString& paperId );
// From equivalent part number
static Template* fromEquiv( const QString& brand,
const QString& part,
const QString& equivPart );
QString brand() const;
QString part() const;
QString description() const;
QString paperId() const;
Distance pageWidth() const;
Distance pageHeight() const;
bool isSizeIso() const;
bool isSizeUs() const;
bool isSizeOther() const;
QString equivPart() const;
void setEquivPart( const QString& value );
QString productUrl() const;
void setProductUrl( const QString& value );
QString name() const;
void addCategory( const QString& categoryId );
void addFrame( Frame* frame );
const QList<Frame*>& frames() const;
bool operator==( const Template& other ) const;
bool hasCategory( const QString& categoryId ) const;
bool isSimilarTo( const Template* other ) const;
private:
QString mBrand;
QString mPart;
QString mDescription;
QString mPaperId;
Distance mPageWidth;
Distance mPageHeight;
bool mIsSizeIso;
bool mIsSizeUs;
QString mEquivPart;
QString mName;
QString mProductUrl;
QStringList mCategoryIds;
QList<Frame*> mFrames;
};
}
#endif // model_Template_h
+149
View File
@@ -0,0 +1,149 @@
/* TextNode.cpp
*
* Copyright (C) 2017 Jim Evins <evins@snaught.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "TextNode.h"
namespace glabels::model
{
///
/// Default Constructor
///
TextNode::TextNode()
: mIsField(false), mData("")
{
// empty
}
///
/// Constructor from Data
///
TextNode::TextNode( bool isField, const QString &data )
: mIsField(isField), mData(data)
{
// empty
}
///
/// == Operator
///
bool TextNode::operator==( const TextNode& other )
{
return (mIsField == other.mIsField) &&
(mData == other.mData);
}
///
/// != Operator
///
bool TextNode::operator!=( const TextNode& other )
{
return (mIsField != other.mIsField) ||
(mData != other.mData);
}
///
/// isField? Property Getter
///
bool TextNode::isField() const
{
return mIsField;
}
///
/// isField Flag Property Setter
///
void TextNode::setField( bool isField )
{
mIsField = isField;
}
///
/// Data Property Getter
///
const QString& TextNode::data() const
{
return mData;
}
///
/// Data Property Setter
///
void TextNode::setData( const QString& data )
{
mData = data;
}
///
/// Get text, expand if necessary
///
QString TextNode::text( merge::Record* record ) const
{
if ( mIsField )
{
if ( !record )
{
return QString("${%1}").arg( mData );
}
else
{
if ( record->contains( mData ) )
{
return (*record)[ mData ];
}
else
{
return "";
}
}
}
else
{
return mData;
}
}
///
/// 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;
}
} // namespace glabels::model
+94
View File
@@ -0,0 +1,94 @@
/* TextNode.h
*
* Copyright (C) 2017 Jim Evins <evins@snaught.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef model_TextNode_h
#define model_TextNode_h
#include "merge/Record.h"
#include <QString>
namespace glabels::model
{
///
/// Text Node Type
///
struct TextNode
{
/////////////////////////////////
// Life Cycle
/////////////////////////////////
public:
TextNode();
TextNode( bool isField, const QString &data );
/////////////////////////////////
// Operators
/////////////////////////////////
public:
bool operator==( const TextNode& other );
bool operator!=( const TextNode& other );
/////////////////////////////////
// Properties
/////////////////////////////////
public:
//
// is field? Property
//
bool isField() const;
void setField( bool isField );
//
// Data Property
//
const QString& data() const;
void setData( const QString& data );
/////////////////////////////////
// Misc. Methods
/////////////////////////////////
QString text( merge::Record* record ) const;
bool isEmptyField( merge::Record* record ) const;
/////////////////////////////////
// Private Data
/////////////////////////////////
private:
bool mIsField;
QString mData;
};
}
#endif // model_TextNode_h
+259
View File
@@ -0,0 +1,259 @@
/* Units.cpp
*
* Copyright (C) 2016 Jim Evins <evins@snaught.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "Units.h"
#include <QTextStream>
#include <QtDebug>
namespace glabels::model
{
Units::Units() : mEnumValue(PT)
{
// empty
}
Units::Units( Units::Enum enumValue ) : mEnumValue(enumValue)
{
switch (enumValue)
{
case PT:
case IN:
case MM:
case CM:
case PC:
/* Catch all valid enum values. */
break;
default:
/* Catch invalid enum values, reset to PT. */
qWarning() << "Bad Units::Enum value = " << enumValue << ".";
mEnumValue = PT;
break;
}
}
Units::Units( const QString& idString )
{
if ( idString == "pt" )
{
mEnumValue = PT;
}
else if ( idString == "in" )
{
mEnumValue = IN;
}
else if ( idString == "mm" )
{
mEnumValue = MM;
}
else if ( idString == "cm" )
{
mEnumValue = CM;
}
else if ( idString == "pc" )
{
mEnumValue = PC;
}
else
{
mEnumValue = PT;
}
}
Units Units::pt()
{
return Units(PT);
}
Units Units::in()
{
return Units(IN);
}
Units Units::mm()
{
return Units(MM);
}
Units Units::cm()
{
return Units(CM);
}
Units Units::pc()
{
return Units(PC);
}
Units::Enum Units::toEnum() const
{
return mEnumValue;
}
QString Units::toIdString() const
{
QString idString;
switch (mEnumValue)
{
case Units::PT:
idString = "pt";
break;
case Units::IN:
idString = "in";
break;
case Units::MM:
idString = "mm";
break;
case Units::CM:
idString = "cm";
break;
case Units::PC:
idString = "pc";
break;
}
return idString;
}
QString Units::toTrName() const
{
QString nameString;
switch (mEnumValue)
{
case Units::PT:
nameString = tr("points");
break;
case Units::IN:
nameString = tr("inches");
break;
case Units::MM:
nameString = tr("mm");
break;
case Units::CM:
nameString = tr("cm");
break;
case Units::PC:
nameString = tr("picas");
break;
}
return nameString;
}
double Units::resolution() const
{
double value;
switch (mEnumValue)
{
case Units::PT:
value = 0.01;
break;
case Units::IN:
value = 0.001;
break;
case Units::MM:
value = 0.01;
break;
case Units::CM:
value = 0.001;
break;
case Units::PC:
value = 0.01;
break;
}
return value;
}
int Units::resolutionDigits() const
{
int digits;
switch (mEnumValue)
{
case Units::PT:
digits = 2;
break;
case Units::IN:
digits = 3;
break;
case Units::MM:
digits = 2;
break;
case Units::CM:
digits = 3;
break;
case Units::PC:
digits = 2;
break;
}
return digits;
}
bool Units::isIdValid( const QString& idString )
{
bool retValue = false;
if ( idString == "pt" )
{
retValue = true;
}
else if ( idString == "in" )
{
retValue = true;
}
else if ( idString == "mm" )
{
retValue = true;
}
else if ( idString == "cm" )
{
retValue = true;
}
else if ( idString == "pc" )
{
retValue = true;
}
return retValue;
}
} // namespace glabels::model
+69
View File
@@ -0,0 +1,69 @@
/* Units.h
*
* Copyright (C) 2016 Jim Evins <evins@snaught.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef model_Units_h
#define model_Units_h
#include <QCoreApplication>
#include <QString>
namespace glabels::model
{
class Units
{
Q_DECLARE_TR_FUNCTIONS(Units)
public:
enum Enum { PT, IN, MM, CM, PC };
Units();
Units( Enum enumValue );
Units( const QString& idString );
static Units pt();
static Units in();
static Units mm();
static Units cm();
static Units pc();
Enum toEnum() const;
QString toIdString() const;
QString toTrName() const;
double resolution() const;
int resolutionDigits() const;
static bool isIdValid( const QString& unitsId );
private:
Enum mEnumValue;
};
}
#endif // model_Units_h
+44
View File
@@ -0,0 +1,44 @@
/* Vendor.cpp
*
* Copyright (C) 2013-2016 Jim Evins <evins@snaught.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "Vendor.h"
namespace glabels::model
{
Vendor::Vendor( const QString &name, const QString &url ) : mName(name), mUrl(url)
{
// empty
}
QString Vendor::name() const
{
return mName;
}
QString Vendor::url() const
{
return mUrl;
}
} // namespace glabels::model
+47
View File
@@ -0,0 +1,47 @@
/* Vendor.h
*
* Copyright (C) 2013-2016 Jim Evins <evins@snaught.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef model_Vendor_h
#define model_Vendor_h
#include <QString>
namespace glabels::model
{
class Vendor
{
public:
Vendor( const QString &name, const QString &url );
QString name() const;
QString url() const;
private:
QString mName;
QString mUrl;
};
}
#endif // model_Vendor_h
+40
View File
@@ -0,0 +1,40 @@
/* Version.h
*
* Copyright (C) 2016 Jim Evins <evins@snaught.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef model_Version_h
#define model_Version_h
namespace glabels::model
{
namespace Version
{
const QString WEBSITE = "@Website@";
const int MAJOR = @Major_Version@;
const int MINOR = @Minor_Version@;
const int MICRO = @Micro_Version@;
const QString STRING = "@Full_Version@";
}
}
#endif // model_Version_h
+103
View File
@@ -0,0 +1,103 @@
/* XmlCategoryParser.cpp
*
* Copyright (C) 2013-2016 Jim Evins <evins@snaught.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "XmlCategoryParser.h"
#include "Category.h"
#include "Db.h"
#include "XmlUtil.h"
#include <QDomDocument>
#include <QDomNode>
#include <QFile>
#include <QtDebug>
namespace glabels::model
{
bool XmlCategoryParser::readFile( const QString &fileName )
{
QFile file( fileName );
if ( !file.open( QFile::ReadOnly | QFile::Text) )
{
qWarning() << "Error: Cannot read file " << fileName
<< ": " << file.errorString();
return false;
}
QDomDocument doc;
QString errorString;
int errorLine;
int errorColumn;
if ( !doc.setContent( &file, false, &errorString, &errorLine, &errorColumn ) )
{
qWarning() << "Error: Parse error at line " << errorLine
<< "column " << errorColumn
<< ": " << errorString;
return false;
}
QDomElement root = doc.documentElement();
if ( root.tagName() != "Glabels-categories" )
{
qWarning() << "Error: Not a Glabels-categories file.";
return false;
}
parseRootNode( root );
return true;
}
void XmlCategoryParser::parseRootNode( const QDomElement &node )
{
for ( QDomNode child = node.firstChild(); !child.isNull(); child = child.nextSibling() )
{
if ( child.toElement().tagName() == "Category" )
{
parseCategoryNode( child.toElement() );
}
else if ( !child.isComment() )
{
qWarning() << "Warning: bad element: "
<< child.toElement().tagName()
<< ", Ignored.";
}
}
}
void XmlCategoryParser::parseCategoryNode( const QDomElement &node )
{
QString id = XmlUtil::getStringAttr( node, "id", "" );
QString name = XmlUtil::getI18nAttr( node, "name", "" );
Category *category = new Category( id, name );
if ( category != nullptr )
{
Db::registerCategory( category );
}
}
} // namespace glabels::model
+47
View File
@@ -0,0 +1,47 @@
/* XmlCategoryParser.h
*
* Copyright (C) 2013-2016 Jim Evins <evins@snaught.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef model_XmlCategoryParser_h
#define model_XmlCategoryParser_h
#include <QDomElement>
#include <QString>
namespace glabels::model
{
class XmlCategoryParser
{
public:
XmlCategoryParser() {}
bool readFile( const QString &fileName );
private:
void parseRootNode( const QDomElement &node );
void parseCategoryNode( const QDomElement &node );
};
}
#endif // model_XmlCategoryParser_h
+521
View File
@@ -0,0 +1,521 @@
/* XmlLabelCreator.cpp
*
* Copyright (C) 2014 Jim Evins <evins@snaught.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "XmlLabelCreator.h"
#include "Model.h"
#include "ModelObject.h"
#include "ModelBarcodeObject.h"
#include "ModelBoxObject.h"
#include "ModelEllipseObject.h"
#include "ModelLineObject.h"
#include "ModelImageObject.h"
#include "ModelTextObject.h"
#include "DataCache.h"
#include "XmlTemplateCreator.h"
#include "XmlUtil.h"
#include "merge/None.h"
#include <QByteArray>
#include <QFile>
#include <QTextBlock>
#include <QTextDocument>
#include <QBuffer>
#include <QtDebug>
namespace glabels::model
{
void
XmlLabelCreator::writeFile( const Model* label, 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();
}
file.write( buffer.data(), buffer.size() );
}
void
XmlLabelCreator::writeBuffer( const Model* label, QByteArray& buffer )
{
QDomDocument doc;
createDoc( doc, label );
buffer = doc.toByteArray( 2 );
}
void
XmlLabelCreator::serializeObjects( const QList<ModelObject*>& objects,
QByteArray& buffer )
{
QDomDocument doc;
QDomNode xmlNode( doc.createProcessingInstruction( "xml", "version=\"1.0\"" ) );
doc.appendChild( xmlNode );
QDomElement root = doc.createElement( "Glabels-objects" );
doc.appendChild( root );
XmlUtil::setStringAttr( root, "version", "4.0" );
createDataNode( root, objects );
createObjectsNode( root, objects, false );
buffer = doc.toByteArray( 2 );
}
void
XmlLabelCreator::createDoc( QDomDocument& doc, const Model* label )
{
QDomNode xmlNode( doc.createProcessingInstruction( "xml", "version=\"1.0\"" ) );
doc.appendChild( xmlNode );
QDomElement root = doc.createElement( "Glabels-document" );
doc.appendChild( root );
XmlUtil::setStringAttr( root, "version", "4.0" );
XmlTemplateCreator().createTemplateNode( root, label->tmplate() );
createObjectsNode( root, label->objectList(), label->rotate() );
if ( label->merge() && !dynamic_cast<merge::None*>(label->merge()) )
{
createMergeNode( root, label );
}
createDataNode( root, label->objectList() );
}
void
XmlLabelCreator::createObjectsNode( QDomElement &parent, const QList<ModelObject*>& objects, bool rotate )
{
QDomDocument doc = parent.ownerDocument();
QDomElement node = doc.createElement( "Objects" );
parent.appendChild( node );
XmlUtil::setStringAttr( node, "id", "0" );
XmlUtil::setBoolAttr( node, "rotate", rotate );
foreach ( ModelObject* object, objects )
{
if ( ModelBoxObject* boxObject = dynamic_cast<ModelBoxObject*>(object) )
{
createObjectBoxNode( node, boxObject );
}
else if ( ModelEllipseObject* ellipseObject = dynamic_cast<ModelEllipseObject*>(object) )
{
createObjectEllipseNode( node, ellipseObject );
}
else if ( ModelLineObject* lineObject = dynamic_cast<ModelLineObject*>(object) )
{
createObjectLineNode( node, lineObject );
}
else if ( ModelImageObject* imageObject = dynamic_cast<ModelImageObject*>(object) )
{
createObjectImageNode( node, imageObject );
}
else if ( ModelBarcodeObject* barcodeObject = dynamic_cast<ModelBarcodeObject*>(object) )
{
createObjectBarcodeNode( node, barcodeObject );
}
else if ( ModelTextObject* textObject = dynamic_cast<ModelTextObject*>(object) )
{
createObjectTextNode( node, textObject );
}
else
{
Q_ASSERT_X( false, "XmlLabelCreator::createObjectsNode", "Invalid object type." );
}
}
}
void
XmlLabelCreator::createObjectBoxNode( QDomElement &parent, const ModelBoxObject* object )
{
QDomDocument doc = parent.ownerDocument();
QDomElement node = doc.createElement( "Object-box" );
parent.appendChild( node );
/* position attrs */
createPositionAttrs( node, object );
/* size attrs */
createSizeAttrs( node, object );
/* line attrs */
createLineAttrs( node, object );
/* fill attrs */
createFillAttrs( node, object );
/* affine attrs */
createAffineAttrs( node, object );
/* shadow attrs */
createShadowAttrs( node, object );
}
void
XmlLabelCreator::createObjectEllipseNode( QDomElement &parent, const ModelEllipseObject* object )
{
QDomDocument doc = parent.ownerDocument();
QDomElement node = doc.createElement( "Object-ellipse" );
parent.appendChild( node );
/* position attrs */
createPositionAttrs( node, object );
/* size attrs */
createSizeAttrs( node, object );
/* line attrs */
createLineAttrs( node, object );
/* fill attrs */
createFillAttrs( node, object );
/* affine attrs */
createAffineAttrs( node, object );
/* shadow attrs */
createShadowAttrs( node, object );
}
void
XmlLabelCreator::createObjectLineNode( QDomElement &parent, const ModelLineObject* object )
{
QDomDocument doc = parent.ownerDocument();
QDomElement node = doc.createElement( "Object-line" );
parent.appendChild( node );
/* position attrs */
createPositionAttrs( node, object );
/* size attrs of line */
XmlUtil::setLengthAttr( node, "dx", object->w() );
XmlUtil::setLengthAttr( node, "dy", object->h() );
/* line attrs */
createLineAttrs( node, object );
/* affine attrs */
createAffineAttrs( node, object );
/* shadow attrs */
createShadowAttrs( node, object );
}
void
XmlLabelCreator::createObjectImageNode( QDomElement &parent, const ModelImageObject* object )
{
QDomDocument doc = parent.ownerDocument();
QDomElement node = doc.createElement( "Object-image" );
parent.appendChild( node );
/* position attrs */
createPositionAttrs( node, object );
/* size attrs */
createSizeAttrs( node, object );
/* file attrs */
if ( object->filenameNode().isField() )
{
XmlUtil::setStringAttr( node, "src_field", object->filenameNode().data() );
}
else
{
XmlUtil::setStringAttr( node, "src", object->filenameNode().data() );
}
/* affine attrs */
createAffineAttrs( node, object );
/* shadow attrs */
createShadowAttrs( node, object );
}
void
XmlLabelCreator::createObjectBarcodeNode( QDomElement &parent, const ModelBarcodeObject* object )
{
QDomDocument doc = parent.ownerDocument();
QDomElement node = doc.createElement( "Object-barcode" );
parent.appendChild( node );
/* position attrs */
createPositionAttrs( node, object );
/* size attrs */
createSizeAttrs( node, object );
/* barcode attrs */
XmlUtil::setStringAttr( node, "backend", object->bcStyle().backendId() );
XmlUtil::setStringAttr( node, "style", object->bcStyle().id() );
XmlUtil::setBoolAttr( node, "text", object->bcTextFlag() );
XmlUtil::setBoolAttr( node, "checksum", object->bcChecksumFlag() );
if ( object->bcColorNode().isField() )
{
XmlUtil::setStringAttr( node, "color_field", object->bcColorNode().key() );
}
else
{
XmlUtil::setUIntAttr( node, "color", object->bcColorNode().rgba() );
}
XmlUtil::setStringAttr( node, "data", object->bcData() );
/* affine attrs */
createAffineAttrs( node, object );
}
void
XmlLabelCreator::createObjectTextNode( QDomElement &parent, const ModelTextObject* object )
{
QDomDocument doc = parent.ownerDocument();
QDomElement node = doc.createElement( "Object-text" );
parent.appendChild( node );
/* position attrs */
createPositionAttrs( node, object );
/* size attrs */
createSizeAttrs( node, object );
/* color attr */
if ( object->textColorNode().isField() )
{
XmlUtil::setStringAttr( node, "color_field", object->textColorNode().key() );
}
else
{
XmlUtil::setUIntAttr( node, "color", object->textColorNode().rgba() );
}
/* font attrs */
XmlUtil::setStringAttr( node, "font_family", object->fontFamily() );
XmlUtil::setDoubleAttr( node, "font_size", object->fontSize() );
XmlUtil::setWeightAttr( node, "font_weight", object->fontWeight() );
XmlUtil::setBoolAttr( node, "font_italic", object->fontItalicFlag() );
XmlUtil::setBoolAttr( node, "font_underline", object->fontUnderlineFlag() );
/* text attrs */
XmlUtil::setDoubleAttr( node, "line_spacing", object->textLineSpacing() );
XmlUtil::setAlignmentAttr( node, "align", object->textHAlign() );
XmlUtil::setAlignmentAttr( node, "valign", object->textVAlign() );
/* affine attrs */
createAffineAttrs( node, object );
/* shadow attrs */
createShadowAttrs( node, object );
/* serialize text contents */
QTextDocument document( object->text() );
int nBlocks = document.blockCount();
for ( int iBlock = 0; iBlock < nBlocks; iBlock++ )
{
createPNode( node, document.findBlockByNumber(iBlock).text() );
}
}
void
XmlLabelCreator::createPNode( QDomElement &parent, const QString& blockText )
{
QDomDocument doc = parent.ownerDocument();
QDomElement node = doc.createElement( "p" );
parent.appendChild( node );
node.appendChild( doc.createTextNode( blockText ) );
}
void
XmlLabelCreator::createPositionAttrs( QDomElement &node, const ModelObject* object )
{
XmlUtil::setLengthAttr( node, "x", object->x0() );
XmlUtil::setLengthAttr( node, "y", object->y0() );
}
void
XmlLabelCreator::createSizeAttrs( QDomElement &node, const ModelObject* object )
{
XmlUtil::setLengthAttr( node, "w", object->w() );
XmlUtil::setLengthAttr( node, "h", object->h() );
}
void
XmlLabelCreator::createLineAttrs( QDomElement &node, const ModelObject* object )
{
XmlUtil::setLengthAttr( node, "line_width", object->lineWidth() );
if ( object->lineColorNode().isField() )
{
XmlUtil::setStringAttr( node, "line_color_field", object->lineColorNode().key() );
}
else
{
XmlUtil::setUIntAttr( node, "line_color", object->lineColorNode().rgba() );
}
}
void
XmlLabelCreator::createFillAttrs( QDomElement &node, const ModelObject* object )
{
if ( object->fillColorNode().isField() )
{
XmlUtil::setStringAttr( node, "fill_color_field", object->fillColorNode().key() );
}
else
{
XmlUtil::setUIntAttr( node, "fill_color", object->fillColorNode().rgba() );
}
}
void
XmlLabelCreator::createAffineAttrs( QDomElement &node, const ModelObject* object )
{
QMatrix a = object->matrix();
XmlUtil::setDoubleAttr( node, "a0", a.m11() );
XmlUtil::setDoubleAttr( node, "a1", a.m12() );
XmlUtil::setDoubleAttr( node, "a2", a.m21() );
XmlUtil::setDoubleAttr( node, "a3", a.m22() );
XmlUtil::setDoubleAttr( node, "a4", a.dx() );
XmlUtil::setDoubleAttr( node, "a5", a.dy() );
}
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::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 )
{
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() );
}
void
XmlLabelCreator::createDataNode( QDomElement &parent, const QList<ModelObject*>& objects )
{
QDomDocument doc = parent.ownerDocument();
QDomElement node = doc.createElement( "Data" );
parent.appendChild( node );
DataCache data( objects );
foreach ( QString name, data.imageNames() )
{
createPngFileNode( node, name, data.getImage( name ) );
}
foreach ( QString name, data.svgNames() )
{
createSvgFileNode( node, name, data.getSvg( name ) );
}
}
void
XmlLabelCreator::createPngFileNode( QDomElement &parent, const QString& name, const QImage& image )
{
QDomDocument doc = parent.ownerDocument();
QDomElement node = doc.createElement( "File" );
parent.appendChild( node );
XmlUtil::setStringAttr( node, "name", name );
XmlUtil::setStringAttr( node, "mimetype", "image/png" );
XmlUtil::setStringAttr( node, "encoding", "base64" );
QByteArray ba;
QBuffer buffer(&ba);
buffer.open(QIODevice::WriteOnly);
image.save(&buffer, "PNG");
QByteArray ba64 = ba.toBase64();
node.appendChild( doc.createTextNode( QString( ba64 ) ) );
}
void
XmlLabelCreator::createSvgFileNode( QDomElement &parent, const QString& name, const QByteArray& svg )
{
QDomDocument doc = parent.ownerDocument();
QDomElement node = doc.createElement( "File" );
parent.appendChild( node );
XmlUtil::setStringAttr( node, "name", name );
XmlUtil::setStringAttr( node, "mimetype", "image/svg+xml" );
XmlUtil::setStringAttr( node, "encoding", "cdata" );
node.appendChild( doc.createCDATASection( QString( svg ) ) );
}
} // namespace glabels::model
+82
View File
@@ -0,0 +1,82 @@
/* XmlLabelCreator.h
*
* Copyright (C) 2014 Jim Evins <evins@snaught.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef model_XmlLabelCreator_h
#define model_XmlLabelCreator_h
#include <QObject>
#include <QDomElement>
namespace glabels::model
{
// Forward references
class Model;
class ModelObject;
class ModelBoxObject;
class ModelEllipseObject;
class ModelLineObject;
class ModelImageObject;
class ModelBarcodeObject;
class ModelTextObject;
///
/// XmlLabelCreator
///
class XmlLabelCreator : public QObject
{
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<ModelObject*>& objects, QByteArray& buffer );
private:
static void createDoc( QDomDocument& doc, const Model* label );
static void createRootNode( const Model* label );
static void createObjectsNode( QDomElement &parent, const QList<ModelObject*>& 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<ModelObject*>& objects );
static void createPngFileNode( QDomElement &parent, const QString& name, const QImage& image );
static void createSvgFileNode( QDomElement &parent, const QString& name, const QByteArray& svg );
};
}
#endif // model_XmlLabelCreator_h
+754
View File
@@ -0,0 +1,754 @@
/* XmlLabelParser.cpp
*
* Copyright (C) 2014-2016 Jim Evins <evins@snaught.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "XmlLabelParser.h"
#include "Model.h"
#include "ModelObject.h"
#include "ModelBarcodeObject.h"
#include "ModelBoxObject.h"
#include "ModelEllipseObject.h"
#include "ModelImageObject.h"
#include "ModelLineObject.h"
#include "ModelTextObject.h"
#include "XmlTemplateParser.h"
#include "XmlUtil.h"
#include "DataCache.h"
#include "barcode/Backends.h"
#include "merge/Factory.h"
#include <QByteArray>
#include <QFile>
#include <QTextCursor>
#include <QTextDocument>
#include <QtDebug>
#include <zlib.h>
namespace glabels::model
{
Model*
XmlLabelParser::readFile( const QString& fileName )
{
QFile file( fileName );
if ( !file.open( QFile::ReadOnly ) )
{
qWarning() << "Error: Cannot read file" << fileName
<< ":" << file.errorString();
return nullptr;
}
QDomDocument doc;
bool success;
QString errorString;
int errorLine;
int errorColumn;
QByteArray rawData = file.readAll();
if ( ((rawData[0]&0xFF) == 0x1F) && ((rawData[1]&0xFF) == 0x8b) ) // gzip magic number 0x1F, 0x8B
{
// gzip compressed format
QByteArray unzippedData;
gunzip( rawData, unzippedData );
success = doc.setContent( unzippedData, false, &errorString, &errorLine, &errorColumn );
}
else
{
// plain text
success = doc.setContent( rawData, false, &errorString, &errorLine, &errorColumn );
}
if ( !success )
{
qWarning() << "Error: Parse error at line " << errorLine
<< "column " << errorColumn
<< ": " << errorString;
return nullptr;
}
QDomElement root = doc.documentElement();
if ( root.tagName() != "Glabels-document" )
{
qWarning() << "Error: Not a Glabels-document file";
return nullptr;
}
return parseRootNode( root );
}
Model*
XmlLabelParser::readBuffer( const QByteArray& buffer )
{
QDomDocument doc;
QString errorString;
int errorLine;
int errorColumn;
if ( !doc.setContent( buffer, false, &errorString, &errorLine, &errorColumn ) )
{
qWarning() << "Error: Parse error at line " << errorLine
<< "column " << errorColumn
<< ": " << errorString;
return nullptr;
}
QDomElement root = doc.documentElement();
if ( root.tagName() != "Glabels-document" )
{
qWarning() << "Error: Not a Glabels-document file";
return nullptr;
}
return parseRootNode( root );
}
QList<ModelObject*>
XmlLabelParser::deserializeObjects( const QByteArray& buffer )
{
QList<ModelObject*> list;
QDomDocument doc;
QString errorString;
int errorLine;
int errorColumn;
if ( !doc.setContent( buffer, false, &errorString, &errorLine, &errorColumn ) )
{
qWarning() << "Error: Parse error at line " << errorLine
<< "column " << errorColumn
<< ": " << errorString;
return list;
}
QDomElement root = doc.documentElement();
if ( root.tagName() != "Glabels-objects" )
{
qWarning() << "Error: Not a Glabels-objects stream";
return list;
}
/* Pass 1, extract data nodes to pre-load cache. */
DataCache data;
for ( QDomNode child = root.firstChild(); !child.isNull(); child = child.nextSibling() )
{
if ( child.toElement().tagName() == "Data" )
{
parseDataNode( child.toElement(), data );
}
}
/* Pass 2, now extract objects. */
for ( QDomNode child = root.firstChild(); !child.isNull(); child = child.nextSibling() )
{
if ( child.toElement().tagName() == "Objects" )
{
list = parseObjectsNode( child.toElement(), data );
}
}
return list;
}
void
XmlLabelParser::gunzip( const QByteArray& data, QByteArray& result )
{
result.clear();
if (data.size() <= 4) {
qWarning("XmlLabelParser::gunzip: Input data is truncated");
return;
}
// setup stream for inflate()
z_stream strm;
strm.zalloc = Z_NULL;
strm.zfree = Z_NULL;
strm.opaque = Z_NULL;
strm.avail_in = data.size();
strm.next_in = (Bytef*)(data.data());
int ret = inflateInit2(&strm, MAX_WBITS + 16); // gzip decoding
if (ret != Z_OK)
{
return;
}
static const int CHUNK_SIZE = 1024;
char out[CHUNK_SIZE];
// run inflate(), one chunk at a time
do {
strm.avail_out = CHUNK_SIZE;
strm.next_out = (Bytef*)(out);
ret = inflate(&strm, Z_NO_FLUSH);
Q_ASSERT(ret != Z_STREAM_ERROR); // state not clobbered
if ( (ret == Z_NEED_DICT) || (ret == Z_DATA_ERROR) || (ret == Z_MEM_ERROR) )
{
// clean up
inflateEnd(&strm);
return;
}
result.append(out, CHUNK_SIZE - strm.avail_out);
} while (strm.avail_out == 0);
// clean up
inflateEnd(&strm);
}
Model*
XmlLabelParser::parseRootNode( const QDomElement &node )
{
QString version = XmlUtil::getStringAttr( node, "version", "" );
if ( version != "4.0" )
{
qWarning() << "TODO: compatability mode.";
}
Model* label = new Model();
/* Pass 1, extract data nodes to pre-load cache. */
DataCache data;
for ( QDomNode child = node.firstChild(); !child.isNull(); child = child.nextSibling() )
{
if ( child.toElement().tagName() == "Data" )
{
parseDataNode( child.toElement(), data );
}
}
/* Pass 2, now extract everything else. */
for ( QDomNode child = node.firstChild(); !child.isNull(); child = child.nextSibling() )
{
QString tagName = child.toElement().tagName();
if ( tagName == "Template" )
{
Template* tmplate = XmlTemplateParser().parseTemplateNode( child.toElement() );
if ( tmplate == nullptr )
{
qWarning() << "Unable to parse template";
delete label;
return nullptr;
}
label->setTmplate( tmplate );
}
else if ( tagName == "Objects" )
{
label->setRotate( parseRotateAttr( child.toElement() ) );
QList<ModelObject*> list = parseObjectsNode( child.toElement(), data );
foreach ( ModelObject* object, list )
{
label->addObject( object );
}
}
else if ( tagName == "Merge" )
{
parseMergeNode( child.toElement(), label );
}
else if ( tagName == "Data" )
{
/* Handled in pass 1. */
}
else if ( !child.isComment() )
{
qWarning() << "Unexpected" << node.tagName() << "child:" << tagName;
}
}
label->clearModified();
return label;
}
QList<ModelObject*>
XmlLabelParser::parseObjectsNode( const QDomElement &node, const DataCache& data )
{
QList<ModelObject*> list;
for ( QDomNode child = node.firstChild(); !child.isNull(); child = child.nextSibling() )
{
QString tagName = child.toElement().tagName();
if ( tagName == "Object-box" )
{
list.append( parseObjectBoxNode( child.toElement() ) );
}
else if ( tagName == "Object-ellipse" )
{
list.append( parseObjectEllipseNode( child.toElement() ) );
}
else if ( tagName == "Object-line" )
{
list.append( parseObjectLineNode( child.toElement() ) );
}
else if ( tagName == "Object-text" )
{
list.append( parseObjectTextNode( child.toElement() ) );
}
else if ( tagName == "Object-image" )
{
list.append( parseObjectImageNode( child.toElement(), data ) );
}
else if ( tagName == "Object-barcode" )
{
list.append( parseObjectBarcodeNode( child.toElement() ) );
}
else if ( !child.isComment() )
{
qWarning() << "Unexpected" << node.tagName() << "child:" << tagName;
}
}
return list;
}
ModelBoxObject*
XmlLabelParser::parseObjectBoxNode( const QDomElement &node )
{
/* position attrs */
Distance x0 = XmlUtil::getLengthAttr( node, "x", 0.0 );
Distance y0 = XmlUtil::getLengthAttr( node, "y", 0.0 );
/* size attrs */
Distance w = XmlUtil::getLengthAttr( node, "w", 0 );
Distance h = XmlUtil::getLengthAttr( node, "h", 0 );
/* 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 );
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 );
ColorNode fillColorNode( field_flag, color, key );
/* affine attrs */
double a[6];
a[0] = XmlUtil::getDoubleAttr( node, "a0", 1.0 );
a[1] = XmlUtil::getDoubleAttr( node, "a1", 0.0 );
a[2] = XmlUtil::getDoubleAttr( node, "a2", 0.0 );
a[3] = XmlUtil::getDoubleAttr( node, "a3", 1.0 );
a[4] = XmlUtil::getDoubleAttr( node, "a4", 0.0 );
a[5] = XmlUtil::getDoubleAttr( node, "a5", 0.0 );
/* shadow attrs */
bool shadowState = XmlUtil::getBoolAttr( node, "shadow", false );
Distance shadowX = XmlUtil::getLengthAttr( node, "shadow_x", 0.0 );
Distance shadowY = XmlUtil::getLengthAttr( node, "shadow_y", 0.0 );
double shadowOpacity = XmlUtil::getDoubleAttr( node, "shadow_opacity", 1.0 );
key = XmlUtil::getStringAttr( node, "shadow_color_field", "" );
field_flag = !key.isEmpty();
color = XmlUtil::getUIntAttr( node, "shadow_color", 0 );
ColorNode shadowColorNode( field_flag, color, key );
return new ModelBoxObject( x0, y0, w, h,
lineWidth, lineColorNode,
fillColorNode,
QMatrix( a[0], a[1], a[2], a[3], a[4], a[5] ),
shadowState, shadowX, shadowY, shadowOpacity, shadowColorNode );
}
ModelEllipseObject*
XmlLabelParser::parseObjectEllipseNode( const QDomElement &node )
{
/* position attrs */
Distance x0 = XmlUtil::getLengthAttr( node, "x", 0.0 );
Distance y0 = XmlUtil::getLengthAttr( node, "y", 0.0 );
/* size attrs */
Distance w = XmlUtil::getLengthAttr( node, "w", 0 );
Distance h = XmlUtil::getLengthAttr( node, "h", 0 );
/* 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 );
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 );
ColorNode fillColorNode( field_flag, color, key );
/* affine attrs */
double a[6];
a[0] = XmlUtil::getDoubleAttr( node, "a0", 1.0 );
a[1] = XmlUtil::getDoubleAttr( node, "a1", 0.0 );
a[2] = XmlUtil::getDoubleAttr( node, "a2", 0.0 );
a[3] = XmlUtil::getDoubleAttr( node, "a3", 1.0 );
a[4] = XmlUtil::getDoubleAttr( node, "a4", 0.0 );
a[5] = XmlUtil::getDoubleAttr( node, "a5", 0.0 );
/* shadow attrs */
bool shadowState = XmlUtil::getBoolAttr( node, "shadow", false );
Distance shadowX = XmlUtil::getLengthAttr( node, "shadow_x", 0.0 );
Distance shadowY = XmlUtil::getLengthAttr( node, "shadow_y", 0.0 );
double shadowOpacity = XmlUtil::getDoubleAttr( node, "shadow_opacity", 1.0 );
key = XmlUtil::getStringAttr( node, "shadow_color_field", "" );
field_flag = !key.isEmpty();
color = XmlUtil::getUIntAttr( node, "shadow_color", 0 );
ColorNode shadowColorNode( field_flag, color, key );
return new ModelEllipseObject( x0, y0, w, h,
lineWidth, lineColorNode,
fillColorNode,
QMatrix( a[0], a[1], a[2], a[3], a[4], a[5] ),
shadowState, shadowX, shadowY, shadowOpacity, shadowColorNode );
}
ModelLineObject*
XmlLabelParser::parseObjectLineNode( const QDomElement &node )
{
/* position attrs */
Distance x0 = XmlUtil::getLengthAttr( node, "x", 0.0 );
Distance y0 = XmlUtil::getLengthAttr( node, "y", 0.0 );
/* size attrs of line */
Distance dx = XmlUtil::getLengthAttr( node, "dx", 0 );
Distance dy = XmlUtil::getLengthAttr( node, "dy", 0 );
/* 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 );
ColorNode lineColorNode( field_flag, color, key );
/* affine attrs */
double a[6];
a[0] = XmlUtil::getDoubleAttr( node, "a0", 1.0 );
a[1] = XmlUtil::getDoubleAttr( node, "a1", 0.0 );
a[2] = XmlUtil::getDoubleAttr( node, "a2", 0.0 );
a[3] = XmlUtil::getDoubleAttr( node, "a3", 1.0 );
a[4] = XmlUtil::getDoubleAttr( node, "a4", 0.0 );
a[5] = XmlUtil::getDoubleAttr( node, "a5", 0.0 );
/* shadow attrs */
bool shadowState = XmlUtil::getBoolAttr( node, "shadow", false );
Distance shadowX = XmlUtil::getLengthAttr( node, "shadow_x", 0.0 );
Distance shadowY = XmlUtil::getLengthAttr( node, "shadow_y", 0.0 );
double shadowOpacity = XmlUtil::getDoubleAttr( node, "shadow_opacity", 1.0 );
key = XmlUtil::getStringAttr( node, "shadow_color_field", "" );
field_flag = !key.isEmpty();
color = XmlUtil::getUIntAttr( node, "shadow_color", 0 );
ColorNode shadowColorNode( field_flag, color, key );
return new ModelLineObject( x0, y0, dx, dy,
lineWidth, lineColorNode,
QMatrix( a[0], a[1], a[2], a[3], a[4], a[5] ),
shadowState, shadowX, shadowY, shadowOpacity, shadowColorNode );
}
ModelImageObject*
XmlLabelParser::parseObjectImageNode( const QDomElement &node, const DataCache& data )
{
/* position attrs */
Distance x0 = XmlUtil::getLengthAttr( node, "x", 0.0 );
Distance y0 = XmlUtil::getLengthAttr( node, "y", 0.0 );
/* size attrs */
Distance w = XmlUtil::getLengthAttr( node, "w", 0 );
Distance h = XmlUtil::getLengthAttr( node, "h", 0 );
/* file attrs */
QString key = XmlUtil::getStringAttr( node, "src_field", "" );
bool field_flag = !key.isEmpty();
QString filename = XmlUtil::getStringAttr( node, "src", "" );
TextNode filenameNode( field_flag, field_flag ? key : filename );
/* affine attrs */
double a[6];
a[0] = XmlUtil::getDoubleAttr( node, "a0", 1.0 );
a[1] = XmlUtil::getDoubleAttr( node, "a1", 0.0 );
a[2] = XmlUtil::getDoubleAttr( node, "a2", 0.0 );
a[3] = XmlUtil::getDoubleAttr( node, "a3", 1.0 );
a[4] = XmlUtil::getDoubleAttr( node, "a4", 0.0 );
a[5] = XmlUtil::getDoubleAttr( node, "a5", 0.0 );
/* shadow attrs */
bool shadowState = XmlUtil::getBoolAttr( node, "shadow", false );
Distance shadowX = XmlUtil::getLengthAttr( node, "shadow_x", 0.0 );
Distance shadowY = XmlUtil::getLengthAttr( node, "shadow_y", 0.0 );
double shadowOpacity = XmlUtil::getDoubleAttr( node, "shadow_opacity", 1.0 );
key = XmlUtil::getStringAttr( node, "shadow_color_field", "" );
field_flag = !key.isEmpty();
uint32_t color = XmlUtil::getUIntAttr( node, "shadow_color", 0 );
ColorNode shadowColorNode( field_flag, color, key );
if ( filenameNode.isField() )
{
return new ModelImageObject( x0, y0, w, h,
filenameNode,
QMatrix( a[0], a[1], a[2], a[3], a[4], a[5] ),
shadowState, shadowX, shadowY, shadowOpacity, shadowColorNode );
}
else
{
if ( data.hasImage( filename ) )
{
return new ModelImageObject( x0, y0, w, h,
filename, data.getImage( filename ),
QMatrix( a[0], a[1], a[2], a[3], a[4], a[5] ),
shadowState, shadowX, shadowY, shadowOpacity, shadowColorNode );
}
else if ( data.hasSvg( filename ) )
{
return new ModelImageObject( x0, y0, w, h,
filename, data.getSvg( filename ),
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,
filenameNode,
QMatrix( a[0], a[1], a[2], a[3], a[4], a[5] ),
shadowState, shadowX, shadowY, shadowOpacity, shadowColorNode );
}
}
}
ModelBarcodeObject*
XmlLabelParser::parseObjectBarcodeNode( const QDomElement &node )
{
/* position attrs */
Distance x0 = XmlUtil::getLengthAttr( node, "x", 0.0 );
Distance y0 = XmlUtil::getLengthAttr( node, "y", 0.0 );
/* size attrs */
Distance w = XmlUtil::getLengthAttr( node, "w", 0 );
Distance h = XmlUtil::getLengthAttr( node, "h", 0 );
/* barcode attrs */
barcode::Style bcStyle = barcode::Backends::style( XmlUtil::getStringAttr( node, "backend", "" ),
XmlUtil::getStringAttr( node, "style", "") );
bool bcTextFlag = XmlUtil::getBoolAttr( node, "text", true );
bool bcChecksumFlag = XmlUtil::getBoolAttr( node, "checksum", true );
QString key = XmlUtil::getStringAttr( node, "color_field", "" );
bool field_flag = !key.isEmpty();
uint32_t color = XmlUtil::getUIntAttr( node, "color", 0 );
ColorNode bcColorNode( field_flag, color, key );
QString bcData = XmlUtil::getStringAttr( node, "data", "" );
/* affine attrs */
double a[6];
a[0] = XmlUtil::getDoubleAttr( node, "a0", 1.0 );
a[1] = XmlUtil::getDoubleAttr( node, "a1", 0.0 );
a[2] = XmlUtil::getDoubleAttr( node, "a2", 0.0 );
a[3] = XmlUtil::getDoubleAttr( node, "a3", 1.0 );
a[4] = XmlUtil::getDoubleAttr( node, "a4", 0.0 );
a[5] = XmlUtil::getDoubleAttr( node, "a5", 0.0 );
return new ModelBarcodeObject( x0, y0, w, h,
bcStyle, bcTextFlag, bcChecksumFlag, bcData, bcColorNode,
QMatrix( a[0], a[1], a[2], a[3], a[4], a[5] ) );
}
ModelTextObject*
XmlLabelParser::parseObjectTextNode( const QDomElement &node )
{
/* position attrs */
Distance x0 = XmlUtil::getLengthAttr( node, "x", 0.0 );
Distance y0 = XmlUtil::getLengthAttr( node, "y", 0.0 );
/* size attrs */
Distance w = XmlUtil::getLengthAttr( node, "w", 0 );
Distance h = XmlUtil::getLengthAttr( node, "h", 0 );
/* color attr */
QString key = XmlUtil::getStringAttr( node, "color_field", "" );
bool field_flag = !key.isEmpty();
uint32_t color = XmlUtil::getUIntAttr( node, "color", 0 );
ColorNode textColorNode( field_flag, color, key );
/* font attrs */
QString fontFamily = XmlUtil::getStringAttr( node, "font_family", "Sans" );
double fontSize = XmlUtil::getDoubleAttr( node, "font_size", 10 );
QFont::Weight fontWeight = XmlUtil::getWeightAttr( node, "font_weight", QFont::Normal );
bool fontItalicFlag = XmlUtil::getBoolAttr( node, "font_italic", false );
bool fontUnderlineFlag = XmlUtil::getBoolAttr( node, "font_underline", false );
/* text attrs */
double textLineSpacing = XmlUtil::getDoubleAttr( node, "line_spacing", 1 );
Qt::Alignment textHAlign = XmlUtil::getAlignmentAttr( node, "align", Qt::AlignLeft );
Qt::Alignment textVAlign = XmlUtil::getAlignmentAttr( node, "valign", Qt::AlignTop );
/* affine attrs */
double a[6];
a[0] = XmlUtil::getDoubleAttr( node, "a0", 1.0 );
a[1] = XmlUtil::getDoubleAttr( node, "a1", 0.0 );
a[2] = XmlUtil::getDoubleAttr( node, "a2", 0.0 );
a[3] = XmlUtil::getDoubleAttr( node, "a3", 1.0 );
a[4] = XmlUtil::getDoubleAttr( node, "a4", 0.0 );
a[5] = XmlUtil::getDoubleAttr( node, "a5", 0.0 );
/* shadow attrs */
bool shadowState = XmlUtil::getBoolAttr( node, "shadow", false );
Distance shadowX = XmlUtil::getLengthAttr( node, "shadow_x", 0.0 );
Distance shadowY = XmlUtil::getLengthAttr( node, "shadow_y", 0.0 );
double shadowOpacity = XmlUtil::getDoubleAttr( node, "shadow_opacity", 1.0 );
key = XmlUtil::getStringAttr( node, "shadow_color_field", "" );
field_flag = !key.isEmpty();
color = XmlUtil::getUIntAttr( node, "shadow_color", 0 );
ColorNode shadowColorNode( field_flag, color, key );
/* deserialize contents. */
QTextDocument document;
QTextCursor cursor( &document );
bool firstBlock = true;
for ( QDomNode child = node.firstChild(); !child.isNull(); child = child.nextSibling() )
{
QString tagName = child.toElement().tagName();
if ( tagName == "p" )
{
if ( !firstBlock )
{
cursor.insertBlock();
}
firstBlock = false;
cursor.insertText( parsePNode( child.toElement() ) );
}
else if ( !child.isComment() )
{
qWarning() << "Unexpected" << node.tagName() << "child:" << tagName;
}
}
QString text = document.toPlainText();
return new ModelTextObject( x0, y0, w, h,
text,
fontFamily, fontSize, fontWeight, fontItalicFlag, fontUnderlineFlag,
textColorNode, textHAlign, textVAlign, textLineSpacing,
QMatrix( a[0], a[1], a[2], a[3], a[4], a[5] ),
shadowState, shadowX, shadowY, shadowOpacity, shadowColorNode );
}
QString
XmlLabelParser::parsePNode( const QDomElement &node )
{
return node.text();
}
bool
XmlLabelParser::parseRotateAttr( const QDomElement &node )
{
return XmlUtil::getBoolAttr( node, "rotate", false );
}
void
XmlLabelParser::parseMergeNode( const QDomElement &node, Model* label )
{
QString type = XmlUtil::getStringAttr( node, "type", "None" );
QString src = XmlUtil::getStringAttr( node, "src", "" );
merge::Merge* merge = merge::Factory::createMerge( type );
merge->setSource( src );
label->setMerge( merge );
}
void
XmlLabelParser::parseDataNode( const QDomElement &node, DataCache& data )
{
for ( QDomNode child = node.firstChild(); !child.isNull(); child = child.nextSibling() )
{
QString tagName = child.toElement().tagName();
if ( tagName == "File" )
{
parseFileNode( child.toElement(), data );
}
else if ( !child.isComment() )
{
qWarning() << "Unexpected" << node.tagName() << "child:" << tagName;
}
}
}
void
XmlLabelParser::parsePixdataNode( const QDomElement& node, DataCache& data )
{
// TODO, compatability with glabels-3
}
void
XmlLabelParser::parseFileNode( const QDomElement& node, DataCache& data )
{
QString name = XmlUtil::getStringAttr( node, "name", "" );
QString mimetype = XmlUtil::getStringAttr( node, "mimetype", "image/png" );
QString encoding = XmlUtil::getStringAttr( node, "encoding", "base64" );
if ( mimetype == "image/png" )
{
QByteArray ba64 = node.text().toUtf8();
QByteArray ba = QByteArray::fromBase64( ba64 );
QImage image;
image.loadFromData( ba, "PNG" );
data.addImage( name, image );
}
else if ( mimetype == "image/svg+xml" )
{
data.addSvg( name, node.text().toUtf8() );
}
}
} // namespace glabels::model
+78
View File
@@ -0,0 +1,78 @@
/* XmlLabelParser.h
*
* Copyright (C) 2014-2016 Jim Evins <evins@snaught.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef model_XmlLabelParser_h
#define model_XmlLabelParser_h
#include <QObject>
#include <QDomElement>
namespace glabels::model
{
// Forward references
class Model;
class ModelObject;
class ModelBoxObject;
class ModelEllipseObject;
class ModelLineObject;
class ModelImageObject;
class ModelBarcodeObject;
class ModelTextObject;
class DataCache;
///
/// XmlLabelParser
///
class XmlLabelParser : public QObject
{
Q_OBJECT
public:
static Model* readFile( const QString& fileName );
static Model* readBuffer( const QByteArray& buffer );
static QList<ModelObject*> deserializeObjects( const QByteArray& buffer );
private:
static void gunzip( const QByteArray& gzippedData, QByteArray& data );
static Model* parseRootNode( const QDomElement &node );
static QList<ModelObject*> 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 );
};
}
#endif // model_XmlLabelParser_h
+108
View File
@@ -0,0 +1,108 @@
/* XmlPaperParser.cpp
*
* Copyright (C) 2013-2016 Jim Evins <evins@snaught.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "XmlPaperParser.h"
#include "Db.h"
#include "Paper.h"
#include "XmlUtil.h"
#include <QDomDocument>
#include <QDomNode>
#include <QFile>
#include <QtDebug>
namespace glabels::model
{
bool XmlPaperParser::readFile( const QString &fileName )
{
QFile file( fileName );
if ( !file.open( QFile::ReadOnly | QFile::Text ) )
{
qWarning() << "Error: Cannot read file " << fileName
<< ": " << file.errorString();
return false;
}
QDomDocument doc;
QString errorString;
int errorLine;
int errorColumn;
if ( !doc.setContent( &file, false, &errorString, &errorLine, &errorColumn ) )
{
qWarning() << "Error: Parse error at line " << errorLine
<< "column " << errorColumn
<< ": " << errorString;
return false;
}
QDomElement root = doc.documentElement();
if ( root.tagName() != "Glabels-paper-sizes" )
{
qWarning() << "Error: Not a Glabels-paper-sizes file.";
return false;
}
parseRootNode( root );
return true;
}
void XmlPaperParser::parseRootNode( const QDomElement &node )
{
for ( QDomNode child = node.firstChild(); !child.isNull(); child = child.nextSibling() )
{
if ( child.toElement().tagName() == "Paper-size" )
{
parsePaperSizeNode( child.toElement() );
}
else if ( !child.isComment() )
{
qWarning() << "Warning: bad element: "
<< child.toElement().tagName()
<< ", Ignored.";
}
}
}
void XmlPaperParser::parsePaperSizeNode( const QDomElement &node )
{
QString id = XmlUtil::getStringAttr( node, "id", "" );
QString name = XmlUtil::getI18nAttr( node, "name", "" );
Distance width = XmlUtil::getLengthAttr( node, "width", Distance(0) );
Distance height = XmlUtil::getLengthAttr( node, "height", Distance(0) );
QString pwgSize = XmlUtil::getStringAttr( node, "pwg_size", "" );
Paper *paper = new Paper( id, name, width, height, pwgSize );
if ( paper != nullptr )
{
Db::registerPaper( paper );
}
}
} // namespace glabels::model
+47
View File
@@ -0,0 +1,47 @@
/* XmlPaperParser.h
*
* Copyright (C) 2013-2016 Jim Evins <evins@snaught.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef model_XmlPaperParser_h
#define model_XmlPaperParser_h
#include <QString>
#include <QDomElement>
namespace glabels::model
{
class XmlPaperParser
{
public:
XmlPaperParser() {}
bool readFile( const QString &fileName );
private:
void parseRootNode( const QDomElement &node );
void parsePaperSizeNode( const QDomElement &node );
};
}
#endif // model_XmlPaperParser_h
+333
View File
@@ -0,0 +1,333 @@
/* XmlTemplateCreator.cpp
*
* Copyright (C) 2013-2016 Jim Evins <evins@snaught.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "XmlTemplateCreator.h"
#include "Db.h"
#include "Template.h"
#include "XmlUtil.h"
#include <QDomNode>
#include <QFile>
#include <QtDebug>
namespace glabels::model
{
bool XmlTemplateCreator::writeTemplates( const QList<const Template*> tmplates, const QString &fileName )
{
QDomDocument doc( "Glabels-templates" );
QDomElement root = doc.createElement( "Glabels-templates" );
doc.appendChild( root );
foreach ( const Template* tmplate, tmplates )
{
createTemplateNode( root, tmplate );
}
QFile file( fileName );
if ( !file.open( QFile::WriteOnly | QFile::Text) )
{
qWarning() << "Error: Cannot open file " << fileName
<< ": " << file.errorString();
return false;
}
if ( file.write( doc.toByteArray() ) < 0 )
{
qWarning() << "Error: Cannot write file " << fileName
<< ": " << file.errorString();
return false;
}
return true;
}
bool XmlTemplateCreator::writeTemplate( const Template* tmplate, const QString& fileName )
{
QList<const Template*> tmplates;
tmplates.append(tmplate);
return writeTemplates( tmplates, fileName );
}
void XmlTemplateCreator::createTemplateNode( QDomElement &parent, const Template* tmplate )
{
QDomDocument doc = parent.ownerDocument();
QDomElement node = doc.createElement( "Template" );
parent.appendChild( node );
XmlUtil::setStringAttr( node, "brand", tmplate->brand() );
XmlUtil::setStringAttr( node, "part", tmplate->part() );
XmlUtil::setStringAttr( node, "size", tmplate->paperId() );
if ( tmplate->isSizeOther() )
{
XmlUtil::setLengthAttr( node, "width", tmplate->pageWidth() );
XmlUtil::setLengthAttr( node, "height", tmplate->pageHeight() );
}
XmlUtil::setStringAttr( node, "description", tmplate->description() );
if ( !tmplate->productUrl().isEmpty() )
{
createMetaNode( node, "product_url", tmplate->productUrl() );
}
#if TODO
foreach ( QString categoryId, tmplate->categoryIds() )
{
createMetaNode( node, "category", categoryId );
}
#endif
foreach ( Frame* frame, tmplate->frames() )
{
createLabelNode( node, frame );
}
}
void XmlTemplateCreator::createMetaNode( QDomElement &parent, const QString& attr, const QString& value )
{
QDomDocument doc = parent.ownerDocument();
QDomElement node = doc.createElement( "Meta" );
parent.appendChild( node );
XmlUtil::setStringAttr( node, attr, value );
}
void XmlTemplateCreator::createLabelNode( QDomElement &parent, const Frame* frame )
{
if ( const FrameRect* frameRect = dynamic_cast<const FrameRect*>(frame) )
{
createLabelRectangleNode( parent, frameRect );
}
else if ( const FrameEllipse* frameEllipse = dynamic_cast<const FrameEllipse*>(frame) )
{
createLabelEllipseNode( parent, frameEllipse );
}
else if ( const FrameRound* frameRound = dynamic_cast<const FrameRound*>(frame) )
{
createLabelRoundNode( parent, frameRound );
}
else if ( const FrameCd* frameCd = dynamic_cast<const FrameCd*>(frame) )
{
createLabelCdNode( parent, frameCd );
}
else
{
Q_ASSERT_X( false, "XmlTemplateCreator::createLabelNode", "Invalid frame type." );
}
}
void XmlTemplateCreator::createLabelRectangleNode( QDomElement &parent, const FrameRect* frame )
{
QDomDocument doc = parent.ownerDocument();
QDomElement node = doc.createElement( "Label-rectangle" );
parent.appendChild( node );
XmlUtil::setStringAttr( node, "id", frame->id() );
XmlUtil::setLengthAttr( node, "width", frame->w() );
XmlUtil::setLengthAttr( node, "height", frame->h() );
XmlUtil::setLengthAttr( node, "round", frame->r() );
XmlUtil::setLengthAttr( node, "x_waste", frame->xWaste() );
XmlUtil::setLengthAttr( node, "y_waste", frame->yWaste() );
createLabelNodeCommon( node, frame );
}
void XmlTemplateCreator::createLabelEllipseNode( QDomElement &parent, const FrameEllipse* frame )
{
QDomDocument doc = parent.ownerDocument();
QDomElement node = doc.createElement( "Label-ellipse" );
parent.appendChild( node );
XmlUtil::setStringAttr( node, "id", frame->id() );
XmlUtil::setLengthAttr( node, "width", frame->w() );
XmlUtil::setLengthAttr( node, "height", frame->h() );
XmlUtil::setLengthAttr( node, "waste", frame->waste() );
createLabelNodeCommon( node, frame );
}
void XmlTemplateCreator::createLabelRoundNode( QDomElement &parent, const FrameRound* frame )
{
QDomDocument doc = parent.ownerDocument();
QDomElement node = doc.createElement( "Label-round" );
parent.appendChild( node );
XmlUtil::setStringAttr( node, "id", frame->id() );
XmlUtil::setLengthAttr( node, "radius", frame->r() );
XmlUtil::setLengthAttr( node, "waste", frame->waste() );
createLabelNodeCommon( node, frame );
}
void XmlTemplateCreator::createLabelCdNode( QDomElement &parent, const FrameCd* frame )
{
QDomDocument doc = parent.ownerDocument();
QDomElement node = doc.createElement( "Label-cd" );
parent.appendChild( node );
XmlUtil::setStringAttr( node, "id", frame->id() );
XmlUtil::setLengthAttr( node, "radius", frame->r1() );
XmlUtil::setLengthAttr( node, "hole", frame->r2() );
XmlUtil::setLengthAttr( node, "waste", frame->waste() );
if ( frame->w() != Distance(0) )
{
XmlUtil::setLengthAttr( node, "width", frame->w() );
}
if ( frame->h() != Distance(0) )
{
XmlUtil::setLengthAttr( node, "height", frame->h() );
}
createLabelNodeCommon( node, frame );
}
void XmlTemplateCreator::createLabelNodeCommon( QDomElement &node, const Frame *frame )
{
foreach ( Markup* markup, frame->markups() )
{
if ( MarkupMargin* markupMargin = dynamic_cast<MarkupMargin*>(markup) )
{
createMarkupMarginNode( node, markupMargin );
}
else if ( MarkupLine* markupLine = dynamic_cast<MarkupLine*>(markup) )
{
createMarkupLineNode( node, markupLine );
}
else if ( MarkupCircle* markupCircle = dynamic_cast<MarkupCircle*>(markup) )
{
createMarkupCircleNode( node, markupCircle );
}
else if ( MarkupRect* markupRect = dynamic_cast<MarkupRect*>(markup) )
{
createMarkupRectNode( node, markupRect );
}
else if ( MarkupEllipse* markupEllipse = dynamic_cast<MarkupEllipse*>(markup) )
{
createMarkupEllipseNode( node, markupEllipse );
}
else
{
Q_ASSERT_X( false, "XmlTemplateCreator::createLabelNodeCommon", "Invalid markup type." );
}
}
foreach ( Layout* layout, frame->layouts() )
{
createLayoutNode( node, layout );
}
}
void XmlTemplateCreator::createLayoutNode( QDomElement& parent, const Layout* layout )
{
QDomDocument doc = parent.ownerDocument();
QDomElement node = doc.createElement( "Layout" );
parent.appendChild( node );
XmlUtil::setIntAttr( node, "nx", layout->nx() );
XmlUtil::setIntAttr( node, "ny", layout->ny() );
XmlUtil::setLengthAttr( node, "x0", layout->x0() );
XmlUtil::setLengthAttr( node, "y0", layout->y0() );
XmlUtil::setLengthAttr( node, "dx", layout->dx() );
XmlUtil::setLengthAttr( node, "dy", layout->dy() );
}
void XmlTemplateCreator::createMarkupMarginNode( QDomElement& parent, const MarkupMargin* markup )
{
QDomDocument doc = parent.ownerDocument();
QDomElement node = doc.createElement( "Markup-margin" );
parent.appendChild( node );
XmlUtil::setLengthAttr( node, "size", markup->size() );
}
void XmlTemplateCreator::createMarkupLineNode( QDomElement& parent, const MarkupLine* markup )
{
QDomDocument doc = parent.ownerDocument();
QDomElement node = doc.createElement( "Markup-line" );
parent.appendChild( node );
XmlUtil::setLengthAttr( node, "x1", markup->x1() );
XmlUtil::setLengthAttr( node, "y1", markup->y1() );
XmlUtil::setLengthAttr( node, "x2", markup->x2() );
XmlUtil::setLengthAttr( node, "y2", markup->y2() );
}
void XmlTemplateCreator::createMarkupCircleNode( QDomElement& parent, const MarkupCircle* markup )
{
QDomDocument doc = parent.ownerDocument();
QDomElement node = doc.createElement( "Markup-circle" );
parent.appendChild( node );
XmlUtil::setLengthAttr( node, "x0", markup->x0() );
XmlUtil::setLengthAttr( node, "y0", markup->y0() );
XmlUtil::setLengthAttr( node, "radius", markup->r() );
}
void XmlTemplateCreator::createMarkupRectNode( QDomElement& parent, const MarkupRect* markup )
{
QDomDocument doc = parent.ownerDocument();
QDomElement node = doc.createElement( "Markup-rect" );
parent.appendChild( node );
XmlUtil::setLengthAttr( node, "x1", markup->x1() );
XmlUtil::setLengthAttr( node, "y1", markup->y1() );
XmlUtil::setLengthAttr( node, "w", markup->w() );
XmlUtil::setLengthAttr( node, "h", markup->h() );
XmlUtil::setLengthAttr( node, "r", markup->r() );
}
void XmlTemplateCreator::createMarkupEllipseNode( QDomElement& parent, const MarkupEllipse* markup )
{
QDomDocument doc = parent.ownerDocument();
QDomElement node = doc.createElement( "Markup-ellipse" );
parent.appendChild( node );
XmlUtil::setLengthAttr( node, "x1", markup->x1() );
XmlUtil::setLengthAttr( node, "y1", markup->y1() );
XmlUtil::setLengthAttr( node, "w", markup->w() );
XmlUtil::setLengthAttr( node, "h", markup->h() );
}
} // namespace glabels::model
+69
View File
@@ -0,0 +1,69 @@
/* XmlTemplateCreator.h
*
* Copyright (C) 2013-2016 Jim Evins <evins@snaught.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef model_XmlTemplateCreator_h
#define model_XmlTemplateCreator_h
#include "FrameCd.h"
#include "FrameEllipse.h"
#include "FrameRect.h"
#include "FrameRound.h"
#include "Layout.h"
#include "Markup.h"
#include "Template.h"
#include <QDomElement>
#include <QString>
namespace glabels::model
{
class XmlTemplateCreator
{
public:
XmlTemplateCreator() {}
bool writeTemplates( const QList<const Template*> tmplates, const QString& fileName );
bool writeTemplate( const Template* tmplate, const QString& fileName );
void createTemplateNode( QDomElement& parent, const Template* tmplate );
private:
void createMetaNode( QDomElement& parent, const QString& attr, const QString& value );
void createLabelNode( QDomElement& parent, const Frame* frame );
void createLabelRectangleNode( QDomElement& parent, const FrameRect* frame );
void createLabelEllipseNode( QDomElement& parent, const FrameEllipse* frame );
void createLabelRoundNode( QDomElement& parent, const FrameRound* frame );
void createLabelCdNode( QDomElement& parent, const FrameCd* frame );
void createLabelNodeCommon( QDomElement& node, const Frame* frame );
void createLayoutNode( QDomElement& parent, const Layout* layout );
void createMarkupMarginNode( QDomElement& parent, const MarkupMargin* markupMargin );
void createMarkupLineNode( QDomElement& parent, const MarkupLine* markupLine );
void createMarkupCircleNode( QDomElement& parent, const MarkupCircle* markupCircle );
void createMarkupRectNode( QDomElement& parent, const MarkupRect* markupRect );
void createMarkupEllipseNode( QDomElement& parent, const MarkupEllipse* markupEllipse );
};
}
#endif // model_XmlTemplateCreator_h
+408
View File
@@ -0,0 +1,408 @@
/* XmlTemplateParser.cpp
*
* Copyright (C) 2013-2016 Jim Evins <evins@snaught.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "XmlTemplateParser.h"
#include "Db.h"
#include "FrameRect.h"
#include "FrameCd.h"
#include "FrameRound.h"
#include "FrameEllipse.h"
#include "Layout.h"
#include "Markup.h"
#include "Template.h"
#include "XmlUtil.h"
#include <QFile>
#include <QDomDocument>
#include <QDomNode>
#include <QtDebug>
namespace glabels::model
{
bool XmlTemplateParser::readFile( const QString &fileName )
{
QFile file( fileName );
if ( !file.open( QFile::ReadOnly | QFile::Text) )
{
qWarning() << "Error: Cannot read file " << fileName
<< ": " << file.errorString();
return false;
}
QDomDocument doc;
QString errorString;
int errorLine;
int errorColumn;
if ( !doc.setContent( &file, false, &errorString, &errorLine, &errorColumn ) )
{
qWarning() << "Error: Parse error at line " << errorLine
<< "column " << errorColumn
<< ": " << errorString;
return false;
}
QDomElement root = doc.documentElement();
if ( root.tagName() != "Glabels-templates" )
{
qWarning() << "Error: Not a Glabels-templates file";
return false;
}
parseRootNode( root );
return true;
}
void XmlTemplateParser::parseRootNode( const QDomElement &node )
{
for ( QDomNode child = node.firstChild(); !child.isNull(); child = child.nextSibling() )
{
if ( child.toElement().tagName() == "Template" )
{
Template *tmplate = parseTemplateNode( child.toElement() );
if ( tmplate != nullptr )
{
Db::registerTemplate( tmplate );
}
else
{
qWarning() << "Warning: could not create template, Ignored.";
}
}
else if ( !child.isComment() )
{
qWarning() << "Warning: bad element: "
<< child.toElement().tagName()
<< ", Ignored.";
}
}
}
Template *XmlTemplateParser::parseTemplateNode( const QDomElement &node )
{
QString brand = XmlUtil::getStringAttr( node, "brand", "" );
QString part = XmlUtil::getStringAttr( node, "part", "" );
if ( (brand == "") || (part == "") )
{
// Try the deprecated "name" attribute.
QString name = XmlUtil::getStringAttr( node, "name", "" );
if ( name != "" )
{
QStringList fields = name.split( " ", QString::SkipEmptyParts );
brand = fields[0];
part = fields[1];
}
else
{
qWarning() << "Error: missing name or brand/part attributes.";
return nullptr;
}
}
Template *tmplate = nullptr;
QString equivPart = XmlUtil::getStringAttr( node, "equiv", "" );
if ( equivPart != nullptr )
{
tmplate = Template::fromEquiv( brand, part, equivPart );
for ( QDomNode child = node.firstChild(); !child.isNull(); child = child.nextSibling() )
{
if ( child.toElement().tagName() == "Meta" )
{
parseMetaNode( child.toElement(), tmplate );
}
else if ( !child.isComment() )
{
qWarning() << "Warning: bad element: "
<< child.toElement().tagName()
<< ", Ignored.";
}
}
}
else
{
QString description = XmlUtil::getI18nAttr( node, "description", "" );
QString paperId = XmlUtil::getStringAttr( node, "size", "" );
if ( !Db::isPaperIdOther( paperId ) )
{
const Paper *paper = Db::lookupPaperFromId( paperId );
if ( paper == nullptr )
{
qWarning() << "Error: unknown paper ID: " << paperId;
return nullptr;
}
tmplate = new Template( brand, part, description,
paper->id(), paper->width(), paper->height() );
}
else
{
Distance width = XmlUtil::getLengthAttr( node, "width", Distance(0) );
Distance height = XmlUtil::getLengthAttr( node, "height", Distance(0) );
tmplate = new Template( brand, part, description, paperId, width, height );
}
for ( QDomNode child = node.firstChild(); !child.isNull(); child = child.nextSibling() )
{
if ( child.toElement().tagName() == "Meta" )
{
parseMetaNode( child.toElement(), tmplate );
}
else if ( child.toElement().tagName() == "Label-rectangle" )
{
parseLabelRectangleNode( child.toElement(), tmplate );
}
else if ( child.toElement().tagName() == "Label-ellipse" )
{
parseLabelEllipseNode( child.toElement(), tmplate );
}
else if ( child.toElement().tagName() == "Label-round" )
{
parseLabelRoundNode( child.toElement(), tmplate );
}
else if ( child.toElement().tagName() == "Label-cd" )
{
parseLabelCdNode( child.toElement(), tmplate );
}
else if ( !child.isComment() )
{
qWarning() << "Warning: bad element: "
<< child.toElement().tagName()
<< ", Ignored.";
}
}
}
return tmplate;
}
void XmlTemplateParser::parseMetaNode( const QDomElement &node, Template *tmplate )
{
QString productUrl = XmlUtil::getStringAttr( node, "product_url", "" );
if ( productUrl != "" )
{
tmplate->setProductUrl( productUrl );
}
QString categoryId = XmlUtil::getStringAttr( node, "category", "" );
if ( categoryId != "" )
{
tmplate->addCategory( categoryId );
}
}
void XmlTemplateParser::parseLabelRectangleNode( const QDomElement &node, Template *tmplate )
{
QString id = XmlUtil::getStringAttr( node, "id", "0" );
Distance w = XmlUtil::getLengthAttr( node, "width", Distance(0) );
Distance h = XmlUtil::getLengthAttr( node, "height", Distance(0) );
Distance r = XmlUtil::getLengthAttr( node, "round", Distance(0) );
Distance xWaste, yWaste;
Distance waste = XmlUtil::getLengthAttr( node, "waste", Distance(-1) );
if ( waste >= Distance(0) )
{
xWaste = waste;
yWaste = waste;
}
else
{
xWaste = XmlUtil::getLengthAttr( node, "x_waste", Distance(0) );
yWaste = XmlUtil::getLengthAttr( node, "y_waste", Distance(0) );
}
Frame *frame = new FrameRect( w, h, r, xWaste, yWaste, id );
parseLabelNodeCommon( node, frame );
tmplate->addFrame( frame );
}
void XmlTemplateParser::parseLabelEllipseNode( const QDomElement &node, Template *tmplate )
{
QString id = XmlUtil::getStringAttr( node, "id", "0" );
Distance w = XmlUtil::getLengthAttr( node, "width", Distance(0) );
Distance h = XmlUtil::getLengthAttr( node, "height", Distance(0) );
Distance waste = XmlUtil::getLengthAttr( node, "waste", Distance(0) );
Frame *frame = new FrameEllipse( w, h, waste, id );
parseLabelNodeCommon( node, frame );
tmplate->addFrame( frame );
}
void XmlTemplateParser::parseLabelRoundNode( const QDomElement &node, Template *tmplate )
{
QString id = XmlUtil::getStringAttr( node, "id", "0" );
Distance r = XmlUtil::getLengthAttr( node, "radius", Distance(0) );
Distance waste = XmlUtil::getLengthAttr( node, "waste", Distance(0) );
Frame *frame = new FrameRound( r, waste, id );
parseLabelNodeCommon( node, frame );
tmplate->addFrame( frame );
}
void XmlTemplateParser::parseLabelCdNode( const QDomElement &node, Template *tmplate )
{
QString id = XmlUtil::getStringAttr( node, "id", "0" );
Distance r1 = XmlUtil::getLengthAttr( node, "radius", Distance(0) );
Distance r2 = XmlUtil::getLengthAttr( node, "hole", Distance(0) );
Distance w = XmlUtil::getLengthAttr( node, "width", Distance(0) );
Distance h = XmlUtil::getLengthAttr( node, "height", Distance(0) );
Distance waste = XmlUtil::getLengthAttr( node, "waste", Distance(0) );
Frame *frame = new FrameCd( r1, r2, w, h, waste, id );
parseLabelNodeCommon( node, frame );
tmplate->addFrame( frame );
}
void XmlTemplateParser::parseLabelNodeCommon( const QDomElement &node, Frame *frame )
{
for ( QDomNode child = node.firstChild(); !child.isNull(); child = child.nextSibling() )
{
if ( child.toElement().tagName() == "Layout" )
{
parseLayoutNode( child.toElement(), frame );
}
else if ( child.toElement().tagName() == "Markup-margin" )
{
parseMarkupMarginNode( child.toElement(), frame );
}
else if ( child.toElement().tagName() == "Markup-line" )
{
parseMarkupLineNode( child.toElement(), frame );
}
else if ( child.toElement().tagName() == "Markup-circle" )
{
parseMarkupCircleNode( child.toElement(), frame );
}
else if ( child.toElement().tagName() == "Markup-rect" )
{
parseMarkupRectNode( child.toElement(), frame );
}
else if ( child.toElement().tagName() == "Markup-ellipse" )
{
parseMarkupEllipseNode( child.toElement(), frame );
}
else if ( !child.isComment() )
{
qWarning() << "Warning: bad element: "
<< child.toElement().tagName()
<< ", Ignored.";
}
}
}
void XmlTemplateParser::parseLayoutNode( const QDomElement &node, Frame *frame )
{
int nX = XmlUtil::getIntAttr( node, "nx", 1 );
int nY = XmlUtil::getIntAttr( node, "ny", 1 );
Distance x0 = XmlUtil::getLengthAttr( node, "x0", Distance(0) );
Distance y0 = XmlUtil::getLengthAttr( node, "y0", Distance(0) );
Distance dX = XmlUtil::getLengthAttr( node, "dx", Distance(0) );
Distance dY = XmlUtil::getLengthAttr( node, "dy", Distance(0) );
frame->addLayout( new Layout( nX, nY, x0, y0, dX, dY ) );
}
void XmlTemplateParser::parseMarkupMarginNode( const QDomElement &node, Frame *frame )
{
Distance size = XmlUtil::getLengthAttr( node, "size", Distance(0) );
frame->addMarkup( new MarkupMargin( frame, size ) );
}
void XmlTemplateParser::parseMarkupLineNode( const QDomElement &node, Frame *frame )
{
Distance x1 = XmlUtil::getLengthAttr( node, "x1", Distance(0) );
Distance y1 = XmlUtil::getLengthAttr( node, "y1", Distance(0) );
Distance x2 = XmlUtil::getLengthAttr( node, "x2", Distance(0) );
Distance y2 = XmlUtil::getLengthAttr( node, "y2", Distance(0) );
frame->addMarkup( new MarkupLine( x1, y1, x2, y2 ) );
}
void XmlTemplateParser::parseMarkupCircleNode( const QDomElement &node, Frame *frame )
{
Distance x0 = XmlUtil::getLengthAttr( node, "x0", Distance(0) );
Distance y0 = XmlUtil::getLengthAttr( node, "y0", Distance(0) );
Distance r = XmlUtil::getLengthAttr( node, "radius", Distance(0) );
frame->addMarkup( new MarkupCircle( x0, y0, r ) );
}
void XmlTemplateParser::parseMarkupRectNode( const QDomElement &node, Frame *frame )
{
Distance x1 = XmlUtil::getLengthAttr( node, "x1", Distance(0) );
Distance y1 = XmlUtil::getLengthAttr( node, "y1", Distance(0) );
Distance w = XmlUtil::getLengthAttr( node, "w", Distance(0) );
Distance h = XmlUtil::getLengthAttr( node, "h", Distance(0) );
Distance r = XmlUtil::getLengthAttr( node, "r", Distance(0) );
frame->addMarkup( new MarkupRect( x1, y1, w, h, r ) );
}
void XmlTemplateParser::parseMarkupEllipseNode( const QDomElement &node, Frame *frame )
{
Distance x1 = XmlUtil::getLengthAttr( node, "x1", Distance(0) );
Distance y1 = XmlUtil::getLengthAttr( node, "y1", Distance(0) );
Distance w = XmlUtil::getLengthAttr( node, "w", Distance(0) );
Distance h = XmlUtil::getLengthAttr( node, "h", Distance(0) );
frame->addMarkup( new MarkupEllipse( x1, y1, w, h ) );
}
} // namespace glabels::model
+62
View File
@@ -0,0 +1,62 @@
/* XmlTemplateParser.h
*
* Copyright (C) 2013-2016 Jim Evins <evins@snaught.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef model_XmlTemplateParser_h
#define model_XmlTemplateParser_h
#include "Template.h"
#include <QDomElement>
#include <QString>
namespace glabels::model
{
class XmlTemplateParser
{
public:
XmlTemplateParser() {}
bool readFile( const QString &fileName );
Template *parseTemplateNode( const QDomElement &node );
private:
void parseRootNode( const QDomElement &node );
void parseMetaNode( const QDomElement &node, Template *tmplate );
void parseLabelRectangleNode( const QDomElement &node, Template *tmplate );
void parseLabelEllipseNode( const QDomElement &node, Template *tmplate );
void parseLabelRoundNode( const QDomElement &node, Template *tmplate );
void parseLabelCdNode( const QDomElement &node, Template *tmplate );
void parseLabelNodeCommon( const QDomElement &node, Frame *frame );
void parseLayoutNode( const QDomElement &node, Frame *frame );
void parseMarkupMarginNode( const QDomElement &node, Frame *frame );
void parseMarkupLineNode( const QDomElement &node, Frame *frame );
void parseMarkupCircleNode( const QDomElement &node, Frame *frame );
void parseMarkupRectNode( const QDomElement &node, Frame *frame );
void parseMarkupEllipseNode( const QDomElement &node, Frame *frame );
};
}
#endif // model_XmlTemplateParser_h
+407
View File
@@ -0,0 +1,407 @@
/* XmlUtil.cpp
*
* Copyright (C) 2013-2016 Jim Evins <evins@snaught.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "XmlUtil.h"
#include <QTextStream>
#include <QCoreApplication>
#include <QtDebug>
namespace glabels::model
{
//
// Static data
//
XmlUtil* XmlUtil::mInstance = nullptr;
XmlUtil::XmlUtil()
{
mUnits = Units(Units::PT);
}
void XmlUtil::init()
{
if ( mInstance == nullptr )
{
mInstance = new XmlUtil();
}
}
Units XmlUtil::units()
{
init();
return mInstance->mUnits;
}
void XmlUtil::setUnits( const Units& units )
{
init();
mInstance->mUnits = units;
}
QString XmlUtil::getStringAttr( const QDomElement& node,
const QString& name,
const QString& default_value )
{
init();
return node.attribute( name, default_value );
}
double XmlUtil::getDoubleAttr( const QDomElement& node,
const QString& name,
double default_value )
{
init();
QString valueString = node.attribute( name, "" );
if ( valueString != "" )
{
bool ok;
double value = valueString.toDouble(& ok );
if ( !ok )
{
qWarning() << "Error: bad double value in attribute "
<< node.tagName() << ":" << name << "=" << valueString;
return default_value;
}
return value;
}
return default_value;
}
bool XmlUtil::getBoolAttr( const QDomElement& node,
const QString& name,
bool default_value )
{
init();
QString valueString = node.attribute( name, "" );
if ( valueString != "" )
{
int intValue = valueString.toInt();
if ( (valueString == "True") ||
(valueString == "TRUE") ||
(valueString == "true") ||
(intValue == 1) )
{
return true;
}
if ( (valueString == "False") ||
(valueString == "FALSE") ||
(valueString == "false") ||
(intValue == 0) )
{
return false;
}
qWarning() << "Error: bad boolean value in attribute "
<< node.tagName() << ":" << name << "=" << valueString;
return default_value;
}
return default_value;
}
int XmlUtil::getIntAttr( const QDomElement& node,
const QString& name,
int default_value )
{
init();
QString valueString = node.attribute( name, "" );
if ( valueString != "" )
{
bool ok;
int value = valueString.toInt(& ok );
if ( !ok )
{
qWarning() << "Error: bad integer value in attribute "
<< node.tagName() << ":" << name << "=" << valueString;
return default_value;
}
return value;
}
return default_value;
}
uint32_t XmlUtil::getUIntAttr( const QDomElement& node,
const QString& name,
uint32_t default_value )
{
init();
QString valueString = node.attribute( name, "" );
if ( valueString != "" )
{
bool ok;
uint32_t value = valueString.toUInt(& ok, 0 );
if ( !ok )
{
qWarning() << "Error: bad unsigned integer value in attribute "
<< node.tagName() << ":" << name << "=" << valueString;
return default_value;
}
return value;
}
return default_value;
}
QString XmlUtil::getI18nAttr( const QDomElement& node,
const QString& name,
const QString& default_value )
{
init();
QString i18nString = node.attribute( QString("_").append(name), "" );
if ( i18nString == "" )
{
return node.attribute( name, default_value );
}
return QCoreApplication::translate( "XmlStrings", i18nString.toUtf8().constData() );
}
Distance XmlUtil::getLengthAttr( const QDomElement& node,
const QString& name,
const Distance& default_value )
{
init();
QString valueString = node.attribute( name, "" );
if ( valueString != "" )
{
double value;
QString unitsString;
QTextStream valueStream( &valueString, QIODevice::ReadOnly );
valueStream >> value >> unitsString;
if ( !unitsString.isEmpty() && !Units::isIdValid( unitsString ) )
{
qWarning() << "Error: bad length value in attribute "
<< node.tagName() << ":" << name << "=" << valueString;
}
return Distance( value, unitsString );
}
return default_value;
}
QFont::Weight XmlUtil::getWeightAttr( const QDomElement& node,
const QString& name,
QFont::Weight default_value )
{
init();
QString valueString = node.attribute( name, "" );
if ( valueString != "" )
{
if ( valueString == "bold" )
{
return QFont::Bold;
}
else if ( valueString == "normal" )
{
return QFont::Normal;
}
}
return default_value;
}
Qt::Alignment XmlUtil::getAlignmentAttr( const QDomElement& node,
const QString& name,
Qt::Alignment default_value )
{
init();
QString valueString = node.attribute( name, "" );
if ( valueString != "" )
{
if ( valueString == "right" )
{
return Qt::AlignRight;
}
else if ( valueString == "hcenter" )
{
return Qt::AlignHCenter;
}
else if ( valueString == "left" )
{
return Qt::AlignLeft;
}
else if ( valueString == "bottom" )
{
return Qt::AlignBottom;
}
else if ( valueString == "vcenter" )
{
return Qt::AlignVCenter;
}
else if ( valueString == "top" )
{
return Qt::AlignTop;
}
}
return default_value;
}
void XmlUtil::setStringAttr( QDomElement& node,
const QString& name,
const QString& value )
{
init();
node.setAttribute( name, value );
}
void XmlUtil::setDoubleAttr( QDomElement& node,
const QString& name,
double value )
{
init();
node.setAttribute( name, QString::number(value) );
}
void XmlUtil::setBoolAttr( QDomElement& node,
const QString& name,
bool value )
{
init();
node.setAttribute( name, value ? "true" : "false" );
}
void XmlUtil::setIntAttr( QDomElement& node,
const QString& name,
int value )
{
init();
node.setAttribute( name, QString::number(value) );
}
void XmlUtil::setUIntAttr( QDomElement& node,
const QString& name,
uint32_t value )
{
init();
node.setAttribute( name, "0x" + QString::number(value, 16) );
}
void XmlUtil::setLengthAttr( QDomElement& node,
const QString& name,
const Distance& value )
{
init();
Units units = mInstance->mUnits;
node.setAttribute( name, QString::number(value.inUnits(units)) + units.toIdString() );
}
void XmlUtil::setWeightAttr( QDomElement& node,
const QString& name,
QFont::Weight value )
{
switch (value)
{
case QFont::Bold:
node.setAttribute( name, "bold" );
break;
default:
node.setAttribute( name, "normal" );
break;
}
}
void XmlUtil::setAlignmentAttr( QDomElement& node,
const QString& name,
Qt::Alignment value )
{
switch (value)
{
case Qt::AlignRight:
node.setAttribute( name, "right" );
break;
case Qt::AlignHCenter:
node.setAttribute( name, "hcenter" );
break;
case Qt::AlignLeft:
node.setAttribute( name, "left" );
break;
case Qt::AlignBottom:
node.setAttribute( name, "bottom" );
break;
case Qt::AlignVCenter:
node.setAttribute( name, "vcenter" );
break;
case Qt::AlignTop:
node.setAttribute( name, "top" );
break;
default:
node.setAttribute( name, "left" );
break;
}
}
} // namespace glabels::model
+131
View File
@@ -0,0 +1,131 @@
/* XmlUtil.h
*
* Copyright (C) 2013-2016 Jim Evins <evins@snaught.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef model_XmlUtil_h
#define model_XmlUtil_h
#include "Distance.h"
#include <QDomElement>
#include <QFont>
#include <QString>
#include <Qt>
#include <cstdint>
namespace glabels::model
{
class XmlUtil
{
private:
XmlUtil();
public:
static void init();
static Units units();
static void setUnits( const Units& units );
static QString getStringAttr( const QDomElement& node,
const QString& name,
const QString& default_value );
static double getDoubleAttr( const QDomElement& node,
const QString& name,
double default_value );
static bool getBoolAttr( const QDomElement& node,
const QString& name,
bool default_value );
static int getIntAttr( const QDomElement& node,
const QString& name,
int default_value );
static uint32_t getUIntAttr( const QDomElement& node,
const QString& name,
uint32_t default_value );
static QString getI18nAttr( const QDomElement& node,
const QString& name,
const QString& default_value );
static Distance getLengthAttr( const QDomElement& node,
const QString& name,
const Distance& default_value );
static QFont::Weight getWeightAttr( const QDomElement& node,
const QString& name,
QFont::Weight default_value );
static Qt::Alignment getAlignmentAttr( const QDomElement& node,
const QString& name,
Qt::Alignment default_value );
static void setStringAttr( QDomElement& node,
const QString& name,
const QString& value );
static void setDoubleAttr( QDomElement& node,
const QString& name,
double value );
static void setBoolAttr( QDomElement& node,
const QString& name,
bool value );
static void setIntAttr( QDomElement& node,
const QString& name,
int value );
static void setUIntAttr( QDomElement& node,
const QString& name,
uint32_t value );
static void setLengthAttr( QDomElement& node,
const QString& name,
const Distance& value );
static void setWeightAttr( QDomElement& node,
const QString& name,
QFont::Weight value );
static void setAlignmentAttr( QDomElement& node,
const QString& name,
Qt::Alignment value );
private:
Units mUnits;
static XmlUtil* mInstance;
};
}
#endif // model_XmlUtil_h
+103
View File
@@ -0,0 +1,103 @@
/* XmlVendorParser.cpp
*
* Copyright (C) 2013-2016 Jim Evins <evins@snaught.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "XmlVendorParser.h"
#include "Db.h"
#include "Vendor.h"
#include "XmlUtil.h"
#include <QDomDocument>
#include <QDomNode>
#include <QFile>
#include <QtDebug>
namespace glabels::model
{
bool XmlVendorParser::readFile( const QString &fileName )
{
QFile file( fileName );
if ( !file.open( QFile::ReadOnly | QFile::Text) )
{
qWarning() << "Error: Cannot read file " << fileName
<< ": " << file.errorString();
return false;
}
QDomDocument doc;
QString errorString;
int errorLine;
int errorColumn;
if ( !doc.setContent( &file, false, &errorString, &errorLine, &errorColumn ) )
{
qWarning() << "Error: Parse error at line " << errorLine
<< "column " << errorColumn
<< ": " << errorString;
return false;
}
QDomElement root = doc.documentElement();
if ( root.tagName() != "Glabels-vendors" )
{
qWarning() << "Error: Not a Glabels-vendors file.";
return false;
}
parseRootNode( root );
return true;
}
void XmlVendorParser::parseRootNode( const QDomElement &node )
{
for ( QDomNode child = node.firstChild(); !child.isNull(); child = child.nextSibling() )
{
if ( child.toElement().tagName() == "Vendor" )
{
parseVendorNode( child.toElement() );
}
else if ( !child.isComment() )
{
qWarning() << "Warning: bad element: "
<< child.toElement().tagName()
<< ", Ignored.";
}
}
}
void XmlVendorParser::parseVendorNode( const QDomElement &node )
{
QString name = XmlUtil::getStringAttr( node, "name", "" );
QString url = XmlUtil::getStringAttr( node, "url", "" );
Vendor *vendor = new Vendor( name, url );
if ( vendor != nullptr )
{
Db::registerVendor( vendor );
}
}
} // namespace glabels::model
+47
View File
@@ -0,0 +1,47 @@
/* XmlVendorParser.h
*
* Copyright (C) 2013-2016 Jim Evins <evins@snaught.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef model_XmlVendorParser_h
#define model_XmlVendorParser_h
#include <QDomElement>
#include <QString>
namespace glabels::model
{
class XmlVendorParser
{
public:
XmlVendorParser() {}
bool readFile( const QString &fileName );
private:
void parseRootNode( const QDomElement &node );
void parseVendorNode( const QDomElement &node );
};
}
#endif // model_XmlVendorParser_h
+11
View File
@@ -0,0 +1,11 @@
if (Qt5Test_FOUND)
#=======================================
# Test SubstitutionField class
#=======================================
qt5_wrap_cpp (TestSubstitutionField_moc_sources TestSubstitutionField.h)
add_executable (TestSubstitutionField TestSubstitutionField.cpp ../SubstitutionField.cpp ${TestSubstitutionField_moc_sources})
target_link_libraries (TestSubstitutionField Model Qt5::Test)
add_test (NAME SubstitutionField COMMAND TestSubstitutionField)
endif (Qt5Test_FOUND)
+342
View File
@@ -0,0 +1,342 @@
/* TestSubstitutionField.cpp
*
* Copyright (C) 2017 Jim Evins <evins@snaught.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "TestSubstitutionField.h"
#include "model/SubstitutionField.h"
QTEST_MAIN(TestSubstitutionField)
void TestSubstitutionField::parseValid()
{
using namespace glabels;
//
// Valid substitution fields (concatenated in single input string)
//
QString input = "${1234}${abc:=ABC}${x:%08.2f}${y:%08.2f:=12.34}${ADDR2:n}";
QStringRef s = &input;
model::SubstitutionField f1;
QCOMPARE( model::SubstitutionField::parse( s, f1 ), true );
QCOMPARE( f1.fieldName(), QString( "1234" ) );
QCOMPARE( f1.newLine(), false );
model::SubstitutionField f2;
QCOMPARE( model::SubstitutionField::parse( s, f2 ), true );
QCOMPARE( f2.fieldName(), QString( "abc" ) );
QCOMPARE( f2.defaultValue(), QString( "ABC" ) );
QCOMPARE( f2.newLine(), false );
model::SubstitutionField f3;
QCOMPARE( model::SubstitutionField::parse( s, f3 ), true );
QCOMPARE( f3.fieldName(), QString( "x" ) );
QCOMPARE( f3.format(), QString( "%08.2f" ) );
QCOMPARE( f3.formatType(), QChar('f') );
QCOMPARE( f3.newLine(), false );
model::SubstitutionField f4;
QCOMPARE( model::SubstitutionField::parse( s, f4 ), true );
QCOMPARE( f4.fieldName(), QString( "y" ) );
QCOMPARE( f4.defaultValue(), QString( "12.34" ) );
QCOMPARE( f4.format(), QString( "%08.2f" ) );
QCOMPARE( f4.formatType(), QChar('f') );
QCOMPARE( f4.newLine(), false );
model::SubstitutionField f5;
QCOMPARE( model::SubstitutionField::parse( s, f5 ), true );
QCOMPARE( f5.fieldName(), QString( "ADDR2" ) );
QCOMPARE( f5.newLine(), true );
}
void TestSubstitutionField::parseInvalid()
{
using namespace glabels;
//
// Ordinary text
//
QString input5 = "Abcdefg";
QStringRef s5 = &input5;
model::SubstitutionField f5;
QCOMPARE( model::SubstitutionField::parse( s5, f5 ), false );
QCOMPARE( s5, QStringRef( &input5 ) ); // Should not advance string reference
//
// Invalid substitution fields (which are treated as ordinary text)
//
QString input6 = "$abc";
QStringRef s6 = &input6;
model::SubstitutionField f6;
QCOMPARE( model::SubstitutionField::parse( s6, f6 ), false );
QCOMPARE( s6, QStringRef( &input6 ) ); // Should not advance string reference
QString input7 = "${abc";
QStringRef s7 = &input7;
model::SubstitutionField f7;
QCOMPARE( model::SubstitutionField::parse( s7, f7 ), false );
QCOMPARE( s7, QStringRef( &input7 ) ); // Should not advance string reference
QString input8 = "${abc:}";
QStringRef s8 = &input8;
model::SubstitutionField f8;
QCOMPARE( model::SubstitutionField::parse( s8, f8 ), false );
QCOMPARE( s8, QStringRef( &input8 ) ); // Should not advance string reference
// Even though format is invalid, let it slide. Overall structure still good. Format will be ignored.
QString input9 = "${abc:%3.2}";
QStringRef s9 = &input9;
model::SubstitutionField f9;
QCOMPARE( model::SubstitutionField::parse( s9, f9 ), true );
}
void TestSubstitutionField::construction()
{
using namespace glabels;
model::SubstitutionField f1( "${1234}" );
QCOMPARE( f1.fieldName(), QString( "1234" ) );
model::SubstitutionField f2( "${abc:=ABC}" );
QCOMPARE( f2.fieldName(), QString( "abc" ) );
QCOMPARE( f2.defaultValue(), QString( "ABC" ) );
model::SubstitutionField f3( "${x:%08.2f}" );
QCOMPARE( f3.fieldName(), QString( "x" ) );
QCOMPARE( f3.format(), QString( "%08.2f" ) );
QCOMPARE( f3.formatType(), QChar('f') );
model::SubstitutionField f4( "${y:%08.2f:=12.34}" );
QCOMPARE( f4.fieldName(), QString( "y" ) );
QCOMPARE( f4.defaultValue(), QString( "12.34" ) );
QCOMPARE( f4.format(), QString( "%08.2f" ) );
QCOMPARE( f4.formatType(), QChar('f') );
}
void TestSubstitutionField::simpleEvaluation()
{
using namespace glabels;
model::SubstitutionField f1( "${1}" );
model::SubstitutionField f2( "${2}" );
model::SubstitutionField f3( "${3}" );
model::SubstitutionField f4( "${4}" );
merge::Record record1;
record1[ "1" ] = "Abcdefg";
record1[ "2" ] = "Hijklmn";
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!@" ) );
merge::Record record2;
record2[ "1" ] = "1234567";
record2[ "2" ] = "FooBar";
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( "#$%^&*" ) );
}
void TestSubstitutionField::defaultValueEvaluation()
{
using namespace glabels;
model::SubstitutionField f1( "${1:=foo1}" );
model::SubstitutionField f2( "${2:=foo2}" );
model::SubstitutionField f3( "${3:=foo3}" );
model::SubstitutionField f4( "${4:=foo4}" );
merge::Record record1;
record1[ "1" ] = "Abcdefg";
record1[ "2" ] = "Hijklmn";
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!@" ) );
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" ) );
merge::Record record3;
record3[ "1" ] = "xyzzy";
// Field "2" empty
// 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" ) );
}
void TestSubstitutionField::formattedStringEvaluation()
{
using namespace glabels;
model::SubstitutionField f1( "${1:%10s}" );
model::SubstitutionField f2( "${2:%10s}" );
model::SubstitutionField f3( "${3:%10s}" );
model::SubstitutionField f4( "${4:%10s}" );
model::SubstitutionField f5( "${5:%-10s}" );
model::SubstitutionField f6( "${6:%-10s}" );
model::SubstitutionField f7( "${7:%-10s}" );
model::SubstitutionField f8( "${8:%-10s}" );
merge::Record record1;
record1[ "1" ] = "0";
record1[ "2" ] = "1";
record1[ "3" ] = "-1";
record1[ "4" ] = "3.14";
record1[ "5" ] = "0";
record1[ "6" ] = "100";
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( f5.evaluate( &record1 ), QString( "0 " ) );
QCOMPARE( f6.evaluate( &record1 ), QString( "100 " ) );
QCOMPARE( f7.evaluate( &record1 ), QString( "-100 " ) );
QCOMPARE( f8.evaluate( &record1 ), QString( "3.14 " ) );
}
void TestSubstitutionField::formattedFloatEvaluation()
{
using namespace glabels;
model::SubstitutionField f1( "${1:%+5.2f}" );
model::SubstitutionField f2( "${2:%+5.2f}" );
model::SubstitutionField f3( "${3:%+5.2f}" );
model::SubstitutionField f4( "${4:%+5.2f}" );
model::SubstitutionField f5( "${5:%+5.2e}" );
model::SubstitutionField f6( "${6:%+5.2e}" );
model::SubstitutionField f7( "${7:%+5.2e}" );
model::SubstitutionField f8( "${8:%+5.2e}" );
merge::Record record1;
record1[ "1" ] = "0";
record1[ "2" ] = "1";
record1[ "3" ] = "-1";
record1[ "4" ] = "3.14";
record1[ "5" ] = "0";
record1[ "6" ] = "100";
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( 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" ) );
}
void TestSubstitutionField::formattedIntEvaluation()
{
using namespace glabels;
model::SubstitutionField f1( "${1:%08d}" );
model::SubstitutionField f2( "${2:%08d}" );
model::SubstitutionField f3( "${3:%08d}" );
model::SubstitutionField f4( "${4:%08d}" );
model::SubstitutionField f5( "${5:%08x}" );
model::SubstitutionField f6( "${6:%08x}" );
model::SubstitutionField f7( "${7:%08x}" );
model::SubstitutionField f8( "${8:%08x}" );
merge::Record record1;
record1[ "1" ] = "0";
record1[ "2" ] = "1";
record1[ "3" ] = "-1";
record1[ "4" ] = "3.14";
record1[ "5" ] = "100";
record1[ "6" ] = "0x100";
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( 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)
}
void TestSubstitutionField::newLineEvaluation()
{
using namespace glabels;
model::SubstitutionField addr2( "${ADDR2:n}" );
QCOMPARE( addr2.fieldName(), QString( "ADDR2" ) );
QCOMPARE( addr2.newLine(), true );
merge::Record record1;
record1[ "ADDR2" ] = "Apt. 5B";
merge::Record record2;
record2[ "ADDR2" ] = ""; // ADDR2 Empty
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
}
+40
View File
@@ -0,0 +1,40 @@
/* TestSubstitutionField.h
*
* Copyright (C) 2017 Jim Evins <evins@snaught.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include <QtTest/QtTest>
class TestSubstitutionField : public QObject
{
Q_OBJECT
private slots:
void parseValid();
void parseInvalid();
void construction();
void simpleEvaluation();
void defaultValueEvaluation();
void formattedStringEvaluation();
void formattedFloatEvaluation();
void formattedIntEvaluation();
void newLineEvaluation();
};