Organization of groups - groups categories. Closes smart-pattern/valentina#15.

This commit is contained in:
Roman Telezhynskyi 2020-03-24 17:31:32 +02:00
parent a84857afda
commit c1453f1715
36 changed files with 793 additions and 59 deletions

View File

@ -46,6 +46,7 @@
- [smart-pattern/valentina#18] Auto-created Visibility Group for group operation.
- Setting scale factor for export and print.
- New layout generator option: Prefer one sheet solution.
- [smart-pattern/valentina#15] Organization of groups - groups categories
# Version 0.6.2 (unreleased)
- [#903] Bug in tool Cut Spline path.

View File

@ -31,7 +31,9 @@
#include "../vtools/dialogs/tools/dialoggroup.h"
#include "../vtools/undocommands/undogroup.h"
#include "../vpatterndb/vcontainer.h"
#include "../vmisc/compatibility.h"
#include <QCompleter>
#include <QMenu>
#include <QTableWidget>
@ -51,6 +53,7 @@ VWidgetGroups::VWidgetGroups(VAbstractPattern *doc, QWidget *parent)
connect(ui->tableWidget, &QTableWidget::cellClicked, this, &VWidgetGroups::GroupVisibilityChanged);
connect(ui->tableWidget, &QTableWidget::cellChanged, this, &VWidgetGroups::RenameGroup);
connect(ui->tableWidget, &QTableWidget::customContextMenuRequested, this, &VWidgetGroups::CtxMenu);
connect(ui->lineEditTags, &QLineEdit::textChanged, this, &VWidgetGroups::UpdateGroups);
}
//---------------------------------------------------------------------------------------------------------------------
@ -110,6 +113,32 @@ void VWidgetGroups::SetMultipleGroupsVisibility(const QVector<vidtype> &groups,
qApp->getUndoStack()->push(changeGroups);
}
//---------------------------------------------------------------------------------------------------------------------
QMap<quint32, VGroupData> VWidgetGroups::FilterGroups(const QMap<quint32, VGroupData> &groups)
{
QMap<quint32, VGroupData> filtered;
QSet<QString> filterCategories = ConvertToSet<QString>(VAbstractPattern::FilterGroupTags(ui->lineEditTags->text()));
if (filterCategories.isEmpty())
{
return groups;
}
auto i = groups.constBegin();
while (i != groups.constEnd())
{
const VGroupData &data = i.value();
QSet<QString> groupCategories = ConvertToSet<QString>(data.tags);
if (SetIntersects(filterCategories, groupCategories))
{
filtered.insert(i.key(), data);
}
++i;
}
return filtered;
}
//---------------------------------------------------------------------------------------------------------------------
int VWidgetGroups::GroupRow(vidtype id) const
{
@ -185,7 +214,7 @@ void VWidgetGroups::CtxMenu(const QPoint &pos)
menu->addAction(QIcon(QStringLiteral("://icon/16x16/closed_eye.png")), tr("Hide")) :
menu->addAction(QIcon(QStringLiteral("://icon/16x16/open_eye.png")), tr("Show"));
QAction *actionRename = menu->addAction(tr("Rename"));
QAction *actionPreferences = menu->addAction(QIcon::fromTheme(preferencesOtherIcon), tr("Preferences"));
QAction *actionDelete = menu->addAction(QIcon::fromTheme(editDeleteIcon), tr("Delete"));
menu->addSeparator();
QAction *actionHideAll = menu->addAction(tr("Hide All"));
@ -199,19 +228,22 @@ void VWidgetGroups::CtxMenu(const QPoint &pos)
{
SetGroupVisibility(id, not doc->GetGroupVisibility(id));
}
else if (selectedAction == actionRename)
else if (selectedAction == actionPreferences)
{
QScopedPointer<VContainer> fackeContainer(new VContainer(qApp->TrVars(), qApp->patternUnitP(),
VContainer::UniqueNamespace()));
QScopedPointer<DialogGroup> dialog(new DialogGroup(fackeContainer.data(), NULL_ID, this));
dialog->SetName(doc->GetGroupName(id));
dialog->SetTags(doc->GetGroupTags(id));
dialog->SetGroupCategories(doc->GetGroupCategories());
const int result = dialog->exec();
if (result == QDialog::Accepted)
{
::RenameGroup *renameGroup = new ::RenameGroup(doc, id, dialog->GetName());
connect(renameGroup, &RenameGroup::UpdateGroups, this, &VWidgetGroups::UpdateGroups);
qApp->getUndoStack()->push(renameGroup);
ChangeGroupOptions *changeGroupOptions = new ChangeGroupOptions(doc, id, dialog->GetName(),
dialog->GetTags());
connect(changeGroupOptions, &ChangeGroupOptions::UpdateGroups, this, &VWidgetGroups::UpdateGroups);
qApp->getUndoStack()->push(changeGroupOptions);
}
}
else if (selectedAction == actionDelete)
@ -277,9 +309,13 @@ void VWidgetGroups::UpdateGroups()
}
//---------------------------------------------------------------------------------------------------------------------
void VWidgetGroups::FillTable(const QMap<quint32, QPair<QString, bool> > &groups)
void VWidgetGroups::FillTable(QMap<quint32, VGroupData> groups)
{
emit doc->UpdateToolTip();
ui->lineEditTags->SetCompletion(doc->GetGroupCategories());
groups = FilterGroups(groups);
ui->tableWidget->blockSignals(true);
ui->tableWidget->clear();
@ -290,12 +326,12 @@ void VWidgetGroups::FillTable(const QMap<quint32, QPair<QString, bool> > &groups
while (i != groups.constEnd())
{
++currentRow;
const QPair<QString, bool> data = i.value();
const VGroupData data = i.value();
QTableWidgetItem *item = new QTableWidgetItem();
item->setTextAlignment(Qt::AlignHCenter);
(data.second) ? item->setIcon(QIcon("://icon/16x16/open_eye.png"))
: item->setIcon(QIcon("://icon/16x16/closed_eye.png"));
(data.visible) ? item->setIcon(QIcon("://icon/16x16/open_eye.png"))
: item->setIcon(QIcon("://icon/16x16/closed_eye.png"));
item->setData(Qt::UserRole, i.key());
@ -306,8 +342,9 @@ void VWidgetGroups::FillTable(const QMap<quint32, QPair<QString, bool> > &groups
ui->tableWidget->setItem(currentRow, 0, item);
item = new QTableWidgetItem(data.first);
item = new QTableWidgetItem(data.name);
item->setTextAlignment(Qt::AlignLeft | Qt::AlignVCenter);
item->setToolTip(tr("Categories: %1.").arg(data.tags.join(", ")));
if(doc->GroupIsEmpty(i.key()))
{

View File

@ -34,6 +34,7 @@
class QTableWidgetItem;
class VAbstractPattern;
struct VGroupData;
namespace Ui
{
@ -61,10 +62,12 @@ private:
Ui::VWidgetGroups *ui;
VAbstractPattern *doc;
void FillTable(const QMap<quint32, QPair<QString, bool> > &groups);
void FillTable(QMap<quint32, VGroupData> groups);
void SetGroupVisibility(vidtype id, bool visible) const;
void SetMultipleGroupsVisibility(const QVector<vidtype> &groups, bool visible) const;
QMap<quint32, VGroupData> FilterGroups(const QMap<quint32, VGroupData> &groups);
int GroupRow(vidtype id) const;
};

View File

@ -7,7 +7,7 @@
<x>0</x>
<y>0</y>
<width>371</width>
<height>279</height>
<height>438</height>
</rect>
</property>
<property name="windowTitle">
@ -18,6 +18,30 @@
<normaloff>:/icon/64x64/icon64x64.png</normaloff>:/icon/64x64/icon64x64.png</iconset>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>Tags:</string>
</property>
</widget>
</item>
<item>
<widget class="VCompleterLineEdit" name="lineEditTags">
<property name="toolTip">
<string>Separate each tag with comma.</string>
</property>
<property name="placeholderText">
<string>Filter by tags</string>
</property>
<property name="clearButtonEnabled">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QTableWidget" name="tableWidget">
<property name="alternatingRowColors">
@ -47,16 +71,23 @@
<attribute name="verticalHeaderVisible">
<bool>false</bool>
</attribute>
<attribute name="verticalHeaderHighlightSections">
<bool>false</bool>
</attribute>
<attribute name="verticalHeaderMinimumSectionSize">
<number>10</number>
</attribute>
<attribute name="verticalHeaderHighlightSections">
<bool>false</bool>
</attribute>
</widget>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>VCompleterLineEdit</class>
<extends>QLineEdit</extends>
<header>vlineedit.h</header>
</customwidget>
</customwidgets>
<resources>
<include location="../../../libs/vmisc/share/resources/icon.qrc"/>
</resources>

View File

@ -648,6 +648,11 @@ void MainWindow::SetToolButton(bool checked, Tool t, const QString &cursor, cons
case Tool::PlaceLabel:
dialogTool->SetPiecesList(doc->GetActivePPPieces());
break;
case Tool::Rotation:
case Tool::Move:
case Tool::FlippingByAxis:
case Tool::FlippingByLine:
dialogTool->SetGroupCategories(doc->GetGroupCategories());
default:
break;
}
@ -1241,7 +1246,8 @@ void MainWindow::ClosedDialogGroup(int result)
{
const QPointer<DialogGroup> dialog = qobject_cast<DialogGroup *>(dialogTool);
SCASSERT(not dialog.isNull())
const QDomElement group = doc->CreateGroup(pattern->getNextId(), dialog->GetName(), dialog->GetGroup());
const QDomElement group = doc->CreateGroup(pattern->getNextId(), dialog->GetName(), dialog->GetTags(),
dialog->GetGroup());
if (not group.isNull())
{
AddGroup *addGroup = new AddGroup(group, doc);

View File

@ -800,6 +800,7 @@
<xs:attribute name="name" type="xs:string"/>
<xs:attribute name="visible" type="xs:boolean"/>
<xs:attribute name="tool" type="xs:unsignedInt"/>
<xs:attribute name="tags" type="xs:string"/>
</xs:complexType>
</xs:element>
</xs:sequence>

View File

@ -135,7 +135,8 @@ const QString VAbstractPattern::AttrNumber = QStringLiteral("number")
const QString VAbstractPattern::AttrCheckUniqueness = QStringLiteral("checkUniqueness");
const QString VAbstractPattern::AttrManualPassmarkLength = QStringLiteral("manualPassmarkLength");
const QString VAbstractPattern::AttrPassmarkLength = QStringLiteral("passmarkLength");
const QString VAbstractPattern::AttrOpacity = QStringLiteral("opacity");
const QString VAbstractPattern::AttrOpacity = QStringLiteral("opacity");
const QString VAbstractPattern::AttrTags = QStringLiteral("tags");
const QString VAbstractPattern::AttrAll = QStringLiteral("all");
@ -283,6 +284,17 @@ QMap<int, QString> AdjustMaterials(QMap<int, QString> materials)
return materials;
}
//---------------------------------------------------------------------------------------------------------------------
QString PrepareGroupTags(QStringList tags)
{
for (auto &tag : tags)
{
tag = tag.simplified();
}
return ConvertToList(ConvertToSet<QString>(tags)).join(',');
}
}
//---------------------------------------------------------------------------------------------------------------------
@ -2428,19 +2440,22 @@ QDomElement VAbstractPattern::CreateGroups()
}
//---------------------------------------------------------------------------------------------------------------------
QDomElement VAbstractPattern::CreateGroup(quint32 id, const QString &name, const QMap<quint32, quint32> &groupData,
vidtype tool)
QDomElement VAbstractPattern::CreateGroup(quint32 id, const QString &name, const QStringList &tags,
const QMap<quint32, quint32> &groupData, vidtype tool)
{
if (id == NULL_ID || groupData.isEmpty())
{
return QDomElement();
}
const QString preparedTags = PrepareGroupTags(tags);
QDomElement group = createElement(TagGroup);
SetAttribute(group, AttrId, id);
SetAttribute(group, AttrName, name);
SetAttribute(group, AttrVisible, true);
SetAttributeOrRemoveIf(group, AttrTool, tool, tool == null_id);
SetAttributeOrRemoveIf(group, AttrTags, preparedTags, preparedTags.isEmpty());
auto i = groupData.constBegin();
while (i != groupData.constEnd())
@ -2502,9 +2517,54 @@ void VAbstractPattern::SetGroupName(quint32 id, const QString &name)
}
//---------------------------------------------------------------------------------------------------------------------
QMap<quint32, QPair<QString, bool> > VAbstractPattern::GetGroups()
QStringList VAbstractPattern::GetGroupTags(vidtype id)
{
QMap<quint32, QPair<QString, bool> > data;
QStringList tags;
QDomElement group = elementById(id, TagGroup);
if (group.isElement())
{
tags = FilterGroupTags(GetParametrEmptyString(group, AttrTags));
}
return tags;
}
//---------------------------------------------------------------------------------------------------------------------
void VAbstractPattern::SetGroupTags(quint32 id, const QStringList &tags)
{
QDomElement group = elementById(id, TagGroup);
if (group.isElement())
{
const QString rawTags = tags.join(',');
SetAttributeOrRemoveIf(group, AttrTags, rawTags, rawTags.isEmpty());
modified = true;
emit patternChanged(false);
}
}
//---------------------------------------------------------------------------------------------------------------------
QStringList VAbstractPattern::GetGroupCategories() const
{
QSet<QString> categories;
const QDomNodeList groups = elementsByTagName(TagGroup);
for (int i=0; i < groups.size(); ++i)
{
const QDomElement group = groups.at(i).toElement();
if (not group.isNull() && group.hasAttribute(AttrTags))
{
QStringList groupTags = VAbstractPattern::FilterGroupTags(GetParametrEmptyString(group, AttrTags));
categories.unite(ConvertToSet<QString>(groupTags));
}
}
return ConvertToList(categories);
}
//---------------------------------------------------------------------------------------------------------------------
QMap<quint32, VGroupData> VAbstractPattern::GetGroups()
{
QMap<quint32, VGroupData> data;
try
{
@ -2521,11 +2581,13 @@ QMap<quint32, QPair<QString, bool> > VAbstractPattern::GetGroups()
{
if (group.tagName() == TagGroup)
{
VGroupData groupData;
const quint32 id = GetParametrUInt(group, AttrId, QChar('0'));
const bool visible = GetParametrBool(group, AttrVisible, trueStr);
const QString name = GetParametrString(group, AttrName, tr("New group"));
groupData.visible = GetParametrBool(group, AttrVisible, trueStr);
groupData.name = GetParametrString(group, AttrName, tr("New group"));
groupData.tags = FilterGroupTags(GetParametrEmptyString(group, AttrTags));
data.insert(id, qMakePair(name, visible));
data.insert(id, groupData);
}
}
}
@ -2539,7 +2601,7 @@ QMap<quint32, QPair<QString, bool> > VAbstractPattern::GetGroups()
}
catch (const VExceptionConversionError &)
{
return QMap<quint32, QPair<QString, bool> >();
return QMap<quint32, VGroupData>();
}
return data;
@ -2796,3 +2858,22 @@ QString VAbstractPattern::PieceDrawName(quint32 id)
return draw.attribute(VAbstractPattern::AttrName);
}
//---------------------------------------------------------------------------------------------------------------------
QStringList VAbstractPattern::FilterGroupTags(const QString &tags)
{
if (tags.isEmpty())
{
return QStringList();
}
QStringList list = tags.split(',');
for (auto &tag : list)
{
tag = tag.simplified();
}
list.removeAll("");
return ConvertToList(ConvertToSet<QString>(list));
}

View File

@ -78,6 +78,13 @@ struct VFinalMeasurement
QString description;
};
struct VGroupData
{
QString name{};
bool visible{true};
QStringList tags{};
};
QT_WARNING_POP
class VAbstractPattern : public VDomDocument
@ -200,18 +207,27 @@ public:
void ParseGroups(const QDomElement &domElement);
QDomElement CreateGroups();
QDomElement CreateGroup(quint32 id, const QString &name, const QMap<quint32, quint32> &groupData,
vidtype tool=null_id);
QDomElement CreateGroup(quint32 id, const QString &name, const QStringList &tags,
const QMap<quint32, quint32> &groupData, vidtype tool=null_id);
vidtype GroupLinkedToTool(vidtype toolId) const;
QString GetGroupName(quint32 id);
void SetGroupName(quint32 id, const QString &name);
QMap<quint32, QPair<QString, bool> > GetGroups();
QStringList GetGroupTags(vidtype id);
void SetGroupTags(quint32 id, const QStringList &tags);
QStringList GetGroupCategories() const;
QMap<quint32, VGroupData> GetGroups();
QMap<quint32, QString> GetGroupsContainingItem(quint32 toolId, quint32 objectId, bool containItem);
QDomElement AddItemToGroup(quint32 toolId, quint32 objectId, quint32 groupId);
QDomElement RemoveItemFromGroup(quint32 toolId, quint32 objectId, quint32 groupId);
bool GroupIsEmpty(quint32 id);
bool GetGroupVisibility(quint32 id);
static QStringList FilterGroupTags(const QString &tags);
QString PieceDrawName(quint32 id);
static const QString TagPattern;
@ -290,6 +306,7 @@ public:
static const QString AttrManualPassmarkLength;
static const QString AttrPassmarkLength;
static const QString AttrOpacity;
static const QString AttrTags;
static const QString AttrAll;

View File

@ -195,4 +195,27 @@ inline void AppendTo(Cont &container, const Input &input)
#endif // QT_VERSION >= QT_VERSION_CHECK(5, 5, 0)
}
//---------------------------------------------------------------------------------------------------------------------
template <typename T>
inline bool SetIntersects(const QSet<T> &set1, const QSet<T> &set2)
{
#if QT_VERSION >= QT_VERSION_CHECK(5, 6, 0)
return set1.intersects(set2);
#else
const bool otherIsBigger = set2.size() > set1.size();
const QSet<T> &smallestSet = otherIsBigger ? set1 : set2;
const QSet<T> &biggestSet = otherIsBigger ? set2 : set1;
typename QSet<T>::const_iterator i = smallestSet.cbegin();
typename QSet<T>::const_iterator e = smallestSet.cend();
while (i != e)
{
if (biggestSet.contains(*i))
return true;
++i;
}
return false;
#endif
}
#endif // COMPATIBILITY_H

View File

@ -30,6 +30,7 @@
#include <QColor>
#include <QComboBox>
#include <QCompleter>
#include <QDialog>
#include <QLabel>
#include <QLineEdit>
@ -173,6 +174,25 @@ void DialogFlippingByAxis::SetHasLinkedVisibilityGroup(bool linked)
ui->groupBoxVisibilityGroup->setChecked(linked);
}
//---------------------------------------------------------------------------------------------------------------------
void DialogFlippingByAxis::SetVisibilityGroupTags(const QStringList &tags)
{
ui->lineEditGroupTags->setText(tags.join(", "));
}
//---------------------------------------------------------------------------------------------------------------------
QStringList DialogFlippingByAxis::GetVisibilityGroupTags() const
{
return ui->lineEditGroupTags->text().split(',');
}
//---------------------------------------------------------------------------------------------------------------------
void DialogFlippingByAxis::SetGroupCategories(const QStringList &categories)
{
m_groupTags = categories;
ui->lineEditGroupTags->SetCompletion(m_groupTags);
}
//---------------------------------------------------------------------------------------------------------------------
void DialogFlippingByAxis::ShowDialog(bool click)
{
@ -342,6 +362,18 @@ void DialogFlippingByAxis::SaveData()
operation->SetOriginPointId(GetOriginPointId());
operation->SetAxisType(GetAxisType());
operation->RefreshGeometry();
QStringList groupTags = ui->lineEditGroupTags->text().split(',');
for (auto &tag : groupTags)
{
tag = tag.trimmed();
if (not m_groupTags.contains(tag))
{
m_groupTags.append(tag);
}
}
ui->lineEditGroupTags->SetCompletion(m_groupTags);
}
//---------------------------------------------------------------------------------------------------------------------

View File

@ -71,6 +71,11 @@ public:
bool HasLinkedVisibilityGroup() const;
void SetHasLinkedVisibilityGroup(bool linked);
void SetVisibilityGroupTags(const QStringList &tags);
QStringList GetVisibilityGroupTags() const;
virtual void SetGroupCategories(const QStringList &categories) override;
virtual void ShowDialog(bool click) override;
public slots:
@ -106,6 +111,8 @@ private:
bool flagGroupName;
bool flagError;
QStringList m_groupTags{};
static void FillComboBoxAxisType(QComboBox *box);
};

View File

@ -7,7 +7,7 @@
<x>0</x>
<y>0</y>
<width>304</width>
<height>207</height>
<height>237</height>
</rect>
</property>
<property name="windowTitle">
@ -62,15 +62,15 @@
<property name="checked">
<bool>false</bool>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QLabel" name="labelGroupName">
<property name="text">
<string>Name:</string>
</property>
</widget>
</item>
<item>
<item row="0" column="1">
<widget class="QLineEdit" name="lineEditVisibilityGroup">
<property name="text">
<string>Flipping by axis</string>
@ -80,6 +80,26 @@
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Tags:</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="VCompleterLineEdit" name="lineEditGroupTags">
<property name="toolTip">
<string>Separate each tag with comma.</string>
</property>
<property name="placeholderText">
<string>Add tags</string>
</property>
<property name="clearButtonEnabled">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
</item>
@ -95,6 +115,13 @@
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>VCompleterLineEdit</class>
<extends>QLineEdit</extends>
<header>vlineedit.h</header>
</customwidget>
</customwidgets>
<resources/>
<connections>
<connection>

View File

@ -30,6 +30,7 @@
#include <QColor>
#include <QComboBox>
#include <QCompleter>
#include <QDialog>
#include <QLabel>
#include <QLineEdit>
@ -168,6 +169,25 @@ void DialogFlippingByLine::SetHasLinkedVisibilityGroup(bool linked)
ui->groupBoxVisibilityGroup->setChecked(linked);
}
//---------------------------------------------------------------------------------------------------------------------
void DialogFlippingByLine::SetVisibilityGroupTags(const QStringList &tags)
{
ui->lineEditGroupTags->setText(tags.join(", "));
}
//---------------------------------------------------------------------------------------------------------------------
QStringList DialogFlippingByLine::GetVisibilityGroupTags() const
{
return ui->lineEditGroupTags->text().split(',');
}
//---------------------------------------------------------------------------------------------------------------------
void DialogFlippingByLine::SetGroupCategories(const QStringList &categories)
{
m_groupTags = categories;
ui->lineEditGroupTags->SetCompletion(m_groupTags);
}
//---------------------------------------------------------------------------------------------------------------------
void DialogFlippingByLine::ShowDialog(bool click)
{
@ -366,6 +386,18 @@ void DialogFlippingByLine::SaveData()
operation->SetFirstLinePointId(GetFirstLinePointId());
operation->SetSecondLinePointId(GetSecondLinePointId());
operation->RefreshGeometry();
QStringList groupTags = ui->lineEditGroupTags->text().split(',');
for (auto &tag : groupTags)
{
tag = tag.trimmed();
if (not m_groupTags.contains(tag))
{
m_groupTags.append(tag);
}
}
ui->lineEditGroupTags->SetCompletion(m_groupTags);
}
//---------------------------------------------------------------------------------------------------------------------

View File

@ -71,6 +71,11 @@ public:
bool HasLinkedVisibilityGroup() const;
void SetHasLinkedVisibilityGroup(bool linked);
void SetVisibilityGroupTags(const QStringList &tags);
QStringList GetVisibilityGroupTags() const;
virtual void SetGroupCategories(const QStringList &categories) override;
virtual void ShowDialog(bool click) override;
public slots:
@ -105,6 +110,8 @@ private:
bool flagName;
bool flagGroupName;
bool flagError;
QStringList m_groupTags{};
};
//---------------------------------------------------------------------------------------------------------------------

View File

@ -7,7 +7,7 @@
<x>0</x>
<y>0</y>
<width>304</width>
<height>207</height>
<height>237</height>
</rect>
</property>
<property name="windowTitle">
@ -66,15 +66,15 @@
<property name="checked">
<bool>false</bool>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QLabel" name="labelGroupName">
<property name="text">
<string>Name:</string>
</property>
</widget>
</item>
<item>
<item row="0" column="1">
<widget class="QLineEdit" name="lineEditVisibilityGroup">
<property name="text">
<string>Flipping by line</string>
@ -84,6 +84,26 @@
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Tags:</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="VCompleterLineEdit" name="lineEditGroupTags">
<property name="toolTip">
<string>Separate each tag with comma.</string>
</property>
<property name="placeholderText">
<string>Add tags</string>
</property>
<property name="clearButtonEnabled">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
</item>
@ -99,6 +119,13 @@
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>VCompleterLineEdit</class>
<extends>QLineEdit</extends>
<header>vlineedit.h</header>
</customwidget>
</customwidgets>
<resources>
<include location="../../../vmisc/share/resources/icon.qrc"/>
</resources>

View File

@ -28,6 +28,7 @@
#include "dialoggroup.h"
#include <QCompleter>
#include <QLineEdit>
#include "ui_dialoggroup.h"
@ -63,6 +64,24 @@ QString DialogGroup::GetName() const
return ui->lineEditName->text();
}
//---------------------------------------------------------------------------------------------------------------------
void DialogGroup::SetTags(const QStringList &tags)
{
ui->lineEditTags->setText(tags.join(", "));
}
//---------------------------------------------------------------------------------------------------------------------
QStringList DialogGroup::GetTags() const
{
return ui->lineEditTags->text().split(",");
}
//---------------------------------------------------------------------------------------------------------------------
void DialogGroup::SetGroupCategories(const QStringList &categories)
{
ui->lineEditTags->SetCompletion(categories);
}
//---------------------------------------------------------------------------------------------------------------------
void DialogGroup::ShowDialog(bool click)
{

View File

@ -54,6 +54,11 @@ public:
void SetName(const QString &name);
QString GetName() const;
void SetTags(const QStringList &tags);
QStringList GetTags() const;
void SetGroupCategories(const QStringList &categories);
QMap<quint32, quint32> GetGroup() const;
virtual void ShowDialog(bool click) override;

View File

@ -6,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>397</width>
<height>80</height>
<width>294</width>
<height>104</height>
</rect>
</property>
<property name="windowTitle">
@ -19,22 +19,45 @@
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Group name:</string>
</property>
</widget>
</item>
<item>
<item row="0" column="1">
<widget class="QLineEdit" name="lineEditName">
<property name="toolTip">
<string>Unique pattern piece name</string>
<string/>
</property>
<property name="placeholderText">
<string>Choose group name</string>
</property>
<property name="clearButtonEnabled">
<bool>true</bool>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Tags:</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="VCompleterLineEdit" name="lineEditTags">
<property name="toolTip">
<string>Separate each tag with comma.</string>
</property>
<property name="placeholderText">
<string>Add tags</string>
</property>
<property name="clearButtonEnabled">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
@ -51,6 +74,13 @@
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>VCompleterLineEdit</class>
<extends>QLineEdit</extends>
<header>vlineedit.h</header>
</customwidget>
</customwidgets>
<resources>
<include location="../../../vmisc/share/resources/icon.qrc"/>
</resources>

View File

@ -30,6 +30,7 @@
#include <QColor>
#include <QComboBox>
#include <QCompleter>
#include <QDialog>
#include <QLabel>
#include <QLineEdit>
@ -283,6 +284,25 @@ void DialogMove::SetHasLinkedVisibilityGroup(bool linked)
ui->groupBoxVisibilityGroup->setChecked(linked);
}
//---------------------------------------------------------------------------------------------------------------------
void DialogMove::SetVisibilityGroupTags(const QStringList &tags)
{
ui->lineEditGroupTags->setText(tags.join(", "));
}
//---------------------------------------------------------------------------------------------------------------------
QStringList DialogMove::GetVisibilityGroupTags() const
{
return ui->lineEditGroupTags->text().split(',');
}
//---------------------------------------------------------------------------------------------------------------------
void DialogMove::SetGroupCategories(const QStringList &categories)
{
m_groupTags = categories;
ui->lineEditGroupTags->SetCompletion(m_groupTags);
}
//---------------------------------------------------------------------------------------------------------------------
void DialogMove::ShowDialog(bool click)
{
@ -551,6 +571,18 @@ void DialogMove::SaveData()
operation->SetRotationAngle(formulaRotationAngle);
operation->SetRotationOriginPointId(GetRotationOrigPointId());
operation->RefreshGeometry();
QStringList groupTags = ui->lineEditGroupTags->text().split(',');
for (auto &tag : groupTags)
{
tag = tag.trimmed();
if (not m_groupTags.contains(tag))
{
m_groupTags.append(tag);
}
}
ui->lineEditGroupTags->SetCompletion(m_groupTags);
}
//---------------------------------------------------------------------------------------------------------------------

View File

@ -76,6 +76,11 @@ public:
bool HasLinkedVisibilityGroup() const;
void SetHasLinkedVisibilityGroup(bool linked);
void SetVisibilityGroupTags(const QStringList &tags);
QStringList GetVisibilityGroupTags() const;
virtual void SetGroupCategories(const QStringList &categories) override;
virtual void ShowDialog(bool click) override;
public slots:
@ -138,6 +143,8 @@ private:
bool flagName;
bool flagGroupName;
QStringList m_groupTags{};
void EvalAngle();
void EvalRotationAngle();
void EvalLength();

View File

@ -6,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>304</width>
<height>402</height>
<width>424</width>
<height>432</height>
</rect>
</property>
<property name="windowTitle">
@ -605,15 +605,15 @@
<property name="checked">
<bool>false</bool>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QLabel" name="labelGroupName">
<property name="text">
<string>Name:</string>
</property>
</widget>
</item>
<item>
<item row="0" column="1">
<widget class="QLineEdit" name="lineEditVisibilityGroup">
<property name="text">
<string>Move</string>
@ -623,6 +623,26 @@
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_5">
<property name="text">
<string>Tags:</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="VCompleterLineEdit" name="lineEditGroupTags">
<property name="toolTip">
<string>Separate each tag with comma.</string>
</property>
<property name="placeholderText">
<string>Add tags</string>
</property>
<property name="clearButtonEnabled">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
</item>
@ -639,6 +659,11 @@
</layout>
</widget>
<customwidgets>
<customwidget>
<class>VCompleterLineEdit</class>
<extends>QLineEdit</extends>
<header>vlineedit.h</header>
</customwidget>
<customwidget>
<class>VPlainTextEdit</class>
<extends>QPlainTextEdit</extends>

View File

@ -30,6 +30,7 @@
#include <QColor>
#include <QComboBox>
#include <QCompleter>
#include <QDialog>
#include <QLabel>
#include <QLineEdit>
@ -196,6 +197,25 @@ void DialogRotation::SetHasLinkedVisibilityGroup(bool linked)
ui->groupBoxVisibilityGroup->setChecked(linked);
}
//---------------------------------------------------------------------------------------------------------------------
void DialogRotation::SetVisibilityGroupTags(const QStringList &tags)
{
ui->lineEditGroupTags->setText(tags.join(", "));
}
//---------------------------------------------------------------------------------------------------------------------
QStringList DialogRotation::GetVisibilityGroupTags() const
{
return ui->lineEditGroupTags->text().split(',');
}
//---------------------------------------------------------------------------------------------------------------------
void DialogRotation::SetGroupCategories(const QStringList &categories)
{
m_groupTags = categories;
ui->lineEditGroupTags->SetCompletion(m_groupTags);
}
//---------------------------------------------------------------------------------------------------------------------
void DialogRotation::ShowDialog(bool click)
{
@ -432,6 +452,18 @@ void DialogRotation::SaveData()
operation->SetOriginPointId(GetOrigPointId());
operation->SetAngle(formulaAngle);
operation->RefreshGeometry();
QStringList groupTags = ui->lineEditGroupTags->text().split(',');
for (auto &tag : groupTags)
{
tag = tag.trimmed();
if (not m_groupTags.contains(tag))
{
m_groupTags.append(tag);
}
}
ui->lineEditGroupTags->SetCompletion(m_groupTags);
}
//---------------------------------------------------------------------------------------------------------------------

View File

@ -69,6 +69,11 @@ public:
bool HasLinkedVisibilityGroup() const;
void SetHasLinkedVisibilityGroup(bool linked);
void SetVisibilityGroupTags(const QStringList &tags);
QStringList GetVisibilityGroupTags() const;
virtual void SetGroupCategories(const QStringList &categories) override;
virtual void ShowDialog(bool click) override;
public slots:
@ -120,6 +125,8 @@ private:
bool flagName;
bool flagGroupName;
bool flagError;
QStringList m_groupTags{};
};
//---------------------------------------------------------------------------------------------------------------------

View File

@ -7,7 +7,7 @@
<x>0</x>
<y>0</y>
<width>392</width>
<height>252</height>
<height>282</height>
</rect>
</property>
<property name="windowTitle">
@ -236,18 +236,38 @@
<property name="checked">
<bool>false</bool>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<layout class="QGridLayout" name="gridLayout">
<item row="1" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Tags:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLineEdit" name="lineEditVisibilityGroup">
<property name="text">
<string>Rotation</string>
</property>
<property name="clearButtonEnabled">
<bool>true</bool>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="labelGroupName">
<property name="text">
<string>Name:</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="lineEditVisibilityGroup">
<property name="text">
<string>Rotation</string>
<item row="1" column="1">
<widget class="VCompleterLineEdit" name="lineEditGroupTags">
<property name="toolTip">
<string>Separate each tag with comma.</string>
</property>
<property name="placeholderText">
<string>Add tags</string>
</property>
<property name="clearButtonEnabled">
<bool>true</bool>
@ -270,6 +290,11 @@
</layout>
</widget>
<customwidgets>
<customwidget>
<class>VCompleterLineEdit</class>
<extends>QLineEdit</extends>
<header>vlineedit.h</header>
</customwidget>
<customwidget>
<class>VPlainTextEdit</class>
<extends>QPlainTextEdit</extends>

View File

@ -799,6 +799,13 @@ void DialogTool::SetToolId(const quint32 &value)
toolId = value;
}
//---------------------------------------------------------------------------------------------------------------------
void DialogTool::SetGroupCategories(const QStringList &categories)
{
Q_UNUSED(categories)
// do nothing
}
//---------------------------------------------------------------------------------------------------------------------
void DialogTool::ShowDialog(bool click)
{

View File

@ -90,6 +90,8 @@ public:
quint32 GetToolId() const;
void SetToolId(const quint32 &value);
virtual void SetGroupCategories(const QStringList &categories);
static void MoveListRowTop(QListWidget *list);
static void MoveListRowUp(QListWidget *list);
static void MoveListRowDown(QListWidget *list);

View File

@ -93,6 +93,7 @@ VToolFlippingByAxis *VToolFlippingByAxis::Create(const QPointer<DialogTool> &dia
initData.source = dialogTool->GetObjects();
initData.hasLinkedVisibilityGroup = dialogTool->HasLinkedVisibilityGroup();
initData.visibilityGroupName = dialogTool->GetVisibilityGroupName();
initData.visibilityGroupTags = dialogTool->GetVisibilityGroupTags();
initData.scene = scene;
initData.doc = doc;
initData.data = data;

View File

@ -93,6 +93,7 @@ VToolFlippingByLine *VToolFlippingByLine::Create(const QPointer<DialogTool> &dia
initData.source = dialogTool->GetObjects();
initData.hasLinkedVisibilityGroup = dialogTool->HasLinkedVisibilityGroup();
initData.visibilityGroupName = dialogTool->GetVisibilityGroupName();
initData.visibilityGroupTags = dialogTool->GetVisibilityGroupTags();
initData.scene = scene;
initData.doc = doc;
initData.data = data;

View File

@ -609,9 +609,9 @@ void VAbstractOperation::ApplyToolOptions(const QList<quint32> &oldDependencies,
{
if (group != null_id)
{
RenameGroup *renameGroup = new RenameGroup(doc, group, groupName);
connect(renameGroup, &RenameGroup::UpdateGroups, doc, &VAbstractPattern::UpdateVisiblityGroups);
qApp->getUndoStack()->push(renameGroup);
ChangeGroupOptions *groupOptions = new ChangeGroupOptions(doc, group, groupName, groupTags);
connect(groupOptions, &ChangeGroupOptions::UpdateGroups, doc, &VAbstractPattern::UpdateVisiblityGroups);
qApp->getUndoStack()->push(groupOptions);
}
else
{
@ -619,6 +619,7 @@ void VAbstractOperation::ApplyToolOptions(const QList<quint32> &oldDependencies,
initData.id = m_id;
initData.hasLinkedVisibilityGroup = hasLinkedGroup;
initData.visibilityGroupName = groupName;
initData.visibilityGroupTags = groupTags;
initData.data = &(VDataTool::data);
initData.doc = doc;
initData.source = source;
@ -790,7 +791,7 @@ bool VAbstractOperation::NeedUpdateVisibilityGroup() const
{
if (group != null_id)
{
if (groupName != doc->GetGroupName(group))
if (groupName != doc->GetGroupName(group) || groupTags != doc->GetGroupTags(group))
{
return true; // rename group
}
@ -916,7 +917,8 @@ void VAbstractOperation::CreateVisibilityGroup(const VAbstractOperationInitData
const QMap<quint32, quint32> groupData = VisibilityGroupDataFromSource(initData.data, initData.source);
vidtype groupId = initData.data->getNextId();
const QDomElement group = initData.doc->CreateGroup(groupId, initData.visibilityGroupName, groupData, initData.id);
const QDomElement group = initData.doc->CreateGroup(groupId, initData.visibilityGroupName,
initData.visibilityGroupTags, groupData, initData.id);
if (not group.isNull())
{
AddGroup *addGroup = new AddGroup(group, initData.doc);

View File

@ -60,6 +60,7 @@ struct VAbstractOperationInitData : VAbstractToolInitData
QVector<quint32> source{};
QVector<DestinationItem> destination{};
QString visibilityGroupName{};
QStringList visibilityGroupTags{};
bool hasLinkedVisibilityGroup{false};
};
@ -134,6 +135,7 @@ protected:
bool hasLinkedGroup{false};
QString groupName{};
QStringList groupTags{};
VAbstractOperation(VAbstractPattern *doc, VContainer *data, quint32 id, const QString &suffix,
const QVector<quint32> &source, const QVector<DestinationItem> &destination,
@ -187,6 +189,7 @@ void VAbstractOperation::SetDialogVisibilityGroupData(QPointer<T> dialogTool)
{
dialogTool->SetHasLinkedVisibilityGroup(true);
dialogTool->SetVisibilityGroupName(doc->GetGroupName(group));
dialogTool->SetVisibilityGroupTags(doc->GetGroupTags(group));
}
else
{

View File

@ -149,6 +149,7 @@ VToolMove *VToolMove::Create(const QPointer<DialogTool> &dialog, VMainGraphicsSc
initData.source = dialogTool->GetObjects();
initData.hasLinkedVisibilityGroup = dialogTool->HasLinkedVisibilityGroup();
initData.visibilityGroupName = dialogTool->GetVisibilityGroupName();
initData.visibilityGroupTags = dialogTool->GetVisibilityGroupTags();
initData.scene = scene;
initData.doc = doc;
initData.data = data;

View File

@ -117,6 +117,7 @@ VToolRotation *VToolRotation::Create(const QPointer<DialogTool> &dialog, VMainGr
initData.source = dialogTool->GetObjects();
initData.hasLinkedVisibilityGroup = dialogTool->HasLinkedVisibilityGroup();
initData.visibilityGroupName = dialogTool->GetVisibilityGroupName();
initData.visibilityGroupTags = dialogTool->GetVisibilityGroupTags();
initData.scene = scene;
initData.doc = doc;
initData.data = data;

View File

@ -145,6 +145,38 @@ void RenameGroup::redo()
emit UpdateGroups();
}
//ChangeGroupOptions
//---------------------------------------------------------------------------------------------------------------------
ChangeGroupOptions::ChangeGroupOptions(VAbstractPattern *doc, quint32 id, const QString &name, const QStringList &tags,
QUndoCommand *parent)
: VUndoCommand(QDomElement(), doc, parent),
newName(name),
newTags(tags)
{
setText(tr("rename group"));
nodeId = id;
oldName = doc->GetGroupName(nodeId);
oldTags = doc->GetGroupTags(nodeId);
}
//---------------------------------------------------------------------------------------------------------------------
void ChangeGroupOptions::undo()
{
qCDebug(vUndo, "Undo.");
doc->SetGroupName(nodeId, oldName);
doc->SetGroupTags(nodeId, oldTags);
emit UpdateGroups();
}
//---------------------------------------------------------------------------------------------------------------------
void ChangeGroupOptions::redo()
{
qCDebug(vUndo, "Redo.");
doc->SetGroupName(nodeId, newName);
doc->SetGroupTags(nodeId, newTags);
emit UpdateGroups();
}
//AddItemToGroup
//---------------------------------------------------------------------------------------------------------------------
AddItemToGroup::AddItemToGroup(const QDomElement &xml, VAbstractPattern *doc, quint32 groupId, QUndoCommand *parent)

View File

@ -69,6 +69,25 @@ private:
QString oldName{};
};
class ChangeGroupOptions : public VUndoCommand
{
Q_OBJECT
public:
ChangeGroupOptions(VAbstractPattern *doc, quint32 id, const QString &name, const QStringList &tags,
QUndoCommand *parent = nullptr);
virtual ~ChangeGroupOptions()=default;
virtual void undo() override;
virtual void redo() override;
signals:
void UpdateGroups();
private:
Q_DISABLE_COPY(ChangeGroupOptions)
QString newName;
QString oldName{};
QStringList newTags;
QStringList oldTags{};
};
class AddItemToGroup : public VUndoCommand
{
Q_OBJECT

View File

@ -28,6 +28,72 @@
#include "vlineedit.h"
#include <QApplication>
#include <QCompleter>
#include <QStringListModel>
#include <QTimer>
#include <QtDebug>
#include "../vmisc/compatibility.h"
namespace
{
class MultiSelectCompleter : public QCompleter
{
public:
MultiSelectCompleter(QObject* parent=nullptr);
MultiSelectCompleter(const QStringList& items, QObject* parent=nullptr);
virtual ~MultiSelectCompleter() =default;
virtual QString pathFromIndex(const QModelIndex& index) const override;
virtual QStringList splitPath(const QString& path) const override;
private:
Q_DISABLE_COPY(MultiSelectCompleter)
};
}
//MultiSelectCompleter
//---------------------------------------------------------------------------------------------------------------------
MultiSelectCompleter::MultiSelectCompleter(QObject *parent)
: QCompleter(parent)
{}
//---------------------------------------------------------------------------------------------------------------------
MultiSelectCompleter::MultiSelectCompleter(const QStringList& items, QObject* parent)
: QCompleter(items, parent)
{}
//---------------------------------------------------------------------------------------------------------------------
QString MultiSelectCompleter::pathFromIndex(const QModelIndex& index) const
{
QString path = QCompleter::pathFromIndex(index);
QString text = static_cast<QLineEdit*>(widget())->text();
int pos = text.lastIndexOf(',');
if (pos >= 0)
{
path = text.left(pos) + ", " + path;
}
return path;
}
//---------------------------------------------------------------------------------------------------------------------
QStringList MultiSelectCompleter::splitPath( const QString& path ) const
{
int pos = path.lastIndexOf(',') + 1;
while (pos < path.length() && path.at(pos) == QLatin1Char(' '))
{
pos++;
}
return QStringList(path.mid(pos));
}
//VLineEdit
//---------------------------------------------------------------------------------------------------------------------
VLineEdit::VLineEdit(QWidget *parent)
: QLineEdit(parent),
@ -74,3 +140,59 @@ void VLineEdit::mousePressEvent(QMouseEvent *e)
}
}
// VCompleterLineEdit
//---------------------------------------------------------------------------------------------------------------------
VCompleterLineEdit::VCompleterLineEdit(QWidget *parent)
: VLineEdit(parent),
m_model(new QStringListModel(this))
{
setCompleter(new MultiSelectCompleter());
completer()->setModel(m_model);
completer()->setCompletionMode(QCompleter::PopupCompletion);
completer()->setCaseSensitivity(Qt::CaseInsensitive);
connect(this, &VCompleterLineEdit::textEdited, this, &VCompleterLineEdit::ShowCompletion);
}
//---------------------------------------------------------------------------------------------------------------------
void VCompleterLineEdit::SetCompletion(const QStringList &list)
{
m_model->setStringList(list);
}
//---------------------------------------------------------------------------------------------------------------------
void VCompleterLineEdit::focusInEvent(QFocusEvent *e)
{
QLineEdit::focusInEvent(e);
// force completion when line edit is focued in
completer()->complete();
}
//---------------------------------------------------------------------------------------------------------------------
void VCompleterLineEdit::ShowCompletion()
{
// PrepareCompletion();
// force to show all items when text is empty
completer()->setCompletionMode(text().isEmpty() ? QCompleter::UnfilteredPopupCompletion
: QCompleter::PopupCompletion);
if (text().isEmpty())
{
// completion list will be hidden now; we will show it again after a delay
QTimer::singleShot(100, this, &VCompleterLineEdit::CompletionPopup);
}
}
//---------------------------------------------------------------------------------------------------------------------
void VCompleterLineEdit::CompletionPopup()
{
// apparently, complete() works only in event handler
QApplication::postEvent(this, new QEvent(QEvent::User));
}
//---------------------------------------------------------------------------------------------------------------------
void VCompleterLineEdit::customEvent(QEvent *e)
{
QLineEdit::customEvent(e);
// force completion after text is deleted
completer()->complete();
}

View File

@ -31,6 +31,8 @@
#include <QLineEdit>
class QStringListModel;
class VLineEdit : public QLineEdit
{
Q_OBJECT
@ -47,4 +49,31 @@ private:
bool m_selectOnMousePress;
};
/*! Line edit widget with auto completion based on QStringListModel.
Modified behaviour: completion list will appear even when contents of
line edit is empty. Full list of options will be showed when line edit
has focus and is empty.
*/
class VCompleterLineEdit : public VLineEdit
{
Q_OBJECT
public:
explicit VCompleterLineEdit(QWidget *parent = nullptr);
//! Set list of options used for completion.
void SetCompletion(const QStringList &list);
protected:
virtual void focusInEvent(QFocusEvent *e) override;
virtual void customEvent(QEvent* e) override;
private slots:
void ShowCompletion();
void CompletionPopup();
private:
Q_DISABLE_COPY(VCompleterLineEdit)
QStringListModel *m_model;
};
#endif // VLINEEDIT_H