Permalink
Fetching contributors…
Cannot retrieve contributors at this time
executable file 3069 lines (2667 sloc) 126 KB
/**************************** controlbox.cpp ***************************
Code to manage the primary user interface to include the QDialog the
user interfaces with and the system tray icon.
Copyright (C) 2013-2018
by: Andrew J. Bibb
License: MIT
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"),to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
***********************************************************************/
/**********************************************************************
* NOTE TO PEOPLE HACKING ON THE CODE
*
* Prior to 2015.11.12 text returned by connman was translated and then
* stored in the various maps. After that date the code was revised so
* that text is stored in the maps exactly as connman returns it and
* is then translated when it needs to be displayed.
*
***********************************************************************/
# include <QDBusArgument>
# include <QTableWidget>
# include <QTableWidgetItem>
# include <QFileInfo>
# include <QFile>
# include <QWhatsThis>
# include <QMenu>
# include <QPixmap>
# include <QMessageBox>
# include <QCloseEvent>
# include <QKeyEvent>
# include <QToolTip>
# include <QTableWidgetSelectionRange>
# include <QProcess>
# include <QProcessEnvironment>
# include <QCryptographicHash>
# include <QLocale>
# include <QColorDialog>
# include <QPainter>
# include <QImage>
# include <QDesktopWidget>
# include <QInputDialog>
# include "../resource.h"
# include "./controlbox.h"
# include "./code/scrollbox/scrollbox.h"
# include "./code/peditor/peditor.h"
# include "./code/provisioning/prov_ed.h"
# include "./code/vpn_prov_ed/vpn_ed.h"
# include "./code/trstring/tr_strings.h"
# include "./code/shared/shared.h"
// headers for system logging
# include <stdio.h>
# include <unistd.h>
# include <syslog.h>
# define DBUS_PATH "/"
# define DBUS_CON_SERVICE "net.connman"
# define DBUS_VPN_SERVICE "net.connman.vpn"
# define DBUS_CON_MANAGER "net.connman.Manager"
# define DBUS_VPN_MANAGER "net.connman.vpn.Manager"
// Custom push button, used in the technology box for powered on/off
// This is really a single use button, after it is clicked all idButtons
// are deleted and recreated. Once is is clicked disable the button.
idButton::idButton(QWidget* parent, const QDBusObjectPath& id) :
QFrame(parent)
{
// margins
const int m_left = 5;
const int m_top = 0;
const int m_right = 5;
const int m_bottom = 0;
// create the button
button = new QToolButton(this);
button->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
obj_id = id;
button->setCheckable(true);
button->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
connect (button, SIGNAL(clicked(bool)), this, SLOT(buttonClicked(bool)));
// create the box
QHBoxLayout* layout = new QHBoxLayout(this);
layout->setContentsMargins(m_left, m_top, m_right, m_bottom);
layout->setAlignment(Qt::AlignCenter);
layout->addWidget(button, 0, 0);
return;
}
void idButton::buttonClicked(bool checked)
{
this->setDisabled(true);
emit clickedID (obj_id.path(), checked);
return;
}
// main GUI element
ControlBox::ControlBox(const QCommandLineParser& parser, QWidget *parent)
: QDialog(parent)
{
// set the Locale (probably not necessary since the default is the system one anyway)
QLocale::setDefault(QLocale::system() );
// setup the user interface
ui.setupUi(this);
// set the window title
setWindowTitle(TranslateStrings::cmtr("connman system tray"));
// data members
q16_errors = CMST::No_Errors;
properties_map.clear();
services_list.clear();
technologies_list.clear();
wifi_list.clear();
peer_list.clear();
vpn_list.clear();
agent = new ConnmanAgent(this);
vpnagent = new ConnmanVPNAgent(this);
counter = new ConnmanCounter(this);
trayiconmenu = new QMenu(this);
tech_submenu = new QMenu(tr("Technologies"), this);
info_submenu = new QMenu(tr("Service Details"), this);
wifi_submenu = new QMenu(tr("WiFi Connections"), this);
vpn_submenu = new QMenu(tr("VPN Connections"), this);
mvsrv_menu = new QMenu(this);
settings = new QSettings(ORG, APP, this);
notifyclient = 0;
onlineobjectpath.clear();
socketserver = new QLocalServer(this);
socketserver->removeServer(SOCKET_NAME); // remove any files that may have been left after a crash
socketserver->listen(SOCKET_NAME);
trayiconbackground = QColor();
trayicon = new QSystemTrayIcon(this);
iconman = new IconManager(this);
// set a stylesheet on the tab widget - used to hide disabled tabs
QFile f0(":/stylesheets/stylesheets/tabwidget.qss");
if (f0.open(QIODevice::ReadOnly | QIODevice::Text)) {
QString qss = QString(f0.readAll());
f0.close();
ui.tabWidget->setStyleSheet(qss);
}
// set a stylesheet on the offlinemode toolbutton. Until 2017.12 this
// was a label to display a pixmap. It is now a QToolButton, but I want the
// picture to show the current state (transmitting or airplane), not the
// state that will happen if you push the button, for instance typical
// play/pause behavior in a media player. If I advertise this is a button
// I'll get complaints that the pictures are backwards, so hide that fact
// by making it look like a label with the stylesheet.
QFile f1(":/stylesheets/stylesheets/airplane.qss");
if (f1.open(QIODevice::ReadOnly | QIODevice::Text)) {
QString qss = QString(f1.readAll());
f1.close();
ui.toolButton_offlinemode->setStyleSheet(qss);
}
// Read saved settings which will set the ui controls in the preferences tab.
this->readSettings();
// Set the iconmanager color
iconman->setIconColor(QColor(ui.lineEdit_colorize->text()) );
// Constructor scope bool, set to true if we are using start options
bool b_so = (! parser.isSet("bypass-start-options") && ui.checkBox_usestartoptions->isChecked() );
// Enable or disable preferences group box (changed via ui signal/slot after the constructor)
ui.groupBox_startoptions->setEnabled(ui.checkBox_usestartoptions->isChecked());
// Restore window if retain_state is checked and we have not bypassed it on the command line
if (! parser.isSet("bypass-restore-state") && settings->value("CheckBoxes/retain_state").toBool() ) {
settings->beginGroup("MainWindow");
resize(settings->value("size", QSize(700, 550)).toSize() );
move(settings->value("pos", QPoint(200, 200)).toPoint() );
ui.splitter01->restoreState(settings->value("splitter_01").toByteArray() );
ui.tabWidget->setCurrentIndex(settings->value("current_page").toInt() );
settings->endGroup();
}
// Make sure the controlbox will fit onto small acreens
QSize sz_target = (qApp->desktop()->availableGeometry(this)).size();
QSize sz_source = this->sizeHint();
sz_target.scale(sz_target.width() - 100, sz_target.height() - 100, Qt::KeepAspectRatio); // give me a little buffer
if (sz_source.width() > sz_target.width() || sz_source.height() > sz_target.height() ) {
sz_source.scale(sz_target.width(), sz_target.height(), Qt::KeepAspectRatio);
resize(sz_source);
move(25, 25);
}
// set a flag if we sent a commandline option to log the connman inputrequest
agent->setLogInputRequest(parser.isSet("log-input-request"));
vpnagent->setLogInputRequest(parser.isSet("log-input-request"));
QDir d(IPT_REQ_LOG_PATH);
d.mkpath(IPT_REQ_LOG_PATH);
if (d.exists(IPT_REQ_LOG_FILE)) d.remove(IPT_REQ_LOG_FILE);
// Set icon theme if provided on the command line or in the settings
if (parser.isSet("icon-theme") ) {
if (parser.value("icon-theme").isEmpty() ) {
if (QIcon::themeName().isEmpty() ) QIcon::setThemeName(INTERNAL_THEME);
} // if
else
QIcon::setThemeName(parser.value("icon-theme") );
} // if parser is set
else {
if (b_so && ui.checkBox_systemicontheme->isChecked() ) {
if (ui.lineEdit_icontheme->text().isEmpty() ) {
if (QIcon::themeName().isEmpty() ) QIcon::setThemeName(INTERNAL_THEME);
} // if
else
QIcon::setThemeName(ui.lineEdit_icontheme->text() );
} // if
else QIcon::setThemeName(INTERNAL_THEME);
} // else
// Set the window icon. If an icon was installed to /usr/share/icons/hicolor/48x48/apps
// use that, otherwise use a freedesktop.org named one
if (QFile::exists("/usr/share/icons/hicolor/48x48/apps/cmst.png") )
this->setWindowIcon(QIcon("/usr/share/icons/hicolor/48x48/apps/cmst.png") );
else
this->setWindowIcon(QIcon::fromTheme("preferences-system-network") );
// Set the whatsthis icons
ui.toolButton_whatsthis->setIcon(iconman->getIcon("whats_this"));
agent->setWhatsThisIcon(iconman->getIcon("whats_this"));
vpnagent->setWhatsThisIcon(iconman->getIcon("whats_this"));
// set a flag if we want to use XFCE or MATE custom code.
// Currently (as of 2014.11.24) this is only used to get around a bug between QT5.3 and the XFCE system tray
// Even then the fix may not work, but for now keep it in.
b_usexfce = (parser.isSet("use-xfce") ? true : (b_so && ui.radioButton_desktopxfce->isChecked()) );
b_usemate = (parser.isSet("use-mate") ? true : (b_so && ui.radioButton_desktopmate->isChecked()) );
// Fake transparency
if (parser.isSet("fake-transparency") ) {
bool ok;
trayiconbackground = QColor(parser.value("fake-transparency").toUInt(&ok, 16) );
if (! ok) trayiconbackground = QColor();
} // if parser set
else
if (b_so && ui.checkBox_faketranparency->isChecked() ) {
trayiconbackground = QColor(ui.spinBox_faketransparency->value() );
} // if
else trayiconbackground = QColor();
// set counter update params from command line options if available otherwise
// default params specified in main.cpp are used. Set a minimum value for
// each to maintain program response.
uint minval = ui.spinBox_counterkb->minimum();
uint setval = 0;
if (parser.isSet("counter-update-kb") ) {
bool ok;
setval = parser.value("counter-update-kb").toUInt(&ok, 10);
if (! ok) setval = minval;
} // if parser set
else if (b_so && ui.checkBox_counterkb->isChecked() ) {
setval = ui.spinBox_counterkb->value();
} // else if
counter_accuracy = setval > minval ? setval : minval; // number of kb for counter updates
minval = ui.spinBox_counterrate->minimum();
setval = 0;
if (parser.isSet("counter-update-rate") ) {
bool ok;
setval = parser.value("counter-update-rate").toUInt(&ok, 10);
if (! ok) setval = minval;
} // if parser set
else if (b_so && ui.checkBox_counterseconds->isChecked() ) {
setval = ui.spinBox_counterrate->value();
}
counter_period = setval > minval ? setval : minval; // number of seconds for counter updates
// Hide the minimize button requested
if (parser.isSet("disable-minimize") ? true : (b_so && ui.checkBox_disableminimized->isChecked()) )
ui.pushButton_minimize->hide();
// operate on settings not dealt with elsewhere
ui.pushButton_provisioning_editor->setVisible(ui.checkBox_advanced->isChecked() );
ui.pushButton_vpn_editor->setVisible(ui.checkBox_advanced->isChecked() );
ui.groupBox_process->setVisible(ui.checkBox_advanced->isChecked() );
enableRunOnStartup(ui.checkBox_runonstartup->isChecked() );
// Create the notifyclient, make four tries; first immediately in constructor, then
// at 1/2 second, 2 seconds and finally at 8 seconds
notifyclient = new NotifyClient(this);
this->connectNotifyClient();
QTimer::singleShot(500, this, SLOT(connectNotifyClient()));
QTimer::singleShot(2 * 1000, this, SLOT(connectNotifyClient()));
QTimer::singleShot(8 * 1000, this, SLOT(connectNotifyClient()));
// setup the dbus interface to connman.manager
if (! QDBusConnection::systemBus().isConnected() ) logErrors(CMST::Err_No_DBus);
else {
con_manager = new QDBusInterface(DBUS_CON_SERVICE, DBUS_PATH, DBUS_CON_MANAGER, QDBusConnection::systemBus(), this);
if (! con_manager->isValid() ) logErrors(CMST::Err_Invalid_Con_Iface);
else {
// Access connman.manager to retrieve the data
this->managerRescan(CMST::Manager_All);
// register the agent
shared::processReply(con_manager->call(QDBus::AutoDetect, "RegisterAgent", QVariant::fromValue(QDBusObjectPath(AGENT_OBJECT))) );
// if counters are enabled connect signal to slot and register the counter
if (parser.isSet("enable-counters") ? true : (b_so && ui.checkBox_enablecounters->isChecked()) ) {
QList<QVariant> vlist_counter;
vlist_counter.clear();
vlist_counter << QVariant::fromValue(QDBusObjectPath(CNTR_OBJECT)) << counter_accuracy << counter_period;
QDBusMessage reply = con_manager->callWithArgumentList(QDBus::AutoDetect, "RegisterCounter", vlist_counter);
if (shared::processReply(reply) == QDBusMessage::ReplyMessage)
connect(counter, SIGNAL(usageUpdated(QDBusObjectPath, QString, QString)), this, SLOT(counterUpdated(QDBusObjectPath, QString, QString)));
} // enable counters
else {
ui.tabWidget->setTabEnabled(ui.tabWidget->indexOf(ui.Counters), false);
}
// connect some dbus signals to our slots
QDBusConnection::systemBus().connect(DBUS_CON_SERVICE, DBUS_PATH, DBUS_CON_MANAGER, "PropertyChanged", this, SLOT(dbsPropertyChanged(QString, QDBusVariant)));
QDBusConnection::systemBus().connect(DBUS_CON_SERVICE, DBUS_PATH, DBUS_CON_MANAGER, "ServicesChanged", this, SLOT(dbsServicesChanged(QList<QVariant>, QList<QDBusObjectPath>, QDBusMessage)));
QDBusConnection::systemBus().connect(DBUS_CON_SERVICE, DBUS_PATH, DBUS_CON_MANAGER, "PeersChanged", this, SLOT(dbsPeersChanged(QList<QVariant>, QList<QDBusObjectPath>, QDBusMessage)));
QDBusConnection::systemBus().connect(DBUS_CON_SERVICE, DBUS_PATH, DBUS_CON_MANAGER, "TechnologyAdded", this, SLOT(dbsTechnologyAdded(QDBusObjectPath, QVariantMap)));
QDBusConnection::systemBus().connect(DBUS_CON_SERVICE, DBUS_PATH, DBUS_CON_MANAGER, "TechnologyRemoved", this, SLOT(dbsTechnologyRemoved(QDBusObjectPath)));
// clear the counters if selected
this->clearCounters();
// VPN manager. Disable if commandline or option is set
vpn_manager = NULL;
if (parser.isSet("disable-vpn") ? true : (b_so && ui.checkBox_disablevpn->isChecked()) ) {
ui.tabWidget->setTabEnabled(ui.tabWidget->indexOf(ui.VPN), false);
ui.pushButton_vpn_editor->setDisabled(true);
} // if parser set
else {
vpn_manager = new QDBusInterface(DBUS_VPN_SERVICE, DBUS_PATH, DBUS_VPN_MANAGER, QDBusConnection::systemBus(), this);
if (! vpn_manager->isValid() ) {
ui.tabWidget->setTabEnabled(ui.tabWidget->indexOf(ui.VPN), false);
ui.pushButton_vpn_editor->setDisabled(true);
logErrors(CMST::Err_Invalid_VPN_Iface);
}
else {
ui.tabWidget->setTabEnabled(ui.tabWidget->indexOf(ui.VPN), true);
ui.pushButton_vpn_editor->setEnabled(true);
shared::processReply(vpn_manager->call(QDBus::AutoDetect, "RegisterAgent", QVariant::fromValue(QDBusObjectPath(VPN_AGENT_OBJECT))) );
} // else register agent
} // else normal vpn manager
} // else have valid connection
} // else have connected systemBus
// add actions to groups
minMaxGroup = new QActionGroup(this);
minimizeAction = new QAction(tr("Mi&nimize"), this);
maximizeAction = new QAction(tr("Ma&ximize"), this);
minMaxGroup->addAction(minimizeAction);
minMaxGroup->addAction(maximizeAction);
exitAction = new QAction(tr("&Exit"), this);
moveGroup = new QActionGroup(this);
moveGroup->addAction(ui.actionMove_Before);
moveGroup->addAction(ui.actionMove_After);
// connect signals and slots - actions and action groups
connect(minMaxGroup, SIGNAL(triggered(QAction*)), this, SLOT(minMaxWindow(QAction*)));
connect(tech_submenu, SIGNAL(triggered(QAction*)), this, SLOT(techSubmenuTriggered(QAction*)));
connect(info_submenu, SIGNAL(triggered(QAction*)), this, SLOT(infoSubmenuTriggered(QAction*)));
connect(wifi_submenu, SIGNAL(triggered(QAction*)), this, SLOT(wifiSubmenuTriggered(QAction*)));
connect(vpn_submenu, SIGNAL(triggered(QAction*)), this, SLOT(vpnSubmenuTriggered(QAction*)));
connect(exitAction, SIGNAL(triggered()), qApp, SLOT(quit()));
connect(moveGroup, SIGNAL(triggered(QAction*)), this, SLOT(moveButtonPressed(QAction*)));
connect(mvsrv_menu, SIGNAL(triggered(QAction*)), this, SLOT(moveService(QAction*)));
connect(ui.actionRescan, SIGNAL (triggered()), this, SLOT(scanWiFi()));
connect(ui.actionIDPass, SIGNAL (triggered()), this, SLOT(wifiIDPass()));
connect(ui.actionOffline_Mode, SIGNAL(toggled(bool)), this, SLOT(toggleOfflineMode(bool)));
// connect signals and slots - ui elements
connect(ui.toolButton_whatsthis, SIGNAL(clicked()), this, SLOT(showWhatsThis()));
connect(ui.comboBox_service, SIGNAL(currentIndexChanged(int)), this, SLOT(getServiceDetails(int)));
connect(ui.pushButton_exit, SIGNAL(clicked()), exitAction, SLOT(trigger()));
connect(ui.pushButton_minimize, SIGNAL(clicked()), minimizeAction, SLOT(trigger()));
connect(ui.checkBox_hideIcon, SIGNAL(clicked(bool)), this, SLOT(toggleTrayIcon(bool)));
connect(ui.pushButton_connect, SIGNAL(clicked()), this, SLOT(connectPressed()));
connect(ui.pushButton_vpn_connect, SIGNAL(clicked()), this, SLOT(connectPressed()));
connect(ui.pushButton_disconnect, SIGNAL(clicked()), this, SLOT(disconnectPressed()));
connect(ui.pushButton_vpn_disconnect, SIGNAL(clicked()), this, SLOT(disconnectPressed()));
connect(ui.pushButton_remove, SIGNAL(clicked()), this, SLOT(removePressed()));
connect(ui.pushButton_aboutCMST, SIGNAL(clicked()), this, SLOT(aboutCMST()));
connect(ui.pushButton_aboutIconSet, SIGNAL(clicked()), this, SLOT(aboutIconSet()));
connect(ui.pushButton_aboutOtherArt, SIGNAL(clicked()), this, SLOT(aboutOtherArt()));
connect(ui.pushButton_aboutQT, SIGNAL(clicked()), qApp, SLOT(aboutQt()));
connect(qApp, SIGNAL(aboutToQuit()), this, SLOT(cleanUp()));
connect(ui.pushButton_license, SIGNAL(clicked()), this, SLOT(showLicense()));
connect(ui.pushButton_change_log, SIGNAL(clicked()), this, SLOT(showChangeLog()));
connect(ui.tableWidget_services, SIGNAL (cellClicked(int, int)), this, SLOT(enableMoveButtons(int, int)));
connect(ui.checkBox_hidecnxn, SIGNAL (toggled(bool)), this, SLOT(updateDisplayWidgets()));
connect(ui.checkBox_hidetethering, SIGNAL (toggled(bool)), this, SLOT(updateDisplayWidgets()));
connect(ui.checkBox_systemtraynotifications, SIGNAL (clicked(bool)), this, SLOT(trayNotifications(bool)));
connect(ui.checkBox_notifydaemon, SIGNAL (clicked(bool)), this, SLOT(daemonNotifications(bool)));
connect(ui.pushButton_configuration, SIGNAL (clicked()), this, SLOT(configureService()));
connect(ui.pushButton_provisioning_editor, SIGNAL (clicked()), this, SLOT(provisionService()));
connect(ui.pushButton_vpn_editor, SIGNAL (clicked()), this, SLOT(provisionService()));
connect(socketserver, SIGNAL(newConnection()), this, SLOT(socketConnectionDetected()));
connect(ui.checkBox_runonstartup, SIGNAL(toggled(bool)), this, SLOT(enableRunOnStartup(bool)));
connect(ui.toolButton_colorize, SIGNAL(clicked()), this, SLOT(callColorDialog()));
connect(ui.lineEdit_colorize, SIGNAL(textChanged(const QString&)), this, SLOT(iconColorChanged(const QString&)));
connect(ui.checkBox_enablesystemtraytooltips, SIGNAL(clicked()), this, SLOT(updateDisplayWidgets()));
connect(ui.pushButton_IDPass, SIGNAL(clicked()), this, SLOT(wifiIDPass()));
// Install an event filter on all child widgets. Used to control
// tooltip visibility
QList<QWidget*> childlist = ui.tabWidget->findChildren<QWidget*>();
for (int i = 0; i < childlist.count(); ++i) {
childlist.at(i)->installEventFilter(this);
}
// Tray icon - disable it if we specifiy that option on the commandline or in
// the settings, otherwise set a singleshot timer to create the tray icon.
if (parser.isSet("disable-tray-icon") ? true : (b_so && ui.checkBox_disabletrayicon->isChecked()) ) {
trayicon = NULL;
ui.checkBox_hideIcon->setDisabled(true);
this->updateDisplayWidgets();
qApp->setQuitOnLastWindowClosed(true); // not running systemtray icon so normal close
this->showNormal(); // no place to minimize to, so showMaximized
} // if
else {
const short mintrigger = 100; // Minimum time (milliseconds) to wait before starting the tray icon. We advertise zero, but not really.
int timeout = 0;
if (parser.isSet("wait-time") ) {
bool ok;
timeout = parser.value("wait-time").toInt(&ok, 10);
if (! ok) timeout = 0;
} // if parser set
else if (b_so && ui.checkBox_waittime->isChecked() ) {
timeout = ui.spinBox_waittime->value();
}
timeout *= 1000;
if (timeout < mintrigger) timeout = mintrigger;
if (parser.isSet("minimized") ? true : (b_so && ui.checkBox_startminimized->isChecked()) ) {
QTimer::singleShot(timeout, this, SLOT(createSystemTrayIcon()) );
} // if showMinimized
else {
this->showNormal();
QTimer::singleShot(timeout, this, SLOT(createSystemTrayIcon()) );
} // else showNormal
} // else
}
////////////////////////////////////////////////// Public Functions //////////////////////////////////
////////////////////////////////////////////////// Public Slots //////////////////////////////////////
//
// slot to display an about box for this program
void ControlBox::aboutCMST()
{
QMessageBox::about(this, tr("About %1").arg(TranslateStrings::cmtr("cmst")),
tr("<center>%1 is a program to interface with the Connman daemon and to provide a system tray control."
"<br><center>Version <b>%2</b>"
"<center>Release date: %3"
"<center>Copyright c %4<center>by"
"<center>Andrew J. Bibb"
"<center>Vermont, USA"
"<br><center><b>Contributors:</b>"
"<center>Brett Dutro"
"<center>Adam Fontenot"
"<center>Lester Bico"
"<center>Yaohan Chen"
"<br><center><b>Translations:</b>"
"<center>Jianfeng Zhang (Chinese)"
"<center>sqozz (German)"
"<center>Ilya Shestopalov (Russian)"
"<br><center><b>Build Information:</b>"
"<center>Compiled using QT version %5"
/*"<center>Built %6 - %7"*/) .arg(TranslateStrings::cmtr("cmst"))
.arg(VERSION)
.arg(RELEASE_DATE)
.arg(COPYRIGHT_DATE)
.arg(QT_VERSION_STR)
/*.arg(__DATE__)
.arg(__TIME__)*/ );
}
//
// slot to display an about box for the icons we used
void ControlBox::aboutIconSet()
{
QMessageBox::about(this, tr("About AwOken"),
tr("<center>This program uses the <b>AwOken</b> icon set version 2.5"
"<br><br>Released under the"
"<br>Creative Commons"
"<br>Attribution-Share Alike 3.0"
"<br>Unported License"
"<br><a href=\"url\">http://creativecommons.org/licenses/by-sa/3.0/legalcode</a>"
) );
}
//
// slot to display an about box for the icons we used
void ControlBox::aboutOtherArt()
{
QMessageBox::about(this, tr("About Other Artwork"),
tr("<center>This program uses artwork from <b>Freepik</b> obtained from www.flaticon.com:"
"<br><br>Released under the Flaticon Basic License"
"<br><a href=\"url\">https://file000.flaticon.com/downloads/license/license.pdf</a>"
"<br><br><b>Artwork files:</b>"
"<li>radio.png</li>"
"<li>basic-plane.png</li>"
) );
}
//
// slot to display the program license
void ControlBox::showLicense()
{
QString s = readResourceText(":/text/text/license.txt");
if ( s.isEmpty() ) s.append(tr("%1 license is the MIT (Expat) license.").arg(TranslateStrings::cmtr("cmst")));
QMessageBox::about(this, tr("License"), s);
}
//
// slot to display the change log of the program
void ControlBox::showChangeLog()
{
QString s = readResourceText(":/text/text/changelog.txt");
if ( s.isEmpty() ) s.append(tr("%1 change log is not available.").arg(TranslateStrings::cmtr("cmst")));
ScrollBox::execScrollBox(tr("ChangeLog"), s, this);
}
////////////////////////////////////////////Private Slots ////////////////////////////////////////////
//
// Slot to update all of our display widgets
void ControlBox::updateDisplayWidgets()
{
// each assemble function will check q16_errors to make sure it can
// get the information it needs. Only check for major errors since we
// can't run the assemble functions if there are.
if ( ((q16_errors & CMST::Err_No_DBus) | (q16_errors & CMST::Err_Invalid_Con_Iface)) == 0x00 ) {
// rebuild our pages
this->assembleTabStatus();
this->assembleTabDetails();
this->assembleTabWireless();
this->assembleTabVPN();
this->assembleTabCounters();
if (trayicon != NULL ) this->assembleTrayIcon();
ui.pushButton_movebefore->setEnabled(false);
ui.pushButton_moveafter->setEnabled(false);
} // if there were no major errors
return;
}
//
// Slot to move the selected service before or after another service.
// Called when an item in mvsrv_menu is selected. QAction act is the
// action selected.
void ControlBox::moveService(QAction* act)
{
// See if act belongs to a service
QString ss;
QDBusObjectPath targetobj;
for (int i = 0; i < services_list.size(); ++i) {
ss = getNickName(services_list.at(i).objpath);
// the items in mvsrv_menu are in the same order as services_list
if (ss == act->text() ) {
targetobj = QDBusObjectPath(services_list.at(i).objpath.path());
break;
} // if
} // for
// make sure we got a targetobject, if not most likely cancel pressed
if (targetobj.path().isEmpty()) return;
// get enough information from tableWidget_services to identify the source object
QList<QTableWidgetItem*> list;
list.clear();
list = ui.tableWidget_services->selectedItems();
if (list.isEmpty() ) return;
// apply the movebefore or moveafter message to the source object
QDBusInterface* iface_serv = new QDBusInterface(DBUS_CON_SERVICE, services_list.at(list.at(0)->row()).objpath.path(), "net.connman.Service", QDBusConnection::systemBus(), this);
if (iface_serv->isValid() ) {
if (mvsrv_menu->title() == ui.actionMove_Before->text()) {
shared::processReply(iface_serv->call(QDBus::AutoDetect, "MoveBefore", QVariant::fromValue(targetobj)) );
}
else {
shared::processReply(iface_serv->call(QDBus::AutoDetect, "MoveAfter", QVariant::fromValue(targetobj)) );
} // else
} // iface_srv is valid
// clean up
iface_serv->deleteLater();
return;
}
//
// Slot called if the movebefore or moveafter button was pressed
void ControlBox::moveButtonPressed(QAction* act)
{
mvsrv_menu->setTitle(act->text());
mvsrv_menu->popup(QCursor::pos());
return;
}
//
// Slot to enable the movebefore and moveafter buttons, and to prepare the poupup menu
// Called when a cell is clicked in ui.tableWidget_services
void ControlBox::enableMoveButtons(int row, int col)
{
(void)col;
// variables
bool b_validsource = false;
bool b_validtarget = false;
// create the menu to show if a user selects one of the buttons
mvsrv_menu->clear();
for (int i = 0; i < services_list.size(); ++i) {
QAction* act = mvsrv_menu->addAction(getNickName(services_list.at(i).objpath) );
// inspect the service, can only move if service is favorite, ready or online
// vpn services can be moved (I was wrong thinking they could not), see https://01.org/jira/browse/CM-620
if (services_list.at(i).objmap.value("Favorite").toBool() &&
(services_list.at(i).objmap.value("State").toString() == "online" || services_list.at(i).objmap.value("State").toString() == "ready") ) {
if (i == row) {
act->setDisabled(true); // can't move onto itself
b_validsource = true;
}
else {
act->setEnabled(true);
b_validtarget = true;
} // else
} // if
else
act->setDisabled(true);
} // for
// add a cancel option
mvsrv_menu->addSeparator();
mvsrv_menu->addAction(tr("Cancel"));
// enable the buttons if source and target both valid
ui.pushButton_movebefore->setEnabled(b_validsource && b_validtarget);
ui.pushButton_moveafter->setEnabled(b_validsource && b_validtarget);
return;
}
//
// Slot to update the service label when this->counter is updated. Other labels in page 4 receive signals directly
void ControlBox::counterUpdated(const QDBusObjectPath& qdb_objpath, const QString& home_label, const QString& roam_label)
{
// Don't update the counter if qdb_objpath is not the online service
if (! qdb_objpath.path().contains(onlineobjectpath) ) return;
// Set the labels in page 4
if (! qdb_objpath.path().isEmpty() ) {
QMap<QString,QVariant> map;
for (int i =0; i < services_list.size(); ++i) {
if (services_list.at(i).objpath == qdb_objpath) {
map = services_list.at(i).objmap;
break;
} // if
} // for
ui.label_counter_service_name->setText(tr("<b>Service:</b> %1").arg(getNickName(qdb_objpath)) );
ui.label_home_counter->setText(home_label);
ui.label_roam_counter->setText(roam_label);
}
else
ui.label_counter_service_name->setText(tr("<b>Service:</b> %1").arg(tr("Unable to determine service")) );
return;
}
//
// Slot to connect a wifi or vpn service. Called when ui.pushButton_connect
// or ui.pushButton_vpn_connect is pressed.
// For VPN's this connects the service, not the vpnconnection. It appears that connman_vpn takes
// the vpnconnections and creates one service for each. The vpnconnection part could be connected by
// using vpn connection interface, but not really worth it since connman automatically creates a
// a service for us.
void ControlBox::connectPressed()
{
// Process wifi or vpn depending on who sent the signal
QTableWidget* qtw = NULL;
if (sender() == ui.pushButton_connect) qtw = ui.tableWidget_wifi;
else if (sender() == ui.pushButton_vpn_connect) qtw = ui.tableWidget_vpn;
else return;
// If there is only one row select it
if (qtw->rowCount() == 1 ) {
QTableWidgetSelectionRange qtwsr = QTableWidgetSelectionRange(0, 0, 0, qtw->columnCount() - 1);
qtw->setRangeSelected(qtwsr, true);
}
// If no row is selected then return(
QList<QTableWidgetItem*> list;
list.clear();
list = qtw->selectedItems();
if (list.isEmpty() ) {
QMessageBox::information(this, tr("No Services Selected"),
tr("You need to select a service before pressing the connect button.") );
return;
}
// send the connect message to the service. TableWidget only allows single selection so list can only have 0 or 1 elments
QDBusInterface* iface_serv = NULL;
if (qtw == ui.tableWidget_wifi) {
iface_serv = new QDBusInterface(DBUS_CON_SERVICE, wifi_list.at(list.at(0)->row()).objpath.path(), "net.connman.Service", QDBusConnection::systemBus(), this);
iface_serv->setTimeout(5);
}
else if (qtw == ui.tableWidget_vpn) {
iface_serv = new QDBusInterface(DBUS_CON_SERVICE, vpn_list.at(list.at(0)->row()).objpath.path(), "net.connman.Service", QDBusConnection::systemBus(), this);
}
else return; // really not needed
iface_serv->setTimeout(5); // need a short timeout to get the Agent
QDBusMessage reply = iface_serv->call(QDBus::AutoDetect, "Connect");
if (reply.errorName() != "org.freedesktop.DBus.Error.NoReply") shared::processReply(reply);
iface_serv->deleteLater();
return;
}
//
// Slot to disconnect a wifi or VPN service. Called when ui.pushButton_disconnect
// or ui.pushBotton_vpn_disconnect is pressed
void ControlBox::disconnectPressed()
{
// Process wifi or vpn depending on who sent the signal
QTableWidget* qtw = NULL;
if (sender() == ui.pushButton_disconnect) qtw = ui.tableWidget_wifi;
else if (sender() == ui.pushButton_vpn_disconnect) qtw = ui.tableWidget_vpn;
else return;
// If there is no item is selected run through the list looking for
// services in "online" or "ready" state. If more than one is found
// break as we will have to use the one currently selected.
int cntr_connected = 0;
int row_connected = -1;
if (qtw->selectedItems().isEmpty() ) {
int itemcount = 0;
QMap<QString,QVariant> map;
if (qtw == ui.tableWidget_wifi) itemcount = wifi_list.size();
else if (qtw == ui.tableWidget_vpn) itemcount = vpn_list.size();
else return; // line is not really needed
for (int row = 0; row < itemcount; ++row) {
if (qtw == ui.tableWidget_wifi) map = wifi_list.at(row).objmap;
else if (qtw == ui.tableWidget_vpn) map = vpn_list.at(row).objmap;
else return; // line is not really needed
if (map.value("State").toString() == "online" || map.value("State").toString() == "ready" ) {
++cntr_connected;
row_connected = row;
}
if (cntr_connected > 1 ) break;
} // for
// Nothing selected, online or ready so return now
if (cntr_connected == 0) return;
// If only one entry is connected or online, select it
if (cntr_connected == 1 ) {
QTableWidgetSelectionRange qtwsr = QTableWidgetSelectionRange(row_connected, 0, row_connected, qtw->columnCount() - 1);
qtw->setRangeSelected(qtwsr, true);
} // cntr_connected == 1
} // if there are no currently selected items
// If no row selected return
QList<QTableWidgetItem*> list;
list.clear();
list = qtw->selectedItems();
if (list.isEmpty() ) {
QMessageBox::information(this, tr("No Services Selected"),
tr("You need to select a service before pressing the disconnect button.") );
return;
}
// Send the disconnect message to the service. TableWidget only allows single selection so list can only have 0 or 1 elments
QDBusInterface* iface_serv = NULL;
if (qtw == ui.tableWidget_wifi)
iface_serv = new QDBusInterface(DBUS_CON_SERVICE, wifi_list.at(list.at(0)->row()).objpath.path(), "net.connman.Service", QDBusConnection::systemBus(), this);
else if (qtw == ui.tableWidget_vpn)
iface_serv = new QDBusInterface(DBUS_CON_SERVICE, vpn_list.at(list.at(0)->row()).objpath.path(), "net.connman.Service", QDBusConnection::systemBus(), this);
else return; // this line really not needed
shared::processReply(iface_serv->call(QDBus::AutoDetect, "Disconnect") );
iface_serv->deleteLater();
return;
}
//
// Slot to remove (unset the Favorite property, clear passphrase if one exists) of a Wifi service
// Called when ui.pushButton_remove is pressed
void ControlBox::removePressed()
{
// if no row selected return
QList<QTableWidgetItem*> list;
list.clear();
list = ui.tableWidget_wifi->selectedItems();
if (list.isEmpty() ) {
QMessageBox::information(this, tr("No Services Selected"),
tr("You need to select a Wifi service before pressing the remove button.") );
return;
}
// send the Remove message to the service
QDBusInterface* iface_serv = new QDBusInterface(DBUS_CON_SERVICE, wifi_list.at(list.at(0)->row()).objpath.path(), "net.connman.Service", QDBusConnection::systemBus(), this);
QDBusMessage reply = iface_serv->call(QDBus::AutoDetect, "Remove");
shared::processReply(reply);
iface_serv->deleteLater();
return;
}
// dbs slots are slots to receive DBus Signals
//
// Slot called whenever DBUS issues a PropertyChanged signal
void ControlBox::dbsPropertyChanged(QString prop, QDBusVariant dbvalue)
{
// save current state and update propertiesMap
QString oldstate = properties_map.value(prop).toString();
properties_map.insert(prop, dbvalue.variant() );
// refresh display widgets
updateDisplayWidgets();
// offlinemode property
if (prop == "OfflineMode") {
notifyclient->init();
if (dbvalue.variant().toBool()) {
notifyclient->setSummary(tr("Offline Mode Engaged"));
notifyclient->setIcon(iconman->getIconName("offline_mode_engaged") );
notifyclient->setBody(tr("All network devices are powered off, now in Airplane mode.") );
}
else {
notifyclient->setSummary(tr("Offline Mode Disabled"));
notifyclient->setIcon(iconman->getIconName("offline_mode_disengaged") );
notifyclient->setBody(tr("Power has been restored to all previously powered network devices.") );
}
this->sendNotifications();
} // if contains offlinemode
// state property
if (prop == "State") {
// local variables
QString state = dbvalue.variant().toString();
// send notification if state is not ready or online
notifyclient->init();
notifyclient->setSummary(tr("Network Services:") );
if (state == "ready" || state == "online") {
if (oldstate != "ready" && oldstate != "online") {
notifyclient->setBody(tr("The system is online.") );
notifyclient->setIcon(iconman->getIconName("state_online") );
this->sendNotifications();
} // if
} // if
else {
notifyclient->setBody(tr("The system is offline.") );
notifyclient->setIcon(iconman->getIconName("state_not_ready") );
this->sendNotifications();
} // else
// execute external program if specified
if (! ui.lineEdit_afterconnect->text().isEmpty() ) {
if( (state == "ready" || state == "online") &&
(oldstate != "ready" && oldstate != "online") ) {
QString text = ui.lineEdit_afterconnect->text();
text = text.simplified();
QStringList args = text.split(' ');
QString cmd = args.first();
args.removeFirst();
QProcess* proc = new QProcess(this);
proc->startDetached(cmd, args);
} // if online or ready and not online before
} // if lineedit not empty
} // if state change
return;
}
//
// Slot called whenever DBUS issues a ServicesChanged signal. When a
// Scan method is called on a technology the results of that scan are
// signaled through this slot. This is also called when the sort order
// of the services list changes. It will not be called when a property
// of a service object changes.
void ControlBox::dbsServicesChanged(QList<QVariant> vlist, QList<QDBusObjectPath> removed, QDBusMessage msg)
{
// process removed services
if (! removed.isEmpty() ) {
for (int i = 0; i < services_list.count(); ++i) {
if (removed.contains(services_list.at(i).objpath) ) {
QDBusConnection::systemBus().disconnect(DBUS_CON_SERVICE, services_list.at(i).objpath.path(), "net.connman.Service", "PropertyChanged", this, SLOT(dbsServicePropertyChanged(QString, QDBusVariant, QDBusMessage)));
services_list.removeAt(i);
} // if
} // for
} // if we needed to remove something
// process added or changed servcies
// Demarshall the raw QDBusMessage instead of vlist as it is easier..
if (! vlist.isEmpty() ) {
QList<arrayElement> revised_list;
if (! getArray(revised_list, msg)) return;
// merge the existing services_list into the revised_list
// first find the original element that matches the revised
for (int i = 0; i < revised_list.size(); ++i) {
arrayElement revised_element = revised_list.at(i);
arrayElement original_element = {QDBusObjectPath(), QMap<QString,QVariant>()};
for (int j = 0; j < services_list.size(); ++j) {
if (revised_element.objpath == services_list.at(j).objpath) {
original_element = services_list.at(j);
break;
} // if
} // j for
// merge the new elementArray into the existing
if (! original_element.objpath.path().isEmpty()) {
QMapIterator<QString, QVariant> itr(revised_element.objmap);
while (itr.hasNext()) {
itr.next();
original_element.objmap.insert(itr.key(), itr.value() );
} // while
// now insert the element into the revised list
QDBusConnection::systemBus().disconnect(DBUS_CON_SERVICE, original_element.objpath.path(), "net.connman.Service", "PropertyChanged", this, SLOT(dbsServicePropertyChanged(QString, QDBusVariant, QDBusMessage)));
revised_list.replace(i, original_element);
QDBusConnection::systemBus().connect(DBUS_CON_SERVICE, revised_element.objpath.path(), "net.connman.Service", "PropertyChanged", this, SLOT(dbsServicePropertyChanged(QString, QDBusVariant, QDBusMessage)));
} // if original element is not empty
} // i for
// now copy the revised list to services_list
services_list.clear();
services_list = revised_list;
} // revised_list not empty
// clear the counters (if selected) and update the widgets
clearCounters();
// update the widgets
updateDisplayWidgets();
return;
}
//
// Slot called whenever DBUS issues a Peerschanged signal. See note above about
// scan results being signaled here.
void ControlBox::dbsPeersChanged(QList<QVariant> vlist, QList<QDBusObjectPath> removed, QDBusMessage msg)
{
// Set the update flag
bool b_needupdate = false;
// Process changed peers. Demarshal the raw QDBusMessage instead of vlist as it is easier.
if (! vlist.isEmpty() ) {
QList<arrayElement> revised_list;
if (! getArray(revised_list, msg)) return;
// if revised_list is not the same size as the existing peer_list
// then we definetely need an update
if (revised_list.count() != peer_list.count() ) b_needupdate = true;
// merge the existing peers_list into the revised_list
// first find the original element that matches the revised
for (int i = 0; i < revised_list.size(); ++i) {
arrayElement revised_element = revised_list.at(i);
arrayElement original_element = {QDBusObjectPath(), QMap<QString,QVariant>()};
for (int j = 0; j < peer_list.size(); ++j) {
if (revised_element.objpath == peer_list.at(j).objpath) {
original_element = peer_list.at(j);
break;
} // if
} // j for
// merge the new elementArray into the existing
if (! original_element.objpath.path().isEmpty()) {
QMapIterator<QString, QVariant> itr(revised_element.objmap);
while (itr.hasNext()) {
itr.next();
b_needupdate = true;
original_element.objmap.insert(itr.key(), itr.value() );
} // while
// now insert the element into the revised list
revised_list.replace(i, original_element);
} // if original element exists
} // i for
// now copy the revised list to peer_list
peer_list.clear();
peer_list = revised_list;
} // vlist not empty
// process removed peers
if (! removed.isEmpty() ) {
for (int i = 0; i < peer_list.count(); ++i) {
if (removed.contains(peer_list.at(i).objpath) )
peer_list.removeAt(i);
} // for
} // if we needed to remove something
// update the widgets
if (b_needupdate) updateDisplayWidgets();
return;
}
//
// Slot called whenever DBUS issues a TechonlogyAdded signal
// There must be an internal counter for technologies, first time a
// technology is changed we get a signal even if we've already run
// getTechnologies. After that first time we never get this signal.
// Use this this to catch real additions, which we defined as something
// we don't already have from getTechnologies.
void ControlBox::dbsTechnologyAdded(QDBusObjectPath path, QVariantMap properties)
{
// iterate over the properties map and replace connman text with translated text
QMapIterator<QString, QVariant> itr(properties);
while (itr.hasNext()) {
itr.next();
properties.insert(itr.key(), itr.value() );
} // map iterator
// construct an arrayElement
arrayElement ae = {path, properties};
bool newelem = true;
// first see if the element exists, if so replace it
for (int i = 0; i < technologies_list.count(); ++i) {
if (path == technologies_list.at(i).objpath) {
technologies_list.replace(i, ae);
newelem = false;
break;
} // if
} // for
// if it is a new element add it
if (newelem) {
technologies_list.append(ae);
}
updateDisplayWidgets();
return;
}
//
// Slot called whenever DBUS issues a TechonlogyAdded signal
void ControlBox::dbsTechnologyRemoved(QDBusObjectPath removed)
{
for (int i = 0; i < technologies_list.count(); ++i) {
if ( removed == technologies_list.at(i).objpath ) {
technologies_list.removeAt(i);
break;
} // if
} // for
updateDisplayWidgets();
return;
}
//
// Slots called from objects. The previous slots were called from Manager
//
// Slot called whenever a service object issues a PropertyChanged signal on DBUS
void ControlBox::dbsServicePropertyChanged(QString property, QDBusVariant dbvalue, QDBusMessage msg)
{
QString s_path = msg.path();
QVariant value = dbvalue.variant();
QString s_state;
// replace the old values with the changed ones.
for (int i = 0; i < services_list.count(); ++i) {
if (s_path == services_list.at(i).objpath.path() ) {
QMap<QString,QVariant> map = services_list.at(i).objmap;
map.remove(property);
map.insert(property, value );
arrayElement ae = {services_list.at(i).objpath, map};
services_list.replace(i, ae);
s_state = map.value("State").toString();
break;
} // if
} // for
// process errrors - errors only valid when service is in the failure state
if (property =="Error" && s_state == "failure") {
notifyclient->init();
notifyclient->setSummary(QString(tr("Service Error: %1")).arg(value.toString()) );
notifyclient->setBody(QString(tr("Object Path: %1")).arg(s_path) );
notifyclient->setIcon(iconman->getIconName("state_error") );
notifyclient->setUrgency(Nc::UrgencyCritical);
this->sendNotifications();
}
// if state property changed sync the online data members.
if (property == "State") {
if (value.toString() == "online") {
onlineobjectpath = s_path;
} //
else if (s_path == onlineobjectpath) {
onlineobjectpath.clear();
} // else if object went offline
// Send notification if vpn changed
for (int i = 0; i < vpn_list.count(); ++i) {
if (s_path == vpn_list.at(i).objpath.path() ) {
notifyclient->init();
if (value.toString() == "ready") {
notifyclient->setSummary(QString(tr("VPN Engaged")) );
notifyclient->setIcon(iconman->getIconName("connection_vpn") );
}
else {
notifyclient->setSummary(QString(tr("VPN Disengaged")) );
notifyclient->setIcon(iconman->getIconName("onnection_not_ready") );
}
notifyclient->setBody(QString(tr("Object Path: %1")).arg(s_path) );
notifyclient->setUrgency(Nc::UrgencyNormal);
this->sendNotifications();
break;
} // if
} // for
} // if property contains State
// update the widgets
updateDisplayWidgets();
return;
}
//
// Slot called whenever a technology object issues a PropertyChanged signal on DBUS
void ControlBox::dbsTechnologyPropertyChanged(QString name, QDBusVariant dbvalue, QDBusMessage msg)
{
QString s_path = msg.path();
// replace the old values with the changed ones.
for (int i = 0; i < technologies_list.count(); ++i) {
if (s_path == technologies_list.at(i).objpath.path() ) {
QMap<QString,QVariant> map = technologies_list.at(i).objmap;
map.remove(name);
map.insert(name, dbvalue.variant() );
arrayElement ae = {technologies_list.at(i).objpath, map};
technologies_list.replace(i, ae);
break;
} // if
} // for
updateDisplayWidgets();
return;
}
// Slot to rescan all WiFi technologies. Called when ui.actionRescan
// is triggered. Action is called from rescanwifi buttons and from
// the context menu.
// Results signaled by manager.ServicesChanged(), except for peer
// services which will be signaled by manager.PeersChanged()
void ControlBox::scanWiFi()
{
// Make sure we got the technologies_list before we try to work with it.
if ( (q16_errors & CMST::Err_Technologies) != 0x00 ) return;
// Run through each technology and do a scan for any wifi
for (int row = 0; row < technologies_list.size(); ++row) {
if (technologies_list.at(row).objmap.value("Type").toString() == "wifi") {
if (technologies_list.at(row).objmap.value("Powered").toBool() ) {
setStateRescan(false);
ui.tableWidget_services->setCurrentIndex(QModelIndex()); // first cell becomes selected once pushbutton is disabled
qApp->processEvents(); // needed to promply disable the button
QDBusInterface* iface_tech = new QDBusInterface(DBUS_CON_SERVICE, technologies_list.at(row).objpath.path(), "net.connman.Technology", QDBusConnection::systemBus(), this);
iface_tech->setTimeout( 8 * 1000); // full 25 second timeout is a bit much when there is a problem
QDBusMessage reply = iface_tech->call(QDBus::AutoDetect, "Scan");
iface_tech->deleteLater();
} // if the wifi was powered
} // if the list item is wifi
} // for
return;
}
// Slot to loop through all WiFi technologies and set or reset the
// id and password. Called from the ui.pushButton_IDPass and from
// toggleTethered().
void ControlBox::wifiIDPass(const QString& obj_path)
{
// Make sure we got the technologies_list before we try to work with it.
if ( (q16_errors & CMST::Err_Technologies) != 0x00 ) return;
// Run through each technology looking for Wifi
for (int row = 0; row < technologies_list.size(); ++row) {
if (technologies_list.at(row).objmap.value("Type").toString() == "wifi") {
if (technologies_list.at(row).objpath.path() == obj_path || obj_path.isEmpty() ) {
QDBusInterface* iface_tech = new QDBusInterface(DBUS_CON_SERVICE, technologies_list.at(row).objpath.path(), "net.connman.Technology", QDBusConnection::systemBus(), this);
shared::ValidatingDialog* vd01 = new shared::ValidatingDialog(this);
vd01->setLabel(tr("<b>Technology: %1</b><p>Please enter the WiFi AP SSID that clients will<br>have to join in order to gain internet connectivity.").arg(technologies_list.at(row).objpath.path()) ),
vd01->setValidator(CMST::ValDialog_min1ch);
vd01->setText(technologies_list.at(row).objmap.value("TetheringIdentifier").toString() );
if (vd01->exec() == QDialog::Accepted) {
if (vd01->getText() != technologies_list.at(row).objmap.value("TetheringIdentifier").toString()) {
shared::processReply(iface_tech->call(QDBus::AutoDetect, "SetProperty", "TetheringIdentifier", QVariant::fromValue(QDBusVariant(vd01->getText()))) );
}
} // if accepted
vd01->deleteLater();
if (! technologies_list.at(row).objmap.value("TetheringIdentifier").toString().isEmpty() ) {
shared::ValidatingDialog* vd02 = new shared::ValidatingDialog(this);
vd02->setLabel(tr("<b>Technology: %1</b><p>Please enter the WPA pre-shared key clients will<br>have to use in order to establish a connection.<p>PSK length: minimum of 8 characters.").arg(technologies_list.at(row).objpath.path()) );
vd02->setValidator(CMST::ValDialog_min8ch);
vd02->setText(technologies_list.at(row).objmap.value("TetheringPassphrase").toString() );
if (vd02->exec() == QDialog::Accepted)
if (vd02->getText() != technologies_list.at(row).objmap.value("TetheringPassphrase").toString() )
shared::processReply(iface_tech->call(QDBus::AutoDetect, "SetProperty", "TetheringPassphrase", QVariant::fromValue(QDBusVariant(vd02->getText()))) );
vd02->deleteLater();
} // if
// cleanup
iface_tech->deleteLater();
} // if wifi match
} // if tech is wifi
} // for
return;
}
//
// Slot to globally turn power off to all network adapters
// Called when ui.checkBox_devicesoff or ui.toolButton_offlinemode is clicked
void ControlBox::toggleOfflineMode(bool checked)
{
if ( ((q16_errors & CMST::Err_No_DBus) | (q16_errors & CMST::Err_Invalid_Con_Iface)) != 0x00 ) return;
shared::processReply(con_manager->call(QDBus::AutoDetect, "SetProperty", "OfflineMode", QVariant::fromValue(QDBusVariant(checked ? true : false))) );
return;
}
//
// Slot to toggle the visibility of the tray icon
// Called when ui.checkBox_hideIcon is clicked
void ControlBox::toggleTrayIcon(bool b_checked)
{
if (trayicon != NULL ) {
if (b_checked) {
trayicon->setVisible(false);
ui.pushButton_minimize->setDisabled(true);
} // if
else {
trayicon->setVisible(true);
ui.pushButton_minimize->setDisabled(false);
} // else
} //if
return;
}
//
// Slot to toggle the powered state of a technology
// Called when our custom idButton in the powered cell in the page 1 technology tableWidget is clicked
void ControlBox::togglePowered(QString object_id, bool checkstate)
{
QDBusInterface* iface_tech = new QDBusInterface(DBUS_CON_SERVICE, object_id, "net.connman.Technology", QDBusConnection::systemBus(), this);
shared::processReply(iface_tech->call(QDBus::AutoDetect, "SetProperty", "Powered", QVariant::fromValue(QDBusVariant(checkstate))) );
// cleanup
iface_tech->deleteLater();
return;
}
//
// Slot to toggle the tethering state of a technology
// Called when our custom idButton in the tethered cell in the page 1 technology tableWidget is clicked
void ControlBox::toggleTethered(QString object_id, bool checkstate)
{
QDBusInterface* iface_tech = new QDBusInterface(DBUS_CON_SERVICE, object_id, "net.connman.Technology", QDBusConnection::systemBus(), this);
// See if this is a wifi technology, get the ID and Pass if necessary
bool ok = true;
for (int row = 0; row < technologies_list.size(); ++row) {
if (technologies_list.at(row).objpath.path() == object_id) {
if(technologies_list.at(row).objmap.value("Type").toString() == "wifi") {
QString sid = technologies_list.at(row).objmap.value("TetheringIdentifier").toString();
QString spw = technologies_list.at(row).objmap.value("TetheringPassphrase").toString();
if (sid.isEmpty() || spw.isEmpty() ) wifiIDPass(object_id);
} // if technology is wifi
} // if object_id
} // for
// Send message if everything is ok
if (ok) {
shared::processReply(iface_tech->call(QDBus::AutoDetect, "SetProperty", "Tethering", QVariant::fromValue(QDBusVariant(checkstate))) );
}
// cleanup
iface_tech->deleteLater();
return;
}
//
// Slot to minimize the input window. QWidget.hide() if the tray icon
// is visible, QWidget.showMinmized() if the tray icon is not visible.
// Do it this way as otherwise there is no way to get the dialog back if
// the tray icon is not shown.
// called when actionMinimize is activated
void ControlBox::minMaxWindow(QAction* act)
{
if (act == minimizeAction ) {
this->writeSettings();
if (trayicon != NULL ) trayicon->isVisible() ? this->hide() : this->showMinimized();
else this->showMinimized();
} // if minimizeAction
else if (act == maximizeAction) {
this->showNormal();
}
// Called from the systemtrayicon context menu. Actions are
// created dynamically and we don't know them up front. Actions here
// we want to open the details page and set the combo box to display
// information on the service.
else {
ui.tabWidget->setCurrentIndex(1);
ui.comboBox_service->setCurrentIndex(ui.comboBox_service->findText(act->text()) );
this->showNormal();
}
return;
}
//
// Called from the systemtrayicon context menu. Actions are
// created dynamically and we don't know them up front. Actions here
// are to power and unpower technologies
void ControlBox::techSubmenuTriggered(QAction* act)
{
// find the techology associated with the action and toggle its powered state
for (int i = 0; i < technologies_list.count(); ++i) {
if (technologies_list.at(i).objmap.value("Name").toString() == act->text() ) {
togglePowered(technologies_list.at(i).objpath.path(), act->isChecked() );
break;
} // if
} // for
return;
}
//
// Called from the systemtrayicon context menu. Actions are
// created dynamically and we don't know them up front. Actions here
// we want to open the details page and set the combo box to display
// information on the service.
void ControlBox::infoSubmenuTriggered(QAction* act)
{
ui.tabWidget->setCurrentIndex(1);
ui.comboBox_service->setCurrentIndex(ui.comboBox_service->findText(act->text()) );
this->showNormal();
return;
}
//
// Called from the systemtrayicon context menu. Actions are
// created dynamically and we don't know them up front. Actions here
// connect to a wifi service.
void ControlBox::wifiSubmenuTriggered(QAction* act)
{
// find the wifi service associated with the action.
for (int i = 0; i < wifi_list.count(); ++i) {
if (getNickName(wifi_list.at(i).objpath) == act->text() ) {
QDBusInterface* iface_serv = new QDBusInterface(DBUS_CON_SERVICE, wifi_list.at(i).objpath.path(), "net.connman.Service", QDBusConnection::systemBus(), this);
QString state = wifi_list.at(i).objmap.value("State").toString();
if (state == "online" || state == "ready") {
shared::processReply(iface_serv->call(QDBus::AutoDetect, "Disconnect") );
}
else {
iface_serv->setTimeout(5);
QDBusMessage reply = iface_serv->call(QDBus::AutoDetect, "Connect");
if (reply.errorName() != "org.freedesktop.DBus.Error.NoReply") shared::processReply(reply);
}
iface_serv->deleteLater();
break;
} // if
} // for
return;
}
//
// Called from the systemtrayicon context menu. Actions are created
// dynamically and we don't know them up front. Actions here connect
// to a VPN service.
void ControlBox::vpnSubmenuTriggered(QAction* act)
{
// find the VPN service associated with the action
for (int i = 0; i < vpn_list.count(); ++i) {
if (getNickName(vpn_list.at(i).objpath) == act->text() ) {
QDBusInterface* iface_serv = new QDBusInterface(DBUS_CON_SERVICE, vpn_list.at(i).objpath.path(), "net.connman.Service", QDBusConnection::systemBus(), this);
iface_serv->setTimeout(5);
QString state = vpn_list.at(i).objmap.value("State").toString();
QDBusMessage reply;
if (state == "ready")
reply = iface_serv->call(QDBus::AutoDetect, "Disconnect");
else
reply = iface_serv->call(QDBus::AutoDetect, "Connect" );
if (reply.errorName() != "org.freedesktop.DBus.Error.NoReply") shared::processReply(reply);
iface_serv->deleteLater();
break;
} // if
} // for
return;
}
//
// Slot to get details of the selected service and write it into ui.label_details
// Called when the ui.comboBox_services currentIndexChanged() signal is emitted.
void ControlBox::getServiceDetails(int index)
{
// Make sure we were sent a valid index, can happen if the comboBox is
// cleared and for whatever reason could not be reseeded with entries.
if (index < 0 ) return;
// variables
bool b_editable = services_list.size() > 0 ? true : false;
// Get the QMap associated with the index stored in an arrayElement
QMap<QString,QVariant> map = services_list.at(index).objmap;
// Some of the QVariants in the map are QMaps themselves, create a data structure for them
QMap<QString,QVariant> submap;
// Get a QFileInfo associated with the index and display the connection
QFileInfo fi = services_list.at(index).objpath.path();
ui.label_details_connection->setText(tr("<b>Connection:</b> %1").arg(fi.baseName()) );
// Start building the string for the left label
QString rs = tr("<br><b>Service Details:</b><br>");
if (getNickName(services_list.at(index).objpath).isEmpty() ) b_editable = false;
rs.append(tr("Service Type: %1<br>").arg(TranslateStrings::cmtr(map.value("Type").toString())) );
rs.append(tr("Service State: %1<br>").arg(TranslateStrings::cmtr(map.value("State").toString())) );
rs.append(tr("Favorite: %1<br>").arg(map.value("Favorite").toBool() ? tr("Yes", "favorite") : tr("No", "favorite")) );
rs.append(tr("External Configuration File: %1<br>").arg(map.value("Immutable").toBool() ? tr("Yes", "immutable") : tr("No", "immutable")) );
if (map.value("Immutable").toBool() ) b_editable = false;
rs.append(tr("Auto Connect: %1<br>").arg(map.value("AutoConnect").toBool() ? tr("On", "autoconnect") : tr("No", "autoconnect")) );
rs.append(tr("<br><b>IPv4</b><br>"));
shared::extractMapData(submap, services_list.at(index).objmap.value("IPv4") );
rs.append(tr("IP Address Acquisition: %1<br>").arg(TranslateStrings::cmtr(submap.value("Method").toString(), "connman ipv4 method string")) );
rs.append(tr("IP Address: %1<br>").arg(submap.value("Address").toString()));
rs.append(tr("IP Netmask: %1<br>").arg(submap.value("Netmask").toString()));
rs.append(tr("IP Gateway: %1<br>").arg(submap.value("Gateway").toString()));
rs.append(tr("<br><b>IPv6</b><br>"));
shared::extractMapData(submap, services_list.at(index).objmap.value("IPv6") );
rs.append(tr("Address Acquisition: %1<br>").arg(TranslateStrings::cmtr(submap.value("Method").toString(), "connman ipv6 method string")) );
rs.append(tr("IP Address: %1<br>").arg(submap.value("Address").toString()));
QString s_ipv6prefix = submap.value("PrefixLength").toString();
if (s_ipv6prefix.isEmpty() )
rs.append(tr("Prefix Length: <br>"));
else
rs.append(tr("Prefix Length: %1<br>").arg(submap.value("PrefixLength").toUInt()));
rs.append(tr("IP Gateway: %1<br>").arg(submap.value("Gateway").toString()));
rs.append(tr("Privacy: %1<br>").arg(TranslateStrings::cmtr(submap.value("Privacy").toString())) );
rs.append(tr("<br><b>Proxy</b><br>"));
shared::extractMapData(submap, services_list.at(index).objmap.value("Proxy") );
QString s_proxymethod = TranslateStrings::cmtr(submap.value("Method").toString(), "connman proxy string" );
rs.append(tr("Address Acquisition: %1<br>").arg(s_proxymethod) );
if (s_proxymethod == "auto" ) {
rs.append(tr("URL: %1<br>").arg(submap.value("URL").toString()) );
}
else if (s_proxymethod == "manual" ) {
rs.append(tr("Servers:<br>&nbsp;&nbsp;%1<br>").arg(submap.value("Servers").toStringList().join("<br>&nbsp;&nbsp;")) );
rs.append(tr("Excludes:<br>&nbsp;&nbsp;%1<br>").arg(submap.value("Excludes").toStringList().join("<br>&nbsp;&nbsp;")) );
}
// write the text to the left display label
ui.label_details_left->setText(rs);
// Start building the string for the right label
rs = tr("<br><b>Name Servers</b><br>");
rs.append(map.value("Nameservers").toStringList().join("<br>") );
rs.append(tr("<br><br><b>Time Servers</b><br> "));
rs.append(map.value("Timeservers").toStringList().join("<br>") );
rs.append(tr("<br><br><b>Search Domains</b><br> "));
rs.append(map.value("Domains").toStringList().join("<br>") );
rs.append(tr("<br><br><b>Ethernet</b><br>"));
shared::extractMapData(submap, services_list.at(index).objmap.value("Ethernet") );
rs.append(tr("Connection Method: %1<br>").arg(TranslateStrings::cmtr(submap.value("Method").toString(), "connman ethernet connection method")) );
rs.append(tr("Interface: %1<br>").arg(submap.value("Interface").toString()) );
rs.append(tr("Device Address: %1<br>").arg(submap.value("Address").toString()) );
rs.append(tr("MTU: %1<br>").arg(submap.value("MTU").value<quint16>()) );
rs.append(tr("<br><b>Wireless</b><br>"));
QStringList sl_tr;
for (int i = 0; i < map.value("Security").toStringList().size(); ++i) {
sl_tr << TranslateStrings::cmtr(map.value("Security").toStringList().at(i) );
} // for
rs.append(tr("Security: %1<br>").arg(sl_tr.join(',')) );
if (! map.value("Strength").toString().isEmpty() ) rs.append(tr("Strength: %1<br>").arg(map.value("Strength").value<quint8>()) );
rs.append(tr("Roaming: %1<br>").arg(map.value("Roaming").toBool() ? tr("Yes", "roaming") : tr("No", "roaming")) );
rs.append(tr("<br><b>VPN Provider</b><br>"));
shared::extractMapData(submap, services_list.at(index).objmap.value("Provider") );
rs.append(tr("Host: %1<br>").arg(submap.value("Host").toString()) );
rs.append(tr("Domain: %1<br>").arg(submap.value("Domain").toString()) );
rs.append(tr("Name: %1<br>").arg(submap.value("Name").toString()) );
rs.append(tr("Type: %1<br>").arg(submap.value("Type").toString()) );
// write the text to the right display label
ui.label_details_right->setText(rs);
// enable or disable the editor button
ui.pushButton_configuration->setEnabled(b_editable);
return;
}
//
// Slot to enter whats this mode
// Called when the ui.toolButton_whatsthis clicked() signal is emitted
void ControlBox::showWhatsThis()
{
QWhatsThis::enterWhatsThisMode();
}
//////////////////////////////////////////// Protected Functions //////////////////////////////////
//
// Close events for this dialog. If there is a systemtray and it is visible
// then a close event will only minimize (for instance clicking the X in a
// window bar. If there is no system tray or there is one but it is not
// visible then close the program.
void ControlBox::closeEvent(QCloseEvent* e)
{
if (trayicon != NULL ) {
if (trayicon->isVisible() ){
this->hide();
e->ignore();
} // if visible
} // if there is a tray icon
else
e->accept();
return;
}
//
// Key event for this dialog. If escape is pressed, minimize instead of close if
// applicable.
void ControlBox::keyPressEvent(QKeyEvent* e)
{
if (e->key() == Qt::Key_Escape &&
trayicon != NULL &&
trayicon->isVisible()) {
this->hide();
return;
}
QDialog::keyPressEvent(e);
}
//
// Event filter used to filter out tooltip events if we don't want to see them
// in eventFilters return true eats the event, false passes on it.
bool ControlBox::eventFilter(QObject* obj, QEvent* evn)
{
(void) obj;
if (evn->type() == QEvent::ToolTip) {
if (ui.checkBox_enableinterfacetooltips->isChecked())
return false;
else
return true;
} // event is a tooltip
return false;
}
//////////////////////////////////////////// Private Functions ////////////////////////////////////
//
// Function to rescan connman properties, technologies and services
// Int return value is the errors encountered
// This function is now really misnamed. Originally we called it a lot, but now
// everything is dealt with using DBus signals so it is only called at startup
// as an initial scan.
int ControlBox::managerRescan(const int& srv)
{
if ( ((q16_errors & CMST::Err_No_DBus) | (q16_errors & CMST::Err_Invalid_Con_Iface)) == 0x00 ) {
// Reset the getXX errors, always a chance we could read them after
// a previous error. Don't actually believe it, but just in case.
q16_errors &= ~CMST::Err_Properties;
q16_errors &= ~CMST::Err_Technologies;
q16_errors &= ~CMST::Err_Services;
// Access connman.manager to retrieve the data
if (srv & CMST::Manager_Technologies) {
if (! getTechnologies() ) {
logErrors(CMST::Err_Technologies);
} // if
else {
// connect technology signals to slots
for (int i = 0; i < technologies_list.size(); ++i) {
QDBusConnection::systemBus().disconnect(DBUS_CON_SERVICE, technologies_list.at(i).objpath.path(), "net.connman.Technology", "PropertyChanged", this, SLOT(dbsTechnologyPropertyChanged(QString, QDBusVariant, QDBusMessage)));
QDBusConnection::systemBus().connect(DBUS_CON_SERVICE, technologies_list.at(i).objpath.path(), "net.connman.Technology", "PropertyChanged", this, SLOT(dbsTechnologyPropertyChanged(QString, QDBusVariant, QDBusMessage)));
} // for
} //else
} // if technolgies
if (srv & CMST::Manager_Services) {
if (! getServices() ) {
logErrors(CMST::Err_Services);
} // if
// connect service signals to slots
else {
for (int i = 0; i < services_list.size(); ++i) {
QDBusConnection::systemBus().disconnect(DBUS_CON_SERVICE, services_list.at(i).objpath.path(), "net.connman.Service", "PropertyChanged", this, SLOT(dbsServicePropertyChanged(QString, QDBusVariant, QDBusMessage)));
QDBusConnection::systemBus().connect(DBUS_CON_SERVICE, services_list.at(i).objpath.path(), "net.connman.Service", "PropertyChanged", this, SLOT(dbsServicePropertyChanged(QString, QDBusVariant, QDBusMessage)));
} // for
} // else
} // if services
if (srv & CMST::Manager_Properties) {
if (! getProperties() ) logErrors(CMST::Err_Properties);
}
} // if
return (q16_errors & CMST::Err_Properties) | (q16_errors & CMST::Err_Technologies) | (q16_errors & CMST::Err_Services);
}
//
// Function to assemble status tab of the dialog
void ControlBox::assembleTabStatus()
{
// Global Properties
if ( (q16_errors & CMST::Err_Properties) == 0x00 ) {
QString s1 = properties_map.value("State").toString();
if (s1 == "online") {
ui.label_state_pix->setPixmap(iconman->getIcon("state_online").pixmap(QSize(16,16)) );
} // if online
else {
if (s1 == "ready") {
ui.label_state_pix->setPixmap(iconman->getIcon("state_ready").pixmap(QSize(16,16)) );
} // if ready
else {
ui.label_state_pix->setPixmap(iconman->getIcon("state_not_ready").pixmap(QSize(16,16)) );
} // else any other state
} // else ready or any other state
s1 = TranslateStrings::cmtr(s1);
s1.prepend(tr("State: ") );
ui.label_state->setText(s1);
bool b1 = properties_map.value("OfflineMode").toBool();
QString s2 = QString();
if (b1) {
s2 = tr("Engaged");
ui.toolButton_offlinemode->setIcon(iconman->getIcon("offline_mode_engaged") );
} // if offline mode is engaged
else {
s2 = tr("Disabled");
ui.toolButton_offlinemode->setIcon(iconman->getIcon("offline_mode_disengaged") );
} // else offlinemode disabled
s2.prepend(tr("Offline Mode "));
ui.label_offlinemode->setText(s2);
} // properties if no error
// Technologies
if ( (q16_errors & CMST::Err_Technologies) == 0x00 ) {
QString st = QString();
bool bt;
ui.tableWidget_technologies->clearContents();
ui.tableWidget_technologies->setRowCount(technologies_list.size() );
ui.tableWidget_technologies->horizontalHeader()->setSectionResizeMode(2, QHeaderView::Fixed);
ui.tableWidget_technologies->horizontalHeader()->setSectionResizeMode(4, QHeaderView::Fixed);
if (ui.checkBox_hidetethering->isChecked() ) {
ui.tableWidget_technologies->hideColumn(4);
ui.tableWidget_technologies->hideColumn(5);
ui.pushButton_IDPass->setHidden(true);
}
else {
ui.tableWidget_technologies->showColumn(4);
ui.tableWidget_technologies->showColumn(5);
ui.pushButton_IDPass->setHidden(false);
}
for (int row = 0; row < technologies_list.size(); ++row) {
QTableWidgetItem* qtwi00 = new QTableWidgetItem();
st = technologies_list.at(row).objmap.value("Name").toString();
qtwi00->setText(TranslateStrings::cmtr(st) );
qtwi00->setTextAlignment(Qt::AlignCenter);
ui.tableWidget_technologies->setItem(row, 0, qtwi00) ;
QTableWidgetItem* qtwi01 = new QTableWidgetItem();
st = technologies_list.at(row).objmap.value("Type").toString();
qtwi01->setText(TranslateStrings::cmtr(st) );
qtwi01->setTextAlignment(Qt::AlignCenter);
ui.tableWidget_technologies->setItem(row, 1, qtwi01);
idButton* qpb02 = new idButton(this, technologies_list.at(row).objpath);
connect (qpb02, SIGNAL(clickedID(QString, bool)), this, SLOT(togglePowered(QString, bool)));
if (technologies_list.at(row).objmap.value("Powered").toBool()) {
qpb02->setText(tr("On", "powered") );
qpb02->setIcon(QPixmap(":/icons/images/interface/golfball_green.png"));
qpb02->setChecked(true);
}
else {
qpb02->setText(tr("Off", "powered") );
qpb02->setIcon(QPixmap(":/icons/images/interface/golfball_red.png"));
qpb02->setChecked(false);
}
ui.tableWidget_technologies->setCellWidget(row, 2, qpb02);
QTableWidgetItem* qtwi03 = new QTableWidgetItem();
bt = technologies_list.at(row).objmap.value("Connected").toBool();
qtwi03->setText( bt ? tr("Yes", "connected") : tr("No", "connected") );
qtwi03->setTextAlignment(Qt::AlignCenter);
ui.tableWidget_technologies->setItem(row, 3, qtwi03);
idButton* qpb04 = new idButton(this, technologies_list.at(row).objpath);
connect (qpb04, SIGNAL(clickedID(QString, bool)), this, SLOT(toggleTethered(QString, bool)));
if (technologies_list.at(row).objmap.value("Tethering").toBool()) {
qpb04->setText(tr("On", "tethering") );
qpb04->setIcon(QPixmap(":/icons/images/interface/golfball_green.png"));
qpb04->setChecked(true);
}
else {
qpb04->setText(tr("Off", "tethering") );
qpb04->setIcon(QPixmap(":/icons/images/interface/golfball_red.png"));
qpb04->setChecked(false);
if (technologies_list.at(row).objmap.value("Type").toString() == "ethernet")
qpb04->setDisabled(true);
else
qpb04->setEnabled(technologies_list.at(row).objmap.value("Powered").toBool() );
}
ui.tableWidget_technologies->setCellWidget(row, 4, qpb04);
QTableWidgetItem* qtwi05 = new QTableWidgetItem();
QString sid = technologies_list.at(row).objmap.value("TetheringIdentifier").toString();
QString spw = technologies_list.at(row).objmap.value("TetheringPassphrase").toString();
if (sid.isEmpty() ) sid = "--";
if (spw.isEmpty() ) spw = "--";
qtwi05->setText(QString("%1 : %2").arg(sid).arg(spw) );
qtwi05->setTextAlignment(Qt::AlignCenter);
ui.tableWidget_technologies->setItem(row, 5, qtwi05);
} // technologies for loop
// resize the columns to contents
ui.tableWidget_technologies->resizeColumnToContents(0);
ui.tableWidget_technologies->resizeColumnToContents(1);
ui.tableWidget_technologies->resizeColumnToContents(3);
} // technologies if no error
// Services
if ( (q16_errors & CMST::Err_Services) == 0x00 ) {
QString ss = QString();
ui.tableWidget_services->clearContents();
ui.tableWidget_services->setRowCount(services_list.size() );
if (ui.checkBox_hidecnxn->isChecked() ) {
ui.tableWidget_services->hideColumn(3);
}
else {
ui.tableWidget_services->showColumn(3);
ui.tableWidget_services->horizontalHeader()->resizeSection(1, ui.tableWidget_services->horizontalHeader()->defaultSectionSize());
}
for (int row = 0; row < services_list.size(); ++row) {
QTableWidgetItem* qtwi00 = new QTableWidgetItem();
ss = getNickName(services_list.at(row).objpath);
qtwi00->setText(TranslateStrings::cmtr(ss) );
qtwi00->setTextAlignment(Qt::AlignCenter);
ui.tableWidget_services->setItem(row, 0, qtwi00);
QTableWidgetItem* qtwi01 = new QTableWidgetItem();
ss = services_list.at(row).objmap.value("Type").toString();
qtwi01->setText(TranslateStrings::cmtr(ss) );
qtwi01->setTextAlignment(Qt::AlignCenter);
ui.tableWidget_services->setItem(row, 1, qtwi01);
QTableWidgetItem* qtwi02 = new QTableWidgetItem();
ss = services_list.at(row).objmap.value("State").toString();
qtwi02->setText(TranslateStrings::cmtr(ss) );
qtwi02->setTextAlignment(Qt::AlignCenter);
ui.tableWidget_services->setItem(row, 2, qtwi02);
QTableWidgetItem* qtwi03 = new QTableWidgetItem();
QFileInfo fi = services_list.at(row).objpath.path();
qtwi03->setText(fi.baseName() );
qtwi03->setTextAlignment(Qt::AlignVCenter|Qt::AlignLeft);
ui.tableWidget_services->setItem(row, 3, qtwi03);
} // services for loop
// resize the services columns to contents
ui.tableWidget_services->resizeColumnToContents(0);
ui.tableWidget_services->resizeColumnToContents(1);
ui.tableWidget_services->resizeColumnToContents(2);
} // services if no error
return;
}
//
// Function to assemble details tab of the dialog. Only fill in the
// ui.comboBox_service widget. The detail portion will be filled in
// by the getServiceDetails() slot whenever the comboBox index changes.
void ControlBox::assembleTabDetails()
{
// variables
int newidx = 0;
QString cursvc = QString();
// if the combobox has any items in it save the nick name of the service we are viewing
if (ui.comboBox_service->count() > 0)
cursvc = ui.comboBox_service->currentText();
// initilize the page2 display widgets
ui.comboBox_service->clear();
ui.label_details_left->clear();
ui.label_details_right->clear();
// services details
if ( (q16_errors & CMST::Err_Services) == 0x00 ) {
// populate the combobox
for (int row = 0; row < services_list.size(); ++row) {
QString ss = getNickName(services_list.at(row).objpath);
ui.comboBox_service->addItem(TranslateStrings::cmtr(ss) );
if (TranslateStrings::cmtr(ss) == cursvc)
newidx = row;
} // services for loop
ui.comboBox_service->setCurrentIndex(newidx);
} // services if no error
return;
}
//
// Function to assemble the wireless tab of the dialog.
void ControlBox::assembleTabWireless()
{
// initilize the table
ui.tableWidget_wifi->clearContents();
ui.tableWidget_wifi->setRowCount(0);
int rowcount = 0;
// Make sure we got the services_list before we try to work with it.
if ( (q16_errors & CMST::Err_Services) != 0x00 ) return;
// Run through the technologies again, this time only look for wifi
if ( (q16_errors & CMST::Err_Technologies) == 0x00 ) {
int i_wifidevices= 0;
int i_wifipowered = 0;
for (int row = 0; row < technologies_list.size(); ++row) {
if (technologies_list.at(row).objmap.value("Type").toString() == "wifi" ) {
++i_wifidevices;
if (technologies_list.at(row).objmap.value("Powered").toBool() ) ++i_wifipowered;
} // if census
} // for loop
ui.label_wifi_state->setText(tr(" WiFi Technologies:<br> %1 Found, %2 Powered").arg(i_wifidevices).arg(i_wifipowered) );
} // technologis if no errors
// Run through each service_list looking for wifi services
wifi_list.clear();
for (int row = 0; row < services_list.size(); ++row) {
QMap<QString,QVariant> map = services_list.at(row).objmap;
if (map.value("Type").toString() == "wifi") {
wifi_list.append(services_list.at(row));
ui.tableWidget_wifi->setRowCount(rowcount + 1);
QTableWidgetItem* qtwi00 = new QTableWidgetItem();
qtwi00->setText(getNickName(services_list.at(row).objpath) );
qtwi00->setTextAlignment(Qt::AlignCenter);
ui.tableWidget_wifi->setItem(rowcount, 0, qtwi00);
QLabel* ql01 = new QLabel(ui.tableWidget_wifi);
if (map.value("Favorite").toBool() ) {
ql01->setPixmap(iconman->getIcon("favorite").pixmap(QSize(16,16)) );
}
ql01->setAlignment(Qt::AlignCenter);
ui.tableWidget_wifi->setCellWidget(rowcount, 1, ql01);
QLabel* ql02 = new QLabel(ui.tableWidget_wifi);
if (map.value("State").toString() == "online") {
ql02->setPixmap(iconman->getIcon("state_online").pixmap(QSize(16,16)) );
} // if online
else {
if (map.value("State").toString() == "ready") {
ql02->setPixmap(iconman->getIcon("state_ready").pixmap(QSize(16,16)) );
} // if ready
else {
ql02->setPixmap(iconman->getIcon("wifi_tab_state_not_ready").pixmap(QSize(16,16)) );
} // else any other state
} // else ready or any other state
ql02->setAlignment(Qt::AlignCenter);
ql02->setToolTip(TranslateStrings::cmtr(map.value("State").toString()) );
ql02->installEventFilter(this);
ui.tableWidget_wifi->setCellWidget(rowcount, 2, ql02);
QTableWidgetItem* qtwi03 = new QTableWidgetItem();
QStringList sl_tr;
for (int i = 0; i < map.value("Security").toStringList().size(); ++i) {
sl_tr << TranslateStrings::cmtr(map.value("Security").toStringList().at(i) );
} // for
qtwi03->setText(sl_tr.join(',') );
qtwi03->setTextAlignment(Qt::AlignCenter);
ui.tableWidget_wifi->setItem(rowcount, 3, qtwi03);
QProgressBar* pb04 = new QProgressBar(ui.tableWidget_wifi);
pb04->setMinimum(0);
pb04->setMaximum(100);
pb04->setOrientation( Qt::Horizontal);
pb04->setValue(map.value("Strength").value<quint8>() );
if (QColor(ui.lineEdit_colorize->text()).isValid() ) {
QPalette pl = pb04->palette();
pl.setColor(QPalette::Active, QPalette::Highlight, QColor(ui.lineEdit_colorize->text()) );
pb04->setPalette(pl);
}
QWidget* w04 = new QWidget(ui.tableWidget_wifi);
QHBoxLayout* l04 = new QHBoxLayout(w04);
l04->addWidget(pb04);
w04->setLayout(l04);
l04->setAlignment(Qt::AlignCenter);
l04->setContentsMargins(7, 5, 11, 5);
ui.tableWidget_wifi->setCellWidget(rowcount, 4, w04);
++rowcount;
} // if wifi cnxn
} // services for loop
// resize the services column 0 to 4 to contents
ui.tableWidget_wifi->resizeColumnToContents(0);
ui.tableWidget_wifi->resizeColumnToContents(1);
ui.tableWidget_wifi->resizeColumnToContents(2);
ui.tableWidget_wifi->resizeColumnToContents(3);
// enable the control buttons if there is at least on line in the table
bool b_enable = false;
if ( wifi_list.count() > 0 ) b_enable = true;
ui.pushButton_connect->setEnabled(b_enable);
ui.pushButton_disconnect->setEnabled(b_enable);
ui.pushButton_remove->setEnabled(b_enable);
setStateRescan(b_enable);
return;
}
//
// FUnction to assemble the VPN tab of the dialog
void ControlBox::assembleTabVPN()
{
// initilize the table
ui.tableWidget_vpn->clearContents();
ui.tableWidget_vpn->setRowCount(0);
int rowcount = 0;
// Make sure we've been able to communicate with the connman-vpn daemon
if ( ((q16_errors & CMST::Err_Invalid_VPN_Iface) != 0x00) | (vpn_manager == NULL) ) {
ui.tabWidget->setTabEnabled(ui.tabWidget->indexOf(ui.VPN), false);
return;
}
// Make sure we got the services_list before we try to work with it.
if ( (q16_errors & CMST::Err_Services ) != 0x00 ) return;
// Run through each service_list looking for vpn services
vpn_list.clear();
for (int row = 0; row < services_list.size(); ++row) {
QMap<QString,QVariant> map = services_list.at(row).objmap;
if (map.value("Type").toString() == "vpn") {
vpn_list.append(services_list.at(row));
ui.tableWidget_vpn->setRowCount(rowcount + 1);
QMap<QString,QVariant> providermap;
shared::extractMapData(providermap, services_list.at(row).objmap.value("Provider") );
QTableWidgetItem* qtwi00 = new QTableWidgetItem();
qtwi00->setText(getNickName(services_list.at(row).objpath) );
qtwi00->setTextAlignment(Qt::AlignCenter);
ui.tableWidget_vpn->setItem(rowcount, 0, qtwi00);
QLabel* ql01 = new QLabel(ui.tableWidget_vpn);
ql01->setText(TranslateStrings::cmtr(providermap.value("Type").toString()) );
ql01->setAlignment(Qt::AlignCenter);
ui.tableWidget_vpn->setCellWidget(rowcount, 1, ql01);
if (map.value("State").toString() == "association") {
QProgressBar* pb02 = new QProgressBar(ui.tableWidget_vpn);
pb02->setMinimum(0);
pb02->setMaximum(0);
pb02->setOrientation( Qt::Horizontal);
pb02->setFormat("Connecting");
// set the stylesheet on pb02
QFile f0(":/stylesheets/stylesheets/vpn_connecting.qss");
if (f0.open(QIODevice::ReadOnly | QIODevice::Text)) {
QString qss = QString(f0.readAll());
if (QColor(ui.lineEdit_colorize->text()).isValid() ) {
qss = qss.left(qss.lastIndexOf('}') );
qss.append(QString("background-color: %1;").arg(ui.lineEdit_colorize->text()) );
qss.append('}');
}
f0.close();
pb02->setStyleSheet(qss);
}
ui.tableWidget_vpn->setCellWidget(rowcount, 2, pb02);
} // if association
else {
QLabel* ql02 = new QLabel(ui.tableWidget_vpn);
if (map.value("State").toString() == "ready") {
ql02->setPixmap(iconman->getIcon("state_vpn_connected").pixmap(QSize(16,16)) );
} // if ready
else {
ql02->setPixmap(iconman->getIcon("state_not_ready").pixmap(QSize(16,16)) );
} // else any other state
ql02->setAlignment(Qt::AlignCenter);
ql02->setToolTip(TranslateStrings::cmtr(map.value("State").toString()) );
ql02->installEventFilter(this);
ui.tableWidget_vpn->setCellWidget(rowcount, 2, ql02);
} // else not association
QLabel* ql03 = new QLabel(ui.tableWidget_vpn);
ql03->setText(providermap.value("Host").toString() );
ql03->setAlignment(Qt::AlignCenter);
ui.tableWidget_vpn->setCellWidget(rowcount, 3, ql03);
QLabel* ql04 = new QLabel(ui.tableWidget_vpn);
QFileInfo fi = services_list.at(row).objpath.path();
ql04->setText(fi.baseName() );
ql04->setAlignment(Qt:: AlignCenter);
ui.tableWidget_vpn->setCellWidget(rowcount, 4, ql04);
++rowcount;
} // if vpn cnxn
} // services for loop
// resize the services column 0 to 3 to contents
ui.tableWidget_vpn->resizeColumnToContents(0);
ui.tableWidget_vpn->resizeColumnToContents(1);
ui.tableWidget_vpn->resizeColumnToContents(2);
ui.tableWidget_vpn->resizeColumnToContents(3);
// enable the control buttons if there is at least on line in the table
bool b_enable = false;
if ( vpn_list.count() > 0 ) b_enable = true;
ui.pushButton_vpn_connect->setEnabled(b_enable);
ui.pushButton_vpn_disconnect->setEnabled(b_enable);
return;
}
//
// Function to assemble the counters tab of the dialog.
void ControlBox::assembleTabCounters()
{
// Text for the counter settings label
ui.label_counter_settings->setText(tr("Update resolution of the counters is based on a threshold of %L1 KB of data and %L2 seconds of time.") \
.arg(counter_accuracy) \
.arg(counter_period) );
return;
}
//
// Function to assemble the tray icon tooltip text and picture. Called
// mainly from updateDisplayWidgets(), also from createSystemTrayIcon()
void ControlBox::assembleTrayIcon()
{
QString stt = QString();
int readycount = 0;
QIcon prelimicon;
if ( (q16_errors & CMST::Err_Properties & CMST::Err_Services) == 0x00 ) {
// count how many services are in the ready state
for (int i = 0; i < services_list.count(); ++i) {
if (services_list.at(i).objmap.value("State").toString() == "ready") ++readycount;
} // readycount for loop
if ((properties_map.value("State").toString() == "online") ||
(properties_map.value("State").toString() == "ready" && readycount == 1) ) {
if ( (q16_errors & CMST::Err_Services) == 0x00 ) {
QMap<QString,QVariant> submap;
if (services_list.at(0).objmap.value("Type").toString() == "ethernet") {
shared::extractMapData(submap, services_list.at(0).objmap.value("Ethernet") );
stt.prepend(tr("Ethernet Connection<br>","icon_tool_tip"));
stt.append(tr("Service: %1<br>").arg(getNickName(services_list.at(0).objpath)) );
stt.append(tr("Interface: %1").arg(TranslateStrings::cmtr(submap.value("Interface").toString())) );
prelimicon = iconman->getIcon("connection_wired");
} // if wired connection
else if (services_list.at(0).objmap.value("Type").toString() == "wifi") {
stt.prepend(tr("WiFi Connection<br>","icon_tool_tip"));
shared::extractMapData(submap, services_list.at(0).objmap.value("Ethernet") );
stt.append(tr("SSID: %1<br>").arg(getNickName(services_list.at(0).objpath)) );
QStringList sl_tr;
for (int i = 0; i < services_list.at(0).objmap.value("Security").toStringList().size(); ++i) {
sl_tr << TranslateStrings::cmtr(services_list.at(0).objmap.value("Security").toStringList().at(i) );
} // for
stt.append(tr("Security: %1<br>").arg(sl_tr.join(',')) );
stt.append(tr("Strength: %1%<br>").arg(services_list.at(0).objmap.value("Strength").value<quint8>()) );
stt.append(tr("Interface: %1").arg(TranslateStrings::cmtr(submap.value("Interface").toString())) );
quint8 str = services_list.at(0).objmap.value("Strength").value<quint8>();
if (str > 80 ) prelimicon = iconman->getIcon("connection_wifi_100");
else if (str > 60 ) prelimicon = iconman->getIcon("connection_wifi_075");
else if (str > 40 ) prelimicon = iconman->getIcon("connection_wifi_050");
else if (str > 20 ) prelimicon = iconman->getIcon("connection_wifi_025");
else prelimicon = iconman->getIcon("connection_wifi_000");
} // else if wifi connection
else if (services_list.at(0).objmap.value("Type").toString() == "vpn") {
shared::extractMapData(submap, services_list.at(0).objmap.value("Provider") );
stt.prepend(tr("VPN Connection<br>","icon_tool_tip"));
stt.append(tr("Type: %1<br>").arg(TranslateStrings::cmtr(submap.value("Type").toString())) );
stt.append(tr("Service: %1<br>").arg(services_list.at(0).objmap.value("Name").toString()) );
stt.append(tr("Host: %1<br>").arg(TranslateStrings::cmtr(submap.value("Host").toString())) );
prelimicon = iconman->getIcon("connection_vpn");
} // else if vpn connection
} // services if no error
} // if the state is online
// else if state is ready
else if (properties_map.value("State").toString() == "ready") {
prelimicon = iconman->getIcon("connection_ready");
stt.append(tr("Connection is in the Ready State.", "icon_tool_tip"));
} // else if if ready
// else if state is failure
else if (properties_map.value("State").toString() == "failure") {
// try to reconnect if service is wifi and Favorite and if reconnect is specified
if (ui.checkBox_retryfailed->isChecked() ) {
if (services_list.at(0).objmap.value("Type").toString() =="wifi" && services_list.at(0).objmap.value("Favorite").toBool() ) {
QDBusInterface* iface_serv = new QDBusInterface(DBUS_CON_SERVICE, services_list.at(0).objpath.path(), "net.connman.Service", QDBusConnection::systemBus(), this);
shared::processReply(iface_serv->call(QDBus::AutoDetect, "Connect") );
iface_serv->deleteLater();
stt.append(tr("Connection is in the Failure State, attempting to reestablish the connection", "icon_tool_tip") );
} // if wifi and favorite
} // if retry checked
prelimicon = iconman->getIcon("state_online");
stt.append(tr("Connection is in the Failure State.", "icon_tool_tip"));
} // else if failure state
// else anything else, states in this case should be "idle", "association", "configuration", or "disconnect"
else {
prelimicon = iconman->getIcon("connection_not_ready");
stt.append(tr("Not Connected", "icon_tool_tip"));
} // else any other connection state
} // properties if no error
// could not get any properties
else {
prelimicon = iconman->getIcon("connection_error");
stt.append(tr("Error retrieving properties via Dbus"));
stt.append(tr("Connection status is unknown"));
}
// Set the tray icon. If the trayiconbackground color is valid and
// there is a valid alpha channel convert the alpha to the background
// color to get our fake transparency. Fake transparency can be set as a command
// line option so trayiconbackground is set up in the constructor.
// Otherwise just convert the image to ARGB32 which seems to be required
// for the icons to display in Plasma5.
// First convert from a QIcon through QPixmap to QImage
QPixmap pxm = prelimicon.pixmap(prelimicon.actualSize(QSize(22,22)) );
QImage src = pxm.toImage();
QImage dest = QImage(src.width(), src.height(), QImage::Format_ARGB32);
QPainter painter(&dest);
if (trayiconbackground.isValid() && src.hasAlphaChannel() ) {
painter.setCompositionMode(QPainter::CompositionMode_Source);
painter.fillRect(dest.rect(), trayiconbackground);
painter.setCompositionMode(QPainter::CompositionMode_SourceOver);
} // if img has alpha channel and background color valid
else {
painter.setCompositionMode(QPainter::CompositionMode_Source);
} // else just make an ARGB32 copy
painter.drawImage(0, 0, src);
prelimicon = QIcon(QPixmap::fromImage(dest));
trayicon->setIcon(prelimicon);
// Set the tool tip (shown when mouse hovers over the systemtrayicon)
if (ui.checkBox_enablesystemtraytooltips->isChecked() )
trayicon->setToolTip(stt);
else
trayicon->setToolTip(QString());
// Don't continue if we can't get properties
if ( (q16_errors & CMST::Err_Properties & CMST::Err_Technologies & CMST::Err_Services) != 0x00 ) return;
// Assemble the submenus for the context menu
// tech_submenu.
tech_submenu->clear();
for (int i = 0; i < technologies_list.count(); ++i) {
QAction* act = tech_submenu->addAction(technologies_list.at(i).objmap.value("Name").toString() );
act->setCheckable(true);
act->setChecked(technologies_list.at(i).objmap.value("Powered").toBool() );
QString ttstr = QString(tr("<p style='white-space:pre'><center><b>%1 Properties</b></center>").arg(TranslateStrings::cmtr(technologies_list.at(i).objmap.value("Name").toString())) );
ttstr.append(tr("Type: %1").arg(technologies_list.at(i).objmap.value("Type").toString()) );
ttstr.append(tr("<br>Powered "));
technologies_list.at(i).objmap.value("Powered").toBool() ? ttstr.append(tr("On")) : ttstr.append(tr("Off"));
ttstr.append("<br>");
technologies_list.at(i).objmap.value("Connected").toBool() ? ttstr.append(tr("Connected")) : ttstr.append(tr("Not Connected"));
ttstr.append(tr("<br>Tethering "));
technologies_list.at(i).objmap.value("Tethering").toBool() ? ttstr.append(tr("Enabled")) : ttstr.append(tr("Disabled"));
act->setToolTip(ttstr);
} // i for
// info_submenu
info_submenu->clear();
for (int j = 0; j < services_list.count(); ++j) {
QAction* act = info_submenu->addAction(getNickName(services_list.at(j).objpath) );
if (services_list.at(j).objmap.value("Type").toString() == "ethernet" ) {
if (services_list.at(j).objmap.value("State").toString() == "online")
act->setIcon(iconman->getIcon("connection_wired"));
else
if(services_list.at(j).objmap.value("State").toString() == "ready")
act->setIcon(iconman->getIcon("connection_ready"));
else
act->setIcon(iconman->getIcon("connection_not_ready"));
} // if wired
else if (services_list.at(j).objmap.value("Type").toString() == "wifi" ) {
if (services_list.at(j).objmap.value("State").toString() == "online" ||
(properties_map.value("State").toString() != "online" &&
(services_list.at(j).objmap.value("State").toString() == "ready" && readycount == 1)) ) {
quint8 str = services_list.at(j).objmap.value("Strength").value<quint8>();
if (str > 80 ) act->setIcon(iconman->getIcon("connection_wifi_100") );
else if (str > 60 ) act->setIcon(iconman->getIcon("connection_wifi_075") );
else if (str > 40 ) act->setIcon(iconman->getIcon("connection_wifi_050") );
else if (str > 20 ) act->setIcon(iconman->getIcon("connection_wifi_025") );
else act->setIcon(iconman->getIcon("connection_wifi_000") );
} // if we want to show a wifi signal symbol
else
if(services_list.at(j).objmap.value("State").toString() == "ready")
act->setIcon(iconman->getIcon("connection_ready"));
else
act->setIcon(iconman->getIcon("connection_not_ready"));
} // else if wifi
else if (services_list.at(j).objmap.value("Type").toString() == "vpn" ) {
if (services_list.at(j).objmap.value("State").toString() == "ready")
act->setIcon(iconman->getIcon("connection_vpn"));
else if (services_list.at(j).objmap.value("State").toString() == "association")
act->setIcon(iconman->getIcon("connection_vpn_acquiring"));
else
act->setIcon(iconman->getIcon("connection_not_ready"));
} // else if vpn
else if (services_list.at(j).objmap.value("State").toString() == "ready") act->setIcon(iconman->getIcon("connection_ready"));
else if (services_list.at(j).objmap.value("State").toString() == "failure" ) act->setIcon(iconman->getIcon("connection_failure"));
else act->setIcon(iconman->getIcon("connection_not_ready"));
} // j for
// wifi_submenu.
wifi_submenu->clear();
for (int k = 0; k < wifi_list.count(); ++k) {
QAction* act = wifi_submenu->addAction(getNickName(wifi_list.at(k).objpath) );
act->setCheckable(true);
QString state = wifi_list.at(k).objmap.value("State").toString();
if (state == "online" || state == "ready") act->setChecked(true);
QString ttstr = QString(tr("<p style='white-space:pre'><center><b>%1</b></center>").arg(getNickName(wifi_list.at(k).objpath)) );
ttstr.append(tr("Connection : %1").arg(TranslateStrings::cmtr(state)) );
ttstr.append("<br>");
ttstr.append(tr("Signal Strength: %1%").arg(wifi_list.at(k).objmap.value("Strength").toInt()) );
ttstr.append("<br>");
wifi_list.at(k).objmap.value("Favorite").toBool() ? ttstr.append(tr("Favorite Connection")) : ttstr.append(tr("Never Connected"));
ttstr.append("<br>");
QStringList sl_tr;
for (int m = 0; m < wifi_list.at(k).objmap.value("Security").toStringList().size(); ++m) {
sl_tr << TranslateStrings::cmtr(wifi_list.at(k).objmap.value("Security").toStringList().at(m) );
} // for
ttstr.append(tr("Security: %1").arg(sl_tr.join(',')) );
if (wifi_list.at(k).objmap.value("Roaming").toBool() ) ttstr.append(tr("<br>Roaming"));
ttstr.append(tr("<br>Autoconnect is "));
wifi_list.at(k).objmap.value("AutoConnect").toBool() ? ttstr.append(tr("Enabled")) : ttstr.append(tr("Disabled"));
act->setToolTip(ttstr);
} // k for
// vpn_submenu
if ( (q16_errors & CMST::Err_Invalid_VPN_Iface) != 0x00 || vpn_manager == NULL) {
vpn_submenu->setDisabled(true);
return;
}
vpn_submenu->clear();
for (int l = 0; l < vpn_list.count(); ++l) {
QAction* act = vpn_submenu->addAction(getNickName(vpn_list.at(l).objpath) );
act->setCheckable(true);
QString state = vpn_list.at(l).objmap.value("State").toString();
if (state == "ready") act->setChecked(true);
QString ttstr = QString(tr("<p style='white-space:pre'><center><b>%1</b></center>").arg(getNickName(vpn_list.at(l).objpath)) );
ttstr.append(tr("Connection : %1").arg(TranslateStrings::cmtr(state)) );
act->setToolTip(ttstr);
} // for
return;
}
// Handler for left click on tray icon
void ControlBox::iconActivated(QSystemTrayIcon::ActivationReason reason)
{
//Only handling left click case
if(reason == QSystemTrayIcon::Trigger)
{
//Show the window if it is currently hidden/minimized
if(this->isHidden() || this->isMinimized())
{
minMaxWindow(maximizeAction);
}
//Otherwise hide the window
else
{
minMaxWindow(minimizeAction);
}
}
}
void ControlBox::enableRunOnStartup(bool enabled)
{
QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
QString HOME = env.value("HOME");
QString XDG_CONFIG_HOME = env.value("XDG_CONFIG_HOME", QFileInfo(QDir(HOME), ".config").absoluteFilePath());
QFileInfo autostart_dir_info(QDir(XDG_CONFIG_HOME), "autostart");
QFileInfo autostart_file_info(QDir(autostart_dir_info.absoluteFilePath()), "cmst-autostart.desktop");
QFile user_autostart_file(autostart_file_info.absoluteFilePath());
if (enabled) {
QCryptographicHash hasher(QCryptographicHash::Sha1);
QFile fileToCopy("/usr/share/cmst/autostart/cmst-autostart.desktop");
if (user_autostart_file.exists()) {
hasher.reset();
hasher.addData(&fileToCopy);
QByteArray orig_file_hash = hasher.result();
hasher.reset();
hasher.addData(&user_autostart_file);
QByteArray user_autostart_file_hash = hasher.result();
if (orig_file_hash == user_autostart_file_hash) {
return;
}
if (!user_autostart_file.remove()) {
return;
}
}
// Copy the autostart file (create the target directory first if needed)
QDir dir = autostart_file_info.dir();
if (! dir.exists() ) dir.mkdir(autostart_file_info.path() );
fileToCopy.copy(autostart_file_info.absoluteFilePath());
} // if enabled
else {
if (!autostart_file_info.exists()) {
return;
}
user_autostart_file.remove();
}
}
// Slot to save GUI settings to disk
void ControlBox::writeSettings()
{
settings->beginGroup("MainWindow");
settings->setValue("size", this->size() );
settings->setValue("pos", this->pos() );
settings->setValue("current_page", ui.tabWidget->currentIndex());
settings->setValue("splitter_01", ui.splitter01->saveState());
settings->endGroup();
settings->beginGroup("CheckBoxes");
settings->setValue("hide_tray_icon", ui.checkBox_hideIcon->isChecked() );
settings->setValue("devices_off", ui.checkBox_devicesoff->isChecked() );
settings->setValue("retain_settings", ui.checkBox_usestartoptions->isChecked() );
settings->setValue("retain_state", ui.checkBox_retainstate->isChecked() );
settings->setValue("services_less", ui.checkBox_hidecnxn->isChecked() );
settings->setValue("technologies_less", ui.checkBox_hidetethering->isChecked() );
settings->setValue("enable_interface_tooltips", ui.checkBox_enableinterfacetooltips->isChecked() );
settings->setValue("enable_systemtray_tooltips", ui.checkBox_enablesystemtraytooltips->isChecked() );
settings->setValue("enable_systemtray_notications", ui.checkBox_systemtraynotifications->isChecked() );
settings->setValue("enable_daemon_notifications", ui.checkBox_notifydaemon->isChecked() );
settings->setValue("reset_counters", ui.checkBox_resetcounters->isChecked() );
settings->setValue("advanced", ui.checkBox_advanced->isChecked() );
settings->setValue("retry_failed", ui.checkBox_retryfailed->isChecked() );
settings->setValue("run_on_startup", ui.checkBox_runonstartup->isChecked());
settings->endGroup();
settings->beginGroup("LineEdits");
settings->setValue("colorize_icons", ui.lineEdit_colorize->text() );
settings->endGroup();
settings->beginGroup("StartOptions");
settings->setValue("enable_counters", ui.checkBox_enablecounters->isChecked() );
settings->setValue("disable_tray_icon", ui.checkBox_disabletrayicon->isChecked() );
settings->setValue("disable_vpn", ui.checkBox_disablevpn->isChecked() );
settings->setValue("use_icon_theme", ui.checkBox_systemicontheme->isChecked() );
settings->setValue("icon_theme", ui.lineEdit_icontheme->text() );
settings->setValue("start_minimized", ui.checkBox_startminimized->isChecked() );
settings->setValue("disable_minimized", ui.checkBox_disableminimized->isChecked() );
settings->setValue("use_wait_time", ui.checkBox_waittime->isChecked() );
settings->setValue("wait_time", ui.spinBox_waittime->value() );
settings->setValue("use_counter_update_rate", ui.checkBox_counterseconds->isChecked() );
settings->setValue("counter_update_rate", ui.spinBox_counterrate->value() );
settings->setValue("use_fake_transparency", ui.checkBox_faketranparency->isChecked() );
settings->setValue("fake_transparency_color", ui.spinBox_faketransparency->value() );
settings->setValue("desktop_none", ui.radioButton_desktopnone->isChecked() );
settings->setValue("desktop_xfce", ui.radioButton_desktopxfce->isChecked() );
settings->setValue("desktop_mate", ui.radioButton_desktopmate->isChecked() );
settings->endGroup();
settings->beginGroup("ExternalPrograms");
settings->setValue("run_after_connect", ui.lineEdit_afterconnect->text() );
settings->endGroup();
return;
}
//
// Slot to read GUI settings to disk
void ControlBox::readSettings()
{
settings->beginGroup("CheckBoxes");
ui.checkBox_hideIcon->setChecked(settings->value("hide_tray_icon").toBool() );
ui.checkBox_devicesoff->setChecked(settings->value("devices_off").toBool() );
ui.checkBox_usestartoptions->setChecked(settings->value("retain_settings").toBool() );
ui.checkBox_retainstate->setChecked(settings->value("retain_state").toBool() );
ui.checkBox_hidecnxn->setChecked(settings->value("services_less").toBool() );
ui.checkBox_hidetethering->setChecked(settings->value("technologies_less").toBool() );
ui.checkBox_enableinterfacetooltips->setChecked(settings->value("enable_interface_tooltips").toBool() );
ui.checkBox_enablesystemtraytooltips->setChecked(settings->value("enable_systemtray_tooltips").toBool() );
ui.checkBox_systemtraynotifications->setChecked(settings->value("enable_systemtray_notications").toBool() );
ui.checkBox_notifydaemon->setChecked(settings->value("enable_daemon_notifications").toBool() );
ui.checkBox_resetcounters->setChecked(settings->value("reset_counters").toBool() );
ui.checkBox_advanced->setChecked(settings->value("advanced").toBool() );
ui.checkBox_retryfailed->setChecked(settings->value("retry_failed").toBool() );
ui.checkBox_runonstartup->setChecked(settings->value("run_on_startup").toBool());
settings->endGroup();
settings->beginGroup("LineEdits");
ui.lineEdit_colorize->setText(settings->value("colorize_icons").toString() );
settings->endGroup();
settings->beginGroup("StartOptions");
// Changed disable counters to enable counters. Figure out what the user wanted
// and adjust accordingly
if (settings->contains("disable_counters") ) {
ui.checkBox_enablecounters->setChecked(! settings->value("disable_counters").toBool() );
settings->remove("disable_counters");
}
else {
ui.checkBox_enablecounters->setChecked(settings->value("enable_counters").toBool() );
}
ui.checkBox_disabletrayicon->setChecked(settings->value("disable_tray_icon").toBool() );
ui.checkBox_disablevpn->setChecked(settings->value("disable_vpn").toBool() );
ui.checkBox_systemicontheme->setChecked(settings->value("use_icon_theme").toBool() );
ui.lineEdit_icontheme->setText(settings->value("icon_theme").toString() );
ui.checkBox_startminimized->setChecked(settings->value("start_minimized").toBool() );
ui.checkBox_disableminimized->setChecked(settings->value("disable_minimized").toBool() );
ui.checkBox_waittime->setChecked(settings->value("use_wait_time").toBool() );
ui.spinBox_waittime->setValue(settings->value("wait_time").toInt() );
ui.checkBox_counterseconds->setChecked(settings->value("use_counter_update_rate").toBool() );
ui.spinBox_counterrate->setValue(settings->value("counter_update_rate").toInt() );
ui.checkBox_faketranparency->setChecked(settings->value("use_fake_transparency").toBool() );
ui.spinBox_faketransparency->setValue(settings->value("fake_transparency_color").toInt() );
ui.radioButton_desktopnone->setChecked(settings->value("desktop_none").toBool() );
ui.radioButton_desktopxfce->setChecked(settings->value("desktop_xfce").toBool() );
ui.radioButton_desktopmate->setChecked(settings->value("desktop_mate").toBool() );
settings->endGroup();
settings->beginGroup("ExternalPrograms");
ui.lineEdit_afterconnect->setText(settings->value("run_after_connect").toString() );
settings->endGroup();
return;
}
//
// Slot to create the systemtray icon. Really part of the constructor
// and called by a single shot QTimer.
void ControlBox::createSystemTrayIcon()
{
// Search for a tray icon, don't read XDG_CURRENT_DESKTOP for the tray type
bool b_dtaware = qApp->desktopSettingsAware();
qApp->setDesktopSettingsAware(false);
// We still need to make sure there is a tray available
if (QSystemTrayIcon::isSystemTrayAvailable() ) {
// Create the outline of the context menu. Submenu contents are defined in the
// assembletrayIcon() function.
trayiconmenu->clear();
trayiconmenu->setTearOffEnabled(true);
trayiconmenu->setToolTipsVisible(true);
tech_submenu->setToolTipsVisible(true);
info_submenu->setToolTipsVisible(true);
wifi_submenu->setToolTipsVisible(true);
vpn_submenu->setToolTipsVisible(true);
trayiconmenu->addMenu(tech_submenu);
trayiconmenu->addMenu(info_submenu);
trayiconmenu->addMenu(wifi_submenu);
trayiconmenu->addMenu(vpn_submenu);
trayiconmenu->addSeparator();
trayiconmenu->addAction(ui.actionRescan);
trayiconmenu->addAction(ui.actionOffline_Mode);
trayiconmenu->addSeparator();
trayiconmenu->addAction(maximizeAction);
trayiconmenu->addAction(minimizeAction);
trayiconmenu->addSeparator();
trayiconmenu->addAction(tr("Cancel"), this, SLOT(closeSystemTrayTearOffMenu()) );
trayiconmenu->addAction(exitAction);
trayicon->setContextMenu(trayiconmenu);
connect(trayicon, SIGNAL(activated(QSystemTrayIcon::ActivationReason)), this, SLOT(iconActivated(QSystemTrayIcon::ActivationReason)));
// We need this if someone is running the program from the tray popup menu.
// The main UI is fine without it, but if you call up the agent dialog and then
// close that seems to be treated as the last window.
qApp->setQuitOnLastWindowClosed(false);
// Assemble the tray icon (set the icon to display)
assembleTrayIcon();
// QT5.3 and XFCE don't play nicely. Hammer the XFCE tray up to
// maxtries to get a valid icon geometry.
// QT5.4 update, may be fixed but leave option in for now
if (b_usexfce || b_usemate) {
const int maxtries = 125;
int i;
for (i = 0; i < maxtries; ++i) {
trayicon->setVisible(true);
//qDebug() << "icon geometry: " << trayicon->geometry();
if ((trayicon->geometry().left() > 0 || trayicon->geometry().top() > 0) && trayicon->geometry().width() > 1) break;
trayicon->setVisible(false);
qApp->processEvents();
} // hammer loop
if (i == maxtries - 1) {
qDebug() << QString("Failed to get a valid icon from the systemtray in %1 tries").arg(maxtries);
ui.pushButton_minimize->setDisabled(true);
trayicon = 0; // reinitialize the pointer
} // if we hit the end of the loop
} // if use xfce
// Sync the visibility to the checkbox
ui.checkBox_hideIcon->setEnabled(true);
trayicon->setVisible(true);
} // if there is a systemtray available
// else no systemtray available
else {
ui.checkBox_hideIcon->setDisabled(true);
trayicon = NULL;
QMessageBox::warning(this,
QString(TranslateStrings::cmtr("cmst")) + tr(" Warning"),
tr("<center><b>Unable to find a systemtray on this machine.</b>"
"<center><br>The program may still be used to manage your connections, but the tray icon will be disabled."
"<center><br><br>If you are seeing this message at system start up and you know a system tray exists once the "
"system is up, try starting with the <b>-w</b> switch and set a delay as necessary. The exact wait time will vary "
"from system to system."
) );
// Even if we want to be minimized we can't there is no place to minimize to.
this->showNormal();
} // else
// Restore the desktopAware
qApp->setDesktopSettingsAware(b_dtaware);
// sync offlinemode checkbox and action b1ased on the saved value from settings
if (settings->value("CheckBoxes/devices_off").toBool() ) {
ui.actionOffline_Mode->trigger();
}
// Lastly update the display widgets (since this is actually the last
// line of the constructor.)
this->updateDisplayWidgets();
return;
}
//
// Function to show notifications (if desired by the user). Called from
// the functions we connect dbus signals to, for instance dbsPropertyChanged(),
// The notifyclient class is used to store data for display from both
// the systemtrayicon and the notification server.
void ControlBox::sendNotifications()
{
// if we want system tray notifications
if (ui.checkBox_systemtraynotifications->isChecked() && QSystemTrayIcon::isSystemTrayAvailable() ) {
QSystemTrayIcon::MessageIcon sticon = QSystemTrayIcon::NoIcon;
if (notifyclient->getUrgency() == Nc::UrgencyCritical) sticon = QSystemTrayIcon::Warning;
else sticon = QSystemTrayIcon::Information;
if (notifyclient->getBody().isEmpty() ) trayicon->showMessage(TranslateStrings::cmtr("cmst"), notifyclient->getSummary(), sticon);
else trayicon->showMessage(TranslateStrings::cmtr("cmst"), QString(notifyclient->getSummary() + "\n" + notifyclient->getBody()), sticon);
}
// if we want notify daemon notifications
if (ui.checkBox_notifydaemon->isChecked() && notifyclient->isValid() ) {
notifyclient->sendNotification();
}
return;
}
//
// Function to query connman.manager.GetProperties
// Return a bool, true on success, false otherwise
bool ControlBox::getProperties()
{
// call connman and GetProperties
QDBusMessage reply = con_manager->call("GetProperties");
shared::processReply(reply);
// call the function to get the map values
properties_map.clear();
return getMap(properties_map, reply);
}
//
// Function to query connman.manager.GetTechnologies
// Return a bool, true on success, false otherwise
bool ControlBox::getTechnologies()
{
// call connman and GetTechnologies
QDBusMessage reply = con_manager->call("GetTechnologies");
shared::processReply(reply);
// call the function to get the map values
technologies_list.clear();
return getArray(technologies_list, reply);
}
//
// Function to query connman.manager.GetServices
// Return a bool, true on success, false otherwise
bool ControlBox::getServices()
{
// call connman and GetServices
QDBusMessage reply = con_manager->call("GetServices");
shared::processReply(reply);
// call the function to get the map values
services_list.clear();
return getArray(services_list, reply);
}
//
// Function to extract arrayElements from a DBus reply message (that contains an array).
// This data type is returned by GetServices and GetTechnologies.
//
// Return value a bool, true on success, false otherwise
// A QList of arrayElements is sent by reference (called r_list here)
// and is modified by this function. r_msg is a constant reference
// to the DBus reply message.
bool ControlBox::getArray(QList<arrayElement>& r_list, const QDBusMessage& r_msg )
{
// make sure r_msg is a QDBusArgument
if ( ! r_msg.arguments().at(0).canConvert<QDBusArgument>() ) return false;
// make sure the QDBusArgument holds an array
const QDBusArgument &qdb_arg = r_msg.arguments().at(0).value<QDBusArgument>();
if (qdb_arg.currentType() != QDBusArgument::ArrayType ) return false;
// iterate over the QDBusArgument pulling array elements out and inserting into
// an arrayElement structure.
qdb_arg.beginArray();
r_list.clear();
while ( ! qdb_arg.atEnd() ) {
// make sure the argument is a structure type
if (qdb_arg.currentType() != QDBusArgument::StructureType ) return false;
arrayElement ael;
qdb_arg.beginStructure();
qdb_arg >> ael.objpath >> ael.objmap;
qdb_arg.endStructure();
r_list.append (ael);
} // while
qdb_arg.endArray();
return true;
}
// Function to extract a QMap from a DBus reply message (that contains a map).
// This data type is returned by GetProperties
//
// Return value a bool, true on success, false otherwise.
// The map is sent by reference (called r_map here) and is modified by this function.
// r_msg is a constant reference to the DBus reply message.
bool ControlBox::getMap(QMap<QString,QVariant>& r_map, const QDBusMessage& r_msg )
{
// make sure r_msg is a QDBusArgument
if ( ! r_msg.arguments().at(0).canConvert<QDBusArgument>() ) return false;
// make sure the QDBusArgument holds a map
const QDBusArgument &qdb_arg = r_msg.arguments().at(0).value<QDBusArgument>();
if (qdb_arg.currentType() != QDBusArgument::MapType ) return false;
// iterate over the QDBusArgument pulling map keys and values out
qdb_arg.beginMap();
r_map.clear();
while ( ! qdb_arg.atEnd() ) {
QString key;
QVariant value;
qdb_arg.beginMapEntry();
qdb_arg >> key >> value;
qdb_arg.endMapEntry();
r_map.insert(key, value);
}
qdb_arg.endMap();
return true;
}
//
// Function to log errors to the system log. Functionallity provided
// by syslog.h and friends.
void ControlBox::logErrors(const quint16& err)
{
// store the error in a data element
q16_errors |= err;
// Log the error in the system log
// LOG_PID Include PID with each message
// LOG_CONS Write to console if there is a problem writing to system log
// LOG_USER User Level Message
// LOG_ERR Error condition
// LOG_WARNING Warning contition
// Defined in resource.h
// LOG_NAME Name to display in the log
openlog(qPrintable(LOG_NAME), LOG_PID|LOG_CONS, LOG_USER);
switch (err)
{
case CMST::Err_No_DBus:
syslog(LOG_ERR, "%s", tr("Could not find a connection to the system bus").toUtf8().constData() );
QMessageBox::critical(this, tr("%1 - Critical Error").arg(TranslateStrings::cmtr("cmst")),
tr("Unable to find a connection to the system bus.<br><br>%1 will not be able to communicate with connman.").arg(TranslateStrings::cmtr("cmst")) );
break;
case CMST::Err_Invalid_Con_Iface:
syslog(LOG_ERR, "%s",tr("Could not create an interface to connman on the system bus").toUtf8().constData());
QMessageBox::critical(this, tr("%1 - Critical Error").arg(TranslateStrings::cmtr("cmst")),
tr("Unable to create an interface to connman on the system bus.<br><br>%1 will not be able to communicate with connman.").arg(TranslateStrings::cmtr("cmst")) );
break;
case CMST::Err_Properties:
syslog(LOG_ERR, "%s", tr("Error reading or parsing connman.Manager.GetProperties").toUtf8().constData() );
QMessageBox::warning(this, tr("%1 - Warning").arg(TranslateStrings::cmtr("cmst")),
tr("There was an error reading or parsing the reply from method connman.Manager.GetProperties.<br><br>It is unlikely any portion of %1 will be functional.").arg(TranslateStrings::cmtr("cmst")) );
break;
case CMST::Err_Technologies:
syslog(LOG_ERR, "%s",tr("Error reading or parsing connman.Manager.GetTechnologies").toUtf8().constData() );
QMessageBox::warning(this, tr("%1 - Warning").arg(TranslateStrings::cmtr("cmst")),
tr("There was an error reading or parsing the reply from method connman.Manager.GetTechnologies.<br><br>Some portion of %1 may still be functional.").arg(TranslateStrings::cmtr("cmst")) );
break;
case CMST::Err_Services:
syslog(LOG_ERR, "%s", tr("Error reading or parsing connman.Manager.GetServices").toUtf8().constData() );
QMessageBox::warning(this, tr("%1 - Warning").arg(TranslateStrings::cmtr("cmst")),
tr("There was an error reading or parsing the reply from method connman.Manager.GetServices.<br><br>Some portion of %1 may still be functional.").arg(TranslateStrings::cmtr("cmst")) );
break;
case CMST::Err_Invalid_VPN_Iface:
// NOTE: this error is logged to the system log only, no message is presented to the user (issue #155). Done
// this way because it will happen when someone does not compile ConnMan with VPN support, or if they don't
// have the connman-vpn daemon running. We're figuring this would be more than likely intentional and not an
// error the user would need to be concerned about. If he is the error will show in the system log.
syslog(LOG_ERR, "%s",tr("Could not create an interface to connman-vpn on the system bus").toUtf8().constData());
break;
default:
break;
}
closelog();
return;
}
//
// Function to read text contained in a resource file. Input is a const char* to the resource,
// Return value is a QString of the text
QString ControlBox::readResourceText(const char* textfile)
{
QString rtnstring = QString();
QFile file(textfile);
if (file.open(QIODevice::ReadOnly | QIODevice::Text)) {
QTextStream in(&file);
while (!in.atEnd()) {
rtnstring.append(in.readLine() );
} // while
} // if
return rtnstring;
}
//
// Function to clear the counters if selected in the ui. Called from the constructor
// and from dbsServicesChanged
void ControlBox::clearCounters()
{
if (ui.checkBox_resetcounters->isChecked() && ! onlineobjectpath.isEmpty() ) {
QDBusInterface* iface_serv = new QDBusInterface(DBUS_CON_SERVICE, onlineobjectpath, "net.connman.Service", QDBusConnection::systemBus(), this);
shared::processReply(iface_serv->call(QDBus::AutoDetect, "ResetCounters") );
iface_serv->deleteLater();
}
return;
}
//
// Function to return a nick name for a service. Typically return the
// Name property. For wired ethernet Name comes back as Wired, and for
// hidden wifi networks this is blank. In those cases create a
// nickname and return it.
QString ControlBox::getNickName(const QDBusObjectPath& objpath)
{
for (int i = 0; i < services_list.size(); ++i) {
if (services_list.at(i).objpath == objpath) {
QMap<QString,QVariant> submap;
if (services_list.at(i).objmap.value("Type").toString() == "ethernet") {
shared::extractMapData(submap, services_list.at(i).objmap.value("Ethernet") );
if (submap.value("Interface").toString().isEmpty() )
return services_list.at(i).objmap.value("Name").toString();
else
return QString(TranslateStrings::cmtr(services_list.at(i).objmap.value("Name").toString()) + " [%1]").arg(submap.value("Interface").toString() );
} // if type ethernet
else if ( services_list.at(i).objmap.value("Type").toString() == "wifi" && services_list.at(i).objmap.value("Name").toString().isEmpty() )
return tr("[Hidden Wifi]");
else
return services_list.at(i).objmap.value("Name").toString();
} // if objpath matches
} // for
return QString();
}
// Slot to connect to the notification client. Called from QTimers to give time for the notification server
// to start up if this program is started automatically at boot. We make four attempts at finding the
// notification server. First is in the constructor of NotifyClient, following we call the connectToServer()
// function.
void ControlBox::connectNotifyClient()
{
//initialize the counter
static short count = 0;
++count;
if (count > 1 ) {
// if we have a valid notifyclient return now
if (notifyclient->isValid() )
return;
// else try to connect again
else
notifyclient->connectToServer();
} // if count > 1
// setup the notify server label if we were successful in finding and connecting to a server
if (notifyclient->isValid() ) {
QString name = notifyclient->getServerName().toLower();
name = name.replace(0, 1, name.left(1).toUpper() );
QString vendor = notifyclient->getServerVendor();
vendor = vendor.replace(0, 1, vendor.left(1).toUpper() );
QString lab = tr("%1 version %2 by %3 has been detected on this system.<p>This server supports desktop Notification Specification version %4")
.arg(name)
.arg(notifyclient->getServerVersion() )
.arg(vendor)
.arg(notifyclient->getServerSpecVersion() );
ui.label_serverstatus->clear();
ui.label_serverstatus->setDisabled(true);
ui.groupBox_notifications->setToolTip(lab);
}
// not successful, try again or abandon if counter is at limit
else {
if (count < 4) {
ui.label_serverstatus->setText(tr("Attempt %1 of 4 looking for notification server.").arg(count));
} // try again
else {
ui.label_serverstatus->setText(tr("Unable to find or connect to a Notification server."));
ui.checkBox_notifydaemon->setChecked(false);
ui.checkBox_notifydaemon->setEnabled(false);
} // else last time
ui.groupBox_notifications->setToolTip("");
ui.groupBox_notifications->setWhatsThis("");
} // else we don't have a valid client.
return;
}
// The following two functions are somewhat similar. ConfigureSerivce opens a dialog to tweak
// defaults set by Connman. All settings are read and written by Connman into files that Connman
// creates.
//
// Provisioning creates a provision file that takes precedence over anything Connman creates. It
// is required for certain types of networks, for instance Eduroam. The provisioning file must be
// created manually before trying to connect via Connman. Disk reads and writes are handled by
// a program (this one) and not by Connman.
//
// Slot to open a dialog to configure the selected service
void ControlBox::configureService()
{
// Make sure the index is real
if (ui.comboBox_service->currentIndex() < 0 ) return;
// Create a new properties editor
PropertiesEditor* peditor = new PropertiesEditor(this, services_list.at(ui.comboBox_service->currentIndex()) );
// Set the whatsthis button icon
peditor->setWhatsThisIcon(iconman->getIcon("whats_this"));
// call then clean up
peditor->exec();
peditor->deleteLater();
return;
}
//
// Slot to open the provisioning editor to create a configuration (provisioning) file
// Called whenever ui.pushButton_provisioning_editor or ui.pushButton_vpn_editor
// is pressed.
void ControlBox::provisionService()
{
if (qobject_cast<QPushButton*>(sender()) == ui.pushButton_provisioning_editor) {
ProvisioningEditor* reditor = new ProvisioningEditor(this);
// Set the whatsthis button icon
reditor->setWhatsThisIcon(iconman->getIcon("whats_this") );
// call then clean up
reditor->exec();
reditor->deleteLater();
}
else if (qobject_cast<QPushButton*>(sender()) == ui.pushButton_vpn_editor) {
VPN_Editor* veditor = new VPN_Editor(this);
// Set the whatsthis button icon
veditor->setWhatsThisIcon(iconman->getIcon("whats_this") );
// call then clean up
veditor->exec();
veditor->deleteLater();
}
return;
}
//
// Slot called when a connection to the local socket was detected. Means another instance of CMST was started
// while this instance was running.
void ControlBox::socketConnectionDetected()
{
this->showNormal();
return;
}
//
// Slot to tidy up the place at close. Called when the QApplication::aboutToQuit() signal is emitted
void ControlBox::cleanUp()
{
// close and delete the socket server
socketserver->close();
socketserver->deleteLater();
// write settings
this->writeSettings();
// unregister objects
if (con_manager->isValid() ) {
// agent
shared::processReply(con_manager->call(QDBus::AutoDetect, "UnregisterAgent", QVariant::fromValue(QDBusObjectPath(AGENT_OBJECT))) );
// counter - only have a signal-slot connection if the counter was able to be registered
if (counter->cnxns() > 0) {
shared::processReply(con_manager->call(QDBus::AutoDetect, "UnregisterCounter", QVariant::fromValue(QDBusObjectPath(CNTR_OBJECT))) );
} // if counters are connected to anything
} // if con_manager isValid
if (vpn_manager != NULL) {
if (vpn_manager->isValid() ) {
shared::processReply(vpn_manager->call(QDBus::AutoDetect, "UnregisterAgent", QVariant::fromValue(QDBusObjectPath(VPN_AGENT_OBJECT))) );
} // ivpn_manager isValid
} // not null
return;
}
//
// Slot to open the color selection dialog and request input.
void ControlBox::callColorDialog()
{
QColor color = QColorDialog::getColor(QColor(ui.lineEdit_colorize->text()), this, tr("Colorize Icons"));
if (color.isValid() ) ui.lineEdit_colorize->setText(color.name() );
return;
}
//
// Slot to process things when the user changes the icon color
void ControlBox::iconColorChanged(const QString& col)
{
iconman->setIconColor(QColor(col) );
this->updateDisplayWidgets();
ui.toolButton_whatsthis->setIcon(iconman->getIcon("whats_this"));
agent->setWhatsThisIcon(iconman->getIcon("whats_this"));
vpnagent->setWhatsThisIcon(iconman->getIcon("whats_this"));
return;
}
//
// Slot to set the enabled/disabled state of the rescan wifi controls
void ControlBox::setStateRescan(bool state)
{
ui.pushButton_rescanwifi01->setEnabled(state);
ui.pushButton_rescanwifi02->setEnabled(state);
ui.actionRescan->setEnabled(state);
return;
}