refs #368, filter for views

This commit is contained in:
Klaus Basan
2015-01-18 23:00:01 +01:00
parent f8464a6b03
commit 23d3ea3ec5
19 changed files with 974 additions and 120 deletions

View File

@@ -0,0 +1,39 @@
/* Copyright (C) 2013
* swift project Community / Contributors
*
* This file is part of swift project. It is subject to the license terms in the LICENSE file found in the top-level
* directory of this distribution and at http://www.swift-project.org/license.html. No part of swift project,
* including this file, may be copied, modified, propagated, or distributed except according to the terms
* contained in the LICENSE file.
*/
#include "aircraftmodelfilterform.h"
#include "ui_aircraftmodelfilterform.h"
using namespace BlackGui::Models;
namespace BlackGui
{
namespace Views
{
CAircraftModelFilterForm::CAircraftModelFilterForm(QWidget *parent) :
CFilterDialog(parent),
ui(new Ui::CAircraftModelFilterForm)
{
ui->setupUi(this);
this->setWindowTitle("Filter models");
}
CAircraftModelFilterForm::~CAircraftModelFilterForm()
{ }
std::unique_ptr<CAircraftModelFilter> CAircraftModelFilterForm::getFilter() const
{
QString model(this->ui->le_ModelString->text());
QString desc(this->ui->le_ModelDescription->text());
return std::unique_ptr<CAircraftModelFilter>(new CAircraftModelFilter(model, desc));
}
} // namespace
} // namespace

View File

@@ -0,0 +1,50 @@
/* Copyright (C) 2013
* swift project Community / Contributors
*
* This file is part of swift project. It is subject to the license terms in the LICENSE file found in the top-level
* directory of this distribution and at http://www.swift-project.org/license.html. No part of swift project,
* including this file, may be copied, modified, propagated, or distributed except according to the terms
* contained in the LICENSE file.
*/
//! \file
#ifndef BLACKGUI_AIRCRAFTMODELFILTERFORM_H
#define BLACKGUI_AIRCRAFTMODELFILTERFORM_H
#include "filterdialog.h"
#include "blackgui/models/aircraftmodelfilter.h"
#include <QDialog>
#include <QScopedPointer>
#include <iostream>
#include <memory>
namespace Ui { class CAircraftModelFilterForm; }
namespace BlackGui
{
namespace Views
{
//! Form for a aircraft model filter
class CAircraftModelFilterForm : public CFilterDialog
{
Q_OBJECT
public:
//! Constructor
explicit CAircraftModelFilterForm(QWidget *parent = nullptr);
//! Destructor
~CAircraftModelFilterForm();
//! Get created filter
std::unique_ptr<BlackGui::Models::CAircraftModelFilter> getFilter() const;
private:
QScopedPointer<Ui::CAircraftModelFilterForm> ui;
};
} // namespace
} // namespace
#endif // guard

View File

@@ -0,0 +1,91 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>CAircraftModelFilterForm</class>
<widget class="QDialog" name="CAircraftModelFilterForm">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>336</width>
<height>95</height>
</rect>
</property>
<property name="windowTitle">
<string>Dialog</string>
</property>
<layout class="QVBoxLayout" name="vl_AircraftModelFilterForm">
<item>
<layout class="QFormLayout" name="fl_FilterLayout">
<property name="fieldGrowthPolicy">
<enum>QFormLayout::AllNonFixedFieldsGrow</enum>
</property>
<item row="0" column="0">
<widget class="QLabel" name="lbl_ModelString">
<property name="text">
<string>Model</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLineEdit" name="le_ModelString"/>
</item>
<item row="1" column="0">
<widget class="QLabel" name="lbl_ModelDescription">
<property name="text">
<string>Description</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLineEdit" name="le_ModelDescription"/>
</item>
</layout>
</item>
<item>
<widget class="QDialogButtonBox" name="bb_ButtonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections>
<connection>
<sender>bb_ButtonBox</sender>
<signal>accepted()</signal>
<receiver>CAircraftModelFilterForm</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>bb_ButtonBox</sender>
<signal>rejected()</signal>
<receiver>CAircraftModelFilterForm</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>

View File

@@ -8,9 +8,13 @@
*/
#include "aircraftmodelview.h"
#include "aircraftmodelfilterform.h"
#include <QHeaderView>
#include <iostream>
#include <memory>
using namespace BlackMisc;
using namespace BlackMisc::Simulation;
using namespace BlackGui::Models;
namespace BlackGui
@@ -22,11 +26,31 @@ namespace BlackGui
this->m_withMenuItemClear = true;
this->m_withMenuItemRefresh = true;
this->standardInit(new CAircraftModelListModel(CAircraftModelListModel::ModelOnly, this));
// filter
QWidget *mainWindow = this->mainApplicationWindowWidget();
Q_ASSERT(mainWindow);
this->setFilterDialog(new CAircraftModelFilterForm(mainWindow));
}
void CAircraftModelView::setAircraftModelMode(CAircraftModelListModel::AircraftModelMode mode)
{
this->m_model->setAircraftModelMode(mode);
}
}
}
bool CAircraftModelView::ps_filterDialogFinished(int status)
{
if (CViewBase::ps_filterDialogFinished(status)) { return true; }
if (!this->m_filterDialog) { this->derivedModel()->removeFilter(); return true; }
std::unique_ptr<IModelFilter<CAircraftModelList>> filter(this->getFilterForm()->getFilter());
this->derivedModel()->setFilter(filter);
return true;
}
CAircraftModelFilterForm *CAircraftModelView::getFilterForm() const
{
return static_cast<CAircraftModelFilterForm *>(this->m_filterDialog.data());
}
} // namespace
} // namespace

View File

@@ -12,6 +12,7 @@
#ifndef BLACKGUI_AIRCRAFTMODELVIEW_H
#define BLACKGUI_AIRCRAFTMODELVIEW_H
#include "aircraftmodelfilterform.h"
#include "viewbase.h"
#include "../models/aircraftmodellistmodel.h"
@@ -20,7 +21,7 @@ namespace BlackGui
namespace Views
{
//! Aircrafts view
class CAircraftModelView : public CViewBase<Models::CAircraftModelListModel, BlackMisc::Network::CAircraftModelList, BlackMisc::Network::CAircraftModel>
class CAircraftModelView : public CViewBase<Models::CAircraftModelListModel, BlackMisc::Simulation::CAircraftModelList, BlackMisc::Simulation::CAircraftModel>
{
public:
@@ -31,6 +32,13 @@ namespace BlackGui
//! Set display mode
void setAircraftModelMode(Models::CAircraftModelListModel::AircraftModelMode mode);
protected slots:
//! \copydoc CViewBaseNonTemplate::ps_filterDialogFinished
virtual bool ps_filterDialogFinished(int status) override;
private:
//! Filter form
CAircraftModelFilterForm *getFilterForm() const;
};
}
}

View File

@@ -0,0 +1,37 @@
/* Copyright (C) 2013
* swift project Community / Contributors
*
* This file is part of swift project. It is subject to the license terms in the LICENSE file found in the top-level
* directory of this distribution and at http://www.swift-project.org/license.html. No part of swift project,
* including this file, may be copied, modified, propagated, or distributed except according to the terms
* contained in the LICENSE file.
*/
#include "filterdialog.h"
#include "blackgui/stylesheetutility.h"
namespace BlackGui
{
namespace Views
{
CFilterDialog::CFilterDialog(QWidget *parent) : QDialog(parent, Qt::Tool)
{
this->setWindowTitle("Filter dialog");
ps_onStyleSheetChanged();
connect(&CStyleSheetUtility::instance(), &CStyleSheetUtility::styleSheetsChanged, this, &CFilterDialog::ps_onStyleSheetChanged);
}
CFilterDialog::~CFilterDialog()
{ }
void CFilterDialog::ps_onStyleSheetChanged()
{
const QString qss = CStyleSheetUtility::instance().style(CStyleSheetUtility::fileNameFilterDialog());
this->setStyleSheet(qss);
}
} // namespace
} // namespace

View File

@@ -0,0 +1,39 @@
/* Copyright (C) 2013
* swift project Community / Contributors
*
* This file is part of swift project. It is subject to the license terms in the LICENSE file found in the top-level
* directory of this distribution and at http://www.swift-project.org/license.html. No part of swift project,
* including this file, may be copied, modified, propagated, or distributed except according to the terms
* contained in the LICENSE file.
*/
//! \file
#ifndef BLACKGUI_FILTERDIALOG_H
#define BLACKGUI_FILTERDIALOG_H
#include <QDialog>
namespace BlackGui
{
namespace Views
{
//! Base for filter dialog
class CFilterDialog : public QDialog
{
public:
//! Constructor
CFilterDialog(QWidget *parent = nullptr);
//! Destructor
virtual ~CFilterDialog();
private slots:
//! Stylesheet changed
void ps_onStyleSheetChanged();
};
} // namespace
} // namespace
#endif // guard

View File

@@ -18,14 +18,19 @@
#include "../models/serverlistmodel.h"
#include "../models/userlistmodel.h"
#include "../models/clientlistmodel.h"
#include "../models/simulatedaircraftlistmodel.h"
#include "../models/keyboardkeylistmodel.h"
#include "../guiutility.h"
#include <QHeaderView>
#include <QModelIndex>
#include <QTime>
#include <QAction>
#include <QSortFilterProxyModel>
#include <QDialog>
using namespace BlackMisc;
using namespace BlackGui;
using namespace BlackGui::Models;
namespace BlackGui
@@ -48,10 +53,36 @@ namespace BlackGui
this->setHorizontalScrollMode(QAbstractItemView::ScrollPerPixel);
}
void CViewBaseNonTemplate::setFilterDialog(QDialog *filterDialog)
{
if (filterDialog)
{
this->m_withMenuFilter = true;
this->m_filterDialog.reset(filterDialog);
connect(filterDialog, &QDialog::finished, this, &CViewBaseNonTemplate::ps_filterDialogFinished);
}
else
{
if (!this->m_filterDialog.isNull()) { disconnect(this->m_filterDialog.data()); }
this->m_withMenuFilter = false;
this->m_filterDialog.reset(nullptr);
}
}
QWidget *CViewBaseNonTemplate::mainApplicationWindowWidget() const
{
return CGuiUtility::mainApplicationWindowWidget();
}
void CViewBaseNonTemplate::customMenu(QMenu &menu) const
{
if (this->m_withMenuItemRefresh) { menu.addAction(BlackMisc::CIcons::refresh16(), "Update", this, SIGNAL(requestUpdate())); }
if (this->m_withMenuItemClear) { menu.addAction(BlackMisc::CIcons::delete16(), "Clear", this, SLOT(ps_clear())); }
if (this->m_withMenuFilter)
{
menu.addAction(BlackMisc::CIcons::tableSheet16(), "Filter", this, SLOT(ps_displayFilterDialog()));
menu.addAction(BlackMisc::CIcons::tableSheet16(), "Remove Filter", this, SLOT(ps_removeFilter()));
}
if (!menu.isEmpty()) { menu.addSeparator(); }
menu.addAction(BlackMisc::CIcons::resize16(), "Full resize", this, SLOT(fullResizeToContents()));
@@ -91,11 +122,23 @@ namespace BlackGui
int fh = qRound(1.5 * this->getHorizontalHeaderFontHeight());
this->horizontalHeader()->setSectionResizeMode(QHeaderView::Interactive); // faster mode
this->horizontalHeader()->setStretchLastSection(true);
this->verticalHeader()->setDefaultSectionSize(fh);
this->verticalHeader()->setMinimumSectionSize(fh);
this->verticalHeader()->setDefaultSectionSize(fh); // for height
this->verticalHeader()->setMinimumSectionSize(fh); // for height
this->initRowsResizeModeToInteractive();
}
int CViewBaseNonTemplate::ps_updateContainer(const CVariant &variant, bool sort, bool resize)
{
return this->performUpdateContainer(variant, sort, resize);
}
void CViewBaseNonTemplate::ps_displayFilterDialog()
{
if (!this->m_withMenuFilter) { return; }
if (!this->m_filterDialog) { return; }
this->m_filterDialog->show();
}
void CViewBaseNonTemplate::initRowsResizeModeToInteractive()
{
const int height = this->verticalHeader()->minimumSectionSize();
@@ -116,8 +159,8 @@ namespace BlackGui
if (m_resizeMode == ResizingOnce) { return m_resizeCount < 1; }
if (m_resizeMode == ResizingAuto)
{
if (reachedResizeThreshold()) return false;
if (m_resizeAutoNthTime < 2) return true;
if (reachedResizeThreshold()) { return false; }
if (m_resizeAutoNthTime < 2) { return true; }
return (m_resizeCount % m_resizeAutoNthTime) == 0;
}
return false;
@@ -125,10 +168,6 @@ namespace BlackGui
void CViewBaseNonTemplate::fullResizeToContents()
{
// KWB remove
QTime t;
t.start();
m_resizeCount++;
this->resizeColumnsToContents();
this->resizeRowsToContents();
@@ -177,7 +216,7 @@ namespace BlackGui
BlackMisc::CWorker *worker = BlackMisc::CWorker::fromTask(this, "ViewSort", [this, model, container, sort, resize, sortColumn, sortOrder]()
{
ContainerType sortedContainer = model->sortContainerByColumn(container, sortColumn, sortOrder);
QMetaObject::invokeMethod(this, "updateContainer",
QMetaObject::invokeMethod(this, "ps_updateContainer",
Q_ARG(BlackMisc::CVariant, sortedContainer.toCVariant()), Q_ARG(bool, false), Q_ARG(bool, resize));
});
worker->then(this, &CViewBase::asyncUpdateFinished);
@@ -197,6 +236,25 @@ namespace BlackGui
}
}
template <class ModelClass, class ContainerType, class ObjectType> void CViewBase<ModelClass, ContainerType, ObjectType>::insert(const ObjectType &value, bool resize)
{
Q_ASSERT(this->m_model);
this->m_model->insert(value);
if (resize) { this->performResizeToContents(); }
}
template <class ModelClass, class ContainerType, class ObjectType> const ObjectType &CViewBase<ModelClass, ContainerType, ObjectType>::at(const QModelIndex &index) const
{
Q_ASSERT(this->m_model);
return this->m_model->at(index);
}
template <class ModelClass, class ContainerType, class ObjectType> const ContainerType &CViewBase<ModelClass, ContainerType, ObjectType>::getContainer() const
{
Q_ASSERT(this->m_model);
return this->m_model->getContainer();
}
template <class ModelClass, class ContainerType, class ObjectType> ContainerType CViewBase<ModelClass, ContainerType, ObjectType>::selectedObjects() const
{
if (!this->hasSelection()) { return ContainerType(); }
@@ -209,25 +267,29 @@ namespace BlackGui
return c;
}
template <class ModelClass, class ContainerType, class ObjectType> int CViewBase<ModelClass, ContainerType, ObjectType>::rowCount() const
template <class ModelClass, class ContainerType, class ObjectType>
int CViewBase<ModelClass, ContainerType, ObjectType>::rowCount() const
{
Q_ASSERT(this->m_model);
return this->m_model->rowCount();
}
template <class ModelClass, class ContainerType, class ObjectType> int CViewBase<ModelClass, ContainerType, ObjectType>::columnCount() const
template <class ModelClass, class ContainerType, class ObjectType>
int CViewBase<ModelClass, ContainerType, ObjectType>::columnCount() const
{
Q_ASSERT(this->m_model);
return this->m_model->columnCount(QModelIndex());
}
template <class ModelClass, class ContainerType, class ObjectType> bool CViewBase<ModelClass, ContainerType, ObjectType>::isEmpty() const
template <class ModelClass, class ContainerType, class ObjectType>
bool CViewBase<ModelClass, ContainerType, ObjectType>::isEmpty() const
{
Q_ASSERT(this->m_model);
return this->m_model->rowCount() < 1;
}
template <class ModelClass, class ContainerType, class ObjectType> void CViewBase<ModelClass, ContainerType, ObjectType>::setObjectName(const QString &name)
template <class ModelClass, class ContainerType, class ObjectType>
void CViewBase<ModelClass, ContainerType, ObjectType>::setObjectName(const QString &name)
{
// then name here is mainly set for debugging purposes so each model can be identified
Q_ASSERT(m_model);
@@ -236,7 +298,8 @@ namespace BlackGui
this->m_model->setObjectName(modelName);
}
template <class ModelClass, class ContainerType, class ObjectType> void CViewBase<ModelClass, ContainerType, ObjectType>::setSortIndicator()
template <class ModelClass, class ContainerType, class ObjectType>
void CViewBase<ModelClass, ContainerType, ObjectType>::setSortIndicator()
{
if (this->m_model->hasValidSortColumn())
{
@@ -247,20 +310,24 @@ namespace BlackGui
}
}
template <class ModelClass, class ContainerType, class ObjectType> void CViewBase<ModelClass, ContainerType, ObjectType>::standardInit(ModelClass *model)
template <class ModelClass, class ContainerType, class ObjectType>
void CViewBase<ModelClass, ContainerType, ObjectType>::standardInit(ModelClass *model)
{
Q_ASSERT(model || this->m_model);
if (model)
{
this->m_model = model;
connect(this->m_model, &ModelClass::rowCountChanged, this, &CViewBase::countChanged);
connect(this->m_model, &ModelClass::rowCountChanged, this, &CViewBase::rowCountChanged);
connect(this->m_model, &ModelClass::objectChanged, this, &CViewBase::objectChanged);
}
this->setModel(this->m_model); // via QTableView
CViewBaseNonTemplate::init();
this->setSortIndicator();
}
template <class ModelClass, class ContainerType, class ObjectType> void CViewBase<ModelClass, ContainerType, ObjectType>::performResizeToContents()
template <class ModelClass, class ContainerType, class ObjectType>
void CViewBase<ModelClass, ContainerType, ObjectType>::performResizeToContents()
{
// small set or large set?
if (this->performResizing())
@@ -273,13 +340,32 @@ namespace BlackGui
}
}
template <class ModelClass, class ContainerType, class ObjectType> int CViewBase<ModelClass, ContainerType, ObjectType>::performUpdateContainer(const BlackMisc::CVariant &variant, bool sort, bool resize)
template <class ModelClass, class ContainerType, class ObjectType>
int CViewBase<ModelClass, ContainerType, ObjectType>::performUpdateContainer(const BlackMisc::CVariant &variant, bool sort, bool resize)
{
ContainerType c;
c.convertFromCVariant(variant);
return this->updateContainer(c, sort, resize);
}
template <class ModelClass, class ContainerType, class ObjectType>
bool CViewBase<ModelClass, ContainerType, ObjectType>::ps_filterDialogFinished(int status)
{
QDialog::DialogCode statusCode = static_cast<QDialog::DialogCode>(status);
if (statusCode == QDialog::Rejected)
{
this->derivedModel()->removeFilter();
return true; // handled
}
return false;
}
template <class ModelClass, class ContainerType, class ObjectType>
void CViewBase<ModelClass, ContainerType, ObjectType>::ps_removeFilter()
{
this->derivedModel()->removeFilter();
}
// see here for the reason of thess forward instantiations
// http://www.parashift.com/c++-faq/separate-template-class-defn-from-decl.html
template class CViewBase<BlackGui::Models::CStatusMessageListModel, BlackMisc::CStatusMessageList, BlackMisc::CStatusMessage>;
@@ -290,7 +376,8 @@ namespace BlackGui
template class CViewBase<BlackGui::Models::CServerListModel, BlackMisc::Network::CServerList, BlackMisc::Network::CServer>;
template class CViewBase<BlackGui::Models::CUserListModel, BlackMisc::Network::CUserList, BlackMisc::Network::CUser>;
template class CViewBase<BlackGui::Models::CClientListModel, BlackMisc::Network::CClientList, BlackMisc::Network::CClient>;
template class CViewBase<BlackGui::Models::CAircraftModelListModel, BlackMisc::Network::CAircraftModelList, BlackMisc::Network::CAircraftModel>;
template class CViewBase<BlackGui::Models::CSimulatedAircraftListModel, BlackMisc::Simulation::CSimulatedAircraftList, BlackMisc::Simulation::CSimulatedAircraft>;
template class CViewBase<BlackGui::Models::CAircraftModelListModel, BlackMisc::Simulation::CAircraftModelList, BlackMisc::Simulation::CAircraftModel>;
template class CViewBase<BlackGui::Models::CKeyboardKeyListModel, BlackMisc::Settings::CSettingKeyboardHotkeyList, BlackMisc::Settings::CSettingKeyboardHotkey>;
} // namespace

View File

@@ -16,6 +16,7 @@
#include "blackmisc/worker.h"
#include "blackmisc/variant.h"
#include <QTableView>
#include <QWizardPage>
#include <QHeaderView>
#include <QMenu>
#include <QPoint>
@@ -70,6 +71,12 @@ namespace BlackGui
//! Selected rows if any
QModelIndexList selectedRows() const;
//! Filter dialog
void setFilterDialog(QDialog *filterDialog);
//! Main application window widget if any
QWidget *mainApplicationWindowWidget() const;
signals:
//! Ask for new data
void requestUpdate();
@@ -78,7 +85,10 @@ namespace BlackGui
void asyncUpdateFinished();
//! Number of elements changed
void countChanged(int count);
void rowCountChanged(int count, bool withFilter);
//! Single object was changed in model
void objectChanged(const BlackMisc::CVariant &object, const BlackMisc::CPropertyIndex &changedIndex);
public slots:
//! Resize to contents, strategy depends on container size
@@ -127,13 +137,21 @@ namespace BlackGui
bool m_forceStretchLastColumnWhenResized = false; //!< a small table might (few columns) might to fail stretching, force again
bool m_withMenuItemClear = false; //!< allow clearing the view via menu
bool m_withMenuItemRefresh = false; //!< allow refreshing the view via menu
bool m_withMenuFilter = false; //!< filter can be opened
QScopedPointer<QDialog> m_filterDialog; //!< filter dialog if any
protected slots:
//! Helper method with template free signature serving as callback from threaded worker
int updateContainer(const BlackMisc::CVariant &variant, bool sort, bool resize)
{
return this->performUpdateContainer(variant, sort, resize);
}
int ps_updateContainer(const BlackMisc::CVariant &variant, bool sort, bool resize);
//! Display the filter dialog
void ps_displayFilterDialog();
//! Remove filter
virtual void ps_removeFilter() = 0;
//! Filter dialog finished
virtual bool ps_filterDialogFinished(int status) = 0;
private slots:
//! Custom menu was requested
@@ -173,19 +191,13 @@ namespace BlackGui
void updateContainerMaybeAsync(const ContainerType &container, bool sort = true, bool performResizing = true);
//! Insert
void insert(const ObjectType &value, bool resize = true)
{
Q_ASSERT(this->m_model);
this->m_model->insert(value);
if (resize) { this->performResizeToContents(); }
}
void insert(const ObjectType &value, bool resize = true);
//! Value object at
const ObjectType &at(const QModelIndex &index) const
{
Q_ASSERT(this->m_model);
return this->m_model->at(index);
}
const ObjectType &at(const QModelIndex &index) const;
//! Access to container
const ContainerType &getContainer() const;
//! Selected objects
ContainerType selectedObjects() const;
@@ -227,6 +239,13 @@ namespace BlackGui
//! \copydoc CViewBaseNonTemplate::performUpdateContainer
virtual int performUpdateContainer(const BlackMisc::CVariant &variant, bool sort, bool performResizing) override;
//! \copydoc CViewBaseNonTemplate::ps_filterDialogFinished
//! \remarks Actually a slot, but not defined as such as the template does not support Q_OBJECT
virtual bool ps_filterDialogFinished(int status) override;
//! \copydoc CViewBaseNonTemplate::ps_removeFilter
//! \remarks Actually a slot, but not defined as such as the template does not support Q_OBJECT
virtual void ps_removeFilter() override;
};
} // namespace
} // namespace