added an MVC interface to the primitives tree

Wed, 14 Mar 2018 12:08:03 +0200

author
Teemu Piippo <teemu@hecknology.net>
date
Wed, 14 Mar 2018 12:08:03 +0200
changeset 1283
3c3a5eb965f7
parent 1282
c6bc95cbf4a3
child 1284
7da74697b7d2

added an MVC interface to the primitives tree

CMakeLists.txt file | annotate | diff | comparison | revisions
data/primitive-categories.cfg file | annotate | diff | comparison | revisions
src/canvas.cpp file | annotate | diff | comparison | revisions
src/mainwindow.cpp file | annotate | diff | comparison | revisions
src/mainwindow.h file | annotate | diff | comparison | revisions
src/mainwindow.ui file | annotate | diff | comparison | revisions
src/primitives.cpp file | annotate | diff | comparison | revisions
src/primitives.h file | annotate | diff | comparison | revisions
--- a/CMakeLists.txt	Sun Mar 11 23:42:03 2018 +0200
+++ b/CMakeLists.txt	Wed Mar 14 12:08:03 2018 +0200
@@ -185,6 +185,7 @@
 
 set (LDFORGE_OTHER_FILES
 	src/configurationoptions.txt
+	data/primitive-categories.cfg
 )
 
 set (LDFORGE_RESOURCES ldforge.qrc)
--- a/data/primitive-categories.cfg	Sun Mar 11 23:42:03 2018 +0200
+++ b/data/primitive-categories.cfg	Wed Mar 14 12:08:03 2018 +0200
@@ -15,6 +15,9 @@
 #
 # All lines starting with # are comments and are ignored.
 
+Moved
+t:~Moved to.*
+
 Rings
 f:[0-9]+\-[0-9]+ring[0-9]\.dat
 f:[0-9]+\-[0-9]+rin[0-9]+\.dat
@@ -100,8 +103,37 @@
 Spheres (48)
 f:48\\[0-9]+\-[0-9]+sphe\.dat
 
-Other (48)
-f:48\\.*\.dat
+Rings (8)
+f:8\\[0-9]+\-[0-9]+ring[0-9]\.dat
+
+Cones (8)
+f:8\\[0-9]+\-[0-9]+cone[0-9]\.dat
+f:8\\[0-9]+\-[0-9]+con[0-9]+\.dat
+
+Circles (8)
+f:8\\[0-9]+\-[0-9]+edge?\.dat
+
+Cylinders (8)
+f:8\\[0-9]+\-[0-9]+cyli[0-9]*\.dat
+f:8\\[0-9]+\-[0-9]+cyl\.dat
+
+Discs (8)
+f:8\\[0-9]+\-[0-9]+disc\.dat
+
+Disc Negatives (8)
+f:8\\[0-9]+\-[0-9]+ndis\.dat
+
+Open/Closed Cylinders (8)
+f:8\\[0-9]+\-[0-9]+cyl(o|c|c2)\.dat
+
+Sloped Cylinders (8)
+f:8\\[0-9]+\-[0-9]+cyl(s|2|se)\.dat
+
+Chords (8)
+f:8\\[0-9]+\-[0-9]+chrd?\.dat
+
+Spheres (8)
+f:8\\[0-9]+\-[0-9]+sphe\.dat
 
 Rectangles
 f:rect.*\.dat
@@ -114,6 +146,7 @@
 
 Studs (Fast-Draw)
 f:stu2.*\.dat
+f:8\\stud.*\.dat
 
 Stud Groups
 f:stug.*\.dat
@@ -138,4 +171,10 @@
 t:Technic .*
 
 Ball Joint-8
-f:joint-8-.*\.dat
\ No newline at end of file
+f:joint8.*\.dat
+
+Other (48)
+f:48\\.*\.dat
+
+Other (8)
+f:8\\.*\.dat
--- a/src/canvas.cpp	Sun Mar 11 23:42:03 2018 +0200
+++ b/src/canvas.cpp	Wed Mar 14 12:08:03 2018 +0200
@@ -242,6 +242,7 @@
 
 void Canvas::dropEvent(QDropEvent* event)
 {
+	/*
 	if (m_window and event->source() == m_window->getPrimitivesTree())
 	{
 		PrimitiveTreeItem* item = static_cast<PrimitiveTreeItem*> (m_window->getPrimitivesTree()->currentItem());
@@ -256,6 +257,7 @@
 		update();
 		event->acceptProposedAction();
 	}
+	*/
 }
 
 void Canvas::keyReleaseEvent(QKeyEvent* event)
@@ -372,6 +374,8 @@
 
 void Canvas::dragEnterEvent(QDragEnterEvent* event)
 {
+	/*
 	if (m_window and event->source() == m_window->getPrimitivesTree() and m_window->getPrimitivesTree()->currentItem())
 		event->acceptProposedAction();
+	*/
 }
--- a/src/mainwindow.cpp	Sun Mar 11 23:42:03 2018 +0200
+++ b/src/mainwindow.cpp	Wed Mar 14 12:08:03 2018 +0200
@@ -69,6 +69,7 @@
 	m_tabs = new QTabBar;
 	m_tabs->setTabsClosable (true);
 	ui.verticalLayout->insertWidget (0, m_tabs);
+	ui.primitives->setModel(m_primitives);
 	createBlankDocument();
 	ui.rendererStack->setCurrentWidget(getRendererForDocument(m_currentDocument));
 
@@ -76,11 +77,6 @@
 	connect (m_tabs, SIGNAL (tabCloseRequested (int)), this, SLOT (closeTab (int)));
 	connect(m_documents, SIGNAL(documentClosed(LDDocument*)), this, SLOT(documentClosed(LDDocument*)));
 
-	if (m_primitives->activeScanner())
-		connect (m_primitives->activeScanner(), SIGNAL (workDone()), this, SLOT (updatePrimitives()));
-	else
-		updatePrimitives();
-
 	m_quickColors = m_guiUtilities->loadQuickColorList();
 	updateActions();
 
@@ -760,13 +756,6 @@
 
 // ---------------------------------------------------------------------------------------------------------------------
 //
-void MainWindow::updatePrimitives()
-{
-	m_primitives->populateTreeWidget(ui.primitives);
-}
-
-// ---------------------------------------------------------------------------------------------------------------------
-//
 void MainWindow::closeTab (int tabindex)
 {
 	LDDocument* doc = m_documents->findDocumentByName (m_tabs->tabData (tabindex).toString());
@@ -822,13 +811,6 @@
 
 // ---------------------------------------------------------------------------------------------------------------------
 //
-QTreeWidget* MainWindow::getPrimitivesTree() const
-{
-	return ui.primitives;
-}
-
-// ---------------------------------------------------------------------------------------------------------------------
-//
 QKeySequence MainWindow::defaultShortcut (QAction* act)
 {
 	return m_defaultShortcuts[act];
--- a/src/mainwindow.h	Sun Mar 11 23:42:03 2018 +0200
+++ b/src/mainwindow.h	Wed Mar 14 12:08:03 2018 +0200
@@ -82,7 +82,6 @@
 	void endAction();
 	class ExtProgramToolset* externalPrograms();
 	QVariant getConfigValue (QString name);
-	QTreeWidget* getPrimitivesTree() const;
 	class QSettings* getSettings() { return m_settings; }
 	LDColor getUniformSelectedColor();
 	Canvas* getRendererForDocument(LDDocument* document);
@@ -137,7 +136,6 @@
 	void historyTraversed();
 	void ringToolHiResClicked (bool clicked);
 	void tabSelected();
-	void updatePrimitives();
 	void documentClosed(LDDocument* document);
 
 protected:
--- a/src/mainwindow.ui	Sun Mar 11 23:42:03 2018 +0200
+++ b/src/mainwindow.ui	Wed Mar 14 12:08:03 2018 +0200
@@ -166,18 +166,16 @@
          </attribute>
          <layout class="QVBoxLayout" name="verticalLayout_3">
           <item>
-           <widget class="QTreeWidget" name="primitives">
+           <widget class="QTreeView" name="primitives">
             <property name="dragDropMode">
              <enum>QAbstractItemView::DragOnly</enum>
             </property>
             <attribute name="headerVisible">
              <bool>false</bool>
             </attribute>
-            <column>
-             <property name="text">
-              <string notr="true">1</string>
-             </property>
-            </column>
+            <attribute name="headerDefaultSectionSize">
+             <number>0</number>
+            </attribute>
            </widget>
           </item>
          </layout>
--- a/src/primitives.cpp	Sun Mar 11 23:42:03 2018 +0200
+++ b/src/primitives.cpp	Wed Mar 14 12:08:03 2018 +0200
@@ -33,10 +33,10 @@
 #include "linetypes/triangle.h"
 
 PrimitiveManager::PrimitiveManager(QObject* parent) :
-	QObject(parent),
-	HierarchyElement(parent),
-	m_activeScanner(nullptr),
-	m_unmatched(nullptr) {}
+	QAbstractItemModel {parent},
+	HierarchyElement {parent},
+	m_activeScanner {nullptr},
+	m_unmatched {nullptr} {}
 
 
 PrimitiveScanner* PrimitiveManager::activeScanner()
@@ -95,10 +95,12 @@
 			if (m_activeScanner)
 			{
 				m_primitives = m_activeScanner->scannedPrimitives();
+				emit layoutAboutToBeChanged();
 				populateCategories();
 				print(tr("%1 primitives scanned"), countof(m_primitives));
 				delete m_activeScanner;
 				m_activeScanner = nullptr;
+				emit layoutChanged();
 			}
 		});
 	}
@@ -514,36 +516,149 @@
 }
 
 /*
- * PrimitiveManager :: populateTreeWidget
- *
- * Fills in a tree widget with all known primitives.
+ * Returns the amount of columns in the primitives tree (1)
  */
-void PrimitiveManager::populateTreeWidget(QTreeWidget* tree, const QString& selectByDefault)
+int	PrimitiveManager::columnCount(const QModelIndex&) const
+{
+	return 1;
+}
+
+/*
+ * For an index that points to a primitive, returns the category that contains it
+ */
+static PrimitiveCategory* categoryForPrimitiveIndex(const QModelIndex& primitiveIndex)
 {
-	tree->clear();
+	return static_cast<PrimitiveCategory*>(primitiveIndex.internalPointer());
+}
 
-	for (PrimitiveCategory* category : m_categories)
+/*
+ * Returns data from the tree model.
+ */
+QVariant PrimitiveManager::data(const QModelIndex& index, int role) const
+{
+	if (index.isValid())
 	{
-		PrimitiveTreeItem* parentItem = new PrimitiveTreeItem {tree, nullptr};
-		parentItem->setText(0, category->name());
-		//QList<QTreeWidgetItem*> subfileItems;
+		if (categoryForPrimitiveIndex(index) != nullptr)
+		{
+			// Index points to a primitive, return primitive information.
+			Primitive& primitive = categoryForPrimitiveIndex(index)->primitives[index.row()];
 
-		for (Primitive& primitive : category->primitives)
+			switch(role)
+			{
+			case Qt::DisplayRole:
+				return format("%1 - %2", primitive.name, primitive.title);
+			case Qt::DecorationRole:
+				return MainWindow::getIcon("subfilereference");
+			default:
+				return {};
+			}
+		}
+		else
 		{
-			PrimitiveTreeItem* item = new PrimitiveTreeItem {parentItem, &primitive};
-			item->setText(0, format("%1 - %2", primitive.name, primitive.title));
-			//subfileItems.append(item);
+			// Index points to a category, return category information.
+			PrimitiveCategory* category = this->m_categories[index.row()];
 
-			// If this primitive is the one the current object points to,
-			// select it by default
-			if (selectByDefault == primitive.name)
-				tree->setCurrentItem(item);
+			switch (role)
+			{
+			case Qt::DisplayRole:
+				return category->name();
+			case Qt::DecorationRole:
+				return MainWindow::getIcon("folder");
+			default:
+				return {};
+			}
 		}
-
-		tree->addTopLevelItem(parentItem);
+	}
+	else
+	{
+		// Index is invalid.
+		return {};
 	}
 }
 
+/*
+ * For a row and parent index, returns a child index.
+ */
+QModelIndex PrimitiveManager::index(int row, int, const QModelIndex& parent) const
+{
+	if (parent.isValid())
+	{
+		if (categoryForPrimitiveIndex(parent))
+		{
+			// Parent is a primitive index. Primitives cannot have children so return an
+			// invalid index.
+			return {};
+		}
+		else
+		{
+			// Parent is a category, return an index to a primitive
+			PrimitiveCategory* category = m_categories[parent.row()];
+
+			// Create an index inside the category
+			if (row >= 0 and row < category->primitives.size())
+				return this->createIndex(row, 0, category);
+			else
+				return {};
+		}
+	}
+	else
+	{
+		// Create a top-level index pointing to a category
+		if (row >= 0 and row < this->m_categories.size())
+			return this->createIndex(row, 0, nullptr);
+		else
+			return {};
+	}
+}
+
+/*
+ * For a primitive index, find the category index that contains it.
+ */
+QModelIndex PrimitiveManager::parent(const QModelIndex &index) const
+{
+	int row = this->m_categories.indexOf(categoryForPrimitiveIndex(index));
+
+	if (row != -1)
+		return this->createIndex(row, 0, nullptr);
+	else
+		return {};
+}
+
+/*
+ * Returns the amount of rows contained inside the given index.
+ */
+int PrimitiveManager::rowCount(const QModelIndex& parent) const
+{
+	if (parent.isValid())
+	{
+		if (categoryForPrimitiveIndex(parent))
+		{
+			// Primitives don't have child nodes, so return 0.
+			return 0;
+		}
+		else
+		{
+			// For categories, return the amount of primitives contained.
+			return this->m_categories[parent.row()]->primitives.size();
+		}
+	}
+	else
+	{
+		// For top-level, return the amount of categories.
+		return this->m_categories.size();
+	}
+}
+
+/*
+ * Returns a static "Primitives" text for the header.
+ */
+QVariant PrimitiveManager::headerData(int section, Qt::Orientation, int role) const
+{
+	if (section == 0 and role == Qt::DisplayRole)
+		return tr("Primitives");
+	else
+		return {};
+}
 
 //
 // ---------------------------------------------------------------------------------------------------------------------
@@ -626,6 +741,14 @@
 	if (not m_iterator.hasNext())
 	{
 		// If there are no more primitives to iterate, we're done. Now save this information into a cache file.
+		std::sort(
+			m_scannedPrimitives.begin(),
+			m_scannedPrimitives.end(),
+			[](const Primitive& one, const Primitive& other) -> bool
+			{
+				return one.title < other.title;
+			}
+		);
 		QString path = m_manager->getPrimitivesCfgPath();
 		QFile configFile = {path};
 
--- a/src/primitives.h	Sun Mar 11 23:42:03 2018 +0200
+++ b/src/primitives.h	Wed Mar 14 12:08:03 2018 +0200
@@ -86,7 +86,7 @@
 	QString m_name;
 };
 
-class PrimitiveManager : public QObject, HierarchyElement
+class PrimitiveManager : public QAbstractItemModel, HierarchyElement
 {
 	Q_OBJECT
 
@@ -98,9 +98,15 @@
 	LDDocument* getPrimitive(const PrimitiveModel &spec);
 	QString getPrimitivesCfgPath() const;
 	void loadPrimitives();
-	void populateTreeWidget(QTreeWidget* tree, const QString& selectByDefault = {});
 	void startScan();
 
+	int	columnCount(const QModelIndex &parent = {}) const override;
+	QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
+	QModelIndex index(int row, int column, const QModelIndex &parent = {}) const override;
+	QModelIndex parent(const QModelIndex &index) const override;
+	int rowCount(const QModelIndex &parent = QModelIndex()) const override;
+	QVariant headerData(int section, Qt::Orientation orientation, int role) const override;
+
 private:
 	QList<PrimitiveCategory*> m_categories;
 	PrimitiveScanner* m_activeScanner;

mercurial