diff --git a/CMakeLists.txt b/CMakeLists.txt index a7bed0e..74b5203 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,142 +1,144 @@ project(kinfocenter) set(PROJECT_VERSION "5.18.80") cmake_minimum_required(VERSION 2.8.12 FATAL_ERROR) set(QT_MIN_VERSION "5.12.0") set(KF5_MIN_VERSION "5.66.0") find_package(ECM ${KF5_MIN_VERSION} REQUIRED NO_MODULE) set(CMAKE_MODULE_PATH ${ECM_MODULE_PATH} ${ECM_KDE_MODULE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/cmake) include(KDEInstallDirs) include(KDECMakeSettings) include(KDECompilerSettings NO_POLICY_SCOPE) include(FeatureSummary) include(KDEClangFormat) +include(ECMQMLModules) find_package(Qt5 ${QT_MIN_VERSION} CONFIG REQUIRED COMPONENTS Core Gui Widgets) find_package(KF5 ${KF5_MIN_VERSION} REQUIRED COMPONENTS Completion Config ConfigWidgets CoreAddons Crash DBusAddons DocTools I18n IconThemes KCMUtils KIO Service Solid WidgetsAddons WindowSystem XmlGui Declarative Package Solid ) if(${Qt5Gui_OPENGL_IMPLEMENTATION} STREQUAL "GL") find_package(OpenGL) set_package_properties(OpenGL PROPERTIES DESCRIPTION "The OpenGL libraries" URL "https://www.opengl.org" TYPE OPTIONAL ) else() find_package(OpenGLES) set_package_properties(OpenGLES PROPERTIES DESCRIPTION "The OpenGLES libraries" URL "https://www.khronos.org/opengles" TYPE OPTIONAL ) endif() find_package(EGL) set_package_properties(EGL PROPERTIES TYPE OPTIONAL PURPOSE "Required for OpenGL Information Module" ) find_package(KF5Wayland CONFIG) set_package_properties(KF5Wayland PROPERTIES TYPE OPTIONAL ) add_feature_info("KF5Wayland" KF5Wayland_FOUND "Required for Wayland Compositor Information Module") if(NOT APPLE) find_package(X11) set_package_properties(X11 PROPERTIES DESCRIPTION "X11 libraries" URL "https://www.x.org" TYPE OPTIONAL PURPOSE "Required for building the X11 based workspace" ) if(X11_FOUND) set(HAVE_X11 TRUE) endif() else() set(X11_FOUND False) endif() +ecm_find_qmlmodule(org.kde.kirigami 2.5) configure_file(config-project-version.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-project-version.h) configure_file(config-X11.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-X11.h) include_directories(${CMAKE_CURRENT_BINARY_DIR}) remove_definitions(-DQT_NO_CAST_FROM_ASCII -DQT_NO_CAST_FROM_BYTEARRAY -DQT_NO_KEYWORDS) add_definitions(-DQT_NO_NARROWING_CONVERSIONS_IN_CONNECT) add_definitions(-DQT_NO_URL_CAST_FROM_STRING) add_definitions(-DQT_USE_QSTRINGBUILDER) add_subdirectory( Categories ) add_subdirectory( kcontrol/menus ) add_subdirectory( Modules ) include(ECMOptionalAddSubdirectory) ecm_optional_add_subdirectory( doc ) include_directories( ToolTips ) set( kinfocenter_SRCS infocenter.cpp main.cpp sidepanel.cpp kcmcontainer.cpp kcmtreeitem.cpp kcmcategoryitem.cpp infokcmmodel.cpp infokcmproxymodel.cpp ToolTips/tooltipmanager.cpp ) add_executable( kinfocenter ${kinfocenter_SRCS} ) target_compile_definitions(kinfocenter PRIVATE -DPROJECT_VERSION="${PROJECT_VERSION}") target_link_libraries( kinfocenter KF5::Completion KF5::ConfigWidgets KF5::CoreAddons KF5::Crash KF5::DBusAddons KF5::I18n KF5::IconThemes KF5::KCMUtils KF5::Service KF5::Solid KF5::WidgetsAddons KF5::WindowSystem KF5::XmlGui ) # add clang-format target for all our real source files file(GLOB_RECURSE ALL_CLANG_FORMAT_SOURCE_FILES *.cpp *.h) kde_clang_format(${ALL_CLANG_FORMAT_SOURCE_FILES}) ##install install( TARGETS kinfocenter ${INSTALL_TARGETS_DEFAULT_ARGS} ) install( FILES org.kde.kinfocenter.appdata.xml DESTINATION ${KDE_INSTALL_METAINFODIR}) install( PROGRAMS org.kde.kinfocenter.desktop DESTINATION ${XDG_APPS_INSTALL_DIR} ) install( FILES kinfocenterui.rc DESTINATION ${KXMLGUI_INSTALL_DIR}/kinfocenter ) feature_summary(WHAT ALL INCLUDE_QUIET_PACKAGES FATAL_ON_MISSING_REQUIRED_PACKAGES) diff --git a/Modules/about-distro/src/Module.cpp b/Modules/about-distro/src/Module.cpp index 89070c6..697689c 100644 --- a/Modules/about-distro/src/Module.cpp +++ b/Modules/about-distro/src/Module.cpp @@ -1,315 +1,315 @@ /* Copyright (C) 2012-2014 Harald Sitter 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) version 3 or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. 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, see . */ #include "Module.h" #include "ui_Module.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef Q_OS_LINUX #include #elif defined(Q_OS_FREEBSD) #include #include #endif #include #include "Version.h" static qlonglong calculateTotalRam() { qlonglong ret = -1; #ifdef Q_OS_LINUX struct sysinfo info; if (sysinfo(&info) == 0) // manpage "sizes are given as multiples of mem_unit bytes" ret = qlonglong(info.totalram) * info.mem_unit; #elif defined(Q_OS_FREEBSD) /* Stuff for sysctl */ size_t len; unsigned long memory; len = sizeof(memory); sysctlbyname("hw.physmem", &memory, &len, NULL, 0); ret = memory; #endif return ret; } Module::Module(QWidget *parent, const QVariantList &args) : KCModule(parent, args), ui(new Ui::Module) { KAboutData *aboutData = new KAboutData(QStringLiteral("kcm-about-distro"), i18nc("@title", "About Distribution"), QString::fromLatin1(global_s_versionStringFull), QString(), KAboutLicense::LicenseKey::GPL_V3, i18nc("@info:credit", "Copyright 2012-2014 Harald Sitter")); aboutData->addAuthor(i18nc("@info:credit", "Harald Sitter"), i18nc("@info:credit", "Author"), QStringLiteral("apachelogger@kubuntu.org")); setAboutData(aboutData); ui->setupUi(this); QFont font = ui->nameVersionLabel->font(); font.setPixelSize(24); font.setBold(true); ui->nameVersionLabel->setFont(font); QFont fontVariant = ui->variantLabel->font(); fontVariant.setPixelSize(18); fontVariant.setBold(true); ui->variantLabel->setFont(fontVariant); ui->urlLabel->setTextInteractionFlags(Qt::TextSelectableByMouse | Qt::LinksAccessibleByMouse); // We have no help so remove the button from the buttons. setButtons(buttons() ^ KCModule::Help ^ KCModule::Default ^ KCModule::Apply); // Setup Copy to Clipboard button connect(ui->pushButtonCopyInfo, &QPushButton::clicked, this, &Module::copyToClipboard); connect(ui->pushButtonCopyInfoInEnglish, &QPushButton::clicked, this, &Module::copyToClipboardInEnglish); - if (QLocale::system().language() == QLocale::English) { + if (QLocale::system().language() == QLocale::English || QLocale::system().language() == QLocale::C) { ui->pushButtonCopyInfoInEnglish->hide(); } ui->pushButtonCopyInfo->setShortcut(QKeySequence::Copy); // https://bugs.kde.org/show_bug.cgi?id=366158 // When a KCM loads fast enough do a blocking load via the constructor. // Otherwise there is a notciable rendering gap where dummy/no data is // shown. Makes it look bad. load(); } Module::~Module() { delete ui; } void Module::load() { labelsForClipboard.clear(); englishTextForClipboard = QStringLiteral(""); loadSoftware(); loadHardware(); } void Module::save() { } void Module::defaults() { } void Module::loadSoftware() { // NOTE: do not include globals, otherwise kdeglobals could provide values // even though we only explicitly want them from our own config. KSharedConfig::Ptr config = KSharedConfig::openConfig(QStringLiteral("kcm-about-distrorc"), KConfig::NoGlobals); KConfigGroup cg = KConfigGroup(config, "General"); KOSRelease os; QString logoPath = cg.readEntry("LogoPath", os.logo()); if (logoPath.isEmpty()) { logoPath = QStringLiteral("start-here-kde"); } const QPixmap logo = QIcon::fromTheme(logoPath).pixmap(128, 128); ui->logoLabel->setPixmap(logo); // We allow overriding of the OS name for branding purposes. // For example OS Ubuntu may be rebranded as Kubuntu. Also Kubuntu Active // as a product brand is different from Kubuntu. const QString distroName = cg.readEntry("Name", os.name()); const QString osrVersion = cg.readEntry("UseOSReleaseVersion", false) ? os.version() : os.versionId(); const QString versionId = cg.readEntry("Version", osrVersion); const QString distroNameVersion = QStringLiteral("%1 %2").arg(distroName, versionId); ui->nameVersionLabel->setText(distroNameVersion); const auto dummyDistroDescriptionLabel = new QLabel(i18nc("@title:row", "Operating System:"), this); dummyDistroDescriptionLabel->hide(); labelsForClipboard << qMakePair(dummyDistroDescriptionLabel, ui->nameVersionLabel); englishTextForClipboard += QStringLiteral("Operating System: %1\n").arg(distroNameVersion); const QString variant = cg.readEntry("Variant", os.variant()); if (variant.isEmpty()) { ui->variantLabel->hide(); } else { ui->variantLabel->setText(variant); } const QString url = cg.readEntry("Website", os.homeUrl()); if (url.isEmpty()) { ui->urlLabel->hide(); } else { ui->urlLabel->setText(QStringLiteral("%1").arg(url)); } // Since Plasma version detection isn't based on a library query it can fail // in weird cases; instead of admitting defeat we simply hide everything :P const QString plasma = plasmaVersion(); if (plasma.isEmpty()) { ui->plasma->hide(); ui->plasmaLabel->hide(); } else { ui->plasmaLabel->setText(plasma); labelsForClipboard << qMakePair(ui->plasma, ui->plasmaLabel); englishTextForClipboard += QStringLiteral("KDE Plasma Version: %1\n").arg(plasma); } const QString frameworksVersion = KCoreAddons::versionString(); ui->frameworksLabel->setText(frameworksVersion); labelsForClipboard << qMakePair(ui->frameworksLabelKey, ui->frameworksLabel); englishTextForClipboard += QStringLiteral("KDE Frameworks Version: %1\n").arg(frameworksVersion); const QString qversion = QString::fromLatin1(qVersion()); ui->qtLabel->setText(qversion); labelsForClipboard << qMakePair(ui->qt, ui->qtLabel); englishTextForClipboard += QStringLiteral("Qt Version: %1\n").arg(qversion); } void Module::loadHardware() { struct utsname utsName; if(uname(&utsName) != 0) { ui->kernel->hide(); ui->kernelLabel->hide(); } else { QString kernelVersion = QString::fromLatin1(utsName.release); ui->kernelLabel->setText(kernelVersion); labelsForClipboard << qMakePair(ui->kernel, ui->kernelLabel); englishTextForClipboard += QStringLiteral("Kernel Version: %1\n").arg(kernelVersion); } const int bits = QT_POINTER_SIZE == 8 ? 64 : 32; const QString bitsStr = QString::number(bits); ui->bitsLabel->setText(i18nc("@label %1 is the CPU bit width (e.g. 32 or 64)", "%1-bit", bitsStr)); labelsForClipboard << qMakePair(ui->bitsKey, ui->bitsLabel); englishTextForClipboard += QStringLiteral("OS Type: %1-bit\n").arg(bitsStr); const QList list = Solid::Device::listFromType(Solid::DeviceInterface::Processor); ui->processor->setText(i18np("Processor:", "Processors:", list.count())); // Format processor string // Group by processor name QMap processorMap; Q_FOREACH(const Solid::Device &device, list) { const QString name = device.product(); auto it = processorMap.find(name); if (it == processorMap.end()) { processorMap.insert(name, 1); } else { ++it.value(); } } // Create a formatted list of grouped processors QStringList names; names.reserve(processorMap.count()); for (auto it = processorMap.constBegin(); it != processorMap.constEnd(); ++it) { const int count = it.value(); QString name = it.key(); name.replace(QStringLiteral("(TM)"), QChar(8482)); name.replace(QStringLiteral("(R)"), QChar(174)); name = name.simplified(); names.append(QStringLiteral("%1 × %2").arg(count).arg(name)); } const QString processorLabel = names.join(QLatin1String(", ")); ui->processorLabel->setText(processorLabel); if (ui->processorLabel->text().isEmpty()) { ui->processor->setHidden(true); ui->processorLabel->setHidden(true); } else { labelsForClipboard << qMakePair(ui->processor, ui->processorLabel); englishTextForClipboard += QStringLiteral("Processors: %1\n").arg(processorLabel); } const qlonglong totalRam = calculateTotalRam(); const QString memoryLabel = totalRam > 0 ? i18nc("@label %1 is the formatted amount of system memory (e.g. 7,7 GiB)", "%1 of RAM", KFormat().formatByteSize(totalRam)) : i18nc("Unknown amount of RAM", "Unknown"); ui->memoryLabel->setText(memoryLabel); labelsForClipboard << qMakePair(ui->memory, ui->memoryLabel); englishTextForClipboard += QStringLiteral("Memory: %1\n").arg(KFormat().formatByteSize(totalRam)); } void Module::copyToClipboard() { QString text; // note that this loop does not necessarily represent the same order as in the GUI for (auto labelPair : qAsConst(labelsForClipboard)) { const auto valueLabel = labelPair.second; if (!valueLabel->isHidden()) { const auto descriptionLabelText = labelPair.first->text(); const auto valueLabelText = valueLabel->text(); text += i18nc("%1 is a label already including a colon, %2 is the corresponding value", "%1 %2", descriptionLabelText, valueLabelText) + QStringLiteral("\n"); } } QGuiApplication::clipboard()->setText(text); } void Module::copyToClipboardInEnglish() { QGuiApplication::clipboard()->setText(englishTextForClipboard); } QString Module::plasmaVersion() const { const QStringList &filePaths = QStandardPaths::locateAll(QStandardPaths::GenericDataLocation, QStringLiteral("xsessions/plasma.desktop")); if (filePaths.length() < 1) { return QString(); } // Despite the fact that there can be multiple desktop files we simply take // the first one as users usually don't have xsessions/ in their $HOME // data location, so the first match should (usually) be the only one and // reflect the plasma session run. KDesktopFile desktopFile(filePaths.first()); return desktopFile.desktopGroup().readEntry("X-KDE-PluginInfo-Version", QString()); } diff --git a/Modules/devinfo/devicelisting.cpp b/Modules/devinfo/devicelisting.cpp index 6ba597e..523e96e 100644 --- a/Modules/devinfo/devicelisting.cpp +++ b/Modules/devinfo/devicelisting.cpp @@ -1,224 +1,225 @@ /* * devicelisting.cpp * * Copyright (C) 2009 David Hubner * * 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. * */ #include "devicelisting.h" #include DeviceListing::DeviceListing(QWidget *parent, InfoPanel *info, DevInfoPlugin *stat) : QTreeWidget(parent) , iPanel(info) , status(stat) { // // Check nic changes // nicSig = new NicSignals(); // connect(nicSig,SIGNAL(nicActivatedOrDisconnected()),this,SLOT(networkingChangedSlot())); // // Check if clicked connect(this, &DeviceListing::itemActivated, this, &DeviceListing::itemActivatedSlot); // Check if item is added connect(Solid::DeviceNotifier::instance(), &Solid::DeviceNotifier::deviceAdded, this, &DeviceListing::deviceAddedSlot); // Check if item is removed connect(Solid::DeviceNotifier::instance(), &Solid::DeviceNotifier::deviceRemoved, this, &DeviceListing::deviceRemovedSlot); setWhatsThis(i18nc("Device Listing Whats This", "Shows all the devices that are currently listed.")); createMenuActions(); setHeaderLabels(QStringList(i18n("Devices"))); populateListing(); setSortingEnabled(true); } DeviceListing::~DeviceListing() { //delete nicSig; clear(); } void DeviceListing::createMenuActions() { colAct = new QAction(i18n("Collapse All"), this); connect(colAct, &QAction::triggered, this, &DeviceListing::collapseAllDevicesSlot); expAct = new QAction(i18n("Expand All"), this); connect(expAct, &QAction::triggered, this, &DeviceListing::expandAllDevicesSlot); allAct = new QAction(i18n("Show All Devices"), this); connect(allAct, &QAction::triggered, this, &DeviceListing::showAllDevicesSlot); relAct = new QAction(i18n("Show Relevant Devices"), this); connect(relAct, &QAction::triggered, this, &DeviceListing::showRelevantDevicesSlot); } void DeviceListing::contextMenuEvent(QContextMenuEvent *event) { QMenu menu(this); menu.addAction(colAct); menu.addAction(expAct); menu.addAction(allAct); menu.addAction(relAct); menu.exec(event->globalPos()); } QTreeWidgetItem *DeviceListing::createListItems(const Solid::DeviceInterface::Type &type) { switch (type) { case Solid::DeviceInterface::Processor: return new SolProcessorDevice(type); case Solid::DeviceInterface::StorageDrive: return new SolStorageDevice(type); case Solid::DeviceInterface::Camera: return new SolCameraDevice(type); case Solid::DeviceInterface::PortableMediaPlayer: return new SolMediaPlayerDevice(type); case Solid::DeviceInterface::Battery: return new SolBatteryDevice(type); default: return new SolDevice(type, i18nc("unknown device type", "Unknown")); } } void DeviceListing::populateListing(const show showStatus) { const Solid::DeviceInterface::Type needHardware[] = { Solid::DeviceInterface::Processor, Solid::DeviceInterface::StorageDrive, Solid::DeviceInterface::Battery, Solid::DeviceInterface::PortableMediaPlayer, Solid::DeviceInterface::Camera }; clear(); for (unsigned int i = 0; i < (sizeof(needHardware)/sizeof(Solid::DeviceInterface::Type)); i++) { QTreeWidgetItem *tmpDevice = createListItems(needHardware[i]); deviceMap[needHardware[i]] = static_cast(tmpDevice); if ((tmpDevice->childCount() > 0) || (showStatus == ALL)) { addTopLevelItem(tmpDevice); } } } void DeviceListing::itemActivatedSlot(QTreeWidgetItem *listItemIn, const int columnIn) { Q_UNUSED(columnIn); SolDevice *listItem = static_cast(listItemIn); if (listItem->isDeviceSet()) { iPanel->setTopInfo(listItem->deviceIcon(), listItem->device()); QVListLayout *bottomLay = listItem->infoPanelLayout(); if (!bottomLay) { return; } iPanel->setBottomInfo(bottomLay); } else { status->updateStatus(i18nc("no device UDI", "None")); } } void DeviceListing::deviceAddedSlot(const QString &udi) { SolidHelper *solhelp = new SolidHelper(); - const QList list = Solid::Device::allDevices(); - - foreach (const Solid::Device &dev, list) { - if (dev.udi() == udi) { - Solid::DeviceInterface::Type deviceType = solhelp->deviceType(&dev); - QTreeWidgetItem *parent = getTreeWidgetItemFromUdi(this, dev.parentUdi()); - - // Incase of bad index - if (deviceMap[deviceType] == nullptr) { - QTreeWidgetItem *topItem = topLevelItem(0); - if (!topItem) { - delete solhelp; - return; - } - deviceMap[deviceType] = static_cast(topItem); - } - - switch (deviceType) { - case Solid::DeviceInterface::Processor: - new SolProcessorDevice(deviceMap[deviceType], dev); - break; - case Solid::DeviceInterface::Camera: - new SolCameraDevice(deviceMap[deviceType], dev); - break; - case Solid::DeviceInterface::PortableMediaPlayer: - new SolMediaPlayerDevice(deviceMap[deviceType], dev); - break; - case Solid::DeviceInterface::Battery: - new SolBatteryDevice(deviceMap[deviceType], dev); - break; - case Solid::DeviceInterface::StorageDrive: - new SolStorageDevice(deviceMap[deviceType], dev, SolStorageDevice::NOCHILDREN); - break; - case Solid::DeviceInterface::StorageVolume: - if (parent == nullptr) { - break; - } - new SolVolumeDevice(parent, dev); - break; - default: - break; - } + + Solid::Device dev(udi); + if (!dev.isValid()) { + // Probably the device already disappeared again. + return; + } + + Solid::DeviceInterface::Type deviceType = solhelp->deviceType(&dev); + QTreeWidgetItem *parent = getTreeWidgetItemFromUdi(this, dev.parentUdi()); + + // Incase of bad index + if (deviceMap[deviceType] == nullptr) { + QTreeWidgetItem *topItem = topLevelItem(0); + if (!topItem) { + delete solhelp; + return; } + deviceMap[deviceType] = static_cast(topItem); + } + + switch (deviceType) { + case Solid::DeviceInterface::Processor: + new SolProcessorDevice(deviceMap[deviceType], dev); + break; + case Solid::DeviceInterface::Camera: + new SolCameraDevice(deviceMap[deviceType], dev); + break; + case Solid::DeviceInterface::PortableMediaPlayer: + new SolMediaPlayerDevice(deviceMap[deviceType], dev); + break; + case Solid::DeviceInterface::Battery: + new SolBatteryDevice(deviceMap[deviceType], dev); + break; + case Solid::DeviceInterface::StorageDrive: + new SolStorageDevice(deviceMap[deviceType], dev, SolStorageDevice::NOCHILDREN); + break; + case Solid::DeviceInterface::StorageVolume: + if (parent == nullptr) { + break; + } + new SolVolumeDevice(parent, dev); + break; + default: + break; } delete solhelp; } void DeviceListing::deviceRemovedSlot(const QString &udi) { const QTreeWidgetItem *item = getTreeWidgetItemFromUdi(this, udi); if (item == nullptr) { return; } delete item; } void DeviceListing::collapseAllDevicesSlot() { collapseAll(); } void DeviceListing::expandAllDevicesSlot() { expandAll(); } void DeviceListing::showAllDevicesSlot() { populateListing(ALL); } void DeviceListing::showRelevantDevicesSlot() { populateListing(RELEVANT); }