diff --git a/CHANGES b/CHANGES index fef667d..15b697f 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,9 @@ +2002-10-28 #################### PortaBase 1.1 #################### + +2002-10-28 JMB Multiple column sorting + + Added support for sorting on multiple columns. + 2002-10-26 JMB Note column type, minor bugfixes Added support for "Note" columns (a.k.a. multi-line text fields). diff --git a/README b/README index a8584b2..87809f8 100644 --- a/README +++ b/README @@ -1,4 +1,4 @@ -PortaBase 1.0 (October 2002) +PortaBase 1.1 (October 2002) ---------------------------- PortaBase (portable database) is a personal database application written for the Linux-based models of Sharp Zaurus PDA (and should work on any other Linux @@ -6,10 +6,11 @@ PDA using the Qtopia environment.) The main features PortaBase currently has are: - One data table per file -- String, Integer, Decimal, and Boolean column types +- String, Integer, Decimal, Boolean, and Note (multi-line text) column types - Add, edit, and delete rows of data - Custom data views (subsets of the columns in any order) -- Sort the rows by any column in ascending or descending order +- Sort the rows by any combination of columns, each in ascending or descending + order - Page navigation buttons, with a custom number of rows per page - Add, delete, rearrange, and rename columns at any time - Specify default values for columns @@ -17,9 +18,21 @@ The main features PortaBase currently has are: - Import data from CSV files - Export data to CSV files -See the help file (help/portabase.html) for more information on features and -usage. This help file is also the online help for the application, available -by clicking the "?" button at the top right of any screen in PortaBase. +See the help file (help/html/portabase.html) for more information on features +and usage. This help file is also the online help for the application, +available by clicking the "?" button at the top right of any screen in +PortaBase. + +Installation +------------ +Note that there are *two* packages that must be installed in order to run +PortaBase; since many people didn't realize this for version 1.0, they are +now only distributed together in a zip file along with this README file. First +install the libmetakit1 .ipk file onto the Zaurus, then install the +portabase .ipk file. (The MetaKit library is packaged separately because +it is likely to be used by other applications in the near future.) Once +both packages have been installed, PortaBase can be launched from the +Applications tab and the two .ipk files may be safely deleted. Technical Info -------------- diff --git a/TODO b/TODO index b6a63a5..2cd759a 100644 --- a/TODO +++ b/TODO @@ -1,4 +1,3 @@ -Multiple column sorting Filtering/Searching Date column type Date and time column type diff --git a/database.cpp b/database.cpp index acb01c7..a03521f 100644 --- a/database.cpp +++ b/database.cpp @@ -19,27 +19,35 @@ #include "portabase.h" #include "view.h" -Database::Database(QString path, bool *ok) : curView(0), Id("_id"), cIndex("_cindex"), cName("_cname"), cType("_ctype"), cDefault("_cdefault"), vName("_vname"), vRpp("_vrpp"), vcView("_vcview"), vcIndex("_vcindex"), vcName("_vcname"), vcWidth("_vcwidth"), vcSortIndex("_vcsortindex"), vcAscending("_vcascending"), vcFilter("_vcfilter"), gVersion("_gversion"), gView("_gview") +Database::Database(QString path, bool *ok) : curView(0), Id("_id"), cIndex("_cindex"), cName("_cname"), cType("_ctype"), cDefault("_cdefault"), vName("_vname"), vRpp("_vrpp"), vcView("_vcview"), vcIndex("_vcindex"), vcName("_vcname"), vcWidth("_vcwidth"), sName("_sname"), scSort("_scsort"), scIndex("_scindex"), scName("_scname"), scDesc("_scdesc"), gVersion("_gversion"), gView("_gview"), gSort("_gsort") { checkedPixmap = Resource::loadPixmap("portabase/checked"); uncheckedPixmap = Resource::loadPixmap("portabase/unchecked"); file = new c4_Storage(path, TRUE); - global = file->GetAs("_global[_gversion:I,_gview:S]"); + global = file->GetAs("_global[_gversion:I,_gview:S,_gsort:S]"); if (global.GetSize() == 0) { - global.Add(gVersion [FILE_VERSION] + gView ["_all"]); + global.Add(gVersion [FILE_VERSION] + gView ["_all"] + gSort [""]); *ok = TRUE; } else if (gVersion (global[0]) > FILE_VERSION) { *ok = FALSE; } + else if (gVersion (global[0]) == 1) { + // sorting name added in file version 2 + gSort (global[0]) = ""; + gVersion (global[0]) = FILE_VERSION; + *ok = TRUE; + } else { *ok = TRUE; } if (*ok) { columns = file->GetAs("_columns[_cindex:I,_cname:S,_ctype:I,_cdefault:S]"); views = file->GetAs("_views[_vname:S,_vrpp:I]"); - viewColumns = file->GetAs("_viewcolumns[_vcview:S,_vcindex:I,_vcname:S,_vcwidth:I,_vcsortindex:I,_vcascending:I,_vcfilter:S]"); + viewColumns = file->GetAs("_viewcolumns[_vcview:S,_vcindex:I,_vcname:S,_vcwidth:I]"); + sorts = file->GetAs("_sorts[_sname:S]"); + sortColumns = file->GetAs("_sortcolumns[_scsort:S,_scindex:I,_scname:S,_scdesc:I]"); data = file->GetAs(formatString()); maxId = data.GetSize() - 1; *ok = TRUE; @@ -110,9 +118,6 @@ void Database::addView(QString name, QStringList names) vcIndex (colRow) = i; vcName (colRow) = names[i]; vcWidth (colRow) = 60; - vcSortIndex (colRow) = 0; - vcAscending (colRow) = 0; - vcFilter (colRow) = ""; viewColumns.Add(colRow); } } @@ -283,6 +288,12 @@ void Database::deleteColumn(QString name) QString viewName(vName (views[i])); deleteViewColumn(viewName, name); } + // remove the column from any sortings containing it + count = sorts.GetSize(); + for (int i = 0; i < count; i++) { + QString sortName(sName (sorts[i])); + deleteSortingColumn(sortName, name); + } // remove the column from the definition columns.RemoveAt(index); } @@ -295,6 +306,12 @@ void Database::renameColumn(QString oldName, QString newName) vcName (viewColumns[nextIndex]) = newName; nextIndex = viewColumns.Find(vcName [oldName]); } + // rename the column in any sortings containing it + nextIndex = sortColumns.Find(scName [oldName]); + while (nextIndex != -1) { + scName (sortColumns[nextIndex]) = newName; + nextIndex = sortColumns.Find(scName [oldName]); + } // rename the column in the format definition int index = columns.Find(cName [oldName]); cName (columns[index]) = newName; @@ -358,36 +375,152 @@ QStringList Database::getRow(int rowId) return results; } -c4_View Database::sortData(QString column, bool ascending) +QString Database::currentSorting() { - int type = getType(column); - if (type == INTEGER || type == BOOLEAN) { - c4_IntProp prop(column); - if (ascending) { - return data.SortOn(prop); - } - else { - return data.SortOnReverse(prop, prop); + QString sortName(gSort (global[0])); + return sortName; +} + +QStringList Database::listSortings() +{ + c4_View sorted = sorts.SortOn(sName); + int size = sorted.GetSize(); + QStringList list; + for (int i = 0; i < size; i++) { + QString name(sName (sorted[i])); + list.append(name); + } + return list; +} + +bool Database::getSortingInfo(QString sortingName, QStringList *allCols, + QStringList *descCols) +{ + c4_View temp = sortColumns.Select(scSort [sortingName]); + int count = temp.GetSize(); + if (count == 0) { + // non-existent or empty sorting; nothing to do + return FALSE; + } + temp = temp.SortOn(scIndex); + for (int i = 0; i < count; i++) { + QString name(scName (temp[i])); + allCols->append(name); + if (scDesc (temp[i]) == 1) { + descCols->append(name); } } - else if (type == FLOAT) { - c4_FloatProp prop(column); - if (ascending) { - return data.SortOn(prop); + return TRUE; +} + +void Database::addSorting(QString name, QStringList allCols, + QStringList descCols) +{ + sorts.Add(sName [name]); + int count = allCols.count(); + for (int i = 0; i < count; i++) { + c4_Row colRow; + scSort (colRow) = name; + scIndex (colRow) = i; + scName (colRow) = allCols[i]; + if (descCols.findIndex(allCols[i]) == -1) { + scDesc (colRow) = 0; } else { - return data.SortOnReverse(prop, prop); + scDesc (colRow) = 1; } + sortColumns.Add(colRow); + } +} + +void Database::deleteSorting(QString name) +{ + int index = sorts.Find(sName [name]); + if (index == -1) { + return; + } + sorts.RemoveAt(index); + // delete the sorting's columns + int nextIndex = sortColumns.Find(scSort [name]); + while (nextIndex != -1) { + sortColumns.RemoveAt(nextIndex); + nextIndex = sortColumns.Find(scSort [name]); + } +} + +void Database::deleteSortingColumn(QString sortName, QString columnName) +{ + int removeIndex = sortColumns.Find(scSort [sortName] + + scName [columnName]); + if (removeIndex == -1) { + // no such column in this sorting + return; + } + int position = scIndex (sortColumns[removeIndex]); + position++; + int nextIndex = sortColumns.Find(scSort [sortName] + scIndex [position]); + while (nextIndex != -1) { + scIndex (sortColumns[nextIndex]) = position - 1; + position++; + nextIndex = sortColumns.Find(scSort [sortName] + scIndex [position]); + } + sortColumns.RemoveAt(removeIndex); +} + +c4_View Database::sortData(QString column, bool ascending) +{ + QStringList colNames; + colNames.append(column); + QStringList descNames; + if (!ascending) { + descNames.append(column); + } + deleteSorting("_single"); + addSorting("_single", colNames, descNames); + gSort (global[0]) = "_single"; + c4_View sortView = createEmptyView(colNames); + if (ascending) { + return data.SortOn(sortView); } else { - c4_StringProp prop(column); - if (ascending) { - return data.SortOn(prop); + return data.SortOnReverse(sortView, sortView); + } +} + +c4_View Database::sortData(QString sortingName) +{ + gSort (global[0]) = sortingName; + QStringList allCols; + QStringList descCols; + if (!getSortingInfo(sortingName, &allCols, &descCols)) { + return data; + } + c4_View allView = createEmptyView(allCols); + c4_View descView = createEmptyView(descCols); + return data.SortOnReverse(allView, descView); +} + +c4_View Database::createEmptyView(QStringList colNames) +{ + int count = colNames.count(); + c4_View result; + for (int i = 0; i < count; i++) { + QString name = colNames[i]; + int type = getType(name); + if (type == INTEGER || type == BOOLEAN) { + c4_IntProp prop(name); + result.AddProperty(prop); + } + else if (type == FLOAT) { + c4_FloatProp prop(name); + result.AddProperty(prop); } else { - return data.SortOnReverse(prop, prop); + c4_StringProp prop(name); + result.AddProperty(prop); } } + return result; } QString Database::addRow(QStringList values) @@ -487,9 +620,6 @@ void Database::addViewColumn(QString viewName, QString columnName) vcIndex (colRow) = cols.GetSize(); vcName (colRow) = columnName; vcWidth (colRow) = 60; - vcSortIndex (colRow) = 0; - vcAscending (colRow) = 0; - vcFilter (colRow) = ""; viewColumns.Add(colRow); } diff --git a/database.h b/database.h index bddc4ae..4586acf 100644 --- a/database.h +++ b/database.h @@ -27,6 +27,7 @@ class Database public: Database(QString path, bool *ok); ~Database(); + QString currentView(); View *getView(QString name); QStringList listViews(); @@ -34,6 +35,7 @@ class Database void deleteView(QString name); void setViewColWidths(int *widths); void setViewRowsPerPage(int rpp); + QStringList listColumns(); int getIndex(QString column); void setIndex(QString column, int index); @@ -51,7 +53,17 @@ class Database void setViewColumnSequence(QString viewName, QStringList colNames); void updateDataFormat(); QStringList getRow(int rowId); + + QString currentSorting(); + QStringList listSortings(); + bool getSortingInfo(QString sortingName, QStringList *allCols, + QStringList *descCols); + void addSorting(QString name, QStringList allCols, QStringList descCols); + void deleteSorting(QString name); + void deleteSortingColumn(QString sortName, QString columnName); c4_View sortData(QString column, bool ascending); + c4_View sortData(QString sortingName); + QString addRow(QStringList values); void updateRow(int rowId, QStringList values); void deleteRow(int id); @@ -62,6 +74,7 @@ class Database private: int *listTypes(); + c4_View createEmptyView(QStringList colNames); QString formatString(); private: @@ -71,6 +84,8 @@ class Database c4_View columns; c4_View views; c4_View viewColumns; + c4_View sorts; + c4_View sortColumns; c4_View global; c4_View data; View *curView; @@ -89,12 +104,17 @@ class Database c4_IntProp vcIndex; c4_StringProp vcName; c4_IntProp vcWidth; - c4_IntProp vcSortIndex; - c4_IntProp vcAscending; - c4_StringProp vcFilter; + // "_sorts" view + c4_StringProp sName; + // "_sortcolumns" view + c4_StringProp scSort; + c4_IntProp scIndex; + c4_StringProp scName; + c4_IntProp scDesc; // "_global" view c4_IntProp gVersion; c4_StringProp gView; + c4_StringProp gSort; }; #endif diff --git a/help/html/portabase.html b/help/html/portabase.html index de5539c..b4c99e9 100644 --- a/help/html/portabase.html +++ b/help/html/portabase.html @@ -1,11 +1,11 @@ - PortaBase 1.0 + PortaBase 1.1 -

PortaBase 1.0

- A portable database -
+

PortaBase 1.1

- A portable database -

1)Introduction
2)File selector
@@ -14,8 +14,9 @@ 5)Data viewer
6)Row editor
7)Note editor/viewer
-8)Data import
-9)Data export
+8)Sorting editor
+9)Data import
+10)Data export


1)Introduction
@@ -23,9 +24,11 @@ custom tables of data. Typical uses are media inventories, reference charts, etc. Notable features include:
Navigation
@@ -175,6 +179,27 @@ switch to a different view, simply select the one you want to see from the menu.

+Sort menu
+The "Sort" menu allows you to select and manage sorting configurations. +The top section of this menu has three options:
+ +Below these items in the menu is a list of all the sortings defined for +the current database, with a check next to the one currently in use +(if any). To change the way the rows are sorted, simply select the +sorting configuration you want to use from the menu. If you just want +to sort by a single column that is displayed in the current view, it is +probably faster to use the "click on a column label to sort" feature +instead.
+
Toolbar buttons
There is a toolbar of four buttons that provide quick access to commonly used operations. These are:
@@ -218,7 +243,29 @@ of the Note editor is shown. Click either "OK" or "X" to dismiss it and return to the data viewer.

-8)Data import
+8)Sorting editor
+Clicking on a column label in the data viewer is a convenient way to +sort the database contents by a single column. But sometimes you may want +to sort by a combination of columns; sort by the content of column A, within +groups of the same value of A sort by the content of column B, etc. To do +this or to sort by a column that isn't shown in the current view, you need +to define a named sorting.
+
+Sortings are defined using the sorting editor dialog, which is very +similar to the view editor dialog. At the top of +the dialog is a text box containing the name of the sorting; changing this +renames the sorting. Below that is a table showing the names of all the +columns in the database, with a checkbox next to each indicating whether +or not it is to be sorted. Click this checkbox to add or remove the column +from the set of ones to be sorted. The third column in the table shows either +"Ascending" or "Descending" for checked rows, indicating which direction to +sort in; click this indicator to change it to the opposite value. At the +bottom of the dialog are "Up" and "Down" buttons for moving the selected row +up or down in the table, changing the sequence in which the columns are +sorted. Click "OK" to accept the currently shown settings or "X" to revert +to the previous values (or to cancel adding a new sorting).
+
+9)Data import
PortaBase can import rows of data from CSV (Comma-Separated Value) files. This allows you to import data exported from a spreadsheet or another database program. To do this:
@@ -235,7 +282,7 @@ other files can be added by repeating this process, or another copy of the same rows can be added by importing the same file again. -9)Data export
+10)Data export
PortaBase can also export database rows to CSV files. The inverse of data import, this allows you to move database content into a spreadsheet or other database program for further manipulation (among other uses). To diff --git a/package/control b/package/control index ef237b1..8dbbb06 100644 --- a/package/control +++ b/package/control @@ -1,7 +1,7 @@ Package: portabase Priority: optional Section: Applications -Version: 1.0 +Version: 1.1 Architecture: arm Maintainer: Jeremy Bowman Depends: qpe-base, libmetakit1 diff --git a/portabase.cpp b/portabase.cpp index 314d8c9..8c97ad4 100644 --- a/portabase.cpp +++ b/portabase.cpp @@ -26,6 +26,7 @@ #include "importdialog.h" #include "inputdialog.h" #include "portabase.h" +#include "sorteditor.h" #include "viewdisplay.h" #include "vieweditor.h" @@ -44,11 +45,15 @@ PortaBase::PortaBase(QWidget *parent, const char *name, WFlags f) QPopupMenu *row = new QPopupMenu(this); view = new QPopupMenu(this); view->setCheckable(TRUE); + sort = new QPopupMenu(this); + sort->setCheckable(TRUE); toolbar = new QPEToolBar(this); - fileSaveAction = new QAction(tr("Save"), - Resource::loadPixmap("portabase/save"), + QIconSet saveIcons = Resource::loadIconSet("portabase/save"); + //QPixmap disabledSave = Resource::loadPixmap("portabase/save_disabled"); + //saveIcons.setPixmap(disabledSave, QIconSet::Small, QIconSet::Disabled); + fileSaveAction = new QAction(tr("Save"), saveIcons, QString::null, 0, this, 0); connect(fileSaveAction, SIGNAL(activated()), this, SLOT(save())); fileSaveAction->addTo(toolbar); @@ -96,9 +101,18 @@ PortaBase::PortaBase(QWidget *parent, const char *name, WFlags f) SLOT(viewAllColumns())); connect(view, SIGNAL(activated(int)), this, SLOT(changeView(int))); + sort->insertItem(addIcons, tr("Add"), this, SLOT(addSorting())); + editSortId = sort->insertItem(editIcons, tr("Edit"), + this, SLOT(editSorting())); + deleteSortId = sort->insertItem(deleteIcons, tr("Delete"), + this, SLOT(deleteSorting())); + sort->insertSeparator(); + connect(sort, SIGNAL(activated(int)), this, SLOT(changeSorting(int))); + mb->insertItem(tr("File"), file); mb->insertItem(tr("Row"), row); mb->insertItem(tr("View"), view); + mb->insertItem(tr("Sort"), sort); mainStack = new QWidgetStack(this); setCentralWidget(mainStack); @@ -133,6 +147,7 @@ bool PortaBase::editColumns() db->addView("_all", db->listColumns()); viewer->setDatabase(db); rebuildViewMenu(); + rebuildSortMenu(); } else { viewAllColumns(); @@ -213,6 +228,7 @@ void PortaBase::openFile(const DocLnk &f) toolbar->show(); updateCaption(); rebuildViewMenu(); + rebuildSortMenu(); } void PortaBase::fileOpen() @@ -344,6 +360,16 @@ void PortaBase::changeView(int id) } } +void PortaBase::changeSorting(int id) +{ + int index = sortIds.findIndex(id); + if (index != -1) { + viewer->setSorting(sortNames[index]); + updateSortMenu(); + setEdited(TRUE); + } +} + void PortaBase::rebuildViewMenu() { // remove old view names @@ -363,6 +389,25 @@ void PortaBase::rebuildViewMenu() updateViewMenu(); } +void PortaBase::rebuildSortMenu() +{ + // remove old sorting names + int count = sortNames.count(); + for (int i = 0; i < count; i++) { + sort->removeItem(sortIds[i]); + } + sortIds.clear(); + // add new sorting names + sortNames = db->listSortings(); + sortNames.remove("_single"); + count = sortNames.count(); + for (int i = 0; i < count; i++) { + int id = sort->insertItem(sortNames[i]); + sortIds.append(id); + } + updateSortMenu(); +} + void PortaBase::updateViewMenu() { QString viewName = db->currentView(); @@ -387,6 +432,28 @@ void PortaBase::updateViewMenu() } } +void PortaBase::updateSortMenu() +{ + QString sortName = db->currentSorting(); + if (sortName == "" || sortName == "_single") { + sort->setItemEnabled(editSortId, FALSE); + sort->setItemEnabled(deleteSortId, FALSE); + } + else { + sort->setItemEnabled(editSortId, TRUE); + sort->setItemEnabled(deleteSortId, TRUE); + } + int count = sortNames.count(); + for (int i = 0; i < count; i++) { + if (sortName == sortNames[i]) { + sort->setItemChecked(sortIds[i], TRUE); + } + else { + sort->setItemChecked(sortIds[i], FALSE); + } + } +} + void PortaBase::editView() { ViewEditor editor; @@ -404,6 +471,22 @@ void PortaBase::editView() } } +void PortaBase::editSorting() +{ + SortEditor editor; + QString sortingName = db->currentSorting(); + if (editor.edit(db, sortingName)) { + editor.applyChanges(); + QString newName = editor.getName(); + viewer->setSorting(newName); + // sort menu is unchanged unless the sorting's name changed + if (sortingName != newName) { + rebuildSortMenu(); + } + setEdited(TRUE); + } +} + void PortaBase::addView() { ViewEditor editor; @@ -416,13 +499,31 @@ void PortaBase::addView() } } +void PortaBase::addSorting() +{ + SortEditor editor; + if (editor.edit(db, "")) { + editor.applyChanges(); + viewer->setSorting(editor.getName()); + rebuildSortMenu(); + setEdited(TRUE); + } +} + void PortaBase::deleteView() { viewer->closeView(); db->deleteView(db->currentView()); viewer->setView("_all"); rebuildViewMenu(); - updateViewMenu(); + setEdited(TRUE); +} + +void PortaBase::deleteSorting() +{ + db->deleteSorting(db->currentSorting()); + viewer->setSorting(""); + rebuildSortMenu(); setEdited(TRUE); } diff --git a/portabase.h b/portabase.h index d6bd23f..cfbe8ee 100644 --- a/portabase.h +++ b/portabase.h @@ -37,6 +37,7 @@ class PortaBase: public QMainWindow void setEdited(bool y); void setRowSelected(bool y); static QPixmap getNotePixmap(); + void updateSortMenu(); public slots: void setDocument(const QString&); @@ -56,6 +57,10 @@ private slots: void addView(); void editView(); void deleteView(); + void changeSorting(int index); + void addSorting(); + void editSorting(); + void deleteSorting(); protected: void closeEvent(QCloseEvent *e); @@ -65,6 +70,7 @@ private slots: void updateCaption(const QString &name=QString::null); void rebuildViewMenu(); void updateViewMenu(); + void rebuildSortMenu(); void closeViewer(); private: @@ -77,6 +83,7 @@ private slots: QAction *rowEditAction; QAction *rowDeleteAction; QPopupMenu *view; + QPopupMenu *sort; DocLnk *doc; ViewDisplay *viewer; bool newdb; @@ -85,6 +92,10 @@ private slots: int deleteViewId; QStringList viewNames; IntList viewIds; + int editSortId; + int deleteSortId; + QStringList sortNames; + IntList sortIds; bool isEdited; }; diff --git a/portabase.pro b/portabase.pro index b41ba62..b441653 100644 --- a/portabase.pro +++ b/portabase.pro @@ -1,8 +1,8 @@ TEMPLATE = app #CONFIG = qt warn_on debug CONFIG = qt warn_on release -HEADERS = portabase.h inputdialog.h view.h viewdisplay.h database.h datatypes.h dbeditor.h columneditor.h roweditor.h csvutils.h importdialog.h vieweditor.h noteeditor.h notebutton.h -SOURCES = main.cpp portabase.cpp inputdialog.cpp view.cpp viewdisplay.cpp database.cpp dbeditor.cpp columneditor.cpp roweditor.cpp csvutils.cpp importdialog.cpp vieweditor.cpp noteeditor.cpp notebutton.cpp +HEADERS = portabase.h inputdialog.h view.h viewdisplay.h database.h datatypes.h dbeditor.h columneditor.h roweditor.h csvutils.h importdialog.h vieweditor.h noteeditor.h notebutton.h sorteditor.h +SOURCES = main.cpp portabase.cpp inputdialog.cpp view.cpp viewdisplay.cpp database.cpp dbeditor.cpp columneditor.cpp roweditor.cpp csvutils.cpp importdialog.cpp vieweditor.cpp noteeditor.cpp notebutton.cpp sorteditor.cpp INCLUDEPATH += $(QPEDIR)/include DEPENDPATH += $(QPEDIR)/include LIBS += -lqpe -lm -lmk4 diff --git a/sorteditor.cpp b/sorteditor.cpp new file mode 100644 index 0000000..08d9fc3 --- /dev/null +++ b/sorteditor.cpp @@ -0,0 +1,273 @@ +/* + * sorteditor.cpp + * + * (c) 2002 by Jeremy Bowman + * + * This program 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 2 of the License, or + * (at your option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "database.h" +#include "sorteditor.h" + +SortEditor::SortEditor(QWidget *parent, const char *name, WFlags f) + : QDialog(parent, name, TRUE, f), db(0) +{ + setCaption(tr("Sorting Editor") + " - " + tr("PortaBase")); + showMaximized(); + hide(); + QVBox *vbox = new QVBox(this); + vbox->resize(size()); + + QHBox *hbox = new QHBox(vbox); + new QLabel(tr("Sorting Name"), hbox); + nameBox = new QLineEdit(hbox); + + table = new QListView(vbox); + table->setAllColumnsShowFocus(TRUE); + table->setSorting(-1); + table->header()->setMovingEnabled(FALSE); + table->addColumn(tr("Sort")); + table->setColumnWidthMode(0, QListView::Manual); + table->setColumnAlignment(0, Qt::AlignHCenter); + int colWidth = (vbox->width() - table->columnWidth(0) - 5) / 2; + table->addColumn(tr("Column Name"), colWidth); + table->addColumn(tr("Direction"), colWidth); + connect(table, SIGNAL(clicked(QListViewItem*, const QPoint&, int)), + this, SLOT(tableClicked(QListViewItem*, const QPoint&, int))); + + hbox = new QHBox(vbox); + QPushButton *upButton = new QPushButton(tr("Up"), hbox); + connect(upButton, SIGNAL(clicked()), this, SLOT(moveUp())); + QPushButton *downButton = new QPushButton(tr("Down"), hbox); + connect(downButton, SIGNAL(clicked()), this, SLOT(moveDown())); +} + +SortEditor::~SortEditor() +{ + +} + +int SortEditor::edit(Database *subject, QString sortingName) +{ + db = subject; + originalName = sortingName; + nameBox->setText(sortingName); + colNames = db->listColumns(); + db->getSortingInfo(sortingName, &sortCols, &descCols); + // move currently sorted columns to the top of the list, in correct order + int count = sortCols.count(); + for (int i = count - 1; i > -1; i--) { + QString name = sortCols[i]; + colNames.remove(name); + colNames.prepend(name); + } + updateTable(); + int result = exec(); + while (result) { + if (hasValidName()) { + break; + } + else { + result = exec(); + } + } + return result; +} + +QString SortEditor::getName() +{ + return nameBox->text(); +} + +void SortEditor::moveUp() +{ + QListViewItem *item = table->selectedItem(); + if (item == 0) { + return; + } + QListViewItem *above = item->itemAbove(); + if (above) { + QString name = item->text(1); + QString aboveName = above->text(1); + colNames.remove(name); + colNames.insert(colNames.find(aboveName), name); + updateTable(); + selectRow(name); + } +} + +void SortEditor::moveDown() +{ + QListViewItem *item = table->selectedItem(); + if (item == 0) { + return; + } + QListViewItem *below = item->itemBelow(); + if (below) { + QString name = item->text(1); + colNames.remove(name); + below = below->itemBelow(); + if (below) { + QString belowName = below->text(1); + colNames.insert(colNames.find(belowName), name); + } + else { + colNames.append(name); + } + updateTable(); + selectRow(name); + } +} + +void SortEditor::selectRow(QString name) +{ + QListViewItem *item = table->firstChild(); + if (item) { + if (item->text(1) == name) { + table->setSelected(item, TRUE); + } + else { + QListViewItem *next = item->nextSibling(); + while (next) { + if (next->text(1) == name) { + table->setSelected(next, TRUE); + break; + } + next = next->nextSibling(); + } + } + } +} + +void SortEditor::updateTable() +{ + table->clear(); + int count = colNames.count(); + QListViewItem *item = 0; + for (int i = 0; i < count; i++) { + QString name = colNames[i]; + bool sorted = isSorted(name); + QString direction = ""; + if (sorted) { + if (descCols.findIndex(name) == -1) { + direction = tr("Ascending"); + } + else { + direction = tr("Descending"); + } + } + if (i == 0) { + item = new QListViewItem(table, "", name, direction); + } + else { + item = new QListViewItem(table, item, "", name, direction); + } + item->setPixmap(0, db->getCheckBoxPixmap(sorted)); + } +} + +void SortEditor::tableClicked(QListViewItem *item, const QPoint &point, + int column) +{ + if (column == 0) { + QString name = item->text(1); + int sorted = isSorted(name); + if (sorted) { + sortCols.remove(name); + descCols.remove(name); + item->setText(2, ""); + } + else { + sortCols.append(name); + item->setText(2, tr("Ascending")); + } + item->setPixmap(0, db->getCheckBoxPixmap(!sorted)); + } + else if (column == 2) { + QString name = item->text(1); + int sorted = isSorted(name); + if (sorted) { + if (descCols.findIndex(name) == -1) { + descCols.append(name); + item->setText(2, tr("Descending")); + } + else { + descCols.remove(name); + item->setText(2, tr("Ascending")); + } + } + } +} + +bool SortEditor::hasValidName() +{ + QString name = nameBox->text(); + if (name.isEmpty()) { + QMessageBox::warning(this, tr("PortaBase"), + tr("No name entered")); + return FALSE; + } + if (name == originalName) { + // hasn't changed and isn't empty, must be valid + return TRUE; + } + if (name[0] == '_') { + QMessageBox::warning(this, tr("PortaBase"), + tr("Name must not start with '_'")); + return FALSE; + } + if (name.find(':') != -1) { + QMessageBox::warning(this, tr("PortaBase"), + tr("Name must not contain ':'")); + return FALSE; + } + // check for other views with same name + bool result = TRUE; + QStringList sortingNames = db->listSortings(); + int count = sortingNames.count(); + for (int i = 0; i < count; i++) { + if (name == sortingNames[i]) { + result = FALSE; + break; + } + } + if (!result) { + QMessageBox::warning(this, tr("PortaBase"), tr("Duplicate name")); + } + return result; +} + +int SortEditor::isSorted(QString name) +{ + return (sortCols.findIndex(name) != -1); +} + +void SortEditor::applyChanges() +{ + QString sortingName = nameBox->text(); + QStringList orderedSort; + QStringList orderedDesc; + int count = colNames.count(); + for (int i = 0; i < count; i++) { + QString name = colNames[i]; + if (isSorted(name)) { + orderedSort.append(name); + if (descCols.findIndex(name) != -1) { + orderedDesc.append(name); + } + } + } + db->deleteSorting(originalName); + db->addSorting(sortingName, orderedSort, orderedDesc); +} diff --git a/sorteditor.h b/sorteditor.h new file mode 100644 index 0000000..9b53832 --- /dev/null +++ b/sorteditor.h @@ -0,0 +1,55 @@ +/* + * sorteditor.h + * + * (c) 2002 by Jeremy Bowman + * + * This program 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 2 of the License, or + * (at your option) any later version. + */ + +#ifndef SORTEDITOR_H +#define SORTEDITOR_H + +#include + +class Database; +class QLineEdit; +class QListView; +class QListViewItem; +class QPoint; + +class SortEditor: public QDialog +{ + Q_OBJECT +public: + SortEditor(QWidget *parent = 0, const char *name = 0, WFlags f = 0); + ~SortEditor(); + + int edit(Database *subject, QString sortingName); + void applyChanges(); + QString getName(); + +private: + void updateTable(); + void selectRow(QString name); + int isSorted(QString name); + bool hasValidName(); + +private slots: + void tableClicked(QListViewItem *item, const QPoint &point, int column); + void moveUp(); + void moveDown(); + +private: + QLineEdit *nameBox; + QListView *table; + Database *db; + QString originalName; + QStringList colNames; + QStringList sortCols; + QStringList descCols; +}; + +#endif diff --git a/view.cpp b/view.cpp index 6a21750..ad3c8fa 100644 --- a/view.cpp +++ b/view.cpp @@ -19,7 +19,7 @@ View::View(Database *parent, c4_View baseview, QStringList colNames, int *types, int *widths, int rpp) : Id("_id"), sortColumn(-1), - ascending(TRUE) + ascending(TRUE), sortName("") { db = parent; dbview = baseview; @@ -28,6 +28,7 @@ View::View(Database *parent, c4_View baseview, QStringList colNames, colWidths = widths; numCols = columns.count(); rowsPerPage = rpp; + sort(db->currentSorting()); } View::~View() @@ -112,11 +113,20 @@ void View::sort(int colIndex) } } +void View::sort(QString sortingName) +{ + sortColumn = -1; + sortName = sortingName; +} + void View::prepareData() { if (sortColumn != -1) { dbview = db->sortData(columns[sortColumn], ascending); } + else if (sortName != "") { + dbview = db->sortData(sortName); + } } int View::getId(int index) diff --git a/view.h b/view.h index 4bec566..b388969 100644 --- a/view.h +++ b/view.h @@ -37,6 +37,7 @@ class View QStringList getRow(int index); int getId(int index); void sort(int colIndex); + void sort(QString sortingName); void prepareData(); QStringList getStatistics(int colIndex); @@ -51,6 +52,7 @@ class View int rowsPerPage; int sortColumn; bool ascending; + QString sortName; }; #endif diff --git a/viewdisplay.cpp b/viewdisplay.cpp index cef4c27..bfcffcb 100644 --- a/viewdisplay.cpp +++ b/viewdisplay.cpp @@ -237,6 +237,12 @@ void ViewDisplay::setView(QString name) updateButtons(); } +void ViewDisplay::setSorting(QString name) +{ + view->sort(name); + updateTable(); +} + void ViewDisplay::closeView() { if (view) { @@ -367,6 +373,7 @@ void ViewDisplay::sort(int column) { view->sort(column); updateTable(); + portabase->updateSortMenu(); } void ViewDisplay::showStatistics(int column) diff --git a/viewdisplay.h b/viewdisplay.h index 9b7c956..fd6e5ea 100644 --- a/viewdisplay.h +++ b/viewdisplay.h @@ -43,6 +43,7 @@ class ViewDisplay: public QVBox void updateButtons(); void saveViewSettings(); void setView(QString name); + void setSorting(QString name); void closeView(); public slots: