pax_global_header00006660000000000000000000000064131713270270014515gustar00rootroot0000000000000052 comment=abd4d43c443e35800b4d1f18a9a51c85cfcb2c83 nm-tray-0.3.0/000077500000000000000000000000001317132702700131045ustar00rootroot00000000000000nm-tray-0.3.0/.gitignore000066400000000000000000000000071317132702700150710ustar00rootroot00000000000000build/ nm-tray-0.3.0/CMakeLists.txt000066400000000000000000000047541317132702700156560ustar00rootroot00000000000000project(nm-tray) cmake_minimum_required(VERSION 3.1.0 FATAL_ERROR) set(NM_TRAY_VERSION "0.3.0") set(QT_MIN_VERSION "5.4.0") set(CMAKE_AUTOMOC on) set(CMAKE_AUTOUIC on) set(CMAKE_INCLUDE_CURRENT_DIR ON) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra") find_package(Qt5 ${QT_MIN_VERSION} REQUIRED COMPONENTS Widgets Gui Network DBus LinguistTools ) find_package(KF5NetworkManagerQt "5.24.0" REQUIRED) include(GNUInstallDirs) set(TRANSLATION_DIR "${CMAKE_INSTALL_FULL_DATADIR}/${PROJECT_NAME}") add_definitions(-DQT_NO_SIGNALS_SLOTS_KEYWORDS "-DTRANSLATION_DIR=\"${TRANSLATION_DIR}\"" "-DNM_TRAY_VERSION=\"${NM_TRAY_VERSION}\"") if (NOT NM_TRAY_XDG_AUTOSTART_DIR) #Note: we need the default to be /etc... (not the ${CMAKE_INSTALL_PREFIX}/etc) set(NM_TRAY_XDG_AUTOSTART_DIR "/${CMAKE_INSTALL_SYSCONFDIR}/xdg/autostart") endif () message(STATUS "Translations destination dir: ${TRANSLATION_DIR}") message(STATUS "Autostart .desktop entry destination dir: ${NM_TRAY_XDG_AUTOSTART_DIR}\n (can be overriden by setting the NM_TRAY_XDG_AUTOSTART_DIR cmake variable)") set(SRCS src/log.cpp src/icons.cpp src/nmmodel.cpp src/nmproxy.cpp src/connectioninfo.cpp src/nmlist.cpp src/menuview.cpp src/windowmenu.cpp src/tray.cpp src/translate.cpp src/main.cpp ) file(GLOB TSS "translations/${PROJECT_NAME}_*.ts") if (UPDATE_TRANSLATIONS) message(WARNING "!! Disable updating translation after make (-DUPDATE_TRANSLATIONS=no) to avoid 'make clean' delete them !!") qt5_create_translation(QMS "translations/${PROJECT_NAME}.ts" ${TSS} "src") else () qt5_add_translation(QMS ${TSS}) endif() qt5_add_dbus_interface(SRCS dbus/org.freedesktop.Notifications.xml dbus/org.freedesktop.Notifications ) add_executable(nm-tray ${SRCS} ${QMS} ) set_property(TARGET nm-tray PROPERTY CXX_STANDARD 11) set_property(TARGET nm-tray PROPERTY CXX_STANDARD_REQUIRED on) target_link_libraries(nm-tray Qt5::Widgets Qt5::Gui KF5::NetworkManagerQt ) if (WITH_MODEMMANAGER_SUPPORT) target_link_libraries(nm-tray KF5::ModemManagerQt) endif() install(TARGETS nm-tray RUNTIME DESTINATION "${CMAKE_INSTALL_FULL_BINDIR}" COMPONENT runtime) install(FILES ${QMS} DESTINATION "${TRANSLATION_DIR}" COMPONENT translations) install(FILES "resources/nm-tray.desktop" DESTINATION "${CMAKE_INSTALL_FULL_DATAROOTDIR}/applications" COMPONENT data) install(FILES "resources/nm-tray-autostart.desktop" DESTINATION "${NM_TRAY_XDG_AUTOSTART_DIR}" COMPONENT data) nm-tray-0.3.0/COPYING000066400000000000000000000432541317132702700141470ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. nm-tray-0.3.0/README.md000066400000000000000000000022471317132702700143700ustar00rootroot00000000000000# nm-tray **nm-tray** is a simple [NetworkManager](https://wiki.gnome.org/Projects/NetworkManager) front end with information icon residing in system tray (like e.g. nm-applet). It's a pure Qt application. For interaction with *NetworkManager* it uses API provided by [**KF5::NetworkManagerQt**](https://projects.kde.org/projects/frameworks/networkmanager-qt) -> plain DBus communication. **! This is work in progress and there are still many TODOs and debugs all around in the code !** ## License This software is licensed under [GNU GPLv2 or later](https://www.gnu.org/licenses/old-licenses/gpl-2.0.html) ## Build example git clone https://github.com/palinek/nm-tray.git cd nm-tray mkdir build cd build cmake .. make ./nm-tray ## Packages For [arch users](https://www.archlinux.org/) there is an AUR packge [nm-tray-git](https://aur.archlinux.org/packages/nm-tray-git/) (thanks to [pmattern](https://github.com/pmattern)). For [openSUSE users](https://www.opensuse.org/) there is a [package](https://build.opensuse.org/package/show/X11:LXQt:git/nm-tray) in the [X11:LXQt:git](https://build.opensuse.org/project/show/X11:LXQt:git) devel project of OBS. nm-tray-0.3.0/dbus/000077500000000000000000000000001317132702700140415ustar00rootroot00000000000000nm-tray-0.3.0/dbus/org.freedesktop.Notifications.xml000066400000000000000000000027501317132702700225000ustar00rootroot00000000000000 nm-tray-0.3.0/resources/000077500000000000000000000000001317132702700151165ustar00rootroot00000000000000nm-tray-0.3.0/resources/nm-tray-autostart.desktop000066400000000000000000000001661317132702700221270ustar00rootroot00000000000000[Desktop Entry] Type=Application Name=nm-tray TryExec=nm-tray Exec=nm-tray NotShowIn=KDE;GNOME; X-LXQt-Need-Tray=true nm-tray-0.3.0/resources/nm-tray.desktop000066400000000000000000000002731317132702700201020ustar00rootroot00000000000000[Desktop Entry] Type=Application Name=nm-tray Comment=NetworkManager frontend (tray icon) Icon=network-transmit TryExec=nm-tray Exec=nm-tray Categories=Network;System;Monitor;Qt;TrayIcon nm-tray-0.3.0/src/000077500000000000000000000000001317132702700136735ustar00rootroot00000000000000nm-tray-0.3.0/src/connectioninfo.cpp000066400000000000000000000076641317132702700174270ustar00rootroot00000000000000/*COPYRIGHT_HEADER This file is a part of nm-tray. Copyright (c) 2015~now Palo Kisa nm-tray is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. COPYRIGHT_HEADER*/ #include "connectioninfo.h" #include "ui_connectioninfo.h" #include "nmproxy.h" #include #include #include #include ConnectionInfo::ConnectionInfo(NmModel * model, QWidget *parent) : QDialog{parent} , ui{new Ui::ConnectionInfo} , mModel{model} , mActive{new NmProxy} , mSorted{new QSortFilterProxyModel} { setAttribute(Qt::WA_DeleteOnClose); ui->setupUi(this); mActive->setNmModel(mModel, NmModel::ActiveConnectionType); mSorted->setSortCaseSensitivity(Qt::CaseInsensitive); mSorted->sort(0); mSorted->setSourceModel(mActive.data()); for (int i = 0, row_cnt = mSorted->rowCount(); i < row_cnt; ++i) { addTab(mSorted->index(i, 0)); } connect(mSorted.data(), &QAbstractItemModel::rowsInserted, [this] (QModelIndex const & parent, int first, int last) { ui->tabWidget->setUpdatesEnabled(false); for (int i = first; i <= last; ++i) addTab(mSorted->index(i, 0, parent)); ui->tabWidget->setUpdatesEnabled(true); }); connect(mSorted.data(), &QAbstractItemModel::rowsAboutToBeRemoved, [this] (QModelIndex const & parent, int first, int last) { ui->tabWidget->setUpdatesEnabled(false); for (int i = first; i <= last; ++i) removeTab(mSorted->index(i, 0, parent)); ui->tabWidget->setUpdatesEnabled(true); }); connect(mSorted.data(), &QAbstractItemModel::dataChanged, [this] (const QModelIndex & topLeft, const QModelIndex & bottomRight, const QVector & /*roles*/) { ui->tabWidget->setUpdatesEnabled(false); for (auto const & i : QItemSelection{topLeft, bottomRight}.indexes()) changeTab(i); ui->tabWidget->setUpdatesEnabled(true); }); } ConnectionInfo::~ConnectionInfo() { } void ConnectionInfo::addTab(QModelIndex const & index) { QScrollArea * content = new QScrollArea; QLabel * l = new QLabel{mSorted->data(index, NmModel::ActiveConnectionInfoRole).toString()}; content->setWidget(l); //QTabWidget takes ownership of the page (if we will not take it back) ui->tabWidget->insertTab(index.row(), content, mSorted->data(index, NmModel::IconRole).value(), mSorted->data(index, NmModel::NameRole).toString()); } void ConnectionInfo::removeTab(QModelIndex const & index) { const int i = index.row(); QWidget * w = ui->tabWidget->widget(i); ui->tabWidget->removeTab(i); w->deleteLater(); } void ConnectionInfo::changeTab(QModelIndex const & index) { const int i = index.row(); QScrollArea * content = qobject_cast(ui->tabWidget->widget(i)); Q_ASSERT(nullptr != content); // Note: the text is HTML formatted and the QLabel probably creates some DOM internal represntation. // Should the DOM structure change, the QLabel will not update correctly upon the plain setText() content->setWidget(new QLabel{mSorted->data(index, NmModel::ActiveConnectionInfoRole).toString()}); ui->tabWidget->tabBar()->setTabText(i, mSorted->data(index, NmModel::NameRole).toString()); ui->tabWidget->tabBar()->setTabIcon(i, mSorted->data(index, NmModel::IconRole).value()); } nm-tray-0.3.0/src/connectioninfo.h000066400000000000000000000027111317132702700170600ustar00rootroot00000000000000/*COPYRIGHT_HEADER This file is a part of nm-tray. Copyright (c) 2015~now Palo Kisa nm-tray is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. COPYRIGHT_HEADER*/ #ifndef CONNECTIONINFO_H #define CONNECTIONINFO_H #include namespace Ui { class ConnectionInfo; } class NmModel; class NmProxy; class QSortFilterProxyModel; class ConnectionInfo : public QDialog { Q_OBJECT public: explicit ConnectionInfo(NmModel * model, QWidget *parent = nullptr); ~ConnectionInfo(); private: void addTab(QModelIndex const & index); void removeTab(QModelIndex const & index); void changeTab(QModelIndex const & index); private: QScopedPointer ui; NmModel * mModel; QScopedPointer mActive; QScopedPointer mSorted; }; #endif // CONNECTIONINFO_H nm-tray-0.3.0/src/connectioninfo.ui000066400000000000000000000014161317132702700172470ustar00rootroot00000000000000 ConnectionInfo 0 0 570 614 Connection information -1 32 32 nm-tray-0.3.0/src/icons.cpp000066400000000000000000000120101317132702700155040ustar00rootroot00000000000000/*COPYRIGHT_HEADER This file is a part of nm-tray. Copyright (c) 2015~now Palo Kisa nm-tray is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. COPYRIGHT_HEADER*/ #include "icons.h" #include #include namespace icons { QIcon getIcon(Icon ico) { static const QStringList i_empty; QStringList const * icon_names = &i_empty; switch (ico) { case NETWORK_OFFLINE: static const QStringList i_network_offline = { QStringLiteral("network-offline-symbolic") }; icon_names = &i_network_offline; break; case NETWORK_WIRED: static const QStringList i_network_wired = { QStringLiteral("network-wired-symbolic") }; icon_names = &i_network_wired; break; case NETWORK_WIRED_DISCONNECTED: static const QStringList i_network_wired_disconnected = { QStringLiteral("network-wired-disconnected-symbolic") }; icon_names = &i_network_wired_disconnected; break; case NETWORK_WIFI_DISCONNECTED: static const QStringList i_wifi_disconnected = { QStringLiteral("network-wireless-disconnected-symbolic") }; icon_names = &i_wifi_disconnected; break; case NETWORK_WIFI_ACQUIRING: static const QStringList i_wifi_acquiring = { QStringLiteral("network-wireless-acquiring-symbolic") }; icon_names = &i_wifi_acquiring; break; case NETWORK_WIFI_NONE: static const QStringList i_wifi_none = { QStringLiteral("network-wireless-signal-none-symbolic"), QStringLiteral("network-wireless-connected-00-symbolic") }; icon_names = &i_wifi_none; break; case NETWORK_WIFI_WEAK: static const QStringList i_wifi_weak = { QStringLiteral("network-wireless-signal-weak-symbolic"), QStringLiteral("network-wireless-connected-25-symbolic") }; icon_names = &i_wifi_weak; break; case NETWORK_WIFI_OK: static const QStringList i_wifi_ok = { QStringLiteral("network-wireless-signal-ok-symbolic"), QStringLiteral("network-wireless-connected-50-symbolic") }; icon_names = &i_wifi_ok; break; case NETWORK_WIFI_GOOD: static const QStringList i_wifi_good = { QStringLiteral("network-wireless-signal-good-symbolic"), QStringLiteral("network-wireless-connected-75-symbolic") }; icon_names = &i_wifi_good; break; case NETWORK_WIFI_EXCELENT: static const QStringList i_wifi_excelent = { QStringLiteral("network-wireless-signal-excellent-symbolic"), QStringLiteral("network-wireless-connected-100-symbolic") }; icon_names = &i_wifi_excelent; break; case NETWORK_VPN: static const QStringList i_network_vpn = { QStringLiteral("network-vpn") }; icon_names = &i_network_vpn; break; case SECURITY_LOW: static const QStringList i_security_low = { QStringLiteral("security-low-symbolic") }; icon_names = &i_security_low; break; case SECURITY_HIGH: static const QStringList i_security_high = { QStringLiteral("security-high-symbolic") }; icon_names = &i_security_high; break; case PREFERENCES_NETWORK: static const QStringList i_preferences_network = { QStringLiteral("preferences-system-network") }; icon_names = &i_preferences_network; break; }; for (auto const & name : *icon_names) { QIcon icon{QIcon::fromTheme(name)}; if (!icon.isNull()) return icon; } //TODO: fallback!?! return QIcon::fromTheme(QStringLiteral("network-transmit")); } Icon wifiSignalIcon(const int signal) { if (0 >= signal) return icons::NETWORK_WIFI_NONE; else if (25 >= signal) return icons::NETWORK_WIFI_WEAK; else if (50 >= signal) return icons::NETWORK_WIFI_OK; else if (75 >= signal) return icons::NETWORK_WIFI_GOOD; else return icons::NETWORK_WIFI_EXCELENT; } } nm-tray-0.3.0/src/icons.h000066400000000000000000000026401317132702700151610ustar00rootroot00000000000000/*COPYRIGHT_HEADER This file is a part of nm-tray. Copyright (c) 2015~now Palo Kisa nm-tray is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. COPYRIGHT_HEADER*/ #if !defined(ICONS_H) #define ICONS_H #include namespace icons { enum Icon { NETWORK_OFFLINE , NETWORK_WIRED , NETWORK_WIRED_DISCONNECTED , NETWORK_WIFI_ACQUIRING , NETWORK_WIFI_NONE , NETWORK_WIFI_WEAK , NETWORK_WIFI_OK , NETWORK_WIFI_GOOD , NETWORK_WIFI_EXCELENT , NETWORK_WIFI_DISCONNECTED , NETWORK_VPN , SECURITY_LOW , SECURITY_HIGH , PREFERENCES_NETWORK }; QIcon getIcon(Icon ico); Icon wifiSignalIcon(const int signal); } #endif nm-tray-0.3.0/src/log.cpp000066400000000000000000000017131317132702700151620ustar00rootroot00000000000000/*COPYRIGHT_HEADER This file is a part of nm-tray. Copyright (c) 2015~now Palo Kisa nm-tray is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. COPYRIGHT_HEADER*/ #include "log.h" #include #if defined(NDEBUG) Q_LOGGING_CATEGORY(NM_TRAY, "nm-tray", QtInfoMsg) #else Q_LOGGING_CATEGORY(NM_TRAY, "nm-tray") #endif nm-tray-0.3.0/src/log.h000066400000000000000000000016371317132702700146340ustar00rootroot00000000000000/*COPYRIGHT_HEADER This file is a part of nm-tray. Copyright (c) 2015~now Palo Kisa nm-tray is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. COPYRIGHT_HEADER*/ #if !defined(LOG_H) #define LOG_H #include Q_DECLARE_LOGGING_CATEGORY(NM_TRAY) #endif //LOG_H nm-tray-0.3.0/src/main.cpp000066400000000000000000000022721317132702700153260ustar00rootroot00000000000000/*COPYRIGHT_HEADER This file is a part of nm-tray. Copyright (c) 2015~now Palo Kisa nm-tray is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. COPYRIGHT_HEADER*/ #include #include "tray.h" #include "icons.h" int main(int argc, char * argv[]) { QApplication app{argc, argv}; app.setOrganizationName(QStringLiteral("nm-tray")); app.setApplicationName(QStringLiteral("nm-tray")); app.setWindowIcon(icons::getIcon(icons::PREFERENCES_NETWORK)); app.setQuitOnLastWindowClosed(false); Tray tray; return app.exec(); } nm-tray-0.3.0/src/menuview.cpp000066400000000000000000000114571317132702700162460ustar00rootroot00000000000000/*COPYRIGHT_HEADER This file is a part of nm-tray. Copyright (c) 2016~now Palo Kisa nm-tray is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. COPYRIGHT_HEADER*/ #include "menuview.h" #include "nmmodel.h" #include #include #include #include #include #include #include namespace { class SingleActivateStyle : public QProxyStyle { public: using QProxyStyle::QProxyStyle; virtual int styleHint(StyleHint hint, const QStyleOption * option = 0, const QWidget * widget = 0, QStyleHintReturn * returnData = 0) const override { if(hint == QStyle::SH_ItemView_ActivateItemOnSingleClick) return 1; return QProxyStyle::styleHint(hint, option, widget, returnData); } }; class MultiIconDelegate : public QStyledItemDelegate { public: using QStyledItemDelegate::QStyledItemDelegate; void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override { Q_ASSERT(index.isValid()); QStyleOptionViewItem opt = option; initStyleOption(&opt, index); //add the security overlay icon QIcon sec_icon = qvariant_cast(index.data(NmModel::IconSecurityRole)); if (!sec_icon.isNull()) { QPixmap res_pixmap = opt.icon.pixmap(opt.decorationSize); QPainter p{&res_pixmap}; QSize sec_size = res_pixmap.size(); sec_size /= 2; QPoint sec_pos = res_pixmap.rect().bottomRight(); sec_pos -= QPoint{sec_size.width(), sec_size.height()}; p.drawPixmap(sec_pos, sec_icon.pixmap(sec_size)); opt.icon = QIcon{res_pixmap}; } QStyle *style = option.widget ? option.widget->style() : QApplication::style(); style->drawControl(QStyle::CE_ItemViewItem, &opt, painter, option.widget); } }; } MenuView::MenuView(QAbstractItemModel * model, QWidget * parent /*= nullptr*/) : QListView(parent) , mProxy{new QSortFilterProxyModel{this}} , mMaxItemsToShow(10) { setEditTriggers(NoEditTriggers); setSizeAdjustPolicy(AdjustToContents); setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); setSelectionBehavior(SelectRows); setSelectionMode(NoSelection); setFrameShape(QFrame::HLine); setFrameShadow(QFrame::Plain); setStyle(new SingleActivateStyle); mProxy->setSourceModel(model); mProxy->setDynamicSortFilter(true); mProxy->setFilterRole(Qt::DisplayRole); mProxy->setFilterCaseSensitivity(Qt::CaseInsensitive); mProxy->setSortRole(Qt::DisplayRole); mProxy->setSortCaseSensitivity(Qt::CaseInsensitive); mProxy->sort(0); { QScopedPointer guard{selectionModel()}; setModel(mProxy); } { QScopedPointer guard{itemDelegate()}; setItemDelegate(new MultiIconDelegate{this}); } } void MenuView::setFilter(QString const & filter) { mProxy->setFilterFixedString(filter); const int count = mProxy->rowCount(); if (0 < count) { if (count > mMaxItemsToShow) { setCurrentIndex(mProxy->index(mMaxItemsToShow - 1, 0)); verticalScrollBar()->triggerAction(QScrollBar::SliderToMinimum); } else { setCurrentIndex(mProxy->index(count - 1, 0)); } } } void MenuView::setMaxItemsToShow(int max) { mMaxItemsToShow = max; } void MenuView::activateCurrent() { QModelIndex const index = currentIndex(); if (index.isValid()) emit activated(index); } QSize MenuView::viewportSizeHint() const { const int count = mProxy->rowCount(); QSize s{0, 0}; if (0 < count) { const bool scrollable = mMaxItemsToShow < count; s.setWidth(sizeHintForColumn(0) + (scrollable ? verticalScrollBar()->sizeHint().width() : 0)); s.setHeight(sizeHintForRow(0) * (scrollable ? mMaxItemsToShow : count)); } return s; } QSize MenuView::minimumSizeHint() const { return QSize{0, 0}; } nm-tray-0.3.0/src/menuview.h000066400000000000000000000032441317132702700157060ustar00rootroot00000000000000/*COPYRIGHT_HEADER This file is a part of nm-tray. Copyright (c) 2016~now Palo Kisa nm-tray is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. COPYRIGHT_HEADER*/ #if !defined(MENU_VIEW_H) #define MENU_VIEW_H #include class QAbstractItemModel; class QSortFilterProxyModel; class MenuView : public QListView { Q_OBJECT public: MenuView(QAbstractItemModel * model, QWidget * parent = nullptr); /*! \brief Sets the filter for entries to be presented */ void setFilter(QString const & filter); /*! \brief Set the maximum number of items/results to show */ void setMaxItemsToShow(int max); /*! \brief Set the maximum width of item to show */ void setMaxItemWidth(int max); public Q_SLOTS: /*! \brief Trigger action on currently active item */ void activateCurrent(); protected: virtual QSize viewportSizeHint() const override; virtual QSize minimumSizeHint() const override; private: QSortFilterProxyModel * mProxy; int mMaxItemsToShow; }; #endif //MENU_VIEW_H nm-tray-0.3.0/src/nmlist.cpp000066400000000000000000000063431317132702700157130ustar00rootroot00000000000000/*COPYRIGHT_HEADER This file is a part of nm-tray. Copyright (c) 2015~now Palo Kisa nm-tray is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. COPYRIGHT_HEADER*/ #include "nmlist.h" #include "ui_nmlist.h" #include "nmmodel.h" #include "nmproxy.h" #include template void installDblClick(QAbstractItemView * view, QAbstractItemModel * m) { T * net_model = qobject_cast(m); if (net_model) { QAbstractProxyModel * proxy = qobject_cast(view->model()); Q_ASSERT(nullptr != proxy && proxy->sourceModel() == net_model); QObject::connect(view, &QAbstractItemView::doubleClicked, [net_model, proxy] (QModelIndex const & i) { QModelIndex source_i = proxy->mapToSource(i); switch (static_cast(net_model->data(source_i, NmModel::ItemTypeRole).toInt())) { case NmModel::ActiveConnectionType: net_model->deactivateConnection(source_i); break; case NmModel::WifiNetworkType: case NmModel::ConnectionType: net_model->activateConnection(source_i); break; default: //do nothing break; } }); } } NmList::NmList(QString const & title, QAbstractItemModel * m, QWidget *parent) : QDialog(parent) , ui(new Ui::NmList) { ui->setupUi(this); setWindowTitle(title); Q_ASSERT(qobject_cast(m)); QSortFilterProxyModel * proxy_sort = new QSortFilterProxyModel{this}; proxy_sort->setSortCaseSensitivity(Qt::CaseInsensitive); proxy_sort->sort(0); proxy_sort->setSourceModel(m); ui->treeView->setModel(proxy_sort); installDblClick(ui->treeView, m); NmProxy * proxy = new NmProxy(this); proxy->setNmModel(qobject_cast(m), NmModel::ActiveConnectionType); proxy_sort = new QSortFilterProxyModel{this}; proxy_sort->setSortCaseSensitivity(Qt::CaseInsensitive); proxy_sort->sort(0); proxy_sort->setSourceModel(proxy); ui->listActive->setModel(proxy_sort); installDblClick(ui->listActive, proxy); proxy = new NmProxy(this); proxy->setNmModel(qobject_cast(m), NmModel::WifiNetworkType); proxy_sort = new QSortFilterProxyModel{this}; proxy_sort->setSortCaseSensitivity(Qt::CaseInsensitive); proxy_sort->sort(0); proxy_sort->setSourceModel(proxy); ui->listWifi->setModel(proxy_sort); installDblClick(ui->listWifi, proxy); } NmList::~NmList() { delete ui; } nm-tray-0.3.0/src/nmlist.h000066400000000000000000000021651317132702700153560ustar00rootroot00000000000000/*COPYRIGHT_HEADER This file is a part of nm-tray. Copyright (c) 2015~now Palo Kisa nm-tray is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. COPYRIGHT_HEADER*/ #ifndef NMLIST_H #define NMLIST_H #include namespace Ui { class NmList; } class QAbstractItemModel; class NmList : public QDialog { Q_OBJECT public: explicit NmList(QString const & title, QAbstractItemModel * m, QWidget *parent = nullptr); ~NmList(); private: Ui::NmList *ui; }; #endif // NMLIST_H nm-tray-0.3.0/src/nmlist.ui000066400000000000000000000025321317132702700155420ustar00rootroot00000000000000 NmList 0 0 565 507 Dialog All information Active connections Available wireless false nm-tray-0.3.0/src/nmmodel.cpp000066400000000000000000001776751317132702700160610ustar00rootroot00000000000000/*COPYRIGHT_HEADER This file is a part of nm-tray. Copyright (c) 2015~now Palo Kisa nm-tray is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. COPYRIGHT_HEADER*/ #include "nmmodel.h" #include "nmmodel_p.h" #include "icons.h" #include "log.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace { NetworkManager::ConnectionSettings::Ptr assembleWpaXPskSettings(const NetworkManager::AccessPoint::Ptr accessPoint) { //TODO: enhance getting the password from user bool ok; QString password = QInputDialog::getText(nullptr, NmModel::tr("nm-tray - wireless password") , NmModel::tr("Password is needed for connection to '%1':").arg(accessPoint->ssid()) , QLineEdit::Password, QString(), &ok); if (!ok) return NetworkManager::ConnectionSettings::Ptr{nullptr}; NetworkManager::ConnectionSettings::Ptr settings{new NetworkManager::ConnectionSettings{NetworkManager::ConnectionSettings::Wireless}}; settings->setId(accessPoint->ssid()); settings->setUuid(NetworkManager::ConnectionSettings::createNewUuid()); settings->setAutoconnect(true); //Note: workaround for wrongly (randomly) initialized gateway-ping-timeout settings->setGatewayPingTimeout(0); NetworkManager::WirelessSetting::Ptr wifi_sett = settings->setting(NetworkManager::Setting::Wireless).dynamicCast(); wifi_sett->setInitialized(true); wifi_sett->setSsid(accessPoint->ssid().toUtf8()); wifi_sett->setSecurity("802-11-wireless-security"); NetworkManager::WirelessSecuritySetting::Ptr security_sett = settings->setting(NetworkManager::Setting::WirelessSecurity).dynamicCast(); security_sett->setInitialized(true); if (NetworkManager::AccessPoint::Adhoc == accessPoint->mode()) { wifi_sett->setMode(NetworkManager::WirelessSetting::Adhoc); security_sett->setKeyMgmt(NetworkManager::WirelessSecuritySetting::WpaNone); } else { security_sett->setKeyMgmt(NetworkManager::WirelessSecuritySetting::WpaPsk); } security_sett->setPsk(password); return settings; } } NmModelPrivate::NmModelPrivate() { insertActiveConnections(); insertConnections(); insertDevices(); insertWifiNetworks(); //initialize NetworkManager signals connect(NetworkManager::notifier(), &NetworkManager::Notifier::deviceAdded, this, &NmModelPrivate::onDeviceAdded); connect(NetworkManager::notifier(), &NetworkManager::Notifier::deviceRemoved, this, &NmModelPrivate::onDeviceRemoved); connect(NetworkManager::notifier(), &NetworkManager::Notifier::activeConnectionAdded, this, &NmModelPrivate::onActiveConnectionAdded); connect(NetworkManager::notifier(), &NetworkManager::Notifier::activeConnectionRemoved, this, &NmModelPrivate::onActiveConnectionRemoved); connect(NetworkManager::settingsNotifier(), &NetworkManager::SettingsNotifier::connectionAdded, this, &NmModelPrivate::onConnectionAdded); connect(NetworkManager::settingsNotifier(), &NetworkManager::SettingsNotifier::connectionRemoved, this, static_cast(&NmModelPrivate::onConnectionRemoved)); // Note: the connectionRemoved is never emitted in case network-manager service stop, // we need remove the connections manually. connect(NetworkManager::notifier(), &NetworkManager::Notifier::serviceDisappeared, this, &NmModelPrivate::clearConnections); //qCDebug(NM_TRAY) << mActiveConns.size() << mConnections.size() << mDevices.size(); } NmModelPrivate::~NmModelPrivate() { } void NmModelPrivate::removeActiveConnection(int pos) { //active connections signals NetworkManager::ActiveConnection::Ptr conn = mActiveConns.takeAt(pos); conn->disconnect(this); } void NmModelPrivate::clearActiveConnections() { while (0 < mActiveConns.size()) removeActiveConnection(0); } void NmModelPrivate::addActiveConnection(NetworkManager::ActiveConnection::Ptr conn) { mActiveConns.push_back(conn); connect(conn.data(), &NetworkManager::ActiveConnection::connectionChanged, this, &NmModelPrivate::onActiveConnectionUpdated); connect(conn.data(), &NetworkManager::ActiveConnection::default4Changed, this, &NmModelPrivate::onActiveConnectionUpdated); connect(conn.data(), &NetworkManager::ActiveConnection::default6Changed, this, &NmModelPrivate::onActiveConnectionUpdated); connect(conn.data(), &NetworkManager::ActiveConnection::dhcp4ConfigChanged, this, &NmModelPrivate::onActiveConnectionUpdated); connect(conn.data(), &NetworkManager::ActiveConnection::dhcp6ConfigChanged, this, &NmModelPrivate::onActiveConnectionUpdated); connect(conn.data(), &NetworkManager::ActiveConnection::ipV4ConfigChanged, this, &NmModelPrivate::onActiveConnectionUpdated); connect(conn.data(), &NetworkManager::ActiveConnection::ipV6ConfigChanged, this, &NmModelPrivate::onActiveConnectionUpdated); connect(conn.data(), &NetworkManager::ActiveConnection::idChanged, this, &NmModelPrivate::onActiveConnectionUpdated); connect(conn.data(), &NetworkManager::ActiveConnection::typeChanged, this, &NmModelPrivate::onActiveConnectionUpdated); connect(conn.data(), &NetworkManager::ActiveConnection::masterChanged, this, &NmModelPrivate::onActiveConnectionUpdated); connect(conn.data(), &NetworkManager::ActiveConnection::specificObjectChanged, this, &NmModelPrivate::onActiveConnectionUpdated); connect(conn.data(), &NetworkManager::ActiveConnection::stateChanged, this, &NmModelPrivate::onActiveConnectionUpdated); connect(conn.data(), &NetworkManager::ActiveConnection::vpnChanged, this, &NmModelPrivate::onActiveConnectionUpdated); connect(conn.data(), &NetworkManager::ActiveConnection::uuidChanged, this, &NmModelPrivate::onActiveConnectionUpdated); connect(conn.data(), &NetworkManager::ActiveConnection::devicesChanged, this, &NmModelPrivate::onActiveConnectionUpdated); if (conn->vpn()) { connect(qobject_cast(conn.data()), &NetworkManager::VpnConnection::bannerChanged, this, &NmModelPrivate::onActiveConnectionUpdated); connect(qobject_cast(conn.data()), &NetworkManager::VpnConnection::stateChanged, this, &NmModelPrivate::onActiveConnectionUpdated); } } void NmModelPrivate::insertActiveConnections() { for (auto const & conn : NetworkManager::activeConnections()) addActiveConnection(conn); } void NmModelPrivate::removeConnection(int pos) { //connections signals NetworkManager::Connection::Ptr conn = mConnections.takeAt(pos); conn->disconnect(this); } void NmModelPrivate::clearConnections() { while (0 < mConnections.size()) removeConnection(0); } void NmModelPrivate::addConnection(NetworkManager::Connection::Ptr conn) { mConnections.push_back(conn); //connections signals connect(conn.data(), &NetworkManager::Connection::updated, this, &NmModelPrivate::onConnectionUpdated); connect(conn.data(), &NetworkManager::Connection::removed, this, static_cast(&NmModelPrivate::onConnectionRemoved)); } void NmModelPrivate::insertConnections() { for (auto const & conn : NetworkManager::listConnections()) addConnection(conn); } void NmModelPrivate::removeDevice(int pos) { //connections signals NetworkManager::Device::Ptr device = mDevices.takeAt(pos); device->disconnect(this); } void NmModelPrivate::clearDevices() { while (0 < mDevices.size()) removeDevice(0); } void NmModelPrivate::addDevice(NetworkManager::Device::Ptr device) { mDevices.push_back(device); //device signals connect(device.data(), &NetworkManager::Device::stateChanged, this, &NmModelPrivate::onDeviceUpdated); connect(device.data(), &NetworkManager::Device::activeConnectionChanged, this, &NmModelPrivate::onDeviceUpdated); connect(device.data(), &NetworkManager::Device::autoconnectChanged, this, &NmModelPrivate::onDeviceUpdated); connect(device.data(), &NetworkManager::Device::availableConnectionChanged, this, &NmModelPrivate::onDeviceUpdated); connect(device.data(), &NetworkManager::Device::availableConnectionAppeared, this, &NmModelPrivate::onDeviceUpdated); connect(device.data(), &NetworkManager::Device::availableConnectionDisappeared, this, &NmModelPrivate::onDeviceUpdated); connect(device.data(), &NetworkManager::Device::capabilitiesChanged, this, &NmModelPrivate::onDeviceUpdated); connect(device.data(), &NetworkManager::Device::dhcp4ConfigChanged, this, &NmModelPrivate::onDeviceUpdated); connect(device.data(), &NetworkManager::Device::dhcp6ConfigChanged, this, &NmModelPrivate::onDeviceUpdated); connect(device.data(), &NetworkManager::Device::driverChanged, this, &NmModelPrivate::onDeviceUpdated); connect(device.data(), &NetworkManager::Device::driverVersionChanged, this, &NmModelPrivate::onDeviceUpdated); connect(device.data(), &NetworkManager::Device::firmwareMissingChanged, this, &NmModelPrivate::onDeviceUpdated); connect(device.data(), &NetworkManager::Device::firmwareVersionChanged, this, &NmModelPrivate::onDeviceUpdated); connect(device.data(), &NetworkManager::Device::interfaceNameChanged, this, &NmModelPrivate::onDeviceUpdated); connect(device.data(), &NetworkManager::Device::ipV4AddressChanged, this, &NmModelPrivate::onDeviceUpdated); connect(device.data(), &NetworkManager::Device::ipV4ConfigChanged, this, &NmModelPrivate::onDeviceUpdated); connect(device.data(), &NetworkManager::Device::ipV6ConfigChanged, this, &NmModelPrivate::onDeviceUpdated); connect(device.data(), &NetworkManager::Device::ipInterfaceChanged, this, &NmModelPrivate::onDeviceUpdated); connect(device.data(), &NetworkManager::Device::managedChanged, this, &NmModelPrivate::onDeviceUpdated); connect(device.data(), &NetworkManager::Device::physicalPortIdChanged, this, &NmModelPrivate::onDeviceUpdated); connect(device.data(), &NetworkManager::Device::mtuChanged, this, &NmModelPrivate::onDeviceUpdated); connect(device.data(), &NetworkManager::Device::nmPluginMissingChanged, this, &NmModelPrivate::onDeviceUpdated); connect(device.data(), &NetworkManager::Device::meteredChanged, this, &NmModelPrivate::onDeviceUpdated); connect(device.data(), &NetworkManager::Device::connectionStateChanged, this, &NmModelPrivate::onDeviceUpdated); connect(device.data(), &NetworkManager::Device::stateReasonChanged, this, &NmModelPrivate::onDeviceUpdated); connect(device.data(), &NetworkManager::Device::udiChanged, this, &NmModelPrivate::onDeviceUpdated); switch (device->type()) { case NetworkManager::Ethernet: connect(qobject_cast(device.data()), &NetworkManager::WiredDevice::bitRateChanged, this, &NmModelPrivate::onDeviceUpdated); connect(qobject_cast(device.data()), &NetworkManager::WiredDevice::carrierChanged, this, &NmModelPrivate::onDeviceUpdated); connect(qobject_cast(device.data()), &NetworkManager::WiredDevice::hardwareAddressChanged, this, &NmModelPrivate::onDeviceUpdated); connect(qobject_cast(device.data()), &NetworkManager::WiredDevice::permanentHardwareAddressChanged, this, &NmModelPrivate::onDeviceUpdated); break; case NetworkManager::Device::Wifi: connect(qobject_cast(device.data()), &NetworkManager::WirelessDevice::bitRateChanged, this, &NmModelPrivate::onDeviceUpdated); connect(qobject_cast(device.data()), &NetworkManager::WirelessDevice::activeAccessPointChanged, this, &NmModelPrivate::onDeviceUpdated); connect(qobject_cast(device.data()), &NetworkManager::WirelessDevice::modeChanged, this, &NmModelPrivate::onDeviceUpdated); connect(qobject_cast(device.data()), &NetworkManager::WirelessDevice::wirelessCapabilitiesChanged, this, &NmModelPrivate::onDeviceUpdated); connect(qobject_cast(device.data()), &NetworkManager::WirelessDevice::hardwareAddressChanged, this, &NmModelPrivate::onDeviceUpdated); connect(qobject_cast(device.data()), &NetworkManager::WirelessDevice::permanentHardwareAddressChanged, this, &NmModelPrivate::onDeviceUpdated); connect(qobject_cast(device.data()), &NetworkManager::WirelessDevice::wirelessPropertiesChanged, this, &NmModelPrivate::onDeviceUpdated); connect(qobject_cast(device.data()), &NetworkManager::WirelessDevice::accessPointAppeared, this, &NmModelPrivate::onDeviceUpdated); connect(qobject_cast(device.data()), &NetworkManager::WirelessDevice::accessPointDisappeared, this, &NmModelPrivate::onDeviceUpdated); connect(qobject_cast(device.data()), &NetworkManager::WirelessDevice::networkAppeared, this, &NmModelPrivate::onWifiNetworkAppeared); connect(qobject_cast(device.data()), &NetworkManager::WirelessDevice::networkDisappeared, this, &NmModelPrivate::onWifiNetworkDisappeared); break; default: //TODO: other device types! break; } } void NmModelPrivate::insertDevices() { for (auto const & device : NetworkManager::networkInterfaces()) addDevice(device); } void NmModelPrivate::removeWifiNetwork(int pos) { //network signals NetworkManager::WirelessNetwork::Ptr net = mWifiNets.takeAt(pos); net->disconnect(this); } void NmModelPrivate::clearWifiNetworks() { while (0 < mWifiNets.size()) removeWifiNetwork(0); } void NmModelPrivate::addWifiNetwork(NetworkManager::WirelessNetwork::Ptr net) { mWifiNets.push_back(net); //device signals connect(net.data(), &NetworkManager::WirelessNetwork::signalStrengthChanged, this, &NmModelPrivate::onWifiNetworkUpdated); connect(net.data(), &NetworkManager::WirelessNetwork::referenceAccessPointChanged, this, &NmModelPrivate::onWifiNetworkUpdated); connect(net.data(), &NetworkManager::WirelessNetwork::disappeared, this, &NmModelPrivate::onWifiNetworkUpdated); } void NmModelPrivate::insertWifiNetworks() { for (auto const & device : mDevices) { if (NetworkManager::Device::Wifi == device->type()) { NetworkManager::WirelessDevice::Ptr w_dev = device.objectCast(); for (auto const & net : w_dev->networks()) { if (!net.isNull()) { addWifiNetwork(net); } } } } } NetworkManager::ActiveConnection::Ptr NmModelPrivate::findActiveConnection(QString const & path) { auto i = std::find_if(mActiveConns.cbegin(), mActiveConns.cend(), [&path] (NetworkManager::ActiveConnection::Ptr const & conn) -> bool { return conn->path() == path; }); return mActiveConns.cend() == i ? NetworkManager::ActiveConnection::Ptr{} : *i; } template NetworkManager::Device::Ptr NmModelPrivate::findDevice(Predicate const & pred) { auto i = std::find_if(mDevices.cbegin(), mDevices.cend(), pred); return mDevices.cend() == i ? NetworkManager::Device::Ptr{} : *i; } NetworkManager::Device::Ptr NmModelPrivate::findDeviceUni(QString const & uni) { return findDevice([&uni] (NetworkManager::Device::Ptr const & dev) { return dev->uni() == uni; }); } NetworkManager::Device::Ptr NmModelPrivate::findDeviceInterface(QString const & interfaceName) { return findDevice([&interfaceName] (NetworkManager::Device::Ptr const & dev) { return dev->interfaceName() == interfaceName; }); } NetworkManager::WirelessNetwork::Ptr NmModelPrivate::findWifiNetwork(QString const & ssid, QString const & devUni) { auto i = std::find_if(mWifiNets.cbegin(), mWifiNets.cend(), [&ssid, &devUni] (NetworkManager::WirelessNetwork::Ptr const & net) -> bool { return net->ssid() == ssid && net->device() == devUni; }); return mWifiNets.cend() == i ? NetworkManager::WirelessNetwork::Ptr{} : *i; } void NmModelPrivate::onConnectionUpdated() { emit connectionUpdate(qobject_cast(sender())); } void NmModelPrivate::onConnectionRemoved() { emit connectionRemove(qobject_cast(sender())); } void NmModelPrivate::onActiveConnectionUpdated() { emit activeConnectionUpdate(qobject_cast(sender())); } void NmModelPrivate::onDeviceUpdated() { emit deviceUpdate(qobject_cast(sender())); } void NmModelPrivate::onWifiNetworkAppeared(QString const & ssid) { NetworkManager::Device * dev = qobject_cast(sender()); emit wifiNetworkAdd(dev, ssid); emit deviceUpdate(dev); } void NmModelPrivate::onWifiNetworkDisappeared(QString const & ssid) { NetworkManager::Device * dev = qobject_cast(sender()); emit wifiNetworkRemove(dev, ssid); emit deviceUpdate(dev); } void NmModelPrivate::onWifiNetworkUpdated() { emit wifiNetworkUpdate(qobject_cast(sender())); } void NmModelPrivate::onDeviceAdded(QString const & uni) { NetworkManager::Device::Ptr dev = NetworkManager::findNetworkInterface(uni); if (!dev.isNull()) { Q_ASSERT(dev->isValid()); emit deviceAdd(dev); } } void NmModelPrivate::onDeviceRemoved(QString const & uni) { NetworkManager::Device::Ptr dev = findDeviceUni(uni); if (!dev.isNull()) { Q_ASSERT(dev->isValid()); emit deviceRemove(dev.data()); } } void NmModelPrivate::onActiveConnectionAdded(QString const & path) { NetworkManager::ActiveConnection::Ptr conn = NetworkManager::findActiveConnection(path);//XXX: const QString &uni if (!conn.isNull()) { Q_ASSERT(conn->isValid()); emit activeConnectionAdd(conn); } } void NmModelPrivate::onActiveConnectionRemoved(QString const & path) { NetworkManager::ActiveConnection::Ptr conn = findActiveConnection(path);//XXX: const QString &uni if (!conn.isNull()) { Q_ASSERT(conn->isValid()); emit activeConnectionRemove(conn.data()); } } void NmModelPrivate::onActiveConnectionsChanged() { emit activeConnectionsReset(); } void NmModelPrivate::onConnectionAdded(QString const & path) { NetworkManager::Connection::Ptr conn = NetworkManager::findConnection(path); if (!conn.isNull()) { Q_ASSERT(conn->isValid()); emit connectionAdd(conn); } } void NmModelPrivate::onConnectionRemoved(QString const & path) { NetworkManager::Connection::Ptr conn = NetworkManager::findConnection(path); if (!conn.isNull()) { Q_ASSERT(conn->isValid()); emit connectionRemove(conn.data()); } } NmModel::NmModel(QObject * parent) : QAbstractItemModel(parent) , d{new NmModelPrivate} { connect(d.data(), &NmModelPrivate::connectionAdd, [this] (NetworkManager::Connection::Ptr conn) { //qCDebug(NM_TRAY) << "connectionAdd" << conn->name(); if (0 > d->mConnections.indexOf(conn)) { const int cnt = d->mConnections.size(); beginInsertRows(createIndex(1, 0, ITEM_CONNECTION), cnt, cnt); d->addConnection(conn); endInsertRows(); } else { //TODO: onConnectionUpdate } }); connect(d.data(), &NmModelPrivate::connectionUpdate, [this] (NetworkManager::Connection * conn) { //qCDebug(NM_TRAY) << "connectionUpdate" << conn->name(); auto i = std::find(d->mConnections.cbegin(), d->mConnections.cend(), conn); if (d->mConnections.cend() != i) { QModelIndex index = createIndex(i - d->mConnections.cbegin(), 0, ITEM_CONNECTION_LEAF); emit dataChanged(index, index); } }); connect(d.data(), &NmModelPrivate::connectionRemove, [this] (NetworkManager::Connection * conn) { //qCDebug(NM_TRAY) << "connectionRemove" << conn->name(); auto i = std::find(d->mConnections.cbegin(), d->mConnections.cend(), conn); if (d->mConnections.cend() != i) { const int pos = i - d->mConnections.cbegin(); beginRemoveRows(createIndex(1, 0, ITEM_CONNECTION), pos, pos); d->removeConnection(pos); endRemoveRows(); } }); connect(d.data(), &NmModelPrivate::activeConnectionAdd, [this] (NetworkManager::ActiveConnection::Ptr conn) { //qCDebug(NM_TRAY) << "activecCnnectionAdd" << conn->connection()->name(); if (0 > d->mActiveConns.indexOf(conn)) { const int cnt = d->mActiveConns.size(); beginInsertRows(createIndex(0, 0, ITEM_ACTIVE), cnt, cnt); d->addActiveConnection(conn); endInsertRows(); } else { //TODO: onActiveConnectionUpdate } }); connect(d.data(), &NmModelPrivate::activeConnectionUpdate, [this] (NetworkManager::ActiveConnection * conn) { //qCDebug(NM_TRAY) << "activecCnnectionUpdate" << conn->connection()->name(); auto i = std::find(d->mActiveConns.cbegin(), d->mActiveConns.cend(), conn); if (d->mActiveConns.cend() != i) { QModelIndex index = createIndex(i - d->mActiveConns.cbegin(), 0, ITEM_ACTIVE_LEAF); emit dataChanged(index, index); } }); connect(d.data(), &NmModelPrivate::activeConnectionRemove, [this] (NetworkManager::ActiveConnection * conn) { //qCDebug(NM_TRAY) << "activecCnnectionRemove" << conn->connection()->name(); auto i = std::find(d->mActiveConns.cbegin(), d->mActiveConns.cend(), conn); if (d->mActiveConns.cend() != i) { const int pos = i - d->mActiveConns.cbegin(); beginRemoveRows(createIndex(0, 0, ITEM_ACTIVE), pos, pos); d->removeActiveConnection(pos); endRemoveRows(); } }); connect(d.data(), &NmModelPrivate::activeConnectionsReset, [this] () { //qCDebug(NM_TRAY) << "activecCnnectionReset"; const int cnt = d->mActiveConns.size(); if (0 < cnt) { beginRemoveRows(createIndex(0, 0, ITEM_ACTIVE), 0, d->mActiveConns.size() - 1); d->clearActiveConnections(); endRemoveRows(); } const int new_cnt = NetworkManager::activeConnections().size(); if (0 < new_cnt) { beginInsertRows(createIndex(0, 0, ITEM_ACTIVE), 0, new_cnt - 1); d->insertActiveConnections(); endInsertRows(); } }); connect(d.data(), &NmModelPrivate::deviceAdd, [this] (NetworkManager::Device::Ptr dev) { //qCDebug(NM_TRAY) << "deviceAdd" << dev->interfaceName(); if (0 > d->mDevices.indexOf(dev)) { const int cnt = d->mDevices.size(); beginInsertRows(createIndex(2, 0, ITEM_DEVICE), cnt, cnt); d->addDevice(dev); endInsertRows(); } else { //TODO: onDeviceUpdate } }); connect(d.data(), &NmModelPrivate::deviceUpdate, [this] (NetworkManager::Device * dev) { //qCDebug(NM_TRAY) << "deviceUpdate" << dev << dev->interfaceName(); auto i = std::find(d->mDevices.cbegin(), d->mDevices.cend(), dev); if (d->mDevices.cend() != i) { QModelIndex index = createIndex(i - d->mDevices.cbegin(), 0, ITEM_DEVICE_LEAF); emit dataChanged(index, index); } }); connect(d.data(), &NmModelPrivate::deviceRemove, [this] (NetworkManager::Device * dev) { //qCDebug(NM_TRAY) << "deviceRemove" << dev->interfaceName(); auto i = std::find(d->mDevices.cbegin(), d->mDevices.cend(), dev); if (d->mDevices.cend() != i) { const int pos = i - d->mDevices.cbegin(); beginRemoveRows(createIndex(2, 0, ITEM_DEVICE), pos, pos); d->removeDevice(pos); endRemoveRows(); } }); connect(d.data(), &NmModelPrivate::wifiNetworkAdd, [this] (NetworkManager::Device * dev, QString const & ssid) { //qCDebug(NM_TRAY) << "wifiNetworkAdd" << dev << dev->interfaceName() << ssid; NetworkManager::WirelessDevice * w_dev = qobject_cast(dev); NetworkManager::WirelessNetwork::Ptr net = w_dev->findNetwork(ssid); if (!net.isNull()) { if (0 > d->mWifiNets.indexOf(net)) { const int cnt = d->mWifiNets.size(); beginInsertRows(createIndex(3, 0, ITEM_WIFINET), cnt, cnt); d->addWifiNetwork(net); endInsertRows(); } else { //TODO: onWifiNetworkUpdate } } }); connect(d.data(), &NmModelPrivate::wifiNetworkUpdate, [this] (NetworkManager::WirelessNetwork * net) { //qCDebug(NM_TRAY) << "wifiNetworkUpdate" << net << net->ssid(); auto i = std::find(d->mWifiNets.cbegin(), d->mWifiNets.cend(), net); if (d->mWifiNets.cend() != i) { if (net->accessPoints().isEmpty()) { //remove auto pos = i - d->mWifiNets.cbegin(); beginRemoveRows(createIndex(3, 0, ITEM_WIFINET), pos, pos); d->removeWifiNetwork(pos); endRemoveRows(); } else { //update QModelIndex index = createIndex(i - d->mWifiNets.cbegin(), 0, ITEM_WIFINET_LEAF); emit dataChanged(index, index); //XXX: active connection auto dev = d->findDeviceUni((*i)->device()); if (!dev.isNull()) { auto active = dev->activeConnection(); if (!active.isNull()) { QModelIndex index = createIndex(d->mActiveConns.indexOf(active), 0, ITEM_ACTIVE_LEAF); emit dataChanged(index, index); } } } } }); connect(d.data(), &NmModelPrivate::wifiNetworkRemove, [this] (NetworkManager::Device * dev, QString const & ssid) { //qCDebug(NM_TRAY) << "wifiNetworkRemove" << dev << dev->interfaceName() << ssid; NetworkManager::WirelessNetwork::Ptr net = d->findWifiNetwork(ssid, dev->uni()); if (!net.isNull()) { auto pos = d->mWifiNets.indexOf(net); if (0 <= pos) { beginRemoveRows(createIndex(3, 0, ITEM_WIFINET), pos, pos); d->removeWifiNetwork(pos); endRemoveRows(); } } }); //qCDebug(NM_TRAY) << __FUNCTION__ << "finished"; } NmModel::~NmModel() { } /* Model hierarchy * root * - mActiveConns * - mConnections * - mDevices */ int NmModel::rowCount(const QModelIndex &parent/* = QModelIndex()*/) const { int cnt = 0; if (!parent.isValid()) cnt = 1; else { const int id = parent.internalId(); if (ITEM_ROOT == id) cnt = 4; else if (ITEM_ACTIVE == id) cnt = d->mActiveConns.size(); else if (ITEM_CONNECTION == id) cnt = d->mConnections.size(); else if (ITEM_DEVICE == id) cnt = d->mDevices.size(); else if (ITEM_WIFINET == id) cnt = d->mWifiNets.size(); } //qCDebug(NM_TRAY) << __FUNCTION__ << parent << cnt; return cnt; } int NmModel::columnCount(const QModelIndex & /*parent = QModelIndex()*/) const { //qCDebug(NM_TRAY) << __FUNCTION__ << parent << 1; //XXX: more columns for wifi connections (for name && icons...)?? return 1; } bool NmModel::isValidDataIndex(const QModelIndex & index) const { switch (static_cast(index.internalId())) { case ITEM_ROOT: case ITEM_ACTIVE: case ITEM_CONNECTION: case ITEM_DEVICE: case ITEM_WIFINET: return true; case ITEM_ACTIVE_LEAF: return d->mActiveConns.size() > index.row() && 0 == index.column(); case ITEM_CONNECTION_LEAF: return d->mConnections.size() > index.row() && 0 == index.column(); case ITEM_DEVICE_LEAF: return d->mDevices.size() > index.row() && 0 == index.column(); case ITEM_WIFINET_LEAF: return d->mWifiNets.size() > index.row() && 0 == index.column(); } return false; } template <> QVariant NmModel::dataRole(const QModelIndex & index) const { switch (static_cast(index.internalId())) { case ITEM_ROOT: case ITEM_ACTIVE: case ITEM_CONNECTION: case ITEM_WIFINET: case ITEM_DEVICE: return HelperType; case ITEM_ACTIVE_LEAF: return ActiveConnectionType; case ITEM_CONNECTION_LEAF: return ConnectionType; case ITEM_DEVICE_LEAF: return DeviceType; case ITEM_WIFINET_LEAF: return WifiNetworkType; } return QVariant{}; } template <> QVariant NmModel::dataRole(const QModelIndex & index) const { switch (static_cast(index.internalId())) { case ITEM_ROOT: return NmModel::tr("root"); case ITEM_ACTIVE: return NmModel::tr("active connection(s)"); case ITEM_CONNECTION: return NmModel::tr("connection(s)"); case ITEM_DEVICE: return NmModel::tr("device(s)"); case ITEM_WIFINET: return NmModel::tr("wifi network(s)"); case ITEM_ACTIVE_LEAF: return d->mActiveConns[index.row()]->connection()->name(); case ITEM_CONNECTION_LEAF: return d->mConnections[index.row()]->name(); case ITEM_DEVICE_LEAF: return d->mDevices[index.row()]->interfaceName(); case ITEM_WIFINET_LEAF: return d->mWifiNets[index.row()]->referenceAccessPoint()->ssid(); } return QVariant{}; } template <> QVariant NmModel::dataRole(const QModelIndex & index) const { switch (static_cast(index.internalId())) { case ITEM_ROOT: case ITEM_ACTIVE: case ITEM_CONNECTION: case ITEM_DEVICE: case ITEM_WIFINET: return QVariant{}; case ITEM_DEVICE_LEAF: //TODO: other types switch (d->mDevices[index.row()]->type()) { case NetworkManager::Device::Wifi: return NetworkManager::ConnectionSettings::Wireless; case NetworkManager::Device::Wimax: return NetworkManager::ConnectionSettings::Wimax; default: return NetworkManager::ConnectionSettings::Wired; } case ITEM_ACTIVE_LEAF: return d->mActiveConns[index.row()]->connection()->settings()->connectionType(); case ITEM_CONNECTION_LEAF: return d->mConnections[index.row()]->settings()->connectionType(); case ITEM_WIFINET_LEAF: return NetworkManager::ConnectionSettings::Wireless; } return QVariant{}; } template <> QVariant NmModel::dataRole(const QModelIndex & index) const { const QVariant conn_type = dataRole(index); if (!conn_type.isValid()) { return QVariant{}; } return NetworkManager::ConnectionSettings::typeAsString(static_cast(conn_type.toInt())); } template <> QVariant NmModel::dataRole(const QModelIndex & index) const { switch (static_cast(index.internalId())) { case ITEM_ROOT: case ITEM_ACTIVE: case ITEM_CONNECTION: case ITEM_DEVICE: case ITEM_CONNECTION_LEAF: case ITEM_DEVICE_LEAF: case ITEM_WIFINET: case ITEM_WIFINET_LEAF: return -1; case ITEM_ACTIVE_LEAF: return d->mActiveConns[index.row()]->state(); } return QVariant{}; } template <> QVariant NmModel::dataRole(const QModelIndex & index) const { switch (static_cast(index.internalId())) { case ITEM_ROOT: case ITEM_ACTIVE: case ITEM_CONNECTION: case ITEM_DEVICE: case ITEM_CONNECTION_LEAF: case ITEM_DEVICE_LEAF: case ITEM_WIFINET: case ITEM_WIFINET_LEAF: return QVariant{}; case ITEM_ACTIVE_LEAF: return d->mActiveConns[index.row()]->master(); } return QVariant{}; } template <> QVariant NmModel::dataRole(const QModelIndex & index) const { switch (static_cast(index.internalId())) { case ITEM_ROOT: case ITEM_ACTIVE: case ITEM_CONNECTION: case ITEM_DEVICE: case ITEM_CONNECTION_LEAF: case ITEM_DEVICE_LEAF: case ITEM_WIFINET: case ITEM_WIFINET_LEAF: return QVariant{}; case ITEM_ACTIVE_LEAF: return d->mActiveConns[index.row()]->devices(); } return QVariant{}; } template <> QVariant NmModel::dataRole(const QModelIndex & index) const { auto const internal_id = static_cast(index.internalId()); switch (internal_id) { case ITEM_ROOT: case ITEM_ACTIVE: case ITEM_CONNECTION: case ITEM_DEVICE: case ITEM_WIFINET: case ITEM_DEVICE_LEAF: return -1; case ITEM_CONNECTION_LEAF: case ITEM_ACTIVE_LEAF: { NetworkManager::ConnectionSettings::Ptr settings = ITEM_CONNECTION_LEAF == internal_id ? d->mConnections[index.row()]->settings() : d->mActiveConns[index.row()]->connection()->settings(); if (NetworkManager::ConnectionSettings::Wireless == settings->connectionType()) { NetworkManager::WirelessSecuritySetting::Ptr w_sett = settings->setting(NetworkManager::Setting::WirelessSecurity).staticCast(); if (w_sett.isNull()) return icons::SECURITY_LOW; else if (NetworkManager::WirelessSecuritySetting::WpaNone != w_sett->keyMgmt()) return icons::SECURITY_HIGH; else return icons::SECURITY_LOW; } return -1; } case ITEM_WIFINET_LEAF: return d->mWifiNets[index.row()]->referenceAccessPoint()->capabilities().testFlag(NetworkManager::AccessPoint::Privacy) ? icons::SECURITY_HIGH : icons::SECURITY_LOW; } return QVariant{}; } template <> QVariant NmModel::dataRole(const QModelIndex & index) const { const auto type = dataRole(index).toInt(); if (0 <= type) return icons::getIcon(static_cast(type)); else return QVariant{}; } template <> QVariant NmModel::dataRole(const QModelIndex & index) const { switch (static_cast(index.internalId())) { case ITEM_ROOT: case ITEM_ACTIVE: case ITEM_CONNECTION: case ITEM_DEVICE: case ITEM_DEVICE_LEAF: case ITEM_WIFINET: return -1; case ITEM_ACTIVE_LEAF: { NetworkManager::ConnectionSettings::Ptr sett = d->mActiveConns[index.row()]->connection()->settings(); //TODO: other type with signals!?! if (NetworkManager::ConnectionSettings::Wireless == sett->connectionType()) { NetworkManager::WirelessSetting::Ptr w_sett = sett->setting(NetworkManager::Setting::Wireless).staticCast(); Q_ASSERT(!w_sett.isNull()); for (auto const & dev_uni : d->mActiveConns[index.row()]->devices()) { auto dev = NetworkManager::findNetworkInterface(dev_uni); if (!dev.isNull() && dev->isValid()) { auto w_dev = dev.objectCast(); if (!w_dev.isNull()) { auto wifi_net = w_dev->findNetwork(w_sett->ssid()); if (!wifi_net.isNull()) return wifi_net->signalStrength(); } } } } return -1; } case ITEM_CONNECTION_LEAF: //TODO: implement return -1; case ITEM_WIFINET_LEAF: return d->mWifiNets[index.row()]->signalStrength(); } return QVariant{}; } template <> QVariant NmModel::dataRole(const QModelIndex & index) const { switch (static_cast(index.internalId())) { case ITEM_ROOT: case ITEM_ACTIVE: case ITEM_CONNECTION: case ITEM_DEVICE: case ITEM_DEVICE_LEAF: case ITEM_WIFINET: case ITEM_WIFINET_LEAF: return QVariant{}; case ITEM_ACTIVE_LEAF: return d->mActiveConns[index.row()]->uuid(); case ITEM_CONNECTION_LEAF: return d->mConnections[index.row()]->uuid(); } return QVariant{}; } template <> QVariant NmModel::dataRole(const QModelIndex & index) const { switch (static_cast(index.internalId())) { case ITEM_ROOT: case ITEM_ACTIVE: case ITEM_CONNECTION: case ITEM_DEVICE: case ITEM_DEVICE_LEAF: case ITEM_WIFINET: case ITEM_WIFINET_LEAF: return QVariant{}; case ITEM_ACTIVE_LEAF: return d->mActiveConns[index.row()]->path(); case ITEM_CONNECTION_LEAF: return d->mConnections[index.row()]->path(); } return QVariant{}; } template <> QVariant NmModel::dataRole(const QModelIndex & index) const { NetworkManager::Device::Ptr dev; NetworkManager::ConnectionSettings::Ptr settings; switch (static_cast(index.internalId())) { case ITEM_ROOT: case ITEM_ACTIVE: case ITEM_CONNECTION: case ITEM_DEVICE: case ITEM_DEVICE_LEAF: case ITEM_WIFINET: case ITEM_WIFINET_LEAF: case ITEM_CONNECTION_LEAF: return QVariant{}; break; case ITEM_ACTIVE_LEAF: { auto const a_conn = d->mActiveConns[index.row()]; auto const dev_list = a_conn->devices(); //TODO: work with all devices?!? if (!dev_list.isEmpty()) dev = d->findDeviceUni(dev_list.first()); Q_ASSERT(!a_conn->connection().isNull()); settings = a_conn->connection()->settings(); } break; } //TODO: we probably shouldn't assemble a string information (with styling) here and leave it to the consumer QString info; QDebug str{&info}; str.noquote(); str.nospace(); if (!dev.isNull()) { auto m_enum = NetworkManager::Device::staticMetaObject.enumerator(NetworkManager::Device::staticMetaObject.indexOfEnumerator("Type")); QString hw_address = NmModel::tr("unknown", "hardware address"); QString security; int bit_rate = -1; switch (dev->type()) { case NetworkManager::Device::Adsl: break; case NetworkManager::Device::Bond: { auto spec_dev = dev->as(); hw_address = spec_dev->hwAddress(); } break; case NetworkManager::Device::Bridge: { auto spec_dev = dev->as(); hw_address = spec_dev->hwAddress(); } break; case NetworkManager::Device::Gre: break; case NetworkManager::Device::Generic: { auto spec_dev = dev->as(); hw_address = spec_dev->hardwareAddress(); } break; case NetworkManager::Device::InfiniBand: { auto spec_dev = dev->as(); hw_address = spec_dev->hwAddress(); } break; case NetworkManager::Device::MacVlan: case NetworkManager::Device::Modem: break; case NetworkManager::Device::Bluetooth: { auto spec_dev = dev->as(); hw_address = spec_dev->hardwareAddress(); } break; case NetworkManager::Device::OlpcMesh: { auto spec_dev = dev->as(); hw_address = spec_dev->hardwareAddress(); } break; case NetworkManager::Device::Team: { auto spec_dev = dev->as(); hw_address = spec_dev->hwAddress(); } break; case NetworkManager::Device::Tun: case NetworkManager::Device::Veth: break; case NetworkManager::Device::Vlan: { auto spec_dev = dev->as(); hw_address = spec_dev->hwAddress(); } break; case NetworkManager::Device::Ethernet: { auto spec_dev = dev->as(); Q_ASSERT(nullptr != spec_dev); hw_address = spec_dev->hardwareAddress(); bit_rate = spec_dev->bitRate(); } break; case NetworkManager::Device::Wifi: { auto spec_dev = dev->as(); Q_ASSERT(nullptr != spec_dev); hw_address = spec_dev->hardwareAddress(); bit_rate = spec_dev->bitRate(); NetworkManager::Setting::Ptr setting = settings->setting(NetworkManager::Setting::WirelessSecurity); if (!setting.isNull()) { QVariantMap const map = setting->toMap(); if (map.contains(QLatin1String(NM_SETTING_WIRELESS_SECURITY_KEY_MGMT))) security = map.value(QLatin1String(NM_SETTING_WIRELESS_SECURITY_KEY_MGMT)).toString(); } } break; case NetworkManager::Device::Wimax: //Wimax support was dropped in network manager 1.2.0 //we should never get here in runtime with nm >= 1.2.0 { auto spec_dev = dev->as(); Q_ASSERT(nullptr != spec_dev); hw_address = spec_dev->hardwareAddress(); //bit_rate = spec_dev->bitRate(); } break; case NetworkManager::Device::UnknownType: case NetworkManager::Device::Unused1: case NetworkManager::Device::Unused2: break; } str << QStringLiteral("") << QStringLiteral("") << QStringLiteral("") << QStringLiteral("") << QStringLiteral("") << QStringLiteral(""); if (!security.isEmpty()) { str << QStringLiteral(""); } //IP4/6 QString const ip4 = NmModel::tr("IPv4", "Active connection information"); QString const ip6 = NmModel::tr("IPv6", "Active connection information"); for (auto const & ip : { std::make_tuple(ip4, dev->ipV4Config()) , std::make_tuple(ip6, dev->ipV6Config()) }) { NetworkManager::IpConfig ip_config = std::get<1>(ip); if (ip_config.isValid()) { str << QStringLiteral(""); int i = 1; for (QNetworkAddressEntry const & address : ip_config.addresses()) { QString suffix = (i > 1 ? QString{"(%1)"}.arg(i) : QString{}); str << QStringLiteral("") << QStringLiteral("") ; ++i; } QString const gtw = ip_config.gateway(); if (!gtw.isEmpty()) { str << QStringLiteral(""); } i = 0; for (auto const & nameserver : ip_config.nameservers()) { str << QStringLiteral(""); } } } str << QStringLiteral("
") << NmModel::tr("General", "Active connection information") << QStringLiteral("
") << NmModel::tr("Interface", "Active connection information") << QStringLiteral(": ") << m_enum.valueToKey(dev->type()) << QStringLiteral(" (") << dev->interfaceName() << QStringLiteral(")
") << NmModel::tr("Hardware Address", "Active connection information") << QStringLiteral(": ") << hw_address << QStringLiteral("
") << NmModel::tr("Driver", "Active connection information") << QStringLiteral(": ") << dev->driver() << QStringLiteral("
") << NmModel::tr("Speed", "Active connection information") << QStringLiteral(": "); if (0 <= bit_rate) str << bit_rate << NmModel::tr(" Kb/s"); else str << NmModel::tr("unknown", "Speed"); str << QStringLiteral("
") << NmModel::tr("Security", "Active connection information") << QStringLiteral(": ") << security << QStringLiteral("
") << std::get<0>(ip) << QStringLiteral("
") << NmModel::tr("IP Address", "Active connection information") << suffix << QStringLiteral(": ") << address.ip().toString() << QStringLiteral("
") << NmModel::tr("Subnet Mask", "Active connection information") << suffix << QStringLiteral(": ") << address.netmask().toString() << QStringLiteral("
") << NmModel::tr("Default route", "Active connection information") << QStringLiteral(": ") << ip_config.gateway() << QStringLiteral("
") << NmModel::tr("DNS(%1)", "Active connection information").arg(++i) << QStringLiteral(": ") << nameserver.toString() << QStringLiteral("
"); } return info; } template <> QVariant NmModel::dataRole(const QModelIndex & index) const { switch (static_cast(index.internalId())) { case ITEM_ROOT: case ITEM_ACTIVE: case ITEM_CONNECTION: case ITEM_DEVICE: case ITEM_WIFINET: return -1; case ITEM_ACTIVE_LEAF: case ITEM_CONNECTION_LEAF: case ITEM_DEVICE_LEAF: { auto type = static_cast(dataRole(index).toInt()); auto state = static_cast(dataRole(index).toInt()); //TODO other types? switch (type) { case NetworkManager::ConnectionSettings::Wireless: case NetworkManager::ConnectionSettings::Wimax: if (0 > state) return icons::NETWORK_WIFI_DISCONNECTED; switch (state) { case NetworkManager::ActiveConnection::Activating: return icons::NETWORK_WIFI_ACQUIRING; case NetworkManager::ActiveConnection::Activated: return icons::wifiSignalIcon(dataRole(index).toInt()); case NetworkManager::ActiveConnection::Unknown: case NetworkManager::ActiveConnection::Deactivating: case NetworkManager::ActiveConnection::Deactivated: return icons::NETWORK_WIFI_DISCONNECTED; } break; case NetworkManager::ConnectionSettings::Vpn: return icons::NETWORK_VPN; default: return NetworkManager::ActiveConnection::Activated == state ? icons::NETWORK_WIRED : icons::NETWORK_WIRED_DISCONNECTED; } } case ITEM_WIFINET_LEAF: return icons::wifiSignalIcon(d->mWifiNets[index.row()]->signalStrength()); } return QVariant{}; } template <> QVariant NmModel::dataRole(const QModelIndex & index) const { return icons::getIcon(static_cast(dataRole(index).toInt())); } QVariant NmModel::data(const QModelIndex &index, int role) const { //qCDebug(NM_TRAY) << __FUNCTION__ << index << role; Q_ASSERT(isValidDataIndex(index)); QVariant ret; if (index.isValid()) switch (role) { case ItemTypeRole: ret = dataRole(index); break; case Qt::DisplayRole: case NameRole: ret = dataRole(index); break; case ConnectionTypeRole: ret = dataRole(index); break; case ConnectionTypeStringRole: ret = dataRole(index); break; case ActiveConnectionStateRole: ret = dataRole(index); break; case ActiveConnectionMasterRole: ret = dataRole(index); break; case ActiveConnectionDevicesRole: ret = dataRole(index); break; case SignalRole: ret = dataRole(index); break; case ConnectionUuidRole: ret = dataRole(index); break; case ConnectionPathRole: ret = dataRole(index); break; case ActiveConnectionInfoRole: ret = dataRole(index); break; case IconTypeRole: ret = dataRole(index); break; case Qt::DecorationRole: case IconRole: ret = dataRole(index); break; case IconSecurityTypeRole: ret = dataRole(index); break; case IconSecurityRole: ret = dataRole(index); break; default: ret = QVariant{}; break; } //qCDebug(NM_TRAY) << __FUNCTION__ << "ret" << index << role << ret; return ret; } QModelIndex NmModel::index(int row, int column, const QModelIndex &parent/* = QModelIndex()*/) const { //qCDebug(NM_TRAY) << __FUNCTION__ << row << column << parent; if (!hasIndex(row, column, parent)) return QModelIndex{}; const int id = parent.internalId(); ItemId int_id; if (!parent.isValid()) { Q_ASSERT(0 == row && 0 == column); int_id = ITEM_ROOT; } else if (ITEM_ROOT == id) { Q_ASSERT(4 > row && 0 == column); switch (row) { case 0: int_id = ITEM_ACTIVE; break; case 1: int_id = ITEM_CONNECTION; break; case 2: int_id = ITEM_DEVICE; break; case 3: int_id = ITEM_WIFINET; break; } } else if (ITEM_ACTIVE == id) { Q_ASSERT(d->mActiveConns.size() > row); int_id = ITEM_ACTIVE_LEAF; } else if (ITEM_CONNECTION == id) { Q_ASSERT(d->mConnections.size() > row); int_id = ITEM_CONNECTION_LEAF; } else if (ITEM_DEVICE == id) { Q_ASSERT(d->mDevices.size() > row); int_id = ITEM_DEVICE_LEAF; } else if (ITEM_WIFINET == id) { Q_ASSERT(d->mWifiNets.size() > row); int_id = ITEM_WIFINET_LEAF; } else { Q_ASSERT(false); //should never get here return QModelIndex{}; } //qCDebug(NM_TRAY) << __FUNCTION__ << "ret: " << row << column << int_id; return createIndex(row, column, int_id); } QModelIndex NmModel::parent(const QModelIndex &index) const { QModelIndex parent_i; if (index.isValid()) { switch (static_cast(index.internalId())) { case ITEM_ROOT: break; case ITEM_ACTIVE: case ITEM_CONNECTION: case ITEM_DEVICE: case ITEM_WIFINET: parent_i = createIndex(0, 0, ITEM_ROOT); break; case ITEM_ACTIVE_LEAF: parent_i = createIndex(0, 0, ITEM_ACTIVE); break; case ITEM_CONNECTION_LEAF: parent_i = createIndex(1, 0, ITEM_CONNECTION); break; case ITEM_DEVICE_LEAF: parent_i = createIndex(2, 0, ITEM_DEVICE); break; case ITEM_WIFINET_LEAF: parent_i = createIndex(3, 0, ITEM_WIFINET); break; } } //qCDebug(NM_TRAY) << __FUNCTION__ << index << parent_i; return parent_i; } QModelIndex NmModel::indexTypeRoot(ItemType type) const { QModelIndex i; switch (type) { case HelperType: i = createIndex(0, 0, ITEM_ROOT); break; case ActiveConnectionType: i = createIndex(0, 0, ITEM_ACTIVE); break; case ConnectionType: i = createIndex(1, 0, ITEM_CONNECTION); break; case DeviceType: i = createIndex(2, 0, ITEM_DEVICE); break; case WifiNetworkType: i = createIndex(3, 0, ITEM_WIFINET); break; } return i; } void NmModel::activateConnection(QModelIndex const & index) { ItemId id = static_cast(index.internalId()); if (!isValidDataIndex(index) || (ITEM_CONNECTION_LEAF != id && ITEM_WIFINET_LEAF != id)) { //TODO: in what form should we output the warning messages qCWarning(NM_TRAY).noquote() << "got invalid index for connection activation" << index; return; } QString conn_uni, dev_uni; QString conn_name, dev_name; QString spec_object; NMVariantMapMap map_settings; bool add_connection = false; switch (id) { case ITEM_CONNECTION_LEAF: { auto const & conn = d->mConnections[index.row()]; conn_uni = conn->path(); conn_name = conn->name(); if (NetworkManager::ConnectionSettings::Vpn == conn->settings()->connectionType()) { spec_object = dev_uni = QStringLiteral("/"); /* // find first non-vpn active connection const auto act_i = std::find_if(d->mActiveConns.cbegin(), d->mActiveConns.cend(), [] (NetworkManager::ActiveConnection::Ptr const & conn) -> bool { return nullptr != dynamic_cast(conn.data()); }); if (act_i != d->mActiveConns.cend() && !(*act_i)->devices().empty()) { dev_uni = (*act_i)->devices().front(); spec_object = (*act_i)->path(); } */ } else { dev_name = conn->settings()->interfaceName(); for (auto const & dev : d->mDevices) for (auto const & dev_conn : dev->availableConnections()) if (dev_conn == conn) { dev_uni = dev->uni(); dev_name = dev->interfaceName(); } if (dev_uni.isEmpty() && !dev_name.isEmpty()) { auto dev = d->findDeviceInterface(dev_name); if (!dev.isNull()) dev_uni = dev->uni(); } } if (dev_uni.isEmpty()) { //TODO: in what form should we output the warning messages qCWarning(NM_TRAY).noquote() << QStringLiteral("can't find device '%1' to activate connection '%2' on").arg(dev_name).arg(conn->name()); return; } } break; case ITEM_WIFINET_LEAF: { auto const & net = d->mWifiNets[index.row()]; auto access_point = net->referenceAccessPoint(); Q_ASSERT(!access_point.isNull()); dev_uni = net->device(); auto dev = d->findDeviceUni(dev_uni); Q_ASSERT(!dev.isNull()); auto spec_dev = dev->as(); Q_ASSERT(nullptr != spec_dev); conn_uni = access_point->uni(); conn_name = access_point->ssid(); //find the device name NetworkManager::Connection::Ptr conn; dev_name = dev->interfaceName(); for (auto const & dev_conn : dev->availableConnections()) if (dev_conn->settings()->id() == conn_name) { conn = dev_conn; } if (conn.isNull()) { //TODO: in what form should we output the warning messages qCWarning(NM_TRAY).noquote() << QStringLiteral("can't find connection for '%1' on device '%2', will create new...").arg(conn_name).arg(dev_name); add_connection = true; spec_object = conn_uni; NetworkManager::WirelessSecurityType sec_type = NetworkManager::findBestWirelessSecurity(spec_dev->wirelessCapabilities() , true, (spec_dev->mode() == NetworkManager::WirelessDevice::Adhoc) , access_point->capabilities(), access_point->wpaFlags(), access_point->rsnFlags()); switch (sec_type) { case NetworkManager::UnknownSecurity: qCWarning(NM_TRAY).noquote() << QStringLiteral("unknown security to use for '%1'").arg(conn_name); case NetworkManager::NoneSecurity: //nothing to do break; case NetworkManager::WpaPsk: case NetworkManager::Wpa2Psk: if (NetworkManager::ConnectionSettings::Ptr settings = assembleWpaXPskSettings(access_point)) { map_settings = settings->toMap(); } else { qCWarning(NM_TRAY).noquote() << QStringLiteral("connection settings assembly for '%1' failed, abandoning activation...") .arg(conn_name); return; } break; //TODO: other types... } } else { conn_uni = conn->path(); } } break; default: Q_ASSERT(false); } qCDebug(NM_TRAY) << __FUNCTION__ << conn_uni << dev_uni << conn_name << dev_name << spec_object; //TODO: check vpn type etc.. QDBusPendingCallWatcher * watcher; if (add_connection) watcher = new QDBusPendingCallWatcher{NetworkManager::addAndActivateConnection(map_settings, dev_uni, spec_object), this}; else watcher = new QDBusPendingCallWatcher{NetworkManager::activateConnection(conn_uni, dev_uni, spec_object), this}; connect(watcher, &QDBusPendingCallWatcher::finished, [conn_name, dev_name] (QDBusPendingCallWatcher * watcher) { if (watcher->isError() || !watcher->isValid()) { //TODO: in what form should we output the warning messages qCWarning(NM_TRAY).noquote() << QStringLiteral("activation of connection '%1' on interface '%2' failed: %3").arg(conn_name) .arg(dev_name).arg(watcher->error().message()); } watcher->deleteLater(); }); } void NmModel::deactivateConnection(QModelIndex const & index) { ItemId id = static_cast(index.internalId()); if (!isValidDataIndex(index) || ITEM_ACTIVE_LEAF != id) { //TODO: in what form should we output the warning messages qCWarning(NM_TRAY).noquote() << "got invalid index for connection deactivation" << index; return; } auto const & active = d->mActiveConns[index.row()]; qCDebug(NM_TRAY) << __FUNCTION__ << active->path(); QDBusPendingReply<> reply = NetworkManager::deactivateConnection(active->path()); QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(reply, this); connect(watcher, &QDBusPendingCallWatcher::finished, [active] (QDBusPendingCallWatcher * watcher) { if (watcher->isError() || !watcher->isValid()) { //TODO: in what form should we output the warning messages qCWarning(NM_TRAY).noquote() << QStringLiteral("deactivation of connection '%1' failed: %3").arg(active->connection()->name()) .arg(watcher->error().message()); } watcher->deleteLater(); }); } nm-tray-0.3.0/src/nmmodel.h000066400000000000000000000055501317132702700155040ustar00rootroot00000000000000/*COPYRIGHT_HEADER This file is a part of nm-tray. Copyright (c) 2015~now Palo Kisa nm-tray is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. COPYRIGHT_HEADER*/ #if !defined(NMMODEL_H) #define NMMODEL_H #include class NmModelPrivate; class NmModel : public QAbstractItemModel { Q_OBJECT public: enum ItemType { HelperType , ActiveConnectionType , ConnectionType , DeviceType , WifiNetworkType }; enum ItemRole { ItemTypeRole = Qt::UserRole + 1 , NameRole , IconTypeRole , IconRole , ConnectionTypeRole , ActiveConnectionTypeRole = ConnectionTypeRole , ConnectionTypeStringRole , ActiveConnectionTypeStringRole = ConnectionTypeStringRole , ConnectionUuidRole , ActiveConnectionUuidRole = ConnectionUuidRole , ConnectionPathRole , ActiveConnectionPathRole = ConnectionPathRole , ActiveConnectionInfoRole , ActiveConnectionStateRole , ActiveConnectionMasterRole , ActiveConnectionDevicesRole , IconSecurityTypeRole , IconSecurityRole , SignalRole }; public: explicit NmModel(QObject * parent = nullptr); ~NmModel(); //QAbstractItemModel methods virtual int rowCount(const QModelIndex &parent = QModelIndex()) const override; virtual int columnCount(const QModelIndex &parent = QModelIndex()) const override; virtual QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override; virtual QModelIndex parent(const QModelIndex &index) const override; virtual QVariant data(const QModelIndex &index, int role) const override; QModelIndex indexTypeRoot(ItemType type) const; public Q_SLOTS: //NetworkManager management methods void activateConnection(QModelIndex const & index); void deactivateConnection(QModelIndex const & index); private: bool isValidDataIndex(const QModelIndex & index) const; template QVariant dataRole(const QModelIndex & index) const; private: QScopedPointer d; }; #endif //NMMODEL_H nm-tray-0.3.0/src/nmmodel_p.h000066400000000000000000000103221317132702700160140ustar00rootroot00000000000000/*COPYRIGHT_HEADER This file is a part of nm-tray. Copyright (c) 2015~now Palo Kisa nm-tray is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. COPYRIGHT_HEADER*/ #if !defined(NMMODEL_P_H) #define NMMODEL_P_H #include #include #include class NmModelPrivate : public QObject { Q_OBJECT public: NmModelPrivate(); ~NmModelPrivate(); void removeActiveConnection(int pos); void clearActiveConnections(); void insertActiveConnections(); void addActiveConnection(NetworkManager::ActiveConnection::Ptr conn); void removeConnection(int pos); void clearConnections(); void insertConnections(); void addConnection(NetworkManager::Connection::Ptr conn); void removeDevice(int pos); void clearDevices(); void insertDevices(); void addDevice(NetworkManager::Device::Ptr conn); void removeWifiNetwork(int pos); void clearWifiNetworks(); void insertWifiNetworks(); void addWifiNetwork(NetworkManager::WirelessNetwork::Ptr net); NetworkManager::ActiveConnection::Ptr findActiveConnection(QString const & path); template NetworkManager::Device::Ptr findDevice(Predicate const & pred); NetworkManager::Device::Ptr findDeviceUni(QString const & uni); NetworkManager::Device::Ptr findDeviceInterface(QString const & interfaceName); NetworkManager::WirelessNetwork::Ptr findWifiNetwork(QString const & ssid, QString const & devUni); Q_SIGNALS: void connectionAdd(NetworkManager::Connection::Ptr conn); void connectionUpdate(NetworkManager::Connection * conn); void connectionRemove(NetworkManager::Connection * conn); void activeConnectionAdd(NetworkManager::ActiveConnection::Ptr conn); void activeConnectionUpdate(NetworkManager::ActiveConnection * conn); void activeConnectionRemove(NetworkManager::ActiveConnection * conn); void activeConnectionsReset(); void deviceAdd(NetworkManager::Device::Ptr dev); void deviceUpdate(NetworkManager::Device * dev); void deviceRemove(NetworkManager::Device * dev); void wifiNetworkAdd(NetworkManager::Device * dev, QString const & ssid); void wifiNetworkUpdate(NetworkManager::WirelessNetwork * net); void wifiNetworkRemove(NetworkManager::Device * dev, QString const & ssid); private Q_SLOT: //connection void onConnectionUpdated(); void onConnectionRemoved(); //active connection void onActiveConnectionUpdated(); //device void onDeviceUpdated(); void onWifiNetworkAppeared(QString const & ssid); void onWifiNetworkDisappeared(QString const & ssid); //wifi network void onWifiNetworkUpdated(); //notifier void onDeviceAdded(QString const & uni); void onDeviceRemoved(QString const & uni); void onActiveConnectionAdded(QString const & path); void onActiveConnectionRemoved(QString const & path); void onActiveConnectionsChanged(); //settings notifier void onConnectionAdded(QString const & path); void onConnectionRemoved(QString const & path); public: NetworkManager::ActiveConnection::List mActiveConns; NetworkManager::Connection::List mConnections; NetworkManager::Device::List mDevices; NetworkManager::WirelessNetwork::List mWifiNets; }; enum ItemId { ITEM_ROOT = 0x0 , ITEM_ACTIVE = 0x01 , ITEM_ACTIVE_LEAF = 0x11 , ITEM_CONNECTION = 0x2 , ITEM_CONNECTION_LEAF = 0x21 , ITEM_DEVICE = 0x3 , ITEM_DEVICE_LEAF = 0x31 , ITEM_WIFINET = 0x4 , ITEM_WIFINET_LEAF = 0x41 }; #endif //NMMODEL_P_H nm-tray-0.3.0/src/nmproxy.cpp000066400000000000000000000246041317132702700161210ustar00rootroot00000000000000/*COPYRIGHT_HEADER This file is a part of nm-tray. Copyright (c) 2015~now Palo Kisa nm-tray is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. COPYRIGHT_HEADER*/ #include "nmproxy.h" #include "log.h" void NmProxy::setSourceModel(QAbstractItemModel * sourceModel) { //we operate only on our known model Q_ASSERT(sourceModel->metaObject() == &NmModel::staticMetaObject); Q_ASSERT(root.isValid()); beginResetModel(); if (nullptr != this->sourceModel()) { disconnect(this->sourceModel(), &QAbstractItemModel::dataChanged, this, &NmProxy::onSourceDataChanged); disconnect(this->sourceModel(), &QAbstractItemModel::headerDataChanged, this, &NmProxy::onSourceHeaderDataChanged); disconnect(this->sourceModel(), &QAbstractItemModel::rowsAboutToBeInserted, this, &NmProxy::onSourceRowsAboutToBeInserted); disconnect(this->sourceModel(), &QAbstractItemModel::rowsInserted, this, &NmProxy::onSourceRowsInserted); disconnect(this->sourceModel(), &QAbstractItemModel::rowsAboutToBeRemoved, this, &NmProxy::onSourceRowsAboutToBeRemoved); disconnect(this->sourceModel(), &QAbstractItemModel::rowsRemoved, this, &NmProxy::onSourceRowsRemoved); disconnect(this->sourceModel(), &QAbstractItemModel::columnsAboutToBeInserted, this, &NmProxy::onSourceColumnsAboutToBeInserted); disconnect(this->sourceModel(), &QAbstractItemModel::columnsInserted, this, &NmProxy::onSourceColumnsInserted); disconnect(this->sourceModel(), &QAbstractItemModel::columnsAboutToBeRemoved, this, &NmProxy::onSourceColumnsAboutToBeRemoved); disconnect(this->sourceModel(), &QAbstractItemModel::columnsRemoved, this, &NmProxy::onSourceColumnsRemoved); disconnect(this->sourceModel(), &QAbstractItemModel::modelAboutToBeReset, this, &NmProxy::onSourceModelAboutToBeReset); disconnect(this->sourceModel(), &QAbstractItemModel::modelReset, this, &NmProxy::onSourceModelReset); disconnect(this->sourceModel(), &QAbstractItemModel::rowsAboutToBeMoved, this, &NmProxy::onSourceRowsAboutToBeMoved); disconnect(this->sourceModel(), &QAbstractItemModel::rowsMoved, this, &NmProxy::onSourceRowsMoved); disconnect(this->sourceModel(), &QAbstractItemModel::columnsAboutToBeMoved, this, &NmProxy::onSourceColumnsAboutToBeMoved); disconnect(this->sourceModel(), &QAbstractItemModel::columnsMoved, this, &NmProxy::onSourceColumnsMoved); } QAbstractProxyModel::setSourceModel(sourceModel); connect(sourceModel, &QAbstractItemModel::dataChanged, this, &NmProxy::onSourceDataChanged); connect(sourceModel, &QAbstractItemModel::headerDataChanged, this, &NmProxy::onSourceHeaderDataChanged); connect(sourceModel, &QAbstractItemModel::rowsAboutToBeInserted, this, &NmProxy::onSourceRowsAboutToBeInserted); connect(sourceModel, &QAbstractItemModel::rowsInserted, this, &NmProxy::onSourceRowsInserted); connect(sourceModel, &QAbstractItemModel::rowsAboutToBeRemoved, this, &NmProxy::onSourceRowsAboutToBeRemoved); connect(sourceModel, &QAbstractItemModel::rowsRemoved, this, &NmProxy::onSourceRowsRemoved); connect(sourceModel, &QAbstractItemModel::columnsAboutToBeInserted, this, &NmProxy::onSourceColumnsAboutToBeInserted); connect(sourceModel, &QAbstractItemModel::columnsInserted, this, &NmProxy::onSourceColumnsInserted); connect(sourceModel, &QAbstractItemModel::columnsAboutToBeRemoved, this, &NmProxy::onSourceColumnsAboutToBeRemoved); connect(sourceModel, &QAbstractItemModel::columnsRemoved, this, &NmProxy::onSourceColumnsRemoved); connect(sourceModel, &QAbstractItemModel::modelAboutToBeReset, this, &NmProxy::onSourceModelAboutToBeReset); connect(sourceModel, &QAbstractItemModel::modelReset, this, &NmProxy::onSourceModelReset); connect(sourceModel, &QAbstractItemModel::rowsAboutToBeMoved, this, &NmProxy::onSourceRowsAboutToBeMoved); connect(sourceModel, &QAbstractItemModel::rowsMoved, this, &NmProxy::onSourceRowsMoved); connect(sourceModel, &QAbstractItemModel::columnsAboutToBeMoved, this, &NmProxy::onSourceColumnsAboutToBeMoved); connect(sourceModel, &QAbstractItemModel::columnsMoved, this, &NmProxy::onSourceColumnsMoved); endResetModel(); } void NmProxy::setNmModel(NmModel * model, NmModel::ItemType shownType) { root = model->indexTypeRoot(shownType); setSourceModel(model); //qCDebug(NM_TRAY) << __FUNCTION__ << model->indexTypeRoot(shownType) << "->" << root; } QModelIndex NmProxy::index(int row, int column, const QModelIndex & proxyParent) const { QModelIndex i; if (hasIndex(row, column, proxyParent)) i = createIndex(row, column); //qCDebug(NM_TRAY) << __FUNCTION__ << row << column << proxyParent << "->" << i; return i; } QModelIndex NmProxy::parent(const QModelIndex &/*proxyIndex*/) const { //showing only one level/list: leaf -> invalid, root -> invalid QModelIndex i; //qCDebug(NM_TRAY) << __FUNCTION__ << proxyIndex << "->" << i; return i; } int NmProxy::rowCount(const QModelIndex &proxyParent) const { //showing only one level/list: leaf -> source root rowcount, root -> 0 if (proxyParent.isValid()) return 0; else return sourceModel()->rowCount(root); } int NmProxy::columnCount(const QModelIndex &proxyParent) const { return sourceModel()->columnCount(mapToSource(proxyParent)); } void NmProxy::activateConnection(QModelIndex const & index) const { qobject_cast(sourceModel())->activateConnection(mapToSource(index)); } void NmProxy::deactivateConnection(QModelIndex const & index) const { qobject_cast(sourceModel())->deactivateConnection(mapToSource(index)); } QModelIndex NmProxy::mapToSource(const QModelIndex & proxyIndex) const { QModelIndex i; if (proxyIndex.isValid()) i = sourceModel()->index(proxyIndex.row(), proxyIndex.column(), root); //qCDebug(NM_TRAY) << __FUNCTION__ << proxyIndex << "->" << i; return i; } QModelIndex NmProxy::mapFromSource(const QModelIndex & sourceIndex) const { QModelIndex i; if (sourceIndex.isValid() && root != sourceIndex) i = createIndex(sourceIndex.row(), sourceIndex.column()); //qCDebug(NM_TRAY) << __FUNCTION__ << sourceIndex << "->" << i; return i; } void NmProxy::onSourceDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector &roles) { if (root == topLeft.parent()) emit dataChanged(mapFromSource(topLeft), mapFromSource(bottomRight), roles); } void NmProxy::onSourceHeaderDataChanged(Qt::Orientation orientation, int first, int last) { emit headerDataChanged(orientation, first, last); } void NmProxy::onSourceRowsAboutToBeInserted(const QModelIndex &parent, int first, int last) { if (root == parent) beginInsertRows(mapFromSource(parent), first, last); } void NmProxy::onSourceRowsInserted(const QModelIndex &parent, int, int) { if (root == parent) endInsertRows(); } void NmProxy::onSourceRowsAboutToBeRemoved(const QModelIndex &parent, int first, int last) { if (root == parent) beginRemoveRows(mapFromSource(parent), first, last); } void NmProxy::onSourceRowsRemoved(const QModelIndex &parent, int, int) { if (root == parent) endRemoveRows(); } void NmProxy::onSourceColumnsAboutToBeInserted(const QModelIndex &parent, int first, int last) { if (root == parent) beginInsertColumns(mapFromSource(parent), first, last); } void NmProxy::onSourceColumnsInserted(const QModelIndex &parent, int, int) { if (root == parent) endInsertColumns(); } void NmProxy::onSourceColumnsAboutToBeRemoved(const QModelIndex &parent, int first, int last) { if (root == parent) beginRemoveColumns(mapFromSource(parent), first, last); } void NmProxy::onSourceColumnsRemoved(const QModelIndex &parent, int, int) { if (root == parent) endRemoveColumns(); } void NmProxy::onSourceModelAboutToBeReset() { beginResetModel(); } void NmProxy::onSourceModelReset() { endResetModel(); } void NmProxy::onSourceRowsAboutToBeMoved( const QModelIndex &sourceParent, int sourceStart, int sourceEnd, const QModelIndex &destinationParent, int destinationRow) { if (root == sourceParent) { if (root == destinationParent) beginMoveRows(mapFromSource(sourceParent), sourceStart, sourceEnd, destinationParent, destinationRow); else beginRemoveRows(mapFromSource(sourceParent), sourceStart, sourceEnd); } else if (root == destinationParent) beginInsertRows(mapFromSource(destinationParent), destinationRow, destinationRow + (sourceEnd - sourceStart)); } void NmProxy::onSourceRowsMoved( const QModelIndex &sourceParent, int, int, const QModelIndex &destinationParent, int) { if (root == sourceParent) { if (root == destinationParent) endMoveRows(); else endRemoveRows(); } else if (root == destinationParent) endInsertRows(); } void NmProxy::onSourceColumnsAboutToBeMoved( const QModelIndex &sourceParent, int sourceStart, int sourceEnd, const QModelIndex &destinationParent, int destinationColumn) { if (root == sourceParent) { if (root == destinationParent) beginMoveColumns(mapFromSource(sourceParent), sourceStart, sourceEnd, destinationParent, destinationColumn); else beginRemoveColumns(mapFromSource(sourceParent), sourceStart, sourceEnd); } else if (root == destinationParent) beginInsertColumns(mapFromSource(destinationParent), destinationColumn, destinationColumn + (sourceEnd - sourceStart)); } void NmProxy::onSourceColumnsMoved( const QModelIndex &sourceParent, int, int, const QModelIndex &destinationParent, int) { if (root == sourceParent) { if (root == destinationParent) endMoveColumns(); else endRemoveColumns(); } else if (root == destinationParent) endInsertColumns(); } nm-tray-0.3.0/src/nmproxy.h000066400000000000000000000065711317132702700155710ustar00rootroot00000000000000/*COPYRIGHT_HEADER This file is a part of nm-tray. Copyright (c) 2015~now Palo Kisa nm-tray is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. COPYRIGHT_HEADER*/ #if !defined(NMPROXY_H) #define NMPROXY_H #include #include "nmmodel.h" class NmProxy : public QAbstractProxyModel { Q_OBJECT public: using QAbstractProxyModel::QAbstractProxyModel; virtual void setSourceModel(QAbstractItemModel * sourceModel) override; void setNmModel(NmModel * model, NmModel::ItemType shownType); virtual QModelIndex index(int row, int column, const QModelIndex & parent = QModelIndex()) const override; virtual QModelIndex parent(const QModelIndex &index) const override; virtual int rowCount(const QModelIndex &parent = QModelIndex()) const override; virtual int columnCount(const QModelIndex &parent = QModelIndex()) const override; void activateConnection(QModelIndex const & index) const; void deactivateConnection(QModelIndex const & index) const; protected: virtual QModelIndex mapToSource(const QModelIndex & proxyIndex) const override; virtual QModelIndex mapFromSource(const QModelIndex & sourceIndex) const override; private Q_SLOTS: void onSourceDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector &roles = QVector()); void onSourceHeaderDataChanged(Qt::Orientation orientation, int first, int last); void onSourceRowsAboutToBeInserted(const QModelIndex &parent, int first, int last); void onSourceRowsInserted(const QModelIndex &parent, int first, int last); void onSourceRowsAboutToBeRemoved(const QModelIndex &parent, int first, int last); void onSourceRowsRemoved(const QModelIndex &parent, int first, int last); void onSourceColumnsAboutToBeInserted(const QModelIndex &parent, int first, int last); void onSourceColumnsInserted(const QModelIndex &parent, int first, int last); void onSourceColumnsAboutToBeRemoved(const QModelIndex &parent, int first, int last); void onSourceColumnsRemoved(const QModelIndex &parent, int first, int last); void onSourceModelAboutToBeReset(); void onSourceModelReset(); void onSourceRowsAboutToBeMoved( const QModelIndex &sourceParent, int sourceStart, int sourceEnd, const QModelIndex &destinationParent, int destinationRow); void onSourceRowsMoved( const QModelIndex &parent, int start, int end, const QModelIndex &destination, int row); void onSourceColumnsAboutToBeMoved( const QModelIndex &sourceParent, int sourceStart, int sourceEnd, const QModelIndex &destinationParent, int destinationColumn); void onSourceColumnsMoved( const QModelIndex &parent, int start, int end, const QModelIndex &destination, int column); private: QModelIndex root; }; #endif //NMPROXY_H nm-tray-0.3.0/src/translate.cpp000066400000000000000000000031661317132702700164020ustar00rootroot00000000000000/*COPYRIGHT_HEADER This file is a part of nm-tray. Copyright (c) 2015~now Palo Kisa nm-tray is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. COPYRIGHT_HEADER*/ #include #include #include #include #if !defined(TRANSLATION_DIR) #define TRANSLATION_DIR "/usr/share/nm-tray" #endif void translate() { const QString locale = QLocale::system().name(); QTranslator * qt_trans = new QTranslator{qApp}; if (qt_trans->load(QLatin1String("qt_") + locale, QLibraryInfo::location(QLibraryInfo::TranslationsPath))) qApp->installTranslator(qt_trans); else delete qt_trans; QString trans_dir = qgetenv("NM_TRAY_TRANSLATION_DIR").constData(); QTranslator * my_trans = new QTranslator{qApp}; if (my_trans->load(QLatin1String("nm-tray_") + locale, trans_dir.isEmpty() ? TRANSLATION_DIR : trans_dir)) qApp->installTranslator(my_trans); else delete my_trans; } Q_COREAPP_STARTUP_FUNCTION(translate) nm-tray-0.3.0/src/tray.cpp000066400000000000000000000361271317132702700153670ustar00rootroot00000000000000/*COPYRIGHT_HEADER This file is a part of nm-tray. Copyright (c) 2015~now Palo Kisa nm-tray is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. COPYRIGHT_HEADER*/ #include "tray.h" #include #include #include #include #include #include #include #include "icons.h" #include "nmmodel.h" #include "nmproxy.h" #include "log.h" #include "dbus/org.freedesktop.Notifications.h" #include "nmlist.h" #include "connectioninfo.h" #include "windowmenu.h" // config keys static const QString ENABLE_NOTIFICATIONS = QStringLiteral("enableNotifications"); class TrayPrivate { public: TrayPrivate(); void updateState(QModelIndex const & index, bool removing); void primaryConnectionUpdate(); void setShown(QPersistentModelIndex const & index); void updateIcon(); void refreshIcon(); void openCloseDialog(QDialog * dialog); void notify(QModelIndex const & index, bool removing); public: QSystemTrayIcon mTrayIcon; QMenu mContextMenu; QTimer mStateTimer; QAction * mActEnableNetwork; QAction * mActEnableWifi; QAction * mActConnInfo; QAction * mActDebugInfo; NmModel mNmModel; NmProxy mActiveConnections; QPersistentModelIndex mPrimaryConnection; QPersistentModelIndex mShownConnection; QList mConnectionsToNotify; //!< just "created" connections to which notification wasn't sent yet icons::Icon mIconCurrent; icons::Icon mIcon2Show; QTimer mIconTimer; QScopedPointer mConnDialog; QScopedPointer mInfoDialog; org::freedesktop::Notifications mNotification; // configuration bool mEnableNotifications; //!< should info about connection establishment etc. be send by org.freedesktop.Notifications }; TrayPrivate::TrayPrivate() : mNotification{QStringLiteral("org.freedesktop.Notifications"), QStringLiteral("/org/freedesktop/Notifications"), QDBusConnection::sessionBus()} { mActiveConnections.setNmModel(&mNmModel, NmModel::ActiveConnectionType); } void TrayPrivate::updateState(QModelIndex const & index, bool removing) { notify(index, removing); const auto state = static_cast(mActiveConnections.data(index, NmModel::ActiveConnectionStateRole).toInt()); const bool is_primary = mPrimaryConnection == index; //qCDebug(NM_TRAY) << __FUNCTION__ << index << removing << mActiveConnections.data(index, NmModel::NameRole) << mActiveConnections.data(index, NmModel::ConnectionUuidRole).toString() << is_primary << mActiveConnections.data(index, NmModel::ConnectionTypeRole).toInt() << state; if (removing || NetworkManager::ActiveConnection::Deactivated == state || NetworkManager::ActiveConnection::Deactivating == state) { if (is_primary) { mPrimaryConnection = QModelIndex{}; setShown(mPrimaryConnection); } else if (mShownConnection == index) { setShown(mPrimaryConnection); } } else { if (is_primary || NetworkManager::ActiveConnection::Activating == state) { setShown(index); } else if (mShownConnection == index) { setShown(mPrimaryConnection); } } //TODO: optimize this text assembly (to not do it every time)? if (mPrimaryConnection.isValid()) { mTrayIcon.setToolTip(Tray::tr("
Connection %1(%2) active
") .arg(mPrimaryConnection.data(NmModel::NameRole).toString()) .arg(mPrimaryConnection.data(NmModel::ActiveConnectionTypeStringRole).toString()) ); } else { mTrayIcon.setToolTip(Tray::tr("
No active connection
")); } } void TrayPrivate::primaryConnectionUpdate() { NetworkManager::ActiveConnection::Ptr prim_conn = NetworkManager::primaryConnection(); if (!prim_conn || !prim_conn->isValid()) { mPrimaryConnection = QModelIndex{}; setShown(mPrimaryConnection); return; } //qCDebug(NM_TRAY) << __FUNCTION__ << prim_conn->uuid(); QModelIndexList l = mActiveConnections.match(mActiveConnections.index(0, 0, QModelIndex{}), NmModel::ActiveConnectionUuidRole, prim_conn->uuid(), -1, Qt::MatchExactly); //qCDebug(NM_TRAY) << __FUNCTION__ << l.size(); //nothing to do if the connection not populated in model yet if (0 >= l.size()) return; Q_ASSERT(1 == l.size()); mPrimaryConnection = l.first(); updateState(mPrimaryConnection, false); } void TrayPrivate::setShown(QPersistentModelIndex const & index) { mShownConnection = index; mIcon2Show = mShownConnection.isValid() ? static_cast(mActiveConnections.data(mShownConnection, NmModel::IconTypeRole).toInt()) : icons::NETWORK_OFFLINE; //postpone setting the icon (for case we change the icon in till our event is finished) mIconTimer.start(); } void TrayPrivate::updateIcon() { if (mIconCurrent == mIcon2Show) return; mIconCurrent = mIcon2Show; refreshIcon(); } void TrayPrivate::refreshIcon() { //Note: the icons::getIcon chooses the right icon from list of possible candidates // -> we need to refresh the icon in case of icon theme change mTrayIcon.setIcon(icons::getIcon(mIconCurrent)); } void TrayPrivate::openCloseDialog(QDialog * dialog) { if (dialog->isHidden() || dialog->isMinimized()) { dialog->showNormal(); dialog->activateWindow(); dialog->raise(); } else dialog->close(); } void TrayPrivate::notify(QModelIndex const & index, bool removing) { if (!mEnableNotifications) { return; } QString summary, body; if (removing) { mConnectionsToNotify.removeOne(index); summary = Tray::tr("Connection lost"); body = Tray::tr("We have just lost the connection to %1 '%2'."); } else { const int notif_i = mConnectionsToNotify.indexOf(index); // do nothing if not just added or the connection is not activated yet if (-1 == notif_i || NetworkManager::ActiveConnection::Activated != static_cast(mActiveConnections.data(index, NmModel::ActiveConnectionStateRole).toInt()) ) { return; } mConnectionsToNotify.removeAt(notif_i); // fire the notification only once summary = Tray::tr("Connection established"); body = Tray::tr("We have just established the connection to %1 '%2'."); } // TODO: do somehow check the result? mNotification.Notify(Tray::tr("NetworkManager(nm-tray)") , 0 , icons::getIcon(static_cast(mActiveConnections.data(index, NmModel::IconTypeRole).toInt())).name() , summary , body.arg(mActiveConnections.data(index, NmModel::ConnectionTypeStringRole).toString()).arg(mActiveConnections.data(index, NmModel::NameRole).toString()) , {} , {} , -1); } Tray::Tray(QObject *parent/* = nullptr*/) : QObject{parent} , d{new TrayPrivate} { d->mEnableNotifications = QSettings{}.value(ENABLE_NOTIFICATIONS, true).toBool(); connect(&d->mTrayIcon, &QSystemTrayIcon::activated, this, &Tray::onActivated); //postpone the update in case of signals flood connect(&d->mStateTimer, &QTimer::timeout, this, &Tray::setActionsStates); d->mStateTimer.setSingleShot(true); d->mStateTimer.setInterval(200); d->mIconCurrent = static_cast(-1); d->setShown(QModelIndex{}); d->refreshIcon(); //force setting the icon instantly //postpone updating of the icon connect(&d->mIconTimer, &QTimer::timeout, [this] { d->updateIcon(); }); d->mIconTimer.setSingleShot(true); d->mIconTimer.setInterval(0); d->mActEnableNetwork = d->mContextMenu.addAction(Tray::tr("Enable Networking")); d->mActEnableWifi = d->mContextMenu.addAction(Tray::tr("Enable Wi-fi")); d->mContextMenu.addSeparator(); QAction * enable_notifications = d->mContextMenu.addAction(Tray::tr("Enable notifications")); d->mContextMenu.addSeparator(); d->mActConnInfo = d->mContextMenu.addAction(QIcon::fromTheme(QStringLiteral("dialog-information")), Tray::tr("Connection information")); d->mActDebugInfo = d->mContextMenu.addAction(QIcon::fromTheme(QStringLiteral("dialog-information")), Tray::tr("Debug information")); connect(d->mContextMenu.addAction(QIcon::fromTheme(QStringLiteral("document-edit")), Tray::tr("Edit connections...")), &QAction::triggered , this, &Tray::onEditConnectionsTriggered); d->mContextMenu.addSeparator(); connect(d->mContextMenu.addAction(QIcon::fromTheme(QStringLiteral("help-about")), Tray::tr("About")), &QAction::triggered , this, &Tray::onAboutTriggered); connect(d->mContextMenu.addAction(QIcon::fromTheme(QStringLiteral("application-exit")), Tray::tr("Quit")), &QAction::triggered , this, &Tray::onQuitTriggered); //for listening on the QEvent::ThemeChange (is delivered only to QWidget objects) d->mContextMenu.installEventFilter(this); d->mActEnableNetwork->setCheckable(true); d->mActEnableWifi->setCheckable(true); enable_notifications->setCheckable(true); enable_notifications->setChecked(d->mEnableNotifications); connect(d->mActEnableNetwork, &QAction::triggered, [this] (bool checked) { NetworkManager::setNetworkingEnabled(checked); }); connect(d->mActEnableWifi, &QAction::triggered, [this] (bool checked) { NetworkManager::setWirelessEnabled(checked); }); connect(enable_notifications, &QAction::triggered, [this] (bool checked) { d->mEnableNotifications = checked; QSettings{}.setValue(ENABLE_NOTIFICATIONS, checked); }); connect(d->mActConnInfo, &QAction::triggered, [this] (bool ) { if (d->mInfoDialog.isNull()) { d->mInfoDialog.reset(new ConnectionInfo{&d->mNmModel}); connect(d->mInfoDialog.data(), &QDialog::finished, [this] { d->mInfoDialog.reset(nullptr); }); } d->openCloseDialog(d->mInfoDialog.data()); }); connect(d->mActDebugInfo, &QAction::triggered, [this] (bool ) { if (d->mConnDialog.isNull()) { d->mConnDialog.reset(new NmList{Tray::tr("nm-tray info"), &d->mNmModel}); connect(d->mConnDialog.data(), &QDialog::finished, [this] { d->mConnDialog.reset(nullptr); }); } d->openCloseDialog(d->mConnDialog.data()); }); // Note: Force all the updates as the NetworkManager::Notifier signals aren't // emitted at application startup. d->primaryConnectionUpdate(); setActionsStates(); connect(NetworkManager::notifier(), &NetworkManager::Notifier::networkingEnabledChanged, &d->mStateTimer, static_cast(&QTimer::start)); connect(NetworkManager::notifier(), &NetworkManager::Notifier::wirelessEnabledChanged, &d->mStateTimer, static_cast(&QTimer::start)); connect(NetworkManager::notifier(), &NetworkManager::Notifier::wirelessHardwareEnabledChanged, &d->mStateTimer, static_cast(&QTimer::start)); connect(NetworkManager::notifier(), &NetworkManager::Notifier::primaryConnectionChanged, this, &Tray::onPrimaryConnectionChanged); connect(&d->mActiveConnections, &QAbstractItemModel::rowsInserted, [this] (QModelIndex const & parent, int first, int last) { for (int i = first; i <= last; ++i) { const QModelIndex index = d->mActiveConnections.index(i, 0, parent); //qCDebug(NM_TRAY) << "rowsInserted" << index; if (d->mEnableNotifications) { d->mConnectionsToNotify.append(index); } d->updateState(index, false); } }); connect(&d->mActiveConnections, &QAbstractItemModel::rowsAboutToBeRemoved, [this] (QModelIndex const & parent, int first, int last) { //qCDebug(NM_TRAY) << "rowsAboutToBeRemoved"; for (int i = first; i <= last; ++i) d->updateState(d->mActiveConnections.index(i, 0, parent), true); }); connect(&d->mActiveConnections, &QAbstractItemModel::dataChanged, [this] (const QModelIndex & topLeft, const QModelIndex & bottomRight, const QVector & /*roles*/) { //qCDebug(NM_TRAY) << "dataChanged"; for (auto const & i : QItemSelection{topLeft, bottomRight}.indexes()) d->updateState(i, false); }); d->mTrayIcon.setContextMenu(&d->mContextMenu); QTimer::singleShot(0, [this] { d->mTrayIcon.show(); }); } Tray::~Tray() { } bool Tray::eventFilter(QObject * object, QEvent * event) { Q_ASSERT(&d->mContextMenu == object); if (QEvent::ThemeChange == event->type()) d->refreshIcon(); return false; } void Tray::onEditConnectionsTriggered() { // Note: let this object dangle, if the process isn't finished until our application is closed QProcess * editor = new QProcess; editor->setProcessChannelMode(QProcess::ForwardedChannels); // TODO: allow the command to be configurable!? qCInfo(NM_TRAY) << "starting the nm-connection-editor"; editor->start(QStringLiteral("nm-connection-editor")); editor->closeWriteChannel(); connect(editor, static_cast(&QProcess::finished), [editor] { qCInfo(NM_TRAY) << "the nm-connection-editor finished"; editor->deleteLater(); }); } void Tray::onAboutTriggered() { QMessageBox::about(nullptr, Tray::tr("%1 about").arg(QStringLiteral("nm-tray")) , Tray::tr("nm-tray is a simple Qt based" " frontend for NetworkManager.

" "Version: %1").arg(NM_TRAY_VERSION)); } void Tray::onQuitTriggered() { QApplication::instance()->quit(); } void Tray::onActivated() { QMenu * menu = new WindowMenu(&d->mNmModel); menu->setAttribute(Qt::WA_DeleteOnClose); menu->popup(QCursor::pos()); } void Tray::setActionsStates() { const bool net_enabled = NetworkManager::isNetworkingEnabled(); d->mActEnableNetwork->setChecked(net_enabled); d->mActEnableWifi->setChecked(NetworkManager::isWirelessEnabled()); d->mActEnableWifi->setEnabled(NetworkManager::isNetworkingEnabled() && NetworkManager::isWirelessHardwareEnabled()); d->mActConnInfo->setEnabled(net_enabled); } void Tray::onPrimaryConnectionChanged(QString const & /*uni*/) { d->primaryConnectionUpdate(); } nm-tray-0.3.0/src/tray.h000066400000000000000000000026171317132702700150310ustar00rootroot00000000000000/*COPYRIGHT_HEADER This file is a part of nm-tray. Copyright (c) 2015~now Palo Kisa nm-tray is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. COPYRIGHT_HEADER*/ #if !defined(TRAY_H) #define TRAY_H #include #include class TrayPrivate; class Tray : public QObject { Q_OBJECT public: Tray(QObject *parent = nullptr); ~Tray(); protected: virtual bool eventFilter(QObject * object, QEvent * event) override; private Q_SLOTS: //menu void onEditConnectionsTriggered(); void onAboutTriggered(); void onQuitTriggered(); void onActivated(); //NetworkManager void setActionsStates(); void onPrimaryConnectionChanged(QString const & uni); private: QScopedPointer d; }; #endif //TRAY_H nm-tray-0.3.0/src/windowmenu.cpp000066400000000000000000000156101317132702700165760ustar00rootroot00000000000000/*COPYRIGHT_HEADER This file is a part of nm-tray. Copyright (c) 2016~now Palo Kisa nm-tray is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. COPYRIGHT_HEADER*/ #include "windowmenu.h" #include "nmmodel.h" #include "nmproxy.h" #include "menuview.h" #include #include #include class WindowMenuPrivate { public: NmModel * mNmModel; QScopedPointer mWirelessModel; QWidgetAction * mWirelessAction; QScopedPointer mActiveModel; QWidgetAction * mActiveAction; QScopedPointer mConnectionModel; QWidgetAction * mConnectionAction; QAction * mMakeDirtyAction; QTimer mDelaySizeRefreshTimer; WindowMenuPrivate(WindowMenu * q); template void onActivated(QModelIndex const & index , QAbstractItemModel const * topParent , F const & functor); void forceSizeRefresh(); void onViewRowChange(QAction * viewAction, QAbstractItemModel const * model); private: WindowMenu * q_ptr; Q_DECLARE_PUBLIC(WindowMenu); }; WindowMenuPrivate::WindowMenuPrivate(WindowMenu * q) : q_ptr{q} { } template void WindowMenuPrivate::onActivated(QModelIndex const & index , QAbstractItemModel const * topParent , F const & functor) { QModelIndex i = index; for (QAbstractProxyModel const * proxy = qobject_cast(index.model()) ; nullptr != proxy && topParent != proxy ; proxy = qobject_cast(proxy->sourceModel()) ) { i = proxy->mapToSource(i); } functor(i); } void WindowMenuPrivate::forceSizeRefresh() { Q_Q(WindowMenu); if (!q->isVisible()) { return; } const QSize old_size = q->size(); //TODO: how to force the menu to recalculate it's size in a more elegant way? q->addAction(mMakeDirtyAction); q->removeAction(mMakeDirtyAction); // ensure to be visible (should the resize make it out of screen) if (old_size != q->size()) { q->popup(q->geometry().topLeft()); } } void WindowMenuPrivate::onViewRowChange(QAction * viewAction, QAbstractItemModel const * model) { viewAction->setVisible(model->rowCount(QModelIndex{}) > 0); mDelaySizeRefreshTimer.start(); } WindowMenu::WindowMenu(NmModel * nmModel, QWidget * parent /*= nullptr*/) : QMenu{parent} , d_ptr{new WindowMenuPrivate{this}} { Q_D(WindowMenu); d->mNmModel = nmModel; //active proxy & widgets d->mActiveModel.reset(new NmProxy); d->mActiveModel->setNmModel(d->mNmModel, NmModel::ActiveConnectionType); MenuView * active_view = new MenuView{d->mActiveModel.data()}; connect(active_view, &QAbstractItemView::activated, [this, d] (const QModelIndex & index) { d->onActivated(index, d->mActiveModel.data(), std::bind(&NmProxy::deactivateConnection, d->mActiveModel.data(), std::placeholders::_1)); close(); }); d->mActiveAction = new QWidgetAction{this}; d->mActiveAction->setDefaultWidget(active_view); connect(d->mActiveModel.data(), &QAbstractItemModel::modelReset, [d] { d->onViewRowChange(d->mActiveAction, d->mActiveModel.data()); }); connect(d->mActiveModel.data(), &QAbstractItemModel::rowsInserted, [d] { d->onViewRowChange(d->mActiveAction, d->mActiveModel.data()); }); connect(d->mActiveModel.data(), &QAbstractItemModel::rowsRemoved, [d] { d->onViewRowChange(d->mActiveAction, d->mActiveModel.data()); }); //wireless proxy & widgets d->mWirelessModel.reset(new NmProxy); d->mWirelessModel->setNmModel(d->mNmModel, NmModel::WifiNetworkType); MenuView * wifi_view = new MenuView{d->mWirelessModel.data()}; connect(wifi_view, &QAbstractItemView::activated, [this, d] (const QModelIndex & index) { d->onActivated(index, d->mWirelessModel.data(), std::bind(&NmProxy::activateConnection, d->mWirelessModel.data(), std::placeholders::_1)); close(); }); d->mWirelessAction = new QWidgetAction{this}; d->mWirelessAction->setDefaultWidget(wifi_view); connect(d->mWirelessModel.data(), &QAbstractItemModel::modelReset, [d] { d->onViewRowChange(d->mWirelessAction, d->mWirelessModel.data()); }); connect(d->mWirelessModel.data(), &QAbstractItemModel::rowsInserted, [d] { d->onViewRowChange(d->mWirelessAction, d->mWirelessModel.data()); }); connect(d->mWirelessModel.data(), &QAbstractItemModel::rowsRemoved, [d] { d->onViewRowChange(d->mWirelessAction, d->mWirelessModel.data()); }); //connection proxy & widgets d->mConnectionModel.reset(new NmProxy); d->mConnectionModel->setNmModel(d->mNmModel, NmModel::ConnectionType); MenuView * connection_view = new MenuView{d->mConnectionModel.data()}; connect(connection_view, &QAbstractItemView::activated, [this, d] (const QModelIndex & index) { d->onActivated(index, d->mConnectionModel.data(), std::bind(&NmProxy::activateConnection, d->mConnectionModel.data(), std::placeholders::_1)); close(); }); d->mConnectionAction = new QWidgetAction{this}; d->mConnectionAction->setDefaultWidget(connection_view); connect(d->mConnectionModel.data(), &QAbstractItemModel::modelReset, [d] { d->onViewRowChange(d->mConnectionAction, d->mConnectionModel.data()); }); connect(d->mConnectionModel.data(), &QAbstractItemModel::rowsInserted, [d] { d->onViewRowChange(d->mConnectionAction, d->mConnectionModel.data()); }); connect(d->mConnectionModel.data(), &QAbstractItemModel::rowsRemoved, [d] { d->onViewRowChange(d->mConnectionAction, d->mConnectionModel.data()); }); addAction(tr("Active connection(s)"))->setEnabled(false); addAction(d->mActiveAction); addAction(tr("Wi-Fi network(s)"))->setEnabled(false); addAction(d->mWirelessAction); addAction(tr("Known connection(s)"))->setEnabled(false); addAction(d->mConnectionAction); d->mMakeDirtyAction = new QAction{this}; d->mDelaySizeRefreshTimer.setInterval(200); d->mDelaySizeRefreshTimer.setSingleShot(true); connect(&d->mDelaySizeRefreshTimer, &QTimer::timeout, [d] { d->forceSizeRefresh(); }); d->onViewRowChange(d->mActiveAction, d->mActiveModel.data()); d->onViewRowChange(d->mWirelessAction, d->mWirelessModel.data()); d->onViewRowChange(d->mConnectionAction, d->mConnectionModel.data()); } WindowMenu::~WindowMenu() { } nm-tray-0.3.0/src/windowmenu.h000066400000000000000000000022311317132702700162360ustar00rootroot00000000000000/*COPYRIGHT_HEADER This file is a part of nm-tray. Copyright (c) 2016~now Palo Kisa nm-tray is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. COPYRIGHT_HEADER*/ #if !defined(WINDOW_MENU_H) #define WINDOW_MENU_H #include class WindowMenuPrivate; class NmModel; class WindowMenu : public QMenu { Q_OBJECT public: WindowMenu(NmModel * nmModel, QWidget * parent = nullptr); ~WindowMenu(); private: QScopedPointer d_ptr; Q_DECLARE_PRIVATE(WindowMenu); }; #endif //WINDOW_MENU_H nm-tray-0.3.0/translations/000077500000000000000000000000001317132702700156255ustar00rootroot00000000000000nm-tray-0.3.0/translations/nm-tray.ts000066400000000000000000000223651317132702700175740ustar00rootroot00000000000000 ConnectionInfo Connection information NmList Dialog All information Active connections Available wireless NmModel root active connection(s) connection(s) device(s) wifi network(s) unknown hardware address nm-tray - wireless password Password is needed for connection to '%1': General Active connection information Interface Active connection information Hardware Address Active connection information Driver Active connection information Speed Active connection information Kb/s unknown Speed Security Active connection information IPv4 Active connection information IPv6 Active connection information IP Address Active connection information Subnet Mask Active connection information Default route Active connection information DNS(%1) Active connection information Tray Connection lost We have just lost the connection to %1 '%2'. Connection established We have just established the connection to %1 '%2'. NetworkManager(nm-tray) Enable Networking Enable Wi-fi Enable notifications Connection information Debug information About Quit %1 about <strong><a href="https://github.com/palinek/nm-tray">nm-tray</a></strong> is a simple Qt based frontend for <a href="https://wiki.gnome.org/Projects/NetworkManager">NetworkManager</a>.<br/><br/>Version: %1 nm-tray info WindowMenu Active connection(s) Wi-Fi network(s) nm-tray-0.3.0/translations/nm-tray_de.ts000066400000000000000000000236021317132702700202370ustar00rootroot00000000000000 ConnectionInfo Connection information Verbindungsinformationen NmList Dialog Did not translate as "Dialog" seems to get replaced with string "nm-tray info" from context "Tray". Dialog All information Verfügbare Informationen Active connections Aktive Verbindungen Available wireless Verfügbare drahtlose Verbindungen NmModel root Translated as "network" hence not literally at all. Not sure what's best here but this seems a bit more reasonable to me. Netzwerk active connection(s) Aktive Verbindungen connection(s) Verbindungen device(s) Geräte wifi network(s) Drahtlose Netzwerke unknown hardware address unbekannt nm-tray - wireless password Password is needed for connection to '%1': General Active connection information Allgemeines Interface Active connection information Schnittstelle Hardware Address Active connection information Hardware-Adresse Driver Active connection information Treiber Speed Active connection information Übertragungsrate Kb/s Kb/s unknown Speed unbekannt Security Active connection information Sicherheit IPv4 Active connection information IPv6 Active connection information IP Address Active connection information Subnet Mask Active connection information Default route Active connection information DNS(%1) Active connection information Tray Connection lost We have just lost the connection to %1 '%2'. Connection established We have just established the connection to %1 '%2'. NetworkManager(nm-tray) Enable Networking Netzwerk aktivieren Enable Wi-fi Drahtlose Verbindungen aktivieren Enable notifications Connection information Verbindungsinformationen Debug information About Über Quit Beenden %1 about %1 über <strong><a href="https://github.com/palinek/nm-tray">nm-tray</a></strong> is a simple Qt based frontend for <a href="https://wiki.gnome.org/Projects/NetworkManager">NetworkManager</a>.<br/><br/>Version: %1 This is the about nm-tray! Pimped this a little bit. Hope that's okay. nm-tray ist eine auf Qt basierende Nutzeroberfläche für den NetworkManager zur Ausführung in der Leiste von Desktop-Umgebungen. nm-tray info nm-tray Informationen WindowMenu Active connection(s) Wi-Fi network(s) nm-tray-0.3.0/translations/nm-tray_pl.ts000066400000000000000000000230151317132702700202600ustar00rootroot00000000000000 ConnectionInfo Connection information Informacje o połączeniu NmList Dialog Okno dialogowe All information Wszystkie informacje Active connections Aktywne połączenia Available wireless Dostępne połączenia bezprzewodowe NmModel root root active connection(s) aktywne połączenia connection(s) połączenia device(s) urządzenia wifi network(s) sieci bezprzewodowe unknown hardware address nieznany nm-tray - wireless password nm-tray - hasło połączenia bezprzewodowego Password is needed for connection to '%1': Potrzebne jest hasło, aby połączyć się z '%1': General Active connection information Ogólne Interface Active connection information Interfejs Hardware Address Active connection information Adres urządzenia Driver Active connection information Informacje o aktywnym połączeniu Speed Active connection information Prędkość Kb/s Kb/s unknown Speed nieznana Security Active connection information Bezpieczeństwo IPv4 Active connection information IPv4 IPv6 Active connection information IPv6 IP Address Active connection information Adres IP Subnet Mask Active connection information Maska podsieci Default route Active connection information Brama domyślna DNS(%1) Active connection information DNS(%1) Tray Connection lost Utracono połączenie We have just lost the connection to %1 '%2'. Utracono połączenie z %1 '%2'. Connection established Ustanowiono połączenie We have just established the connection to %1 '%2'. Ustanowiono połączenie z %1 '%2'. NetworkManager(nm-tray) NetworkManager(nm-tray) Enable Networking Włącz sieci Enable Wi-fi Włącz Wi-Fi Enable notifications Włącz powiadomienia Connection information Informacje o połączeniu Debug information Informacje debugowania About O programie Quit Zakończ %1 about o %1 <strong><a href="https://github.com/palinek/nm-tray">nm-tray</a></strong> is a simple Qt based frontend for <a href="https://wiki.gnome.org/Projects/NetworkManager">NetworkManager</a>.<br/><br/>Version: %1 <strong><a href="https://github.com/palinek/nm-tray">nm-tray</a></strong> jest prostą, napisaną w Qt nakładką dla <a href="https://wiki.gnome.org/Projects/NetworkManager">NetworkManagera</a>.<br/><br/>Wersja: %1 nm-tray info Informacje o nm-tray WindowMenu Active connection(s) Aktywne połączenia Wi-Fi network(s) Sieci Wi-Fi nm-tray-0.3.0/translations/nm-tray_sk.ts000066400000000000000000000223311317132702700202620ustar00rootroot00000000000000 ConnectionInfo Connection information Informácie o spojení NmList Dialog All information Všetky informácie Active connections Aktívne spojenia Available wireless Dostupné bezdôtové NmModel root active connection(s) aktívne spojenie/a connection(s) spojenie/a device(s) zariadenie/a wifi network(s) wifi sieť/siete unknown hardware address neznáme nm-tray - wireless password Password is needed for connection to '%1': General Active connection information Základné Interface Active connection information Rozhranie Hardware Address Active connection information Hardvérová adresa Driver Active connection information Ovládač Speed Active connection information Rýchlosť Kb/s unknown Speed neznáme Security Active connection information Bezpečnosť IPv4 Active connection information IPv6 Active connection information IP Address Active connection information Subnet Mask Active connection information Default route Active connection information DNS(%1) Active connection information Tray Connection lost We have just lost the connection to %1 '%2'. Connection established We have just established the connection to %1 '%2'. NetworkManager(nm-tray) Enable Networking don't know how to correctly translate Zapnúť sieť Enable Wi-fi Zapnúť Wi-fi Enable notifications Connection information Informácie o spojení Debug information About O ... Quit Vypnúť %1 about O %1 <strong><a href="https://github.com/palinek/nm-tray">nm-tray</a></strong> is a simple Qt based frontend for <a href="https://wiki.gnome.org/Projects/NetworkManager">NetworkManager</a>.<br/><br/>Version: %1 nm-tray info nm-tray info WindowMenu Active connection(s) Wi-Fi network(s)