WIP: package template selection dialog

Plus some initial package templates (without files).
This commit is contained in:
Matthias Koefferlein 2017-03-23 22:19:13 +01:00
parent 1353c9dfb0
commit 4a90479187
14 changed files with 633 additions and 32 deletions

View File

@ -0,0 +1,237 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>SaltGrainTemplateSelectionDialog</class>
<widget class="QDialog" name="SaltGrainTemplateSelectionDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>401</width>
<height>499</height>
</rect>
</property>
<property name="windowTitle">
<string>Create Package</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QLabel" name="label">
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>Template</string>
</property>
</widget>
</item>
<item>
<widget class="QListView" name="salt_view">
<property name="alternatingRowColors">
<bool>true</bool>
</property>
<property name="iconSize">
<size>
<width>64</width>
<height>64</height>
</size>
</property>
<property name="selectionRectVisible">
<bool>false</bool>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_4">
<property name="font">
<font>
<italic>true</italic>
</font>
</property>
<property name="text">
<string>(Pick a template with which to initialize your new package)</string>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>10</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QLabel" name="label_2">
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>Package Name</string>
</property>
</widget>
</item>
<item>
<widget class="QFrame" name="frame">
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
<layout class="QHBoxLayout" name="horizontalLayout">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QLineEdit" name="name_edit"/>
</item>
<item>
<widget class="lay::AlertLogButton" name="name_alert">
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="text">
<string>...</string>
</property>
<property name="icon">
<iconset resource="layResources.qrc">
<normaloff>:/warn.png</normaloff>:/warn.png</iconset>
</property>
<property name="autoRaise">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QLabel" name="label_3">
<property name="font">
<font>
<weight>50</weight>
<italic>true</italic>
<bold>false</bold>
</font>
</property>
<property name="text">
<string>(Choose a simple name composed of letters, digits and underscores. Use the notation &quot;group/package&quot; to create a package inside a group)</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
<action name="actionNew">
<property name="icon">
<iconset resource="layResources.qrc">
<normaloff>:/add.png</normaloff>:/add.png</iconset>
</property>
<property name="text">
<string>New</string>
</property>
<property name="toolTip">
<string>New package</string>
</property>
</action>
<action name="actionDelete">
<property name="icon">
<iconset resource="layResources.qrc">
<normaloff>:/clear.png</normaloff>:/clear.png</iconset>
</property>
<property name="text">
<string>Delete</string>
</property>
<property name="toolTip">
<string>Delete package</string>
</property>
</action>
<action name="actionImport">
<property name="icon">
<iconset resource="layResources.qrc">
<normaloff>:/import.png</normaloff>:/import.png</iconset>
</property>
<property name="text">
<string>Import</string>
</property>
<property name="toolTip">
<string>Import package</string>
</property>
</action>
</widget>
<customwidgets>
<customwidget>
<class>lay::AlertLogButton</class>
<extends>QToolButton</extends>
<header>layLogViewerDialog.h</header>
</customwidget>
</customwidgets>
<resources>
<include location="layResources.qrc"/>
</resources>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>SaltGrainTemplateSelectionDialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>273</x>
<y>431</y>
</hint>
<hint type="destinationlabel">
<x>276</x>
<y>448</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>SaltGrainTemplateSelectionDialog</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>351</x>
<y>426</y>
</hint>
<hint type="destinationlabel">
<x>363</x>
<y>445</y>
</hint>
</hints>
</connection>
</connections>
</ui>

View File

@ -99,7 +99,8 @@ FORMS = \
TechSaveOptionsEditorPage.ui \
MainConfigPage7.ui \
SaltManagerDialog.ui \
SaltGrainPropertiesDialog.ui
SaltGrainPropertiesDialog.ui \
SaltGrainTemplateSelectionDialog.ui
SOURCES = \
gsiDeclLayApplication.cc \
@ -156,6 +157,7 @@ RESOURCES = layBuildInMacros.qrc \
layLayoutStatistics.qrc \
layMacroTemplates.qrc \
layResources.qrc \
laySaltTemplates.qrc
INCLUDEPATH += ../tl ../gsi ../db ../rdb ../laybasic ../ant ../img ../edt
DEPENDPATH += ../tl ../gsi ../db ../rdb ../laybasic ../ant ../img ../edt

View File

@ -81,11 +81,15 @@ Salt::grain_by_name (const std::string &name)
void
Salt::add_location (const std::string &path)
{
// do nothing if the collection is already there
QFileInfo fi (tl::to_qstring (path));
for (lay::SaltGrains::collection_iterator g = m_root.begin_collections (); g != m_root.end_collections (); ++g) {
if (QFileInfo (tl::to_qstring (g->path ())) == fi) {
return;
tl_assert (! path.empty ());
if (path[0] != ':') {
// do nothing if the collection is already there
QFileInfo fi (tl::to_qstring (path));
for (lay::SaltGrains::collection_iterator g = m_root.begin_collections (); g != m_root.end_collections (); ++g) {
if (QFileInfo (tl::to_qstring (g->path ())) == fi) {
return;
}
}
}

View File

@ -28,6 +28,7 @@
#include <QDir>
#include <QFileInfo>
#include <QBuffer>
#include <QResource>
namespace lay
{
@ -326,8 +327,28 @@ SaltGrain::is_readonly () const
void
SaltGrain::load (const std::string &p)
{
tl::XMLFileSource source (p);
xml_struct.parse (source, *this);
tl_assert (!p.empty ());
if (p[0] != ':') {
tl::XMLFileSource source (p);
xml_struct.parse (source, *this);
} else {
QResource res (tl::to_qstring (p));
QByteArray data;
if (res.isCompressed ()) {
data = qUncompress ((const unsigned char *)res.data (), (int)res.size ());
} else {
data = QByteArray ((const char *)res.data (), (int)res.size ());
}
std::string str_data (data.constData (), data.size ());
tl::XMLStringSource source (str_data);
xml_struct.parse (source, *this);
}
}
void
@ -376,9 +397,15 @@ SaltGrain::from_url (const std::string &url)
bool
SaltGrain::is_grain (const std::string &path)
{
QDir dir (tl::to_qstring (path));
QString gf = dir.filePath (tl::to_qstring (grain_filename));
return QFileInfo (gf).exists ();
tl_assert (! path.empty ());
if (path[0] != ':') {
QDir dir (tl::to_qstring (path));
QString gf = dir.filePath (tl::to_qstring (grain_filename));
return QFileInfo (gf).exists ();
} else {
return QResource (tl::to_qstring (path + "/" + grain_filename)).isValid ();
}
}
}

View File

@ -26,6 +26,7 @@
#include <QDir>
#include <QFileInfo>
#include <QResource>
namespace lay
{
@ -129,37 +130,102 @@ SaltGrains::is_readonly () const
return QFileInfo (tl::to_qstring (path ())).isWritable ();
}
namespace
{
/**
* @brief A helper class required because directory traversal is not supported by QResource directly
*/
class OpenResource
: public QResource
{
public:
using QResource::isDir;
using QResource::isFile;
using QResource::children;
OpenResource (const QString &path)
: QResource (path)
{
// .. nothing yet ..
}
};
}
SaltGrains
SaltGrains::from_path (const std::string &path, const std::string &prefix)
{
tl_assert (! path.empty ());
SaltGrains grains;
grains.set_path (path);
QDir dir (tl::to_qstring (path));
QStringList entries = dir.entryList (QDir::NoDotAndDotDot | QDir::Dirs, QDir::Name);
for (QStringList::const_iterator e = entries.begin (); e != entries.end (); ++e) {
if (path[0] != ':') {
QDir dir (tl::to_qstring (path));
QStringList entries = dir.entryList (QDir::NoDotAndDotDot | QDir::Dirs, QDir::Name);
for (QStringList::const_iterator e = entries.begin (); e != entries.end (); ++e) {
std::string new_prefix = prefix;
if (! new_prefix.empty ()) {
new_prefix += "/";
}
new_prefix += tl::to_string (*e);
std::string epath = tl::to_string (dir.absoluteFilePath (*e));
if (SaltGrain::is_grain (epath)) {
try {
SaltGrain g (SaltGrain::from_path (epath));
g.set_name (new_prefix);
grains.add_grain (g);
} catch (...) {
// ignore errors (TODO: what to do here?)
}
} else if (QFileInfo (tl::to_qstring (epath)).isDir ()) {
SaltGrains c = SaltGrains::from_path (epath, new_prefix);
c.set_name (new_prefix);
if (! c.is_empty ()) {
grains.add_collection (c);
}
}
std::string new_prefix = prefix;
if (! new_prefix.empty ()) {
new_prefix += "/";
}
new_prefix += tl::to_string (*e);
std::string epath = tl::to_string (dir.absoluteFilePath (*e));
if (SaltGrain::is_grain (epath)) {
try {
SaltGrain g (SaltGrain::from_path (epath));
g.set_name (new_prefix);
grains.add_grain (g);
} catch (...) {
// ignore errors (TODO: what to do here?)
}
} else if (QFileInfo (tl::to_qstring (epath)).isDir ()) {
SaltGrains c = SaltGrains::from_path (epath, new_prefix);
c.set_name (new_prefix);
if (! c.is_empty ()) {
grains.add_collection (c);
} else {
OpenResource resource (tl::to_qstring (path));
if (resource.isDir ()) {
QStringList templ_dir = resource.children ();
for (QStringList::const_iterator t = templ_dir.begin (); t != templ_dir.end (); ++t) {
std::string new_prefix = prefix;
if (! new_prefix.empty ()) {
new_prefix += "/";
}
new_prefix += tl::to_string (*t);
std::string epath = path + "/" + tl::to_string (*t);
if (SaltGrain::is_grain (epath)) {
try {
SaltGrain g (SaltGrain::from_path (epath));
g.set_name (new_prefix);
grains.add_grain (g);
} catch (...) {
// ignore errors (TODO: what to do here?)
}
} else if (OpenResource (tl::to_qstring (epath)).isDir ()) {
SaltGrains c = SaltGrains::from_path (epath, new_prefix);
c.set_name (new_prefix);
if (! c.is_empty ()) {
grains.add_collection (c);
}
}
}
}
}

View File

@ -23,6 +23,7 @@
#include "laySaltManagerDialog.h"
#include "laySaltGrainPropertiesDialog.h"
#include "laySalt.h"
#include "ui_SaltGrainTemplateSelectionDialog.h"
#include "tlString.h"
#include <QAbstractItemModel>
@ -33,6 +34,7 @@
#include <QDir>
#include <QTextStream>
#include <QBuffer>
#include <QResource>
namespace lay
{
@ -219,6 +221,56 @@ public:
}
};
// --------------------------------------------------------------------------------------
/**
* @brief A tiny dialog to select a template and a name for the grain
*/
class SaltGrainTemplateSelectionDialog
: public QDialog, private Ui::SaltGrainTemplateSelectionDialog
{
public:
SaltGrainTemplateSelectionDialog (QWidget *parent)
: QDialog (parent)
{
Ui::SaltGrainTemplateSelectionDialog::setupUi (this);
m_salt_templates.add_location (":/salt_templates");
salt_view->setModel (new SaltModel (this, &m_salt_templates));
salt_view->setItemDelegate (new SaltItemDelegate (this));
salt_view->setCurrentIndex (salt_view->model ()->index (0, 0, QModelIndex ()));
}
lay::SaltGrain templ () const
{
SaltModel *model = dynamic_cast<SaltModel *> (salt_view->model ());
tl_assert (model != 0);
SaltGrain *g = model->grain_from_index (salt_view->currentIndex ());
tl_assert (g != 0);
g->set_name (tl::to_string (name_edit->text ().simplified ()));
return *g;
}
void accept ()
{
name_alert->clear ();
std::string name = tl::to_string (name_edit->text ().simplified ());
if (name.empty ()) {
name_alert->error () << tr ("Name must not be empty");
} else if (! SaltGrain::valid_name (name)) {
name_alert->error () << tr ("Name is not valid (must be composed of letters, digits or underscores.\nGroups and names need to be separated with slashes.");
} else {
QDialog::accept ();
}
}
private:
lay::Salt m_salt_templates;
};
// --------------------------------------------------------------------------------------
// SaltManager implementation
@ -242,6 +294,9 @@ SaltManagerDialog::SaltManagerDialog (QWidget *parent)
mp_properties_dialog = new lay::SaltGrainPropertiesDialog (this);
connect (edit_button, SIGNAL (clicked ()), this, SLOT (edit_properties ()));
connect (create_button, SIGNAL (clicked ()), this, SLOT (create_grain ()));
connect (delete_button, SIGNAL (clicked ()), this, SLOT (delete_grain ()));
connect (install_button, SIGNAL (clicked ()), this, SLOT (install_grain ()));
// @@@
salt = lay::Salt (); salt_initialized = false;
@ -279,6 +334,58 @@ SaltManagerDialog::edit_properties ()
}
}
// @@@
namespace
{
/**
* @brief A helper class required because directory traversal is not supported by QResource directly
*/
class OpenResource
: public QResource
{
public:
using QResource::isDir;
using QResource::isFile;
using QResource::children;
OpenResource (const QString &path)
: QResource (path)
{
// .. nothing yet ..
}
};
}
// @@@
void
SaltManagerDialog::create_grain ()
{
SaltGrainTemplateSelectionDialog temp_dialog (this);
if (temp_dialog.exec ()) {
// @@@
}
}
void
SaltManagerDialog::delete_grain ()
{
// @@@
}
void
SaltManagerDialog::install_grain ()
{
// @@@
}
void
SaltManagerDialog::salt_changed ()
{

View File

@ -64,6 +64,21 @@ private slots:
*/
void edit_properties ();
/**
* @brief Called when the "edit" button is pressed
*/
void create_grain ();
/**
* @brief Called when the "delete" button is pressed
*/
void delete_grain ();
/**
* @brief Called when the "install" button is pressed
*/
void install_grain ();
private:
lay::Salt *mp_salt;
bool m_current_changed_enabled;

View File

@ -0,0 +1,47 @@
<RCC>
<qresource prefix="/salt_templates">
</qresource>
<!-- font template -->
<qresource prefix="/salt_templates/font">
<file alias="grain.xml">salt_templates/font/grain.xml</file>
</qresource>
<qresource prefix="/salt_templates/font/fonts">
</qresource>
<!-- lib template -->
<qresource prefix="/salt_templates/lib">
<file alias="grain.xml">salt_templates/lib/grain.xml</file>
</qresource>
<qresource prefix="/salt_templates/lib/libraries">
</qresource>
<!-- pcell_lib template -->
<qresource prefix="/salt_templates/pcell_lib">
<file alias="grain.xml">salt_templates/pcell_lib/grain.xml</file>
</qresource>
<qresource prefix="/salt_templates/pcell_lib/macros">
</qresource>
<!-- macro template -->
<qresource prefix="/salt_templates/macro">
<file alias="grain.xml">salt_templates/macro/grain.xml</file>
</qresource>
<qresource prefix="/salt_templates/macro/macros">
</qresource>
<!-- pymacro template -->
<qresource prefix="/salt_templates/pymacro">
<file alias="grain.xml">salt_templates/pymacro/grain.xml</file>
</qresource>
<qresource prefix="/salt_templates/pymacro/pymacros">
</qresource>
<!-- tech template -->
<qresource prefix="/salt_templates/tech">
<file alias="grain.xml">salt_templates/tech/grain.xml</file>
</qresource>
<qresource prefix="/salt_templates/tech/tech">
</qresource>
</RCC>

View File

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<salt-grain>
<name>font</name>
<version>0.0</version>
<title>Font package</title>
<doc>This template provides a font for the Basic.TEXT PCell</doc>
<doc-url/>
<url/>
<license>GPLv3</license>
<author/>
<author-contact/>
<authored-time/>
<installed-time/>
<icon/>
<screenshot/>
</salt-grain>

View File

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<salt-grain>
<name>lib</name>
<version>0.0</version>
<title>Static Library</title>
<doc>This template provides a static library</doc>
<doc-url/>
<url/>
<license>GPLv3</license>
<author/>
<author-contact/>
<authored-time/>
<installed-time/>
<icon/>
<screenshot/>
</salt-grain>

View File

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<salt-grain>
<name>macro</name>
<version>0.0</version>
<title>Ruby Macro</title>
<doc>This template provides a Ruby macro</doc>
<doc-url/>
<url/>
<license>GPLv3</license>
<author/>
<author-contact/>
<authored-time/>
<installed-time/>
<icon/>
<screenshot/>
</salt-grain>

View File

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<salt-grain>
<name>macro</name>
<version>0.0</version>
<title>PCell library</title>
<doc>This template provides a PCell library implemented in Ruby</doc>
<doc-url/>
<url/>
<license>GPLv3</license>
<author/>
<author-contact/>
<authored-time/>
<installed-time/>
<icon/>
<screenshot/>
</salt-grain>

View File

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<salt-grain>
<name>macro</name>
<version>0.0</version>
<title>Python Macro</title>
<doc>This template provides a Python macro</doc>
<doc-url/>
<url/>
<license>GPLv3</license>
<author/>
<author-contact/>
<authored-time/>
<installed-time/>
<icon/>
<screenshot/>
</salt-grain>

View File

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<salt-grain>
<name>macro</name>
<version>0.0</version>
<title>Technology</title>
<doc>This template provides a technology</doc>
<doc-url/>
<url/>
<license>GPLv3</license>
<author/>
<author-contact/>
<authored-time/>
<installed-time/>
<icon/>
<screenshot/>
</salt-grain>