You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
nm-tray-packaging/src/windowmenu.cpp

183 lines
6.9 KiB

/*COPYRIGHT_HEADER
This file is a part of nm-tray.
Copyright (c)
2016~now Palo Kisa <palo.kisa@gmail.com>
nm-tray 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.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
COPYRIGHT_HEADER*/
#include "windowmenu.h"
#include "nmmodel.h"
#include "nmproxy.h"
#include "menuview.h"
#include <QWidgetAction>
#include <functional>
#include <QTimer>
class WindowMenuPrivate
{
public:
NmModel * mNmModel;
QScopedPointer<NmProxy> mWirelessModel;
QWidgetAction * mWirelessAction;
QScopedPointer<NmProxy> mActiveModel;
QWidgetAction * mActiveAction;
QScopedPointer<NmProxy> mConnectionModel;
QWidgetAction * mConnectionAction;
QAction * mMakeDirtyAction;
QTimer mDelaySizeRefreshTimer;
WindowMenuPrivate(WindowMenu * q);
template <typename F>
void onActivated(QModelIndex const & index
, QAbstractItemModel const * topParent
, F const & functor);
void forceSizeRefresh();
void onViewRowChange(QAction * viewAction, QAbstractItemModel const * model);
private:
WindowMenu * q_ptr;
Q_DECLARE_PUBLIC(WindowMenu);
};
WindowMenuPrivate::WindowMenuPrivate(WindowMenu * q)
: q_ptr{q}
{
}
template <typename F>
void WindowMenuPrivate::onActivated(QModelIndex const & index
, QAbstractItemModel const * topParent
, F const & functor)
{
QModelIndex i = index;
for (QAbstractProxyModel const * proxy = qobject_cast<QAbstractProxyModel const *>(index.model())
; nullptr != proxy && topParent != proxy
; proxy = qobject_cast<QAbstractProxyModel const *>(proxy->sourceModel())
)
{
i = proxy->mapToSource(i);
}
functor(i);
}
void WindowMenuPrivate::forceSizeRefresh()
{
Q_Q(WindowMenu);
if (!q->isVisible())
{
return;
}
const QSize old_size = q->size();
//TODO: how to force the menu to recalculate it's size in a more elegant way?
q->addAction(mMakeDirtyAction);
q->removeAction(mMakeDirtyAction);
// ensure to be visible (should the resize make it out of screen)
if (old_size != q->size())
{
q->popup(q->geometry().topLeft());
}
}
void WindowMenuPrivate::onViewRowChange(QAction * viewAction, QAbstractItemModel const * model)
{
viewAction->setVisible(model->rowCount(QModelIndex{}) > 0);
mDelaySizeRefreshTimer.start();
}
WindowMenu::WindowMenu(NmModel * nmModel, QWidget * parent /*= nullptr*/)
: QMenu{parent}
, d_ptr{new WindowMenuPrivate{this}}
{
Q_D(WindowMenu);
d->mNmModel = nmModel;
//active proxy & widgets
d->mActiveModel.reset(new NmProxy);
d->mActiveModel->setNmModel(d->mNmModel, NmModel::ActiveConnectionType);
MenuView * active_view = new MenuView{d->mActiveModel.data()};
connect(active_view, &QAbstractItemView::activated, [this, d] (const QModelIndex & index) {
d->onActivated(index, d->mActiveModel.data(), std::bind(&NmProxy::deactivateConnection, d->mActiveModel.data(), std::placeholders::_1));
close();
});
d->mActiveAction = new QWidgetAction{this};
d->mActiveAction->setDefaultWidget(active_view);
connect(d->mActiveModel.data(), &QAbstractItemModel::modelReset, [d] { d->onViewRowChange(d->mActiveAction, d->mActiveModel.data()); });
connect(d->mActiveModel.data(), &QAbstractItemModel::rowsInserted, [d] { d->onViewRowChange(d->mActiveAction, d->mActiveModel.data()); });
connect(d->mActiveModel.data(), &QAbstractItemModel::rowsRemoved, [d] { d->onViewRowChange(d->mActiveAction, d->mActiveModel.data()); });
//wireless proxy & widgets
d->mWirelessModel.reset(new NmProxy);
d->mWirelessModel->setNmModel(d->mNmModel, NmModel::WifiNetworkType);
MenuView * wifi_view = new MenuView{d->mWirelessModel.data()};
connect(wifi_view, &QAbstractItemView::activated, [this, d] (const QModelIndex & index) {
d->onActivated(index, d->mWirelessModel.data(), std::bind(&NmProxy::activateConnection, d->mWirelessModel.data(), std::placeholders::_1));
close();
});
d->mWirelessAction = new QWidgetAction{this};
d->mWirelessAction->setDefaultWidget(wifi_view);
connect(d->mWirelessModel.data(), &QAbstractItemModel::modelReset, [d] { d->onViewRowChange(d->mWirelessAction, d->mWirelessModel.data()); });
connect(d->mWirelessModel.data(), &QAbstractItemModel::rowsInserted, [d] { d->onViewRowChange(d->mWirelessAction, d->mWirelessModel.data()); });
connect(d->mWirelessModel.data(), &QAbstractItemModel::rowsRemoved, [d] { d->onViewRowChange(d->mWirelessAction, d->mWirelessModel.data()); });
//connection proxy & widgets
d->mConnectionModel.reset(new NmProxy);
d->mConnectionModel->setNmModel(d->mNmModel, NmModel::ConnectionType);
MenuView * connection_view = new MenuView{d->mConnectionModel.data()};
connect(connection_view, &QAbstractItemView::activated, [this, d] (const QModelIndex & index) {
d->onActivated(index, d->mConnectionModel.data(), std::bind(&NmProxy::activateConnection, d->mConnectionModel.data(), std::placeholders::_1));
close();
});
d->mConnectionAction = new QWidgetAction{this};
d->mConnectionAction->setDefaultWidget(connection_view);
connect(d->mConnectionModel.data(), &QAbstractItemModel::modelReset, [d] { d->onViewRowChange(d->mConnectionAction, d->mConnectionModel.data()); });
connect(d->mConnectionModel.data(), &QAbstractItemModel::rowsInserted, [d] { d->onViewRowChange(d->mConnectionAction, d->mConnectionModel.data()); });
connect(d->mConnectionModel.data(), &QAbstractItemModel::rowsRemoved, [d] { d->onViewRowChange(d->mConnectionAction, d->mConnectionModel.data()); });
addAction(tr("Active connection(s)"))->setEnabled(false);
addAction(d->mActiveAction);
addAction(tr("Wi-Fi network(s)"))->setEnabled(false);
addAction(d->mWirelessAction);
addAction(tr("Known connection(s)"))->setEnabled(false);
addAction(d->mConnectionAction);
d->mMakeDirtyAction = new QAction{this};
d->mDelaySizeRefreshTimer.setInterval(200);
d->mDelaySizeRefreshTimer.setSingleShot(true);
connect(&d->mDelaySizeRefreshTimer, &QTimer::timeout, [d] { d->forceSizeRefresh(); });
d->onViewRowChange(d->mActiveAction, d->mActiveModel.data());
d->onViewRowChange(d->mWirelessAction, d->mWirelessModel.data());
d->onViewRowChange(d->mConnectionAction, d->mConnectionModel.data());
}
WindowMenu::~WindowMenu()
{
}