diff --git a/CMakeLists.txt b/CMakeLists.txt index 5442172f..97550063 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,6 +3,11 @@ project(KDEBASE_WORKSPACE) # TODO: Remove when kdelibs >= 4.10 will be required cmake_minimum_required(VERSION 2.8.6 FATAL_ERROR) +include(CTest) +include(CTestConfig.cmake) +include(CheckIncludeFiles) +include(CheckFunctionExists) + # Used e.g. in KDE4WorkspaceConfig.cmake, Alex set(KDE4WORKSPACE_VERSION_MAJOR 4) set(KDE4WORKSPACE_VERSION_MINOR 11) @@ -15,7 +20,7 @@ set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules ${CMAKE_MODULE_P #search packages used by KDE set(QT_MIN_VERSION "4.8.0") -find_package(KDE4 4.9.4 REQUIRED) +find_package(KDE4 4.9.95 REQUIRED) include(KDE4Defaults) option(WITH_XINERAMA "Xinerama support for multi-headed X displays" ON) @@ -55,7 +60,7 @@ find_package(KDeclarative QUIET CONFIG) set_package_properties(KDeclarative PROPERTIES DESCRIPTION "KDE Declarative (QML) support from kdelibs" URL "http://www.kde.org" TYPE REQUIRED - PURPOSE "Required for building ksmserver" + PURPOSE "Required for building ksmserver and corebindingsplugin (org.kde.plasma.core)" ) macro_optional_find_package(OpenGL) @@ -157,8 +162,38 @@ set_package_properties(QJSON PROPERTIES DESCRIPTION "Library to manage JSON obje PURPOSE "Required to build Chrome/Chromium support for Plasma Bookmarks Runners" ) +find_package(LibGcrypt 1.5.0 REQUIRED QUIET) +set_package_properties(LibGcrypt PROPERTIES DESCRIPTION "Libgcrypt is a general purpose cryptographic library based on the code from GnuPG." + URL "http://www.gnu.org/software/libgcrypt/" + TYPE REQUIRED + PURPOSE "kwalletd needs libgcrypt to perform PBKDF2-SHA512 hashing" + ) + +macro_optional_find_package(SLP) +set_package_properties(SLP PROPERTIES DESCRIPTION "SLP (Service Location Protocol) implementation" + URL "http://www.openslp.org/" + TYPE OPTIONAL + PURPOSE "Provides SLP support in the network:/ kioslave." + ) + +find_package(LibAttica 0.1.4) +set_package_properties(LibAttica PROPERTIES DESCRIPTION "A library to access Open Collaboration Service providers" + URL "https://projects.kde.org/attica" + TYPE REQUIRED + PURPOSE "Attica is needed for the Get Hot New Stuff support" + ) + +macro_optional_find_package(QCA2 2.0.0) +set_package_properties(QCA2 PROPERTIES DESCRIPTION "Support for remote plasma widgets" + URL "http://delta.affinix.com/qca" + TYPE OPTIONAL + ) + +check_include_files(sys/wait.h HAVE_SYS_WAIT_H) +check_include_files(sys/time.h HAVE_SYS_TIME_H) include(ConfigureChecks.cmake) +configure_file (config-runtime.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-runtime.h ) if(NOT WIN32) configure_file(config-unix.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-unix.h ) configure_file(config-X11.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-X11.h ) @@ -171,7 +206,7 @@ configure_file(config-workspace.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-works add_definitions(${QT_DEFINITIONS} ${KDE4_DEFINITIONS} -DHAVE_CONFIG_H=1) add_definitions(-DQT_USE_FAST_CONCATENATION -DQT_USE_FAST_OPERATOR_PLUS) -include_directories(${CMAKE_SOURCE_DIR} ${CMAKE_BINARY_DIR} ${KDE4_INCLUDES} ${KACTIVITIES_INCLUDE_DIRS} ${CMAKE_SOURCE_DIR}/libs) +include_directories(${CMAKE_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_BINARY_DIR} ${KDE4_INCLUDES} ${KACTIVITIES_INCLUDE_DIRS} ${CMAKE_SOURCE_DIR}/libs) # libs add_subdirectory(cmake) @@ -187,7 +222,6 @@ if(NOT WIN32) macro_optional_add_subdirectory( kcheckpass ) macro_optional_add_subdirectory( kwin ) macro_optional_add_subdirectory( ksmserver ) - macro_optional_add_subdirectory( kdesu ) find_package(JPEG REQUIRED) find_package(PNG REQUIRED) @@ -242,7 +276,61 @@ macro_optional_add_subdirectory(plasma) macro_optional_add_subdirectory(statusnotifierwatcher) macro_optional_add_subdirectory(kstyles) +# imported from kde-runtime +macro_optional_add_subdirectory(kdesu) +macro_optional_add_subdirectory(phonon) +macro_optional_add_subdirectory(menu) +macro_optional_add_subdirectory(khelpcenter) +macro_optional_add_subdirectory(kwalletd) +macro_optional_add_subdirectory(knotify) +macro_optional_add_subdirectory(kuiserver) +macro_optional_add_subdirectory(soliduiserver) +macro_optional_add_subdirectory(solidautoeject) +macro_optional_add_subdirectory(solid-device-automounter) +macro_optional_add_subdirectory(solid-networkstatus) +macro_optional_add_subdirectory(kdebugdialog) +macro_optional_add_subdirectory(kcmshell) +macro_optional_add_subdirectory(kioslave) +macro_optional_add_subdirectory(kurifilter-plugins) +macro_optional_add_subdirectory(kimgio) +macro_optional_add_subdirectory(renamedlgplugins) +if (Q_WS_X11) + macro_optional_add_subdirectory(kstart) +endif (Q_WS_X11) +macro_optional_add_subdirectory(kquitapp) +# Background processes +macro_optional_add_subdirectory(kpasswdserver) +macro_optional_add_subdirectory(kdontchangethehostname) +macro_optional_add_subdirectory(kglobalaccel) +macro_optional_add_subdirectory(ktimezoned) +# Command-line tools (e.g. for shell scripts) +if ( UNIX ) + macro_optional_add_subdirectory(kdeeject) +endif ( UNIX ) +macro_optional_add_subdirectory(kfile) +macro_optional_add_subdirectory(kiconfinder) +macro_optional_add_subdirectory(kioclient) +macro_optional_add_subdirectory(kioexec) +macro_optional_add_subdirectory(ktraderclient) +macro_optional_add_subdirectory(kreadconfig) +macro_optional_add_subdirectory(kmimetypefinder) +# UI Helper applications +macro_optional_add_subdirectory(drkonqi) +macro_optional_add_subdirectory(khelpcenter) +macro_optional_add_subdirectory(knetattach) +macro_optional_add_subdirectory(knewstuff) +macro_optional_add_subdirectory(keditfiletype) +# Default settings, content and config +macro_optional_add_subdirectory(l10n) +macro_optional_add_subdirectory(localization) +macro_optional_add_subdirectory(kde-menu) +# KDE integration for attica +if(LIBATTICA_FOUND) + macro_optional_add_subdirectory(attica) +endif(LIBATTICA_FOUND) + ########### install files ############### +install(PROGRAMS ${CMAKE_CURRENT_SOURCE_DIR}/kde4 DESTINATION ${BIN_INSTALL_DIR}) if(NOT WIN32) install(PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/startkde DESTINATION ${BIN_INSTALL_DIR}) endif(NOT WIN32) diff --git a/attica/CMakeLists.txt b/attica/CMakeLists.txt new file mode 100644 index 00000000..11d3e3b4 --- /dev/null +++ b/attica/CMakeLists.txt @@ -0,0 +1,5 @@ +include_directories(${LIBATTICA_INCLUDE_DIR}) + +add_subdirectory(kdeplugin) +add_subdirectory(kcm) + diff --git a/attica/kcm/CMakeLists.txt b/attica/kcm/CMakeLists.txt new file mode 100644 index 00000000..976dace4 --- /dev/null +++ b/attica/kcm/CMakeLists.txt @@ -0,0 +1,14 @@ +set(kcm_attica_PART_SRCS + providerconfigwidget.cpp + atticamodule.cpp +) + +kde4_add_ui_files(kcm_attica_PART_SRCS providermanagement.ui providerconfigwidget.ui) + +kde4_add_plugin(kcm_attica ${kcm_attica_PART_SRCS}) + +target_link_libraries(kcm_attica ${LIBATTICA_LIBRARIES} ${KDE4_KDEUI_LIBS} ${KDE4_KIO_LIBS}) + +install(TARGETS kcm_attica DESTINATION ${PLUGIN_INSTALL_DIR}) +install(FILES kcm_attica.desktop DESTINATION ${SERVICES_INSTALL_DIR}) + diff --git a/attica/kcm/Messages.sh b/attica/kcm/Messages.sh new file mode 100644 index 00000000..543c21ff --- /dev/null +++ b/attica/kcm/Messages.sh @@ -0,0 +1,3 @@ +#! /bin/sh +$EXTRACTRC `find . -name \*.rc -o -name \*.ui -o -name \*.kcfg` >> rc.cpp +$XGETTEXT *.cpp -o $podir/kcm_attica.pot diff --git a/attica/kcm/TODO b/attica/kcm/TODO new file mode 100644 index 00000000..9e6d8c96 --- /dev/null +++ b/attica/kcm/TODO @@ -0,0 +1,3 @@ +KDE4.5: +- Check that password is more than 8 chars in length (something server should do) +- Rename "Login" tab to "Login Settings" to not confuse user diff --git a/attica/kcm/atticamodule.cpp b/attica/kcm/atticamodule.cpp new file mode 100644 index 00000000..4e9205d2 --- /dev/null +++ b/attica/kcm/atticamodule.cpp @@ -0,0 +1,158 @@ +/* + This file is part of KDE. + + Copyright (c) 2009 Eckhart Wörner + Copyright (c) 2010 Frederik Gladhorn + + 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 "atticamodule.h" + + +#include +#include +#include +#include +#include + +#include + +#include "providerconfigwidget.h" + + +K_PLUGIN_FACTORY(AtticaModuleFactory, registerPlugin();) +K_EXPORT_PLUGIN(AtticaModuleFactory("kcm_attica")) + +AtticaModule::AtticaModule(QWidget* parent, const QVariantList&) + : KCModule(AtticaModuleFactory::componentData(), parent) +{ + KAboutData *about = new KAboutData( + "kcm_attica", 0, ki18n("Social Desktop"), + KDE_VERSION_STRING, KLocalizedString(), KAboutData::License_GPL, + ki18n("Copyright 2009 Eckhart Wörner")); + about->addAuthor(ki18n("Eckhart Wörner"), KLocalizedString(), "ewoerner@kde.org"); + about->addAuthor(ki18n("Dmitry Suzdalev"), KLocalizedString(), "dimsuz@gmail.com"); + about->addAuthor(ki18n("Frederik Gladhorn"), KLocalizedString(), "gladhorn@kde.org"); + setAboutData(about); + + m_ui.setupUi(this); + + m_ui.addProviderButton->setIcon(KIcon("list-add")); + m_ui.removeProviderButton->setIcon(KIcon("list-remove")); + + // FIXME + m_ui.removeProviderButton->setEnabled(false); + + connect(m_ui.addProviderButton, SIGNAL(clicked()), this, SLOT(addProvider())); + connect(m_ui.removeProviderButton, SIGNAL(clicked()), this, SLOT(removeProvider())); + + connect(m_ui.providerComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(providerSelected(int))); + + connect(m_ui.providerConfigWidget, SIGNAL(changed(bool)), + this, SIGNAL(changed(bool))); + + m_manager.setAuthenticationSuppressed(true); + + connect(&m_manager, SIGNAL(providerAdded(const Attica::Provider&)), SLOT(providerAdded(const Attica::Provider&))); + connect(&m_manager, SIGNAL(defaultProvidersLoaded()), SLOT(onDefaultProvidersLoaded())); + + startLoadingDefaultProviders(); +} + +AtticaModule::~AtticaModule() +{ +} + +void AtticaModule::defaults() +{ +} + +void AtticaModule::load() +{ + startLoadingDefaultProviders(); +} + + +void AtticaModule::save() +{ + m_ui.providerConfigWidget->saveData(); +} + +void AtticaModule::startLoadingDefaultProviders() +{ + emit changed(true); + m_manager.clear(); + m_manager.loadDefaultProviders(); + m_ui.lblProviderList->setText(i18n("Loading provider list...")); + m_ui.providerComboBox->hide(); + m_ui.providerConfigWidget->setEnabled(false); +} + +void AtticaModule::providerAdded(const Attica::Provider& provider) +{ + // Add new provider + QString baseUrl = provider.baseUrl().toString(); + int idx = m_ui.providerComboBox->findData(baseUrl); + + if ( idx == -1) + { + kDebug() << "Adding provider" << baseUrl; + QString name = provider.name(); + if (name.isEmpty()) + name = baseUrl; + m_ui.providerComboBox->addItem(KIcon("system-users"), name, provider.baseUrl()); + } + + // set only if this is a first provider, otherwise it will be + // set on explicit selection + if (m_ui.providerComboBox->count() == 1) { + m_ui.providerConfigWidget->setProvider(provider); + } +} + +void AtticaModule::providerSelected(int providerNumber) +{ + QUrl providerUrl = m_ui.providerComboBox->itemData(providerNumber).toUrl(); + m_ui.providerConfigWidget->setProvider(m_manager.providerByUrl(providerUrl)); +} + +void AtticaModule::onDefaultProvidersLoaded() +{ + m_ui.lblProviderList->setText(i18n("Choose a provider to manage:")); + m_ui.providerComboBox->show(); + m_ui.providerConfigWidget->setEnabled(true); + + // at least now set it to not changed + emit changed(false); +} + +void AtticaModule::addProvider() +{ + KUrlRequesterDialog dialog("http://", i18nc("addition of an attica/knewstuff provider by entering its url", "URL of the provider file (provider.xml)"), this); + if (dialog.exec() == KDialog::Accepted) { + kDebug() << "Add provider: " << dialog.selectedUrl(); + m_manager.addProviderFileToDefaultProviders(dialog.selectedUrl()); + } +} + +void AtticaModule::removeProvider() +{ + //m_manager.removeProviderFileToDefaultProviders(url); +} + + +#include "atticamodule.moc" diff --git a/attica/kcm/atticamodule.h b/attica/kcm/atticamodule.h new file mode 100644 index 00000000..6c18bfb3 --- /dev/null +++ b/attica/kcm/atticamodule.h @@ -0,0 +1,64 @@ +/* + This file is part of KDE. + + Copyright (c) 2009 Eckhart Wörner + Copyright (c) 2010 Frederik Gladhorn + + 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. +*/ + +#ifndef ATTICAMODULE_H +#define ATTICAMODULE_H + +#include + +#include + +#include "ui_providermanagement.h" + + +namespace KWallet { + class Wallet; +} + +class AtticaModule : public KCModule +{ + Q_OBJECT + +public: + AtticaModule(QWidget* parent, const QVariantList&); + ~AtticaModule(); + void save(); + void load(); + void defaults(); + +private Q_SLOTS: + void providerAdded(const Attica::Provider&); + void onDefaultProvidersLoaded(); + void addProvider(); + void removeProvider(); + void providerSelected(int); + +private: + void startLoadingDefaultProviders(); + +private: + Ui::ProviderManagement m_ui; + Attica::ProviderManager m_manager; +}; + + +#endif diff --git a/attica/kcm/kcm_attica.desktop b/attica/kcm/kcm_attica.desktop new file mode 100644 index 00000000..ae8f5f60 --- /dev/null +++ b/attica/kcm/kcm_attica.desktop @@ -0,0 +1,148 @@ +[Desktop Entry] +Exec=kcmshell4 kcm_attica +Type=Service +Icon=get-hot-new-stuff + +X-KDE-ServiceTypes=KCModule +X-KDE-Library=kcm_attica +X-KDE-ParentApp=kcontrol +X-KDE-System-Settings-Parent-Category=account-details +X-DocPath=kcontrol/attica/index.html + +Name=Social Desktop +Name[ar]=سطح المكتب اجتماعي +Name[ast]=Escritoriu social +Name[bg]=Социален работен плот +Name[bn]=সামাজিক ডেস্কটপ +Name[bs]=Društvena površ +Name[ca]=Escriptori social +Name[ca@valencia]=Escriptori social +Name[cs]=Sociální pracovní prostředí +Name[da]=Social desktop +Name[de]=Social-Desktop +Name[el]=Κοινωνική επιφάνεια εργασίας +Name[en_GB]=Social Desktop +Name[eo]=Socia labortablo +Name[es]=Escritorio social +Name[et]=Sotsiaalne töölaud +Name[eu]=Mahaigain soziala +Name[fa]=رومیزی اجتماعی +Name[fi]=Sosiaalinen työpöytä +Name[fr]=Bureau social +Name[ga]=Deasc Shóisialta +Name[gl]=Escritorio social +Name[gu]=સોશિયલ ડેસ્કટોપ +Name[he]=שולחן עבודה חברתי +Name[hi]=सामुहिक डेस्कटॉप +Name[hr]=Društvena radna površina +Name[hu]=Közösségi asztal +Name[ia]=Scriptorio social +Name[id]=Desktop Sosial +Name[is]=Samskiptaskjáborð +Name[it]=Desktop sociale +Name[ja]=ソーシャルデスクトップ +Name[kk]=Қоғамдық үстел +Name[km]=ផ្ទៃតុ​សង្គម +Name[kn]=ಸಾಮಾಜಿಕ ಗಣಕತೆರೆ +Name[ko]=사회적 데스크톱 +Name[lt]=Socialinis darbastalis +Name[lv]=Sociālā darbvirsma +Name[mai]=समाज डेस्कटाप +Name[ml]=സാമൂഹിക പണിയിടം +Name[mr]=सामाजिक डेस्कटॉप +Name[nb]=Sosialt skrivebord +Name[nds]=Meenschap-Schriefdisch +Name[nl]=Sociale bureaublad +Name[nn]=Sosialt skrivebord +Name[pa]=ਸਮਾਜਕ ਡੈਸਕਟਾਪ +Name[pl]=Pulpit społecznościowy +Name[pt]=Ambiente de Trabalho Social +Name[pt_BR]=Área de Trabalho Social +Name[ro]=Birou social +Name[ru]=Social Desktop +Name[si]=සමාජීය වැඩතලය +Name[sk]=Sociálne pracovné prostredie +Name[sl]=Družabno namizje +Name[sr]=Друштвена површ +Name[sr@ijekavian]=Друштвена површ +Name[sr@ijekavianlatin]=Društvena površ +Name[sr@latin]=Društvena površ +Name[sv]=Socialt skrivbord +Name[tg]=Мизи кории ҷамъиятӣ +Name[th]=แวดวงสังคมออนไลน์ +Name[tr]=Sosyal Masaüstü +Name[ug]=ئىجتىمائىي ئۈستەلئۈستى +Name[uk]=Соціальна стільниця +Name[vi]=Máy làm việc xã hội +Name[wa]=Sicribanne sociå +Name[x-test]=xxSocial Desktopxx +Name[zh_CN]=社会化桌面 +Name[zh_TW]=Social 桌面 +Comment=Manage Social Desktop Providers +Comment[ar]=أدر مزودي سطح المكتب الاجتماعي +Comment[ast]=Xestionar fornidores del escritoriu social +Comment[bg]=Управление на доставчици на социален работен плот +Comment[bn]=সামাজিক ডেস্কটপ সরবরাহকারী ব্যবস্থাপনা +Comment[bs]=Upravljanje dobavljačima društvene površi +Comment[ca]=Gestiona els proveïdors de l'escriptori social +Comment[ca@valencia]=Gestiona els proveïdors de l'escriptori social +Comment[cs]=Spravovat poskytovatele sociálního pracovního prostředí +Comment[da]=Håndtér udbydere af social desktop +Comment[de]=Social-Desktop-Anbieter verwalten +Comment[el]=Διαχείριση παρόχων κοινωνικής επιφάνειας εργασίας +Comment[en_GB]=Manage Social Desktop Providers +Comment[eo]=Mastrumi provizantojn de socia labortablo +Comment[es]=Gestionar proveedores del escritorio social +Comment[et]=Sotsiaalse töölaua pakkujate haldamine +Comment[eu]=Mahaigain sozialen hornitzaileak kudeatzea +Comment[fa]=مدیریت ارائه دهندگان میزکارهای اجتماعی +Comment[fi]=Sosiaalisen työpöydän tarjoajien asetukset +Comment[fr]=Gérer les fournisseurs de bureaux sociaux +Comment[ga]=Bainistigh Soláthraithe na Deisce Shóisialta +Comment[gl]=Xestión dos provedores de escritorio social +Comment[gu]=સોશિઅલ ડેસ્કટોપ પૂરા પાડનારાઓનું સંચાલન કરો +Comment[he]=משמש לניהול ספקי שולחן עבודה חברתי +Comment[hi]=सामाजिक डेस्कटॉप प्रदाता को प्रबंधित करें +Comment[hr]=Upravljanje pružateljima društvene radne površine +Comment[hu]=Közösségiasztal-szolgáltatók kezelése +Comment[ia]=Gere fornitores de Scriptorio Social +Comment[id]=Atur Penyedia Desktop Sosial +Comment[is]=Sýsla með efnisveitur fyrir samskiptaveftengt efni fyrir skjáborð +Comment[it]=Gestisci i fornitori del desktop sociale +Comment[ja]=ソーシャルデスクトッププロバイダを管理 +Comment[kk]=Әлеуметтік үстел провайдерлерін басқару +Comment[km]=គ្រប់គ្រង​ក្រុមហ៊ុន​ផ្ដល់​ផ្ទៃតុ​សង្គម +Comment[kn]=ಸಾಮಾಜಿಕ ಗಣಕತೆರೆ ಪೂರೈಕೆದಾರರನ್ನು ನಿರ್ವಹಿಸು +Comment[ko]=사회적 데스크톱 프로바이더 관리 +Comment[lt]=Tvarkyti socialinio darbastalio tiekėjus +Comment[lv]=Pārvaldīt sociālās darbvirsmas sniedzējus +Comment[ml]=സാമൂഹിക പണിയിട ദാതാക്കളെ കൈകാര്യം ചെയ്യുക +Comment[mr]=सामाजिक डेस्कटॉप पुरवठाकर्ते नियंत्रीत करा +Comment[nb]=Håndter sosialt skrivebord-leverandører +Comment[nds]=Anbeders vun Meenschap-Schriefdischen plegen +Comment[nl]=Leveranciers van sociale bureaubladen beheren +Comment[nn]=Handsam sosialt skrivebord-leverandørar +Comment[pa]=ਸਮਾਜਿਕ ਡੈਸਕਟਾਪ ਪਰੋਵਾਇਡਰ ਪਰਬੰਧ +Comment[pl]=Zarządzanie dostawcami dla pulpitu społecznościowego +Comment[pt]=Gerir os Fornecedores do Ambiente de Trabalho Social +Comment[pt_BR]=Gerencia os fornecedores da Área de Trabalho Social +Comment[ro]=Gestionează furnizorii de birou social +Comment[ru]=Настройка Social Desktop +Comment[si]=සමාජීය වැඩපත් සපයන්නන් කළමනාකරනය කරන් +Comment[sk]=Správa poskytovateľov sociálneho pracovného prostredia +Comment[sl]=Upravljanje s ponudniki družabnega namizja +Comment[sr]=Управљање добављачима друштвене површи +Comment[sr@ijekavian]=Управљање добављачима друштвене површи +Comment[sr@ijekavianlatin]=Upravljanje dobavljačima društvene površi +Comment[sr@latin]=Upravljanje dobavljačima društvene površi +Comment[sv]=Hantera leverantörer av socialt skrivbord +Comment[tg]=Идоракунии провайдерҳои мизи кории ҷамъиятӣ +Comment[th]=จัดการผู้ให้บริการแวดวงสังคมออนไลน์ +Comment[tr]=Sosyal Masaüstü Hizmetlerini Yönet +Comment[ug]=ئىجتىمائىي ئۈستەلئۈستى تەمىنلىگۈچىنى باشقۇرىدۇ +Comment[uk]=Керування постачальниками даних соціальної стільниці +Comment[vi]=Quản lý các nhà cung cấp máy làm việc xã hội +Comment[wa]=Manaedjî des ahesseus d' sicribanne sociå +Comment[x-test]=xxManage Social Desktop Providersxx +Comment[zh_CN]=管理社会化桌面信息提供方 +Comment[zh_TW]=管理 Social 桌面提供者 diff --git a/attica/kcm/providerconfigwidget.cpp b/attica/kcm/providerconfigwidget.cpp new file mode 100644 index 00000000..af1d4114 --- /dev/null +++ b/attica/kcm/providerconfigwidget.cpp @@ -0,0 +1,320 @@ +/* + This file is part of KDE. + + Copyright (c) 2009 Eckhart Wörner + Copyright (c) 2009 Dmitry Suzdalev + Copyright (c) 2010 Frederik Gladhorn + + 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 "providerconfigwidget.h" + +#include +#include +#include +#include + +#include + +static const int loginTabIdx = 0; +static const int registerTabIdx = 1; + +ProviderConfigWidget::ProviderConfigWidget(QWidget* parent) + : QWidget(parent) +{ + m_ui.setupUi(this); +} + +void ProviderConfigWidget::setProvider(const Attica::Provider& provider) +{ + m_provider = provider; + + // TODO ensure that it reinits all fields nicely for new provider! + initLoginPage(); + initRegisterPage(); + + m_ui.userEditLP->setFocus(); +} + +void ProviderConfigWidget::initLoginPage() +{ + QString header; + if (m_provider.name().isEmpty()) { + header = i18n("Account details"); + } else { + header = i18n("Account details for %1", m_provider.name()); + } + m_ui.titleWidgetLogin->setText(header); + m_ui.tabWidget->setTabIcon(loginTabIdx, KIcon("applications-internet")); + + if (m_provider.hasCredentials()) { + QString user; + QString password; + m_provider.loadCredentials(user, password); + kDebug() << "cred for: " << user; + m_ui.userEditLP->setText(user); + m_ui.passwordEditLP->setText(password); + } else { + m_ui.userEditLP->clear(); + m_ui.passwordEditLP->clear(); + } + m_ui.enableProviderCheckBox->setChecked(m_provider.isEnabled()); + m_ui.testLoginButton->setIcon(KIcon("network-connect")); + m_ui.iconLabelLP->setPixmap(KIcon("help-about").pixmap(24,24)); + + connect(m_ui.userEditLP, SIGNAL(textChanged(const QString&)), this, SLOT(onLoginChanged())); + connect(m_ui.passwordEditLP, SIGNAL(textChanged(const QString&)), this, SLOT(onLoginChanged())); + connect(m_ui.testLoginButton, SIGNAL(clicked()), this, SLOT(onTestLogin())); + connect(m_ui.infoLabelLP, SIGNAL(linkActivated(const QString&)), this, SLOT(onInfoLinkActivated())); + connect(m_ui.enableProviderCheckBox, SIGNAL(clicked(bool)), this, SLOT(enableToggled(bool))); +} + +void ProviderConfigWidget::initRegisterPage() +{ + QString header; + if (m_provider.name().isEmpty()) { + header = i18n("Register new account"); + } else { + header = i18n("Register new account at %1", m_provider.name()); + } + m_ui.titleWidgetRegister->setText(header); + m_ui.tabWidget->setTabIcon(registerTabIdx, KIcon("list-add-user")); + + m_ui.infoLabelRP->setFont(KGlobalSettings::smallestReadableFont()); + + connect(m_ui.userEditRP, SIGNAL(textChanged(QString)), SLOT(onRegisterDataChanged())); + connect(m_ui.mailEdit, SIGNAL(textChanged(QString)), SLOT(onRegisterDataChanged())); + connect(m_ui.firstNameEdit, SIGNAL(textChanged(QString)), SLOT(onRegisterDataChanged())); + connect(m_ui.lastNameEdit, SIGNAL(textChanged(QString)), SLOT(onRegisterDataChanged())); + connect(m_ui.passwordEditRP, SIGNAL(textChanged(QString)), SLOT(onRegisterDataChanged())); + connect(m_ui.passwordRepeatEdit, SIGNAL(textChanged(QString)), SLOT(onRegisterDataChanged())); + + connect(m_ui.registerButton, SIGNAL(clicked()), SLOT(onRegisterClicked())); + + onRegisterDataChanged(); +} + +void ProviderConfigWidget::onLoginChanged() +{ + m_ui.testLoginButton->setText(i18n("Test login")); + m_ui.testLoginButton->setEnabled(true); + emit changed(true); +} + +void ProviderConfigWidget::onTestLogin() +{ + m_ui.testLoginButton->setEnabled(false); + m_ui.testLoginButton->setText(i18n("Testing login...")); + + Attica::PostJob* postJob = m_provider.checkLogin(m_ui.userEditLP->text(), m_ui.passwordEditLP->text()); + connect(postJob, SIGNAL(finished(Attica::BaseJob*)), SLOT(onTestLoginFinished(Attica::BaseJob*))); + postJob->start(); +} + +void ProviderConfigWidget::onTestLoginFinished(Attica::BaseJob* job) +{ + Attica::PostJob* postJob = static_cast(job); + + if (postJob->metadata().error() == Attica::Metadata::NoError) { + m_ui.testLoginButton->setText(i18n("Success")); + } + + if (postJob->metadata().error() == Attica::Metadata::OcsError) { + m_ui.testLoginButton->setText(i18n("Login failed")); + } +} + +void ProviderConfigWidget::enableToggled(bool enabled) +{ + m_provider.setEnabled(enabled); +} + +void ProviderConfigWidget::onInfoLinkActivated() +{ + m_ui.tabWidget->setCurrentIndex(registerTabIdx); + m_ui.userEditRP->setFocus(); +} + +void ProviderConfigWidget::onRegisterDataChanged() +{ + QString login = m_ui.userEditRP->text(); + QString mail = m_ui.mailEdit->text(); + QString firstName = m_ui.firstNameEdit->text(); + QString lastName = m_ui.lastNameEdit->text(); + QString password = m_ui.passwordEditRP->text(); + QString passwordRepeat = m_ui.passwordRepeatEdit->text(); + + bool isDataValid = (!login.isEmpty() && !mail.isEmpty() && !firstName.isEmpty() && + !lastName.isEmpty() && !password.isEmpty()); + bool isPasswordLengthValid = password.size() > 7; + bool isPasswordEqual = password == passwordRepeat; + + if (!isDataValid) { + showRegisterHint("dialog-cancel", i18n("Not all required fields are filled")); + } else if (!isPasswordLengthValid) { + showRegisterHint("dialog-cancel", i18n("Password is too short")); + } else if (!isPasswordEqual) { + showRegisterHint("dialog-cancel", i18n("Passwords do not match")); + } else { + showRegisterHint("dialog-ok-apply", i18n("All required information is provided")); + } + + m_ui.registerButton->setEnabled(isDataValid && isPasswordLengthValid && isPasswordEqual); + + emit changed(true); +} + +void ProviderConfigWidget::showRegisterHint(const QString& iconName, const QString& hint) +{ + m_ui.iconLabelRP->setPixmap(KIcon(iconName).pixmap(16,16)); + m_ui.infoLabelRP->setText(hint); +} + +void ProviderConfigWidget::showRegisterError(const Attica::Metadata& metadata) +{ + if (metadata.error() == Attica::Metadata::NetworkError) { + showRegisterHint("dialog-close", i18n("Failed to register new account.")); + } else { + /* +# 100 - successful / valid account +# 101 - please specify all mandatory fields +# 102 - please specify a valid password +# 103 - please specify a valid login +# 104 - login already exists +# 105 - email already taken +*/ + // TODO: Looks like more correct place for this stuff is in libattica, + // for example metadata().statusString() or smth like that. + // So here will be only showRegisterHint("dialog-close", statusString); + // no switch. + QWidget* widgetToHighlight = 0; + QString hint; + switch (metadata.statusCode()) { + case 102: + hint = i18n("Failed to register new account: invalid password."); + widgetToHighlight = m_ui.passwordEditRP; + break; + case 103: + hint = i18n("Failed to register new account: invalid username."); + widgetToHighlight = m_ui.userEditRP; + break; + case 104: + hint = i18n("Failed to register new account: the requested username is already taken."); + widgetToHighlight = m_ui.userEditRP; + break; + case 105: + hint = i18n("Failed to register new account: the specified email address is already taken."); + widgetToHighlight = m_ui.mailEdit; + break; + case 106: + hint = i18n("Failed to register new account: the specified email address is invalid."); + widgetToHighlight = m_ui.mailEdit; + default: + hint = i18n("Failed to register new account."); + break; + } + + if (!hint.isEmpty()) + showRegisterHint("dialog-close", hint); + + if (widgetToHighlight) { + QPalette pal = widgetToHighlight->palette(); + KColorScheme::adjustBackground(pal, KColorScheme::NegativeBackground, QPalette::Base); + widgetToHighlight->setPalette(pal); + widgetToHighlight->setFocus(); + } + } +} + +void ProviderConfigWidget::clearHighlightedErrors() +{ + QList widList = allRegisterWidgets(); + foreach (QWidget* wid, widList) { + QPalette pal = wid->palette(); + KColorScheme::adjustBackground(pal, KColorScheme::NormalBackground, QPalette::Base); + wid->setPalette(pal); + } +} + +void ProviderConfigWidget::onRegisterClicked() +{ + // here we assume that all data has been checked in onRegisterDataChanged() + + clearHighlightedErrors(); + + QString login = m_ui.userEditRP->text(); + QString mail = m_ui.mailEdit->text(); + QString firstName = m_ui.firstNameEdit->text(); + QString lastName = m_ui.lastNameEdit->text(); + QString password = m_ui.passwordEditRP->text(); + //QString passwordRepeat = m_ui.passwordRepeatEdit->text(); + + Attica::PostJob* postJob = m_provider.registerAccount(login, password, mail, firstName, lastName); + connect(postJob, SIGNAL(finished(Attica::BaseJob*)), SLOT(onRegisterAccountFinished(Attica::BaseJob*))); + postJob->start(); + showRegisterHint("help-about", i18n("Registration is in progress...")); + m_ui.registerButton->setEnabled(false); // should be disabled while registering +} + +void ProviderConfigWidget::onRegisterAccountFinished(Attica::BaseJob* job) +{ + Attica::PostJob* postJob = static_cast(job); + + // this will enable "register" button if possible + onRegisterDataChanged(); + + if (postJob->metadata().error() == Attica::Metadata::NoError) + { + KMessageBox::information(this, i18n("Registration complete. New account was successfully registered. Please check your Email to activate the account.")); + + QString user = m_ui.userEditRP->text(); + QString password = m_ui.passwordEditRP->text(); + m_ui.userEditLP->setText(user); + m_ui.passwordEditLP->setText(password); + + // clear register fields and switch to login page + foreach (QWidget* wid, allRegisterWidgets()) + { + QLineEdit* le = qobject_cast(wid); + if (le) + le->clear(); + } + m_ui.tabWidget->setCurrentIndex(loginTabIdx); + m_ui.userEditLP->setFocus(); + } + else + { + kDebug() << "register error:" << postJob->metadata().error() << "statusCode:" << postJob->metadata().statusCode(); + showRegisterError( postJob->metadata() ); + } +} + +void ProviderConfigWidget::saveData() +{ + m_provider.saveCredentials(m_ui.userEditLP->text(), m_ui.passwordEditLP->text()); +} + +QList ProviderConfigWidget::allRegisterWidgets() const +{ + QList widList; + widList << m_ui.userEditRP << m_ui.mailEdit << m_ui.firstNameEdit + << m_ui.lastNameEdit << m_ui.passwordEditRP << m_ui.passwordRepeatEdit; + + return widList; +} + +#include "providerconfigwidget.moc" diff --git a/attica/kcm/providerconfigwidget.h b/attica/kcm/providerconfigwidget.h new file mode 100644 index 00000000..2524e3c1 --- /dev/null +++ b/attica/kcm/providerconfigwidget.h @@ -0,0 +1,78 @@ +/* + This file is part of KDE. + + Copyright (c) 2009 Eckhart Wörner + Copyright (c) 2009 Dmitry Suzdalev + Copyright (c) 2010 Frederik Gladhorn + + 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. +*/ + +#ifndef PROVIDERCONFIGWIDGET_H +#define PROVIDERCONFIGWIDGET_H + +#include + +#include + +#include "ui_providerconfigwidget.h" + +namespace Attica +{ + class Metadata; +} + +class ProviderConfigWidget : public QWidget +{ + Q_OBJECT + +public: + explicit ProviderConfigWidget(QWidget* parent = 0); + void setProvider(const Attica::Provider& provider); + void saveData(); + +Q_SIGNALS: + void changed(bool hasChanged); + +private Q_SLOTS: + // login page + void onLoginChanged(); + void onTestLogin(); + void onTestLoginFinished(Attica::BaseJob* job); + void enableToggled(bool enabled); + + // register page + void onInfoLinkActivated(); + void onRegisterDataChanged(); + void onRegisterClicked(); + void onRegisterAccountFinished(Attica::BaseJob* job); + + +private: + void initLoginPage(); + void initRegisterPage(); + void showRegisterHint(const QString&, const QString&); + void showRegisterError(const Attica::Metadata&); + void clearHighlightedErrors(); + + QList allRegisterWidgets() const; + +private: + Attica::Provider m_provider; + Ui::ProviderConfigWidget m_ui; +}; + +#endif diff --git a/attica/kcm/providerconfigwidget.ui b/attica/kcm/providerconfigwidget.ui new file mode 100644 index 00000000..902c5b7a --- /dev/null +++ b/attica/kcm/providerconfigwidget.ui @@ -0,0 +1,572 @@ + + + ProviderConfigWidget + + + + 0 + 0 + 467 + 453 + + + + + + + 0 + + + + Login + + + + + + 10 + + + + + &Username: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + userEditLP + + + + + + + + + + &Password: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + passwordEditLP + + + + + + + QLineEdit::Password + + + + + + + &Test Login + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 20 + 20 + + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 10 + 10 + + + + + + + + + 75 + true + + + + + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 10 + + + + + + + + If a provider is not enabled, it will be ignored by the applications using the social desktop + + + Enabled + + + true + + + + + + + + + Qt::Vertical + + + + 443 + 174 + + + + + + + + + + + 0 + 0 + + + + + 16 + 16 + + + + Qt::AlignHCenter|Qt::AlignTop + + + + + + + Do not have an account? Create one on the <a href="register">Register tab</a> + + + true + + + + + + + + + The Social Desktop Providers are used for "Get Hot New Stuff" and the "Community" and "Social News" Plasma applets. + + + true + + + + + + + + Register + + + + + + 10 + + + + + Fill in the details below and click <b>Register...</b> button + + + true + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 20 + + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 20 + + + + + + + + Qt::Vertical + + + + 20 + 29 + + + + + + + + + + &User name: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + userEditRP + + + + + + + + + + &Email: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + mailEdit + + + + + + + + + + &Password: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + passwordEditRP + + + + + + + true + + + + + + + Repeat password: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + passwordRepeatEdit + + + + + + + true + + + + + + + &First name: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + firstNameEdit + + + + + + + + + + &Last name: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + lastNameEdit + + + + + + + + + + + + + 0 + 0 + + + + + 16 + 16 + + + + Qt::AlignHCenter|Qt::AlignTop + + + + + + + + + + Qt::RichText + + + true + + + + + + + + + + + &Register... + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 15 + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + 75 + true + + + + + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 10 + + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 10 + + + + + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 20 + 20 + + + + + + + + + + + + + + + KLineEdit + QLineEdit +
klineedit.h
+
+
+ + tabWidget + userEditLP + passwordEditLP + testLoginButton + userEditRP + mailEdit + firstNameEdit + lastNameEdit + passwordEditRP + passwordRepeatEdit + registerButton + + + +
diff --git a/attica/kcm/providermanagement.ui b/attica/kcm/providermanagement.ui new file mode 100644 index 00000000..cf169219 --- /dev/null +++ b/attica/kcm/providermanagement.ui @@ -0,0 +1,119 @@ + + + ProviderManagement + + + + 0 + 0 + 585 + 492 + + + + + + + + + Choose a provider to manage: + + + + + + + + 0 + 0 + + + + QComboBox::AdjustToContents + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Add Provider + + + + + + + Remove Provider + + + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 15 + + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 15 + + + + + + + + + 0 + 1 + + + + + + + + + ProviderConfigWidget + QWidget +
providerconfigwidget.h
+ 1 +
+
+ + +
diff --git a/attica/kdeplugin/CMakeLists.txt b/attica/kdeplugin/CMakeLists.txt new file mode 100644 index 00000000..3d27f688 --- /dev/null +++ b/attica/kdeplugin/CMakeLists.txt @@ -0,0 +1,10 @@ +################# KDE PLUGIN for LibAttica ################# + +set(attica_kde_SRCS + kdeplatformdependent.cpp +) + +kde4_add_plugin(attica_kde ${attica_kde_SRCS}) +target_link_libraries(attica_kde ${KDE4_KIO_LIBS} ${QT_QTMAIN_LIBRARY} ${QT_QTCORE_LIBRARY} ${KDE4_KCMUTILS_LIBS} ) +install(TARGETS attica_kde EXPORT kdelibsLibraryTargets ${INSTALL_TARGETS_DEFAULT_ARGS}) + diff --git a/attica/kdeplugin/Messages.sh b/attica/kdeplugin/Messages.sh new file mode 100644 index 00000000..7721b2b3 --- /dev/null +++ b/attica/kdeplugin/Messages.sh @@ -0,0 +1,2 @@ +#! /bin/sh +$XGETTEXT *.cpp -o $podir/attica_kde.pot diff --git a/attica/kdeplugin/kdeplatformdependent.cpp b/attica/kdeplugin/kdeplatformdependent.cpp new file mode 100644 index 00000000..d0041b8a --- /dev/null +++ b/attica/kdeplugin/kdeplatformdependent.cpp @@ -0,0 +1,279 @@ +/* + This file is part of KDE. + + Copyright (c) 2009 Eckhart Wörner + Copyright (c) 2010 Frederik Gladhorn + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 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 6 of version 3 of the license. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library. If not, see . + +*/ + +#include "kdeplatformdependent.h" + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace Attica; + +KdePlatformDependent::KdePlatformDependent() + : m_config(KSharedConfig::openConfig("atticarc")), m_accessManager(0), m_wallet(0) +{ + // when a plain Qt application loads this plugin, it needs a valid KGlobal object + if (!KGlobal::hasMainComponent()) { + KComponentData componentData("attica_kde"); + } + + KLocale* locale = KGlobal::locale(); + if (locale) { + locale->insertCatalog("attica_kde"); + } + + m_accessManager = new KIO::Integration::AccessManager(this); +} + +KdePlatformDependent::~KdePlatformDependent() +{ + delete m_wallet; +} + +bool KdePlatformDependent::openWallet(bool force) +{ + if (m_wallet) { + return true; + } + + QString networkWallet = KWallet::Wallet::NetworkWallet(); + // if not forced, or the folder doesn't exist, don't try to open the wallet + if (force || (!KWallet::Wallet::folderDoesNotExist(networkWallet, "Attica"))) { + m_wallet = KWallet::Wallet::openWallet(networkWallet, 0); + } + + if (m_wallet) { + m_wallet->createFolder("Attica"); + m_wallet->setFolder("Attica"); + return true; + } + return false; +} + +QNetworkReply* KdePlatformDependent::post(const QNetworkRequest& request, const QByteArray& data) +{ + return m_accessManager->post(removeAuthFromRequest(request), data); +} + +QNetworkReply* KdePlatformDependent::post(const QNetworkRequest& request, QIODevice* data) +{ + return m_accessManager->post(removeAuthFromRequest(request), data); +} + +QNetworkReply* KdePlatformDependent::get(const QNetworkRequest& request) +{ + return m_accessManager->get(removeAuthFromRequest(request)); +} + +QNetworkRequest KdePlatformDependent::removeAuthFromRequest(const QNetworkRequest& request) +{ + QStringList noauth; + noauth << "no-auth-prompt" << "true"; + QNetworkRequest notConstReq = const_cast(request); + notConstReq.setAttribute(QNetworkRequest::User, noauth); + return notConstReq; +} + +bool KdePlatformDependent::saveCredentials(const QUrl& baseUrl, const QString& user, const QString& password) +{ + m_passwords[baseUrl.toString()] = QPair (user, password); + + if (!m_wallet && !openWallet(true)) { + + if (KMessageBox::warningContinueCancel(0, i18n("Should the password be stored in the configuration file? This is unsafe.") + , i18n("Social Desktop Configuration")) + == KMessageBox::Cancel) { + return false; + } + + // use kconfig + KConfigGroup group(m_config, baseUrl.toString()); + group.writeEntry("user", user); + group.writeEntry("password", KStringHandler::obscure(password)); + kDebug() << "Saved credentials in KConfig"; + return true; + } + + // Remove the entry when user name is empty + if (user.isEmpty()) { + m_wallet->removeEntry(baseUrl.toString()); + return true; + } + + QMap entries; + entries.insert("user", user); + entries.insert("password", password); + kDebug() << "Saved credentials in KWallet"; + + return !m_wallet->writeMap(baseUrl.toString(), entries); +} + + +bool KdePlatformDependent::hasCredentials(const QUrl& baseUrl) const +{ + if (m_passwords.contains(baseUrl.toString())) { + return true; + } + + QString networkWallet = KWallet::Wallet::NetworkWallet(); + if (!KWallet::Wallet::folderDoesNotExist(networkWallet, "Attica") && + !KWallet::Wallet::keyDoesNotExist(networkWallet, "Attica", baseUrl.toString())) { + kDebug() << "Found credentials in KWallet"; + return true; + } + + KConfigGroup group(m_config, baseUrl.toString()); + QString user; + user = group.readEntry("user", QString()); + if (!user.isEmpty()) { + kDebug() << "Found credentials in KConfig"; + return true; + } + + kDebug() << "No credentials found"; + return false; +} + + +bool KdePlatformDependent::loadCredentials(const QUrl& baseUrl, QString& user, QString& password) +{ + QString networkWallet = KWallet::Wallet::NetworkWallet(); + if (KWallet::Wallet::folderDoesNotExist(networkWallet, "Attica") && + KWallet::Wallet::keyDoesNotExist(networkWallet, "Attica", baseUrl.toString())) { + // use KConfig + KConfigGroup group(m_config, baseUrl.toString()); + user = group.readEntry("user", QString()); + password = KStringHandler::obscure(group.readEntry("password", QString())); + if (!user.isEmpty()) { + kDebug() << "Successfully loaded credentials from kconfig"; + m_passwords[baseUrl.toString()] = QPair (user, password); + return true; + } + return false; + } + + if (!m_wallet && !openWallet(true)) { + return false; + } + + QMap entries; + if (m_wallet->readMap(baseUrl.toString(), entries) != 0) { + return false; + } + user = entries.value("user"); + password = entries.value("password"); + kDebug() << "Successfully loaded credentials."; + + m_passwords[baseUrl.toString()] = QPair (user, password); + + return true; +} + + +bool Attica::KdePlatformDependent::askForCredentials(const QUrl& baseUrl, QString& user, QString& password) +{ + Q_UNUSED(baseUrl); + Q_UNUSED(user); + Q_UNUSED(password); + kDebug() << "Attempting to start KCM for credentials"; + KCMultiDialog KCM; + KCM.setWindowTitle( i18n( "Open Collaboration Providers" ) ); + KCM.addModule( "kcm_attica" ); + + KCM.exec(); + + return false; +} + +QList KdePlatformDependent::getDefaultProviderFiles() const +{ + KConfigGroup group(m_config, "General"); + QStringList pathStrings = group.readPathEntry("providerFiles", QStringList("http://download.kde.org/ocs/providers.xml")); + QList paths; + foreach (const QString& pathString, pathStrings) { + paths.append(QUrl(pathString)); + } + qDebug() << "Loaded paths from config:" << paths; + return paths; +} + +void KdePlatformDependent::addDefaultProviderFile(const QUrl& url) +{ + KConfigGroup group(m_config, "General"); + QStringList pathStrings = group.readPathEntry("providerFiles", QStringList("http://download.kde.org/ocs/providers.xml")); + QString urlString = url.toString(); + if(!pathStrings.contains(urlString)) { + pathStrings.append(urlString); + group.writeEntry("providerFiles", pathStrings); + group.sync(); + kDebug() << "wrote providers: " << pathStrings; + } +} + +void KdePlatformDependent::removeDefaultProviderFile(const QUrl& url) +{ + KConfigGroup group(m_config, "General"); + QStringList pathStrings = group.readPathEntry("providerFiles", QStringList("http://download.kde.org/ocs/providers.xml")); + pathStrings.removeAll(url.toString()); + group.writeEntry("providerFiles", pathStrings); +} + +void KdePlatformDependent::enableProvider(const QUrl& baseUrl, bool enabled) const +{ + KConfigGroup group(m_config, "General"); + QStringList pathStrings = group.readPathEntry("disabledProviders", QStringList()); + if (enabled) { + pathStrings.removeAll(baseUrl.toString()); + } else { + if (!pathStrings.contains(baseUrl.toString())) { + pathStrings.append(baseUrl.toString()); + } + } + group.writeEntry("disabledProviders", pathStrings); + group.sync(); +} + +bool KdePlatformDependent::isEnabled(const QUrl& baseUrl) const +{ + KConfigGroup group(m_config, "General"); + return !group.readPathEntry("disabledProviders", QStringList()).contains(baseUrl.toString()); +} + +QNetworkAccessManager* Attica::KdePlatformDependent::nam() +{ + return m_accessManager; +} + + +Q_EXPORT_PLUGIN2(attica_kde, Attica::KdePlatformDependent) + + +#include "kdeplatformdependent.moc" diff --git a/attica/kdeplugin/kdeplatformdependent.h b/attica/kdeplugin/kdeplatformdependent.h new file mode 100644 index 00000000..69883dba --- /dev/null +++ b/attica/kdeplugin/kdeplatformdependent.h @@ -0,0 +1,79 @@ +/* + This file is part of KDE. + + Copyright (c) 2009 Eckhart Wörner + Copyright (c) 2010 Frederik Gladhorn + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 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 6 of version 3 of the license. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library. If not, see . + +*/ + +#ifndef ATTICA_KDEPLATFORMDEPENDENT_H +#define ATTICA_KDEPLATFORMDEPENDENT_H + +#include + +#include + +#include +#include + + +namespace KWallet { + class Wallet; +} + +namespace Attica { + +class KdePlatformDependent : public QObject, public Attica::PlatformDependent +{ + Q_OBJECT + Q_INTERFACES(Attica::PlatformDependent) + +public: + KdePlatformDependent(); + virtual ~KdePlatformDependent(); + virtual QList getDefaultProviderFiles() const; + virtual void addDefaultProviderFile(const QUrl& url); + virtual void removeDefaultProviderFile(const QUrl& url); + virtual void enableProvider(const QUrl& baseUrl, bool enabled) const; + virtual bool isEnabled(const QUrl& baseUrl) const; + + virtual QNetworkReply* post(const QNetworkRequest& request, const QByteArray& data); + virtual QNetworkReply* post(const QNetworkRequest& request, QIODevice* data); + virtual QNetworkReply* get(const QNetworkRequest& request); + virtual bool saveCredentials(const QUrl& baseUrl, const QString& user, const QString& password); + virtual bool hasCredentials(const QUrl& baseUrl) const; + virtual bool loadCredentials(const QUrl& baseUrl, QString& user, QString& password); + virtual bool askForCredentials(const QUrl& baseUrl, QString& user, QString& password); + virtual QNetworkAccessManager* nam(); + +private: + bool openWallet(bool force); + QNetworkRequest removeAuthFromRequest(const QNetworkRequest& request); + + KSharedConfigPtr m_config; + //QNetworkAccessManager m_qnam; + KIO::Integration::AccessManager* m_accessManager; + KWallet::Wallet* m_wallet; + QHash > m_passwords; +}; + +} + + +#endif diff --git a/cmake/modules/CMakeLists.txt b/cmake/modules/CMakeLists.txt index 2fd68b88..6fa94932 100644 --- a/cmake/modules/CMakeLists.txt +++ b/cmake/modules/CMakeLists.txt @@ -2,7 +2,9 @@ # don't glob for the files, since we don't want to # install e.g. FindLibKNotification-1.cmake -set(cmakeFiles FindDBus.cmake +set(cmakeFiles FindCLucene.cmake + FindSLP.cmake + FindDBus.cmake FindLibXKlavier.cmake FindOpenGLES.cmake FindPAM.cmake diff --git a/cmake/modules/FindCLucene.cmake b/cmake/modules/FindCLucene.cmake new file mode 100644 index 00000000..b7c0e862 --- /dev/null +++ b/cmake/modules/FindCLucene.cmake @@ -0,0 +1,97 @@ +# +# This module looks for clucene (http://clucene.sf.net) support +# It will define the following values +# +# CLUCENE_INCLUDE_DIR = where CLucene/StdHeader.h can be found +# CLUCENE_LIBRARY_DIR = where CLucene/clucene-config.h can be found +# CLUCENE_LIBRARY = the library to link against CLucene +# CLUCENE_VERSION = The CLucene version string +# CLucene_FOUND = set to 1 if clucene is found +# + +INCLUDE(CheckSymbolExists) +INCLUDE(FindLibraryWithDebug) + +if(NOT CLUCENE_MIN_VERSION) + set(CLUCENE_MIN_VERSION "0.9.19") +endif(NOT CLUCENE_MIN_VERSION) + +IF(EXISTS ${PROJECT_CMAKE}/CLuceneConfig.cmake) + INCLUDE(${PROJECT_CMAKE}/CLuceneConfig.cmake) +ENDIF(EXISTS ${PROJECT_CMAKE}/CLuceneConfig.cmake) + +SET(TRIAL_LIBRARY_PATHS + $ENV{CLUCENE_HOME}/lib${LIB_SUFFIX} + ${CMAKE_INSTALL_PREFIX}/lib${LIB_SUFFIX} + /usr/local/lib${LIB_SUFFIX} + /usr/lib${LIB_SUFFIX} + /sw/lib${LIB_SUFFIX} + /usr/pkg/lib${LIB_SUFFIX} + ) +SET(TRIAL_INCLUDE_PATHS + $ENV{CLUCENE_HOME}/include + ${CMAKE_INSTALL_PREFIX}/include + /usr/local/include + /usr/include + /sw/include + /usr/pkg/include + ) +FIND_LIBRARY_WITH_DEBUG(CLUCENE_LIBRARY + WIN32_DEBUG_POSTFIX d + NAMES clucene clucene-core + PATHS ${TRIAL_LIBRARY_PATHS}) +IF (CLUCENE_LIBRARY) + MESSAGE(STATUS "Found CLucene library: ${CLUCENE_LIBRARY}") +ENDIF (CLUCENE_LIBRARY) +FIND_PATH(CLUCENE_INCLUDE_DIR + NAMES CLucene.h + PATHS ${TRIAL_INCLUDE_PATHS}) + +IF (CLUCENE_INCLUDE_DIR) + MESSAGE(STATUS "Found CLucene include dir: ${CLUCENE_INCLUDE_DIR}") +ENDIF (CLUCENE_INCLUDE_DIR) + +IF(WIN32) + SET(TRIAL_LIBRARY_PATHS ${CLUCENE_INCLUDE_DIR}) +ENDIF(WIN32) + +SET(CLUCENE_GOOD_VERSION TRUE) + +FIND_PATH(CLUCENE_LIBRARY_DIR + NAMES CLucene/clucene-config.h PATHS ${TRIAL_LIBRARY_PATHS} ${TRIAL_INCLUDE_PATHS} NO_DEFAULT_PATH) +IF (CLUCENE_LIBRARY_DIR) + MESSAGE(STATUS "Found CLucene library dir: ${CLUCENE_LIBRARY_DIR}") + FILE(READ ${CLUCENE_LIBRARY_DIR}/CLucene/clucene-config.h CLCONTENT) + STRING(REGEX MATCH "_CL_VERSION +\".*\"" CLMATCH ${CLCONTENT}) + IF (CLMATCH) + STRING(REGEX REPLACE "_CL_VERSION +\"(.*)\"" "\\1" CLUCENE_VERSION ${CLMATCH}) + IF (CLUCENE_VERSION STRLESS "${CLUCENE_MIN_VERSION}") + MESSAGE(ERROR " CLucene version ${CLUCENE_VERSION} is less than the required minimum ${CLUCENE_MIN_VERSION}") + SET(CLUCENE_GOOD_VERSION FALSE) + ENDIF (CLUCENE_VERSION STRLESS "${CLUCENE_MIN_VERSION}") + IF (CLUCENE_VERSION STREQUAL "0.9.17") + MESSAGE(ERROR "CLucene version 0.9.17 is not supported.") + SET(CLUCENE_GOOD_VERSION FALSE) + ENDIF (CLUCENE_VERSION STREQUAL "0.9.17") + ENDIF (CLMATCH) +ENDIF (CLUCENE_LIBRARY_DIR) + +IF(CLUCENE_INCLUDE_DIR AND CLUCENE_LIBRARY AND CLUCENE_LIBRARY_DIR AND CLUCENE_GOOD_VERSION) + SET(CLucene_FOUND TRUE) +ENDIF(CLUCENE_INCLUDE_DIR AND CLUCENE_LIBRARY AND CLUCENE_LIBRARY_DIR AND CLUCENE_GOOD_VERSION) + +IF(CLucene_FOUND) + IF(NOT CLucene_FIND_QUIETLY) + MESSAGE(STATUS "Found CLucene: ${CLUCENE_LIBRARY} version ${CLUCENE_VERSION}") + ENDIF(NOT CLucene_FIND_QUIETLY) +ELSE(CLucene_FOUND) + IF(CLucene_FIND_REQUIRED) + MESSAGE(FATAL_ERROR "Could not find CLucene.") + ENDIF(CLucene_FIND_REQUIRED) +ENDIF(CLucene_FOUND) + +MARK_AS_ADVANCED( + CLUCENE_INCLUDE_DIR + CLUCENE_LIBRARY_DIR + CLUCENE_LIBRARY + ) diff --git a/cmake/modules/FindLibGcrypt.cmake b/cmake/modules/FindLibGcrypt.cmake new file mode 100644 index 00000000..e2a0b9dc --- /dev/null +++ b/cmake/modules/FindLibGcrypt.cmake @@ -0,0 +1,81 @@ +#.rst +# FindLibGcrypt +# ------------- +# +# Finds the Libgcrypt library. +# +# This will define the following variables: +# +# ``LIBGCRYPT_FOUND`` +# True if the requested version of gcrypt was found +# ``LIBGCRYPT_VERSION`` +# The version of gcrypt that was found +# ``LIBGCRYPT_INCLUDE_DIRS`` +# The gcrypt include directories +# ``LIBGCRYPT_LIBRARIES`` +# The linker libraries needed to use the gcrypt library + +# Copyright 2014 Nicolás Alvarez +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. The name of the author may not be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +find_program(LIBGCRYPTCONFIG_SCRIPT NAMES libgcrypt-config) +if(LIBGCRYPTCONFIG_SCRIPT) + execute_process(COMMAND "${LIBGCRYPTCONFIG_SCRIPT}" --prefix OUTPUT_VARIABLE PREFIX) + set(LIBGCRYPT_LIB_HINT "${PREFIX}/lib") + set(LIBGCRYPT_INCLUDE_HINT "${PREFIX}/include") +endif() + +find_library(LIBGCRYPT_LIBRARY + NAMES gcrypt + HINTS ${LIBGCRYPT_LIB_HINT} +) +find_path(LIBGCRYPT_INCLUDE_DIR + NAMES gcrypt.h + HINTS ${LIBGCRYPT_INCLUDE_HINT} +) + +if(LIBGCRYPT_INCLUDE_DIR) + file(STRINGS ${LIBGCRYPT_INCLUDE_DIR}/gcrypt.h GCRYPT_H REGEX "^#define GCRYPT_VERSION ") + string(REGEX REPLACE "^#define GCRYPT_VERSION \"(.*)\".*$" "\\1" LIBGCRYPT_VERSION "${GCRYPT_H}") +endif() + +include(FindPackageHandleStandardArgs) + +find_package_handle_standard_args(LibGcrypt + REQUIRED_VARS LIBGCRYPT_LIBRARY LIBGCRYPT_INCLUDE_DIR + VERSION_VAR LIBGCRYPT_VERSION +) +if(LIBGCRYPT_FOUND) + set(LIBGCRYPT_LIBRARIES ${LIBGCRYPT_LIBRARY}) + set(LIBGCRYPT_INCLUDE_DIRS ${LIBGCRYPT_INCLUDE_DIR}) +endif() + +mark_as_advanced(LIBGCRYPT_LIBRARY LIBGCRYPT_INCLUDE_DIR) + +include(FeatureSummary) +set_package_properties(LibGcrypt PROPERTIES + DESCRIPTION "A general purpose cryptographic library based on the code from GnuPG." + URL "http://www.gnu.org/software/libgcrypt/" +) diff --git a/cmake/modules/FindLibSSH.cmake b/cmake/modules/FindLibSSH.cmake new file mode 100644 index 00000000..aeb685ad --- /dev/null +++ b/cmake/modules/FindLibSSH.cmake @@ -0,0 +1,80 @@ +# - Try to find LibSSH +# Once done this will define +# +# LIBSSH_FOUND - system has LibSSH +# LIBSSH_INCLUDE_DIRS - the LibSSH include directory +# LIBSSH_LIBRARIES - Link these to use LibSSH +# LIBSSH_DEFINITIONS - Compiler switches required for using LibSSH +# +# Copyright (c) 2009-2014 Andreas Schneider +# +# Redistribution and use is allowed according to the terms of the New +# BSD license. +# For details see the accompanying COPYING-CMAKE-SCRIPTS file. +# + +find_path(LIBSSH_INCLUDE_DIR + NAMES + libssh/libssh.h + PATHS + /usr/include + /usr/local/include + /opt/local/include + /sw/include + ${CMAKE_INCLUDE_PATH} + ${CMAKE_INSTALL_PREFIX}/include +) + +find_library(SSH_LIBRARY + NAMES + ssh + libssh + PATHS + /usr/lib + /usr/local/lib + /opt/local/lib + /sw/lib + ${CMAKE_LIBRARY_PATH} + ${CMAKE_INSTALL_PREFIX}/lib +) + +set(LIBSSH_LIBRARIES + ${LIBSSH_LIBRARIES} + ${SSH_LIBRARY} +) + +if (LIBSSH_INCLUDE_DIR AND LibSSH_FIND_VERSION) + file(STRINGS ${LIBSSH_INCLUDE_DIR}/libssh/libssh.h LIBSSH_VERSION_MAJOR + REGEX "#define[ ]+LIBSSH_VERSION_MAJOR[ ]+[0-9]+") + + # Older versions of libssh like libssh-0.2 have LIBSSH_VERSION but not LIBSSH_VERSION_MAJOR + if (LIBSSH_VERSION_MAJOR) + string(REGEX MATCH "[0-9]+" LIBSSH_VERSION_MAJOR ${LIBSSH_VERSION_MAJOR}) + file(STRINGS ${LIBSSH_INCLUDE_DIR}/libssh/libssh.h LIBSSH_VERSION_MINOR + REGEX "#define[ ]+LIBSSH_VERSION_MINOR[ ]+[0-9]+") + string(REGEX MATCH "[0-9]+" LIBSSH_VERSION_MINOR ${LIBSSH_VERSION_MINOR}) + file(STRINGS ${LIBSSH_INCLUDE_DIR}/libssh/libssh.h LIBSSH_VERSION_PATCH + REGEX "#define[ ]+LIBSSH_VERSION_MICRO[ ]+[0-9]+") + string(REGEX MATCH "[0-9]+" LIBSSH_VERSION_PATCH ${LIBSSH_VERSION_PATCH}) + + set(LIBSSH_VERSION ${LIBSSH_VERSION_MAJOR}.${LIBSSH_VERSION_MINOR}.${LIBSSH_VERSION_PATCH}) + + else (LIBSSH_VERSION_MAJOR) + message(STATUS "LIBSSH_VERSION_MAJOR not found in ${LIBSSH_INCLUDE_DIR}/libssh/libssh.h, assuming libssh is too old") + set(LIBSSH_FOUND FALSE) + endif (LIBSSH_VERSION_MAJOR) +endif (LIBSSH_INCLUDE_DIR AND LibSSH_FIND_VERSION) + +# If the version is too old, but libs and includes are set, +# find_package_handle_standard_args will set LIBSSH_FOUND to TRUE again, +# so we need this if() here. +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(LibSSH + REQUIRED_VARS + LIBSSH_LIBRARIES + LIBSSH_INCLUDE_DIR + VERSION_VAR + LIBSSH_VERSION) + +# show the LIBSSH_INCLUDE_DIRS and LIBSSH_LIBRARIES variables only in the advanced view +mark_as_advanced(LIBSSH_INCLUDE_DIR LIBSSH_LIBRARIES) diff --git a/cmake/modules/FindQNtrack.cmake b/cmake/modules/FindQNtrack.cmake new file mode 100644 index 00000000..7a6d57b7 --- /dev/null +++ b/cmake/modules/FindQNtrack.cmake @@ -0,0 +1,70 @@ +# - Try to find the QNtrack library +# Once done this will define +# +# QNTRACK_FOUND - system has the CK Connector +# QNTRACK_INCLUDE_DIR - the CK Connector include directory +# QNTRACK_LIBRARIES - the libraries needed to use CK Connector + +# Copyright (C) 2010 Sune Vuorela +# modeled after FindCkConnector.cmake: +# Copyright (c) 2008, Kevin Kofler, +# modeled after FindLibArt.cmake: +# Copyright (c) 2006, Alexander Neundorf, +# +# Redistribution and use is allowed according to the terms of the BSD license. +# For details see the accompanying COPYING-CMAKE-SCRIPTS file. + + +if(QNTRACK_INCLUDE_DIR AND QNTRACK_LIBRARIES) + + # in cache already + SET(QNTRACK_FOUND TRUE) + +else (QNTRACK_INCLUDE_DIR AND QNTRACK_LIBRARIES) + + IF (NOT WIN32) + FIND_PACKAGE(PkgConfig) + IF (PKG_CONFIG_FOUND) + # use pkg-config to get the directories and then use these values + # in the FIND_PATH() and FIND_LIBRARY() calls + pkg_check_modules(_QNTRACK_PC QUIET libntrack-qt4 ) + ENDIF (PKG_CONFIG_FOUND) + ENDIF (NOT WIN32) + + FIND_PATH(QNTRACK_QT_INCLUDE_DIR QNtrack.h + ${_QNTRACK_PC_INCLUDE_DIRS} + ) + #Hide from cmake user interfaces + SET(QNTRACK_QT_INCLUDE_DIR ${QNTRACK_QT_INCLUDE_DIR} CACHE INTERNAL "" FORCE) + + FIND_PATH(NTRACK_INCLUDE_DIR ntrackmonitor.h + ${_QNTRACK_PC_INCLUDE_DIRS} + ) + #Hide from cmake user interfaces + SET(NTRACK_INCLUDE_DIR ${NTRACK_INCLUDE_DIR} CACHE INTERNAL "" FORCE) + + FIND_LIBRARY(QNTRACK_LIBRARIES NAMES ntrack-qt4 + PATHS + ${_QNTRACK_PC_LIBDIR} + ) + + + if (QNTRACK_QT_INCLUDE_DIR AND NTRACK_INCLUDE_DIR AND QNTRACK_LIBRARIES) + set(QNTRACK_FOUND TRUE) + set(QNTRACK_INCLUDE_DIR ${QNTRACK_QT_INCLUDE_DIR} ${NTRACK_INCLUDE_DIR}) + endif (QNTRACK_QT_INCLUDE_DIR AND NTRACK_INCLUDE_DIR AND QNTRACK_LIBRARIES) + + + if (QNTRACK_FOUND) + if (NOT QNtrack_FIND_QUIETLY) + message(STATUS "Found QNtrack: ${QNTRACK_LIBRARIES}") + endif (NOT QNtrack_FIND_QUIETLY) + else (QNTRACK_FOUND) + if (QNtrack_FIND_REQUIRED) + message(FATAL_ERROR "Could NOT find QNtrack") + endif (QNtrack_FIND_REQUIRED) + endif (QNTRACK_FOUND) + + MARK_AS_ADVANCED(QNTRACK_INCLUDE_DIR QNTRACK_LIBRARIES) + +endif (QNTRACK_INCLUDE_DIR AND QNTRACK_LIBRARIES) diff --git a/cmake/modules/FindSLP.cmake b/cmake/modules/FindSLP.cmake new file mode 100644 index 00000000..4e87fa45 --- /dev/null +++ b/cmake/modules/FindSLP.cmake @@ -0,0 +1,22 @@ +# cmake macro to test SLP LIB + +# Copyright (c) 2006, 2007 Laurent Montel, +# +# Redistribution and use is allowed according to the terms of the BSD license. +# For details see the accompanying COPYING-CMAKE-SCRIPTS file. + + +if (SLP_INCLUDE_DIR AND SLP_LIBRARIES) + # Already in cache, be silent + set(SLP_FIND_QUIETLY TRUE) +endif (SLP_INCLUDE_DIR AND SLP_LIBRARIES) + + +FIND_PATH(SLP_INCLUDE_DIR slp.h) + +FIND_LIBRARY(SLP_LIBRARIES NAMES slp libslp) + +include(FindPackageHandleStandardArgs) +FIND_PACKAGE_HANDLE_STANDARD_ARGS(SLP DEFAULT_MSG SLP_LIBRARIES SLP_INCLUDE_DIR ) + +MARK_AS_ADVANCED(SLP_INCLUDE_DIR SLP_LIBRARIES) diff --git a/cmake/modules/MacroDBusAddActivationService.cmake b/cmake/modules/MacroDBusAddActivationService.cmake new file mode 100644 index 00000000..7305d64b --- /dev/null +++ b/cmake/modules/MacroDBusAddActivationService.cmake @@ -0,0 +1,9 @@ +macro(dbus_add_activation_service _sources) + foreach (_i ${_sources}) + get_filename_component(_service_file ${_i} ABSOLUTE) + string(REGEX REPLACE "\\.service.*$" ".service" _output_file ${_i}) + set(_target ${CMAKE_CURRENT_BINARY_DIR}/${_output_file}) + configure_file(${_service_file} ${_target}) + install(FILES ${_target} DESTINATION ${DBUS_SERVICES_INSTALL_DIR} ) + endforeach (_i ${ARGN}) +endmacro(dbus_add_activation_service _sources) diff --git a/config-runtime.h.cmake b/config-runtime.h.cmake new file mode 100644 index 00000000..3db7a8ab --- /dev/null +++ b/config-runtime.h.cmake @@ -0,0 +1,47 @@ +/* config-runtime.h. Generated by cmake from config-runtime.h.cmake */ + +/* media HAL backend compilation */ +#undef COMPILE_HALBACKEND + +/* Define if you have long long as datatype */ +#cmakedefine HAVE_LONG_LONG 1 + +/* Define to 1 if you have the `nice' function. */ +#cmakedefine HAVE_NICE 1 + +/* Define to 1 if you have the `sigaction' function. */ +#cmakedefine HAVE_SIGACTION 1 + +/* Define to 1 if you have the `sigset' function. */ +#cmakedefine HAVE_SIGSET 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_STRING_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_SYS_SELECT_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_SYS_SOCKET_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_SYS_TIME_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_SYS_TYPES_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_SYS_WAIT_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_UNISTD_H 1 + +/* Number of bits in a file offset, on hosts where this is settable. */ +#define _FILE_OFFSET_BITS 64 + +/* + * On HP-UX, the declaration of vsnprintf() is needed every time ! + */ + +/* type to use in place of socklen_t if not defined */ +#define kde_socklen_t socklen_t diff --git a/doc/CMakeLists.txt b/doc/CMakeLists.txt index af00f4cd..67147f49 100644 --- a/doc/CMakeLists.txt +++ b/doc/CMakeLists.txt @@ -7,6 +7,22 @@ add_subdirectory(plasma-desktop) add_subdirectory(kcontrol) add_subdirectory(systemsettings) add_subdirectory(kinfocenter) + if(POLKITQT_FOUND) add_subdirectory(PolicyKit-kde) endif(POLKITQT_FOUND) + +if ( UNIX ) + add_subdirectory(kdesu) +endif ( UNIX ) + +add_subdirectory(kcontrol) +add_subdirectory(glossary) +add_subdirectory(kdebugdialog) +add_subdirectory(khelpcenter) +add_subdirectory(kioslave) +add_subdirectory(knetattach) +add_subdirectory(onlinehelp) +add_subdirectory(documentationnotfound) +add_subdirectory(fundamentals) +add_subdirectory(plasmapkg) \ No newline at end of file diff --git a/doc/api/Doxyfile.local b/doc/api/Doxyfile.local new file mode 100644 index 00000000..952cc6a8 --- /dev/null +++ b/doc/api/Doxyfile.local @@ -0,0 +1,25 @@ +## Warn about everything, just like in kdelibs. +WARN_IF_UNDOCUMENTED = YES +## Be strict, we want all parameters +## to be documented as well. +WARN_NO_PARAMDOC = YES + +## Sort methods to make 'same as above' easier. +SORT_MEMBER_DOCS = YES + +## Remove unsightly export macros +PREDEFINED = Q_EXPORT="" \ + Q_GUI_EXPORT="" \ + KWIN_EXPORT="" \ + KFONTINST_EXPORT="" \ + PLASMA_EXPORT="" \ + LIBDOLPHINPRIVATE_EXPORT="" \ + KONQSIDEBAR_EXPORT="" \ + KONQSIDEBARPLUGIN_EXPORT="" \ + SOLIDCONTROL_EXPORT="" \ + SOLIDCONTROLIFACES_EXPORT="" \ + KNEPREGCORE_EXPORT= "" \ + KDEUI_EXPORT="" \ + KDE_EXPORT="" \ + Q_SLOTS="slots" \ + Q_SIGNALS="signals" diff --git a/doc/documentationnotfound/CMakeLists.txt b/doc/documentationnotfound/CMakeLists.txt new file mode 100644 index 00000000..9d35fb34 --- /dev/null +++ b/doc/documentationnotfound/CMakeLists.txt @@ -0,0 +1,2 @@ +########### install files ############### +kde4_create_handbook(index.docbook INSTALL_DESTINATION ${HTML_INSTALL_DIR}/en SUBDIR khelpcenter/documentationnotfound) diff --git a/doc/documentationnotfound/index.docbook b/doc/documentationnotfound/index.docbook new file mode 100644 index 00000000..c7a81198 --- /dev/null +++ b/doc/documentationnotfound/index.docbook @@ -0,0 +1,66 @@ + + + +]> +
+Documentation not Found + + +Jack +Ostroff + +
ostroffjh@users.sourceforge.net
+
+
+ +
+ +2010-09-21 +&kde; 4.5 + +
+ +The requested documentation was not found on your computer. +Normally, &kde; looks for application handbooks in a location that depends +on how &kde; was installed on your computer. There are a number of +possible reasons why it could not find the documentation you +requested. The document might not exist, or it may not have been +installed along with the application. + +How to solve this issue: + +Start by searching the KDE +Documentation site for the requested documentation. If you find +the documentation on that site, your distribution might ship a separate +package for documentation (⪚ called kdepim-doc for all applications +from the kdepim module, like &kmail;, &kontact;, &etc;). Please use the +package manager of your distribution to find and install the missing +documentation. + +If you use a source based distribution, such as Gentoo, be sure that +there are not any configuration settings (USE flags in Gentoo) that +might have disabled the installation of the documentation. + + +If you have done that, but still get this page displayed instead of the +application handbook, you probably found a bug in the &kde; help +system. In this case, please report this on the KDE Bug Tracker. + + +If you do not find any documentation on the KDE Documentation site, the +application may not have offline documentation. Please report this on +the KDE Bug Tracker. + + +In case the application does not have offline documentation, you should +use the online resources UserBase Documentation and +KDE Community Forums to get +help. + + +
\ No newline at end of file diff --git a/doc/fundamentals/CMakeLists.txt b/doc/fundamentals/CMakeLists.txt new file mode 100644 index 00000000..dd75aec8 --- /dev/null +++ b/doc/fundamentals/CMakeLists.txt @@ -0,0 +1 @@ +kde4_create_handbook(index.docbook INSTALL_DESTINATION ${HTML_INSTALL_DIR}/en) diff --git a/doc/fundamentals/colors.png b/doc/fundamentals/colors.png new file mode 100644 index 00000000..7059435b Binary files /dev/null and b/doc/fundamentals/colors.png differ diff --git a/doc/fundamentals/config.docbook b/doc/fundamentals/config.docbook new file mode 100644 index 00000000..5de09be6 --- /dev/null +++ b/doc/fundamentals/config.docbook @@ -0,0 +1,391 @@ + +Customizing &kde; software + + + + +&TC.Hollingsworth; &TC.Hollingsworth.mail; + + + +Customizing Toolbars + + + + + +The &gwenview; Toolbar + + +The &gwenview; toolbar. +The toolbar in +&gwenview;. + + + + + +Modifying Toolbar Items + +To customize an application's toolbars, go to +SettingsConfigure +Toolbars... or right-click on a toolbar and select +Configure Toolbars.... + +On the left side of the toolbar configuration panel, the available items +that you can put in your toolbar are shown. On the right, the ones that already +appear on the toolbar are shown. At the top, you can select the toolbar +you wish to modify or view. + +Above each side of the panel there is a Filter text +box you can use to easily find items in the list. + + +The Customize Toolbars Window + + +The Customize Toolbars window. +The Customize Toolbars window in &gwenview; with the +Previous button selected. + + + + +Adding an Item +You can add an item to your toolbar by selecting it from the left side and +clicking on the right arrow button. + + + +Removing an Item +You can remove an item by selecting it and clicking the left arrow +button. + + + + +Changing the Position of Items + +You can change the position of the items by moving them lower or higher in +the list. To move items lower, press the down arrow button, while to move items +higher press the up arrow button. You can also change items' position by +dragging and dropping them. + +On horizontal toolbars, the item that's on top will be the one on the left. +On vertical toolbars, items are arranged as they appear in the toolbar. + + + + +Adding a Separator +You can add separator lines between items by adding a +--- separator --- item to the toolbar. + + + +Restoring Defaults + +You can restore your toolbar to the way it was when you installed the +application by pressing the Defaults button at the bottom +of the window and then confirming your decision. + + + + +Changing Text and Icons + +You can change the icon and text of individual toolbar items by selecting +an item and clicking either the Change Icon... or +Change Text... button. + + + + + +Customizing Toolbar Appearance + +You can change the appearance of toolbars by right-clicking on a toolbar +to access it's context menu. + + +Text Position + +You can change the appearance of text on toolbars in the +Text Position submenu of a toolbar's context menu. + +You can choose from: + + + +Icons - +only the icon for each toolbar item will appear. + + + +Text - +only the text label for each toolbar item will appear. + + + +Text Alongside Icons - + +the text label will appear to the right of each toolbar item's icon + + + +Text Under Icons - +the text label will appear underneath each toolbar item's icon + + + + +You can also show or hide text for individual toolbar items by +right-clicking on an item and checking or unchecking the item under +Show Text. + + + + +Icon Size + +You can change the size of toolbar items' icons by selecting +Icon Size from the toolbar's context menu. + +You can choose from the following options: (each lists the icon size +in pixels) + + +Small (16x16) +Medium (22x22) + [the default value] +Large (32x32) +Huge (48x48) + + + + + +Moving Toolbars + +In order to move toolbars, you must unlock them. To do +so, uncheck Lock Toolbar Positions from a toolbar's +context menu. To restore the lock, simply recheck this menu item. + +You can change a toolbar's position from the +Orientation submenu of its context menu. + +You can choose from: + +Top + [the default in many applications] +Left +Right +Bottom + + +You can also move a toolbar by clicking and holding onto the dotted line +at the left of horizontal toolbars or the top of vertical toolbars and dragging +it to your desired location. + + + + +Show/Hide Toolbars + +If your application has only one toolbar, you can hide a toolbar by +deselecting Show Toolbar from either the toolbar's +context menu or the Settings menu. To restore the toolbar, +select Show Toolbar from the Settings +menu. Note that toolbars must be unlocked to hide them from their +context menu; see for more +information. + +If your application has more than one toolbar, a submenu called +Toolbars Shown will appear in the context menu and +Settings menu instead of the above menu entry. From that +menu you may select individual toolbars to hide and show. + + + + + +Thanks and Acknowledgments +Thanks to an anonymous Google Code-In 2011 participant for writing much +of this section. + + + + + + + + +Alexey Subach +&TC.Hollingsworth; &TC.Hollingsworth.mail; + + + + + + +Using and Customizing Shortcuts + + +Introduction + +Many &kde; applications allow you to configure keyboard shortcuts. To open +the standard keyboard shortcuts configuration panel, go to +SettingsConfigure +Shortcuts.... + +In the Configure Shortcuts window, you will see a list of all the shortcuts +available in the current application. You can use the search box at the top to +search for the shortcut you want. + + +The Customize Shortcuts Window + + +The Customize Shortcuts window. +Searching for shortcuts with file in +&dolphin;. + + + + + + + +Changing a Shortcut + +To change a shortcut, first click on the name of a shortcut you want to change. +You will see a radio group where you can choose whether to set the shortcut to its +default value, or select a new shortcut for the selected action. To set a new shortcut, +choose Custom and click on the button next to it. Then just +type the shortcut you would like to use, and your changes will be saved. + + +Setting a Shortcut + + +The Customize Shortcuts window demonstrating how to +set a shortcut. + + + + + + +Resetting Shortcuts +There is a button at the bottom of the window, called Reset to +Defaults. Clicking on this button will reset all your custom shortcuts +to their default values. + +You can also reset an individual shortcut to its default value by selecting +it, and choosing the Default radio button. + + + + +Removing a Shortcut + +To remove a shortcut, select it from the list, then click the remove icon (a +black arrow with a cross) to the right of the button that allows you to select +a shortcut. + + + + +Working with Schemes + +Schemes are keyboard shortcuts configuration profiles, so you can create +several profiles with different shortcuts and switch between these profiles +easily. + +This feature is under development. It is not possible to import +schemes using a &GUI; at this time. + + +Working with Schemes + + +The Customize Shortcuts window displaying the scheme +editing tools. +Editing a scheme called work. + + + +To see a menu allowing you to edit schemes, click on the +Details button at the bottom of the form. The following +options will appear: + + + + +Current Scheme +Allows you to switch between your schemes. + + + +New... +Creates a new scheme. This opens a window that lets you select +a name for your new scheme. + + + +Delete +Deletes the current scheme. + + + +More Actions + +Opens the following menu: + + + +Save as Scheme Defaults +Sets the current scheme as the default for all new schemes. + + + +Export Scheme... +Exports the current scheme to a file named applicationnameschemenameshortcuts.rc. + +Move this file to the folder $KDEDIR/apps/applicationname/ +and the exported scheme will be available in the drop down box labelled Current Scheme + + + + + + + + + + + +Printing Shortcuts + +You can print out a list of shortcuts for easy reference by clicking the +Print button at the bottom of the window. + + + + +Thanks and Acknowledgments + +Special thanks to Google Code-In 2011 participant Alexey Subach for +writing much of this section. + + + + + + diff --git a/doc/fundamentals/files-locationbar-breadcrumb.png b/doc/fundamentals/files-locationbar-breadcrumb.png new file mode 100644 index 00000000..a1dfc26c Binary files /dev/null and b/doc/fundamentals/files-locationbar-breadcrumb.png differ diff --git a/doc/fundamentals/files-locationbar-context-menu.png b/doc/fundamentals/files-locationbar-context-menu.png new file mode 100644 index 00000000..f26b9c34 Binary files /dev/null and b/doc/fundamentals/files-locationbar-context-menu.png differ diff --git a/doc/fundamentals/files-locationbar-editable.png b/doc/fundamentals/files-locationbar-editable.png new file mode 100644 index 00000000..8bd6ac3a Binary files /dev/null and b/doc/fundamentals/files-locationbar-editable.png differ diff --git a/doc/fundamentals/files-locationbar-places-icon.png b/doc/fundamentals/files-locationbar-places-icon.png new file mode 100644 index 00000000..1b620f74 Binary files /dev/null and b/doc/fundamentals/files-locationbar-places-icon.png differ diff --git a/doc/fundamentals/files-open.png b/doc/fundamentals/files-open.png new file mode 100644 index 00000000..e6b45374 Binary files /dev/null and b/doc/fundamentals/files-open.png differ diff --git a/doc/fundamentals/files-save.png b/doc/fundamentals/files-save.png new file mode 100644 index 00000000..d584bff3 Binary files /dev/null and b/doc/fundamentals/files-save.png differ diff --git a/doc/fundamentals/find-find-inline.png b/doc/fundamentals/find-find-inline.png new file mode 100644 index 00000000..58c1ebb2 Binary files /dev/null and b/doc/fundamentals/find-find-inline.png differ diff --git a/doc/fundamentals/find-find.png b/doc/fundamentals/find-find.png new file mode 100644 index 00000000..6201a039 Binary files /dev/null and b/doc/fundamentals/find-find.png differ diff --git a/doc/fundamentals/find-found.png b/doc/fundamentals/find-found.png new file mode 100644 index 00000000..0a9dd906 Binary files /dev/null and b/doc/fundamentals/find-found.png differ diff --git a/doc/fundamentals/find-replace-inline.png b/doc/fundamentals/find-replace-inline.png new file mode 100644 index 00000000..0bef63a1 Binary files /dev/null and b/doc/fundamentals/find-replace-inline.png differ diff --git a/doc/fundamentals/find-replace.png b/doc/fundamentals/find-replace.png new file mode 100644 index 00000000..81b7f750 Binary files /dev/null and b/doc/fundamentals/find-replace.png differ diff --git a/doc/fundamentals/fonts.png b/doc/fundamentals/fonts.png new file mode 100644 index 00000000..1e371176 Binary files /dev/null and b/doc/fundamentals/fonts.png differ diff --git a/doc/fundamentals/index.docbook b/doc/fundamentals/index.docbook new file mode 100644 index 00000000..ee269960 --- /dev/null +++ b/doc/fundamentals/index.docbook @@ -0,0 +1,147 @@ + + + + + + + + + Gwenview'> + + + + + + &kde; &plasma; Desktop"> + &plasma; Active"> + Meta"> + + + + + + +]> + + +&kde; Fundamentals + + + +&TC.Hollingsworth; &TC.Hollingsworth.mail; + + + + + +201120122013 +&TC.Hollingsworth; + + +2011 +Alexey Subach + + +2011 +Salma Sultana + +&FDLNotice; + +2013-12-08 +&kde; 4.12 + + +This guide provides an introduction to the &kde-sc; and describes many +common tasks that can be performed in all &kde; applications. + + + +KDE +introduction +user interface +menus +files +open +save +spelling +spellcheck +find +replace +colors +configuration +customization +toolbars +installation +compiling + + + + + +Introduction +Welcome to &kde;! + +This guide will introduce you to the many features of the &kde-sc; and +describe many common tasks you can perform in all &kde; applications. + +For more information on &kde;, visit the +KDE website. + + + +&install-chapter; + +&ui-chapter; + +&tasks-chapter; + +&config-chapter; + + + +Credits and License + +The original idea for this guide was proposed by Chusslove Illich and +brought to fruition with input from &Burkhard.Lueck;, Yuri Chornoivan, and +&TC.Hollingsworth; + +Much of it was written by participants of +Google +Code-In 2011. Thanks to Google for sponsoring their excellent work! + + + +&underFDL; +&underGPL; + + + +&documentation.index; + + + + + diff --git a/doc/fundamentals/install.docbook b/doc/fundamentals/install.docbook new file mode 100644 index 00000000..ffc1f0d1 --- /dev/null +++ b/doc/fundamentals/install.docbook @@ -0,0 +1,127 @@ + +Installing the &kde-sc; + +You can install the &kde-sc; on a variety of different platforms, ranging from +smartphones and tablets to computers running &Microsoft; &Windows;, &MacOS;, +&UNIX;, &BSD; or &Linux;. Binary packages are available for many different +platforms and distributions, or advanced users may build the source code. + + +Installing Packages + +Hundreds of developers worldwide have done a lot of work to make it easy +to install &kde; on a variety of different devices and platforms. + + +&Linux; + +Nearly every &Linux; distribution provides binary packages for individual +&kde-sc; applications and the &plasma-workspaces; as a whole. + +To install an individual application, look for its name in your +distribution's package collection. To install one of the &plasma-workspaces;, +like &plasma-desktop;, look for a metapackage or package +group, typically kde-desktop. + + +Some core applications may be installed together with other core +applications in a combined package named after the &kde; package they are +provided in. For instance, &dolphin; might be found in the +kde-baseapps package. + + +If you have trouble locating &kde; packages for your distribution, please +contact their support resources. Many distributions also have a team dedicated +to packaging &kde; that can provide assistance specific to &kde; + + + + + + +&Microsoft; &Windows; + +The &kde; on Windows Initiative provides binary packages of &kde-sc; +applications for &Microsoft; &Windows;. They also provide a special installer +application that permits you to install individual applications or groups and +all necessary dependencies easily. + +For more information on the initiative and to download the installer, +visit the KDE on Windows Initiative. + + + + + + + +&MacOS; + +Individual &kde-sc; applications can be installed through several +different ports systems available for &MacOS;. Several different +&kde; applications also provide their own binary builds for &MacOS;. + +For more information, visit +&kde; on &MacOS;X. + + + + +&BSD; + +Most &BSD; distributions allows you to install &kde-sc; applications +and the &plasma-workspaces; as a whole through their ports +system. + +For more information on installing ports, see your &BSD; distribution's +documentation. + + + + + + +Mobile Devices + +&plasma-active; is an exciting initiative to bring a new &kde; +experience to mobile devices like smartphones or tablets. Binary releases are +provided for several different devices. + +For more information, visit +&plasma-active;. + + + + +Live Media + +Several &Linux; and &BSD; distributions offer live media. This permits you +to try out the &plasma-workspaces; without installing anything to your system. +All you have to do insert a CD or connect a USB drive and boot from it. If you +like what you see, most offer an option to install it to your hard drive. + +There is a list +of distributions that offer the &kde-sc; on live media on the &kde; website. + + + +Building from Source Code + +For detailed information on how to compile and install &kde; +applications see + +Building and Running &kde; Software From Source on &kde; TechBase. + +Since &kde; software uses cmake you should +have no trouble compiling it. Should you run into problems please report them to the +&kde; mailing lists. + + + + + + \ No newline at end of file diff --git a/doc/fundamentals/menus.png b/doc/fundamentals/menus.png new file mode 100644 index 00000000..37c806a2 Binary files /dev/null and b/doc/fundamentals/menus.png differ diff --git a/doc/fundamentals/shortcuts-schemes.png b/doc/fundamentals/shortcuts-schemes.png new file mode 100644 index 00000000..5316cf6e Binary files /dev/null and b/doc/fundamentals/shortcuts-schemes.png differ diff --git a/doc/fundamentals/shortcuts-search.png b/doc/fundamentals/shortcuts-search.png new file mode 100644 index 00000000..19bb85b2 Binary files /dev/null and b/doc/fundamentals/shortcuts-search.png differ diff --git a/doc/fundamentals/shortcuts-set.png b/doc/fundamentals/shortcuts-set.png new file mode 100644 index 00000000..7158e2cc Binary files /dev/null and b/doc/fundamentals/shortcuts-set.png differ diff --git a/doc/fundamentals/spellcheck-check.png b/doc/fundamentals/spellcheck-check.png new file mode 100644 index 00000000..8d4a468b Binary files /dev/null and b/doc/fundamentals/spellcheck-check.png differ diff --git a/doc/fundamentals/tasks.docbook b/doc/fundamentals/tasks.docbook new file mode 100644 index 00000000..f4804899 --- /dev/null +++ b/doc/fundamentals/tasks.docbook @@ -0,0 +1,1198 @@ + +Common Tasks + + + + + +&TC.Hollingsworth; &TC.Hollingsworth.mail; + + + +Navigating Documents + + +Scrolling + +You're probably familiar with the scrollbar that appears on the right side +(and sometimes the bottom) of documents, allowing you to move within documents. +However, there are several other ways you can navigate documents, some of which +are faster and easier. + +Several mice have a wheel in the middle. You can move it up and down to +scroll within a document. If you press the &Shift; key while using the mouse +wheel, the document will scroll faster. + +If you're using a portable computer like a laptop, you might also be able +to scroll using the touchpad. Some computers allow you to scroll vertically +by moving your finger up and down the rightmost side of the touchpad, and allow +you to scroll horizontally by moving your finger across the bottommost side +of the touchpad. Others let you scroll using two fingers: move both fingers +up and down anywhere on the touchpad to scroll vertically, and move them left +and right to scroll horizontally. Since this functionality emulates the mouse +wheel functionality described above, you can also press the &Shift; key while +you do this to scroll faster. + +If you use the &plasma-workspaces;, you can control mouse wheel behavior +in the Mouse module in &systemsettings;, +and you can control touchpad scrolling behavior in the Touchpad module in +&systemsettings;. Otherwise, look in the configuration area of your operating +system or desktop environment. + +Additionally, the scrollbar has several options in its context menu. You +can access these by right-clicking anywhere on the scrollbar. The following +options are available: + + + + +Scroll here +Scroll directly to the location represented by where you +right-clicked on the scrollbar. This is the equivalent of simply clicking on +that location on the scrollbar. + + + + +&Ctrl;Home +Top + +Go to the beginning of the document. + + + + +&Ctrl;End +Bottom + +Go to the end of the document. + + + + +PgUp +Page up + +Navigate to the previous page in a document that represents a +printed document, or one screen up in other types of documents. + + + + +PgDown +Page down + +Navigate to the next page in a document that represents a +printed document, or one screen down in other types of documents. + + + + +Scroll up +Scroll up one unit (usually a line) in the document. This is +the equivalent of clicking the up arrow at the top of the scrollbar. + + + + +Scroll down +Scroll down one unit (usually a line) in the document. This is +the equivalent of clicking the down arrow at the bottom of the scrollbar. + + + + + + + + +Zooming + +Many applications permit you to zoom. This makes the text or image you +are viewing larger or smaller. You can generally find the zoom function in the +View menu, and sometimes in the status bar +of the application. + +You can also zoom using the keyboard by pressing +&Ctrl;+ to zoom in, or +&Ctrl;- to zoom out. If you +can scroll with the mouse wheel or touchpad as described in +, you can also zoom by pressing &Ctrl; and scrolling +that way. + + + + + + + + + +&TC.Hollingsworth; &TC.Hollingsworth.mail; + + + +Opening and Saving Files + + +Introduction + +Many &kde; applications work with files. Most applications have a +File menu with options that allow you to open and save files. +For more information on that, see . However, +there are lots of different operations that require selecting a file. Regardless +of the method, all &kde; applications generally use the same file selection +window. + + +The File Open Window + + +The File Open window. +Opening a file in +&konqueror;. + + + + + + + +The File Selection Window + + + + + + +The Toolbar + +This contains standard navigation tool buttons: + + + +Back +Causes the folder view to change to the previously displayed +folder in its history. This button is disabled, if there is no previous item. + + + + +Forward +Causes the folder view to change to the next folder in its +history. This button is disabled, if there is no next folder. + + + +Parent Folder +This will cause the folder view to change to the immediate +parent of the currently displayed folder, if possible. + + + +Reload (F5) +Reloads the folder view, displaying any changes that have been +made since it was first loaded or last reloaded. + + + +Show Preview +Displays a preview of each file inside the folder view. + + + + +Zoom Slider +This allows you to change the size of the icon or preview +shown in the folder view. + + + +Options + + + + + +OptionsSorting + + + + + + +OptionsSorting +By Name + +Sort files listed in the folder view alphabetically by name. + + + + + +OptionsSorting +By Size + +Sort files listed in the folder view in order of their file +size. + + + + +OptionsSorting +By Date + +Sort files listed in the folder view by the date they were last +modified. + + + + +OptionsSorting +By Type + +Sort files listed in the folder view alphabetically by their +file type. + + + + +OptionsSorting +Descending + +When unchecked (the default), files in the folder view will be +sorted in ascending order. (For instance, files sorted alphabetically will +be sorted from A to Z, while files sorted numerically will be sorted from +smallest to largest.) When checked, files in the folder will be sorted in +descending order (in reverse). + + + + +OptionsSorting +Folders First + +When enabled (the default), folders will appear before regular +files. + + + + + + + + +OptionsView + + + + + + +OptionsView +Short View + +Displays only the filenames. + + + + +OptionsView +Detailed View + +Displays Name, Date +and Size of the files. + + + + +OptionsView +Tree View + +Like Short View, but folders can be expanded to view their contents. + + + + +OptionsView +Detailed Tree View + +This also allows folders to be expanded, but displays the additional columns +available in Detailed View. + + + + + + + + + + &Alt;. + +OptionsShow Hidden Files + +Displays files or folders normally hidden by your operating system. + +The alternate shortcut for this action is F8. + + + + + +F9 +OptionsShow Places Navigation Panel + +Displays the places panel which provides quick access +to bookmarked locations and disks or other media. + + + + +OptionsShow Bookmarks + +Displays an additional icon on the toolbar that provides +access to bookmarks, a list of saved locations. + + + + +OptionsShow Aside Preview + +Displays a preview of the currently highlighted file to the +right of the folder view. + + + + + + + +Bookmarks +Opens a submenu to edit or add bookmarks and to add a new +bookmark folder. + + + + + + + + +Location Bar + +The location bar, which can be found on top of the folder view, displays +the path to the current folder. The location bar has two modes: + + + +Bread Crumb Mode + +In the bread crumb mode, which is the default, each folder +name in the path to the current folder is a button which can be clicked to quickly +open that folder. Moreover, clicking the > sign to the right of +a folder opens a menu which permits to quickly open a subfolder of that folder. + + + +Screenshot of the location bar in bread crumb mode + + + + + +Location bar in bread crumb mode. + +Location bar in bread crumb mode. + + + + + + + +Editable Mode + +When in bread crumb mode, clicking in the gray area to the right of the path +with the &LMB; switches the location bar to the editable mode, +in which the path can be edited using the keyboard. To switch back to bread +crumb mode, click the check mark at the right of the location bar with the &LMB;. + + + +Screenshot of the location bar in editable mode + + + + + +Location bar in editable mode. + +Location bar in editable mode. + + + + + + + + + + +The context menu of the location bar offers action to switch between the modes and +to copy and paste the path using the clipboard. Check the last option in this context menu to +display either the full path starting with the root folder of the file system or to display +the path starting with the current places entry. + + + +Location bar context menu + + + + + +Location bar context menu + + + + + + + + +The Places List +This provides the standard &kde; list of Places, shared with +&dolphin; and other file management tools. + + + +The Folder View + +The largest part of the file selection window is the area that lists all +items in the current directory. To select a file, you can double-click on it, +or choose one and hit Open or +Save. + +You can also select multiple files at once. To select specific files, or +to unselect specific files that are already selected, press and hold &Ctrl;, +click on each file, then release &Ctrl;. To select a +contiguous group of files, click the first file, press and hold &Shift;, click +on the last file in the group, and release &Shift;. + +The Folder View supports a limited set of file operations, which can be +accessed by right-clicking on a file to access its context menu, or using +keyboard shortcuts. The following items are available in the context menu: + + + + +Create New... +Create a new file or folder. + + + +Move to Trash... +(Del) +Move the currently selected item to the trash. + + + +Sorting +This submenu can also be accessed from the toolbar, and is +described in . + + + +View +This submenu can also be accessed from the toolbar, and is +described in . + + + +Open File Manager +Opens the current folder in your default file manager +application. + + + +Properties +(&Alt;&Enter;) +Open the Properties window that allows you to view and modify +various types of metadata related to the currently selected file. + + + + + + + +The Preview Pane +If enabled, this displays a preview of the currently highlighted +file. + + + +The Name Entry +When a file is selected, a name will appear in this text box. +You may also manually enter a file name or path in this text box. + + + +The Filter Entry + +When opening a file, the Filter entry allows you to +enter a filter for the files displayed in the folder view. The filter uses +standard globs; patterns must be separated by white space. For instance, you can +enter *.cpp *.h *.moc to display several different +common &Qt; programming files. + +To display all files, enter a single asterisk +(*). + +The filter entry saves the last 10 filters entered between +sessions. To use one, press the arrow button on the right of the entry +and select the desired filter string. You can disable the filter by pressing +the Clear text button to the left of the autocompletion +arrow button. + +When saving a file, the Filter entry will instead +display a drop down box that allows you to select from all the file types the +application supports. Select one to save a file in that format. + + + + +Automatically select filename extension +When saving a file, this check box will appear. When selected +(the default), the application will automatically append the default file +extension for the selected file type to the end of the file name, if it does +not already appear in the Name entry. The file extension +that will be used is listed in parenthesis at the end of the check box label. + + + +The File Save Window + + +The File Save window. +Saving a file in +&konqueror;. + + + + + + + + +The Open or Save Button +Depending on the action being performed, an +Open or Save button will be +displayed. Clicking on this button will close the file selection window and +perform the requested action. + + + +The Cancel Button +Clicking Cancel will close the file +dialog without performing any action. + + + + + + + +Thanks and Acknowledgments + +Special thanks to Google Code-In 2011 participant Alexey Subach for +writing parts of this section. + + + + + + + + + +&David.Sweet; &David.Sweet.mail; +Salma Sultana +&TC.Hollingsworth; &TC.Hollingsworth.mail; + + + +Check Spelling + +&sonnet; is the spelling checker used by &kde; applications such as &kate;, +&kmail;, and &kword;. It is a &GUI; frontend to various free spell checkers. + +To use &sonnet; you need to install a spell checker like +&GNU; Aspell, Enchant, +Hspell, ISpell or +Hunspell and additionally the corresponding +dictionaries for the languages that you wish to use. + + +Check Spelling + + +The Check Spelling Window + + + + + +The Check spelling window. + +Correcting a misspelling. + + + +To check spelling, go to Tools +Spelling.... + +If a word is possibly misspelled in your document, it is displayed in the +top line in the dialog. &sonnet; tries to appropriate word(s) for replacement. +The best guess is displayed to the right of Replace with. +To accept this replacement, click on Replace. + +&sonnet; also allows you to select a word from the list of suggestions and +replace the misspelled word with that selected word. With the help of the +Suggest button, you can add more suggestions from the +dictionary to the suggestions list. + +Click on Ignore to keep your original spelling. + +Click on Finished to stop spellchecking and +keep the changes made. + +Click on Cancel to stop spellchecking and +cancel the changes already made. + +Click on Replace All to automatically replace +the misspelled word(s) with the chosen replacement word, if they appear again in +your document later. + +Click on Ignore All to ignore the spelling at +that point and all the future occurrences of the word misspelled. + +Click on Add to Dictionary to add the misspelled +word to your personal dictionary. + +The Personal Dictionary is a distinct dictionary from the +system dictionary and the additions made by you will not be seen by others. + +The drop down box Language at the bottom of this +dialog allows you to switch to another dictionary temporarily. + + + + +Automatic Spell Checking + + + +In many applications, you can automatically check spelling as you type. +To enable this feature, select Tools +Automatic Spell Checking. + +Potentially misspelled words will be underlined in red. To select a +suggestion, right click on the word, select the Spelling +submenu, and select the suggestion. You may also instruct &sonnet; to ignore +this spelling for this document by selecting Ignore Word, +or you may select Add to Dictionary to save it in your +personal dictionary. + + + + +Configuring &sonnet; + +To change your dictionary, go to Tools +Change Dictionary.... A small window will +appear at the bottom of the current document that will allow you to change your +dictionary. + + +For more information on configuring &sonnet;, see the +Spell Checker &systemsettings; module +documentation + + + + +Thanks and Acknowledgments + +Special thanks to Google Code-In 2011 Participant Salma Sultana for writing +much of this section. + + + + + + + + + +&TC.Hollingsworth; &TC.Hollingsworth.mail; + + + +Find and Replace + + +The Find function of many &kde-sc; applications lets you find specific +text in a document, while the Replace function allows you to replace text that +is found with different text you provide. + +You can find both these functions in the Edit menu of +many &kde; applications. For more information on this menu, see +. + + +The Find Function + +The Find function searches for text in a document and selects it. + + +The Find Window + + +The Find window. +Searching for software in +&kmail;'s composer window. + + + + +To use Find in many applications, go to Edit +Find... or press +&Ctrl;F. Then, in the +Text to find: text box, enter the text that you want to +find. + +If Regular expression is checked you will be able to +search using regular expressions. Click on Edit to select +from and enter commonly used regular expression characters, like +White Space or Start of Line. If +&kate; is installed, you can find +more information on writing +regular expressions in its documentation. + + +You can limit the found results by configuring these options: + + + +Case sensitive +Capital and lowercase characters are considered different. For +example, if you search for This, results that contain +this will not be returned. + + + +Whole words only +By default, when the application searches for text, it will +return results even in the middle of other text. For instance, if you search +for is it will stop on every word that contains that, +like this or +history. If you check this option, the +application will only return results when the search text is a word by itself, +that is, surrounded by whitespace. + + + +From cursor +The search will start from the location of the cursor and stop +at the end of the text. + + + +Find backwards +By default, the application searches for the text starting at +the beginning of the document, and move through it to the end. If you check this +option, it will instead start at the end and work its way to the beginning. + + + + +Selected text +Select this option to search only in the text that is currently +selected, not the entire document. It is disabled when no text is selected. + + + + + +The Find function only selects the first match that it finds. You can +continue searching by selecting EditFind Next +or by pressing F3. + + +Example of a Search + + +Example of a search. +&kmail; displays a match for software. + + + + + +Applications which use the &kde; text editor component show a search bar instead of the Find window. See &kwrite; documentation for additional information on the search bar. + + +The search bar in &kate;. + + +The search bar in &kate;. +Searching for software in &kate;'s search bar. + + + + + + + +The Replace Function + +The Replace function searches for text in a document and replaces it with +other text. You can find it in many application at +EditReplace... +or by pressing &Ctrl;R. + + +The Replace Window + + +The Replace window. +Replacing food with +drink in &kmail; + + + +The window of the Replace function is separated into 3 sections: + + + +Find +Here you may enter the text you wish to search for. See + for more information on the options provided here. + + + + +Replace + +Here you may enter the text you wish to replace the found text with. + +You can reuse the found text in the replacement text by selecting the +Use placeholders checkbox. Placeholders, sometimes known as +backreferences, are a special character sequence that will be replaced with all +or part of the found text. For instance, \0 represents the +entire found string. + You may insert placeholders into the text box by clicking the +Insert Placeholder button, then selecting an option from +the menu like Complete Match. For example, if you are +searching for message, and you want to replace it with +messages insert the Complete Match +placeholder and add an s. The replace field will then +contain \0s. + +If &kate; is installed, you can learn more about placeholders in the +Regular Expressions appendix +of its documentation. + + + + +Options +This contains all the same options that the +Find function does, with one addition: +If the Prompt on replace option is checked a window +will appear on every found word, allowing you to confirm whether you would like +to replace the found text. + + + + + +Applications which use the &kde; text editor component show a search and replace bar instead of the Replace window. See &kwrite; documentation for additional information on the search and replace bar. + + +The search and replace bar. + + +The search and replace bar. +Replacing kmail with +kate in &kate;'s search and replace bar + + + + + + +Thanks and Acknowledgments +Thanks to an anonymous Google Code-In 2011 participant for writing much +of this section. + + + + + + + + +&TC.Hollingsworth; &TC.Hollingsworth.mail; + + + +Choosing Fonts + +The font selector appears in many different &kde; applications. It lets +you select the font face, font style, and font size of the text that appears in +your application. + + +The Font Selector + + +The font selector. +Selecting a font in +&systemsettings;. + + + + + + +Font +This is the leftmost selection box, and lets you choose the +font face from a list of fonts on your system. + + + +Font style + +This is the center selection box, and lets you choose the font style from +the following choices: + + +Italic - this displays text in a cursive, +or slanted fashion, and is commonly used for citations or to emphasize text. + + +Regular - the default. Text is displayed +without any special appearance. + +Bold Italic - a combination of both +Bold and Italic + +Bold - this displays text in a darker, +thicker fashion, and is commonly used for titles of documents or to emphasize +text. + + + + + + +Size +This is the rightmost selection box, and lets you select the +size of your text. Font size is measured in points, a +standard unit of measure in typography. For more information on this, see +the Point +(typography) article on Wikipedia. + + + +Preview +The bottom of the font selector displays a preview of text using +the font settings that are currently selected. You may change this text if you +wish. + + + + + + + + + +&TC.Hollingsworth; &TC.Hollingsworth.mail; + + + +Choosing Colors + +The color chooser appears in many &kde; applications, whenever you need + to select a color. It lets you pick from a palette consisting of many +predefined colors or mix your own when you want a specific color. + + +The Color Selector + + +The color selector. +Selecting a color in +&systemsettings;. + + + + +Using Palettes + +A palette is a set of predefined colors. You can find it on the right +side of the color chooser window. + +To select a color from a palette, simply click on it. The color will be +displayed below the palette, along with its &HTML; hexadecimal code and name, if +any. + +To switch between them, use the drop down box above the color palette. +Most palettes will display a grid consisting of the colors, except for the +Named Colors, which lets you select from a list of names. +Other special palettes include * Recent Colors *, which +will display colors that you have recently selected, and +* Custom Colors *, which will display custom colors that +you have saved. For more information on setting custom colors, see + + + + + +Mixing Colors + +The color chooser also lets you mix your own colors. There are several +ways to do this: + + +Using the Grid + +The left side of the color chooser contains a large box, and a thinner box +immediately to its right. You can use the left box to select the Hue and +Saturation of the desired color based on the visual guide provided in the box. +The right bar adjusts the Value. Adjust these to select the desired color, +which is displayed in the lower-right corner of the window. + +For more information on Hue, Saturation, and Value, see + + + + + +Using the Eyedropper + +The eyedropper tool allows you to select a color from your screen. To use +it, select the eyedropper button to the right of the +Add to Custom Colors button, and then click anywhere on +your screen to select that color. + + + + +Hue/Saturation/Value + +The lower-left corner of the screen allows you to manually enter the +coordinates of the desired color in the Hue/Saturation/Value +(HSV) color space. For more information on this, see +the HSL and +HSV article on Wikipedia. + +These values are also updated when selecting a color by other methods, +so they always accurately represent the currently selected color. + + + + +Red/Green/Blue + +The lower-left corner of the screen also allows you to manually enter the +coordinates of the desired color in the Red/Green/Blue (RGB) +color model. For more information on this, see +the RGB color +model article on Wikipedia. + +These values are also updated when selecting a color by other methods, +so they always accurately represent the currently selected color. + + + + +&HTML; Hexadecimal Code + +You may enter the &HTML; hexadecimal code representing +the color in the lower-right corner of the screen. For more information on this, +see the Web +colors article on Wikipedia. + +This value is also updated when selecting a color by other methods, +so it always accurately represents the currently selected color. + + + + + +Saving Custom Colors + +After selecting a color, you may save it to the Custom Colors palette so +you can find it later. To do so, click the +Add to Custom Colors button. You can then find it by +selecting the * Custom Colors * palette from the drop +down box in the upper-right corner of the screen. For more information on using +palettes, see . + + + + + + diff --git a/doc/fundamentals/toolbars-configure.png b/doc/fundamentals/toolbars-configure.png new file mode 100644 index 00000000..52ff11c1 Binary files /dev/null and b/doc/fundamentals/toolbars-configure.png differ diff --git a/doc/fundamentals/toolbars-toolbar.png b/doc/fundamentals/toolbars-toolbar.png new file mode 100644 index 00000000..a204b1b6 Binary files /dev/null and b/doc/fundamentals/toolbars-toolbar.png differ diff --git a/doc/fundamentals/ui.docbook b/doc/fundamentals/ui.docbook new file mode 100644 index 00000000..6c91d31f --- /dev/null +++ b/doc/fundamentals/ui.docbook @@ -0,0 +1,1983 @@ + + + +Finding Your Way Around + + + + +Claus Christensen +&TC.Hollingsworth; &TC.Hollingsworth.mail; + + + + +A Visual Dictionary + +The &plasma-workspaces; feature many different graphical user interface +elements, commonly known as widgets. This guide will introduce +you to their names and functions. + + +The Big Picture + + +Windows + + +A Window + + + + + + + + + + + + + + + + + + + + + + + +This is the window of the &kwrite;, a text editor. Click on +part of the window to learn more about it. + + + + +The Window Menu + + + +A Button to place this window on all +desktops + + + +The Titlebar + + + +Buttons to minimize, maximize, or +close the window + + + +The Menubar + + + +The Toolbar + + + +A very large +Text Area +that acts as this program's +Central Widget + + + +A vertical Scrollbar +(there is also a horizontal scrollbar below the text box) + + + +The Statusbar + + + + + +Another Window + + + + + + + + + + + + + + + + + + +This is the another window, that of the &dolphin; file manager. Click on +part of the window to learn more about it. + + + + +A panel +that contains a list of Places on the computer system + + + +A Breadcrumb +of the path of the displayed folder + + + +A folder Icon + + + +A file Icon + + + +A highlighted Icon + + + +A Context Menu +listing actions that can be performed on a file + + + +A Slider +that changes the size of the Icons +displayed + + + +More Panels + + + + + + + +&GUI; Elements + + +Some &GUI; Elements + + + + + + + + + + + + + + + + +This screenshot, from the &systemsettings; Country/Region & Language panel, +shows some &GUI; elements. Click on part of the window to learn more about it. + + + + +An Icon List +(the first item is selected) + + + +Some Tabs + + + +An open +Drop Down Box + + + +A Button +that resets the Drop Down Box to +its default value + + + +An item in the Drop Down Box that +has been selected + + + + +Some more Buttons + + + + + +Some More &GUI; Elements + + + + + + + + + + + + + + + +This screenshot, from the &systemsettings; Custom Shortcuts panel, +shows some more &GUI; elements. + + + + +A Tree View + + + +A Check Box +that has been selected + + + +A pair of Spin Boxes + + + +A Menu Button + + + + + +Even More &GUI; Elements + + + + + + + + + + + + + +This screenshot, from the &systemsettings; Default Applications panel, +shows even more &GUI; elements. Click on part of the window to learn more about +it. + + + + +A List Box + + + +A pair of Radio Buttons + + + +A Text Box + + + + + +Some Combo Boxes + + + + + + + + + + +Finally, this screenshot, from another tab +of the &systemsettings; Country/Region & Language panel, shows five +Combo Boxes + + + + + + + +The Widgets + + + + + + + + +Name +Description +Screenshot + + + + + + + +Central Widget +The main area of the running application. This might be the document +you are editing in a word processor or the board of a game like Chess. + + + + + + + + + + +Button +These can be clicked with the &LMB; to perform an action. + + + + + + + + + + +Breadcrumb +Shows the path in a hierarchical system, such as a filesystem. Click on +any part of the path to go up in the tree to that location. Click on the arrow +to the right of part of the path to go to another child element of that path. + + + + + + + + + + + +Check Box +These can be clicked to select and unselect items. They are typically +used in a list of several selections. Selected items typically display a check +mark, whereas unselected items will have an empty box. + + + + + + + + + + +Color Selector +This allows a color to be selected for various purposes, such as changing +the color of text. For more information, see + + + + + + + + + + +Combo Box +A combination of a +Drop Down Box and a +Text Box. You can select an option +from the list, or type in the text box. Some combo boxes may automatically +complete entries for you, or open the list with a list of choices that match +what you have typed. + + + + + + + + + + +Context Menu +Many user interface elements in the &kde-sc; contain a context menu, +which can be opened by clicking on something with the &RMB;. This menu contains +options and actions that usually affect the user interface element that was +right-clicked. + + + + + + + + + + +Dialog Box +A small window that appears above a larger application window. It may +contain a message, warning, or configuration panel, among others. + + + + + + + + + + +Drop Down Box +This provides a list of items, from which you may select one. + + + + + + + + + + +Icon +A graphical representation of something, such as a file or action. They +typically, but not always, also contain a text description, either beneath or +to the right of the icon. + + + + + + + + + + +Icon List +This provides a list of items represented by an +Icon and a description. It is typically +used in the left panel of configuration panels to allow selection from various +types of configuration categories. + + + + + + + + + + +List Box +This is a list of items that typically allows multiple items to be +selected. To select a group of contiguous items, press the &Shift; key and +click the first and last items. To select multiple items that are not +contiguous, press the &Ctrl; key and select the desired items. + + + + + + + + + + +Menu +A list of selections, that usually perform an action, set an option, or +opens a window. These can be opened from +menubars or +menu buttons. + + + + + + + + + + +Menubar +These are located at the top of nearly every window and provide access +to all the functions of the running application. For more information, see +. + + + + + + + + + + +Menu Button +A special type of button that +opens a menu. + + + + + + + + + + +Panel or Sidebar or Tool View +These are located on the sides or bottom of the +central widget and allow +you to perform many different tasks in an application. A text editor might +provide a list of open documents in one, while a word processor might allow you +to select a clip art image. + + + + + + + + + + +Progress Bar +A small bar that indicates that a long-running operation is being +performed. The bar may indicate how much of the operation has completed, or it +may simply bounce back and forth to indicate that the operation is in progress. + + + + + + + + + + + +Radio Button +These are used in a list of options, and only permit one of the options in +the list to be selected. + + + + + + + + + + +Scrollbar +Allows you to navigate a document. + + + + + + + + + + +Slider +Allows a numeric value to be selected by moving a small bar either +horizontally or vertically across a line. + + + + + + + + + + +Spin Box +This permits a numerical value to be selected, either by using the up and +down arrows to the right of the box to raise or lower the value, respectively, +or by typing the value into the +text box. + + + + + + + + + + +Status Bar +These are located at the bottom of many applications and display +information about what the application is currently doing. For instance, a web +browser might indicate the progress of loading a web page, while a +word processor might display the current word count. + + + + + + + + + + +Tab +These appear at the top of an area of a window, and permit that area of +the window to be changed to a variety of different selections. + + + + + + + + + + +Text Area +Allows a large amount of text to be typed in, typically multiple lines or +paragraphs. Unlike a Text Box, +pressing &Enter; will usually result in a line break. + + + + + + + + + + + +Text Box +A single-line text entry that allows a small amount of text to be typed +in. Typically, pressing &Enter; will perform the same action as clicking the +OK button. + + + + + + + + + + +Titlebar +This is located at the top of every window. It contains the name of the +application and usually information about what the application is doing, like +the title of the web page being viewed in a web browser or the filename of a +document open in a word processor. + + + + + + + + + + +Toolbar +These are located near the top of many applications, typically directly +underneath the menu bar. They +provide access to many common functions of the running application, like +Save or Print. + + + + + + + + + + +Tree View +A Tree View allows you to select from a hierarchical list of options. A +section, or category, of the Tree View may be unexpanded, in which case no +options will appear beneath it and the arrow to the left of the title will be +pointing right, toward the title. It may also be expanded, in which case several +options will be listed below it, and the arrow to the left of the title will be +pointing down, toward the options. To expand a portion of the tree view, click +the arrow to the left of the title of the section you wish to expand, +double-click on the title, or select the title using your keyboard's arrow keys +and press the &Enter; or + key. To minimize a portion of the +tree view, you may also click the arrow, double-click on the title, or press the +&Enter; or - key. + + + + + + + + + + + + + + + + + + + + +&TC.Hollingsworth; &TC.Hollingsworth.mail; + + + + +Common Menus + +Many &kde; applications contain these menus. However, most +applications will have more menu entries than those listed here, and others may +be missing some of the entries listed here. + + +A Menu Bar + + +A menubar +The menubar in +&gwenview;. + + + + +Some applications, like &dolphin;, do not show a menubar by default. You +can show it by pressing &Ctrl;M. You can +also use this to hide the menubar in applications that support doing so. + + +The File Menu +The File menu allows you to perform operations on the +currently open file and access common tasks in applications. + +Common menu items include: + + + + + +&Ctrl;N +FileNew + + +Creates a new file. + + + + + +FileNew Window + + +Opens a new window. + + + + + +&Ctrl;O +FileOpen... + + +Opens an already existing file. + + + + + +&Ctrl;S +FileSave + + +Saves the file. If the file already exists it will be overwritten. + + + + + +FileSave As... + + + Saves the file with a new filename. + + + + + + +FileSave All + + +Saves all open files. + + + + + +F5 +FileReload + + +Reloads the current file. + + + + + +FileReload All + + +Reloads all open files. + + + + + +&Ctrl;P +FilePrint... + + +Prints the file. + + + + + +&Ctrl;W +FileClose + + +Closes the current file. + + + + + +FileClose All + + +Closes all open files. + + + + + +&Ctrl;Q +FileQuit + + +Exits the program. + + + + + + + +The Edit Menu +The Edit menu allows you to modify the currently +open file. + + + + + +&Ctrl;Z +EditUndo + + +Undo the last action you performed in the file. + + + + + +&Ctrl;&Shift;Z +EditRedo + + +Redo the last action you performed in the file. + + + + + +&Ctrl;X +EditCut + + +Removes the currently selected portion of the file, if any, and places a copy of +it in the clipboard buffer. + + + + + +&Ctrl;C +EditCopy + + +Places a copy of the currently selected portion of the file, if any, in the +clipboard buffer. + + + + + +&Ctrl;V +EditPaste + + +Copies the first item in the clipboard buffer to the current location in the +file, if any. + + + + + +&Ctrl;A +EditSelect All + + +Selects the entire contents of the currently open file. + + + + + +&Ctrl;F +EditFind... + + +Allows you to search for text in the currently open file. + + + + + +&Ctrl;R +EditReplace... + + +Allows you to search for text in the currently open file and replace it with +something else. + + + + + +F3 +EditFind Next + + +Go to the next match of the last Find operation. + + + + + +&Shift;F3 +EditFind Previous + + +Go to the previous match of the last Find operation. + + + + + + + +The View Menu +The View menu allows you to change the layout of the +currently open file and/or the running application. + +This menu has different options depending on the application you are +using. + + + +The Tools Menu +The Tools menu allows you to perform certain actions +on the currently open file. + + + + + +&Ctrl;&Shift;O +ToolsAutomatic Spell Checking + + +Check for spelling errors as you type. For more information, see +. + + + + + +ToolsSpelling... + + +This initiates the spellchecking program - a program designed to help the user +catch and correct any spelling errors. For more information, see +. + + + + + +ToolsSpelling (from cursor)... + + +This initiates the spellchecking program, but only checks the portion of the +document from the current location of the cursor to the end. For more information, +see . + + + + + +ToolsSpellcheck Selection... + + +This initiates the spellchecking program, but only checks the currently selected +text in the document. For more information, see . + + + + + +ToolsChange Dictionary... + + +This allows you to change the dictionary used to check spellings. For more +information, see . + + + + + + + + +The Settings Menu +The Settings allows you to customize the application. + +This menu typically contains the following items: + + + + + +&Ctrl;M + +Settings +Show Menubar + +Hides and shows the menubar. + + + + +Settings +Show Statusbar + + + +Toggles the display of the statusbar on and off. Some &kde; applications use statusbar at the bottom of their screen to display useful information. + + + + + + +SettingsToolbars Shown + + +Allows you to show and hide the various toolbars supported by the application. + + + + + +SettingsConfigure Shortcuts... + + +Allows you to enable, disable, and modify keyboard shortcuts. For more +information, see . + + + + + +SettingsConfigure Toolbars... + + +Allows you to customize the contents, layout, text, and icons of toolbars. For +more information, see . + + + + +SettingsConfigure +Notifications... +This item displays a standard &kde; notifications configuration +dialog, where you can change the notifications (sounds, visible messages, +&etc;) used by the application. +For more information how to configure notifications please read the documentation for +the &systemsettings; module Manage Notifications. + + + + + + +SettingsConfigure Application... + + +Opens the configuration panel for the currently running application. + + + + + + + +The Help Menu +The Help menu gives you access to the application's +documentation and other useful resources. + + + + + + + +F1 + +Help +Application Handbook + + +Invokes the KDE Help system starting at the +running application's handbook. + + + + + +&Shift;F1 + +Help +What's This? + + +Changes the mouse cursor to a combination arrow and +question mark. Clicking on items within the application; will open a help +window (if one exists for the particular item) explaining the item's +function. + + + + + +Help +Report Bug... + +Opens the Bug report dialog where you can +report a bug or request a wishlist feature. + + + + +Help +Switch Application Language... + +Opens a dialog where you can +edit the Primary language and Fallback language +for this application. + + + + +Help +About Application + +This will display version and author +information for the running application. + + + + +Help +About KDE + +This displays the &kde; Development Platform version +and other basic information. + + + + + + +Thanks and Acknowledgments + +Special thanks to an anonymous Google Code-In 2011 participant for writing +much of this documentation. + + + + + + + + +&TC.Hollingsworth; &TC.Hollingsworth.mail; + + + + +Common Keyboard Shortcuts + +The &plasma-workspaces; provide keyboard shortcuts that allow you to +perform many tasks without touching your mouse. If you use your keyboard +frequently, using these can save you lots of time. + +This list contains the most common shortcuts supported by the workspace +itself and many applications available within. Every application also provides +its own shortcuts, so be sure to check their manuals for a comprehensive +listing. + + +The Meta key described below is a generic name for +the custom key found on many different keyboards. On keyboards +designed for &Microsoft; &Windows;, this key is usually called the +Windows key, and will have a picture of the &Windows; +logo. On keyboards designed for &Mac; computers, this key is known as +the Command key and will have a picture of the +Apple logo and/or the + symbol. On keyboards designed for &UNIX; systems, this key +is really known as the Meta key and is typically labeled with a +diamond: . + + + +Working with Windows + +These shortcuts allow you to perform all kinds of operations with windows, +whether it be opening, closing, moving, or switching between them. + + +Starting and Stopping Applications + +These shortcuts make it easy to start and stop programs. + + + + + + +Shortcut +Description + + + + + + +&Ctrl;Q +Quit + + + +&Ctrl;Esc +System Activity + + + +&Ctrl;&Alt;&Esc; +Force Quit + + + +&Alt;F2 +Run Command Interface + + + +&Alt;F4 +Close + + + + + + + + +Moving Around + +These shortcuts allow you to navigate between windows, activities, and +desktops efficiently. + + + + + + +Shortcut +Description + + + + + + +&Ctrl;F10 +Present Windows + + + +&Ctrl;F9 +Present Windows on current desktop + + + +&Ctrl;F7 +Present Windows of current application only + + + +&Ctrl;F11 +Desktop Cube + + + +&Ctrl;F12 +Show Dashboard + + + +&Ctrl;&Alt;A +Activate Window Demanding Attention + + + +&Alt; +Walk through windows + + + +&Alt;` +Walk through windows of the current application + + + +&Alt;F3 +Open the Window Operations menu + + + +&Meta;&Alt;Up +Switch to Window Above + + + +&Meta;&Alt;Down +Switch to Window Below + + + +&Meta;&Alt;Left +Switch to Window to the Left + + + +&Meta;&Alt;Right +Switch to Window to the Right + + + + + + + + +Panning and Zooming + +Need to get a closer look? The &plasma-workspaces; allow you to zoom in +and out and move your entire desktop around, so you can zoom in even when the +application you are using doesn't support it. + + + + + + +Shortcut +Description + + + + + + + + +&Meta;= +Zoom In + + + +&Meta;- +Zoom Out + + + +&Meta;0 +Zoom Normal + + + +&Meta;Up +Pan Up + + + +&Meta;Down +Pan Down + + + +&Meta;Left +Pan left + + + +&Meta;Right +Pan Right + + + + + + + + + +Working with Activities and Virtual Desktops + +These shortcuts allow you to switch between and manage +Activities +and virtual desktops. + + + + + + +Shortcut +Description + + + + + + +&Ctrl;Q +View all your Activities + + + +&Meta; +Next Activity + + + +&Meta;&Shift; +Previous Activity + + + + + &Alt;D + R + +Remove this Activity + + + + + &Alt;D + S + +Activities Settings + + + +&Ctrl;F1 +Switch to Desktop 1 + + + +&Ctrl;F2 +Switch to Desktop 2 + + + +&Ctrl;F3 +Switch to Desktop 3 + + + +&Ctrl;F4 +Switch to Desktop 4 + + + + + + + + +Working with the Desktop + +These shortcuts allow you to work with the &plasma-desktop; and panels. + + + + + + + +Shortcut +Description + + + + + + + + &Alt;D + A + +Add Widgets + + + + + &Alt;D + R + +Remove Widgets + + + + + &Alt;D + L + +Lock/Unlock Widgets + + + + + &Alt;D + N + +Next Widget + + + + + &Alt;D + P + +Previous Widget + + + + + &Alt;D + S + +Widget Settings + + + +&Ctrl;F12 +Show Dashboard + + + + + &Alt;D + T + +Run the Associated Application + + + +&Alt;&Shift;F12 +Enable/Disable Desktop Effects + + + + + + + + +Getting Help + +Need some help? The manual for the current application is only a keypress +away, and some programs even have additional help that explains the element in +focus. + + + + + + +Shortcut +Description + + + + + + +F1 +Help + + + +&Shift;F1 +What's This? + + + + + + + + +Working with Documents + +Whether it's a text document, spreadsheet, or web site, these shortcuts +make performing many kinds of tasks with them easy. + + + + + + +Shortcut +Description + + + + + + +F5 +Refresh + + + +&Ctrl;A +Select All + + + +&Ctrl;Z +Undo + + + +&Ctrl;&Shift;Z +Redo + + + +&Ctrl;X +Cut + + + +&Ctrl;C +Copy + + + +&Ctrl;V +Paste + + + +&Ctrl;N +New + + + +&Ctrl;P +Print + + + + +&Ctrl;S +Save + + + + +&Ctrl;F +Find + + + + +&Ctrl;W +Close Document/Tab + + + + + + + + +Working with Files + +Whether your in an Open/Save dialog or the &dolphin; file manager, these +shortcuts save you time when performing operations on files. Note that some of +the concepts used with files are the same as with documents, so several of the +shortcuts are identical to their counterparts listed above. + + + + + + +Shortcut +Description + + + + + + +&Ctrl;Z +Undo + + + +&Ctrl;X +Cut + + + +&Ctrl;C +Copy + + + +&Ctrl;V +Paste + + + +&Ctrl;A +Select All + + + +&Ctrl;L +Replace Location + + + +&Ctrl;&Shift;A +Invert Selection + + + +&Alt;Left +Back + + + +&Alt;Right +Forward + + + +&Alt;Up +Up (to folder that contains this one) + + + +&Alt;Home +Home Folder + + + +Delete +Move to Trash + + + +&Shift;Delete +Delete Permanently + + + + + + + + +Changing Volume and Brightness + +In addition to the standard keys, many computer keyboards and laptops +nowadays have special keys or buttons to change the speaker volume, as well as +the brightness of your monitor if applicable. If present, you can use these +keys in the &plasma-workspaces; to perform those tasks. + +If you do not have such keys, see for +information on how to assign keys for these tasks. + + + + +Leaving Your Computer + +All done? Use these shortcuts and put your computer away! + + + + + + +Shortcut +Description + + + + + + +&Ctrl;&Alt;Insert +Switch User + + + +&Ctrl;&Alt;L +Lock Session + + + +&Ctrl;&Alt;Delete +Logout + + + +&Ctrl;&Alt;&Shift;Delete +Logout without confirmation + + + +&Ctrl;&Alt;&Shift;Page Down +Shut Down without confirmation + + + +&Ctrl;&Alt;&Shift;Page Up +Reboot without confirmation + + + + + + + + +Modifying Shortcuts + +The shortcuts described in Working With +Windows, Leaving Your Computer, and +Changing Volume and Brightness are called +global shortcuts, since they work regardless of which +window you have open on your screen. These can be modified in the +Global Shortcuts panel of +&systemsettings;, where they are separated by &kde; component. + +The shortcuts described in Working with +Activities and Virtual Desktops and Working +with the Desktop can be modified by clicking on the +Desktop Toolbox and +selecting Shortcut Settings. + +The shortcuts described in Working with +Documents and Getting Help are set by +individual programs. Most &kde; programs allow you to use the +common shortcut editing dialog to modify these. +The shortcuts described in Working With Files +can be edited in the same manner when used inside a file manager like &dolphin; +or &konqueror;, but cannot be modified in the case of Open/Save dialogs, &etc; + + + + + + diff --git a/doc/fundamentals/visualdict-breadcrumb.png b/doc/fundamentals/visualdict-breadcrumb.png new file mode 100644 index 00000000..e2a8db5b Binary files /dev/null and b/doc/fundamentals/visualdict-breadcrumb.png differ diff --git a/doc/fundamentals/visualdict-button.png b/doc/fundamentals/visualdict-button.png new file mode 100644 index 00000000..845c4940 Binary files /dev/null and b/doc/fundamentals/visualdict-button.png differ diff --git a/doc/fundamentals/visualdict-central-widget.png b/doc/fundamentals/visualdict-central-widget.png new file mode 100644 index 00000000..b8305a7c Binary files /dev/null and b/doc/fundamentals/visualdict-central-widget.png differ diff --git a/doc/fundamentals/visualdict-check-box.png b/doc/fundamentals/visualdict-check-box.png new file mode 100644 index 00000000..32046468 Binary files /dev/null and b/doc/fundamentals/visualdict-check-box.png differ diff --git a/doc/fundamentals/visualdict-color-selector.png b/doc/fundamentals/visualdict-color-selector.png new file mode 100644 index 00000000..7d19b369 Binary files /dev/null and b/doc/fundamentals/visualdict-color-selector.png differ diff --git a/doc/fundamentals/visualdict-combo-box.png b/doc/fundamentals/visualdict-combo-box.png new file mode 100644 index 00000000..2b4c3d76 Binary files /dev/null and b/doc/fundamentals/visualdict-combo-box.png differ diff --git a/doc/fundamentals/visualdict-context-menu.png b/doc/fundamentals/visualdict-context-menu.png new file mode 100644 index 00000000..0bbac64e Binary files /dev/null and b/doc/fundamentals/visualdict-context-menu.png differ diff --git a/doc/fundamentals/visualdict-dialog-box.png b/doc/fundamentals/visualdict-dialog-box.png new file mode 100644 index 00000000..87ef8beb Binary files /dev/null and b/doc/fundamentals/visualdict-dialog-box.png differ diff --git a/doc/fundamentals/visualdict-drop-down-box.png b/doc/fundamentals/visualdict-drop-down-box.png new file mode 100644 index 00000000..42bb4319 Binary files /dev/null and b/doc/fundamentals/visualdict-drop-down-box.png differ diff --git a/doc/fundamentals/visualdict-gui1.png b/doc/fundamentals/visualdict-gui1.png new file mode 100644 index 00000000..17b2a7a1 Binary files /dev/null and b/doc/fundamentals/visualdict-gui1.png differ diff --git a/doc/fundamentals/visualdict-gui2.png b/doc/fundamentals/visualdict-gui2.png new file mode 100644 index 00000000..5c2df0af Binary files /dev/null and b/doc/fundamentals/visualdict-gui2.png differ diff --git a/doc/fundamentals/visualdict-gui3.png b/doc/fundamentals/visualdict-gui3.png new file mode 100644 index 00000000..c8aafcef Binary files /dev/null and b/doc/fundamentals/visualdict-gui3.png differ diff --git a/doc/fundamentals/visualdict-gui4.png b/doc/fundamentals/visualdict-gui4.png new file mode 100644 index 00000000..9e763a42 Binary files /dev/null and b/doc/fundamentals/visualdict-gui4.png differ diff --git a/doc/fundamentals/visualdict-icon-list.png b/doc/fundamentals/visualdict-icon-list.png new file mode 100644 index 00000000..89f40cad Binary files /dev/null and b/doc/fundamentals/visualdict-icon-list.png differ diff --git a/doc/fundamentals/visualdict-icon.png b/doc/fundamentals/visualdict-icon.png new file mode 100644 index 00000000..be294b73 Binary files /dev/null and b/doc/fundamentals/visualdict-icon.png differ diff --git a/doc/fundamentals/visualdict-list-box.png b/doc/fundamentals/visualdict-list-box.png new file mode 100644 index 00000000..4a7e9cbc Binary files /dev/null and b/doc/fundamentals/visualdict-list-box.png differ diff --git a/doc/fundamentals/visualdict-menu-button.png b/doc/fundamentals/visualdict-menu-button.png new file mode 100644 index 00000000..51d3f3e5 Binary files /dev/null and b/doc/fundamentals/visualdict-menu-button.png differ diff --git a/doc/fundamentals/visualdict-menu.png b/doc/fundamentals/visualdict-menu.png new file mode 100644 index 00000000..7e235946 Binary files /dev/null and b/doc/fundamentals/visualdict-menu.png differ diff --git a/doc/fundamentals/visualdict-menubar.png b/doc/fundamentals/visualdict-menubar.png new file mode 100644 index 00000000..768dfd69 Binary files /dev/null and b/doc/fundamentals/visualdict-menubar.png differ diff --git a/doc/fundamentals/visualdict-panel.png b/doc/fundamentals/visualdict-panel.png new file mode 100644 index 00000000..a7093bc7 Binary files /dev/null and b/doc/fundamentals/visualdict-panel.png differ diff --git a/doc/fundamentals/visualdict-progress-bar.png b/doc/fundamentals/visualdict-progress-bar.png new file mode 100644 index 00000000..627ce6f5 Binary files /dev/null and b/doc/fundamentals/visualdict-progress-bar.png differ diff --git a/doc/fundamentals/visualdict-radio-button.png b/doc/fundamentals/visualdict-radio-button.png new file mode 100644 index 00000000..e350ff43 Binary files /dev/null and b/doc/fundamentals/visualdict-radio-button.png differ diff --git a/doc/fundamentals/visualdict-scrollbar.png b/doc/fundamentals/visualdict-scrollbar.png new file mode 100644 index 00000000..f5762983 Binary files /dev/null and b/doc/fundamentals/visualdict-scrollbar.png differ diff --git a/doc/fundamentals/visualdict-slider.png b/doc/fundamentals/visualdict-slider.png new file mode 100644 index 00000000..27a61159 Binary files /dev/null and b/doc/fundamentals/visualdict-slider.png differ diff --git a/doc/fundamentals/visualdict-spin-box.png b/doc/fundamentals/visualdict-spin-box.png new file mode 100644 index 00000000..ed1fe812 Binary files /dev/null and b/doc/fundamentals/visualdict-spin-box.png differ diff --git a/doc/fundamentals/visualdict-statusbar.png b/doc/fundamentals/visualdict-statusbar.png new file mode 100644 index 00000000..247dceb9 Binary files /dev/null and b/doc/fundamentals/visualdict-statusbar.png differ diff --git a/doc/fundamentals/visualdict-tab.png b/doc/fundamentals/visualdict-tab.png new file mode 100644 index 00000000..cf269029 Binary files /dev/null and b/doc/fundamentals/visualdict-tab.png differ diff --git a/doc/fundamentals/visualdict-text-area.png b/doc/fundamentals/visualdict-text-area.png new file mode 100644 index 00000000..29b66a95 Binary files /dev/null and b/doc/fundamentals/visualdict-text-area.png differ diff --git a/doc/fundamentals/visualdict-text-box.png b/doc/fundamentals/visualdict-text-box.png new file mode 100644 index 00000000..3b2ce3cc Binary files /dev/null and b/doc/fundamentals/visualdict-text-box.png differ diff --git a/doc/fundamentals/visualdict-titlebar.png b/doc/fundamentals/visualdict-titlebar.png new file mode 100644 index 00000000..46a1dc1f Binary files /dev/null and b/doc/fundamentals/visualdict-titlebar.png differ diff --git a/doc/fundamentals/visualdict-toolbar.png b/doc/fundamentals/visualdict-toolbar.png new file mode 100644 index 00000000..319332ce Binary files /dev/null and b/doc/fundamentals/visualdict-toolbar.png differ diff --git a/doc/fundamentals/visualdict-tree-view.png b/doc/fundamentals/visualdict-tree-view.png new file mode 100644 index 00000000..4c8722e7 Binary files /dev/null and b/doc/fundamentals/visualdict-tree-view.png differ diff --git a/doc/fundamentals/visualdict-window.png b/doc/fundamentals/visualdict-window.png new file mode 100644 index 00000000..e618521b Binary files /dev/null and b/doc/fundamentals/visualdict-window.png differ diff --git a/doc/fundamentals/visualdict-window2.png b/doc/fundamentals/visualdict-window2.png new file mode 100644 index 00000000..1afa2376 Binary files /dev/null and b/doc/fundamentals/visualdict-window2.png differ diff --git a/doc/glossary/CMakeLists.txt b/doc/glossary/CMakeLists.txt new file mode 100644 index 00000000..18cd3d05 --- /dev/null +++ b/doc/glossary/CMakeLists.txt @@ -0,0 +1,2 @@ +########### install files ############### +kde4_create_handbook(index.docbook INSTALL_DESTINATION ${HTML_INSTALL_DIR}/en SUBDIR khelpcenter/glossary) diff --git a/doc/glossary/checkxrefs b/doc/glossary/checkxrefs new file mode 100755 index 00000000..0805ec6b --- /dev/null +++ b/doc/glossary/checkxrefs @@ -0,0 +1,10 @@ +#!/bin/sh +DEFINED_ENTRIES=`sed -ne "s^.*.*^\1^p" *.docbook` +REFERENCED_ENTRIES=`sed -ne "s^.*.*^\1^p" *.docbook | uniq` + +# Check for entries which are referenced but not defined. +for ENTRY in $REFERENCED_ENTRIES; do + if ! echo $DEFINED_ENTRIES | grep $ENTRY - > /dev/null 2>&1; then + echo "'$ENTRY' referenced but not defined!" + fi +done diff --git a/doc/glossary/index.docbook b/doc/glossary/index.docbook new file mode 100644 index 00000000..5f31f04a --- /dev/null +++ b/doc/glossary/index.docbook @@ -0,0 +1,611 @@ + + + + + + + + + + + + +]> + + + + + + Technologies + + Akonadi + The data storage access mechanism for all PIM (Personal Information Manager) data in &kde; SC 4. One single + storage and retrieval system allows efficiency and extensibility not possible under &kde; 3, where each PIM component had + its own system. Note that use of Akonadi does not change data storage formats (vcard, iCalendar, mbox, maildir etc.) - it + just provides a new way of accessing and updating the data.&newpara; + The main reasons for design and development of Akonadi are of technical nature, ⪚ having a unique way to access PIM-data (contacts, calendars, emails..) from different applications (⪚ &kmail;, &kword; &etc;), thus eliminating the need to write similar code here and there.&newpara; + Another goal is to de-couple GUI applications like &kmail; from the direct access to external resources like mail-servers - which was a major reason for bug-reports/wishes with regard to performance/responsiveness in the past.&newpara; + More info:&newpara; + &linkstart;"http://pim.kde.org/akonadi/"&linkmid;Akonadi for KDE's PIM&linkend;&newpara; + &linkstart;"http://en.wikipedia.org/wiki/Akonadi"&linkmid;Wikipedia: Akonadi&linkend;&newpara; + &linkstart;"http://techbase.kde.org/Projects/PIM/Akonadi"&linkmid;Techbase - Akonadi&linkend; + &GUI; + &kde; + + + + ARts + The sound framework in &kde; 2 and 3. Its single-tasking nature caused problems when two sources of sound were encountered. In the &plasma; desktop it is replaced by Phonon.&newpara; + More info:&newpara; + &linkstart;"http://en.wikipedia.org/wiki/ARts"&linkmid; Wikipedia: ARts&linkend;&newpara; + &linkstart;"http://www.arts-project.org"&linkmid;ARts home page&linkend; + &kde; + Phonon + &plasma; + + + + D-Bus + D-Bus or Desktop Bus is an inter-service messaging system. Developed by &RedHat;, it was heavily influenced by &kde; 3 DCOP, which it supersedes. Most POSIX operating systems support D-Bus, and a port for Windows exists. It is used by Qt 4 and GNOME.&newpara; + More info:&newpara; + &linkstart;"http://freedesktop.org/wiki/Software/dbus/"&linkmid;FreeDesktop.org: What is D-Bus?&linkend;&newpara; + &linkstart;"http://en.wikipedia.org/wiki/D-Bus"&linkmid;Wikipedia: D-Bus&linkend; + &DCOP; + GNOME + &kde; + &Qt; + + + + DCOP + DCOP, which stands for Desktop COmmunication Protocol, is a light-weight interprocess and software componentry communication system used in &kde; 3. Replaced with &DBus; in &kde; SC 4.&newpara; + More info:&newpara; + &linkstart;"http://en.wikipedia.org/wiki/DCOP"&linkmid;Wikipedia: DCOP&linkend; + D-Bus + &kde; + + + + Flake + Flake is a programming library to be used in &koffice;/Calligra. Functionally, it provides Shapes to display content and Tools to manipulate content. Shapes can be zoomed or rotated and can be grouped to work as a single Shape, around which text flow is possible.&newpara; + More info:&newpara; + &linkstart;"http://community.kde.org/Calligra/Libs/Flake"&linkmid;&kde; Community Wiki: Flake&linkend; + &kde; + KParts + + + + Get Hot New Stuff + &emstart;G&emend;et &emstart;H&emend;ot &emstart;N&emend;ew &emstart;S&emend;tuff (GHNS) is an open standard that makes it easy for users to download and install various extensions for their applications. Our implementation of GHNS is used by &plasma; (for example to get new desktop themes), and by many applications and widgets.&newpara; + More info:&newpara; + &linkstart;"http://ghns.freedesktop.org"&linkmid;Home of GHNS&linkend;&newpara; + &linkstart;"http://lwn.net/Articles/227855/"&linkmid;An article on GHNS in &kde; SC 4&linkend; + &kde; + &plasma; + + + + GHNS + GHNS is the acronym of Get Hot New Stuff. + Get Hot New Stuff + + + + IO Slave + IO Slaves enable &kde; applications to + access remote resources as easily as local resources (making them + "network transparent"). Remote resources (⪚ files) might + be stored on SMB shares or similar. + SMB + &kde; + + + + KHTML + KHTML is the &HTML; rendering engine for the &kde; &plasma; desktop, as used by the &konqueror; browser. It also provides a KPart that enables all &kde; applications to display web content. A new introduction, &Qt; WebKit is also for Plasma and other application development. + &kde; + &konqueror; + KParts + &plasma; + WebKit + + + + KIO + The &kde; Input/Output system which makes use of so-called + "IO Slaves". + IO +Slave + &kde; + + + + Kiosk + Kiosk is a framework for restricting user capabilities on a &kde; platform system, ideal for use in locked-down environments such as Internet cafés. It is present in &kde; 3 and &kde; 4, but the administration tool, Kiosktool is &kde; 3 only. It can be used to configure &kde; 4 applications, or kiosk configurations can be maintained by editing config files manually. + &kde; + + + + KParts + KParts is an embedding technology which allows &kde; + applications to embed other &kde; applications. For example, the text + view used by &konqueror; is a KPart. + &konqueror; + + + + KSycoca + KSycoca (&kde; &emstart;Sy&emend;stem + &emstart;Co&emend;nfiguration &emstart;Ca&emend;che) is a + configuration cache which, for example, guarantees fast access to the menu + entries. + KBuildSycoca + + + + Phonon + A cross-platform multimedia API, interfacing with existing frameworks, such as gstreamer and xine engines. &kde; 2 and 3 depended on aRts for sound. Phonon replaces it.&newpara; + More info:&newpara; + &linkstart;"http://en.wikipedia.org/wiki/Phonon_(KDE)"&linkmid; Wikipedia: Phonon (KDE)&linkend;&newpara; + &linkstart;"http://phonon.kde.org"&linkmid;Phonon website&linkend; + &arts; + &kde; + + + + Solid + Solid provides a single API for hardware management. Hardware is grouped into 'domains'. Since the backends for Solid are pluggable, Solid helps application developers write less code, and have it platform independent.&newpara; + More info:&newpara; + &linkstart;"http://solid.kde.org"&linkmid;Discover Solid&linkend; + &kde; + + + + Threadweaver + This thread programming library spreads work among multiple-core processors where available, prioritizing them before queuing them for execution. ThreadWeaver provides a high-level job interface for multithreaded programming.&newpara; + More info:&newpara; + &linkstart;"http://www.englishbreakfastnetwork.org/apidocs/apidox-kde-4.0/kdelibs-apidocs/threadweaver/html/Why.html"&linkmid;Why Multithreading?&linkend; + &kde; + + + + WebKit + HTML rendering engine, originating from a fork of KHTML. Adopted by Apple and developed for Safari. Webkit brings the whole functionality back to &kde; SC 4, where it is available through &Qt;.&newpara; + More info:&newpara; + &linkstart;"http://webkit.org/"&linkmid;WebKit home page&linkend;&newpara; + &linkstart;"http://en.wikipedia.org/wiki/Webkit"&linkmid;Wikipedia: WebKit&linkend; + &kde; + KHTML + + + + + + X.Org + + Antialiasing + If mentioned in context with &kde;, anti-aliasing often means + the smoothing of the fonts visible on the screen. &Qt; version 3.3 + or higher used together with X.Org server makes this possible under &kde; + as well. + &kde; + &Qt; + + + + &X-Server; + The &X-Server; represents a basic layer upon which the + various &GUI;s like &kde; are built. It manages the + basic mouse and keyboard input (from the local host as well as from + remote hosts) and provides elementary graphic routines to draw + rectangles and other primitives. + &kde; + &GUI; + + + + + + Applications + + Dolphin + The default file manager in &kde; SC 4. It has a side panel (Places), but navigation is mainly by the 'breadcrumb' trail above the main window. Split windows are possible, and views can be applied to individual windows. Mounting and unmounting USB devices can be done in the side panel. Other directories can be added to the Places panel. A Tree view is also possible.&newpara; + More info:&newpara; + &linkstart;"http://en.wikipedia.org/wiki/Dolphin_(software)"&linkmid;Wikipedia: Dolphin&linkend;&newpara; + &linkstart;"http://introducingkde4.blogspot.com/2007/12/dolphin.html"&linkmid;Introducing KDE 4 Blog - Dolphin&linkend;&newpara; + &linkstart;"http://userbase.kde.org/Tutorials/File_Management"&linkmid;Userbase: File Management Tutorial&linkend; + &kde; + &konqueror; + + + + KBuildSycoca + KBuildSycoca4 is a command line + program and regenerates the + so-called KSycoca. This is useful, for example, if some + or all modules in + &systemsettings; are missing. + KSycoca + &systemsettings; + + + + KInfoCenter + Kinfocenter originated as part of Kcontrol standing alone from KDE 3.1. In KDE SC 4 it is replaced by modules configured in System Settings, notably Solid, and is being reintroduced as an application in &kde; SC 4.5.&newpara; + More info:&newpara; + &linkstart;"http://en.wikipedia.org/wiki/Kinfocenter"&linkmid;Wikipedia: KInfoCenter&linkend; + &kde; + Solid + &systemsettings; + + + + &konqueror; + &konqueror; is a web browser, picture viewer, file manager + and more, and a core part of the &kde; project. You can + find more information about &konqueror; at &linkstart;"http://www.konqueror.org"&linkmid;www.konqueror.org&linkend;. + &kde; + + + + KRunner + The mini-command-line that is accessed from the Classic menu, the keyboard shortcut &Alt;+F2, or a right-click on the desktop. In &kde; SC 4 a partial name will display all possible matches.&newpara; + More info:&newpara; + &linkstart;"http://userbase.kde.org/Tutorials/Krunner"&linkmid;UserBase: KRunner Usage&linkend; + &kde; + &plasma; + + + + KWin + KWin is the window manager. This is where window decorations can be changed and themes applied. &kde; SC 4 extends KWin to provide support for 3D Compositing effects on the desktop.&newpara; + More info:&newpara; + &linkstart;"http://userbase.kde.org/KWin"&linkmid;UserBase: KWin&linkend; + &kde; + &X-Server; + + + + Mini-CLI + Mini &emstart;C&emend;ommand &emstart;L&emend;ine &emstart;I&emend;nterface. Synonym to KRunner. + KRunner + + + + Pager + A pager is a small program or panel applet which shows the position of windows on your desktop and usually if you have several Virtual Desktops gives an overview over all. + &kde; + Kickoff + Kicker + Panel + &plasma; + Virtual Desktops + + + + &systemsettings; + This is the project and filename of the &kde; control + center. &systemsettings; allows you to customize virtually + every configuration option of &kde;. + &kde; + KInfoCenter + + + + + + Desktop Terminology + + Activities + Activities are sets of &plasma; widgets that have their own wallpaper&newpara; + A bit like Virtual Desktops, but not quite. For example you have a "work activity" with commit rss feeds, a note with your TODO, a Folder View with your work related files, and a subtle wallpaper.&newpara; + Next to it, you have your freetime activity, with previews of family photos and dogs, rss feeds from your favorite blogs, a Folder View showing your movie collection, a twitter applet and of course that Iron Maiden wallpaper you have been loving since the early 80s.&newpara; + At 17:00 hours sharp you switch from the work activity to your freetime activity.&newpara; + More info:&newpara; + &linkstart;"http://userbase.kde.org/Plasma"&linkmid;Plasma FAQ&linkend; + &kde; + Virtual Desktops + + + + Containment + A Containment is a top level grouping of widgets. Each Containment manages the layout and configuration data of its set of widgets independently from other Containments.&newpara; + The end result is that you can group widgets within a Containment according to the significance to your working pattern, rather than by directory grouping.&newpara; + More info:&newpara; + &linkstart;"http://userbase.kde.org/Plasma"&linkmid;Plasma FAQ&linkend; + &kde; + Widget + + + + Drag and Drop + This concept tries to replace many actions like copying + files from one place to another by a certain mouse movement, ⪚ + clicking on an icon in a &konqueror; window, moving the mouse to another + window while keeping the mouse button pressed, and releasing the mouse + button ("dropping" the object) copies files. + &konqueror; + + + + Extender + Extenders are a special kind of popup that can grow out of a &plasma; panel for example. Extenders have detachable parts. Extenders are a new concept that arrived in &plasma; for &kde; 4.2. The Kuiserver (the interface that collects all long running jobs and puts them into one window) will make use of extenders so you can detach various jobs and monitor their progress separately.&newpara; + More info:&newpara; + &linkstart;"http://userbase.kde.org/Plasma"&linkmid;Plasma FAQ&linkend; + &kde; + &plasma; + + + + GNOME + + &emstart;G&emend;NU &emstart;N&emend;etwork &emstart;O&emend;bject + &emstart;M&emend;odel &emstart;E&emend;nvironment, one of the + leading &UNIX; &GUI;s. + &GUI; + + + + &GUI; + Abbreviation for &emstart;G&emend;raphical + &emstart;U&emend;ser &emstart;I&emend;nterface. Every desktop + environment (like &kde;) is a &GUI;. Most + &GUI;s feature mouse support and/or windows to manage + the programs. + &kde; + + + + Home Directory + That's the place in system, where all your files are kept. You can write your files outside of this folder, but all applications are configured to propose this folder as place to write your files to. And this is easier, when you are keeping your things here.&newpara; + More info:&newpara; + &linkstart;"http://en.wikipedia.org/wiki/Home_directory"&linkmid;Wikipedia: Home Directory&linkend; + &dolphin; + + + + &kde; + Abbreviation for "K Desktop Environment", a + leading &GUI; for &UNIX;-based systems. You can find more + detailed information at &linkstart; + "http://www.kde.org"&linkmid;www.kde.org&linkend;.&newpara; + &kde; is more than just software. It is a community made up of programmers, translators, contributors, artists, writers, distributors, and users from all over the world. Our international technology team is committed to creating the best free software for the desktop. And not only contributors, but users and fans of &kde; software can be found throughout the entire globe, giving help to other users, spreading the news, or just simply enjoying the experience. + &GUI; + + + + &kicker; + + In &kde; 3, the relocatable bar, usually at the bottom of the screen (sometimes called the Panel), on which application launchers, the Pager, and buttons for running applications reside. + Panel + &plasma; + + + + &kickoff; + + In &kde; SC 4 (and some late versions of &kde; 3), a launch menu in which apps are sorted by functional group. 'Favorites' replaces the 'Most used applications' in Classic Menu, and applications can be added to it. Right-click also offers the possibility of adding applications to the desktop or panel. Rapid access to a less-used application can be by the search box. Other menus are being worked on, since &kde; SC 4 can be used with more than one launcher, should that be required.&newpara; + More info:&newpara; + &linkstart;"http://home.kde.org/~binner/kickoff/sneak_preview.html"&linkmid;Kickoff Sneak Preview&linkend; + &kde; + Pager + Panel + &plasma; + + + + Oxygen + + Oxygen is the default theme of &kde; SC 4. Designed to bring 'a breath of fresh air' to the desktop by removing the simplistic, cartoonish icons, and replacing them with a clean theme and photo-realistic icons. Oxygen uses a desaturated palette to avoid the icons becoming a distraction and uses detailed scalable graphics (SVG).&newpara; + More info:&newpara; + &linkstart;"http://en.wikipedia.org/wiki/Oxygen_Project"&linkmid;Wikipedia: Oxygen Project&linkend;&newpara; + &linkstart;"http://www.oxygen-icons.org/?cat=3"&linkmid;Oxygen Icons&linkend; + &kde; + KSVG + &plasma; + + + + Panel + Refers to the panel which often resides at the bottom of the + screen. + &kde; + &kicker; + &kickoff; + &plasma; + + + + Plasma + In &kde; SC 4 the &plasma; Desktop replaces KDesktop, &kicker; and the SuperKaramba widget engine. The applets are called Plasmoids, and range from informational widgets to mini-apps such as a calculator or dictionary. Widgets from other sources, such as SuperKaramba widgets or Google Gadgets are also supported.&newpara; + More info:&newpara; + &linkstart;"http://en.wikipedia.org/wiki/Plasma_(KDE)"&linkmid;Wikipedia: Plasma&linkend;&newpara; + &linkstart;"http://plasma.kde.org/cms/1107/"&linkmid;Plasma website&linkend;&newpara; + &linkstart;"http://userbase.kde.org/Plasma"&linkmid;Plasma FAQ&linkend;&newpara; + &linkstart;"http://userbase.kde.org/Tutorials/TweakingPlasma"&linkmid;Tweaking Plasma&linkend; + &kde; + &kicker; + Widget + + + + Ripping + The process of reading audio data from a &cdrom; and + storing it on the hard disk. + + + + Virtual Desktops + A popular concept of &UNIX; based window managers is the one of virtual desktops. This means you have not only one screen where you can place your windows on but several. When you switch to a different desktop (usually with a pager) you will only see the windows which you started on your new desktop or moved to it. A window can also be made "sticky" which means it appears on all virtual desktops.&newpara; + More info:&newpara; + &linkstart;"http://userbase.kde.org/Plasma"&linkmid;Plasma FAQ&linkend; + &kde; + &kickoff; + Pager + + + + + + &kde; Development + + &Qt; + The &GUI; of &kde; is built on top of + the &Qt; toolkit, which provides many graphical elements (so-called + "Widgets") which are used to construct the desktop. You + can find more information about &Qt; at &linkstart; + "http://qt-project.org/"&linkmid;http://qt-project.org/&linkend;. + &kde; + &GUI; + Widget + + + + Git + Git is a free and open source, distributed version control system designed to handle everything from small to very large projects with speed and efficiency.&newpara; + Every Git clone is a full-fledged repository with complete history and full revision tracking capabilities, not dependent on network access or a central server. Branching and merging are fast and easy to do.&newpara; + Git is used for version control of files, much like tools such as Mercurial, Bazaar, Subversion, CVS, Perforce, and Visual SourceSafe.&newpara; + It was decided that Git will be the main version control system of &kde;, replacement of SVN. It has been already used for some &kde; projects like Konversation and Amarok.&newpara; + More info:&newpara; + &linkstart;"http://git-scm.com/"&linkmid;Git Homepage&linkend; + &kde; + SVN + + + + i18n + Abbreviation for "internationalization". &kde; + supports many different languages, and several i18n techniques make it + easy to translate the &GUI; as well as the accompanying + documents of &kde; into all these languages. More information about the + i18n process is available at &linkstart; + "http://l10n.kde.org"&linkmid;l10n.kde.org&linkend;. + &kde; + &GUI; + + + + Kross + Kross is a scripting framework, enabling support for multiple scripting languages. A plugin system allows for the support of further languages in the future. + &kde; + + + + KDOM + A KPart module making KHTML DOM (&emstart;D&emend;ocument &emstart;O&emend;bject &emstart;M&emend;odel) rendering capabilities available to all applications. KSVG2 is built on KDOM for &kde; SC 4. + &kde; + KHTML + KParts + KSVG + + + + KJS + &kde; platform's JavaScript engine. + &kde; + KParts + &plasma; + + + + KSVG + KSVG enables support for scalable vector graphics in a KHTML browser. KSVG2 extends this for &kde; SC 4. + &kde; + KHTML + KParts + + + + l10n + Abbreviation for "localization", the process + of adapting a program to the local environment. This includes ⪚ the + currency used for monetary values or the time format. + i18n + + + + Strigi + A deep-indexed search daemon, Strigi aims to be fast and light-weight. It also uses SHA-1 hash which will help in the identification of duplicate files.&newpara; + More info:&newpara; + &linkstart;"http://en.wikipedia.org/wiki/Strigi"&linkmid;Wikipedia: Strigi&linkend; + &kde; + + + + Widget + Graphical elements like scrollbars, buttons or input + fields which are used by &kde; to construct the &GUI;. + + &kde; + &GUI; + + + + SVN + Abbreviation for &emstart;Subversion&emend;, a version control system. The SVN is a very elegant way of managing file versions that allow more than one developer to easily work on the same project. You can find a description of how to get the latest (developer) version of the &kde; sources via anonymous SVN on &linkstart;"http://developer.kde.org/source/anonsvn.html"&linkmid;http://developer.kde.org/source/anonsvn.html&linkend;.&newpara; More about SVN is available at &linkstart;"http://subversion.tigris.org/"&linkmid;http://subversion.tigris.org/&linkend;. + Git + + + + XMLGUI + A programmers' framework for designing the user interface. It is extensively used by KParts.&newpara; + More info:&newpara; + &linkstart;"http://en.wikipedia.org/wiki/XMLGUI"&linkmid;Wikipedia: XMLGUI&linkend;&newpara; + &linkstart;"http://en.wikipedia.org/wiki/Qt_Style_Sheets"&linkmid;Wikipedia: Qt Style Sheets&linkend; + &GUI; + Kparts + &Qt; + + + + + + Miscellaneous + + RFC + &emstart;R&emend;equest &emstart;F&emend;or + &emstart;C&emend;omment. A common way to publish new protocol + ideas or procedures for evaluation of the Internet community. Though + RFCs are not mandatory, many applications try to + adhere to them, once they have been approved by the community.&newpara; + More information about RFCs can be found at the + &linkstart;"http://www.rfc-editor.org"&linkmid;RFC Homepage&linkend;. + + + + + + Various protocols + + SMB + &emstart;S&emend;erver &emstart;M&emend;essage + &emstart;B&emend;lock. A network protocol used in &Microsoft; &Windows; + networks to access the file systems of other computers. + IO Slave + + + + IRC + &emstart;I&emend;nternet &emstart;R&emend;elay + &emstart;C&emend;hat. A protocol defined in RFC + 1459, which handles the specification to enable real-time text chat. + RFC + + + + Host + This can either be a name from your + /etc/hosts file + (mycomputer), + an Internet name (www.kde.org) or an IP-Address + (192.168.0.10). + + + + + + &glossary-kdeprinting; + diff --git a/doc/glossary/kdeprintingglossary.docbook b/doc/glossary/kdeprintingglossary.docbook new file mode 100644 index 00000000..fffc420b --- /dev/null +++ b/doc/glossary/kdeprintingglossary.docbook @@ -0,0 +1,941 @@ + + + + Printing + + + + ACLs + Abbreviation for &emstart;A&emend;ccess + &emstart;C&emend;ontrol &emstart;L&emend;ists; + ACLs are used to check for the access by a given + (authenticated) user. A first rough support for ACLs + for printing is available from &CUPS;; this will be refined + in future versions. + Authentication + + + + + AppSocket Protocol + AppSocket is a protocol for the transfer of + print data, also frequently called "Direct TCP/IP Printing". + &Hewlett-Packard; have taken AppSocket, added a few minor + extensions around it and been very successful in renaming + and marketing it under the brand "&HP; JetDirect"... + &HP; JetDirect Protocol + Direct TCP/IP Printing + + + + + APSfilter + APSfilter is used mainly in the context of "classical" + &UNIX; printing (BSD-style LPD). It is a sophisticated shell script, + disguised as an "all-in-one" filtering program. In reality, + APSfilter calls "real filters" to do the jobs needed. It sends + printjobs automatically through these other filters, based on an + initial file-type analysis of the printfile. + It is written and maintained by Andreas Klemm.&newpara; + It is + similar to Magicfilter and mostly uses Ghostscript for file conversions. + Some Linux Distributions (like &SuSE;) use APSfilter, others + Magicfilter (like &RedHat;), some have both for preference selection + (like *BSD).&newpara; + &CUPS; has &emstart;no&emend; need for APSfilter, + as it runs its own file type recognition (based on &MIME; types) + and applies its own filtering logic. + Ghostscript + Magicfilter + &MIME;-Types + printcap + + + + + Authentication + Proving the identity of a certain person (maybe via username/password + or by means of a certificate) is often called authentication. Once you are + authenticated, you may or may not get access to a requested resource, + possibly based on ACLs. + ACLs + + + + + Bi-directional communication + In the context of printing, a server or a host may receive additional + information sent back from the printer (status messages &etc;), either + upon a query or unrequested. AppSocket ( = &HP; JetDirect), &CUPS; and IPP + support bi-directional communication, LPR/LPD and BSD-style printing + do not... + AppSocket Protocol + &CUPS; + Direct TCP/IP Printing + &HP; JetDirect + IPP + LPR/LPD + + + + + BSD-style Printing + Generic term for different variants of the traditional &UNIX; + printing method. Its first version appeared in the early 70s on + BSD &UNIX; and was formally described in &linkstart;"http://www.rfc.net/rfc1179.html"&linkmid;RFC 1179&linkend; only as late + as 1990.&newpara; + At the time when BSD "remote" printing was first designed, printers + were serially or otherwise directly connected devices to a host + (with the Internet hardly consisting of more than 100 nodes!); printers + used hole-punched, continuous paper, fed through by a tractor + mechanism, with simple rows of ASCII text mechanically hammered on to + the medium, drawn from a cardboard box beneath the table. It came out + like a zig-zag folded paper "snake". Remote printing consisted of a + neighboring host in the next room sending a file + asking for printout.&newpara; + How technology has changed! Printers generally use cut-sheet media, they have + built-in intelligence to compute the raster images of pages after pages + that are sent to them using one of the powerful page description + languages (PDL). Many are network nodes in their own right, + with CPU, RAM, a hard disk and their own Operation System, and + are hooked to a net with potentially millions of users...&newpara; + It is a vast proof of the flexible &UNIX; concept for doing things, + that it made "Line Printing" reliably work even under these modern + conditions. But time has finally come now to go for something new + -- the IPP. + + IPP + &CUPS; + LPR/LPD printing + + + + + &CUPS; + Abbreviation for &emstart;C&emend;ommon + &emstart;U&emend;NIX &emstart;P&emend;rinting + &emstart;S&emend;ystem; &CUPS; is the most modern &UNIX; and Linux + printing system, also providing cross-platform print services + to &Microsoft; &Windows; and Apple &MacOS; clients. Based on IPP, it does + away with all the pitfalls of old-style BSD printing, + providing authentication, encryption and ACLs, plus many more + features. At the same time it is backward-compatible enough + to serve all legacy clients that are not yet up to IPP, via + LPR/LPD (BSD-style).&newpara; + &CUPS; is able to control any &PostScript; printer by + utilizing the vendor-supplied PPD (PostScript Printer + Description file), targeted originally for &Microsoft; Windows NT + printing only. &kde; Printing is most powerful if based on + &CUPS;.&newpara; + More info:&newpara; + &linkstart;"http://www.cups.org"&linkmid;&CUPS; Homepage&linkend; + ACLs + Authentication + BSD-style printing + IPP + LPR/LPD + PPD + + + + + + &CUPS;-FAQ + &linkstart;"http://www.cups.org/articles.php?L+TFAQ"&linkmid;&CUPS;-FAQ&linkend; + is a valuable resource to answer many questions that anyone new to + &CUPS; printing might have at first. + + + + + + Daemon + Abbreviation for &emstart;D&emend;isk + &emstart;a&emend;nd &emstart;e&emend;xecution + &emstart;mon&emend;itor; Daemons are present + on all &UNIX; systems to perform tasks independent of user + intervention. Readers more familiar with &Microsoft; &Windows; might + want to compare daemons and the tasks they are responsible + with "services".&newpara; + One example of a daemon present on most + legacy &UNIX; systems is the LPD (Line Printer Daemon); &CUPS; is + widely seen as the successor to LPD in the &UNIX; world and + it also operates through a daemon. + SPOOLing + + + + + Database, Linuxprinting.org + Already years ago, when Linux printing was still really difficult + (only command line printing was known to most Linux users, no device + specific print options were available for doing the jobs), Grant Taylor, + author of the "Linux Printing HOWTO", collected most of the available + information about printers, drivers and filters in his database.&newpara; + With the emerging + &CUPS; concept, extending the use of PPDs even to non-PostScript printers, + he realized the potential of this database: if one puts the different + datablobs (with content that could be described along the lines + "Which device prints with which Ghostscript or other + filter?", "How well?", and "What command line switches are available?") into + PPD-compatible files, he could have all the power of &CUPS; on top of + the traditional printer "drivers".&newpara; + This has now developed into a broader + concept, known as "Foomatic". Foomatic extends the capabilities + of spoolers other than &CUPS; (LPR/LPD, LPRng, PDQ, PPR) to a certain + degree ("stealing" some concepts from &CUPS;). The Linuxprinting + Database is not a Linux-only stop -- people running other &UNIX; + based OSes (like *BSD or &MacOS; X) will also find valuable information + and software there. + + Foomatic + Linuxprinting database + + + + + Direct TCP/IP Printing + This is a method that often uses TCP/IP port 9100 to connect + to the printer. It works with many modern network printers and has + a few advantages over LPR/LPD, as it is faster and provides some + "backchannel feedback data" from the printer to the host sending + the job. + AppSocket Protocol + &HP; JetDirect Protocol + + + + + + Drivers, Printer Drivers + The term "printer drivers", used in the same sense + as on the &Microsoft; &Windows; platform, is not entirely applicable + to a Linux or &UNIX; platform. A "driver" functionality + is supplied on &UNIX; by different modular components working + together. At the core of the printer drivers are "filters". Filters convert + print files from a given input format to another format that is acceptable + to the target printer. In many cases filters may be connected to a whole + filter "chain", where only the result of the last conversion is sent to the + printer. The actual transfer of the print data to the device is performed by + a "backend". + + Filter + PPDs + + + + + Easy Software Products + Mike Sweet's company, which has contributed a few substantial + software products towards the Free Software community; amongst + them the initial version of &linkstart; + "http://gimp-print.sf.net/"&linkmid;Gimp-Print,&linkend; the &linkstart; + "http://www.easysw.com/epm/"&linkmid;EPM software packaging&linkend; tool + and &linkstart;"http://www.easysw.com/htmldoc/"&linkmid;HTMLDOC&linkend; + (used by the "Linux Documentation Project" to build the PDF versions + of the HOWTOs) -- but most importantly: &linkstart; + "http://www.cups.org/"&linkmid;&CUPS;&linkend; (the 'Common &UNIX; Printing + System').&newpara; + ESP financed themselves by selling a commercial version + of &CUPS;, called ESP PrintPro, + that includes some professional enhancements. + ESP Print Pro was purchased by Apple Inc. in February of 2007. ESP Print Pro software and support are no longer available from Easy Software Products. ESP Print Pro users were given non-expiring, floating licenses which may be accessed from the MyESP pages. + + &CUPS; + ESP + Gimp-Print + + + + + Encryption + Encryption of confidential data is an all-important issue if + you transfer it over the Internet or even within intranets.&newpara; + Printing + via traditional protocols is not encrypted at all -- it is very easy + to tap and eavesdrop ⪚ into &PostScript; or PCL data transferred + over the wire.&newpara; + Therefore, in the design of IPP, provision was made for the easy + plugin of encryption mechanisms (which can be provided by the same + means as the encryption standards for HTTP traffic: SSL and TLS). + Authentication + &CUPS; + IPP + SSL + TLS + + + + + + Epson + Epson inkjets are among the best supported models by Free software + drivers, as the company was not necessarily as secretive about their + devices and handed technical specification documents to developers. + The excellent print quality achieved by Gimp-Print on the Stylus + series of printers can be attributed to this openness. + + + + + + + Escape Sequences + The first ever printers printed ASCII data only. To + initiate a new line, or eject a page, they included special + command sequences, often carrying a leading [ESC]-character. + &HP; evolved this concept through its series of PCL language + editions until today, having now developed a full-blown + Page Description Language (PDL) from these humble beginnings. + + PCL + PDL + + + + + ESC/P + Abbreviation for &emstart;E&emend;pson + &emstart;S&emend;tandard &emstart;C&emend;odes for + &emstart;P&emend;rinters. Besides &PostScript; and PCL, Epson's ESC/P + printer language is one of the best known. + PCL + &PostScript; + hpgl + + + + + ESP + Abbreviation for &emstart;E&emend;asy + &emstart;S&emend;oftware &emstart;P&emend;roducts; + the company that developed &CUPS; (the "Common &UNIX; Printing System"). + + Easy Software Products + &CUPS; + + + + + + Filter + Filters, in general, are programs that take some input + data, work on it and pass it on as their output data. Filters + may or may not change the data.&newpara; + Filters in the context of printing, are programs that convert + a given file (destined for printing, but not suitable in the + format it is presently) into a printable format. Sometimes + whole "filter chains" have to be constructed to achieve the + goal, piping the output of one filter as the input to the next. + + Ghostscript + RIP + + + + + Foomatic + Foomatic started out as the wrapper name for a set of + different tools available from &linkstart;"http://www.linuxfoundation.org/collaborate/workgroups/openprinting/database/foomatic"&linkmid;Linuxprinting.org&linkend; + These tools aimed to make the usage of traditional + Ghostscript and other print filters easier for users and + extend the filters' capabilities by adding more command line + switches or explain the driver's execution data.&newpara; + More recently, Foomatic gravitated towards becoming a "meta-spooling" + system, that allows configuration of the underlying print subsystem + through a unified set of commands (however, this is much more + complicated than &kde; printing &GUI; interface, which performs a similar + task with regards to different print subsystems). + + + + + Ghostscript + Ghostscript is a an interpreter for the &PostScript; language and for PDF or Raster Image Processor (RIP) in software, originally developed by L. Peter Deutsch. There is always a GPL version + of Ghostscript available for free usage and distribution. + Ghostscript is widely used inside the Linux and &UNIX; world + for transforming &PostScript; into raster data suitable + for sending to non-&PostScript; devices. + More info: + &linkstart;"http://www.ghostscript.com/"&linkmid;Ghostscript Homepage&linkend; + &PostScript; + RIP + + + + + Gimp-Print + Contrary to its name, Gimp-Print is no longer + just the plugin to be used for printing from the popular + Gimp program -- its codebase can also serve to be compiled + into...&newpara; + ...a set of PPDs and associated filters that integrate seamlessly + into &CUPS;, supporting around 130 different printer models, providing + photographic output quality in many cases;&newpara; + ...a Ghostscript filter that can be used with any other + program that needs a software-RIP;&newpara; + ...a library that can be used by other software applications + in need of rasterization functions. + Lexmark Drivers + RIP + Ghostscript + + + + + &HP; + Abbreviation for &emstart;H&emend;ewlett-&emstart;Packard&emend;; + one of the first companies to distribute their own Linux printer + drivers. -- More recently, the Company has released their + "HPIJS" package of drivers, including source code and a Free license. + This is the first printer manufacturer to do so. HPIJS supports most + current models of HP Ink- and DeskJets. + + + + + + + &HP;/GL + Abbreviation for &emstart;&HP;&emend; + &emstart;G&emend;raphical &emstart;L&emend;anguage; + a &HP; printer language mainly used for plotters; many CAD + (Computer Aided Design) software programs output &HP;/GL files for + printing. + ESC/P + PCL + &PostScript; + + + + + &HP; JetDirect Protocol + A term branded by &HP; to describe their implementation + of print data transfer to the printer via an otherwise "AppSocket" or + "Direct TCP/IP Printing" named protocol. + AppSocket Protocol + Direct TCP/IP Printing + + + + + IETF + Abbreviation for &emstart;I&emend;nternet + &emstart;E&emend;ngineering &emstart;T&emend;ask + &emstart;F&emend;orce; an assembly of Internet, software + and hardware experts that discuss + new networking technologies and very often arrive at + conclusions that are regarded by many as standards. "TCP/IP" + is the most famous example.&newpara; + IETF standards, as well as + drafts, discussions, ideas and useful tutorials, are + put in writing in the famous series of "RFCs", which + are available to the public and included in most Linux and + BSD distributions. + IPP + PWG + RFC + + + + + IPP + Abbreviation for &emstart;I&emend;nternet + &emstart;P&emend;rinting &emstart;P&emend;rotocol; + defined in a series of RFCs accepted by the IETF with + status "proposed standard"; was designed + by the PWG. -- IPP is a completely new design for network printing, + but it utilizes a very well-known and proven method for the + actual data transfer: HTTP 1.1! By not "re-inventing the wheel", + and basing itself on an existing and robust Internet standard, + IPP is able to relatively easily bolt other HTTP-compatible standard + mechanisms into its framework:&newpara; + + Basic, Digest or Certificate authentication mechanisms&newpara; + SSL or TLS for encryption of transferred data&newpara; + LDAP for directory services (to publish + data on printers, device-options, drivers, costs or + also to the network; or to check for passwords while + conducting authentication) + + + &CUPS; + PWG + IETF + RFC + TLS + + + + + + Lexmark + was one of the first companies to distribute their own Linux printer + drivers for some of their models. However, those drivers are binary only + (no source code available), and therefore cannot be used to integrate into + other Free printing software projects. + + + + + + Linuxprinting.org + Linuxprinting.org = not just for Linux; all &UNIX;-like OS-es, + like *BSD and commercial Unices may find useful printing + information on this site. This web site is the home for the interesting + Foomatic project, that strives to develop the "Meta Print Spool and Driver + Configuration Toolset" (being able to configure, through one common + interface, different print subsystems and their required drivers) with the + ability to transfer all queues, printers and configuration files seamlessly + to another spooler without new configuration effort. -- Also, they maintain + the Printing Database; a collection of driver and device information that + enables everybody to find the most current information about printer models, + and also generate online the configuration files for any + spooler/driver/device combo known to work with one of the common Linux or + &UNIX; print subsystems. + + Linuxprinting database + + + + + + Linuxprinting.org Database + &linkstart;"http://www.openprinting.org/printers"&linkmid;Database&linkend; containing printers and drivers that are suitable for them. + More info: + &linkstart;"http://www.linuxfoundation.org/collaborate/workgroups/openprinting/database/indexfaq"&linkmid;Linuxprinting.org FAQ&linkend; + Foomatic + + + + + LPR/LPD printing + LPR == some people translate &emstart;L&emend;ine + &emstart;P&emend;rinting &emstart;R&emend;equest, others: + &emstart;L&emend;ine &emstart;P&emend;rinter + &emstart;R&emend;emote. + BSD-style printing + + + + + Magicfilter + Similarly to the APSfilter program, Magicfilter + provides automatic file type recognition functions and, base + on that, automatic file conversion to a printable format, + depending on the target printer. + APSfilter + + + + + &MIME;-Types + Abbreviation for &emstart;M&emend;ultipurpose (or + Multimedia) &emstart;I&emend;nternet &emstart;M&emend;ail + &emstart;E&emend;xtensions; &MIME;-Types were first used to allow + the transport of binary data (like mail attachments containing + graphics) over mail connections that were normally only transmitting + ASCII characters: the data had to be encoded into an ASCII representation.&newpara; + Later this concept was extended to describe a data format in + a platform independent, but at the same time non-ambiguous, way. + From &Windows; everybody knows the .doc extensions for &Microsoft; Word files. + This is handled ambiguously on the &Windows; platform: .doc extensions are also + used for simple text files or for Adobe Framemaker files. And if a real + Word file is renamed with a different extension, it can no longer be + opened by the program.&newpara; + &MIME; typed files carry a recognition string with them, describing + their file format based on &emstart;main_category/sub_category&emend;. + Inside IPP, print files are also described using the &MIME; type scheme. + &MIME; types are registered with the IANA (Internet Assigning Numbers + &emstart;Association&emend;) to keep them unambiguous.&newpara; + &CUPS; has some &MIME; types of its own registered, like + &emstart;application/vnd.cups-raster&emend; (for the &CUPS;-internal + raster image format). + + &CUPS; + Easy Software Products + Gimp-Print + + + + + PCL + Abbreviation for &emstart;P&emend;rinter + &emstart;C&emend;ontrol &emstart;L&emend;anguage; + developed by &HP;. PCL started off in version 1 as a simple + command set for ASCII printing; now, + in its versions PCL6 and PCL-X, it is capable of printing graphics + and color -- but outside the &Microsoft; &Windows; realm and &HP-UX; + (&HP;'s own brand of &UNIX;), it is not commonly used... + ESC/P + &HP;/GL + PDL + &PostScript; + + + + + PDL + Abbreviation for &emstart;P&emend;age + &emstart;D&emend;escription &emstart;L&emend;anguage; + PDLs describe, in an abstract way, the graphical representation + of a page. - Before it is actually transferred into + toner or ink laid down on to paper, a PDL needs to be + "interpreted" first. In &UNIX;, the most important PDL + is &PostScript;. + + ESC/P + &HP;/GL + PCL + &PostScript; + + + + + Pixel + Abbreviation for &emstart;Pic&emend;ture + &emstart;El&emend;ement; this term describes the smallest + part of a raster picture (either as printed on paper + or as displayed on a monitor by cathode rays or LCD elements). As + any graphical or image representation on those types of output + devices is composed of pixels, the values of "ppi" (pixel per inch) + and &dpi; (dots per inch) are one important parameter for the + overall quality and resolution of an image. + Filter + Ghostscript + &PostScript; + Raster + + + + + PJL + Abbreviation for &emstart;P&emend;rint + &emstart;J&emend;ob &emstart;L&emend;anguage; + developed by &HP; to control and influence default and per-job + settings of a printer. It may not only be used + for &HP;'s own (PCL-)printers; also many &PostScript; + and other printers understand PJL commands sent to them + inside a print job, or in a separate signal. + PCL + + + + + &PostScript; + &PostScript; (often shortened to "PS") is the de-facto + standard in the &UNIX; world for printing files. It was + developed by Adobe and licensed to printer manufacturers + and software companies.&newpara; + As the &PostScript; specifications were + published by Adobe, there are also "Third Party" implementations + of &PostScript; generating and &PostScript; interpreting software + available (one of the best-known in the Free software world + being Ghostscript, a powerful PS-interpreter). + + ESC/P + &HP;/GL + PCL + PPD + + + + + PPD + Abbreviation for &emstart;P&emend;ostScript + &emstart;P&emend;rinter &emstart;D&emend;escription; + PPDs are ASCII files storing all information about the special + capabilities of a printer, plus definitions of the (PostScript- + or PJL-) commands to call on a certain capability (like print + duplexing).&newpara; + As the explanation of the acronym reveals, PPDs were originally + only used for &PostScript; printers. &CUPS; has extended the + PPD concept to all types of printers.&newpara; + PPDs for &PostScript; printers are provided by the printer + vendors. They can be used with &CUPS; and &kde; printing subsystem to have access + to the full features of any &PostScript; printer. The &kde; Team + recommends using a PPD originally intended for use with + &Microsoft; Windows NT.&newpara; + PPDs for non-PostScript printers &emstart;need&emend; a + companion "filter" to process the &PostScript; print files into + a format digestible for the non-PostScript target device. Those + PPD/filter combos are not (yet) available from the vendors. After + the initiative by the &CUPS; developers to utilize PPDs, the Free + Software community was creative enough to quickly come up with + support for most of the currently used printer models, through + PPDs and classical Ghostscript filters. But note: the printout + quality varies from "hi-quality photographic output" (using + Gimp-Print with most Epson inkjets) to "hardly readable" (using + Foomatic-enabled Ghostscript filters for models rated as + "paperweight" in the Linuxprinting.org database). + + &CUPS; + Linuxprinting.org + &PostScript; + + + + + printcap + In BSD-style print systems, the "printcap" file holds + the configuration information; the printing daemon reads this file + to determine which printers are available, what filters are to be + user for each, where the spooling folder is located, + if there are banner pages to be used, and so on... + Some applications also depend on read access to the printcap + file, to obtain the names of available printers. + BSD-style printing + + + + + + Printer-MIB + Abbreviation for + &emstart;Printer&emend;-&emstart;M&emend;anagement + &emstart;I&emend;nformation &emstart;B&emend;ase; the + Printer-MIB defines a set of parameters that are to be + stored inside the printer for access + through the network. This is useful if many (in some cases, literally + thousands) network printers are managed centrally + with the help of SNMP (Simple Network Management Protocol). + PWG + SNMP + + + + + PWG + Abbreviation for + &emstart;P&emend;rinter &emstart;W&emend;orking + &emstart;G&emend;roup; the PWG is a loose grouping of + representatives of the printer industry that has, in the past + years, developed different standards + in relation to network printing. These were later accepted by the + IETF as RFC standards, like the "Printer-MIB" and the IPP. + &PostScript; + IPP + Printer-MIB + SNMP + + + + + + + Printer Database + Good database of printer drivers can be found at &linkstart;"http://www.openprinting.org/printers"&linkmid;http://www.openprinting.org/printers&linkend;. + Linuxprinting Database + + + + + Raster Image + Every picture on a physical medium + is composed of a pattern of discrete dots in different colors and (maybe) + sizes. This is called a "raster image".&newpara; + This is as opposed to a "vector image" + where the graphic is described in terms of continuous curves, shades, + forms and filled areas, represented by mathematical formula. Vector images + normally have a smaller file size and may be scaled in size + without any loss of information and quality --- but they cannot be + output directly, but always have to be "rendered" or "rasterized" + first to the given resolution that the output device is capable of...&newpara; + The rasterization is done by a Raster Image Processor (RIP, + often the Ghostscript software) or some other filtering + instance. + Pixel + Ghostscript + &PostScript; + Filter + RIP + + + + + RIP + Abbreviation for + &emstart;R&emend;aster &emstart;I&emend;mage + &emstart;P&emend;rocess(or); if used in the context of + printing, "RIP" means a hardware or software + instance that converts &PostScript; (or other print formats + that are represented in one of the non-Raster PDLs) into a + raster image format in such a way that it is acceptable + for the "marking engine" of the printer.&newpara; + &PostScript; printers + contain their own PostScript-RIPs. A RIP may or may not be located + inside a printer.&newpara; + For many &UNIX; systems, Ghostscript is the package that provides + a "RIP in software", running on the host computer, and pre-digesting + the &PostScript; or other data to become ready to be sent to the + printing device (hence you may perceive a "grain of truth" in the + slogan "Ghostscript turns your printer into a &PostScript; + machine", which of course is not correct in the true sense of the + meaning). + Filter + Ghostscript + &PostScript; + PDL + Raster + + + + + + RLPR (Remote LPR) + Abbreviation for &emstart;R&emend;emote + &emstart;L&emend;ine &emstart;P&emend;rinting + &emstart;R&emend;equest; this is a BSD-style printing system, + that needs no root privileges to be installed, and no "printcap" to + work: all parameters may be specified on the command + line.&newpara; + RLPR comes in handy for many laptop users who are + working in frequently changing environments. This is because it + may be installed concurrently with every other printing + sub system, and allows a very flexible and quick + way to install a printer for direct access via LPR/LPD. + + printcap + + + + + + SNMP + Abbreviation for &emstart;S&emend;imple + &emstart;N&emend;etwork &emstart;M&emend;anagement + &emstart;P&emend;rotocol; SNMP is widely used to control + all types of network node (Hosts, Routers, Switches, Gateways, + Printers...) remotely. + PWG + Printer-MIB + + + + + SSL(3) encryption + Abbreviation for &emstart;S&emend;ecure + &emstart;S&emend;ocket &emstart;L&emend;ayer; + SSL is a proprietary encryption method for data + transfer over HTTP that was developed by Netscape. It is now being + replaced by an IETF standard named TLS. + + TLS + + + + + + SPOOLing + Abbreviation for &emstart;S&emend;ynchronous + &emstart;P&emend;eripheral &emstart;O&emend;perations + &emstart;O&emend;n&emstart;L&emend;ine; + SPOOLing enables printing applications + (and users) to continue their work + as the job is being taken care of by a system daemon, + which stores the file at a temporary location until the printer is ready + to print. + Daemon + + + + + + TLS encryption + Abbreviation for &emstart;T&emend;ransport + &emstart;L&emend;ayer &emstart;S&emend;ecurity; + TLS is an encryption standard for + data transferred over HTTP 1.1; it is defined in RFC 2246; + although based on the former SSL development + (from Netscape) it is not fully compatible with it. + + SSL(3) + + + + + + System V-style printing + This is the second flavor of traditional &UNIX; + printing (as opposed to BSD-style printing). It uses + a different command set (lp, lpadmin,...) to BSD, + but is not fundamentally different from it. However, the + gap between the two is big enough to make the two + incompatible, so that a BSD-client cannot simply print + to a System V style print server without additional + tweaking... IPP is supposed to resolve this weakness + and more. + + BSD-style printing + IPP + + + + + TurboPrint + Shareware software providing photo quality printing for many + inkjet printers. It is useful if you are unable to find a driver for your + printer and may be hooked into either a traditional Ghostscript system + or a modern &CUPS; system. + Gimp-Print + + + + + XPP + Abbreviation for &emstart;X&emend; + &emstart;P&emend;rinting &emstart;P&emend;anel; + XPP was the first Free + graphical print command for &CUPS;, written by Till Kamppeter, + and in some ways a model for the "kprinter" utility in &kde; 3. + + + + + + + diff --git a/doc/kcontrol/CMakeLists.txt b/doc/kcontrol/CMakeLists.txt index 87f836a3..ce39a4a4 100644 --- a/doc/kcontrol/CMakeLists.txt +++ b/doc/kcontrol/CMakeLists.txt @@ -9,6 +9,21 @@ add_subdirectory(splashscreen) add_subdirectory(powerdevil) add_subdirectory(kwincompositing) add_subdirectory(kwinscreenedges) +add_subdirectory(bookmarks) +add_subdirectory(icons) +add_subdirectory(cookies) +add_subdirectory(ebrowsing) +add_subdirectory(useragent) +add_subdirectory(khtml-general) +add_subdirectory(khtml-plugins) +add_subdirectory(khtml-java-js) +add_subdirectory(khtml-behavior) +add_subdirectory(khtml-adblock) +add_subdirectory(nepomuk) +add_subdirectory(attica) +add_subdirectory(kcm_ssl) +add_subdirectory(smb) +add_subdirectory(emoticons) if ( Q_WS_X11 ) add_subdirectory(autostart) @@ -29,4 +44,22 @@ add_subdirectory(kwintabbox) add_subdirectory(kcmsmserver) add_subdirectory(workspaceoptions) add_subdirectory(khotkeys) +add_subdirectory(cache) +add_subdirectory(filemanager) +add_subdirectory(filetypes) +add_subdirectory(kcmcgi) +add_subdirectory(kcmcss) +add_subdirectory(kcmlaunch) +add_subdirectory(kcmnotify) +add_subdirectory(language) +add_subdirectory(netpref) +add_subdirectory(performance) +add_subdirectory(proxy) +add_subdirectory(spellchecking) +add_subdirectory(componentchooser) +add_subdirectory(kded) +add_subdirectory(trash) +add_subdirectory(history) +add_subdirectory(solid-device-automounter) +add_subdirectory(phonon) endif ( Q_WS_X11 ) diff --git a/doc/kcontrol/attica/CMakeLists.txt b/doc/kcontrol/attica/CMakeLists.txt new file mode 100644 index 00000000..63ca05e1 --- /dev/null +++ b/doc/kcontrol/attica/CMakeLists.txt @@ -0,0 +1,2 @@ +########### install files ############### +kde4_create_handbook(index.docbook INSTALL_DESTINATION ${HTML_INSTALL_DIR}/en SUBDIR kcontrol/attica) diff --git a/doc/kcontrol/attica/index.docbook b/doc/kcontrol/attica/index.docbook new file mode 100644 index 00000000..1f5d36ce --- /dev/null +++ b/doc/kcontrol/attica/index.docbook @@ -0,0 +1,61 @@ + + + +]> + +
+ + +Social Desktop + +FrederikGladhorn +gladhorn@kde.org + + + + + +2013-11-05 +&kde; 4.12 + + +KDE +Systemsettings +Social Desktop + + + +The Social Desktop (Open Collaboration Services) settings module lets you +configure your user accounts for Open Collaboration Service Providers. + +At the time of writing openDesktop.org + is the first provider that you can use. +You can use the web site or this settings dialog to register and manage your account. + + +The benefit is that you can do more things in Get Hot New Stuff: +vote for items, become a fan of them and upload new content. A configured +account also allows you to use the social Plasma widgets (Community, +Social News &etc;) to their full extent. + + +Using the &systemsettings; module: + +You can select which provider to configure at the top. +Either enter your existing user name and password to let &kde; use them. +You can verify that these work by using the Test Login button + + + +If you do not have an account yet, use the Register tab. +Here you need to fill out all fields. +After clicking Register... you will receive an email from the +server to activate your account. + + +
diff --git a/doc/kcontrol/bookmarks/CMakeLists.txt b/doc/kcontrol/bookmarks/CMakeLists.txt new file mode 100644 index 00000000..2f98e645 --- /dev/null +++ b/doc/kcontrol/bookmarks/CMakeLists.txt @@ -0,0 +1,2 @@ +########### install files ############### +kde4_create_handbook(index.docbook INSTALL_DESTINATION ${HTML_INSTALL_DIR}/en SUBDIR kcontrol/bookmarks) diff --git a/doc/kcontrol/bookmarks/index.docbook b/doc/kcontrol/bookmarks/index.docbook new file mode 100644 index 00000000..9f32fc43 --- /dev/null +++ b/doc/kcontrol/bookmarks/index.docbook @@ -0,0 +1,101 @@ + + + +]> + +
+ + +Bookmarks + + +XavierVello +xavier.vello@gmail.com + + + + +2010-09-24 +0.2 (&kde; 4.5) + + +KDE +KControl +bookmarks +KIO + + + +Bookmarks home page +This module lets you configure the bookmarks home page. +To view the bookmarks home page enter bookmarks:/ in +the location bar. +The settings in this module are also accessible by entering +bookmarks:/config in the location bar. + +General settings + + +Number of columns to show + +Folders are automatically distributed in several columns. The optimal number of columns depends on the width of the konqueror window and the number of bookmarks you have. + + + + +Show folder backgrounds + +Disable it on slow system to disable background images. + + + + + + +Bookmarks + + +Show bookmarks without folder + +If this option is unchecked, bookmarks at the root of the hierarchy (not in a folder) are not displayed. If checked, they are gathered in a "root" folder. + + + + +Flatten bookmarks tree + +Sub-folders are shown within their parent by default. If you activate this option, sub-folders are displayed on their own. It looks less nice but it may help if you have a very big folder you want to spread in two columns. + + + + +Show system places + +Show a box with KDE places (Home, Network, ...). Useful if you use konqueror as a file manager. + + + + + + +Pixmap cache + + +Disk cache size + +Specify how much disk space is used to cache the pixmaps. + + + + +Clear Cache + +Remove all cached images. This may be necessary if some favicons become corrupt and don't refresh automatically. + + + + + +
diff --git a/doc/kcontrol/cache/CMakeLists.txt b/doc/kcontrol/cache/CMakeLists.txt new file mode 100644 index 00000000..7509aba7 --- /dev/null +++ b/doc/kcontrol/cache/CMakeLists.txt @@ -0,0 +1,2 @@ +########### install files ############### +kde4_create_handbook(index.docbook INSTALL_DESTINATION ${HTML_INSTALL_DIR}/en SUBDIR kcontrol/cache) diff --git a/doc/kcontrol/cache/index.docbook b/doc/kcontrol/cache/index.docbook new file mode 100644 index 00000000..ce9ead36 --- /dev/null +++ b/doc/kcontrol/cache/index.docbook @@ -0,0 +1,66 @@ + + + +]> + +
+Cache + + + +LauriWatts + + + + +2009-11-20 +&kde; 4.4 + + +KDE +Systemsettings +Konqueror +Cache + + + +This module allows you to control the size of the local cache +folder used by &konqueror;. Note that each user account on your +computer has a separate cache folder, and this folder is not +shared with other web browsers such as &Netscape;. + +Storing local copies of web pages that you have visited allows +&konqueror; to quickly load their contents on subsequent visits. It +will only be necessary to reload the contents from the original site +if they have changed since your last visit, or if you click the reload +button in &konqueror;. + +If you really do not want any of the web pages you visit to be +stored on your computer, you can disable &konqueror;'s disk cache by +clearing the checkbox labeled Use cache. + +You can set here how aggressively &konqueror; keeps the cache up +to date. Keep cache in sync means that &konqueror; +will hit the cache for all objects, downloading them if they are not +there, and then display the item from the cache. Use cache +whenever possible means that &konqueror; will try the cache, +and if an object is not there, it will directly download it for display. +Offline browsing mode means that &konqueror; will +try the cache, and if an object is not there, it will not attempt to +download it from the Internet. + +You can control the size of the cache by typing a number into the +text box labeled Disk cache size. This is the +average amount of space in kilobytes that the cache folder is allowed +to use. When the cache grows too large, &konqueror; will delete older +files to reduce the size of the cache folder. + +This is however, only an average, and during a browsing session +the cache could become substantially larger. + +You can use the Clear Cache button to empty +the cache at any time. + +
diff --git a/doc/kcontrol/componentchooser/CMakeLists.txt b/doc/kcontrol/componentchooser/CMakeLists.txt new file mode 100644 index 00000000..9164b121 --- /dev/null +++ b/doc/kcontrol/componentchooser/CMakeLists.txt @@ -0,0 +1,2 @@ +########### install files ############### +kde4_create_handbook(index.docbook INSTALL_DESTINATION ${HTML_INSTALL_DIR}/en SUBDIR kcontrol/componentchooser) diff --git a/doc/kcontrol/componentchooser/index.docbook b/doc/kcontrol/componentchooser/index.docbook new file mode 100644 index 00000000..4e353603 --- /dev/null +++ b/doc/kcontrol/componentchooser/index.docbook @@ -0,0 +1,68 @@ + + + +]> + +
+ + +Default Applications + +BurkhardLück +lueck@hube-lueck.de + + + + + +2013-12-05 +&kde; 4.12 + + +KDE +Systemsettings +component + + + +In this module you can change &kde; default components. + +Components are programs that handle basic tasks, like the terminal emulator, the text +editor and the email client. Different &kde; applications sometimes need to +invoke a console emulator, send a mail or display some text. + +To do so consistently, these applications always call the same components. Here you +can select which programs these components are. + +The list on the left shows the configurable component types: + + +Email Client + + +Embedded Text Editor + + +File Manager + + +Instant Messenger + + +Terminal Emulator + + +Web Browser + + +Window Manager + + + + Click the component you want to configure. In the right part of the dialog then all available +applications for this service are displayed and you are able to select your favorite terminal emulator, text +editor and the email client &etc; + +
diff --git a/doc/kcontrol/cookies/CMakeLists.txt b/doc/kcontrol/cookies/CMakeLists.txt new file mode 100644 index 00000000..88fac298 --- /dev/null +++ b/doc/kcontrol/cookies/CMakeLists.txt @@ -0,0 +1,2 @@ +########### install files ############### +kde4_create_handbook(index.docbook INSTALL_DESTINATION ${HTML_INSTALL_DIR}/en SUBDIR kcontrol/cookies) diff --git a/doc/kcontrol/cookies/index.docbook b/doc/kcontrol/cookies/index.docbook new file mode 100644 index 00000000..cd817332 --- /dev/null +++ b/doc/kcontrol/cookies/index.docbook @@ -0,0 +1,208 @@ + + + +]> + +
+ +Cookies + +&Krishna.Tateneni; &Krishna.Tateneni.mail; +&Jost.Schenck; &Jost.Schenck.mail; + + + +2012-11-11 +&kde; 4.10 + + +KDE +Systemsettings +cookie + + + + + +Cookies + +Cookies are a mechanism used by web sites to store and retrieve +information using your browser. For example, a web site may allow you +to customize the content and layout of the pages you see, so that your +choices are persistent across different visits to that web site. + +The web site is able to remember your preferences by storing a +cookie on your computer. Then, on future visits, the web site retrieves +the information stored in the cookie to format the content of the site +according to your previously specified preferences. + +Thus, cookies play a very useful role in web browsing. +Unfortunately, web sites often store and retrieve information in cookies +without your explicit knowledge or consent. Some of this information may +be quite useful to the web site owners, for example, by allowing them to +collect summary statistics on the number of visits different areas of +the web sites get, or to customize banner advertising. + +The cookies page allows you to set policies +for the use of cookies when you are browsing the web with the +&konqueror; web browser. + +Note that the policies that you set using this control +module will not apply to other web browsers such +as &Netscape;. + + + +Policy + +Using the Policy tab, you can configure the +&kde; applications that will handle cookies. You can do this by specifying a +general cookie policy as well as special cookie policies for certain +domains or hosts. + +The top of the policy tab has a check box labeled Enable +cookies. If you leave this unchecked, cookies will be +completely disabled. However, this may make browsing rather +inconvenient, especially as some web sites require the use of browsers +with cookies enabled. + +You will probably want to enable cookies and then set +specific policies on how you want them to be handled. + +The first group of options create settings that apply to all cookies. + + + +Only accept cookies from originating server + +Some pages try to set cookies from servers other than the one +you are seeing the &HTML; page from. For example, +they show you advertisements, and the advertisements are from another +computer, often one that belongs to a large advertising group. These +advertisements may try to set a cookie which would allow them to +track the pages you view across multiple web sites. +Enabling this option will mean only cookies that come from the +same web server as you are explicitly connecting to will be +accepted. + + + +Automatically accept session cookies + + +An increasingly common use for cookies is not to track your +movements across many visits to a web site, but to just follow what you +do during one single visit. Session cookies are saved as long as you +are looking at the site, and deleted when you leave it. + +Web sites can use this information for various things, most +commonly it is a convenience so that you do not have to keep logging in +to view pages. For example, on a webmail site, without some kind of +session ID, you would have to give your password +again for each email you want to read. There are other ways to +achieve this, but cookies are simple and very common. + +Enabling this option means that session cookies are always +accepted, even if you don't accept any other kind, and even if you +choose to reject cookies from a particular site, session cookies from +that site will be accepted. + + + + +The section for Default Policy sets some +further options that are mutually exclusive — you can choose only one +of these options as the default, but you are free to set a different +option for any specific web server. +Site specific policies always take precedence over the default +policy. + + + +Accept all cookies + +If this option is selected, all cookies will be accepted without +asking for confirmation. + + + +Accept until end of session + +Cookies will be accepted, but they will expire at the end +of the session. + + + +Ask for confirmation + +If this option is selected, you will be asked for confirmation +every time a cookie is stored or retrieved. You can selectively accept +or reject each cookie. The confirmation dialog will also allow you to +set a domain specific policy, if you do not want to confirm each +cookie for that domain. + + + +Reject all cookies + +If this option is selected, all cookies will be rejected without +asking for confirmation. + + + + +In addition to the default policy for handling of cookies, which you can +set by selecting one of the three options described above, you can also set +policies for specific host domains using the controls in the Site +Policy group. + +The Ask, Accept, Accept until end of session, or Reject policy can be applied to a specific +domain by clicking on the New... button, which +brings up a dialog. In this dialog, you can type the name of the +domain (with a leading dot), then select the policy you want to apply +to this domain. Note that entries may also get added while you are +browsing, if the default policy is to ask for confirmation, and you +choose a general policy for a specific host (for example, by selecting +Reject when asked to +confirm a cookie). + +You can also select a specific host domain from the list and click the +Change button to choose a different policy for that +domain than the one shown in the list. + +To delete a domain specific policy, choose a domain from the list, and +then click the Delete button. The default policy will +apply to domains which have been deleted from the list. + + + + +Management + +In the Management tab you can browse and selectively +delete cookies that have been set in the past. + +In the upper part of this dialog, you can see a list of domains displayed + as a tree. Click on the little > next to a domain to see all +cookies that have been set for this particular target domain. If you select one +of these cookies, you will notice that its contents will show up in the frame +Details below. + +By clicking the Delete button you can now delete the selected +cookie. Click Delete All to delete all cookies stored. + +If a domain is selected, you can use Configure Policy to set +a site policy. + +Choose Reload List to reload the list +from your hard disk. You might want to do this if you have had the +module open and are testing web sites, or have made many changes in the +module itself. + + + + + +
diff --git a/doc/kcontrol/ebrowsing/CMakeLists.txt b/doc/kcontrol/ebrowsing/CMakeLists.txt new file mode 100644 index 00000000..2bdd4b02 --- /dev/null +++ b/doc/kcontrol/ebrowsing/CMakeLists.txt @@ -0,0 +1,2 @@ +########### install files ############### +kde4_create_handbook(index.docbook INSTALL_DESTINATION ${HTML_INSTALL_DIR}/en SUBDIR kcontrol/ebrowsing) diff --git a/doc/kcontrol/ebrowsing/index.docbook b/doc/kcontrol/ebrowsing/index.docbook new file mode 100644 index 00000000..63e6f693 --- /dev/null +++ b/doc/kcontrol/ebrowsing/index.docbook @@ -0,0 +1,173 @@ + + + +]> + +
+ +Web Shortcuts + +&Krishna.Tateneni; &Krishna.Tateneni.mail; +&Yves.Arrouye; &Yves.Arrouye.mail; + + + +2013-05-30 +&kde; 4.11 + + +KDE +Systemsettings +enhanced browsing +web shortcuts +browsing + + + + + +Web Shortcuts + + + +Introduction + +&konqueror; offers some features to enhance your browsing +experience. One such feature is Web Shortcuts. + +You may already have noticed that &kde; is very Internet friendly. +For example, you can click on the Run menu +item or type the keyboard shortcut assigned to that command (&Alt;F2, +unless you have changed it) and type in a &URI;. +Uniform Resource Identifier. A standardized way of +referring to a resource such as a file on your computer, a World Wide +Web address, an email address, +etc.... + +Web shortcuts, on the other hand, let you come up with new pseudo +&URL; schemes, or shortcuts, that basically let you +parameterize commonly used +&URI;s. For example, if you like the Google search +engine, you can configure &kde; so that a pseudo &URL; +scheme like gg will trigger a search on +Google. This way, typing gg:my +query will search for my +query on Google. + +One can see why we call these pseudo &URL; +schemes. They are used like a &URL; scheme, but the +input is not properly &URL; encoded, so one will type +google:kde apps and not +google:kde+apps. + +You can use web +shortcuts wherever you would normally use +&URI;s. Shortcuts for several search engines should +already be configured on your system, but you can add new keywords, and +change or delete existing ones in this module. + + + + + +Web Shortcuts + +The descriptive names of defined web shortcuts are shown in a +list box. As with other lists in &kde;, you can click on a column +heading to toggle the sort order between ascending and +descending, and you can resize the columns. + +At the bottom of the list the option Enable Web shortcuts +has to be checked to enable this feature. Use the buttons on the right to +create, modify or delete shortcuts. + +If Use preferred shortcuts only is checked, only +web shortcuts marked as preferred in the third column of the list +are used in places where only a few select +shortcuts can be shown at one time. + + +Below the list you find two additional options: + +Default Web shortcuts + +Select the search engine to use for input boxes that provide automatic +lookup services when you type in normal words and phrases instead of a &URL;. +To disable this feature select None from the list. + + +Keyword delimiter + +Choose the delimiter that separates the keyword from the phrase or word to +be searched. + + + +If you double-click on a specific entry in the list of defined +search providers or click the Change button, +the details for that entry are shown in a popup +dialog. In addition to the descriptive name for the item, you can +also see the &URI; which is used, as well as the +associated shortcuts which you can type anywhere in &kde; where +&URI;s are expected. A given search provider can have +multiple shortcuts, each separated by a comma. + + The text boxes are used not only for displaying information +about an item in the list of web shortcuts, but also for modifying or +adding new items. + +You can change the contents of either the Shortcut +URL or the Shortcuts text box. +Click OK to save your changes or +Cancel to exit the dialog with no +changes. + +If you examine the contents of the Shortcuts +URL text box, you will find that most, if not all of the +entries have a in them. This sequence of four +characters acts as a parameter, which is to say that they are replaced +by whatever you happen to type after the colon character that is +between a shortcut and its parameter. To add this query placeholder +to a shortcuts url, click on the button at the right of the text box. +Let's consider some examples to clarify how to use web shortcuts. + +Suppose that the &URI; is +http://www.google.com/search?q=\{@}, and +gg is a shortcut to this +&URI;. Then, typing +gg:alpha is +equivalent to +http://www.google.com/search?q=alpha. +You could type anything after the : character; +whatever you have typed simply replaces the +characters, after being converted to the appropriate character set for +the search provider and then properly +&URL;-encoded. Only the part of +the search &URI; is touched, the rest of it is +supposed to be properly &URL;-encoded already and is +left as is. + +You can also have shortcuts without parameters. Suppose the +&URI; was +file:/home/me/mydocs/calligra/words and the +shortcut was mywords. Then, typing +mywords: is the same as typing the complete +&URI;. Note that there is nothing after the colon +when typing the shortcut, but the colon is still required in order for +the shortcut to be recognized as such. + +By now, you will have understood that even though these shortcuts +are called web shortcuts, they really are shortcuts to parameterized +&URI;s, which can point not only to web sites like +search engines but also to anything else that can be pointed to by a +&URI;. Web shortcuts are a very powerful feature of +navigation in &kde;. + + + + + +
diff --git a/doc/kcontrol/emoticons/CMakeLists.txt b/doc/kcontrol/emoticons/CMakeLists.txt new file mode 100644 index 00000000..c8a3d7aa --- /dev/null +++ b/doc/kcontrol/emoticons/CMakeLists.txt @@ -0,0 +1,3 @@ +########### install files ############### +# +kde4_create_handbook(index.docbook INSTALL_DESTINATION ${HTML_INSTALL_DIR}/en SUBDIR kcontrol/emoticons) diff --git a/doc/kcontrol/emoticons/emoticons.png b/doc/kcontrol/emoticons/emoticons.png new file mode 100644 index 00000000..9c467272 Binary files /dev/null and b/doc/kcontrol/emoticons/emoticons.png differ diff --git a/doc/kcontrol/emoticons/index.docbook b/doc/kcontrol/emoticons/index.docbook new file mode 100644 index 00000000..c5283b1f --- /dev/null +++ b/doc/kcontrol/emoticons/index.docbook @@ -0,0 +1,168 @@ + + + +]> +
+ +Emoticons + +&Anne-Marie.Mahfouf; + + + +2013-12-05 +&kde; 4.12 + + +KDE +System Settings +emoticons +KCMEmoticons + + + + +<guilabel>Emoticons Themes Manager</guilabel> + +Introduction + + + +Screenshot of the Emoticons Theme Manager + + + + + + The Emoticons Theme Manager + + + + + +Emoticons can be used in several &kde; applications: &kopete;, &konversation;, &kmail;... This module offers you to easily manage your emoticons sets. You can: + + +add emoticons themes +remove emoticons themes +install an existing theme +add, remove or edit emoticons within a theme + + +Please note that you will set emoticons themes per application. + + +The module is separated in two parts: on the left you can manage your themes and on the right you can manage emoticons within themes. + + + +An emoticon consists in two parts: an icon (typically a .png, .mng or .gif picture) and a text describing the emoticon. The text can be some ASCII symbols like ]:-> or the emoticon short description enclosed within * like *FRIEND*. The user types the symbol or the text and the emoticon icon replaces it. + + + +The emoticons themes will be saved locally in your home in $KDEHOME/share/emoticons. + + + + + +Emoticons Themes + + +This section allows you to manage emoticons themes. + + + +Require spaces around emoticons + + +When this option is checked, you need to separate the emoticon with a white space before and after it so it is changed to an icon. If you type "Hello:-)" then this string will stay as it is while if you type "Hello :-)" you will get "Hello" followed by the :-) emoticon. + + +When this option is not checked (default), each emoticon string will be replaced by its icon. + + + + +New Theme... + + +You can create your own new theme from scratch. Clicking on this button brings a dialog asking for the name of the new theme. You can then use the Add... button on the right to create new emoticons and their associated text. + + + +Get New Icon Themes... + + +You need to be connected to the Internet to use this action. A dialog displays a list of emoticons themes from http://www.kde-look.org and you can install one by clicking the Install button on the right side of the theme description in the list. + + + +Install Theme File... + + +This action allows you to install a theme you downloaded yourself. A theme file is an archive file, usually a .tar.gz or a .zip file or any other archive files. A dialog asks you for the location of this local archive file and after you entered or dragged the URL and clicked OK, the theme is installed and will appear in the themes list. + + + +Remove Theme + + +This action will remove the selected theme from your disk. Select the theme you want to remove in the list. Click the Remove Theme button. This theme will be removed from the disk if you click Apply. + + + + + + + + +Emoticons Management + + +This section allows you to manage emoticons within the selected theme. The list on the right displays all emoticons of the selected theme. You can add, edit or remove any emoticon. Select a theme in the list on the left and then select the action you want to perform. + + + +Add... + + +This button allows you to add an emoticon to the selected theme. The dialog asks you to choose an icon for your emoticon and to enter the corresponding ASCII symbol or text attached to it. After that, clicking OK will add your new emoticon in the emoticon list, you will see the icon and the corresponding text displayed. If you want to modify either the icon or the text, you can use the Edit... button described below. + + + + +Edit... + + +The Edit... button allows you to change either the icon or the text of the selected emoticon. You need to click the OK button to validate this action. + + + +Remove + + +This will remove the selected emoticon from the selected theme. You need to click the Yes button to validate this action. + + + + + + + +
+ + diff --git a/doc/kcontrol/filemanager/CMakeLists.txt b/doc/kcontrol/filemanager/CMakeLists.txt new file mode 100644 index 00000000..65689b05 --- /dev/null +++ b/doc/kcontrol/filemanager/CMakeLists.txt @@ -0,0 +1,2 @@ +########### install files ############### +kde4_create_handbook(index.docbook INSTALL_DESTINATION ${HTML_INSTALL_DIR}/en SUBDIR kcontrol/filemanager) diff --git a/doc/kcontrol/filemanager/index.docbook b/doc/kcontrol/filemanager/index.docbook new file mode 100644 index 00000000..0f638d54 --- /dev/null +++ b/doc/kcontrol/filemanager/index.docbook @@ -0,0 +1,61 @@ + + + +]> + +
+ +File Management + +&Mike.McBride; &Mike.McBride.mail; + + + +2009-12-18 +&kde; 4.4 + + +KDE +Systemsettings +file manager + + + +In these modules, you can configure various aspects of +&konqueror;'s file manager functionality. + +&konqueror;'s web browser functionality has its own configuration +modules. + + +<guilabel>Misc Options</guilabel> + +Open folders in separate windows + If this option is checked, a new +&konqueror; window will be created when you open a +folder, rather than simply showing that folder's contents in the + current +window. + + + +Show 'Delete' menu entries which +bypass the trashcan + +Check this if you want Delete menu commands to be +displayed on the desktop and in the file manager's context menus. +You can always delete files by holding the &Shift; key while calling +Move to Trash. + + + + +The settings for &konqueror;'s file manager mode on the View Modes, +Navigation, Services, General +and Trash pages are used by &dolphin; as well. + + +
diff --git a/doc/kcontrol/filetypes/CMakeLists.txt b/doc/kcontrol/filetypes/CMakeLists.txt new file mode 100644 index 00000000..e12793e3 --- /dev/null +++ b/doc/kcontrol/filetypes/CMakeLists.txt @@ -0,0 +1,2 @@ +########### install files ############### +kde4_create_handbook(index.docbook INSTALL_DESTINATION ${HTML_INSTALL_DIR}/en SUBDIR kcontrol/filetypes) diff --git a/doc/kcontrol/filetypes/index.docbook b/doc/kcontrol/filetypes/index.docbook new file mode 100644 index 00000000..36a31291 --- /dev/null +++ b/doc/kcontrol/filetypes/index.docbook @@ -0,0 +1,367 @@ + +Calligra Words"> + + +]> + +
+ + +File Associations + +&Mike.McBride; &Mike.McBride.mail; + + + +2013-12-05 +&kde; 4.12 + + +KDE +Systemsettings +files association +association + + + +File Associations + + +Introduction + +One of the most convenient aspects of &kde;, is its ability to +automatically match a data file with its application. As an example, +when you click on your favorite &calligrawords; document in the filemanager, &kde; +automatically starts &calligrawords;, and automatically loads that file into +&calligrawords; so you can begin working on it. + +In the example above, the &calligrawords; Data file is +associated with &calligrawords; (the application). These +file associations are crucial to the functioning of &kde;. + +When &kde; is installed, it automatically creates hundreds of file +associations to many of the most common data types. These initial +associations are based on the most commonly included software, and the +most common user preferences. + +Unfortunately, &kde; can not: + + +predict every possible combination of software and data files +prepare for file formats not yet invented +or predict everyone's favorite application for certain file formats + + +You can change your current file associations or add new file +associations using this module. + +Each file association is recorded as a mime type. +&MIME; stands for Multipurpose Internet Mail +Extensions. It allows a computer to determine the type of file, +without opening and analyzing the format of each and every file. + + + + +How to use this module + +You can start this module +by opening &systemsettings; and selecting File Associations in the +Common Appearance and Behavior category. Alternatively, you can start it by +typing kcmshell4 filetypes from the terminal or &krunner;. + +The file associations are organized into several categories, and +at a minimum you will have: + + +Application +Audio +Image +Inode +Message +Multipart +Text +Video + + +All of the file associations are sorted into one of these +categories. + +There is no functional difference between any of the +categories. These categories are designed to help organize your file +associations, but they do not alter the associations in any way. + + +The categories are listed in the box labeled Known +Types. + +You can explore each of these categories, and see the file +associations contained within each one, by simply double-clicking on the +category name. You will be presented with a list of the associated +mime-types under that category. + +You can also search for a particular &MIME; type by using the +search box. The search box is labeled Find file type or filename +pattern and is located above the category list. + +Simply type the first letter of the &MIME; type you are interested +in. The categories are automatically expanded, and only the mime-types +that include that letter are displayed. + +You can then enter a second character and the mime-types will be +further limited to mime types containing those two +characters. + + +Adding a new mime type + +If you want to add a new &MIME; type to your file associations, +you can click on the Add... button. A small +dialog box will appear. You select the category from the drop down +box labeled Group, and type the &MIME; name in the blank labeled Type +name. Click OK to add the new mime +type, or click Cancel to not add any new +mime-types. + + + + +Removing a mime type + +If you want to remove a &MIME; type, simply select the &MIME; +type you want to delete by clicking once with the mouse on the &MIME; +type name. Then click the button labeled +Remove. The &MIME; type will be deleted +immediately. + + + + +Editing a mime types properties + +Before you can edit a &MIME; types property, you must first +specify which &MIME; type. Simply browse through the categories until +you find the &MIME; type you want to edit, then click once on it with +the mouse. + +As soon as you have selected the &MIME; type, the current values of +the &MIME; type will appear in the module window. + +You will notice the current values are split into two tabs: +General and Embedding + + + +General + +There are 4 properties for each &MIME; type in this tab: + + +Mime Type Icon is the icon that +will be visible when using &dolphin; or &konqueror; as a file +manager. +Filename Patterns is a search +pattern which &kde; will use to determine the &MIME; type. +Description is a short description +of the file type. This is for your benefit only. +Application Preference Order +determines which applications will be associated with the specified +&MIME; type. + + + + + +Embedding Tab + +The Embedding tab allows you to determine if a file will be +viewed within a filemanager window, or by starting the +application. + + + + + + + +Changing the Icon + +To change the icon, simply click on the Icon button. A dialog box +will appear, which will show you all available icons. Simply click once +with the mouse on the icon of your choice, and click +OK. + + + + +Editing the mime-type patterns + +The box labeled Filename Patterns, determines +what files will be included within this mime-type. + +Usually, files are selected based on their suffix. (Examples: +Files that end with .wav are sound +files, using the WAV format and files that end in .c are program files written in C). + +You should enter your filename mask in this combo box. + +The asterisk (*) is a wildcard character that +will be used with nearly every mime type mask. A complete discussion +of wildcards is beyond the scope of this manual, but it is important +to understand that the asterisk (in this context), +matches any number of characters. As an example: +*.pdf will match +Datafile.pdf, Graphics.pdf +and User.pdf, but not PDF, +Datafile.PDF, or +.pdf. + +It is very beneficial to have multiple masks. One for lower +case, one for upper case, &etc; This will help ensure that &kde; can +determine the file type more accurately. + + + + +Editing a mime types description. + +You can type a short description of the &MIME; type in the text +box labeled Description. This label is to help +you, it does not affect the function of the &MIME; type. + + + + +Editing the application associations + +There are five buttons (Move Up, +Move Down, Add, Edit and +Remove) and a list box (which lists the +applications) which are used to configure the applications. + +The list box lists all of the applications associated with a +specific &MIME; type. The list is in a specific order. The top +application is the first application tried. The next application down +the list is the second, &etc; + +What do you mean there is more than one application per +&MIME; type? Why is this necessary? + +We started out by saying that &kde; comes preconfigured with +hundreds of file associations. The reality is, each system that &kde; +is installed on has a different selection of applications. By +allowing multiple associations per &MIME; type, &kde; can continue to +operate when a certain application is not installed on the +system. + +As an example: +For the &MIME; type pdf, there are two +applications associated with this file type. The first program is +called &okular;. If your system does not +have &okular; installed, then &kde; +automatically starts the second application &krita;. +As you can see, this will help keep &kde; running +strong as you add and subtract applications. + +We have established that the order is important. You can change +the order of the applications by clicking once with the mouse on the +application you want to move, and then clicking either Move +Up or Move Down. This will shift +the currently selected application up or down the list of +applications. + +You can add new applications to the list by clicking the button +labeled Add. A dialog box will appear. Using the +dialog box, you can select the application you want to use for this mime +type. Click OK when you are done, and the +application will be added to the current list. + +To change the options of an application for a particular &MIME; type +select it in the list and then press the Edit... button. +This opens a new dialog with General, +Permissions, Applications and +Preview tabs. +On the Applications tab you can edit Name, +Description and Comment. +In the Command field you can have several place holders +following the command, which will be replaced with the actual values +when the actual program is run: + +%f - a single file name +%F - a list of files; use for applications that can open several local files +at once +%u - a single URL +%U - a list of URLs +%d - the folder of the file to open +%D - a list of folders +%i - the icon +%m - the mini-icon +%c - the caption + + +You can remove an application (thereby ensuring that the +application will never run with this &MIME; type by clicking once on the +name of the application, and clicking the Remove +button. + +It is a good idea to use the Move Up +and Move Down buttons to adjust the unwanted +application to a lower position in the list, rather than deleting the +application from the list entirely. Once you have deleted an +application, if your preferred application should become compromised, +there will not be an application to view the data document. + + + + +Embedding +These settings are valid only for &konqueror; used as file manager, &dolphin; +is not able to use embedded views and opens a file always in the associated application. +By clicking on the Embedding tab, you are +presented with four radio buttons in the Left click +action group. These determine how the filemanager views the selected +&MIME; type: + + +Show file in embedded viewer +If this is selected, the file will be shown within the filemanager window. +Show file in separate viewer +This will cause a separate window to be created when showing this mime-type. +Use settings for 'application' group +This will cause the mime-type to use the settings for the mime-type group. +(if you are editing an audio mime type, then the settings for the audio group are used). +Ask whether to save to disk instead +This setting applies only to &konqueror; in browser mode and determines +if the file is shown in an embedded viewer or if you are asked to save the file to disk instead. + + +Below this is a listbox labeled Services Preference +Order. + +When you use a filemanager like &dolphin; or &konqueror;, you can +right mouse click, and a menu will with an +entry labeled Open with... will appear. This box +lists the applications that will appear, in the order they will +appear, under this menu. + +You can use the Move Up and +Move Down buttons to change the order. + + + + +Making changes permanent + +When you are done making any changes to mime types, you can click +Apply to make your changes permanent, but keep +you in this module. + + + + + + +
diff --git a/doc/kcontrol/history/CMakeLists.txt b/doc/kcontrol/history/CMakeLists.txt new file mode 100644 index 00000000..fcd8d597 --- /dev/null +++ b/doc/kcontrol/history/CMakeLists.txt @@ -0,0 +1,2 @@ +########### install files ############### +kde4_create_handbook(index.docbook INSTALL_DESTINATION ${HTML_INSTALL_DIR}/en SUBDIR kcontrol/history) diff --git a/doc/kcontrol/history/index.docbook b/doc/kcontrol/history/index.docbook new file mode 100644 index 00000000..ffc074d4 --- /dev/null +++ b/doc/kcontrol/history/index.docbook @@ -0,0 +1,62 @@ + + + +]> +
+History Sidebar + + +&Burkhard.Lueck; + + + +2009-11-24 +&kde; 4.4 + + +KDE +Systemsettings +history + + + + +This dialog allows you to configure the history sidebar. + + + +Limits + +The options in this section can be used to set the maximum size of your history and set a time after which +items are automatically removed. + + + + +Custom Font + +Here you can also set different fonts for new and +old &URL;s by selecting the Choose Font button. + + + + +Details + +The Detailed tooltips check box controls how much +information is displayed when you hover the mouse pointer over an item in the +history page. +If checked the number of times visited and the dates of the first and last +visits are shown, in addition to the URL. + + + + +Selecting Clear History will +clear out the entire history. + +
diff --git a/doc/kcontrol/icons/CMakeLists.txt b/doc/kcontrol/icons/CMakeLists.txt new file mode 100644 index 00000000..9629f320 --- /dev/null +++ b/doc/kcontrol/icons/CMakeLists.txt @@ -0,0 +1,2 @@ +########### install files ############### +kde4_create_handbook(index.docbook INSTALL_DESTINATION ${HTML_INSTALL_DIR}/en SUBDIR kcontrol/icons) diff --git a/doc/kcontrol/icons/delete-theme.png b/doc/kcontrol/icons/delete-theme.png new file mode 100644 index 00000000..8421b7e5 Binary files /dev/null and b/doc/kcontrol/icons/delete-theme.png differ diff --git a/doc/kcontrol/icons/effects.png b/doc/kcontrol/icons/effects.png new file mode 100644 index 00000000..78f27292 Binary files /dev/null and b/doc/kcontrol/icons/effects.png differ diff --git a/doc/kcontrol/icons/get-new-theme.png b/doc/kcontrol/icons/get-new-theme.png new file mode 100644 index 00000000..a6ba6fe7 Binary files /dev/null and b/doc/kcontrol/icons/get-new-theme.png differ diff --git a/doc/kcontrol/icons/index.docbook b/doc/kcontrol/icons/index.docbook new file mode 100644 index 00000000..eaec490e --- /dev/null +++ b/doc/kcontrol/icons/index.docbook @@ -0,0 +1,354 @@ + + + +]> + +
+ +Icons + +&Mike.McBride; &Mike.McBride.mail; +&Jost.Schenck; &Jost.Schenck.mail; +&Anne-Marie.Mahfouf; &Anne-Marie.Mahfouf.mail; + + + +2013-12-05 +&kde; 4.12 + + +KDE +KControl +icon + + + +Icons + + +Introduction + +&kde; comes with a full set of icons in several sizes. These icons +are being used all over &kde;: the desktop, the panel, the &konqueror; file +manager, in every toolbar of every &kde; application, etc. The icons +control module offers you very flexible ways of customizing the way &kde; +handles icons. + + + +Here's a screenshot of the icon theme manager + + + + + + Customizing &kde; icons + + + + + +In this module you can: + +install and choose icon themes +choose different icon sizes +assign effects to icons (for example make them +semi-transparent or colorize them) +configure these settings for each of the different places +icons will be used in: for example the desktop, toolbars &etc; + + + +Please note that some of these settings may depend on +your selected icon theme. &kde; comes with three icon themes by default, +Oxygen, Monochrome and Crystal SVG. There are additional color themes +in the kdeartwork package. + +There are two pages in this module: Theme and Advanced. Theme manages the icon themes while Advanced lets you configure how icons will be used in &kde;. + + + +Theme + +At the top is a preview of the current theme icons. Most default +installations will have only one icon theme available, the &kde; default +Oxygen theme. There are other themes contained separately in the +kdeartwork package, and you can also download more from the Internet from http://www.kde-look.org. + + +Get New Themes... + + +You need to be connected to the Internet to use it. Clicking on this button will display a dialog where you can choose a new icon theme. Clicking on Install in the dialog will install the chosen icon theme and after you Close the installer your new theme is immediately available. + + + +Get New Icon Themes + + + + + + Get New Icon Themes + + + + + + +Install Theme File... + + +If you dowloaded new themes from the internet, you can use this to browse to the +location of those newly downloaded themes. Clicking on this button will bring you a small dialog to point to the icon theme tarball you have on your disk. + + +Installing A New Icon Theme + + + + + + Installing A New Icon Theme + + + + +Clicking OK in this dialog will install the theme you pointed to and make it available in the theme list. + + + +Remove Theme + + +Clicking this button will remove all files for this theme from your system. A confirmation message is displayed and will ask you if you are really sure you want to remove all the files for this theme. + + + +Removing A Theme + + + + + + Removing A Theme + + + + +Clicking Delete will remove the theme files and clicking Cancel will not delete anything and will cancel the remove action. + + + + + + + + +Advanced + +Looking at this second page of the icons control module, you +will see two areas: + + + +An area labelled Use of Icon. Here you can +choose which particular usage of icons you want to configure, for +example Toolbar or Panel. + + + +Choosing the icons to configure + + + + + + Choosing the icons to configure + + + + + + + A preview area where you can see how +icons of the selected kind will look using the current +settings. Note that the state of this preview also depends on the icon +state selected in the effects below (do not worry +about that now, we will explain that below). + + +When you want to configure icons, first select the usage of icons +you want to configure. Change the settings until you like the +preview. You can then choose a different icon usage and configure +that. At the end, if you are satisfied with your settings, click +OK or Apply to take the +changes in effect. + +There are two further options to consider, +Size and Effects. + + +Icon Size + + + +Setting icons sizes + + + + + + Setting icons sizes + + + + + +You can choose +from a list of icon sizes. The largest icon sizes are especially useful +for visually impaired people. + +Which sizes will be offered by the icon size listbox depends on +the icon theme you have selected in the icon themes control module. For +example, the low color icon theme only offers the sizes 16 and 32 for +desktop icons and 16, 22 and 32 for toolbar icons. The HiColor theme +offers icon sizes 16, 32 and 48 as well as sizes from 64 to 128. +However, as &kde; can not have all these icon sizes in store, icons +using size 64 to 128 will be automatically generated which may result in +a loss of quality. + + + +You can also choose animated icons. Many of the icons have +animations associated with them. Enable the checkbox labelled +Animate Icons, to enable this effect, but note +that it may appear slow or jerky if your graphics card is old or you +are low on memory. + + + + +Effects + + +Setting icons effects + + + + + + Setting icons effects + + + + + +Finally you can configure certain filters to be +applied on icons which are in one of three states: + + + +Default +This is how the icon will look normally. + + +Active: +This is how the icon will look when the mouse cursor is over the icon. + + +Disabled: +This is how the icon will look if its corresponding action is +disabled, &ie; clicking on it will not lead to any +result. + + + +Select one of these states, and press the Set +Effect... button to configure a corresponding icon effect. +Please note that this configuration will only affect icons of the +currently selected Use of Icon category (see +above): configuring an effect for active icons, while +Toolbar icon usage is selected, will +not affect active icons used in other +places. + +Below the list of icon states there are two options: you can +configure an effect and you can select the +Semi-transparent option, which will make the +background shine through the icon. To the right of the +effects list box there is a slider button to pass additional parameters to +a filter for colours and Amount. + + +The following effects can be applied to icons: + + + +No Effect: +Icons will be used without applying any +effect. + + +To Gray: +This filter will apply a grayish look to the icon. Use the +Amount slider to configure the intensity of this filter. Note +that it is customary for most user interfaces to use this effect for disabled +icons only. + + +Colorize: +Icons will be colorized using a custom color. For example, you +may configure active icons (&ie; the icon the mouse cursor is over) to +shine golden. Use the color buttons and the Amount slider +to configure the used color and the intensity of the colorization. + + +Gamma: +A different gamma value will be applied to all icons. If you're +no photographer and don't know what Gamma is: it's quite similar to what people +call contrast. Just play around with the gamma settings by moving the +Amount slider to get a feeling for this +effect. + + +Desaturate: +Icons will be drawn desaturated. This is quite similar to the +Color setting on your television. Use the slider to configure +the amount of desaturation. + + + +To Monochrome: + +Icons will be drawn using only the two colours selected. + + + + + + + + + + + +
diff --git a/doc/kcontrol/icons/install-theme.png b/doc/kcontrol/icons/install-theme.png new file mode 100644 index 00000000..fbe5316d Binary files /dev/null and b/doc/kcontrol/icons/install-theme.png differ diff --git a/doc/kcontrol/icons/main.png b/doc/kcontrol/icons/main.png new file mode 100644 index 00000000..bae9e469 Binary files /dev/null and b/doc/kcontrol/icons/main.png differ diff --git a/doc/kcontrol/icons/size.png b/doc/kcontrol/icons/size.png new file mode 100644 index 00000000..599c162b Binary files /dev/null and b/doc/kcontrol/icons/size.png differ diff --git a/doc/kcontrol/icons/use-of-icons.png b/doc/kcontrol/icons/use-of-icons.png new file mode 100644 index 00000000..5132bcc9 Binary files /dev/null and b/doc/kcontrol/icons/use-of-icons.png differ diff --git a/doc/kcontrol/kcm_ssl/CMakeLists.txt b/doc/kcontrol/kcm_ssl/CMakeLists.txt new file mode 100644 index 00000000..ce2344b7 --- /dev/null +++ b/doc/kcontrol/kcm_ssl/CMakeLists.txt @@ -0,0 +1,2 @@ +########### install files ############### +kde4_create_handbook(index.docbook INSTALL_DESTINATION ${HTML_INSTALL_DIR}/en SUBDIR kcontrol/kcm_ssl) diff --git a/doc/kcontrol/kcm_ssl/details.png b/doc/kcontrol/kcm_ssl/details.png new file mode 100644 index 00000000..f4131b3a Binary files /dev/null and b/doc/kcontrol/kcm_ssl/details.png differ diff --git a/doc/kcontrol/kcm_ssl/index.docbook b/doc/kcontrol/kcm_ssl/index.docbook new file mode 100644 index 00000000..f74d0cac --- /dev/null +++ b/doc/kcontrol/kcm_ssl/index.docbook @@ -0,0 +1,134 @@ + + + +]> +
+SSL Versions and Certificates + + +Subhashish Pradhan +&TC.Hollingsworth; &TC.Hollingsworth.mail; + + + +2013-12-05 +&kde; 4.12 + + +KDE +Systemsettings +SSL +certificates + + + + +Introduction +&kde; provides a list of all the X.509 certificates used by the system. They +can be accessed in the SSL Preferences module in +&systemsettings;. + +This module provides a categorized listing of all SSL versions and +certificates. You can see the details of each of the certificates and add, delete, +disable, or enable them. + +The certificates are categorized into System certificates +and User-added certificates. The System +certificates are further categorized by the organization that issued +them. + + +The SSL Versions and Certificates Module + + +The SSL Versions and Certificates module. + + + + +Viewing the Details of a Certificate + +Select a certificate under a listed organization, and click on the +Display underneath the list to view the details of the +certificate. + + +Viewing the Details of a Certificate + + +The certificate details window. + + + + + + +Enabling or Disabling a Certificate + +First, select a certificate listed under an organization. Then, click the +Enable button to enable the certificate, or click the +Disable button to disable an enabled certificate. + +Alternatively, you can enable or disable a certificate by selecting or +clearing the check box before the certificate. + + +You can enable or disable multiple certificates by selecting them while +holding the &Ctrl; key and then clicking on the Enable or +Disable button below the list. + + + + + +Adding a Certificate + + +First, click on the Add button below the certificate +list. It will open the file selector dialog allowing you to locate where the +certificate files are stored. After locating the certificate file, select it +and click on the Open button to add it. + + +The certificates must be in one of the following formats: +DER, PEM, or &Netscape;-encoded X.509 +certificate. + + + + + +Removing a Certificate + +Select the listed certificate that you want to remove, and click the +Remove button to remove the certificate. + + +System certificates cannot be removed. + + + + + +Thanks and Acknowledgments + +Special thanks to Google Code-In 2011 participant Subhashish Pradhan for +writing this article. + + + + + +
+ + diff --git a/doc/kcontrol/kcm_ssl/module.png b/doc/kcontrol/kcm_ssl/module.png new file mode 100644 index 00000000..80253e23 Binary files /dev/null and b/doc/kcontrol/kcm_ssl/module.png differ diff --git a/doc/kcontrol/kcmcgi/CMakeLists.txt b/doc/kcontrol/kcmcgi/CMakeLists.txt new file mode 100644 index 00000000..44b16910 --- /dev/null +++ b/doc/kcontrol/kcmcgi/CMakeLists.txt @@ -0,0 +1,2 @@ +########### install files ############### +kde4_create_handbook(index.docbook INSTALL_DESTINATION ${HTML_INSTALL_DIR}/en SUBDIR kcontrol/kcmcgi) diff --git a/doc/kcontrol/kcmcgi/index.docbook b/doc/kcontrol/kcmcgi/index.docbook new file mode 100644 index 00000000..8958aca0 --- /dev/null +++ b/doc/kcontrol/kcmcgi/index.docbook @@ -0,0 +1,44 @@ + + + +]> + +
+ + +CGI Scripts + +BurkhardLück +lueck@hube-lueck.de + + + + +2009-11-20 +&kde; 4.4 + + +KDE +Systemsettings +cgi + + + + +The CGI KIO slave lets you execute local CGI programs +without the need to run a web server. + +In this system settings module you can +configure the paths that are searched for CGI scripts. + + +Paths to CGI scripts are displayed in the list box at the +bottom of this dialog. + + +Use the buttons below the list box to add or remove paths from the search. + + +
diff --git a/doc/kcontrol/kcmcss/CMakeLists.txt b/doc/kcontrol/kcmcss/CMakeLists.txt new file mode 100644 index 00000000..f2c5b585 --- /dev/null +++ b/doc/kcontrol/kcmcss/CMakeLists.txt @@ -0,0 +1,2 @@ +########### install files ############### +kde4_create_handbook(index.docbook INSTALL_DESTINATION ${HTML_INSTALL_DIR}/en SUBDIR kcontrol/kcmcss) diff --git a/doc/kcontrol/kcmcss/index.docbook b/doc/kcontrol/kcmcss/index.docbook new file mode 100644 index 00000000..050a72ab --- /dev/null +++ b/doc/kcontrol/kcmcss/index.docbook @@ -0,0 +1,367 @@ + + + +]> + +
+ +Appearance + +&Lauri.Watts; &Lauri.Watts.mail; + + + +2009-12-01 +&kde; 4.4 + + +KDE +CSS +Appearance +Font +CSS +Stylesheets +Accessibility + + + + + +Appearance +This module consists of three tabs with configure options how to display web pages. + + +General + +The check box labeled Automatically load +images allows you to control whether images on web pages are +loaded by default. Unless you have a very slow connection, you will +probably want to leave this option selected, as there are many web pages +that are difficult to use without images. If you don't select the option +to automatically load images, you can still view the text on the page, +and then load the images if you need them. + +If Draw frame around not completely loaded images +is checked, &konqueror; will draw a frame as a placeholder +around images embedded in a web page that are not yet fully loaded. You +will probably want to check this box to enhance your browsing experience, +especially if have a slow network connection. + +Many web pages use animated gif images, and these can be very +annoying, and in some cases, quite a drain on your system resources. +The Animations option lets you choose when +animations are enabled. The default is enabled, but you can set this +to disabled, or to run the animation only once, even if the file +itself contains instructions that the animation should run more times, +or continuously. + +The next setting is Underline links:. You can +choose to underline links Enabled. If this option +is selected, any text on web pages that acts as a link will be shown in +an underlined font. While many web pages do use color to distinguish +text that acts as a link, underlining makes it very easy to spot +links. + +If you don't like underlined links, you can choose +Disabled, so that no links are underlined. Or you +can choose a middle ground, Only on Hover, so that links +are underlined when the mouse cursor is resting over them, and not +underlined the rest of the time. + +The site's CSS definitions can override this value. + +Smooth scrolling +determines whether &konqueror; should use smooth steps to scroll &HTML; +pages, or whole steps: + +Always: Always use smooth steps +when scrolling. +Never: Never use smooth scrolling, scroll +with whole steps instead. +When Efficient: Only use smooth +scrolling on pages where it can be achieved with moderate usage of system +resources. + + + + + + +Fonts +Under this tab, you can select various options related to the use +of fonts. Although the shapes and sizes of fonts are often part of the +design of a web page, you can select some default settings for +&konqueror; to use. + +The first thing you can set here is the font size. There are two +settings which work together to allow you a comfortable browsing +experience. + +Firstly, you can set a Minimum font size. +This means, even if the font size is set specifically in the page you +are viewing, &konqueror; will ignore that instruction and never show +smaller fonts than you set here. + +Next you can set a Medium font size. This is +not only the default size of text, used when the page does not specify +sizes, but it is also used as the base size that relative font sizes are +calculated against. That is, the &HTML; instruction +smaller, it means smaller than the size you set for this +option. + +For either option, you can select the exact font size in points by +using the up/down spin control (or just typing) next to the option +label. + +These options are independent of each other. Pages that do not +set a font size, or ask for the default, will display with the size +you set from Medium font size, while any pages +that ask for a size smaller than your Minimum font +size setting will instead show that size. The one does not +affect the other. + +The remaining options are for the fonts to be associated with +different types of markup used in &HTML; pages. Note +that many web pages may override these settings. For any type of font +(Standard, Fixed, Serif, &etc;) you can select a different font if you like. + +Below this, you can set a Font size adjustment for this +encoding. Sometimes the fonts you want to use for a +particular encoding or language are much larger or smaller than average, +so you can use this setting to bring them into line. + +You can set a default encoding that &konqueror; should assume +pages are when rendering them. The default setting is Use +Language Encoding, but you can change it to any encoding +available in the list. + + + + + +Stylesheets + + +Introduction + +CSS style sheets affect the way web pages +appear. CSS stands for +Cascading Style +Sheets. + +&kde; can use its own stylesheet, based on simple defaults and +the color scheme you are using for your desktop. &kde; can also use a +stylesheet that you have written yourself. Finally, you can specify a +stylesheet in this module. The options presented in this module are +tuned for accessibility purposes, especially for people with reduced +vision. + +Your choices here affect every &kde; application that renders HTML +with &kde;'s own renderer, which is called khtml. These include +&kmail;, &khelpcenter; and of course &konqueror;. Choices here do not +affect other browsers such as &Netscape;. + + + + +Stylesheets + +This section contains the following options: + + + +Use default stylesheet + +&kde; will use the default stylesheet. Some of the colors will +default to those defined in your chosen color scheme. Most settings are +easily overridden by the page you are viewing. + + + + +Use user-defined stylesheet + +&kde; will use a stylesheet that you have written yourself. You +can use the browse button to locate the stylesheet on your system. +CSS files traditionally have a .css extension, but this is not +required. + + + + +Use accessibility stylesheet + +Use the settings defined in the Customize +dialog. Enabling this option will enable the Customize +button lo launch a dialog to define stylesheet settings. + + + + + + + +Customize + +In this dialog you can set up a user stylesheet. The options available are +only a subset of the instructions you can add in a stylesheet, and they +are geared towards people with reduced vision, to allow users to create +a stylesheet that makes web pages and the &kde; help files more +readable. + +The options in this dialog are disabled unless you chose +Use accessibility stylesheet. + + +<guilabel>Font Family</guilabel> + + + +Base family + +Choose a font family to use for body text. + + + + +Use same family for all text + +If you enable this, then the same font family will be used for all +text, regardless of the settings on the page you are viewing. This is +useful for pages which have used a decorative or hard to read font for +headlines. + + + + + + +Font Size + + + +Base font size + +This is the default size for text on the page. Many web sites set +their font sizes relative to this default, using larger +or +1 to make the text bigger, and smaller +or -1 to make the text smaller. +Many people design their web pages on platforms where the ordinary +default text size is too large for the average user to read, so it is +very common to come across web pages that have forced the font smaller +in this way. +This setting will allow you to set the default font to a +comfortable size, so that the relative sizes are also enlarged enough to +be comfortable. +Do not forget you can also have &konqueror; enforce a minimum size, +so that text is never too small to read. + + + + + + +Use same size for all elements + +If you enable this option, then all text will be rendered at your +specified font size, regardless of the instructions the page contains. +Relative font sizes as discussed earlier, and even specific instructions +that text should be rendered at a certain size will be overridden +here. + + + + + + +Images + + + +Suppress images + +If you do not want to view images, you can turn this off +here. + + + +Suppress background images + +One major problem for reduced vision users is that background +images do not give sufficient contrast to allow them to read the text. +You can disable background images here, independently of your choice +above to view all images. + + + + + + +Colors + + + +Black on white + +Many people with reduced vision find black text on a white screen +gives the most contrast, and is easiest to read. If this applies to +you, you can set this here. + + + + +White on black + +Many other people with reduced vision find the opposite to be +true, that white text on a black screen is easier to read. + + + + +Custom + +Still other people find that pure black and white, in either +order, is difficult to read. You can set custom colors here for both +the Background and the +Foreground. + + + + +Use same color for all text + +Many web sites use a different, often contrasting color for +headings or other flourishes. If this interferes with your ability to +read the content, you can enable this check box to have &kde; use the +colors you have set above for all text. + + + + + + + +Preview + +The Preview section allows you to see the effect of +your changes. Several types of headings are displayed with your stylesheet, +and a sentence in the default body text. + +This should allow you to fine-tune your stylesheet until you have +something that you can comfortably read. + +Happy surfing! + + + + + + + + + +
diff --git a/doc/kcontrol/kcmlaunch/CMakeLists.txt b/doc/kcontrol/kcmlaunch/CMakeLists.txt new file mode 100644 index 00000000..12f7ee5f --- /dev/null +++ b/doc/kcontrol/kcmlaunch/CMakeLists.txt @@ -0,0 +1,2 @@ +########### install files ############### +kde4_create_handbook(index.docbook INSTALL_DESTINATION ${HTML_INSTALL_DIR}/en SUBDIR kcontrol/kcmlaunch) diff --git a/doc/kcontrol/kcmlaunch/index.docbook b/doc/kcontrol/kcmlaunch/index.docbook new file mode 100644 index 00000000..68d3e352 --- /dev/null +++ b/doc/kcontrol/kcmlaunch/index.docbook @@ -0,0 +1,59 @@ + + + +]> + +
+ +Launch Feedback + +&Lauri.Watts; &Lauri.Watts.mail; + + + +2013-12-05 +&kde; 4.12 + + + +Sometimes it is reassuring to know that your computer didn't just +ignore your command, and something is happening behind the scenes. In +this module you can configure visible feedback to help you know if you +really hit that icon or not. + +The traditional way to indicate that your computer is busy is to +modify the cursor, and you can turn this on by choosing a +Busy Cursor. + +With this option enabled, your cursor will have an icon attached +to it for a short time, when a new application is being launched. You +can configure how long this icon is displayed beside your cursor with the +Startup indication timeout: spinbox. The +default is 10 seconds. + +There are several variations of busy cursor available, including +a Blinking Cursor, a Bouncing Cursor +or a Passive Busy Cursor icon with no animation. + +Traditional &kde; launch notification has taken another form, +which you can also enable and disable here. Normally when you start an +application, it gets an immediate entry in the taskbar, with the icon +replaced by a spinning hourglass to let you know something is +happening. You can toggle this behavior on and off with the +Enable taskbar notification checkbox, and when it's +enabled, you can set a time in the +Startup indication timeout spinbox. + +Not all applications that you start will eventually show a +window, or an entry in the taskbar. Some of them, for example, are +docked into the &kde; system tray. Alternatively, it might be that you +sent it off to a different virtual desktop, and in the Filters +section of the +Task Manager Settings the option Only show +tasks from the current desktop is checked. Setting a timeout ensures that, +even in these cases, you can still get launch feedback, but also that +it will go away when the job is done. + +
diff --git a/doc/kcontrol/kcmnotify/CMakeLists.txt b/doc/kcontrol/kcmnotify/CMakeLists.txt new file mode 100644 index 00000000..446889dc --- /dev/null +++ b/doc/kcontrol/kcmnotify/CMakeLists.txt @@ -0,0 +1,2 @@ +########### install files ############### +kde4_create_handbook(index.docbook INSTALL_DESTINATION ${HTML_INSTALL_DIR}/en SUBDIR kcontrol/kcmnotify) diff --git a/doc/kcontrol/kcmnotify/index.docbook b/doc/kcontrol/kcmnotify/index.docbook new file mode 100644 index 00000000..a1726040 --- /dev/null +++ b/doc/kcontrol/kcmnotify/index.docbook @@ -0,0 +1,159 @@ + + + +]> + +
+System Notification Settings + + + +&Mike.McBride; &Mike.McBride.mail; + + + +2013-12-05 +&kde; 4.12 + + +KDE +Systemsettings +system notification +notification + + + + +System Notification Settings + +&kde;, like all applications, needs to inform the user when a +problem occurs, a task is completed, or something has happened. &kde; +uses a set of System Notifications to keep the user +informed on what is happening. + +Using this module, you can determine what &kde; does to communicate +each event. + +This settings module consists of the two tabs Applications +and Player Settings. + + +Applications +To configure a notification, simply select the application from the drop down box at the top +of the dialog labeled Event source:. This will lead to a list of +all configurable notifications for the application. The list of notifications includes 6 columns to +the left of the notification name. These columns (from left to right) are: + + + +Play a sound +This does exactly what you think it does. If an icon is present in this column, &kde; will play a specific sound over the speakers. This is commonly used by games in &kde; for starting a new game, or other action within the game. + + + +Show a message in a pop up +If an icon is present in this column, &kde; will open a message box and inform the user of the notification. This is probably the most commonly selected option for alerting users to an error. + + + +Log to a file +If an icon is present in this column, &kde; will write certain information to a file on disk for later retrieval. This is useful for tracking problems or important system changes. + + + +Mark taskbar entry +If an icon is present in this column, &kde; will cause the taskbar to flash until the user has clicked the taskbar entry. This is most useful when you want the user to look at the program (such as a new email message was received, or the users name was said on an IRC channel). + + + +Speech +If a mark is in this checkbox, &kde; will cause the taskbar of the program sending the notification to flash until the user has clicked the taskbar entry. + + + + +Run command +If an icon is present in this column, a separate program will be executed when this notification is performed. This can be used to execute a program to help restore data, shutdown a potentially compromised system or email another user to alert them to a problem. + + + + +Change a notification +To make a change to a notification, click on the name of the notification once with the &LMB;. The notification will be highlighted +and the checkboxes for all notification types are enabled. + +You can have more than one event triggered by a single notification. As an example, it is easy to have a sound played and +a message box appear in response to a system notification. One notification does not prevent other notifications from operating. + +The following list details each of the notification types and how to use them. + + + +Play a sound +If a mark is in this checkbox, &kde; will play a sound everytime this notification is initiated. To specify the sound, use the text box to the right of the checkbox to enter the folder location of the sound file you want &kde; to play. You can use the folder button (located to the far right of the dialog box) to browse your directory tree. To hear a test of your sound, simply click on the play button (small button directly to the right of Play a sound.) + + + +Show a message in a pop up +If a mark is in this checkbox, &kde; will open a message box and inform the user of the notification. The text of the box can not be changed from this dialog. + + + +Log to a file +If a mark is in this checkbox, &kde; will write certain information to a file on disk for later retrieval. To specify the log file to use, enter the pathname in the text box to the right of the checkbox. You can use the folder button (located to the far right of the dialog box) to browse your directory tree. + + + +Mark taskbar entry +If a mark is in this checkbox, &kde; will cause the taskbar of the program sending the notification to flash until the user has clicked the taskbar entry. + + + +Run command +If a mark is in this checkbox, a separate program will be executed when this notification is performed. To specify the program to execute, enter the pathname in the text box to the right of the checkbox. You can use the folder button (located to the far right of the dialog box) to browse your directory tree. + + + +Speech +If a mark is in this checkbox, &kde; will use Jovie to speak the event +message, event name or custom text. +If you select Speak Custom Text, enter the text in the box. +You may use the following +substitution strings in the text: + + %e Name of the event + %a Application that sent the event + %m Message sent by the application + + + + + +You can use the icon columns (located to the left of the notifications) to quickly select or deselect the options. Clicking in the column with the &LMB; will toggle the notification on and off. + + + + +Player Settings + + + +Use the &kde; sound system +If a mark is in this radio button, &kde; will play all sound notifications through the &kde; sound system. You can adjust the volume of system notifications using the slider. +The slider only affects &kde; system notifications. Changes to this slider will not affect other sounds on your computer. + + +Use an external player +If a mark is in this radio button, &kde; will not use the &kde; sound system to play the sound. This is a good choice if the sound format you want to use is not supported by the &kde; notification system. After checking the radio box, enter the full path and name of the program you want to use into the text field. You can use the folder button (located along the right side) to browse the directory tree. + + +No audio output +Disables all sound notifications. + + + + + +
diff --git a/doc/kcontrol/kded/CMakeLists.txt b/doc/kcontrol/kded/CMakeLists.txt new file mode 100644 index 00000000..101c29b8 --- /dev/null +++ b/doc/kcontrol/kded/CMakeLists.txt @@ -0,0 +1,2 @@ +########### install files ############### +kde4_create_handbook(index.docbook INSTALL_DESTINATION ${HTML_INSTALL_DIR}/en SUBDIR kcontrol/kded) diff --git a/doc/kcontrol/kded/index.docbook b/doc/kcontrol/kded/index.docbook new file mode 100644 index 00000000..b63668ac --- /dev/null +++ b/doc/kcontrol/kded/index.docbook @@ -0,0 +1,64 @@ + + + +]> + +
+ + +Service Manager + +BurkhardLück +lueck@hube-lueck.de + + + + +2013-12-05 +&kde; 4.12 + + +KDE +Systemsettings +Service + + + + +The Service Manager module allows you to have an overview of all +plugins of the &kde; Daemon, also referred to as &kde; Services. Generally, +there are two types of service: + + + + +Load-on-Demand Services + +This is a list of available &kde; services which will be started on demand. +They are only listed for convenience, as you cannot manipulate these +services. + + + + +Startup Services + +This shows all &kde; services that can be loaded on &kde; startup. +Services checked in the Use column will be invoked on next startup. +Be careful with deactivation of +unknown services: some services are vital for &kde;; do +not deactivate services if you do not know what you are doing. + +To change the Status of a service, select it in the list. +Then you can use the Start and Stop +to change the status of a service from Not running to Running +and vice versa. + + + + + + +
diff --git a/doc/kcontrol/khtml-adblock/CMakeLists.txt b/doc/kcontrol/khtml-adblock/CMakeLists.txt new file mode 100644 index 00000000..c50b0f11 --- /dev/null +++ b/doc/kcontrol/khtml-adblock/CMakeLists.txt @@ -0,0 +1,2 @@ +########### install files ############### +kde4_create_handbook(index.docbook INSTALL_DESTINATION ${HTML_INSTALL_DIR}/en SUBDIR kcontrol/khtml-adblock) diff --git a/doc/kcontrol/khtml-adblock/index.docbook b/doc/kcontrol/khtml-adblock/index.docbook new file mode 100644 index 00000000..e153d5f4 --- /dev/null +++ b/doc/kcontrol/khtml-adblock/index.docbook @@ -0,0 +1,90 @@ + + + + +]> + +
+ +AdBlocK Filters + +&Krishna.Tateneni; &Krishna.Tateneni.mail; + + + +2011-11-22 +&kde; 4.8 + + +&konqueror; AdBlocK can be configured to replace or remove +images or frames from web pages that match a series of filters. + +The setting Enable filters enables or +disables the use of list of URL filters. +If Hide filtered images is enabled then +blocked images are completely removed from the page and the space they +occupied is reclaimed. If the option is disabled then a placeholder +image is used in place of filtered images. + + + +Manual Filter + +The main part of this tab is a list of +URLs that will be compared against image and frame names to decide +on fitlering actions. The wildcards can be given as filename style +regular expressions. + +Use the Search edit box above the list box +to filter matching entries an the fly. + +Each filter can either be expressed as a file style wildcard +string (e.g. http://www.site.com/ads/*) or as a full regular expression +by enclosing the filter with forward slashes (e.g. //(ads|dclk)\./). + +Any filter string can be preceded by @@ to whitelist +(allow) any matching &URL;, which takes priority over any blacklist (blocking) +filter. + +Import and Export will +save or read the current filter list to a plain text file. The file begins with a +header line [AdBlock], then all of the filters follow each +on a separate line. Lines prefixed with an exclamation mark (!) +and the header line are treated as comments and can be used +to clarify or label a set of filters. + +Highlight an entry from the list to change it in the edit box or remove this item. +Enter a new filter string here and add it to the list using the +Insert button. + + + + +Automatic Filter + + +This tab shows a list of names and &URL;'s with predefined AdBlock filter entries. +To enable an entry tick the checkbox beside the filter name and adjust the +Automatic update interval (default 7 days). + + + + + + + +If AdBlock filters are enabled, an icon at the right side of status bar is shown. +Use a &RMB; click on this icon to open the context menu with actions to show all blockable +elements on a web page, open this &systemsettings; module and disable blocking for a site +or page temporarily. + +A click with the &LMB; shows the dialog with all blockable elements on the opened web page +as well. From this dialog you can add new filters directly without opening this &systemsettings; +module. + +
diff --git a/doc/kcontrol/khtml-behavior/CMakeLists.txt b/doc/kcontrol/khtml-behavior/CMakeLists.txt new file mode 100644 index 00000000..71ad7fbb --- /dev/null +++ b/doc/kcontrol/khtml-behavior/CMakeLists.txt @@ -0,0 +1,2 @@ +########### install files ############### +kde4_create_handbook(index.docbook INSTALL_DESTINATION ${HTML_INSTALL_DIR}/en SUBDIR kcontrol/khtml-behavior) diff --git a/doc/kcontrol/khtml-behavior/index.docbook b/doc/kcontrol/khtml-behavior/index.docbook new file mode 100644 index 00000000..f101feac --- /dev/null +++ b/doc/kcontrol/khtml-behavior/index.docbook @@ -0,0 +1,96 @@ + + + + +]> + +
+ +Web Browsing + +&Krishna.Tateneni; &Krishna.Tateneni.mail; + + + +2011-11-11 +&kde; 4.10 + + +KDE +Systemsettings +konqueror +browsing + + + + +Web Browsing + +The &konqueror; Browser module of &systemsettings; allows you to select +various options for the behavior of &konqueror;, the +integrated web browser of &kde;. + +If Ask for name and folder when adding bookmarks +is checked, &konqueror; will allow you to change the title of the +bookmark and choose a folder in which to store it when you add a new +bookmark. + +Enable Show only marked bookmarks in bookmark toolbar +and &konqueror; will show only those bookmarks in the +bookmark toolbar which you have marked to do so in the bookmark editor. + +The next option you can enable on this page is Form +Completion. If you check this box, &konqueror; will +try to remember what you answer to form questions, and will try to fill +in forms for you with the answers you previously used. + +You can configure the number of form items &konqueror; remembers +with the spin box labelled Maximum +completions + +Of course, anything &konqueror; fills in a form with, you +can still edit before submitting the form! + +The next option is Change cursor over +links. If this option is selected, the shape of the cursor +will change (usually to a hand) whenever it moves over a +hyperlink. This makes it easy to identify links, especially when they +are in the form of images. + +If Middle click opens URL in selection +is checked, you can open the &URL; in the selection by middle +clicking on a &konqueror; view. + +As a convenience feature, if you enable Right click +goes back in history, then clicking an empty area (&ie; not +a link) in the &konqueror; window will act as if you pressed the +Back button on the toolbar. + +Enabling Allow automatic delayed +reloading/redirecting allows websites to send you to +another page without your interaction. In many cases, this is a +convenience. For example, the website has moved to a new +&URL;. Many webmasters in this situation will put up +a page on the old site, telling you that it has moved and you may like +to change your bookmark, and then automatically move you along to the +new website. However, such features can be confusing, or annoying, +when misused, and so you may wish to disable it. + +Enable Access Key activation with &Ctrl; key: +Pressing the &Ctrl; key when viewing web pages activates Access Keys. +Unchecking this box will disable this accessibility feature. &konqueror; +needs to be restarted for this change to take effect. + +Send the DNT header to tell web sites you do not want +to be tracked. Check this box if you want to inform a web site +that you do not want to your web browsing habits tracked. + + +Offer to save website passwords. +Uncheck this box from being prompted to save website passwords + + + +
diff --git a/doc/kcontrol/khtml-general/CMakeLists.txt b/doc/kcontrol/khtml-general/CMakeLists.txt new file mode 100644 index 00000000..23cdaef4 --- /dev/null +++ b/doc/kcontrol/khtml-general/CMakeLists.txt @@ -0,0 +1,2 @@ +########### install files ############### +kde4_create_handbook(index.docbook INSTALL_DESTINATION ${HTML_INSTALL_DIR}/en SUBDIR kcontrol/khtml-general) diff --git a/doc/kcontrol/khtml-general/index.docbook b/doc/kcontrol/khtml-general/index.docbook new file mode 100644 index 00000000..70c14f08 --- /dev/null +++ b/doc/kcontrol/khtml-general/index.docbook @@ -0,0 +1,135 @@ + + + +]> + +
+General &konqueror; Behavior + + + +&Burkhard.Lueck; + + + +2011-11-22 +&kde; 4.8 + + +On this page you find settings for home and start page and the behavior +of tabbed browsing both for &konqueror;'s file manager and browser mode. + + + +When Konqueror starts + +This option determines which page is displayed when &konqueror; starts, +the introduction page, your home page, a blank page or your bookmarks page. + + + + +Home page +This is the &URL; (⪚ a +folder or a web page) where &konqueror; in browser mode will jump to +when the Home Page button in the toolbar is pressed. +You can set a path that is your Home page by +typing into the text field, or using the browse +icon to select a local folder. &konqueror; needs to be restarted for +changes to take effect. +When &konqueror; is used in file manager mode, the Home Page +button in the toolbar is replaced by a Home Folder button +which makes it jump to your local home folder instead. + + + +Default web browser engine + +This option provides an easy way to select the preferred web engine in &konqueror;, either +KHTML or Webkit, if installed. +Using the ViewView Mode +menu allows you to change the web engine temporarily on the fly. + + + + + +Open links in +new tab instead of in new window +&konqueror; defaults to a single window per page, but has the +capability to open multiple tabs inside a +single window. &konqueror; also, by default, has a &MMB; shortcut to +open any link in a new window. If you enable Open links in +new tab instead of in new window you can &MMB; click on a +link to have it open in a new tab. + + + +Open popups in new tab instead of in new window +Whether or not JavaScript popups if allowed shall open in a new tab or in a +new window. + + + +Open as tab in existing Konqueror when URL is called externally +When you click a &URL; in another &kde; program or call kfmclient to open a &URL;, +the current desktop will be searched for a non-minimized &konqueror; and, if +found, the &URL; opened as a new tab within it. Otherwise a new &konqueror; +window will be opened with the required &URL;. + + + +Open new tabs in the background +If you are using tabbed browsing, you can choose if a newly +opened tab becomes the active (front) tab, or goes to +the back. On a slow Internet connection, or while browsing a page +that has a list of headlines or other links in a list, you may like to +have the new tabs load in the background while you continue reading. +In this case, enable this setting. If you prefer to go +straight to the new page, leaving the old one in the background to +return to later, disable it. + + + +Open new tab after current tab +This will open a new tab opened from a page after the current tab, instead +of after the last tab. + + + +Hide the tab bar when only one tab is open +This will display the tab bar only if there are two or more tabs. Otherwise +it will always be displayed. + + + +Show close button on tabs +This will display close buttons inside each tab instead of websites' icons. + + + +Middle-click on a tab to close it +When you click on a tab using the middle mouse button or mouse wheel, it +will close that tab. &konqueror; needs to be restarted for changes to take +effect. + + + +Confirm when closing windows with multiple tabs +If you close a window in &konqueror; that has multiple tabs +open, &konqueror; will ask you if you're sure that you meant to close +it. You can toggle on and off this behavior with this +check box. + + + +Activate previously used tab when closing the current tab +When checking this the previous used or opened tab will be activated when +you close the current active tab instead of the one right to the current tab. + + + + +
diff --git a/doc/kcontrol/khtml-java-js/CMakeLists.txt b/doc/kcontrol/khtml-java-js/CMakeLists.txt new file mode 100644 index 00000000..c91facf6 --- /dev/null +++ b/doc/kcontrol/khtml-java-js/CMakeLists.txt @@ -0,0 +1,2 @@ +########### install files ############### +kde4_create_handbook(index.docbook INSTALL_DESTINATION ${HTML_INSTALL_DIR}/en SUBDIR kcontrol/khtml-java-js) diff --git a/doc/kcontrol/khtml-java-js/index.docbook b/doc/kcontrol/khtml-java-js/index.docbook new file mode 100644 index 00000000..0b0e5dad --- /dev/null +++ b/doc/kcontrol/khtml-java-js/index.docbook @@ -0,0 +1,145 @@ + + + + +]> + +
+ +Java and JavaScript + +&Krishna.Tateneni; &Krishna.Tateneni.mail; + + + +2009-11-24 +&kde; 4.4 + + +KDE +Systemsettings +konqueror +browsing +Java +JavaScript + + + + +&Java; and JavaScript + + +&Java; + +&Java; allows applications to be downloaded and run by a web +browser, provided you have the necessary software installed on your +machine. Many web sites make use of &Java; (for example, online +banking services or interactive gaming sites). You should be aware +that running programs from unknown sources could pose a threat to the +security of your computer, even if the potential extent of the damage +is not great. + +The check box Enable Java globally allows +you to turn &Java; support on for all web sites by default. You can +also select to turn &Java; on or off for specific hosts. To add a +policy for a specific host, click the New... +button to bring up a dialog in which you can type the host name and +then choose to accept or reject &Java; code from that particular host, +which will add the domain to the list on the left of the page. + +You can select a host in the list, and click the +Change... button to choose a different policy for +that host. Clicking the Delete button removes the +policy for the selected host; after deletion, the global settings will +then apply to that host. + +Finally, the group of controls labeled Java Runtime +Settings allows you to set some options for the way in +which &Java; should run. + +Use security +manager is normally enabled by default. This setting will +cause the JVM to run with a Security Manager in place. This will keep +applets from being able to read and write to your file system, creating +arbitrary sockets, and other actions which could be used to compromise +your system. Disable this option at your own risk. You can modify your +$HOME/.java.policy file with the +&Java; policytool utility to give code downloaded from certain sites +more permissions. + +Use KIO will cause the +JVMto use &kde;'s own KIO +transports for network connections. + +The Shutdown applet server when inactive for more than +check box allows you to save resources by closing the &Java; Applet +Server when it is not in use, rather than leaving it running in the +background. Leaving this disabled may make &Java; applets start up +faster, but it will use system resources when you are not using a +&Java; applet. If you enable this, you can set a timeout. + +You can either opt to have &konqueror; automatically detect the +&Java; installation on your system, or specify the path to the +installation yourself by selecting Path to Java +executable or 'java'. You may want to choose the latter method, for +instance, if you have multiple &Java; installations on your system, +and want to specify which one to use. If the &Java; Virtual Machine +you are using requires any special startup options, you can type them +in the text box labeled Additional Java +arguments. + + + + +JavaScript + +Despite the name, JavaScript is not related at all to +&Java;. + +The first part of this tab works the same as the &Java; settings. + +The checkbox Enable JavaScript globally allows +you to turn JavaScript support on for all web sites by default. You +can also select to turn JavaScript on or off for specific hosts. To +add a policy for a specific host, click the +New... button to bring up a dialog in which you +can type the host name and then choose to accept or reject JavaScript +code from that particular host, which will add the domain to the list +on the left of the page. + +You can select a host in the list, and click the +Change... button to choose a different policy for +that host. Clicking the Delete button removes the +policy for the selected host; after deletion, the global settings will +then apply to that host. + +The final set of options in the section Global JavaScript +Policies determine what happens +when a page uses JavaScript for specific actions. + +You can individually enable or disable the ability of JavaScript +to manipulate your windows by moving, resizing or changing focus. You +can also disable JavaScript from changing the status bar text, so that +for instance, you can always see where links will take you when +clicked. The choices for these options are Allow and +Ignore. + +For opening a new window, there is even more control. You can +set &konqueror; to Allow all such requests, +Ask each time a request is made, or +Deny all popup requests. + +The Smart setting will only allow +JavaScript popup windows when you have explicitly chosen a link that +creates one. + + + + +
diff --git a/doc/kcontrol/khtml-plugins/CMakeLists.txt b/doc/kcontrol/khtml-plugins/CMakeLists.txt new file mode 100644 index 00000000..f65154b2 --- /dev/null +++ b/doc/kcontrol/khtml-plugins/CMakeLists.txt @@ -0,0 +1,2 @@ +########### install files ############### +kde4_create_handbook(index.docbook INSTALL_DESTINATION ${HTML_INSTALL_DIR}/en SUBDIR kcontrol/khtml-plugins) diff --git a/doc/kcontrol/khtml-plugins/index.docbook b/doc/kcontrol/khtml-plugins/index.docbook new file mode 100644 index 00000000..410162be --- /dev/null +++ b/doc/kcontrol/khtml-plugins/index.docbook @@ -0,0 +1,149 @@ + + + + +]> + +
+ +Browser Plugins + +&Krishna.Tateneni;&Jost.Schenck; + + + + +2009-11-24 +&kde; 4.4 + + +KDE +Systemsettings +Konqueror +Browsing +Plugins + + + + + +Browser Plugins + + +Global Settings + +The first setting here is Enable Plugins +globally. If you disable this check box, then &konqueror; +will not use any plugins. If you enable it, then any installed and +configured plugins that it can find will be used by &konqueror; + +You can also restrict &konqueror; to Only allow HTTP +and HTTPS URLs for plugins by checking the box. + +The next option determines, if plugins are loaded on demand only. +Use the slider labeled CPU priority for plugins +to adjust this setting. + + +Click the Domain-Specific Settings button to open +a dialog where you can set specific plugin policies for any particular +host or domain. These policies will be used instead of the default policy for +enabling or disabling plugins on pages sent by these domains or hosts. + +Add a new policy here or select a policy and use the controls on the right to modify it. + + + + +Plugins + + +Introduction + +As &Netscape;'s Navigator has been a +web browsing standard for many years, so-called &Netscape; plugins have +appeared that allow rich web content. Using those plugins, web sites +can contain PDF files, flash animations, video, &etc; +With &konqueror;, you can still use these plugins to take advantage of +rich web content. + +&Netscape; plugins should not be confused with &konqueror; +plugins. The latter ones specifically extend &konqueror;'s +functionality; they are normally not used to display rich web +content. + + + + +Scan for Plugins + +&konqueror; has to know where your &Netscape; plugins are +installed. This can be in several places, &ie; you might have +system-wide plugins in /opt/netscape/plugins and your personal +plugins in $HOME/.netscape/plugins. +However, &konqueror; will not automatically use the installed plugins: +it first has to scan a list of folders. You can initiate the scan +by clicking Scan for Plugins. + +To find plugins, &konqueror; will look in the folders +specified in the Folders frame. When you +use this control module for the first time, this list will already be +filled with reasonable paths that should work on most operating systems. +If you need to provide a new path, click the New +button; then you can either enter the new path in the text edit box to +the left, or choose a folder using the file dialog by clicking the +Open file icon. As scanning the folders can take +a little time, you might want to remove folders from the list where +you know that no plugins are installed: do this by selecting a folder +and clicking Remove. Using the +Up and Down buttons you +can change the order in which folders will be scanned by moving the +selected folder up or down. + +As usual, click Apply to save your changes +permanently. + + + + +Plugins + +In this section, you can see a list of the &Netscape; plugins found by +&konqueror;, displayed as a tree. Double click on a plugin to fold it +out and you will see that the different mime types this plugin can handle +will be displayed as branches. Fold out a mime type to see its +info. + +This list is only for informational purposes. + + + + + + +
diff --git a/doc/kcontrol/language/CMakeLists.txt b/doc/kcontrol/language/CMakeLists.txt new file mode 100644 index 00000000..b4f20027 --- /dev/null +++ b/doc/kcontrol/language/CMakeLists.txt @@ -0,0 +1,2 @@ +########### install files ############### +kde4_create_handbook(index.docbook INSTALL_DESTINATION ${HTML_INSTALL_DIR}/en SUBDIR kcontrol/language) diff --git a/doc/kcontrol/language/index.docbook b/doc/kcontrol/language/index.docbook new file mode 100644 index 00000000..cf15342e --- /dev/null +++ b/doc/kcontrol/language/index.docbook @@ -0,0 +1,633 @@ + + + +]> + +
+ +Country/Region & Language + +&Mike.McBride; &Mike.McBride.mail; +&Krishna.Tateneni; &Krishna.Tateneni.mail; + + + + 2013-12-05 + 4.12 + + + KDE + Systemsettings + locale + country + language + + + + + + +Country/Region & Language + + +This module of the &kde; &systemsettings; allows you to select customization +options that depend on the region of the world that you happen to live in. +There are seven different tabs in this module, each of which is described in +detail in the following sections. + + + +In most cases, you can simply select the country and the language, and the +other options will be set in an appropriate manner. + + + +Below the tabs of this module you can see a preview of what the settings look +like. In addition to positive and negative numbers, you can see how positive +and negative currency values, long and short dates, and times are displayed. +When you change any of the settings, the preview shows the effects of the +changes before you apply them. + + + +Each setting option in the various tabs has an individual + + default button which +is activated whenever that setting is different to your country default value. +Clicking on the button will restore only that setting to your Country default. + + + + + +Country + + +In this tab you can select the country or region that you want to use. + + + +The Country drop down box contains the list of available +countries and will initially show your currently selected country. If the +selection shows System Country then you have not set a country +and are defaulting to the Country set by the system, which will also be shown. +Changing the country will automatically change the settings to the defaults for +that country, except were you have set your own settings which will be left +unchanged. You can easily see where your personal settings differ from the +country settings by looking at the Default button next to the individual +setting. If the button is enabled then your personal setting is different and +you can click on the button to restore the country setting for that option +only. + + + + + + + +Languages + + +In this tab you can set your preferred languages for the &kde; Workspace and +Applications to be displayed in. + + + +The &kde; Workspace and Applications are written in American English and are +translated into many different languages by teams of volunteers. These +translations need to be installed first before you can choose to use them. The +list of Available Languages shows what KDE translations +are installed and available on your system. If the language you want to use is +not shown in this list then you will need to install it using the usual method +for your system. Your system may have enabled the +Install more languages button to make this easy for you. + + + +The Preferred Languages list shows the languages that will +be used when displaying the &kde; Workspace and Applications. Because not all +of the KDE Workspace and Applications may be translated into every language +&kde; will try to find suitable translations for you by working down the +Preferred Languages list until it finds a translation. If +none of your preferred languages have a required translation then the original +American English will be used. + + + +You can add a language to the Preferred Languages list by +selecting it in the Available Languages and then clicking +on the Add arrow button. You can remove a language from the +Preferred Languages list by selecting it and then clicking +on the Remove arrow button. You can change the order of preference in the +Preferred Languages list by selecting a language and +clicking on the Up or Down arrow button. + + +Only languages listed in Preferred Languages and +Available Languages will be offered as options +for Primary language and Fallback language +in the Switch Application Language dialog of the +Help menu. + + + + +Language and Country/Region are independent settings. Changing a language does +not automatically change the settings for numbers, +currency &etc; to the corresponding country or region. It will only change the +language used in displaying dates, such as month names. + + + + + + + + +Numbers + + +On this tab, you can select options for how numbers are displayed. The defaults +are selected automatically based on the country which is currently selected. + + +In the first drop down box you can define the Digit grouping +used to display numbers. + + +In the Group separator text box you can type the character +that you want to use to separate groups of digits in numbers, usually a +. or a ,. You should ensure that +this value is different to the Decimal separator setting. +The drop-down box provides a list of common values to choose from. + + + +In the Decimal separator text box you can type the +character that you want to use to separate the decimal portion of numbers, +usually a . or a ,. You should +ensure that this value is different to the Group separator +setting. The drop-down box provides a list of common values to choose from. + + + +In the Decimal places spin box you can set the number of +decimal places displayed for numeric values, &ie; the number of digits +after the decimal separator. + + + +In the Positive sign text box you can type the character +that you want to use to indicate positive numbers. You should ensure that this +value is different to the Negative sign setting. The +drop-down box provides a list of common values to choose from. This value may +also be used for monetary values depending on the +Positive format selected in the Money +tab. + + + +In the Negative sign text box you can type the character +that you want to use to indicate negative numbers. You should ensure that this +value is different to the Positive sign setting. The +drop-down box provides a list of common values to choose from. This value may +also be used for monetary values depending on the +Negative format selected in the Money +tab. + + + +The Digit set drop down box lists digit sets which may be +used instead of Arabic digits when displaying numbers. If you select a digit +set other than Arabic, it will be applied only to numbers which appear in a +language context that uses that digit set while Arabic digits are still going +to be used elsewhere, ⪚ Arabic-Indic digits will be applied to Arabic but +not to American English. + + + +Note that digit grouping, group separator, decimal separator, decimal places, positive format, +negative format and the digit set used to display monetary values has to be set +separately on the Money tab. + + + + + + + +Money + + +On this tab, you can select options for how monetary values are displayed. The +defaults are selected automatically based on the country which is currently +selected. + + + +In the Currency drop-down box you can choose the currency +you want to use when displaying monetary values. This will default to the main +currency in use in your selected country. You can choose a different currency +from the drop-down box, which displays the names of all available currencies +their ISO 4217 standard Currency Code. The currencies used in your selected +country are listed at the top, followed by all the other currencies. Changing +the currency will also update the Currency symbol to use +the default symbol for that currency, but no other format settings will be +changed. + + + +In the Currency symbol drop-down box you can choose the +currency symbol you want to use when displaying monetary values. This will +default to the usual symbol of the currency you have selected in the +Currency drop-down box. This will only allow you to select +a valid currency symbol for the currency code to prevent inconsistent choices, +such as choosing US Dollars but showing the Pound Sterling symbol £ instead. +This setting will automatically be changed when you change the +Currency setting. + + +In the next drop down box you can define the Digit grouping +used to display monetary values. + + +In the Group separator text box you can type the character +that you want to use to separate groups of digits in monetary values, usually a +. or a ,. You should ensure that +this value is different to the Decimal separator setting. +The drop-down box provides a list of common values to choose from. + + + +In the Decimal separator text box you can type the +character that you want to use to separate the decimal portion of monetary +values, usually a . or a ,. You +should ensure that this value is different to the +Group separator setting. The drop-down box provides a list +of common values to choose from. + + + +In the Decimal places spin box you can set the number of +decimal places displayed for monetary values, &ie; the number of digits +after the decimal separator. + + + +In the Positive format drop-down box you can select how +you want positive monetary values to be displayed. The drop-down box displays a +list of four sample formats that you can choose from, combining the options for +where the Currency symbol and the numeric value +Positive sign are displayed. You can also choose to +replace the numeric value Positive sign with brackets. + + + +In the Negative format drop-down box you can select how +you want negative monetary values to be displayed. The drop-down box displays a +list of ten sample formats that you can choose from, combining the options for +where the Currency symbol and the numeric value +Negative sign are displayed. You can also choose to +replace the numeric value Negative sign with brackets. + + + +The Digit set drop down box lists digit sets which may be +used instead of Arabic digits when displaying money. If you select a digit +set other than Arabic, it will be applied only to numbers which appear in a +language context that uses that digit set while Arabic digits are still going +to be used elsewhere, ⪚ Arabic-Indic digits will be applied to Arabic but +not to American English. + + + +Note that digit grouping, group separator, decimal separator, decimal places, positive sign, +negative sign and the digit set used to display numeric values has to be set +separately on the Numbers tab. + + + + + + + +Calendar + + +On this tab, you can select options for how calendar information is displayed. +The defaults are selected automatically based on the country which is currently +selected. + + + +In the Calendar system drop-down box you can choose the +calendar system to be used when displaying or inputting dates. This will +default to the main calendar system in use in your selected country, usually +the Gregorian calendar. Changing the calendar system will also update the +various weekday name drop-down combos with the names of days of the week in the +new calendar system, will enable or disable the Use Common Era +tick box and may change the value of the Short year window +setting. + + + +Note that the Gregorian calendar used is a hybrid of the Julian calendar up to +Thursday 4 October 1582 and the Gregorian calendar from Friday 15 October 1582, +leaving a gap of ten missing days. We are aware +this conversion date is not factually correct for all countries, however this +is how Qt have chosen to implement the Gregorian calendar and we wish to remain +consistent with them. + + + +If you have selected the Gregorian calendar system then the Use +Common Era tick box will be enabled. This allows you to choose to +use the Common Era (CE/BCE) instead of the Christian Era (AD/BC) when +displaying and inputting dates. See the Date & Time +tab for how to set this up. + + + +The Short year window option is only used when you choose +to use a short two digit year format (YY) in the Long date +format or Short date format settings in the +Date & Time tab. When inputting a short year value, +⪚ 10, the system must guess what century that year falls in. By setting +the Short year window you tell the system how you want the +short year to be interpreted, ⪚ whether 50 is interpreted as 1950 or 2050. +This window can be set differently for each calendar system as they all use +different epochs (start dates). For example, the Hebrew calendar is into its +58th century (2010 Gregorian is roughly 5771 Hebrew), so may use a window of +5750 to 5850. + + +The Week number system option determines how the +week number will be calculated. There are four options available: + + +ISO Week +Use the ISO standard Week Number. This will always use Monday +as the first day of the ISO week. This is the most commonly used system. + + + +Full First Week +The first week of the year starts on the first occurrence +of the First day of the week, and lasts for seven days. +Any days before Week 1 are considered part of the last week of the previous year. +This system is most commonly used in the USA. + + + +Partial First Week +The first week +starts on the first day of the year. The second week of the year starts on +the first occurrence of the First day of the week, and +lasts for seven days. The first week may not contain seven days. + + + +Simple Week +The first week starts on the first day of the year and lasts +seven days, with all new weeks starting on the same weekday as the first day +of the year. + + + + +In the First day of week drop-down box you can choose +which weekday is considered the first day of the week. This value is often +used when displaying calendar tables to determine which day is listed first. + + + +In the First working day of week drop-down box you can +choose which weekday is considered the first working day of the week. This +value is often used when displaying calendar tables to determine when the +weekend is. + + + +In the Last working day of week drop-down box you can +choose which weekday is considered the last working day of the week. This +value is often used when displaying calendar tables to determine when the +weekend is. + + + +In the Week day for special religious observance drop-down +box you can choose which weekday is regularly used for special religious +observances. This value is often used when displaying calendar tables to +red letter a certain day. If you do not have any particular +weekday for religious observance then you can choose the +None / None in particular option. + + + + + + + +Date & Time + + +On this tab, you can select options for how date and time values are input or +displayed. The defaults are selected automatically based on the country which +is currently selected. + + + +In the Time format text box you can enter the format that +you want to use to input and display times. The format entered is a combination +of special codes representing time components and literal text used to separate +the time components. The special time component codes are listed below. You can +set the format to any combination of time components you like, but you should +always include at least an hour and minutes portion to allow you to input times +that are not ambiguous. The drop-down box provides a list of common time +formats in your currently selected language to choose from. + + + + +HH - The hour as a decimal number using a 24-hour clock +(00-23). + + +hH - The hour as a decimal number using a 24-hour clock +(0-23). + + +PH - The hour as a decimal number using a 12-hour clock +(01-12). + + +pH - The hour as a decimal number using a 12-hour clock +(1-12). + + +MM - The minutes as a decimal number (00-59). + + +SS - The seconds as a decimal number (00-59). + + +AMPM - Either 'AM' or 'PM' according to the given time +value. Noon is treated as 'PM' and midnight as 'AM'. You should always include +this code if you are using the 12-hour clock codes PH or +pH to prevent ambiguity when entering times. + + + + +In the AM symbol text box you can enter the symbol that +you want to use to input or display for AM when using a 12-hour clock. The +drop-down box provides a list of common symbols for your currently selected +language to choose from. + + + +In the PM symbol text box you can enter the symbol that +you want to use to input or display for PM when using a 12-hour clock. The +drop-down box provides a list of common symbols for your currently selected +language to choose from. + + + +In the Long date format text box you can enter the format +that you want to use to input and display long dates. The format entered is a +combination of special codes representing date components and literal text used +to separate the date components. The special date component codes are listed +below. You can set the format to any combination of date components you like, +but you should always include at least enough components to uniquely identify a +day in the year, ⪚ a month and day, to allow you to input dates that are not +ambiguous. If you don't include a year component then the current year will be +used. The drop-down box provides a list of common date formats in your +currently selected language to choose from. + + + + +YYYY - The year with century as a decimal number +(0000-9999). + + +YY - The year without century as a decimal number +(00-99). + + +MM - The month as a decimal number (01-12). + + +mM - The month as a decimal number (1-12). + + +MONTH - The full month name. + + +SHORTMONTH - The first three characters of the month +name. + + +DD - The day of month as a decimal number (01-31). + + +dD - The day of month as a decimal number (1-31). + + +WEEKDAY - The full weekday name. + + +SHORTWEEKDAY - The first three characters of the weekday +name. + + +ERAYEAR - The Era Year in local format (⪚ 2000 AD). + + +SHORTERANAME - The short Era Name (⪚ AD). + + +YEARINERA - The Year in Era as a decimal number +(⪚ 2000). + + +DAYOFYEAR - The Day of Year as a decimal number. + + +ISOWEEK - The ISO Week as a decimal number. + + +DAYOFISOWEEK - The Day of the ISO Week as a decimal +number. + + + + +In the Short date format text box you can enter the format +that you want to use to input and display short dates. This is in the same +format as the Long date format, please read that section +for more details. The drop-down box provides a list of common date formats in +your currently selected language to choose from. + + + +The Digit set drop down box lists digit sets which may be +used instead of Arabic digits when displaying dates and times. If you select a +digit set other than Arabic, it will be applied only to numbers which appear in +a language context that uses that digit set while Arabic digits are still going +to be used elsewhere, ⪚ Arabic-Indic digits will be applied to Arabic but +not to American English. + + + + + + + +Other + + +On this tab, you can select how other options are displayed. The defaults are +selected automatically based on the country which is currently selected. + + + +In the Page size drop-down box you can choose the page +size to use as the default for new documents, ⪚ in KWord. Note that this +setting does not affect your default paper size in the print dialog, to set +that you need to use the Printers module of the &kde; &systemsettings;. + + + +In the Measurement system drop-down box you can choose the +measurement system to use, either metric or imperial. + + + +In the Byte size units drop-down box you can choose the +unit system to use when displaying numbers counted in bytes. Traditionally +kilobytes meant units of 1024 instead of the metric 1000 for +most but not all byte sizes. To reduce confusion you can choose which system +you prefer. The available unit systems are listed below. + + + + +The IEC Units standard is always in multiples of 1024. + + +The Metric Units standard is always in multiples of 1000. + + +The JEDEC Units standard uses the traditional units used +in &kde; 3.5 and some other operating systems. + + + + + + + +
diff --git a/doc/kcontrol/language/oxygen-22x22-document-revert.png b/doc/kcontrol/language/oxygen-22x22-document-revert.png new file mode 100644 index 00000000..75ff210d Binary files /dev/null and b/doc/kcontrol/language/oxygen-22x22-document-revert.png differ diff --git a/doc/kcontrol/nepomuk/CMakeLists.txt b/doc/kcontrol/nepomuk/CMakeLists.txt new file mode 100644 index 00000000..cf87e2d6 --- /dev/null +++ b/doc/kcontrol/nepomuk/CMakeLists.txt @@ -0,0 +1,2 @@ +########### install files ############### +kde4_create_handbook(index.docbook INSTALL_DESTINATION ${HTML_INSTALL_DIR}/en SUBDIR kcontrol/nepomuk) diff --git a/doc/kcontrol/nepomuk/index.docbook b/doc/kcontrol/nepomuk/index.docbook new file mode 100644 index 00000000..96ef4ab7 --- /dev/null +++ b/doc/kcontrol/nepomuk/index.docbook @@ -0,0 +1,152 @@ + + + +]> + +
+ +Nepomuk Desktop Search Configuration + + +SebastianTruegtrueg@kde.org +&Anne-Marie.Mahfouf; &Anne-Marie.Mahfouf.mail; + + + +2013-11-01 +&kde; 4.12 + + +KDE +KControl +nepomuk +desktop search + + + + +Introduction + +This module allows to configure certain parts of the desktop search and the Nepomuk semantic desktop. More information +about the Nepomuk semantic desktop can be found at the Nepomuk homepage. + + +Basic Settings + +The basic settings tab allows to enable or disable the semantic desktop and desktop search systems. + +There are three checkboxes: + +Enable Nepomuk Semantic Desktop Enabling the Nepomuk semantic desktop means that +the Nepomuk services are running. These services provide metadata/annotation storage (files can be tagged or rated in &dolphin; +for example) but also desktop search which can be used through the &kde; runner or again &dolphin;. +Enable Nepomuk File Indexer Enabling the nepomuk file indexer means that +the file indexer service is started in addition to the standard services already running. The file indexer service will run through +all files in the configured folders (see below) and extract metadata from them (such as title or artist on music files or even +simple things like the creation date). This metadata is then exposed through the desktop search just like the manual annotations +mentioned earlier. +Enable PIM Data Indexer This option has to be checked to allow full text search in +&kmail;. + + +On the right of Enable Nepomuk Semantic Desktop you can click on Details... and +a dialog will inform you on the status of the KDE metadata store: how many files are indexed and the size of the store. + +Under the Enable Nepomuk File Indexer checkbox the current status of the file indexing service is +shown. The service has four normal operation states: + +File indexer is idle - The file indexer is currently not working and waiting for an event to +trigger an update (an event can be a newly created file or a changed file or a timeout for the recurring full check) +Indexing files in folder foobar - The file indexer is currently running though +all files in folder foobar and analyzes new or changed files. +Scanning for recent changes in files for desktop search - The file indexer is currently performing +its recurring check for new files in all index folders. This check is intended to find files that were not caught through normal file +system monitoring. +File indexer is suspended - The file indexer has been suspended, &ie; it is in a paused state. +This can either be triggered by the user or due to low disk space or a laptop being in a power-saving state. In the two latter +cases the indexer will resume once the reason for the suspension has been resolved. + + +Apart from the normal operation states the indexer service can have an erroneous state. There are two possibilities: + +File indexing service failed to initialize, most likely due to an installation problem - This should rarely +occur that means that a mandatory plugin could not be loaded. This can be due to an installation problem (missing dependency) or due +to a faulty setup of the &kde; plugin system. +Any other error means a communication problem with the service. These errors are produced by the &DBus; subsystem and need +to be evaluated case by case. + + + + + +Indexing + +This tab allows to select the files and folders that are to be analyzed by the file indexer explained + above. By default Documents, Audio, Images and Videos are selected here. + + +Click the Customize Folders button to select and de-select folders that should be searched for files +to be analyzed. By default the home folder and all subfolders are analyzed. By simply unchecking a folder it can be excluded. +It is also possible to include a subfolder of an excluded one by checking it again. This allows a rather fine selection of the +folders to be analyzed. + +Clicking the Advanced button allows to define exclude filters using the mime type or the name of a file. +The mime types and names of all files found in the configured folders will be matched against these filters. Only if none of them +matches the file will be analyzed. This is very helpful to exclude log and backup files and the like. + +Removable media handling: Nepomuk can index files on removable devices like USB keys or external +hard-disks for fast desktop searches. By default no files are indexed. Here this behaviour can be changed to one of two options: + +Index files on all removable devices - Files on removable media are indexed as soon as the +medium is mounted. Caution: this does not include media which have been rejected via the second option +Ask individually when newly mounted - The user will be asked to decide if files on the +newly mounted medium should be indexed or not. Once decided Nepomuk will not ask again. + + + + +Backup + +On this tab you can decide to make a backup of all data that could not be restored otherwise. This includes +manually created tags, ratings but also statistical data. No backup is done as default so you need to decide what you want to do. +You have two possibilities: automatic backups and manual ones. + + +Automatic Backups +First choose the Backup Frequency: this is set to Disable Automatic Backups but you +can choose Daily Backup or Weekly Backup. +Then set the Backup Time: to anything convenient for you using the spinbox: you can set the hour and minutes +and the day of the week for weekly backups. +Finally you can set a limit for the number of backup files using Max Number of Backups:. +This will ensure you do not waste disk space with the backup files and only the N last files will be kept, N being +the number you set there, 10 as default. +Your automatic backups are saved locally in the following directory: +$KDEHOME/share/apps/nepomuk/backupsync/backups/. + + + +Tools + +Manual Backup... +You can also perform manual backups. Manual backups will be saved in your chosen location, as a file. +Click on Manual Backup... and a wizard will guide you. You first need to point to the location +of the backup file. Enter a full valid path in the field or use the file dialog to point to a file. +You can create a new file in the folder of your choice and then point to this new file. +Then click on the Next button and the dialog should report that the backup has been done. + +Restore Backup... +If you want to later restore your backup, use this button and follow the wizard. The backup will be merged +into the local Nepomuk database. + + + + + + + + +
diff --git a/doc/kcontrol/netpref/CMakeLists.txt b/doc/kcontrol/netpref/CMakeLists.txt new file mode 100644 index 00000000..1d634b51 --- /dev/null +++ b/doc/kcontrol/netpref/CMakeLists.txt @@ -0,0 +1,2 @@ +########### install files ############### +kde4_create_handbook(index.docbook INSTALL_DESTINATION ${HTML_INSTALL_DIR}/en SUBDIR kcontrol/netpref) diff --git a/doc/kcontrol/netpref/index.docbook b/doc/kcontrol/netpref/index.docbook new file mode 100644 index 00000000..d5436bb3 --- /dev/null +++ b/doc/kcontrol/netpref/index.docbook @@ -0,0 +1,109 @@ + + + +]> + +
+ +Connection Preferences + +&Lauri.Watts; &Lauri.Watts.mail; + + + + +2013-12-05 +&kde; 4.12 + + +KDE +kdebase +kcontrol +network +timeouts + + + + + + +Connection Preferences + +Here you can set timeout values. You might want to tweak them +if your connection is very slow, but the default settings are +appropriate for most users. + +Here Timeout Values are the length of time +an application should wait for an answer from a network operation. + +You can configure the following timeouts: + + + +Socket read: + + Some applications use sockets to +communicate. You can think of a socket as a water tap; while it is +open, water (or in our case, data) comes out, without any interaction. +If something stops this flow of data, the application will wait for +more to come. This could be a very long time, but you can configure a +maximum time for an application to wait with this option. +This setting will only apply to &kde; applications, of course. + + + + +Proxy connect: + + +Sets how long to wait for a connection to a proxy server, if one is configured. + + + + + +Server connect: + + +Sets how long to wait for a connection to a remote server. + + + + + +Server response: + + +Sets how long to wait for a reply from a remote server. + + + + + + +You can configure FTP Options here. At +present there is just two options: + + +Enable passive mode (PASV) +Passive &FTP; is often required when you are behind a firewall. +Many firewalls only permit connections that were initiated from +the inside. Passive &FTP; is controlled by the client, +which makes it usable through firewalls. + + + +Mark partially uploaded files +When a mark is placed in this box, partially uploaded files will +have a .part extension added to the end +of the file. This extension is removed once the file download is complete. + + + + + + + +
diff --git a/doc/kcontrol/performance/CMakeLists.txt b/doc/kcontrol/performance/CMakeLists.txt new file mode 100644 index 00000000..027649ef --- /dev/null +++ b/doc/kcontrol/performance/CMakeLists.txt @@ -0,0 +1,2 @@ +########### install files ############### +kde4_create_handbook(index.docbook INSTALL_DESTINATION ${HTML_INSTALL_DIR}/en SUBDIR kcontrol/performance) diff --git a/doc/kcontrol/performance/index.docbook b/doc/kcontrol/performance/index.docbook new file mode 100644 index 00000000..3534dc00 --- /dev/null +++ b/doc/kcontrol/performance/index.docbook @@ -0,0 +1,91 @@ + + + +]> + +
+ +Performance + +&Mike.McBride; &Mike.McBride.mail; + + + +2009-11-24 +&kde; 4.4 + + +KDE +Systemsettings +performance +preload + + + + +Performance Settings + +&kde;, is used on a wide variety of computers by a wide variety of users. Under the category of +performance, this dialog allows each user to adjust options which may make the computer that &konqueror; is +installed on feel more responsive. + +&konqueror; instances +The first section of this dialog is labeled Minimize Memory Usage and has three options which determine maximum number of instances of &konqueror; that can be open on one machine at any one time. + +Do not confuse &konqueror; instances, with &konqueror; windows or tabs. The number of &konqueror; instances is determined by &kde; not by the user. You can think of instances as the hidden data of your &konqueror; windows and tabs. One &konqueror; instance can contain the data for multiple windows or tabs. Your choice on the following radio buttons does not limit the number of windows you can open at one time, but rather, how many instances of &konqueror; you can have open. +The reason the choices you make in this dialog box are important is evident when something goes wrong and &konqueror; is forced to close an instance. All &konqueror; windows associated with a &konqueror; instance must be closed immediatly (without time to save data or bookmark locations). Therefore, the more instances you can have open at one time, the less likely a problem in one instance will affect all of your work. Each instance requires more memory which can be a problem on systems with less system memory. + +Your options are: + + + +Never +There are no restraints. Any number of &konqueror; instances can be open at any one time. The advantage of this option is if any &konqueror; instance crashes the remaining will be unaffected. The disadvantage is that each &konqueror; instance uses more memory. + + + +For file browsing only (recommended) +If this option is selected, you can have as many as you want &konqueror; instances open that are browsing the web, but only one instance of &konqueror; for file management. + + + +Always (use with care) +If this option is selected, you can only have one instance of &konqueror; running at any one time. This saves system memory, but if your &konqueror; window crashes, all your browsing windows close immediatly without warning. This should only be used for seriously memory limited systems. + + + + +Preloading +The subsection labeled Preloading also makes a tradeoff between memory and performance. + +Preloading refers to loading an instance of &konqueror; into memory before a user asks to start &konqueror;. The positive effect of this is that when a user asks &kde; to load &konqueror; the window appears instantly + because most of the application has been preloaded. The negative effect is that this instance of &konqueror; uses memory that +could be used by other programs. By default, when a user closes &konqueror;, &kde; does not close the instance. +This means that the next time a user wants &konqueror; loaded, it is nearly instantaneous again. +The spinbox labeled Maximum number of instances kept preloaded: can be used to adjust the maximum number of preloaded instances. This option does not affect instances when they are loaded. It also does not limit the number of instances that can be used by active windows. It only affects the number of preloaded instances. +The check box labeled Preload an instance after &kde; startup does just what it says. It tells +&kde; to preload one instance of &konqueror; at the startup of &kde;. +This does extend the startup time for &kde;. +The final check box labeled Always try to have at least one preloaded instance signals to &kde; that you always want &kde; to have one preloaded, but not used, instance of &konqueror; available. This option will actually decrease performance on some machines (especially those with limited physical memory). + + + + +
diff --git a/doc/kcontrol/phonon/CMakeLists.txt b/doc/kcontrol/phonon/CMakeLists.txt new file mode 100644 index 00000000..035c37d9 --- /dev/null +++ b/doc/kcontrol/phonon/CMakeLists.txt @@ -0,0 +1,2 @@ +########### install files ############### +kde4_create_handbook(index.docbook INSTALL_DESTINATION ${HTML_INSTALL_DIR}/en SUBDIR kcontrol/phonon) diff --git a/doc/kcontrol/phonon/index.docbook b/doc/kcontrol/phonon/index.docbook new file mode 100644 index 00000000..eed863c8 --- /dev/null +++ b/doc/kcontrol/phonon/index.docbook @@ -0,0 +1,93 @@ + + + +]> +
+Audio and Video Settings + + +MatthiasKretz + + + +2013-12-05 +&kde; 4.12 + + +KDE +Systemsettings +hardware +multimedia +sound +video +backend + + + + +This &systemsettings; module allows you to configure the sound and video device +preference and the backends used by Phonon. + + + +Device Preference tab + +On the left you are presented a tree list with various categories of playback and recording. +For each category you may choose what device you wish to use. +The Audio Playback and Audio Recording +items define the default ordering of devices which can be overridden by +each sub items. +Clicking the Apply Device List To button shows a dialog +which enables you to copy the selected setting from one category to many others. +Highlight a category and the available devices for this category are displayed in the +list on the right. The order in this list determines the preference of the output and capture +devices. If for some reason the first device cannot be used Phonon will try to use the second, &etc; +Use the Prefer and Defer buttons to change the order +and the Test button to play a test sound on the selected device. + + + +Audio Hardware Setup tab + +The various drop down boxes in this tab allow full control over all cards that are attached +to the system. + + +Hardware +Select the Sound Card and an available +Profile to be used. + + +Device Configuration +Select the Sound Device and a Connector. + + +Speaker Placement and Testing or Input Levels + +For a playback device: The buttons on this pane allow you to test each speaker separately. + +For a recording device: A slider shows the Input Levels +of the selected Connector. + + + + + + + + + +Backend tab + +On the left side of this module a list of Phonon backends found on your system is shown. +The order here determines the order Phonon will use the backends. +Use the Prefer and Defer buttons +to change this order. + + + + + +
diff --git a/doc/kcontrol/proxy/CMakeLists.txt b/doc/kcontrol/proxy/CMakeLists.txt new file mode 100644 index 00000000..7777c4ec --- /dev/null +++ b/doc/kcontrol/proxy/CMakeLists.txt @@ -0,0 +1,2 @@ +########### install files ############### +kde4_create_handbook(index.docbook INSTALL_DESTINATION ${HTML_INSTALL_DIR}/en SUBDIR kcontrol/proxy) diff --git a/doc/kcontrol/proxy/index.docbook b/doc/kcontrol/proxy/index.docbook new file mode 100644 index 00000000..ec5d7777 --- /dev/null +++ b/doc/kcontrol/proxy/index.docbook @@ -0,0 +1,209 @@ + + + +]> + +
+Proxy + + +&Krishna.Tateneni; &Krishna.Tateneni.mail; + + + +2013-12-05 +&kde; 4.12 + + +KDE +Systemsettings +proxy +proxies + + + + +Proxies + + + +Introduction + +Proxies are programs running on a computer that acts a server on +the network you are connected to (whether by modem or other +means). These programs receive &HTTP; and &FTP; requests, retrieve the +relevant files from the internet, and pass them on to the client +computer that made the requests. + +When you have configured a proxy, &HTTP; and/or &FTP; requests +are re-routed through the computer that is acting as a proxy server. +However, you can also select specific hosts which should be contacted +directly, rather than through the proxy server. If you are on a local +network, for example, access to local hosts probably doesn't need to +go through a proxy server. + +You should only need to configure a proxy server if your network +administrator requires it (if you are a dial-up user, that would be +your internet service provider or ISP). Otherwise, +especially if you are feeling a bit confused about this proxy +business, but everything seems to be fine with your internet +connection, you don't need to change anything. + +Please note that using proxy servers is optional, but has the +benefit or advantage of giving you faster access to data on the +internet. + +If you are uncertain whether or not you need to use a proxy +server to connect to the internet, please consult with your internet +service provider's setup guide or your system administrator. + + + + + +Use + + + +No Proxy + + +Select this option if you do not want to use a proxy server +and connect to the Internet directly. + + + + +If you have decided to use a proxy, you have several methods to +configure the settings for it. + + + +Detect proxy configuration automatically + + +Select this option if you want the proxy setup configuration +script file to be automatically detected and downloaded. +This option only differs from the next choice in that it +does not require you to supply the location of +the configuration script file. Instead, it will be automatically +downloaded using Web Proxy Auto-Discovery +(WPAD) protocol. + +If you have a problem using this setup, please consult the +FAQ section at http://www.konqueror.org for +more information. + + + + +Use proxy auto configuration URL + +Select this option if your proxy support is provided through a +script file located at a specific address. You can then enter the +address in the location text box, or use the folder +icon to browse to it. + + + + +Use system proxy configuration + +Some systems are setup with $HTTP_PROXY to allow +graphical as well as non-graphical applications to share the same +proxy configuration information. +If you know this applies to you, select this option and click on +the Auto Detect button to provide the environment +variable names used to set the address of the proxy server(s). + +In the Exceptions field enter the environment variable, +⪚ $NO_PROXY, used to store the +addresses of sites for which the proxy server should not be used. +Use Show the value of the environment variables to +show the value of an environment variable instead of its name. +However it is not possible to edit the values of environment variables in this module. + + + + + +Use manually specified proxy configuration + + +The complete addressing information for the proxy includes both +the Internet address and a port number. You should enter these into +the relevant text boxes. Check Use this proxy server for all +protocols to copy the addresses and port of the HTTP proxy server +into all other proxy fields, in order to help save some typing. + + + +Exceptions + +Enter a comma separated list of hostnames or ip addresses that should +be excluded from using the above proxy settings. If you want to exclude all +hosts for a given domain, then simply enter the domain name preceded by a dot. +For example, to exclude all hostnames for kde.org, enter .kde.org. +Wildcard characters such as * or ? +are not supported and will have no effect. +Additionally, you can also enter IP addresses, e.g. 127.0.0.1 and +IP addresses with a subnet, e.g. 192.168.0.1/24. + + + + +You can also choose Use proxy settings only for addresses +in the Exceptions list. + +Check this box to reverse the use of the exception list, &ie; +the proxy servers will only be used when the requested &URL; matches +one of the addresses listed here. + +This feature is useful if all you need is a proxy to access a +few specific sites, for example, an internal intranet. If you have +more complex requirements you might want to use a configuration +script. + + + + + + + + +
diff --git a/doc/kcontrol/smb/CMakeLists.txt b/doc/kcontrol/smb/CMakeLists.txt new file mode 100644 index 00000000..295359ac --- /dev/null +++ b/doc/kcontrol/smb/CMakeLists.txt @@ -0,0 +1,2 @@ +########### install files ############### +kde4_create_handbook(index.docbook INSTALL_DESTINATION ${HTML_INSTALL_DIR}/en SUBDIR kcontrol/smb) diff --git a/doc/kcontrol/smb/index.docbook b/doc/kcontrol/smb/index.docbook new file mode 100644 index 00000000..70d331d8 --- /dev/null +++ b/doc/kcontrol/smb/index.docbook @@ -0,0 +1,104 @@ + + + +]> + +
+ +Windows Shares + +&Mike.McBride; &Mike.McBride.mail; +&Jost.Schenck; &Jost.Schenck.mail; + + + +2013-12-05 +&kde; 4.12 + + +KDE +Systemsettings +Windows shares + + + +Windows Shares + + +Introduction + +In many small local area networks, the SMB +protocol is used to offer network services. Names like +&Windows; Network or &Windows; for Workgroups +Network or LanManager are often used as +well. Using SMB you can access so-called +shares (&ie; folders made available by the server) +as well as printers. + +&kde; comes with built-in support for the SMB +protocol. As &kde; is network-transparent that means you can access +SMB shares from everywhere you can access your +local files, for example in the &konqueror; file manager and in the +file dialog. To make use of this you should provide &kde; with some +information on your SMB network. But don't worry, +this is normally pretty simple as, for example, all the Windows +clients in your network need and have the same information. + + + + + +For the SMB protocol to work, it is +required to have Samba correctly +installed. + + + + + + +Use + +Although there are a lot of insecure SMB +networks out there which allow access to anyone, in principle you have +to authenticate yourself to access the services of an +SMB server. By default, &kde; will use the data +entered in the Default user name and +Default password fields to authenticate itself on +SMB hosts. If you leave the field Default +user name empty, &kde; will try to access +SMB hosts without a username. If you leave the +default password empty, it will try without a password. If &kde; is +unsuccessful accessing the host using these settings, you will be +asked for a username and a password. + +While it makes things more comfortable if &kde; +stores your SMB password, this may be a security +problem. If you are using SMB in a security +conscious environment, you should not store your password here but +rather enter it anew every time you need to access an +SMB host. + + + + + + +
diff --git a/doc/kcontrol/solid-device-automounter/CMakeLists.txt b/doc/kcontrol/solid-device-automounter/CMakeLists.txt new file mode 100644 index 00000000..4b626ed6 --- /dev/null +++ b/doc/kcontrol/solid-device-automounter/CMakeLists.txt @@ -0,0 +1,2 @@ +########### install files ############### +kde4_create_handbook(index.docbook INSTALL_DESTINATION ${HTML_INSTALL_DIR}/en SUBDIR kcontrol/solid-device-automounter) diff --git a/doc/kcontrol/solid-device-automounter/index.docbook b/doc/kcontrol/solid-device-automounter/index.docbook new file mode 100644 index 00000000..4197374b --- /dev/null +++ b/doc/kcontrol/solid-device-automounter/index.docbook @@ -0,0 +1,102 @@ + + + +]> +
+Removable Devices + + +TreverFischer + + + +2012-12-05 +&kde; 4.12 + + +KDE +Systemsettings +automount +device + + + + +This dialog allows you to configure automatic handling of removable storage media. + + +If you enable the automatic mounting features in this module, you will not need to use +the device notifier applet or the navigation panel in the file manager to get access to a +recently plugged in device. + + +At the top of the dialog you find the global settings, which can be overridden +for each single device in the Device Overrides list. +For a single-user desktop it is recommended to have all the +check boxes above the overrides list enabled. + + +Enable automatic mounting of removable media + +When this is unchecked, no device automounting of any kind will happen, +regardless of anything selected in the Device Overrides section. + + + +Only automatically mount removable media that has been +manually mounted before + +When this is checked, &kde; will only automatically mount devices it +remembers. A device is remembered if it has ever been mounted before; ⪚ +plugging in a USB media player to charge is not sufficient to remember it. +If the files are not accessed, &kde; +will not automatically mount the player next time it is seen. Once they have +been accessed, however, &kde; will remember to automatically make the contents +accessible to your system. + + + +Mount all removable media at login + +If any removable storage devices are connected to your system when you login +to your desktop, &kde; will automatically make the contents available to your +system for other programs to read. + + + +Automatically mount removable media when attached + +When this is checked, &kde; will automatically make the contents of any +storage device available to the system when it is plugged in or attached. + + + +Device Overrides + +This list contains the storage devices known to &kde;. If Automount on Login +is checked, the device will be automatically mounted even though Mount +all removable media at login is unchecked. The same applies for +Automount on Attach. + +If Enable automatic mounting of removable media is unchecked, the +overrides do not apply and no devices will be automatically mounted. + + + +Forget Device + +Clicking this button causes &kde; to forget that the selected devices ever +existed. This is only useful if Only automatically mount removable media +that has been manually mounted before is checked. Once a device is +forgotten and &kde; is set to only automatically mount familiar devices, the +device will not be automatically mounted. + + + + + + + +
diff --git a/doc/kcontrol/spellchecking/CMakeLists.txt b/doc/kcontrol/spellchecking/CMakeLists.txt new file mode 100644 index 00000000..1e15f569 --- /dev/null +++ b/doc/kcontrol/spellchecking/CMakeLists.txt @@ -0,0 +1,2 @@ +########### install files ############### +kde4_create_handbook(index.docbook INSTALL_DESTINATION ${HTML_INSTALL_DIR}/en SUBDIR kcontrol/spellchecking) diff --git a/doc/kcontrol/spellchecking/index.docbook b/doc/kcontrol/spellchecking/index.docbook new file mode 100644 index 00000000..59526340 --- /dev/null +++ b/doc/kcontrol/spellchecking/index.docbook @@ -0,0 +1,119 @@ + + + + +]> + +
+ +Spell Checker + + +&Lauri.Watts; &Lauri.Watts.mail; + + + + +2013-12-05 +&kde; 4.12 + + +KDE +Spelling +dictionary + + + + + + + +Spell Checker +The configuration options available here are used as default by all &kde; +applications that use &sonnet;, which is a frontend to various free spell checkers. + +To use &sonnet; you need to install spell checkers like ⪚ +GNU Aspell, +Enchant, +Hspell, +ISpell or +Hunspell +and additionally the corresponding dictionaries for your language. + +The configuration options selected here can be overridden by each application. + +In the drop down box Default language choose from the +available dictionaries, which one to use for &sonnet;. + + +Spell Options + + + + +Automatic spell checking enabled by default + +If a mark is placed in this checkbox, the spelling of words will be check in your document +as you type them. Misspelled will have a red line drawn under them. + + + + + +Skip all uppercase words + +If a mark is placed in this checkbox, the spelling of any word which consists of all capital +letters will not be checked. +This is useful for document using a large number of acronyms. If this box is left unchecked, +most of those acronyms will be incorrectly marked. By placing a mark in this checkbox, +the acronyms will not be marked as misspelled. + + + + +Skip run-together words +If this box is not checked, then words that appear in the +dictionary separately, but have been run together, are considered to be +spelling errors. Examples of such words are shutout, cannot, and blackout. + + +Checking this box will help prevent applications from flagging website and email addresses +for spelling errors. These addresses often contain words run together. + + + + + + +Ignoring words +The bottom half of the dialog box allows you to designate specific words (they may be specialized terminology, proper names, &etc;) which +should be ignored by the spelling program. + +Adding a word to the ignore list +To add a word, type the word in the text box and click the Add button. + + +Deleting a word from the ignore list +To remove a word, select the word in the listbox containing all the currently ignored words by clicking on it with +the &LMB;. Now click the Remove button. + + +Changing the order a word appears in the list +To move a word in the list, select the word in the listbox containing all the currently ignored words by clicking on it with +the &LMB;. Now click the Move Up button or the Move Down button to move the word +within the list. + +When you are happy with the changes, simply click +Apply. + +Clicking on the Defaults button restores all +values to their default values. + + + + +
diff --git a/doc/kcontrol/trash/CMakeLists.txt b/doc/kcontrol/trash/CMakeLists.txt new file mode 100644 index 00000000..559f8e34 --- /dev/null +++ b/doc/kcontrol/trash/CMakeLists.txt @@ -0,0 +1,2 @@ +########### install files ############### +kde4_create_handbook(index.docbook INSTALL_DESTINATION ${HTML_INSTALL_DIR}/en SUBDIR kcontrol/trash) diff --git a/doc/kcontrol/trash/index.docbook b/doc/kcontrol/trash/index.docbook new file mode 100644 index 00000000..099d6db2 --- /dev/null +++ b/doc/kcontrol/trash/index.docbook @@ -0,0 +1,65 @@ + + + +]> +
+Trash + + +&Burkhard.Lueck; + + + +2009-11-24 +&kde; 4.4 + + +KDE +Systemsettings +trash + + + + +This module allows you to configure the settings for the trash. + + + +Delete files older than + +Check this box to allow automatic deletion of files that are +older than the value specified. Leave this disabled to not +automatically delete any items after a certain timespan. +Set the number of days that files can remain in the trash. Any files +older than this will be automatically deleted. + + + +Limit to maximum size + +Check this box to limit the trash to the maximum amount of disk space +that you specify below. Otherwise, it will be unlimited. + + + +Maximum size + +This is the maximum percent of disk space that will be used for the +trash. The calculated amount of disk space that will be allowed for +the trash is displayed right of the spinbox. + + + +When limit reached + +When the size limit is reached, the selected action will be performed, +either the oldest or biggest files will be deleted automatically +or you will be warned. + + + + + +
diff --git a/doc/kcontrol/useragent/CMakeLists.txt b/doc/kcontrol/useragent/CMakeLists.txt new file mode 100644 index 00000000..c350c7bc --- /dev/null +++ b/doc/kcontrol/useragent/CMakeLists.txt @@ -0,0 +1,2 @@ +########### install files ############### +kde4_create_handbook(index.docbook INSTALL_DESTINATION ${HTML_INSTALL_DIR}/en SUBDIR kcontrol/useragent) diff --git a/doc/kcontrol/useragent/index.docbook b/doc/kcontrol/useragent/index.docbook new file mode 100644 index 00000000..816e379f --- /dev/null +++ b/doc/kcontrol/useragent/index.docbook @@ -0,0 +1,110 @@ + + + +]> + +
+Browser Identification + + +&Krishna.Tateneni; &Krishna.Tateneni.mail; + + + +2009-11-24 +&kde; 4.4 + + +KDE +Systemsettings +user agent +browser +identification + + + + + +Browser Identification + + + +Introduction + +When &konqueror; connects to a web site to retrieve information, +some basic identifying information is sent to the web site in the form +of a User Agent header. + +Because of minor differences in the way that different web +browsers function, web sites that rely too much on a single browser may +sometimes not display as intended when viewed using another +browser. Some web sites are smart enough to examine the contents of the +user agent header and incorporate this information in the +&HTML; code so that the content is displayed correctly +regardless of the browser used. + +However, you may find that some web sites refuse to function +correctly unless you are using a browser recognized as +proper by that site. In these cases, you may find it +necessary to fool the web site by having &konqueror; report itself to be +another browser by means of the user agent header. + + + + +Use + +In this module you can configure the +type of browser that &konqueror; will report itself to be. You can +control this information by web site. Usually, the list box that is +labeled Site Specific Identification will be +empty, so that &konqueror; will always use its default useragent +string. + +You can disable the sending of a user agent entirely, by +unchecking the Send identification +check box. This may cause strange behavior on some sites, and may even +deny you access to some websites, so disable this with caution. + +To configure a new agent binding, press the +New... button. Type the name of the server or +a domain in the text box at the top of the dialog that pops up, which +is labeled When browsing the following +site. + +Note that you can not use the wildcard +character * in this text box. However, the string +kde.org will match all hosts in the domain +kde.org + +After typing the name of the server, type in the identifying +string in the next combo box, which is labeled Use the +following identification:, or choose a string from the list. If +you don't choose a string from the list, you will need to know what a +valid string from the browser looks like. For example, you could type +Mozilla/4.0 (compatible; MSIE 4.0). + +You can click on an existing entry in the list, and then modify the contents of the +text boxes, followed by clicking Change.... + +The Delete button can be used to delete +the selected entry in the list of configured agent bindings. The +Delete All will remove all the configured user +agent strings. Click the Apply to take your +changes in effect. + +You can use the check boxes at the top of the screen to build a +user agent that is uniquely yours, by choosing your own combination of +operating system name and version, platform, processor type, and +language. + +In all cases, the user agent that is being sent by default is +displayed in bold text at the top of the page. + + + + + +
\ No newline at end of file diff --git a/doc/kdebugdialog/CMakeLists.txt b/doc/kdebugdialog/CMakeLists.txt new file mode 100644 index 00000000..cad13c8f --- /dev/null +++ b/doc/kdebugdialog/CMakeLists.txt @@ -0,0 +1,3 @@ +########### install files ############### +# +kde4_create_handbook(index.docbook INSTALL_DESTINATION ${HTML_INSTALL_DIR}/en) diff --git a/doc/kdebugdialog/index.docbook b/doc/kdebugdialog/index.docbook new file mode 100644 index 00000000..b3250911 --- /dev/null +++ b/doc/kdebugdialog/index.docbook @@ -0,0 +1,138 @@ + +KDebugDialog"> + + + + + +]> + +
+KDebugDialog + + +&David.Faure; &David.Faure.mail; + + + +2011-12-20 +1.0 &kde; 4.8 + + +KDE +KDebugdialog +Debug + + + + +&kdebugdialog; is a dialog box for managing diagnostic messages at runtime. +It features a simple and a full mode. +In order to be able to make changes +Disable all debug output has to be unchecked. + + + +Simple mode + +If you simply start kdebugdialog, you will +see a list of areas, that can be disabled or enabled. A +kDebug(area) call in the code will show +something in the debug output only if the area is enabled. + +Note that kWarning, kError and kFatal always appear, +they are NOT controlled by this setting. + +Enter a matching string into the Search +box at the top of the list, this allows you to filter the areas +which are displayed in the list view. +Use the buttons below the list to select or deselect all items in the view +(the other areas are not effected) or change the debug output for a single +item using the check box in front of it. + + + + + + +Full mode + +If you start kdebugdialog +, then for every severity level you can +define separately what should be done with the diagnostic messages of +that level, and the same for each debug area. + +In full mode, first you should select the debug area you are +interested in from the list at the left of the dialog using the +search box at the top of the list. + +You may independently set the output for various types of +messages: + + +Information +Warning +Error +Fatal Error + + +For each of these types, you can set the following: + + + +Output to: + +In this Combobox, you can choose where the messages +should be output. The choices are: File, Message +Box, Shell (meaning stderr) and +Syslog. Please do not direct fatal messages to syslog +unless you are the system administrator yourself. The default is +Shell. + + + + +Filename: +This is only enabled when you have chosen +File as the output and provides the name of that file +(which is interpreted as relative to the current folder). The +default is kdebug.dbg. + + + + +Apart from this, you can also tick the check box Abort +on fatal errors. In this case, if a diagnostic message with +the severity level KDEBUG_FATAL is +output, the application aborts with a SIGABRT after outputting the +message. + + + + + +When you close the dialog by pressing OK, +your entries apply immediately and are saved in +$KDEHOME/share/config/kdebugrc. When you press +Cancel, your entries are discarded and the old +ones are restored. + +Credits to Kalle Dalheimer for the original version of +&kdebugdialog; + + + +&underFDL; + +
+ + diff --git a/doc/kdesu/CMakeLists.txt b/doc/kdesu/CMakeLists.txt new file mode 100644 index 00000000..e78f6bd5 --- /dev/null +++ b/doc/kdesu/CMakeLists.txt @@ -0,0 +1,7 @@ +########### install files ############### +# + +# +kde4_create_handbook(index.docbook INSTALL_DESTINATION ${HTML_INSTALL_DIR}/en) + +kde4_create_manpage(man-kdesu.1.docbook 1 INSTALL_DESTINATION ${MAN_INSTALL_DIR}) diff --git a/doc/kdesu/index.docbook b/doc/kdesu/index.docbook new file mode 100644 index 00000000..dee6f311 --- /dev/null +++ b/doc/kdesu/index.docbook @@ -0,0 +1,339 @@ + + + + + +]> + + + + +The &kdesu; handbook + + +&Geert.Jansen; &Geert.Jansen.mail; + + + + +2000 +&Geert.Jansen; + + +&FDLNotice; + +2010-09-21 +&kde; 4.5 + + +&kdesu; is a graphical front end for the &UNIX; +su command. + + +KDE +su +password +root + + + + + +Introduction + + + +Welcome to &kdesu;! &kdesu; is a graphical front end for the +&UNIX; su command for the K Desktop Environment. +It allows you to run a program as different user by supplying the +password for that user. &kdesu; is an unprivileged program; it uses +the system's su. + +&kdesu; has one additional feature: it can remember passwords +for you. If you are using this feature, you only need to enter the +password once for each command. See for more information on this and a +security analysis. + +This program is meant to be started from the command line or +from .desktop files. Although it asks for the +root password using a &GUI; +dialog, I consider it to be more of a command line <-> &GUI; +glue instead of a pure &GUI; program. + +Since kdesu is no longer installed in +$(kde4-config --prefix)/bin but in kde4-config --path libexec +and therefore not in your Path, you have to use $(kde4-config +--path libexec)kdesu to launch kdesu. + + + +Using &kdesu; + +Usage of &kdesu; is easy. The syntax is like this: + + +kdesu + + command + + file + icon name + + priority + + + + user + + winid + + + +kdesu +&kde; Generic Options +&Qt; Generic Options + + +The command line options are explained below. + + + + +This specifies the command to run as root. It has to be passed +in one argument. So if, for example, you want to start a new file manager, you +would enter at the prompt: $(kde4-config --path libexec)kdesu + + + +Show debug information. + + + +This option allow efficient use of &kdesu; in +.desktop files. It tells &kdesu; to examine the +file specified by file. If this file is +writable by the current user, &kdesu; will execute the command as the +current user. If it is not writable, the command is executed as user +user (defaults to root). +file is evaluated like this: if +file starts with a /, it is +taken as an absolute filename. Otherwise, it is taken as the name of a +global &kde; configuration file. + + + icon name +Specify icon to use in the password dialog. You may specify +just the name, without any extension. +For instance to run &konqueror; in filemanager mode and show the +&konqueror; icon in the password dialog: +$(kde4-config --path libexec)kdesu + + + + + + +Do not keep the password. This disables the keep +password checkbox in the password dialog. + + + priority + +Set priority value. The priority is an arbitrary number between 0 and +100, where 100 means highest priority, and 0 means lowest. The default is +50. + + + + +Use realtime scheduling. + + + + + +Stop the kdesu daemon. See . + + + +Enable terminal output. This disables password keeping. This is +largely for debugging purposes; if you want to run a console mode app, use the +standard su instead. + + + user +While the most common use for &kdesu; is to run a command as +the superuser, you can supply any user name and the appropriate +password. + + + + + + + + +Internals + + +X authentication + +The program you execute will run under the root user id and will +generally have no authority to access your X display. &kdesu; gets +around this by adding an authentication cookie for your display to a +temporary .Xauthority file. After the command +exits, this file is removed. + +If you don't use X cookies, you are on your own. &kdesu; will +detect this and will not add a cookie but you will have to make sure +that root is allowed to access to your display. + + + + +Interface to <command>su</command> + +&kdesu; uses the sytem's su for acquiring +priviliges. In this section, I explain the details of how &kdesu; does +this. + +Because some su implementations (&ie; the one +from &RedHat;) don't want to read the password from +stdin, &kdesu; creates a pty/tty pair and executes +su with its standard filedescriptors connected to +the tty. + +To execute the command the user selected, rather than an +interactive shell, &kdesu; uses the argument with +su. This argument is understood by every shell that +I know of so it should work portably. su passes +this argument to the target user's shell, and the +shell executes the program. Example command: su . + +Instead of executing the user command directly with +su, &kdesu; executes a little stub program called +kdesu_stub. This stub (running as the +target user), requests some information from &kdesu; over the pty/tty +channel (the stub's stdin and stdout) and then executes the user's +program. The information passed over is: the X display, an X +authentication cookie (if available), the PATH and the +command to run. The reason why a stub program is used is that the X +cookie is private information and therefore cannot be passed on the +command line. + + + + +Password Checking + +&kdesu; will check the password you entered and gives an error +message if it is not correct. The checking is done by executing a test +program: /bin/true. If this succeeds, the +password is assumed to be correct. + + + + +Password Keeping + +For your comfort, &kdesu; implements a keep +password feature. If you are interested in security, you +should read this paragraph. + +Allowing &kdesu; to remember passwords opens up a (small) +security hole in your system. Obviously, &kdesu; does not allow +anybody but your user id to use the passwords, but, if done without +caution, this would lowers root's security level to that of a +normal user (you). A hacker who breaks into your account, would get +root access. &kdesu; tries +to prevent this. The security scheme it uses is, in my opinion at +least, reasonably safe and is explained here. + +&kdesu; uses a daemon, called +kdesud. The daemon listens to a &UNIX; +socket in /tmp for commands. The mode of the +socket is 0600 so that only your user id can connect to it. If +password keeping is enabled, &kdesu; executes commands through this +daemon. It writes the command and root's password to the socket and the +daemon executes the command using su, as describe +before. After this, the command and the password are not thrown +away. Instead, they are kept for a specified amount of time. This is +the timeout value from in the control module. If another request for +the same command is coming within this time period, the client does +not have to supply the password. To keep hackers who broke into your +account from stealing passwords from the daemon (for example, by +attaching a debugger), the daemon is installed set-group-id +nogroup. This should prevent all normal users (including you) from +getting passwords from the kdesud +process. Also, the daemon sets the DISPLAY environment +variable to the value it had when it was started. The only thing a +hacker can do is execute an application on your display. + +One weak spot in this scheme is that the programs you execute +are probably not written with security in mind (like setuid +root programs). This means +that they might have buffer overruns or other problems and a hacker +could exploit those. + +The use of the password keeping feature is a tradeoff between +security and comfort. I encourage you to think it over and decide for +yourself if you want to use it or not. + + + + + +Author + +&kdesu; + +Copyright 2000 &Geert.Jansen; + +&kdesu; is written by &Geert.Jansen;. It is somewhat based on +Pietro Iglio's &kdesu;, version 0.3. Pietro and I agreed that I will +maintain this program in the future. + +The author can be reached through email at &Geert.Jansen.mail;. +Please report any bugs you find to me so that I can fix them. If you +have a suggestion, feel free to contact me. + + + +&underFDL; +&underArtisticLicense; + + + + + + diff --git a/doc/kdesu/man-kdesu.1.docbook b/doc/kdesu/man-kdesu.1.docbook new file mode 100644 index 00000000..9de4f05e --- /dev/null +++ b/doc/kdesu/man-kdesu.1.docbook @@ -0,0 +1,194 @@ + + +]> + + + +KDE User's Manual +&Lauri.Watts; &Lauri.Watts.mail; +2010-09-18 +K Desktop Environment + + + +kdesu +1 + + + +kdesu +Runs a program with elevated privileges + + + + +kdesu + + command + + file + icon name + + priority + + + + user + + winid + + + +kdesu +KDE Generic Options +Qt Generic Options + + + + +Description +&kdesu; is a graphical front end for the +&UNIX; su command for the K Desktop Environment. +It allows you to run a program as different user by supplying the +password for that user. &kdesu; is an unprivileged program; it uses +the system's su. + +&kdesu; has one additional feature: it can optionally remember passwords +for you. If you are using this feature, you only need to enter the +password once for each command. + +This program is meant to be started from the command line or +from .desktop files. + +Since kdesu is no longer installed in +$(kde4-config --prefix)/bin but in kde4-config --path libexec +and therefore not in your Path, you have to use $(kde4-config +--path libexec)kdesu to launch kdesu. + + + +Options + + + + +This specifies the command to run as root. It has to be passed +in one argument. So if, for example, you want to start a new file manager, you +would enter at the prompt: $(kde4-config --path libexec)kdesu + + + +Show debug information. + + + +This option allow efficient use of &kdesu; in +.desktop files. It tells &kdesu; to examine the +file specified by file. If this file is +writable by the current user, &kdesu; will execute the command as the +current user. If it is not writable, the command is executed as user +user (defaults to root). +file is evaluated like this: if +file starts with a /, it is +taken as an absolute filename. Otherwise, it is taken as the name of a +global &kde; configuration file. + + + icon name +Specify icon to use in the password dialog. You may specify +just the name, without any extension. + + + + + +Do not keep the password. This disables the keep +password checkbox in the password dialog. + + + priority + +Set priority value. The priority is an arbitrary number between 0 and +100, where 100 means highest priority, and 0 means lowest. The default is +50. + + + + +Use realtime scheduling. + + + + + +Stop the kdesu daemon. This is the daemon that caches +successful passwords in the background. This feature may also be disabled with + when &kdesu; is initially run. + + + +Enable terminal output. This disables password keeping. This is +largely for debugging purposes; if you want to run a console mode app, use the +standard su instead. + + + user +While the most common use for &kdesu; is to run a command as +the superuser, you can supply any user name and the appropriate +password. + + + + + +Do not display an ignore button. + + + + + winid +Makes the dialog transient for an X app specified by winid. + + + + + + + + +See Also +su(1) + +More detailed user documentation is available from help:/kdesu +(either enter this URL into &konqueror;, or run +khelpcenter +help:/kdesu). + + + + +Examples +Run kfmclient as user jim, and show the &konqueror; icon in the +password dialog: +$(kde4-config --path libexec)kdesu kfmclient + + + + +Authors +&kdesu; was written by +GeertJansen jansen@kde.org +and PietroIglio +iglio@fub.it. + + + + diff --git a/doc/khelpcenter/CMakeLists.txt b/doc/khelpcenter/CMakeLists.txt new file mode 100644 index 00000000..d5868ac2 --- /dev/null +++ b/doc/khelpcenter/CMakeLists.txt @@ -0,0 +1,5 @@ +########### install files ############### +# +# +# +kde4_create_handbook(index.docbook INSTALL_DESTINATION ${HTML_INSTALL_DIR}/en) diff --git a/doc/khelpcenter/background.png b/doc/khelpcenter/background.png new file mode 100644 index 00000000..65459539 Binary files /dev/null and b/doc/khelpcenter/background.png differ diff --git a/doc/khelpcenter/bgtable.png b/doc/khelpcenter/bgtable.png new file mode 100644 index 00000000..145bbd48 Binary files /dev/null and b/doc/khelpcenter/bgtable.png differ diff --git a/doc/khelpcenter/index.docbook b/doc/khelpcenter/index.docbook new file mode 100644 index 00000000..84bbad86 --- /dev/null +++ b/doc/khelpcenter/index.docbook @@ -0,0 +1,906 @@ + + + + +]> + + + +The &khelpcenter; + +The &kde; Team + + +&FDLNotice; +2013-05-22 +&kde; 4.11 + + + +&kde; is an international technology team that creates +Free Software +for desktop and portable computing. Among &kde;'s products are a modern +desktop system for &Linux; and &UNIX; platforms, comprehensive office +productivity and groupware suites and hundreds of software titles in many +categories including Internet and web applications, multimedia, entertainment, +educational, graphics and software development. + + + + +KDE +kdebase +khelpcenter +kdehelp +help +help center +KDE help center + + + + + + +&kde; Help System Handbook + + + +&kde; Help System + +The &kde; help system is designed to make accessing the common +&UNIX; help systems (man and +info) simple, as well as the native &kde; +documentation (&XML;). + + + +All base &kde; applications come fully documented, thanks to the efforts of the +Documentation team. If you are interested in helping with the documentation +efforts, join the +mailing +list and write to the team at kde-doc-english@kde.org. No +experience is required, just enthusiasm and patience. + + + +If you would like to help translating &kde; documentation to your native +language, review the information, including coordinators for each language team, +on the Localization web site. + + + +Installation + + +&khelpcenter; is an integral part of the &kde; Base installation, and +is installed with every copy of &kde;. It can be found in the kdebase-runtime +package, and is available from the &kde-ftp;, or will be found in your +operating system's kdebase-runtime package. + + + + + + +Invoking Help + + +&khelpcenter; can be called in several ways: + + + + +From the Help menu + + +The most common will probably be from within an application. Choose + + +F1 + +Help +Application Handbook to open that +application's handbook. + + + + + +From the Kickoff Application Launcher + + +Choose the big K in your panel, and select the +Applications tab followed by selecting +Help to open &khelpcenter;, which will open up to the +default start page. + + + + + +From the command line + + +&khelpcenter; may be started using a &URL; to display a +file. &URL;s have been added for +info and man pages +also. You can use them as follows: + + + + +An application help file + + +khelpcenter + + + +Opens the &kwrite; help file, at the contents page. + + + + + +A local &URL; + +khelpcenter + + + + + + +A Man page + + +khelpcenter + + + + + + +An Info page + + +khelpcenter + + + + + + + +Invoking khelpcenter with no parameters opens the +default start page. + + + + + + + + +The &khelpcenter; interface + + +The &khelpcenter; interface consists of two panes of information. + + + +The toolbar and menus are explained further in . + + + +Documents contain their own navigation tools, enabling you to move +either sequentially through a document, using +Next, Previous, and +Contents links, or to move around in a less +structured manner, using hyperlinks. + + + +Links can take you to other parts of the same document, or to a +different document, and you can use the Back (Left +pointing arrow) or Forward (Right pointing arrow) +icons on the toolbar to move through the documents you have viewed in +this session. + + + +The two panes display the contents of the help system, and the help +files themselves, on the left and right respectively. + + + +The Contents Pane + + +The contents pane in &khelpcenter; is +displayed on the left hand side of the window. As you might expect, you +can move the splitter bar, to make sure you can comfortably read the +contents of either pane. + + + +The contents pane is further divided into two +tabs, one containing a tree view +showing all the help information &khelpcenter; is aware of, and the +other contains the &kde; glossary +of terms. + + + +The Contents Tab + + +The Contents tab contains the following default +top level entries in the tree view: + + + + + +&kde; Fundamentals + +The Fundamentals introduce you to the many features of the &kde; Software Collection and +describe many common tasks you can perform in all &kde; applications. + + + + + +Plasma Manual + + +The &plasma; Manual is the documentation for the most visible pillar of &kde;, +the core interface to the desktop. + + + + + +Online Help + +A page with links to online help and additional information provided by the &kde; community. + + + + + +Application Manuals + + +Native &kde; application documentation. All &kde; applications have +documentation in &XML; format, which are converted to +HTML when you view them. This section lists all the +&kde; applications with a brief description and a link to the full +application documentation. + + +The applications are displayed in a tree structure that echoes the default +structure of the K menu, making it easy to find the +application you are looking for. + + + + + +Control Center Modules + + +Provides a list of links to various modules that are located in the &kde; +&systemsettings; application. + + + + + +KInfoCenter Modules + + +Contains a list of links to various KInfocenter modules documentation. + + + + + +Kioslaves + + +Contains a list of links to various KIO modules documentation. + + + + + +&UNIX; manual pages + + +&UNIX; man pages are the traditional on-line documentation format for +&UNIX; systems. Most programs on your system will have a man page. In +addition, man pages exist for programming functions and file +formats. + + + + + +Scrollkeeper + +Additional non-&kde; documentation installed on your system. + + + + + +Browse Info Pages + + +TeXinfo documentation is used by many &GNU; applications, +including gcc (the C/C++ compiler), +emacs, and many others. + + + + + + + + + + + + +The <application>Man</application> and <application>Info</application> +sections + +Man pages are the standard &UNIX; manual pages, and have been in +use for many years on many operating systems. They are extremely +thorough, and are the very best place to get information about most +&UNIX; commands and applications. When people say +RTFM, the Manual they are referring to is very often the +man page. + +The man pages are not perfect. They tend to be in depth, but +also extremely technical, often written by developers, and for +developers. In some cases this makes them somewhat unfriendly, if not +downright impossible for many users to understand. They are, however, +the best source of solid information on most command line +applications, and very often the only source. + +If you've ever wondered what the number is when people write +things like man(1) it means which section of the manual the item is +in. You will see &khelpcenter; uses the numbers to divide the very many +man pages into their own sections, making it easier for you to find +the information you're looking for, if you're just browsing. + +Also available are the Info pages, intended to be a replacement +for the man pages. The maintainer of some applications no longer +update the man pages, so if there is both a man page and an info page +available, the info page is probably the most recent. Most +applications have one or the other though. If the application you are +looking for help on is a &GNU; utility, you will most likely find it +has an info page, not a man page. + + +Navigating inside the <application>Info</application> pages + +Info documents are arranged hierarchically with each page called +a node. All info documents have a Top node, +&ie; the opening page. You can return to the +Top of an info document by pressing +Top. + +Prev & Next +are used to move to the previous/next page at the current level of the +hierarchy. + +Clicking on a menu item within a document moves you to a lower +level in the hierarchy. You may move up the hierarchy by pressing +Up. + +Man is treated similarly to info, with the section index being +the Top node and each man page on the level below. Man entries are +one page long. + + + + + +The &kde; glossary + + +The glossary provides a quick reference point, where you can look up +the definitions of words that may be unfamiliar to you. These range +from &kde; specific applications and technologies, through to general +&UNIX; computing terms. + + + +In the left hand pane you will see a tree view, with two choices: +Alphabetically or By Topic. +Both contain the same entries, sorted differently, to allow you to +quickly find the item of interest. + + + +Navigate down the tree views to the left, and items you select will be +displayed on the right. + + + + + +The menus and toolbar + + +&khelpcenter; has a very minimal interface, allowing you to concentrate +on getting help rather than learning how to use the help browser. + + + +The icons available to you in the toolbar are as follows: + + + +Toolbar Icons + + +Table of Contents + + +Go to the main start page of &khelpcenter;. + + + + + +Back + + +Go to the previous page you viewed. Click the check mark right to the icon. +This displays a list of previously viewed pages. Selecting one +will take you directly back to that page. + + + + + +Forward + + +Go forward one page. This icon is only active if you have +already used the Back icon. + + + + + +Copy + + +Copy text to the clipboard to be pasted in another application. + + + + + +Find + + +Find a word or words within the currently visible page. + + + + + +Increase Font Sizes + + +Increase the size of the text in the viewer pane. + + + + + +Decrease Font Sizes + + +Decrease the size of the text in the viewer pane. This icon is only +enabled if you have previously enlarged the text. + + + + + + + +The menus contain the following entries: + + + + +File + + + + + + + + +&Ctrl;P + +File +Print + + + + +Print the contents of the currently visible page. Handbooks in PDF format you find +on the &kde; Documentation Server. + + + + + + + + +&Ctrl;Q + +File +Quit + + + + +Close and exit &khelpcenter; + + + + + + + + + + +Edit + + + + + + + +&Ctrl;C + +EditCopy + + + + +Copy the selected text to the clipboard. + + + + + + +&Ctrl;A +Edit +Select All + + + + +Select all the text in the current page. + + + + + + +&Ctrl;F +Edit +Find... + + + + +Find a word or words in the currently visible page. + + + + + + + + + + +View + + + + +View +Set Encoding + + + + +Change the encoding of the current page. Normally, the default setting +of Default should be sufficient, but if you are +having problems viewing pages written in languages other than English, +you may need to choose a specific encoding in this menu. + + + + + + + + + + +Go + + + + +&Alt;Home +Go +Table of Contents + + +Go to the main start page of &khelpcenter;. + + + + + + +&Ctrl;PgUp +Go +Previous Page + + +Go to the previous page of the current documentation. + + + + + + +&Ctrl;PgDown +Go +Next Page + + +Go to the next page of the current documentation. + + + + + + +&Alt;Left +Go +Back + +Go back to the previous page you were viewing. + + + + + +&Alt;Right +Go +Forward + + +If you have previously moved back with the back icon or menu +entry, you can work your way forward again with this menu +entry. + + + + + + + + + + + +Settings + + + + + + +Settings +Configure Fonts... + + + + +Allows you to configure the font family and size used by &khelpcenter;. + + + + + + + + + + +Additionally &khelpcenter; has the common &kde; Settings and Help +menu items, for more information read the sections about the Settings Menu and Help Menu +of the &kde; Fundamentals. + + + + + + + +Credits and License + +&khelpcenter; + +Originally developed by &Matthias.Elter; &Matthias.Elter.mail; +The current maintainer is &Cornelius.Schumacher; &Cornelius.Schumacher.mail; + + + +&underFDL; +&underGPL; + + + + + + + + + diff --git a/doc/khelpcenter/kdelogo2.png b/doc/khelpcenter/kdelogo2.png new file mode 100644 index 00000000..d2039e2b Binary files /dev/null and b/doc/khelpcenter/kdelogo2.png differ diff --git a/doc/khelpcenter/khelpcenter.png b/doc/khelpcenter/khelpcenter.png new file mode 100644 index 00000000..224084a4 Binary files /dev/null and b/doc/khelpcenter/khelpcenter.png differ diff --git a/doc/khelpcenter/konq.css b/doc/khelpcenter/konq.css new file mode 100644 index 00000000..ee75f658 --- /dev/null +++ b/doc/khelpcenter/konq.css @@ -0,0 +1,68 @@ +body {background-color: #3679AD; + color: #000000; + margin-left: 0; + margin-right: 0; + margin-top: 5; + padding: 0; + background-image: url(background.png); + background-repeat: no-repeat; + background-position: top-center;} + +.caption { + color: black; + font-family: sans-serif; + font-size: 23pt; + font-style: italic; + font-weight: bolder; + margin-left: 3pt; +} + +td.trans {background-image: url(bgtable.png); + background-repeat: no-repeat;} +td.end {background-image: url(lines2.png); + background-repeat: x-repeat;} +td.shadow1 {background-image: url(shadow1.png); + background-repeat: x-repeat;} + +table.vnice { font-family: sans-serif; + font-size: x-small;} + +a:link {background-color: transparent; + color: #191970; + text-decoration:none;} +a:visited {background-color: transparent; + color: #551a8a; + text-decoration:none;} +a:active {background-color: transparent; + color: #fe0000; + text-decoration:none;} +a:hover {background-color: transparent; + color: #1919aa; + text-decoration:underline;} + +tr.menurow {background-color: #505050; + color: #000000; + vertical-align: middle;} + +td.deco {color: #ffffff; + background-color: #505050; + font-family: sans-serif; + font-size: small;} + +td.menuactive {color: #ffcc00; + background-color: #777777; + font-family: sans-serif; + font-size: small;} + +td.menu {color: #ffffff; + background-color: #505050; + font-family: sans-serif; + font-size: small;} + +a.menu {color: #eeeeee; + font-family: sans-serif; + font-size: small;} + +a.menu:hover {color: #ffffff; + text-decoration:none;} + diff --git a/doc/khelpcenter/lines.png b/doc/khelpcenter/lines.png new file mode 100644 index 00000000..5fbba934 Binary files /dev/null and b/doc/khelpcenter/lines.png differ diff --git a/doc/khelpcenter/lines2.png b/doc/khelpcenter/lines2.png new file mode 100644 index 00000000..f2dd21c5 Binary files /dev/null and b/doc/khelpcenter/lines2.png differ diff --git a/doc/khelpcenter/pointers.png b/doc/khelpcenter/pointers.png new file mode 100644 index 00000000..987283a0 Binary files /dev/null and b/doc/khelpcenter/pointers.png differ diff --git a/doc/khelpcenter/shadow1.png b/doc/khelpcenter/shadow1.png new file mode 100644 index 00000000..661c0b9c Binary files /dev/null and b/doc/khelpcenter/shadow1.png differ diff --git a/doc/kioslave/CMakeLists.txt b/doc/kioslave/CMakeLists.txt new file mode 100644 index 00000000..f4c618e5 --- /dev/null +++ b/doc/kioslave/CMakeLists.txt @@ -0,0 +1,19 @@ +add_subdirectory(bookmarks) +add_subdirectory(bzip2) +add_subdirectory(cgi) +add_subdirectory(finger) +add_subdirectory(fish) +add_subdirectory(floppy) +add_subdirectory(gzip) +add_subdirectory(info) +add_subdirectory(man) +add_subdirectory(network) +add_subdirectory(nfs) +add_subdirectory(sftp) +if(NOT WIN32) +add_subdirectory(smb) +endif(NOT WIN32) +add_subdirectory(tar) +add_subdirectory(thumbnail) +add_subdirectory(xz) +add_subdirectory(nepomuksearch) diff --git a/doc/kioslave/bookmarks/CMakeLists.txt b/doc/kioslave/bookmarks/CMakeLists.txt new file mode 100644 index 00000000..f030511b --- /dev/null +++ b/doc/kioslave/bookmarks/CMakeLists.txt @@ -0,0 +1,3 @@ +########### install files ############### +kde4_create_handbook(index.docbook INSTALL_DESTINATION ${HTML_INSTALL_DIR}/en SUBDIR kioslave/bookmarks) + diff --git a/doc/kioslave/bookmarks/index.docbook b/doc/kioslave/bookmarks/index.docbook new file mode 100644 index 00000000..9923e6c0 --- /dev/null +++ b/doc/kioslave/bookmarks/index.docbook @@ -0,0 +1,29 @@ + + + +]> + +
+bookmarks + + + +XavierVello +xavier.vello@gmail.com + + + + +2008-08-31 +0.2 + + + +This KIO displays your bookmarks as a nice and functional &HTML; page. You access it typing bookmarks:/ in the &konqueror; location bar. + +The content and layout of the page is configurable. Just point &konqueror; to bookmarks:/config to launch the configuration dialog. + +
+ diff --git a/doc/kioslave/bzip2/CMakeLists.txt b/doc/kioslave/bzip2/CMakeLists.txt new file mode 100644 index 00000000..114efda1 --- /dev/null +++ b/doc/kioslave/bzip2/CMakeLists.txt @@ -0,0 +1,3 @@ +########### install files ############### +kde4_create_handbook(index.docbook INSTALL_DESTINATION ${HTML_INSTALL_DIR}/en SUBDIR kioslave/bzip2) + diff --git a/doc/kioslave/bzip2/index.docbook b/doc/kioslave/bzip2/index.docbook new file mode 100644 index 00000000..d104ac6f --- /dev/null +++ b/doc/kioslave/bzip2/index.docbook @@ -0,0 +1,40 @@ + + + +]> + +
+bzip2 / bzip + + +&Lauri.Watts; &Lauri.Watts.mail; + + + + +bzip2 is a compression program. + +The bzip2 kioslave is not directly usable, and is intended for use +as a filter. For example, the tar kioslave can filter a file through +the bzip2 kioslave, in order to display the contents of a tar.bz2 file directly in a &konqueror; +window. + +If you click on a file compressed with a .bz2 in &konqueror;, this kioslave is used to +uncompress it and display it as a normal (uncompressed) file. + +If you are a developer, and would like to use the bzip2 filter, +you can find documentation on using kioslaves at http://techbase.kde.org + + See the manual: bzip2. + + +bzip is the ancestor of bzip2. It is rarely +used today, having been replaced with bzip2, which offers much better +compression. + +
diff --git a/doc/kioslave/cgi/CMakeLists.txt b/doc/kioslave/cgi/CMakeLists.txt new file mode 100644 index 00000000..132d95dd --- /dev/null +++ b/doc/kioslave/cgi/CMakeLists.txt @@ -0,0 +1,3 @@ +########### install files ############### +kde4_create_handbook(index.docbook INSTALL_DESTINATION ${HTML_INSTALL_DIR}/en SUBDIR kioslave/cgi) + diff --git a/doc/kioslave/cgi/index.docbook b/doc/kioslave/cgi/index.docbook new file mode 100644 index 00000000..04e9721b --- /dev/null +++ b/doc/kioslave/cgi/index.docbook @@ -0,0 +1,45 @@ + + + +]> + +
+cgi + + +&Lauri.Watts;&Lauri.Watts.mail; + + + + +The CGI slave provides a way to execute +CGI programs without the need to have a running web +server. This can for example be used for local testing of +CGI programs or for using search engines that only +provide a CGI frontend like the one from +Doxygen. + +The slave implements the cgi: protocol. It +uses the filename from the given &URL; and searches a configurable +list of folders. +The list of folders can be retrieved using the command +kde4-config +. The value defaults to $HOME/.kde4/cgi-bin/. + +Use the &systemsettings; module CGI Script +(launched with kcmshell4 +) to add or remove additional user defined paths that are searched for +CGI scripts. + +If this kioslave finds an executable with the given name it +executes it, passes the arguments of the &URL; and sets the +environment variables needed by CGI +programs. + +
+ diff --git a/doc/kioslave/finger/CMakeLists.txt b/doc/kioslave/finger/CMakeLists.txt new file mode 100644 index 00000000..a3bc4b6e --- /dev/null +++ b/doc/kioslave/finger/CMakeLists.txt @@ -0,0 +1,3 @@ +########### install files ############### +kde4_create_handbook(index.docbook INSTALL_DESTINATION ${HTML_INSTALL_DIR}/en SUBDIR kioslave/finger) + diff --git a/doc/kioslave/finger/index.docbook b/doc/kioslave/finger/index.docbook new file mode 100644 index 00000000..988450b2 --- /dev/null +++ b/doc/kioslave/finger/index.docbook @@ -0,0 +1,40 @@ + + + +]> + +
+finger + + +&Lauri.Watts;&Lauri.Watts.mail; + + + + +Finger is a program to display information about users. + +If finger is enabled on the remote machine, you may be given +information on the user's real name, if they are currently logged in, if +they have mail and the text of their .plan file in +their home folder. + +Finger is normally associated with a user@hostname address, which +may or may not be the same as a users email address. + +Most Internet Service Providers no longer allow finger access, so, +you may find that you get no useful answer for most people. + +Other people use their local .plan file to +hold such information as PGP keys, the fact they are +on vacation, and all sorts of information. + +Use the finger kioslave like this: +finger://username@hostname + + See the manual: finger. + + +
diff --git a/doc/kioslave/fish/CMakeLists.txt b/doc/kioslave/fish/CMakeLists.txt new file mode 100644 index 00000000..cdfbbe89 --- /dev/null +++ b/doc/kioslave/fish/CMakeLists.txt @@ -0,0 +1,3 @@ +########### install files ############### +kde4_create_handbook(index.docbook INSTALL_DESTINATION ${HTML_INSTALL_DIR}/en SUBDIR kioslave/fish) + diff --git a/doc/kioslave/fish/index.docbook b/doc/kioslave/fish/index.docbook new file mode 100644 index 00000000..f1af31db --- /dev/null +++ b/doc/kioslave/fish/index.docbook @@ -0,0 +1,73 @@ + + + +]> + +
+fish + + +&Joerg.Walter; &Joerg.Walter.mail; +&Brad.Hards; &Brad.Hards.mail; + + + +2010-10-27 +&kde; 4.5 + + + +Allows you to access another computer's files using the Secure SHell (SSH) protocol. The remote computer needs to be running the SSH daemon, but the remainder of the protocol uses standard commandline tools as discussed below. + +You can use the fish kioslave like this: +fish://hostname or fish://username@hostname. + +You need to use double forward slashes. + +You can omit the username (and the trailing +@ symbol) if you have the same username on both computers. + +You can add a password in the format: +fish://username:password@hostname +but it is not necessary as you will be prompted for one if it is not +supplied. + +If you are running the SSH daemon on a non-standard +port, you can specify that port using the normal &URL; syntax as shown +below: +fish://hostname:portnumber. + +Fish should work with any roughly POSIX compatible +&UNIX; based remote computer. It uses the shell commands +cat, chgrp, +chmod, chown, +cp, dd, +env, expr, +grep, ls, +mkdir, mv, +rm, rmdir, +sed, +and wc. Fish starts +/bin/sh as its shell and expects it to be a +Bourne shell (or compatible, like bash). +If the sed and +file commands are available, as well as a +/etc/apache/magic file with &MIME; type +signatures, these will be used to guess &MIME; types. + + +If Perl is available on the remote +machine, it will be used instead. Then only env and +/bin/sh are needed. Using +Perl has the additional benefit of being +faster. + +Fish may even work on &Windows; machines, if tools like +Cygwin are installed. All the above +utilities must be in the system PATH, and the initial +shell must be able to process the command echo +FISH:;/bin/sh correctly. + +
diff --git a/doc/kioslave/floppy/CMakeLists.txt b/doc/kioslave/floppy/CMakeLists.txt new file mode 100644 index 00000000..6eaae266 --- /dev/null +++ b/doc/kioslave/floppy/CMakeLists.txt @@ -0,0 +1,3 @@ +########### install files ############### +kde4_create_handbook(index.docbook INSTALL_DESTINATION ${HTML_INSTALL_DIR}/en SUBDIR kioslave/floppy) + diff --git a/doc/kioslave/floppy/index.docbook b/doc/kioslave/floppy/index.docbook new file mode 100644 index 00000000..f90d4416 --- /dev/null +++ b/doc/kioslave/floppy/index.docbook @@ -0,0 +1,58 @@ + + + +]> + +
+Floppy + + +&Alexander.Neundorf; &Alexander.Neundorf.mail; + + + + + +The floppy ioslave gives you easy access to the floppy disk drives +installed on your system. + + + +The drive letter becomes the first subdirectory +in the floppy &URL;. Let's say there is a file logo.png on your floppy +disk in drive A, then the &URL; will be floppy:/a/logo.png + + + +If you want to access drive B, floppy:/b will do it. +floppy:/ is a shortcut for floppy:/a. + + +Note that floppy:/logo.png means you have a disk drive +named logo.png. + + +To use it you need to have the mtools package +installed, and the floppy ioslave supports everything the various mtools +command line utilities support. You don't have to mount your floppy disks, +simply enter floppy:/ in any &kde; 3.x app and you will be able to +read from and write to your floppy drive. + + +It also works with USB sticks, ZIP and JAZ drives. +You can use floppy:/u for the USB stick and floppy:/z for the zip drive, for example. +To make this work, you might need to adjust your /etc/mtools file. See the manpage +for documentation. + + +The ioslave gives read and write access to the floppy drive, but not +simultaneously. While you can read and write to the floppy during the same +session, reading and writing have to happen one after the other, not at the same +time. + +Author: Alexander Neundorf neundorf@kde.org + +
+ diff --git a/doc/kioslave/gzip/CMakeLists.txt b/doc/kioslave/gzip/CMakeLists.txt new file mode 100644 index 00000000..7a2b465f --- /dev/null +++ b/doc/kioslave/gzip/CMakeLists.txt @@ -0,0 +1,3 @@ +########### install files ############### +kde4_create_handbook(index.docbook INSTALL_DESTINATION ${HTML_INSTALL_DIR}/en SUBDIR kioslave/gzip) + diff --git a/doc/kioslave/gzip/index.docbook b/doc/kioslave/gzip/index.docbook new file mode 100644 index 00000000..d8752a5c --- /dev/null +++ b/doc/kioslave/gzip/index.docbook @@ -0,0 +1,37 @@ + + + +]> + +
+gzip + + +&Lauri.Watts; &Lauri.Watts.mail; + + + + +gzip is a compression program + +The gzip kioslave is not directly usable, and is intended for use +as a filter. For example, the tar kioslave can filter a file through +the gzip kioslave, in order to display the contents of a tar.gz file directly in a &konqueror; +window. + +If you click on a file compressed with a gz extension in &konqueror;, this kioslave is +used to uncompress it and display it as a normal (uncompressed) +file. + +If you are a developer, and would like to use the gzip filter, you +can find documentation on using kioslaves at http://techbase.kde.org + + See the manual: gzip. + + +
diff --git a/doc/kioslave/info/CMakeLists.txt b/doc/kioslave/info/CMakeLists.txt new file mode 100644 index 00000000..76351eff --- /dev/null +++ b/doc/kioslave/info/CMakeLists.txt @@ -0,0 +1,3 @@ +########### install files ############### +kde4_create_handbook(index.docbook INSTALL_DESTINATION ${HTML_INSTALL_DIR}/en SUBDIR kioslave/info) + diff --git a/doc/kioslave/info/index.docbook b/doc/kioslave/info/index.docbook new file mode 100644 index 00000000..2724c7dd --- /dev/null +++ b/doc/kioslave/info/index.docbook @@ -0,0 +1,43 @@ + + + +]> + +
+Info + + +&Lauri.Watts; &Lauri.Watts.mail; + + Nicolas + Goutte + goutte@kde.org + + + + + +Info is a type of documentation. The documents are in a file +format called texinfo, and can be read on the command line with the +info program. + +The Info ioslave allows you to read the info pages installed on +your system, from within &konqueror;. You can use it very easily: + +info:gcc + +This would show you the top level node of the Info documentation +for the &gcc; compiler. + +Info is a &GNU; replacement for +man, but is not widely used outside of +&GNU; software. + +You can quite easily browse the info documentation you have +installed from within the &khelpcenter; application, or you can use the +info ioslave directly from within both &konqueror; and the +mini-cli. + +
diff --git a/doc/kioslave/man/CMakeLists.txt b/doc/kioslave/man/CMakeLists.txt new file mode 100644 index 00000000..4d61de76 --- /dev/null +++ b/doc/kioslave/man/CMakeLists.txt @@ -0,0 +1,3 @@ +########### install files ############### +kde4_create_handbook(index.docbook INSTALL_DESTINATION ${HTML_INSTALL_DIR}/en SUBDIR kioslave/man) + diff --git a/doc/kioslave/man/index.docbook b/doc/kioslave/man/index.docbook new file mode 100644 index 00000000..d337f2cb --- /dev/null +++ b/doc/kioslave/man/index.docbook @@ -0,0 +1,93 @@ + + + +]> + +
+Man + + +&Lauri.Watts; &Lauri.Watts.mail; + + Nicolas + Goutte + goutte@kde.org + + + + + + +Using the man ioslave you are able to read the man pages installed +on your system. It is easy to use: + + + + +man: + +See the sections of the manual, click to find the rest. + + + + +man:/fopen + +See the man page of fopen. + + + + +man:/fopen(3) + +See the man page of fopen in section 3. + + + + +man:/(3) + +See the index of section 3. + + + + +man:/intro(3) + +See the introduction of section 3. + + + + + +If there are more than one man page of the name that you +have entered, you will get a list where you can choose the man page +that you want to see. + + +There is also a shortcut: #fopen, +which has the same effect as above. + + + +If you do not find all your man pages, adjust the configuration file +/etc/manpath.config +(or a file of a similar name depending on your distribution) +or adjust the environment variables +MANPATH and MANSECT. + + + +As with any other &kde; ioslave, it is possible to enter a &URL;, like +man:/socket in any +&kde; application. Try it in &kwrite; and you will see the man page in +&HTML; format. + + + +Contact mailing list: kde-devel@kde.org + + +
diff --git a/doc/kioslave/nepomuksearch/CMakeLists.txt b/doc/kioslave/nepomuksearch/CMakeLists.txt new file mode 100644 index 00000000..1154b0f2 --- /dev/null +++ b/doc/kioslave/nepomuksearch/CMakeLists.txt @@ -0,0 +1,3 @@ +########### install files ############### +kde4_create_handbook(index.docbook INSTALL_DESTINATION ${HTML_INSTALL_DIR}/en SUBDIR kioslave/nepomuksearch) + diff --git a/doc/kioslave/nepomuksearch/index.docbook b/doc/kioslave/nepomuksearch/index.docbook new file mode 100644 index 00000000..4843ebf6 --- /dev/null +++ b/doc/kioslave/nepomuksearch/index.docbook @@ -0,0 +1,110 @@ + + + + +]> + +
+ nepomuksearch + + + + + Sebastian + Trüg + + trueg@kde.org + + + + + 2010-09-10 + 1.0.0 + + + + Overview + + The nepomuksearch protocol allows to search the Nepomuk meta data store for files or any other type of resource (although files is the most important use case since we are talking about virtual file systems here). + + For it to work the Nepomuk system needs to be activated. Activating the Strigi file indexer provides better results and way more search possibilities. + + + Typically nepomuksearch is used transparently to the user through an application like Dolphin which provide GUI elements to construct the necessary query and the corresponding URL. However, it is also possible to write a query URL manually. There are two different possibilities which might be of interest to the user (be aware that queries created as presented below are not restricted to files): + + + + nepomuksearch:/?query=Nepomuk + + + will look for anything containing the word "Nepomuk". "Nepomuk" can be replaced with anything the simple allows. + + + + + nepomuksearch:/?sparql=select ?r where { ?r nao:hasTag ?tag . ?tag nao:prefLabel 'Nepomuk'^^xsd:string . } + + + will execute the SPARQL query which in this case looks for all resources that are tagged with a tag that has the label "Nepomuk". Be aware that the query needs to be percent-encoded, &ie; a URI like <http://www.semanticdesktop.org/ontologies/2007/08/15/nao#Tag> would have to be written as %3chttp:%2f%2fwww.semanticdesktop.org%2fontologies%2f2007%2f08%2f15%2fnao#Tag%3e. + + + + + + + + Nepomuk Query Syntax + The syntax is fairly simple. Multiple query terms can be combined with the keywords AND or OR, terms can be excluded by prefixing them with a minus, and specific properties can be searched by combining the property name with a comparator and the value. + + This syntax can also be used in standard search fields such as the Dolphin one. + + + Examples + + + + Nepomuk KDE or Nepomuk AND KDE + + + search for everything containing the words "Nepomuk" and "KDE" in any of their properties (this includes the content of files). + + + + + Nepomuk OR KDE + + + search for everything containing either the word "Nepomuk" or the word "KDE" in any of their properties. + + + + + "Nepomuk KDE" + + + search for everything containing the exact phrase "Nepomuk KDE" in any of their properties. + + + + + hastag:Nepomuk + + + search for everything that is tagged with a tag named "Nepomuk". + + + + + +hastag:nepomuk AND -hastag:scribo + + + search for everything that has a tag labeled "nepomuk" but not a tag labeled "scribo". + + + + + + +
diff --git a/doc/kioslave/network/CMakeLists.txt b/doc/kioslave/network/CMakeLists.txt new file mode 100644 index 00000000..707228e9 --- /dev/null +++ b/doc/kioslave/network/CMakeLists.txt @@ -0,0 +1 @@ +kde4_create_handbook(index.docbook INSTALL_DESTINATION ${HTML_INSTALL_DIR}/en SUBDIR kioslave/network) diff --git a/doc/kioslave/network/index.docbook b/doc/kioslave/network/index.docbook new file mode 100644 index 00000000..560d4c1d --- /dev/null +++ b/doc/kioslave/network/index.docbook @@ -0,0 +1,61 @@ + + + +]> + +
+ +network + + + + + Friedrich W. H.Kossebau + kossebau@kde.org + + + + + 2009-04-28 + 0.1 + + + + + + The network ioslave enables the user to browse the devices connected to the local network + and the services running on them. It it also possible to start programs for services + whose type is known. + + + + To see all the devices found, enter + network:/. + + + + network:/hostname_of_device + will list the services found to be running on a device. + + + + Selecting a service will forward to a url which matches the service, given there is a suitable, e.g. + ssh:/hostname_of_device:port/ for a SSH service. + Each known service type has a mimetype assigned to it, so a user can assign new handlers + for the resulting urls. This is done with the control module + File Associations in &systemsettings;. + The mimetypes of the services are currently all named inode/vnd.kde.service.*. + + + + + The network kioslave currently only finds and displays devices and services which are + actively advertising themselves using the service discovery framework + DNS-SD. + + + +
+ diff --git a/doc/kioslave/nfs/CMakeLists.txt b/doc/kioslave/nfs/CMakeLists.txt new file mode 100644 index 00000000..668a6040 --- /dev/null +++ b/doc/kioslave/nfs/CMakeLists.txt @@ -0,0 +1,3 @@ +########### install files ############### +kde4_create_handbook(index.docbook INSTALL_DESTINATION ${HTML_INSTALL_DIR}/en SUBDIR kioslave/nfs) + diff --git a/doc/kioslave/nfs/index.docbook b/doc/kioslave/nfs/index.docbook new file mode 100644 index 00000000..f0c8799b --- /dev/null +++ b/doc/kioslave/nfs/index.docbook @@ -0,0 +1,46 @@ + + + +]> + +
+nfs + + +&Lauri.Watts; &Lauri.Watts.mail; + + + + +Sun's NFS protocol provides transparent remote access to +shared file systems across networks. The NFS protocol is +designed to be machine, operating system, network architecture, and +transport protocol independent. This independence is achieved through the +use of Remote Procedure Call (RPC) primitives built on +top of an eXternal Data Representation (XDR). + + + +The supporting MOUNT protocol performs the operating system-specific +functions that allow clients to attach remote folder trees to a point +within the local file system. The mount process also allows the server to +grant remote access privileges to a restricted set of clients via export +control. + + +The Lock Manager provides support for file locking when used in the +NFS environment. The Network Lock Manager +(NLM) protocol isolates the inherently stateful aspects +of file locking into a separate protocol. + + +Source: + +http://www.networksorcery.com/enp/protocol/nfs.htm + + + See the manual: nfs. + +
diff --git a/doc/kioslave/sftp/CMakeLists.txt b/doc/kioslave/sftp/CMakeLists.txt new file mode 100644 index 00000000..9e83b7eb --- /dev/null +++ b/doc/kioslave/sftp/CMakeLists.txt @@ -0,0 +1,3 @@ +########### install files ############### +kde4_create_handbook(index.docbook INSTALL_DESTINATION ${HTML_INSTALL_DIR}/en SUBDIR kioslave/sftp) + diff --git a/doc/kioslave/sftp/index.docbook b/doc/kioslave/sftp/index.docbook new file mode 100644 index 00000000..ba14a682 --- /dev/null +++ b/doc/kioslave/sftp/index.docbook @@ -0,0 +1,26 @@ + + + +]> + +
+sftp + + +&Ferdinand.Gassauer; &Ferdinand.Gassauer.mail; + + + +SFTP is a Secure file transfer protocol. +sftp is an interactive file transfer program, +similar to ftp, but it performs all operations over an encrypted +ssh transport. It may use many of the features of +ssh, including public key authentication and +compression. + + See the manual: sftp. + + +
diff --git a/doc/kioslave/smb/CMakeLists.txt b/doc/kioslave/smb/CMakeLists.txt new file mode 100644 index 00000000..06084267 --- /dev/null +++ b/doc/kioslave/smb/CMakeLists.txt @@ -0,0 +1,3 @@ +########### install files ############### +kde4_create_handbook(index.docbook INSTALL_DESTINATION ${HTML_INSTALL_DIR}/en SUBDIR kioslave/smb) + diff --git a/doc/kioslave/smb/index.docbook b/doc/kioslave/smb/index.docbook new file mode 100644 index 00000000..e676e8ae --- /dev/null +++ b/doc/kioslave/smb/index.docbook @@ -0,0 +1,64 @@ + + + +]> + +
+SMB + + +&Alexander.Neundorf; &Alexander.Neundorf.mail; + + + + +The smb ioslave enables you to browse the shares of a &Windows; (or Samba) +network. + + + +To see the workgroups, enter +smb:/. + + +smb://a_workgroup +will list the hosts in this workgroup. + + +To see the shares of a host, enter +smb://the_host +or +smb:/a_workgroup/the_host. + + +To access a share directly enter +smb://the_host/the_share +or +smb:/a_workgroup/the_host/the_share + + + +The smb ioslave requires that you have libsmbclient to use this ioslave. + + + +You can set your default user name and password in the &systemsettings; +category Network and Connectivity in +Sharing +Windows Shares. This is especially useful if you are a +member of a &Windows; NT domain. There you can also set your +workgroup name, but in most cases this is not required. The kioslave will ask for your username and password if a default is not set. + + + +This ioslave is tested and developed using mainly Samba 2.0.7, but other +versions of Samba should work too. + + + +Author: Alexander Neundorf neundorf@kde.org + +
+ diff --git a/doc/kioslave/tar/CMakeLists.txt b/doc/kioslave/tar/CMakeLists.txt new file mode 100644 index 00000000..9577b046 --- /dev/null +++ b/doc/kioslave/tar/CMakeLists.txt @@ -0,0 +1,3 @@ +########### install files ############### +kde4_create_handbook(index.docbook INSTALL_DESTINATION ${HTML_INSTALL_DIR}/en SUBDIR kioslave/tar) + diff --git a/doc/kioslave/tar/index.docbook b/doc/kioslave/tar/index.docbook new file mode 100644 index 00000000..d15770ac --- /dev/null +++ b/doc/kioslave/tar/index.docbook @@ -0,0 +1,25 @@ + + + +]> + +
+tar + + +&Ferdinand.Gassauer; &Ferdinand.Gassauer.mail; + + + + +An archiving program designed to store and extract files from an archive +file known as a tarfile. A tarfile may be made on a tape drive, however, it +is also common to write a tarfile to a normal file. + + + See the manual: tar. + + +
diff --git a/doc/kioslave/thumbnail/CMakeLists.txt b/doc/kioslave/thumbnail/CMakeLists.txt new file mode 100644 index 00000000..987324e7 --- /dev/null +++ b/doc/kioslave/thumbnail/CMakeLists.txt @@ -0,0 +1,3 @@ +########### install files ############### +kde4_create_handbook(index.docbook INSTALL_DESTINATION ${HTML_INSTALL_DIR}/en SUBDIR kioslave/thumbnail) + diff --git a/doc/kioslave/thumbnail/index.docbook b/doc/kioslave/thumbnail/index.docbook new file mode 100644 index 00000000..5cbd9a2b --- /dev/null +++ b/doc/kioslave/thumbnail/index.docbook @@ -0,0 +1,35 @@ + + + +]> + +
+thumbnail + + +&Carsten.Pfeiffer; &Carsten.Pfeiffer.mail; + + + +The thumbnail kioslave is used by &kde; for network transparent +and persistent generation of thumbnails. + +The thumbnail kioslave uses plugins to generate the actual +thumbnails. You can enable viewing of these thumbnails from the +View +Preview submenu, available in +&konqueror; in file manager mode. + +The thumbnail kioslave is not directly useful to a user, but if +you are a developer, you can use it within your own applications to +create file previews. + +See the documentation in the sources for more information. You +will find these at +$KDEDIR/include/kio/thumbcreator.h or +in the source folder kdebase/runtime/kioslave/thumbnail + +
diff --git a/doc/kioslave/xz/CMakeLists.txt b/doc/kioslave/xz/CMakeLists.txt new file mode 100644 index 00000000..6d422ad5 --- /dev/null +++ b/doc/kioslave/xz/CMakeLists.txt @@ -0,0 +1,3 @@ +########### install files ############### +kde4_create_handbook(index.docbook INSTALL_DESTINATION ${HTML_INSTALL_DIR}/en SUBDIR kioslave/xz) + diff --git a/doc/kioslave/xz/index.docbook b/doc/kioslave/xz/index.docbook new file mode 100644 index 00000000..b8c5fecf --- /dev/null +++ b/doc/kioslave/xz/index.docbook @@ -0,0 +1,37 @@ + + + +]> + +
+xz / lzma + + +Per Øyvind Karlsen + + + + +Xz is a compression program + +The xz kioslave is not directly usable, and is intended for use +as a filter. For example, the tar kioslave can filter a file through +the xz kioslave, in order to display the contents of a tar.lzma or tar.xz +file directly in a &konqueror; window. + +If you click on a file compressed with a .lzma or tar.xz +in &konqueror;, this kioslave is used to +uncompress it and display it as a normal (uncompressed) file. + +If you are a developer, and would like to use the xz filter, +you can find documentation on using kioslaves at http://techbase.kde.org + +See the manual: xz. + + +
diff --git a/doc/knetattach/CMakeLists.txt b/doc/knetattach/CMakeLists.txt new file mode 100644 index 00000000..ac64649a --- /dev/null +++ b/doc/knetattach/CMakeLists.txt @@ -0,0 +1,2 @@ +########### install files ############### +kde4_create_handbook(index.docbook INSTALL_DESTINATION ${HTML_INSTALL_DIR}/en) diff --git a/doc/knetattach/index.docbook b/doc/knetattach/index.docbook new file mode 100644 index 00000000..ccbb55e7 --- /dev/null +++ b/doc/knetattach/index.docbook @@ -0,0 +1,378 @@ + + + + + + + + +]> + + + + + + +The &knetattach; Handbook + + + +&Orville.Bennett; &Orville.Bennett.mail; + + + + + + +2005 +&Orville.Bennett; + +&FDLNotice; + +2010-01-18 +&kde; 4.4 + + + +&knetattach; is a wizard which makes it easier to integrate your +network resources with your &kde; Desktop. + + + + + + +KDE +kdebase +knetattach +Network Folders +Network Folder Wizard +KDE Network Folder Wizard + + + + + + + +Introduction + + +The &knetattach; wizard, affectionately and hereafter known as the +Network Folder Wizard, allows easy addition and integration of various +network folders with your &kde; desktop. Please report any problems or +feature requests for it to the &kde; bugs website. + + + + +Using &knetattach; + + +As you will see in the screenshot below, the Network Folder Wizard currently +allows you to add four types of network folders: WebDav, &FTP;, +&Microsoft; &Windows; (Samba) network drives and SSH. +Additionally you can select a recent connection for the list box. + + +Here's a screenshot of &knetattach; + + + + + +Screenshot + + +Network Folder Wizard main window + + + + + + + +Adding network folders + + +Network folders show up in a special location of &konqueror; and &dolphin; +called a virtual folder. +This virtual folder is accessed by typing remote:/ in +the location bar or by selecting Network from the +Places panel. You will then be able to see +any folders which have been previously added and you also will be able to use +the wizard to add new ones. + +Here's a screenshot of &knetattach; + + + + + +Screenshot + + +The virtual folder with the Network Folder wizard + + + + + + +Speaking of wizards, the Network Folder Wizard aims at being very easy to use. +After opening the wizard you must choose the type of network folder you would +like to access. When you move on to the next screen you will just need to +fill in the requested information. The final step is entering your username and +login password for the network share you've chosen to access. + + +Below is a list of the information needed by the wizard to create the network +folders. If an option is not +available for a particular folder it does not have to be entered. The Samba +folders ⪚ do not require a Port entry. + + + + + +Name: + + +This is where you give a name to the network connection. It is limited only by +your imagination (or alphabet). + + + + +User: + + +This is the username that will be used to establish the connection. + + + + +Server: + + +This is the address of the server you are attempting to add. It can be an +IP address or domain name. + + + + +Port: + + +Here you enter the port number you wish to connect to. The defaults are usually +sufficient. + + +Not available for &Microsoft; &Windows; (Samba) folders. + + + + + + +Folder: + + +The path to the folder you wish to connect to should go here. + + + + +Encoding: + + +Use the items in this list box to select an encoding for &FTP; and ssh connections. + + + + +Create an icon for this remote folder + + +If this box is checked an icon will be created allowing access through the +remote:/ virtual folder. If it is not checked, a connection will be possible +but it will not be accessible from remote:/. + + +The Recent connection: option allows you to re-connect to +the +last network mount point you connected to using the wizard whether an icon is +created or not. + + + + + + +Use encryption + + +If checked the ability to make a secure connection will be enabled. + +Available only for WebDav folders. + + + + + + + + + + + +&knetattach; Walkthrough + + + +This will be a quick walkthrough of the Network Folder Wizard. Don't +blink or you might miss it. + + + +Below you see the main window of the Network Folder Wizard. It is here +that we choose what type of folder we want to add or connect to. For +the purposes of this walkthrough we will be using &FTP;. It contains most +of the options you will encounter while using the wizard. + + + + +Here's a screenshot of the &knetattach; main window + + + + + +Screenshot + + + + + + +OK, so we (as in me) have chosen to add an &FTP; folder. Below you see +an example of the type of information you will need to add for your particular +&FTP; server. After filling it in we press Save & +Connect +and wait for the magic. Oh yes, if your server requires validation of some kind +you will be prompted at this point before being allowed to connect. + + + + +Screenshot showing addition of &FTP; Folder +using &knetattach; + + + + + +Screenshot + + + + + + +So now we are all connected now and able to navigate our newly added share. Joy! + + + + +Screenshot of the connected &FTP; folder + + + + + +Screenshot + + + + + + +To get back to our network folders all that is necessary is typing +remote:/ +in the location bar of &konqueror; or &dolphin; or +select Network from the Places panel. + + + + +Screenshot of the remote:/ virtual folder with the +added connection + + + + + +Screenshot + + + + + + +You can even add new folders from the same location by using the +Add a Network Folder link. Well that brings us to +the end of our walkthrough (told you it would be quick). I wish you the +best of luck in your own network folder adventures ;-) + + + + + +Credits and License + + +&knetattach; + + +Program copyright 2004 &George.Staikos; &George.Staikos.mail; + + + +Documentation Copyright © 2005 &Orville.Bennett; &Orville.Bennett.mail; + + + + +&underFDL; +&underGPL; + + + +&documentation.index; + + + diff --git a/doc/knetattach/screenshot.png b/doc/knetattach/screenshot.png new file mode 100644 index 00000000..4ec81f46 Binary files /dev/null and b/doc/knetattach/screenshot.png differ diff --git a/doc/knetattach/screenshot1.png b/doc/knetattach/screenshot1.png new file mode 100644 index 00000000..93f0a64e Binary files /dev/null and b/doc/knetattach/screenshot1.png differ diff --git a/doc/knetattach/screenshot2.png b/doc/knetattach/screenshot2.png new file mode 100644 index 00000000..e5ca3e45 Binary files /dev/null and b/doc/knetattach/screenshot2.png differ diff --git a/doc/knetattach/screenshot3.png b/doc/knetattach/screenshot3.png new file mode 100644 index 00000000..04328978 Binary files /dev/null and b/doc/knetattach/screenshot3.png differ diff --git a/doc/knetattach/screenshot4.png b/doc/knetattach/screenshot4.png new file mode 100644 index 00000000..94ce11a5 Binary files /dev/null and b/doc/knetattach/screenshot4.png differ diff --git a/doc/onlinehelp/CMakeLists.txt b/doc/onlinehelp/CMakeLists.txt new file mode 100644 index 00000000..b3d0a394 --- /dev/null +++ b/doc/onlinehelp/CMakeLists.txt @@ -0,0 +1,3 @@ +########### install files ############### +# +kde4_create_handbook(index.docbook INSTALL_DESTINATION ${HTML_INSTALL_DIR}/en SUBDIR onlinehelp) diff --git a/doc/onlinehelp/index.docbook b/doc/onlinehelp/index.docbook new file mode 100644 index 00000000..77aa4232 --- /dev/null +++ b/doc/onlinehelp/index.docbook @@ -0,0 +1,96 @@ + + + +]> +
+Online Help + + +2010-05-13 +&kde; 4.5 + + + +On this page, you can find different ways to find online +help and additional information provided by the KDE community. + + +KDE UserBase + +An +Introduction to KDE  + +Learn more about the +KDE community and its software and find information to help you get +started. Also, discover what +UserBase is and how it can help you. + + + + + +Getting Help  + +Need some help? Here are some suggested places where you can get help +with problems, as well some hints on how to improve the quality of answers you receive. + + + + + +Applications  + +Discover the wide variety of applications from the KDE Community, +and find out what program suits your needs and preferences. + + + + + +Tutorials  + +How-To's, Tips & Tricks that can help make your KDE software +experience more enjoyable and productive. + + + + + + + +KDE Forum + +KDE Community Forums  + +The KDE Forums offer users, developers and people interested in KDE +a place to help each other, discuss KDE-related topics and exchange ideas. +You can find Tutorials & +Tips in the forum. + + + + + +KDE Techbase + +KDE Techbase  + +Information for developers and help to set up a KDE development environment. + + + + + +KDE Documentation + +KDE Documentation site  + +This page holds the complete KDE User Documentation in over 25 languages +for the released and the development version of KDE SC. + + + + +
\ No newline at end of file diff --git a/doc/plasmapkg/CMakeLists.txt b/doc/plasmapkg/CMakeLists.txt new file mode 100644 index 00000000..f846cd5e --- /dev/null +++ b/doc/plasmapkg/CMakeLists.txt @@ -0,0 +1,2 @@ +kde4_create_manpage(man-plasmapkg.1.docbook 1 INSTALL_DESTINATION ${MAN_INSTALL_DIR}) + diff --git a/doc/plasmapkg/man-plasmapkg.1.docbook b/doc/plasmapkg/man-plasmapkg.1.docbook new file mode 100644 index 00000000..223ba622 --- /dev/null +++ b/doc/plasmapkg/man-plasmapkg.1.docbook @@ -0,0 +1,107 @@ + + +]> + + + +KDE User's Manual +2012-12-05 +K Desktop Environment + + + +plasmapkg +1 + + + +plasmapkg +Install, list, remove Plasma packages + + + + +plasmapkg + + path + + type + path + path + + + name + path +KDE Generic Options +Qt Generic Options + + + + +Description +plasmapkg is a command line tool to +install, list, remove Plasma packages. + + + + +Options + + + + path +Generate a SHA1 hash for the package at path. + + + +For install or remove, operates on packages installed for all users. + + + type +The type of package, ⪚ theme, wallpaper, plasmoid, dataengine, runner, layout-template, &etc; [plasmoid]. + + + path +Install the package at path. + + + path +Upgrade the package at path. + + + +List installed packages. + + + name +Remove the package named name. + + + path +Absolute path to the package root. If not supplied, then the standard data +directories for this &kde; session will be searched instead. + + + + + + + +See Also + +More detailed user documentation is available from help:/plasma-desktop +(either enter this URL into &konqueror;, or run +khelpcenter +help:/plasma-desktop). + + + + +Authors +plasmapkg was written by +AaronSeigo aseigo@kde.org. + + + diff --git a/drkonqi/.kateconfig b/drkonqi/.kateconfig new file mode 100644 index 00000000..5dff1098 --- /dev/null +++ b/drkonqi/.kateconfig @@ -0,0 +1 @@ +kate: replace-tabs on; indent-width 4; \ No newline at end of file diff --git a/drkonqi/AUTHORS b/drkonqi/AUTHORS new file mode 100644 index 00000000..78fb78c4 --- /dev/null +++ b/drkonqi/AUTHORS @@ -0,0 +1,5 @@ +Hans Petter Bieker +Dario Andres Rodriguez +George Kiagiadakis +A. L. Spehr +Lee Olson \ No newline at end of file diff --git a/drkonqi/CMakeLists.txt b/drkonqi/CMakeLists.txt new file mode 100644 index 00000000..61489683 --- /dev/null +++ b/drkonqi/CMakeLists.txt @@ -0,0 +1,74 @@ +project(drkonqi) + +check_function_exists("strsignal" HAVE_STRSIGNAL) +check_function_exists("uname" HAVE_UNAME) + +if (NOT DEBUG_PACKAGE_INSTALLER_NAME) + set (DEBUG_PACKAGE_INSTALLER_NAME "installdbgsymbols.sh") +endif (NOT DEBUG_PACKAGE_INSTALLER_NAME) + +configure_file (config-drkonqi.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-drkonqi.h ) + +include_directories(${KDEPIMLIBS_INCLUDE_DIRS}) + +add_definitions(-DKDE_DEFAULT_DEBUG_AREA=1410) + +add_subdirectory( data ) +add_subdirectory( parser ) +add_subdirectory( tests ) +if ( WIN32 ) + add_subdirectory( kdbgwin ) +endif ( WIN32 ) + +set(drkonqi_SRCS + main.cpp + drkonqidialog.cpp + statuswidget.cpp + aboutbugreportingdialog.cpp + reportassistantdialog.cpp + reportassistantpage.cpp + reportassistantpages_base.cpp + reportinterface.cpp + backtraceratingwidget.cpp + backtracewidget.cpp + backtracegenerator.cpp + drkonqi.cpp + drkonqibackends.cpp + detachedprocessmonitor.cpp + debugpackageinstaller.cpp + systeminformation.cpp + crashedapplication.cpp + debugger.cpp + debuggerlaunchers.cpp + debuggermanager.cpp + applicationdetailsexamples.cpp + gdbhighlighter.cpp +) + +kde4_add_ui_files(drkonqi_SRCS + ui/maindialog.ui + ui/backtracewidget.ui + ui/assistantpage_introduction.ui + ui/assistantpage_bugawareness.ui + ui/assistantpage_conclusions.ui + ui/assistantpage_conclusions_dialog.ui +) + +# if BACKTRACE_PARSER_DEBUG is enabled, it will show both the +# parsed and the unparsed backtrace in the backtrace widget. +# Comment this out for release. +#add_definitions(-DBACKTRACE_PARSER_DEBUG) + +kde4_add_executable(drkonqi ${drkonqi_SRCS}) + +target_link_libraries(drkonqi + ${KDE4_KIO_LIBS} + ${QT_QTWEBKIT_LIBRARY} + ${KDE4_KDEWEBKIT_LIBRARY} + ${KDEPIMLIBS_KXMLRPCCLIENT_LIBRARY} + drkonqi_backtrace_parser +) + +install(TARGETS drkonqi DESTINATION ${LIBEXEC_INSTALL_DIR}) + +install(FILES drkonqi-rename-config-section.upd DESTINATION ${KCONF_UPDATE_INSTALL_DIR}) diff --git a/drkonqi/ExtraDesktop.sh b/drkonqi/ExtraDesktop.sh new file mode 100644 index 00000000..da48d446 --- /dev/null +++ b/drkonqi/ExtraDesktop.sh @@ -0,0 +1,4 @@ +#! /bin/sh +#This file has output in separate line each file with a .desktop syntax +#that needs to be translated but has a non .desktop extension +find -name "*rc" -print diff --git a/drkonqi/LICENSE b/drkonqi/LICENSE new file mode 100644 index 00000000..d511905c --- /dev/null +++ b/drkonqi/LICENSE @@ -0,0 +1,339 @@ + 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. diff --git a/drkonqi/Messages.sh b/drkonqi/Messages.sh new file mode 100644 index 00000000..6e16ce3f --- /dev/null +++ b/drkonqi/Messages.sh @@ -0,0 +1,4 @@ +#! /usr/bin/env bash +$EXTRACTRC ui/*.ui >> rc.cpp +$XGETTEXT *.cpp -o $podir/drkonqi.pot +rm -f rc.cpp diff --git a/drkonqi/README b/drkonqi/README new file mode 100644 index 00000000..af35289f --- /dev/null +++ b/drkonqi/README @@ -0,0 +1,6 @@ +How to activate the debug button for DrKonqi: + +$KDEHOME/share/config/drkonqirc: + +[Drkonqi] +ShowDebugButton=true diff --git a/drkonqi/ToDo b/drkonqi/ToDo new file mode 100644 index 00000000..0949e82d --- /dev/null +++ b/drkonqi/ToDo @@ -0,0 +1,205 @@ +##Main Tasks +------------- + +##For KDE4.5+: +-------------- + +- Offer option to "subscribe" (addToCC) to a bug report + +#P1: + +- Check the wording of the new introduced texts (common crashes warnings and notes) + +- Implement inline help (tooltip/whatsthis) for Bugzilla Duplicate Confirmation dialog + +#P2 + +#- Have a "canceled " page (instead of directly exiting the assistant) ????? + +- If the report was "dismissed" because it was not really useful, and the backtrace was not generated; + allow the advanced users to generate it later (on the "Show report's content" button or in the backtrace tab) + +#P3 + +- Merge the two main dialogs (?) + +#Other + +- If attaching, include in the attach'description, a condensed string with the app/kdesc version + +- Check for plugins / Read memory-maps (/proc/PID/maps) and upload as attachment + (example, if plasma crashes, which libs were loaded, which lib caused the crash) + This is useful to determine if some external plugin is involved + (I don't know if this is technically possible) + +- Implement TerminalDebuggerLauncher (the idea is to use the same trick as the one used in the installdbgsymbols.sh examples) + +- BacktraceGenerator should not be allowed to start if another debugger is running. + Add some check and possibly some signal indicating this state. As a consequence, + remove the call to DrKonqi::debuggerManager()->debuggerIsRunning() from BacktraceWidget + to make it trully independent from drkonqi. + +- Make a docs dir and add documentation for: + 1) the format of the debugger files + 2) The dbus interface + + move README.packagers in there with a proper name. + +- Register dynamic debug area (see dfaure's mail on k-c-d). + +- Use external .desktop files to provide examples of "useful crash details" for external applications + (ex. Amarok installs a amarokdrkonqiexamples.desktop file with a content like "Type of music you were listening to..." + - It can contain translations too. + +## FUTURE +--------------- + +- Update DrKonqi to use the remote product mapping implementation (being done by Mattr) + [[ currently bugzillalib detects unexistent products to later use the "kde" product ]] + ##Update: local mappings file support already implemented. + ##Sample PHP script sent + Waiting for remote implementation to be complete. + +- Implement a bugzilla field "Fixed at" X version, to show to the user... (mattr) + +- Detect app versions and encourage the user to test new version? + (detect stable or devel) + +- Custom usefulness values needed by application + (ex. Amarok wants only perfect backtraces...) + +##Brainstorming +-------------- + +- Try to also provide full backtraces ("bt full") + The simple backtrace is going to be pasted inline as always + The complete backtrace could be added as an attachment + (how to retrieve both versions at the same time?, fetch only the full and "manually strip it" to get the simple one ?) + +- Implement bugtracking-system-agnostic interface on KDE servers and adapt DrKonqi to interact with it + (this will also remove the HTML parsing code from DrKonqi itself, to put it on a remote script) + +- Display the time of the crash + ("I came back to the computer some time later and drkonqi was there.. + when the application crashed? during the night?") (by sreich) + +- Usability review and suggestions: + http://blogs.msdn.com/oldnewthing/archive/2003/09/01/54734.aspx (by Maciej) + +- Hide backtrace from user (only show progress and backtrace status)?? + +- Search in backtrace (esp. for [KCrash Handler]) + +- Backtrace syntax highlighting (xml parser+ some qt/kde class ?) + +- Option to "don't show DrKonqi for this(X) app" + (Do we want this?) + +- Option to avoid drkonqi at all (setting KDE_DEBUG=1), and GUI to renable it + (Do we want this?) + +#Later +--------- + +- Implement a proper DBus interface. +- Include help in the details page, near the "Details:" label (ex. "What should I write this?" link with help) + +#DONE +------- + +- Improve the "Enter manual bug ID" option in the Duplicates page to be more discoverable + +- Improve the help about the information the user needs to provide + +- Show the minimum text require length / or a "progress bar"(or capacitybar) + +- If we are going to attach the bug report to an existent one, and that one has too much duplicates, warn the user that his/her attachment is only going to be useful if s/he provides good info + +- In the "Details page" (user enters description) write the headers like +"What I was doing when app crashed: \n\n Other useful config details:" (depending on the options checked before) + +- Exclude some backtrace functions to improve the search feature (like Qt base stuff at the top of the bt) + +- Replace the progressbar of the StatusWidget with a throbber.... + +- The reporting dialog should check (on start) if the backtrace was already generated by the main dialog +(to use it when saving the report to a file, even when the backtrace page is not shown) + +- If reproducibility is Always or Sometimes, set a minimum required char ammount in the details page + +- Title is not needed when attaching the report to an existant one + +- Remove the "Are you ready to submit this bug report" in the Preview page + +- Application detection: ask for or detect specific things depending on application + ie konqueror: url, plasma: plasmoids in use, kopete: protocol, etc. + +- REVIEW criteria of minimum chars/words to use in the Title and Details fields +"- If a possible duplicate is marked as FIXED, show a better (banner) message so the user will notice.... + +!!IMPORTANT: (to be done before 2009Nov25 / String Freeze) +- Update "AboutBugReporting" guide to reflect the new workflow +- Review the confirmation dialog in the Bug Report Information page: +if the text is not long enough, we dismiss the whole report saying something like "a report without a good description +will only waste bug triagers and developers time"... + +##- Use https://bugs.kde.org/enter_bug.cgi?product=X to fetch product versions... (it will reduce server load) + +##Bugzilla DrKonqi reports cleanup: +Wontfix: 143243, 185547 + +--------- +--------- + +* Crashes on Shutdown: + +https://bugs.kde.org/show_bug.cgi?id=126073 -> +**** Restore block shutdown/logout while DrKonqi window is up +(to catch crashes on shutdown) +- Config option to: + - (default) Show a feedback indicator for a "automatically closing window" timer (and continue with shutdown) + - non-default Block shutdown/logout completely, do not use a closing timer. + +- Ask Seli for Session Management stuff (we need to ask from code if we are in the middle of a shutdown process) +- Use " unsetenv("SESSION_MANAGER");" again on main.cpp (http://websvn.kde.org/trunk/kdebase/drkonqi/main.cpp?r1=408177&r2=408176&pathrev=408177) + +- Startkde waiting for drkonqi to exit-> + # wait if there's any crashhandler shown +318 while dcop | grep -q ^drkonqi- ; do +319 sleep 5 +320 done + +" while qdbus | grep "^[^w]*org.kde.drkonqi" > /dev/null ; do sleep 5; done " +http://websvn.kde.org/trunk/kdebase/startkde?r1=408177&r2=408176&pathrev=408177 + +http://websvn.kde.org/?view=rev&revision=408177 + +bool KSessionManager::saveState ( QSessionManager & sm ) [virtual] +void QApplication::saveState ( QSessionManager & manager ) + +--------------------- +--------------------- +Improving symbol loading speed using GDB +--- + +- Create a temp file "init" + +"init" contents: +set auto-solib-add off + +(this will disable the symbols autoload) + +Start gdb with .. "-x init" (init includes the fullpath) + +"bt full" will show an empty backtrace, but with the libraries path. + +Use "shar path" to load the debug symbols for that file + +"bt full" will now be more complete (but it may need more symbols to be loaded) + + +-- + +The current gdb commands could be adapted to... +- Do not include the PID on the command line +- "set auto-solib-add off" could be the first command of the BatchCommands (passed tempfile with -x) +- "attach PID" could be the second command diff --git a/drkonqi/aboutbugreportingdialog.cpp b/drkonqi/aboutbugreportingdialog.cpp new file mode 100644 index 00000000..6b503368 --- /dev/null +++ b/drkonqi/aboutbugreportingdialog.cpp @@ -0,0 +1,229 @@ +/******************************************************************* +* aboutbugreportingdialog.cpp +* Copyright 2009 Dario Andres Rodriguez +* Copyright 2009 A. L. Spehr +* +* 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, see . +* +******************************************************************/ + +#include "aboutbugreportingdialog.h" + +#include +#include +#include +#include +#include +#include + +#include "drkonqi_globals.h" + +AboutBugReportingDialog::AboutBugReportingDialog(QWidget * parent): + KDialog(parent) +{ + setAttribute(Qt::WA_DeleteOnClose, true); + + setWindowIcon(KIcon("help-hint")); + setCaption(i18nc("@title title of the dialog", "About Bug Reporting - Help")); + + setButtons(KDialog::Close); + setDefaultButton(KDialog::Close); + + m_textBrowser = new KTextBrowser(this); + m_textBrowser->setMinimumSize(QSize(600, 300)); + m_textBrowser->setNotifyClick(true); + connect(m_textBrowser, SIGNAL(urlClick(QString)), this, SLOT(handleInternalLinks(QString))); + + QString text = + + //Introduction + QString("

%2

").arg(QLatin1String(PAGE_HELP_BEGIN_ID), + i18nc("@title","Information about bug reporting")) + + QString("

%1

%2

%3

").arg( + i18nc("@info/rich", "You can help us improve this software by filing a bug report."), + i18nc("@info/rich","It is safe to close this dialog. If you do not " + "want to, you do not have to file a bug report."), + i18nc("@info/rich","In order to generate a useful bug report we need some " + "information about both the crash and your system. (You may also " + "need to install some debug packages.)")) + + + //Sub-introduction + QString("

%1

").arg(i18nc("@title","Bug Reporting Assistant Guide")) + + QString("

%1

").arg( + i18nc("@info/rich","This assistant will guide you through the crash " + "reporting process for the KDE bug tracking system. All the " + "information you enter on the bug report must be written " + "in English, if possible, as KDE is formed internationally.")) + + + //Bug Awareness Page + QString("

%2

").arg(QLatin1String(PAGE_AWARENESS_ID), + i18nc("@title","What do you know about the crash?")) + + QString("

%1

%2

  • %3
  • %4
  • %5
  • %6
  • %7
  • %8
  • " + "
%9

").arg( + i18nc("@info/rich","In this page you need to describe how much do you know about " + "the desktop and the application state before it crashed."), + i18nc("@info/rich","If you can, describe in as much detail as possible the crash " + "circumstances, and what you were doing when the application crashed " + "(this information is going to be requested later.) You can mention: "), + i18nc("@info/rich crash situation example","actions you were taking inside or outside " + "the application"), + i18nc("@info/rich crash situation example","documents or images that you were using " + "and their type/format (later if you go to look at the report in the " + "bug tracking system, you can attach a file to the report)"), + i18nc("@info/rich crash situation example","widgets that you were running"), + i18nc("@info/rich crash situation example","the URL of a web site you were browsing"), + i18nc("@info/rich crash situation example","configuration details of the application"), + i18nc("@info/rich crash situation example","or other strange things you notice before " + "or after the crash. "), + i18nc("@info/rich","Screenshots can be very helpful sometimes. You can attach them to " + "the bug report after it is posted to the bug tracking system.")) + + + //Crash Information Page + QString("

%2

").arg(QLatin1String(PAGE_CRASHINFORMATION_ID), + i18nc("@title","Crash Information (backtrace)")) + + QString("

%1

%2

%3

%4

").arg( + i18nc("@info/rich","This page will generate a \"backtrace\" of the crash. This " + "is information that tells the developers where the application " + "crashed."), + i18nc("@info/rich", "If the crash information is not detailed enough, you may " + "need to install some debug packages and reload it (if the " + "Install Debug Symbols button is available you " + "can use it to automatically install the missing information.)"), + i18nc("@info/rich", "You can find more information about backtraces, what they mean, " + "and how they are useful at %1",QString(TECHBASE_HOWTO_DOC) ), + i18nc("@info/rich","Once you get a useful backtrace (or if you do not want to " + "install the missing debugging packages) you can continue.")) + + + //Conclusions Page + QString("

%2

").arg(QLatin1String(PAGE_CONCLUSIONS_ID), + i18nc("@title","Conclusions")) + + QString("

%1

%2

%3

").arg( + i18nc("@info/rich","Using the quality of the crash information gathered, " + "and your answers on the previous page, the assistant will " + "tell you if the crash is worth reporting or not."), + i18nc("@info/rich","If the crash is worth reporting but the application " + "is not supported in the KDE bug tracking system, you " + "will need to directly contact the maintainer of the application."), + i18nc("@info/rich","If the crash is listed as being not worth reporting, " + "and you think the assistant has made a mistake, " + "you can still manually report the bug by logging into the " + "bug tracking system. You can also go back and change information " + "and download debug packages.")) + + + //Bugzilla Login Page + QString("

%2

").arg(QLatin1String(PAGE_BZLOGIN_ID), + i18nc("@title","Login into the bug tracking system")) + + QString("

%1

%2

%3

").arg( + i18nc("@info/rich","We may need to contact you in the future to ask for " + "further information. As we need to keep track of the bug reports, " + "you " + "need to have an account on the KDE bug tracking system. If you do " + "not have one, you can create one here: %1", + QString(KDE_BUGZILLA_CREATE_ACCOUNT_URL)), + i18nc("@info/rich","Then, enter your username and password and " + "press the Login button. You can use this login to directly access the " + "KDE bug tracking system later."), + i18nc("@info/rich","The KWallet dialog may appear when pressing Login to " + "save your password in the KWallet password system. Also, it will " + "prompt you for the KWallet password upon loading to autocomplete " + "the login fields if you use this assistant again.")) + + + //Bugzilla Duplicates Page + QString("

%2

").arg(QLatin1String(PAGE_BZDUPLICATES_ID), + i18nc("@title","List of possible duplicate reports")) + + QString("

%1

%2

%3

%4

%5

").arg( + //needs some more string cleanup below + i18nc("@info/rich","This page will search the bug report system for " + "similar crashes which are possible duplicates of your bug. If " + "there are similar bug reports found, you can double click on them " + "to see details. Then, read the current bug report information so " + "you can check to see if they are similar. "), + i18nc("@info/rich","If you are very sure your bug is the same as another that is " + "previously reported, you can set your information to be attached to " + "the existing report."), + i18nc("@info/rich","If you are unsure whether your report is the same, follow the main " + "options to tentatively mark your crash as a duplicate of that " + "report. This is usually the safest thing to do. We cannot " + "uncombine bug reports, but we can easily merge them."), + i18nc("@info/rich","If not enough possible duplicates are found, or you " + "did not find a similar report, then you can force it to search " + "for more bug reports (only if the date range limit is not reached.)"), + i18nc("@info/rich","If you do not find any related reports, your crash information " + "is not useful enough, and you really cannot give additional " + "information about the crash context, then it is better to " + "not file the bug report, thereby closing the assistant.")) + + + //Bugzilla Crash Information - Details Page + QString("

%2

").arg(QLatin1String(PAGE_BZDETAILS_ID), + i18nc("@title","Details of the bug report and your system")) + + QString("

%1%3

%4

%5

").arg( + i18nc("@info/rich","In this case you need to write a title and description " + "of the crash. Explain as best you can. "), + QLatin1String(PAGE_AWARENESS_ID), + i18nc("@title","What do you know about the crash?"), + i18nc("@info/rich", "You can also specify your distribution method (GNU/Linux " + "distribution or packaging system) or if you compiled the KDE " + "Platform from sources."), + i18nc("@info/rich", "You should write those information in English.")) + + + //Bugzilla Send Page + QString("

%2

").arg(QLatin1String(PAGE_BZSEND_ID), + i18nc("@title","Sending the Crash Report")) + + QString("

%1

%2

").arg( + i18nc("@info/rich","The last page will send the bug report to the bug tracking " + "system and will notify you when it is done. It will then show " + "the web address of the bug report in the KDE bug tracking system, " + "so that you can look at the report later."), + i18nc("@info/rich","If the process fails, you can click " + "Retry to try sending the bug report again. " + "If the report cannot be sent because the bug tracking system has a " + "problem, you can save it to a file to manually report later.")) + + + QString("

%1

%2

").arg( + i18nc("@info/rich", "Thank you for being part of KDE!"), + i18nc("@info/rich", "If you are interested in helping us to keep the KDE bug tracker system " + "clean and useful, which allows the developers to be more focused on " + "fixing the real issues, you are welcome to " + "join the BugSquad team.")); + + m_textBrowser->setText(text); + + setMainWidget(m_textBrowser); + + KConfigGroup config(KGlobal::config(), "AboutBugReportingDialog"); + restoreDialogSize(config); +} + +AboutBugReportingDialog::~AboutBugReportingDialog( ) +{ + KConfigGroup config(KGlobal::config(), "AboutBugReportingDialog"); + saveDialogSize(config); +} + +void AboutBugReportingDialog::handleInternalLinks(const QString& url) +{ + if (!url.isEmpty()) { + if (url.startsWith('#')) { + showSection(url.mid(1,url.length())); + } else { + KToolInvocation::invokeBrowser(url); + } + } +} + +void AboutBugReportingDialog::showSection(const QString& anchor) +{ + m_textBrowser->scrollToAnchor(anchor); +} + diff --git a/drkonqi/aboutbugreportingdialog.h b/drkonqi/aboutbugreportingdialog.h new file mode 100644 index 00000000..99a40988 --- /dev/null +++ b/drkonqi/aboutbugreportingdialog.h @@ -0,0 +1,43 @@ +/******************************************************************* +* aboutbugreportingdialog.h +* Copyright 2009 Dario Andres Rodriguez +* +* 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, see . +* +******************************************************************/ + +#ifndef ABOUTBUGREPORTINGDIALOG__H +#define ABOUTBUGREPORTINGDIALOG__H + +#include + +class KTextBrowser; + +class AboutBugReportingDialog: public KDialog +{ + Q_OBJECT + +public: + explicit AboutBugReportingDialog(QWidget * parent = 0); + ~AboutBugReportingDialog(); + void showSection(const QString&); + +private Q_SLOTS: + void handleInternalLinks(const QString&); + +private: + KTextBrowser * m_textBrowser; +}; + +#endif diff --git a/drkonqi/applicationdetailsexamples.cpp b/drkonqi/applicationdetailsexamples.cpp new file mode 100644 index 00000000..65ceb18c --- /dev/null +++ b/drkonqi/applicationdetailsexamples.cpp @@ -0,0 +1,76 @@ +/******************************************************************* +* applicationdetailsexamples.cpp +* Copyright 2010 Dario Andres Rodriguez +* +* 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, see . +* +******************************************************************/ + +#include "applicationdetailsexamples.h" + +#include + +#include "drkonqi.h" +#include "crashedapplication.h" + +ApplicationDetailsExamples::ApplicationDetailsExamples(QObject * parent) + : QObject(parent) +{ + QString binaryName = DrKonqi::crashedApplication()->fakeExecutableBaseName(); + + if (binaryName == QLatin1String("plasma-desktop")) { + m_examples = i18nc("@info examples about information the user can provide", + "Widgets you have in your desktop and panels (both official and unofficial), " + "desktop settings (wallpaper plugin, themes), activities, and dashboard configuration."); + } else if (binaryName == QLatin1String("kwin")) { + m_examples = i18nc("@info examples about information the user can provide", + "State of Desktop Effects (Compositing), kind of effects enabled, window decoration, " + "and specific window rules and configuration."); + } else if (binaryName == QLatin1String("konqueror") || + binaryName == QLatin1String("rekonq")) { + m_examples = i18nc("@info examples about information the user can provide", + "sites you were visiting, number of opened tabs, plugins you have installed, " + "and any other non-default setting."); + } else if (binaryName == QLatin1String("dolphin")) { + m_examples = i18nc("@info examples about information the user can provide", + "File view mode, grouping and sorting settings, preview settings, and directory you were browsing."); + } else if (binaryName == QLatin1String("kopete")) { + m_examples = i18nc("@info examples about information the user can provide", + "Instant Messaging protocols you use, and plugins you have installed (official and unofficial)."); + } else if (binaryName == QLatin1String("kmail")) { + m_examples = i18nc("@info examples about information the user can provide", + "Mail protocols and account-types you use."); + } else if (binaryName == QLatin1String("kwrite") || + binaryName == QLatin1String("kate") || + binaryName == QLatin1String("kword")) { + m_examples = i18nc("@info examples about information the user can provide", + "Type of the document you were editing."); + } else if (binaryName == QLatin1String("juk") || + binaryName == QLatin1String("amarok") || + binaryName == QLatin1String("dragon") || + binaryName == QLatin1String("kaffeine")) { + m_examples = i18nc("@info examples about information the user can provide", + "Type of media (extension and format) you were watching and/or listening to."); + } +} + +bool ApplicationDetailsExamples::hasExamples() const +{ + return !m_examples.isEmpty(); +} + +QString ApplicationDetailsExamples::examples() const +{ + return m_examples; +} diff --git a/drkonqi/applicationdetailsexamples.h b/drkonqi/applicationdetailsexamples.h new file mode 100644 index 00000000..3efb8b36 --- /dev/null +++ b/drkonqi/applicationdetailsexamples.h @@ -0,0 +1,38 @@ +/******************************************************************* +* applicationdetailsexamples.h +* Copyright 2010 Dario Andres Rodriguez +* +* 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, see . +* +******************************************************************/ + +#ifndef APPLICATIONDETAILSEXAMPLES__H +#define APPLICATIONDETAILSEXAMPLES__H + +#include +#include + +class ApplicationDetailsExamples : QObject +{ +Q_OBJECT +public: + explicit ApplicationDetailsExamples(QObject * parent); + bool hasExamples() const; + QString examples() const; + +private: + QString m_examples; +}; + +#endif diff --git a/drkonqi/backtracegenerator.cpp b/drkonqi/backtracegenerator.cpp new file mode 100644 index 00000000..1107e117 --- /dev/null +++ b/drkonqi/backtracegenerator.cpp @@ -0,0 +1,165 @@ +/***************************************************************** + * drkonqi - The KDE Crash Handler + * + * Copyright (C) 2000-2003 Hans Petter Bieker + * Copyright (C) 2009 George Kiagiadakis + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *****************************************************************/ +#include "backtracegenerator.h" + +#include +#include +#include + +#include "parser/backtraceparser.h" + +BacktraceGenerator::BacktraceGenerator(const Debugger & debugger, QObject *parent) + : QObject(parent), + m_debugger(debugger), m_proc(NULL), + m_temp(NULL), m_state(NotLoaded) +{ + m_parser = BacktraceParser::newParser(m_debugger.codeName(), this); + m_parser->connectToGenerator(this); + +#ifdef BACKTRACE_PARSER_DEBUG + m_debugParser = BacktraceParser::newParser(QString(), this); //uses the null parser + m_debugParser->connectToGenerator(this); +#endif +} + +BacktraceGenerator::~BacktraceGenerator() +{ + if (m_proc && m_proc->state() == QProcess::Running) { + kWarning() << "Killing running debugger instance"; + m_proc->disconnect(this); + m_proc->terminate(); + if (!m_proc->waitForFinished(10000)) { + m_proc->kill(); + m_proc->waitForFinished(); + } + delete m_proc; + delete m_temp; + } +} + +bool BacktraceGenerator::start() +{ + //they should always be null before entering this function. + Q_ASSERT(m_proc == NULL && m_temp == NULL); + + m_parsedBacktrace.clear(); + m_state = Loading; + + emit starting(); + + if (!m_debugger.isValid() || !m_debugger.isInstalled()) { + m_state = FailedToStart; + emit failedToStart(); + return false; + } + + m_proc = new KProcess; + m_proc->setEnv("LC_ALL", "C"); // force C locale + + m_temp = new KTemporaryFile; + m_temp->open(); + m_temp->write(m_debugger.backtraceBatchCommands().toLatin1()); + m_temp->write("\n", 1); + m_temp->flush(); + + // start the debugger + QString str = m_debugger.command(); + Debugger::expandString(str, Debugger::ExpansionUsageShell, m_temp->fileName()); + + *m_proc << KShell::splitArgs(str); + m_proc->setOutputChannelMode(KProcess::OnlyStdoutChannel); + m_proc->setNextOpenMode(QIODevice::ReadWrite | QIODevice::Text); + connect(m_proc, SIGNAL(readyReadStandardOutput()), + SLOT(slotReadInput())); + connect(m_proc, SIGNAL(finished(int,QProcess::ExitStatus)), + SLOT(slotProcessExited(int,QProcess::ExitStatus))); + + m_proc->start(); + if (!m_proc->waitForStarted()) { + //we mustn't keep these around... + m_proc->deleteLater(); + m_temp->deleteLater(); + m_proc = NULL; + m_temp = NULL; + + m_state = FailedToStart; + emit failedToStart(); + return false; + } + + return true; +} + +void BacktraceGenerator::slotReadInput() +{ + // we do not know if the output array ends in the middle of an utf-8 sequence + m_output += m_proc->readAllStandardOutput(); + + int pos; + while ((pos = m_output.indexOf('\n')) != -1) { + QString line = QString::fromLocal8Bit(m_output, pos + 1); + m_output.remove(0, pos + 1); + + emit newLine(line); + } +} + +void BacktraceGenerator::slotProcessExited(int exitCode, QProcess::ExitStatus exitStatus) +{ + //these are useless now + m_proc->deleteLater(); + m_temp->deleteLater(); + m_proc = NULL; + m_temp = NULL; + + //mark the end of the backtrace for the parser + emit newLine(QString()); + + if (exitStatus != QProcess::NormalExit || exitCode != 0) { + m_state = Failed; + emit someError(); + return; + } + + //no translation, string appears in the report + QString tmp("Application: %progname (%execname), signal: %signame\n"); + Debugger::expandString(tmp); + + m_parsedBacktrace = tmp + m_parser->parsedBacktrace(); + m_state = Loaded; + +#ifdef BACKTRACE_PARSER_DEBUG + //append the raw unparsed backtrace + m_parsedBacktrace += "\n------------ Unparsed Backtrace ------------\n"; + m_parsedBacktrace += m_debugParser->parsedBacktrace(); //it's not really parsed, it's from the null parser. +#endif + + emit done(); +} + +#include "backtracegenerator.moc" diff --git a/drkonqi/backtracegenerator.h b/drkonqi/backtracegenerator.h new file mode 100644 index 00000000..52c3539b --- /dev/null +++ b/drkonqi/backtracegenerator.h @@ -0,0 +1,92 @@ +/***************************************************************** + * drkonqi - The KDE Crash Handler + * + * Copyright (C) 2000-2003 Hans Petter Bieker + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *****************************************************************/ + +#ifndef BACKTRACEGENERATOR_H +#define BACKTRACEGENERATOR_H + +#include + +#include "debugger.h" + +class KTemporaryFile; +class BacktraceParser; + +class BacktraceGenerator : public QObject +{ + Q_OBJECT + +public: + enum State { NotLoaded, Loading, Loaded, Failed, FailedToStart }; + + BacktraceGenerator(const Debugger & debugger, QObject *parent); + ~BacktraceGenerator(); + + State state() const { + return m_state; + } + + BacktraceParser *parser() const { + return m_parser; + } + + QString backtrace() const { + return m_parsedBacktrace; + } + + const Debugger debugger() const { + return m_debugger; + } + +public Q_SLOTS: + bool start(); + +Q_SIGNALS: + void starting(); + void newLine(const QString &str); // emitted for every line + void someError(); + void failedToStart(); + void done(); + +private Q_SLOTS: + void slotProcessExited(int exitCode, QProcess::ExitStatus exitStatus); + void slotReadInput(); + +private: + const Debugger m_debugger; + KProcess * m_proc; + KTemporaryFile * m_temp; + QByteArray m_output; + State m_state; + BacktraceParser * m_parser; + QString m_parsedBacktrace; + +#ifdef BACKTRACE_PARSER_DEBUG + BacktraceParser * m_debugParser; +#endif +}; + +#endif diff --git a/drkonqi/backtraceratingwidget.cpp b/drkonqi/backtraceratingwidget.cpp new file mode 100644 index 00000000..2858c767 --- /dev/null +++ b/drkonqi/backtraceratingwidget.cpp @@ -0,0 +1,97 @@ +/******************************************************************* +* backtraceratingwidget.cpp +* Copyright 2009 Dario Andres Rodriguez +* +* 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, see . +* +******************************************************************/ + +#include "backtraceratingwidget.h" + +#include +#include + +#include + +BacktraceRatingWidget::BacktraceRatingWidget(QWidget * parent) : + QWidget(parent), + m_state(BacktraceGenerator::NotLoaded), + m_star1(false), + m_star2(false), + m_star3(false) +{ + setMinimumSize(105, 24); + + m_starPixmap = KIcon("favorites").pixmap(QSize(22, 22)); + m_disabledStarPixmap = KIcon("favorites").pixmap(QSize(22, 22), QIcon::Disabled); + m_errorPixmap = KIcon("dialog-error").pixmap(QSize(22, 22)); +} + +void BacktraceRatingWidget::setUsefulness(BacktraceParser::Usefulness usefulness) +{ + switch (usefulness) { + case BacktraceParser::ReallyUseful: { + m_star1 = true; + m_star2 = true; + m_star3 = true; + break; + } + case BacktraceParser::MayBeUseful: { + m_star1 = true; + m_star2 = true; + m_star3 = false; + break; + } + case BacktraceParser::ProbablyUseless: { + m_star1 = true; + m_star2 = false; + m_star3 = false; + break; + } + case BacktraceParser::Useless: + case BacktraceParser::InvalidUsefulness: { + m_star1 = false; + m_star2 = false; + m_star3 = false; + break; + } + } + + update(); +} + +void BacktraceRatingWidget::paintEvent(QPaintEvent * event) +{ + Q_UNUSED(event); + + QPainter p(this); + + p.drawPixmap(QPoint(30, 1) , m_star1 ? m_starPixmap : m_disabledStarPixmap); + p.drawPixmap(QPoint(55, 1) , m_star2 ? m_starPixmap : m_disabledStarPixmap); + p.drawPixmap(QPoint(80, 1) , m_star3 ? m_starPixmap : m_disabledStarPixmap); + + switch (m_state) { + case BacktraceGenerator::Failed: + case BacktraceGenerator::FailedToStart: { + p.drawPixmap(QPoint(0, 1) , m_errorPixmap); + break; + } + case BacktraceGenerator::Loading: + case BacktraceGenerator::Loaded: + default: + break; + } + + p.end(); +} diff --git a/drkonqi/backtraceratingwidget.h b/drkonqi/backtraceratingwidget.h new file mode 100644 index 00000000..1e8f9a9b --- /dev/null +++ b/drkonqi/backtraceratingwidget.h @@ -0,0 +1,60 @@ +/******************************************************************* +* backtraceratingwidget.h +* Copyright 2009 Dario Andres Rodriguez +* +* 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, see . +* +******************************************************************/ + +#ifndef BACKTRACERATINGWIDGET__H +#define BACKTRACERATINGWIDGET__H + +#include + +#include "parser/backtraceparser.h" +#include "backtracegenerator.h" + +class QPixmap; + +class BacktraceRatingWidget: public QWidget +{ + Q_OBJECT + +public: + + explicit BacktraceRatingWidget(QWidget *); + void setUsefulness(BacktraceParser::Usefulness); + void setState(BacktraceGenerator::State s) { + m_state = s; update(); + } + +protected: + + void paintEvent(QPaintEvent * event); + +private: + + BacktraceGenerator::State m_state; + + bool m_star1; + bool m_star2; + bool m_star3; + + QPixmap m_errorPixmap; + + QPixmap m_starPixmap; + QPixmap m_disabledStarPixmap; +}; + +#endif diff --git a/drkonqi/backtracewidget.cpp b/drkonqi/backtracewidget.cpp new file mode 100644 index 00000000..c0a307f1 --- /dev/null +++ b/drkonqi/backtracewidget.cpp @@ -0,0 +1,408 @@ +/******************************************************************* +* backtracewidget.cpp +* Copyright 2009,2010 Dario Andres Rodriguez +* +* 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, see . +* +******************************************************************/ + +#include "backtracewidget.h" + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "drkonqi.h" +#include "backtraceratingwidget.h" +#include "crashedapplication.h" +#include "backtracegenerator.h" +#include "parser/backtraceparser.h" +#include "drkonqi_globals.h" +#include "debuggermanager.h" +#include "gdbhighlighter.h" + +static const char extraDetailsLabelMargin[] = " margin: 5px; "; + +BacktraceWidget::BacktraceWidget(BacktraceGenerator *generator, QWidget *parent, + bool showToggleBacktrace) : + QWidget(parent), + m_btGenerator(generator), + m_highlighter(0) +{ + ui.setupUi(this); + + //Debug package installer + m_debugPackageInstaller = new DebugPackageInstaller(this); + connect(m_debugPackageInstaller, SIGNAL(error(QString)), this, SLOT(debugPackageError(QString))); + connect(m_debugPackageInstaller, SIGNAL(packagesInstalled()), this, SLOT(regenerateBacktrace())); + connect(m_debugPackageInstaller, SIGNAL(canceled()), this, SLOT(debugPackageCanceled())); + + connect(m_btGenerator, SIGNAL(done()) , this, SLOT(loadData())); + connect(m_btGenerator, SIGNAL(someError()) , this, SLOT(loadData())); + connect(m_btGenerator, SIGNAL(failedToStart()) , this, SLOT(loadData())); + connect(m_btGenerator, SIGNAL(newLine(QString)) , this, SLOT(backtraceNewLine(QString))); + + connect(ui.m_extraDetailsLabel, SIGNAL(linkActivated(QString)), this, + SLOT(extraDetailsLinkActivated(QString))); + ui.m_extraDetailsLabel->setVisible(false); + ui.m_extraDetailsLabel->setStyleSheet(QLatin1String(extraDetailsLabelMargin)); + + //Setup the buttons + ui.m_reloadBacktraceButton->setGuiItem( + KGuiItem2(i18nc("@action:button", "&Reload"), + KIcon("view-refresh"), i18nc("@info:tooltip", "Use this button to " + "reload the crash information (backtrace). This is useful when you have " + "installed the proper debug symbol packages and you want to obtain " + "a better backtrace."))); + connect(ui.m_reloadBacktraceButton, SIGNAL(clicked()), this, SLOT(regenerateBacktrace())); + + ui.m_installDebugButton->setGuiItem( + KGuiItem2(i18nc("@action:button", "&Install Debug Symbols"), + KIcon("system-software-update"), i18nc("@info:tooltip", "Use this button to " + "install the missing debug symbols packages."))); + ui.m_installDebugButton->setVisible(false); + connect(ui.m_installDebugButton, SIGNAL(clicked()), this, SLOT(installDebugPackages())); + + ui.m_copyButton->setGuiItem(KGuiItem2(QString(), KIcon("edit-copy"), + i18nc("@info:tooltip", "Use this button to copy the " + "crash information (backtrace) to the clipboard."))); + connect(ui.m_copyButton, SIGNAL(clicked()) , this, SLOT(copyClicked())); + ui.m_copyButton->setEnabled(false); + + ui.m_saveButton->setGuiItem(KGuiItem2(QString(), + KIcon("document-save"), + i18nc("@info:tooltip", "Use this button to save the " + "crash information (backtrace) to a file. This is useful " + "if you want to take a look at it or to report the bug " + "later."))); + connect(ui.m_saveButton, SIGNAL(clicked()) , this, SLOT(saveClicked())); + ui.m_saveButton->setEnabled(false); + + //Create the rating widget + m_backtraceRatingWidget = new BacktraceRatingWidget(ui.m_statusWidget); + ui.m_statusWidget->addCustomStatusWidget(m_backtraceRatingWidget); + + ui.m_statusWidget->setIdle(QString()); + + //Do we need the "Show backtrace" toggle action ? + if (!showToggleBacktrace) { + ui.mainLayout->removeWidget(ui.m_toggleBacktraceCheckBox); + ui.m_toggleBacktraceCheckBox->setVisible(false); + toggleBacktrace(true); + } else { + //Generate help widget + ui.m_backtraceHelpLabel->setText( + i18n("

What is a \"backtrace\" ?

A backtrace basically describes what was " + "happening inside the application when it crashed, so the developers may track " + "down where the mess started. They may look meaningless to you, but they might " + "actually contain a wealth of useful information.
Backtraces are commonly " + "used during interactive and post-mortem debugging.

")); + ui.m_backtraceHelpIcon->setPixmap(KIcon("help-hint").pixmap(48,48)); + connect(ui.m_toggleBacktraceCheckBox, SIGNAL(toggled(bool)), this, + SLOT(toggleBacktrace(bool))); + toggleBacktrace(false); + } + + ui.m_backtraceEdit->setFont( KGlobalSettings::fixedFont() ); +} + +void BacktraceWidget::setAsLoading() +{ + //remove the syntax highlighter + delete m_highlighter; + m_highlighter = 0; + + //Set the widget as loading and disable all the action buttons + ui.m_backtraceEdit->setText(i18nc("@info:status", "Loading...")); + ui.m_backtraceEdit->setEnabled(false); + + ui.m_statusWidget->setBusy(i18nc("@info:status", + "Generating backtrace... (this may take some time)")); + m_backtraceRatingWidget->setUsefulness(BacktraceParser::Useless); + m_backtraceRatingWidget->setState(BacktraceGenerator::Loading); + + ui.m_extraDetailsLabel->setVisible(false); + ui.m_extraDetailsLabel->clear(); + + ui.m_installDebugButton->setVisible(false); + ui.m_reloadBacktraceButton->setEnabled(false); + + ui.m_copyButton->setEnabled(false); + ui.m_saveButton->setEnabled(false); +} + +//Force backtrace generation +void BacktraceWidget::regenerateBacktrace() +{ + setAsLoading(); + + if (!DrKonqi::debuggerManager()->debuggerIsRunning()) { + m_btGenerator->start(); + } else { + anotherDebuggerRunning(); + } + + emit stateChanged(); +} + +void BacktraceWidget::generateBacktrace() +{ + if (m_btGenerator->state() == BacktraceGenerator::NotLoaded) { + //First backtrace generation + regenerateBacktrace(); + } else if (m_btGenerator->state() == BacktraceGenerator::Loading) { + //Set in loading state, the widget will catch the backtrace events anyway + setAsLoading(); + emit stateChanged(); + } else { + //*Finished* states + setAsLoading(); + emit stateChanged(); + //Load already generated information + loadData(); + } +} + +void BacktraceWidget::anotherDebuggerRunning() +{ + //As another debugger is running, we should disable the actions and notify the user + ui.m_backtraceEdit->setEnabled(false); + ui.m_backtraceEdit->setText(i18nc("@info", "Another debugger is currently debugging the " + "same application. The crash information could not be fetched.")); + m_backtraceRatingWidget->setState(BacktraceGenerator::Failed); + m_backtraceRatingWidget->setUsefulness(BacktraceParser::Useless); + ui.m_statusWidget->setIdle(i18nc("@info:status", "The crash information could not be fetched.")); + ui.m_extraDetailsLabel->setVisible(true); + ui.m_extraDetailsLabel->setText(i18nc("@info/rich", "Another debugging process is attached to " + "the crashed application. Therefore, the DrKonqi debugger cannot " + "fetch the backtrace. Please close the other debugger and " + "click Reload.")); + ui.m_installDebugButton->setVisible(false); + ui.m_reloadBacktraceButton->setEnabled(true); +} + +void BacktraceWidget::loadData() +{ + //Load the backtrace data from the generator + m_backtraceRatingWidget->setState(m_btGenerator->state()); + + if (m_btGenerator->state() == BacktraceGenerator::Loaded) { + ui.m_backtraceEdit->setEnabled(true); + ui.m_backtraceEdit->setPlainText(m_btGenerator->backtrace()); + + // scroll to crash + QTextCursor crashCursor = ui.m_backtraceEdit->document()->find("[KCrash Handler]"); + if (!crashCursor.isNull()) { + crashCursor.movePosition(QTextCursor::Up, QTextCursor::MoveAnchor); + ui.m_backtraceEdit->verticalScrollBar()->setValue(ui.m_backtraceEdit->cursorRect(crashCursor).top()); + } + + // highlight if possible + if (m_btGenerator->debugger().codeName() == "gdb") { + m_highlighter = new GdbHighlighter(ui.m_backtraceEdit->document(), + m_btGenerator->parser()->parsedBacktraceLines()); + } + + BacktraceParser * btParser = m_btGenerator->parser(); + m_backtraceRatingWidget->setUsefulness(btParser->backtraceUsefulness()); + + //Generate the text to put in the status widget (backtrace usefulness) + QString usefulnessText; + switch (btParser->backtraceUsefulness()) { + case BacktraceParser::ReallyUseful: + usefulnessText = i18nc("@info", "The generated crash information is useful"); + break; + case BacktraceParser::MayBeUseful: + usefulnessText = i18nc("@info", "The generated crash information may be useful"); + break; + case BacktraceParser::ProbablyUseless: + usefulnessText = i18nc("@info", "The generated crash information is probably not useful"); + break; + case BacktraceParser::Useless: + usefulnessText = i18nc("@info", "The generated crash information is not useful"); + break; + default: + //let's hope nobody will ever see this... ;) + usefulnessText = i18nc("@info", "The rating of this crash information is invalid. " + "This is a bug in DrKonqi itself."); + break; + } + ui.m_statusWidget->setIdle(usefulnessText); + + if (btParser->backtraceUsefulness() != BacktraceParser::ReallyUseful) { + //Not a perfect bactrace, ask the user to try to improve it + ui.m_extraDetailsLabel->setVisible(true); + if (canInstallDebugPackages()) { + //The script to install the debug packages is available + ui.m_extraDetailsLabel->setText(i18nc("@info/rich", "You can click the " + "Install Debug Symbols button in order to automatically " + "install the missing debugging information packages. If this method " + "does not work: please read How to " + "create useful crash reports to learn how to get a useful " + "backtrace; install the needed packages (" + "list of files) and click the " + "Reload button.", + QLatin1String(TECHBASE_HOWTO_DOC), + QLatin1String("#missingDebugPackages"))); + ui.m_installDebugButton->setVisible(true); + //Retrieve the libraries with missing debug info + QStringList missingLibraries = btParser->librariesWithMissingDebugSymbols().toList(); + m_debugPackageInstaller->setMissingLibraries(missingLibraries); + } else { + //No automated method to install the missing debug info + //Tell the user to read the howto and reload + ui.m_extraDetailsLabel->setText(i18nc("@info/rich", "Please read How to " + "create useful crash reports to learn how to get a useful " + "backtrace; install the needed packages (" + "list of files) and click the " + "Reload button.", + QLatin1String(TECHBASE_HOWTO_DOC), + QLatin1String("#missingDebugPackages"))); + } + } + + ui.m_copyButton->setEnabled(true); + ui.m_saveButton->setEnabled(true); + } else if (m_btGenerator->state() == BacktraceGenerator::Failed) { + //The backtrace could not be generated because the debugger had an error + m_backtraceRatingWidget->setUsefulness(BacktraceParser::Useless); + + ui.m_statusWidget->setIdle(i18nc("@info:status", "The debugger has quit unexpectedly.")); + + ui.m_backtraceEdit->setPlainText(i18nc("@info:status", + "The crash information could not be generated.")); + + ui.m_extraDetailsLabel->setVisible(true); + ui.m_extraDetailsLabel->setText(i18nc("@info/rich", "You could try to regenerate the " + "backtrace by clicking the Reload" + " button.")); + } else if (m_btGenerator->state() == BacktraceGenerator::FailedToStart) { + //The backtrace could not be generated because the debugger could not start (missing) + //Tell the user to install it. + m_backtraceRatingWidget->setUsefulness(BacktraceParser::Useless); + + ui.m_statusWidget->setIdle(i18nc("@info:status", "The debugger application is missing or " + "could not be launched.")); + + ui.m_backtraceEdit->setPlainText(i18nc("@info:status", + "The crash information could not be generated.")); + ui.m_extraDetailsLabel->setVisible(true); + ui.m_extraDetailsLabel->setText(i18nc("@info/rich", "You need to first install the debugger " + "application (%1) then click the Reload" + " button.", + m_btGenerator->debugger().name())); + } + + ui.m_reloadBacktraceButton->setEnabled(true); + emit stateChanged(); +} + +void BacktraceWidget::backtraceNewLine(const QString & line) +{ + //While loading the backtrace (unparsed) a new line was sent from the debugger, append it + ui.m_backtraceEdit->append(line.trimmed()); +} + +void BacktraceWidget::copyClicked() +{ + ui.m_backtraceEdit->selectAll(); + ui.m_backtraceEdit->copy(); +} + +void BacktraceWidget::saveClicked() +{ + DrKonqi::saveReport(m_btGenerator->backtrace(), this); +} + +void BacktraceWidget::hilightExtraDetailsLabel(bool hilight) +{ + QString stylesheet; + if (hilight) { + stylesheet = QLatin1String("border-width: 2px; " + "border-style: solid; " + "border-color: red;"); + } else { + stylesheet = QLatin1String("border-width: 0px;"); + } + stylesheet += QLatin1String(extraDetailsLabelMargin); + ui.m_extraDetailsLabel->setStyleSheet(stylesheet); +} + +void BacktraceWidget::focusImproveBacktraceButton() +{ + ui.m_installDebugButton->setFocus(); +} + +void BacktraceWidget::installDebugPackages() +{ + ui.m_installDebugButton->setVisible(false); + m_debugPackageInstaller->installDebugPackages(); +} + +void BacktraceWidget::debugPackageError(const QString & errorMessage) +{ + ui.m_installDebugButton->setVisible(true); + KMessageBox::error(this, errorMessage, i18nc("@title:window", "Error during the installation of" + " debug symbols")); +} + +void BacktraceWidget::debugPackageCanceled() +{ + ui.m_installDebugButton->setVisible(true); +} + +bool BacktraceWidget::canInstallDebugPackages() const +{ + return m_debugPackageInstaller->canInstallDebugPackages(); +} + +void BacktraceWidget::toggleBacktrace(bool show) +{ + ui.m_backtraceStack->setCurrentWidget(show ? ui.backtracePage : ui.backtraceHelpPage); +} + +void BacktraceWidget::extraDetailsLinkActivated(QString link) +{ + if (link.startsWith(QLatin1String("http"))) { + //Open externally + KToolInvocation::invokeBrowser(link); + } else if (link == QLatin1String("#missingDebugPackages")) { + BacktraceParser * btParser = m_btGenerator->parser(); + + QStringList missingDbgForFiles = btParser->librariesWithMissingDebugSymbols().toList(); + missingDbgForFiles.insert(0, DrKonqi::crashedApplication()->executable().absoluteFilePath()); + + //HTML message + QString message; + message = ""; + message += i18n("The packages containing debug information for the following application and libraries are missing:"); + message += "
    "; + + Q_FOREACH(const QString & string, missingDbgForFiles) { + message += "
  • " + string + "
  • "; + } + + message += "
"; + + KMessageBox::information(this, message, i18nc("messagebox title","Missing debug information packages")); + } +} + diff --git a/drkonqi/backtracewidget.h b/drkonqi/backtracewidget.h new file mode 100644 index 00000000..3cfcadc9 --- /dev/null +++ b/drkonqi/backtracewidget.h @@ -0,0 +1,78 @@ +/******************************************************************* +* backtracewidget.h +* Copyright 2009 Dario Andres Rodriguez +* +* 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, see . +* +******************************************************************/ + +#ifndef BACKTRACEWIDGET__H +#define BACKTRACEWIDGET__H + +#include + +#include "debugpackageinstaller.h" +#include "ui_backtracewidget.h" + +class QSyntaxHighlighter; +class BacktraceRatingWidget; +class BacktraceGenerator; + +class BacktraceWidget: public QWidget +{ + Q_OBJECT + +public: + explicit BacktraceWidget(BacktraceGenerator *generator, QWidget *parent = 0, + bool showToggleBacktrace = false); + + bool canInstallDebugPackages() const; + +public Q_SLOTS: + void generateBacktrace(); + void hilightExtraDetailsLabel(bool hilight); + void focusImproveBacktraceButton(); + + void toggleBacktrace(bool show); + void extraDetailsLinkActivated(QString link); + +Q_SIGNALS: + void stateChanged(); + +private: + BacktraceGenerator * m_btGenerator; + Ui::Form ui; + BacktraceRatingWidget * m_backtraceRatingWidget; + QSyntaxHighlighter *m_highlighter; + DebugPackageInstaller * m_debugPackageInstaller; + + void setAsLoading(); + +private Q_SLOTS: + void loadData(); + void backtraceNewLine(const QString &); + + void regenerateBacktrace(); + + void saveClicked(); + void copyClicked(); + + void anotherDebuggerRunning(); + + void installDebugPackages(); + void debugPackageError(const QString &); + void debugPackageCanceled(); +}; + +#endif diff --git a/drkonqi/bugreportaddress.h b/drkonqi/bugreportaddress.h new file mode 100644 index 00000000..c64331c2 --- /dev/null +++ b/drkonqi/bugreportaddress.h @@ -0,0 +1,44 @@ +/* + Copyright (C) 2009 George Kiagiadakis + + 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, see . +*/ +#ifndef BUGREPORTADDRESS_H +#define BUGREPORTADDRESS_H + +#include + +#include "drkonqi_globals.h" + +class BugReportAddress : public QString +{ +public: + inline BugReportAddress() : QString() {} + inline BugReportAddress(const QString & address) + : QString(address == QLatin1String("submit@bugs.kde.org") ? + QLatin1String(KDE_BUGZILLA_URL) : address) + {} + + inline bool isKdeBugzilla() const + { + return *this == QLatin1String(KDE_BUGZILLA_URL); + } + + inline bool isEmail() const + { + return contains('@'); + } +}; + +#endif diff --git a/drkonqi/config-drkonqi.h.cmake b/drkonqi/config-drkonqi.h.cmake new file mode 100644 index 00000000..f5723d50 --- /dev/null +++ b/drkonqi/config-drkonqi.h.cmake @@ -0,0 +1,3 @@ +#cmakedefine HAVE_STRSIGNAL 1 +#cmakedefine HAVE_UNAME 1 +#define DEBUG_PACKAGE_INSTALLER_NAME "@DEBUG_PACKAGE_INSTALLER_NAME@" diff --git a/drkonqi/crashedapplication.cpp b/drkonqi/crashedapplication.cpp new file mode 100644 index 00000000..ef63232b --- /dev/null +++ b/drkonqi/crashedapplication.cpp @@ -0,0 +1,186 @@ +/* + Copyright (C) 2009 George Kiagiadakis + + 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, see . +*/ + +#include + +#include "crashedapplication.h" + +#if defined(HAVE_STRSIGNAL) && defined(Q_OS_UNIX) +# include +# include +# include +#else +# if defined(Q_OS_UNIX) +# include +# else +# include +# endif +#endif + +#include + +CrashedApplication::CrashedApplication(QObject *parent) + : QObject(parent), m_restarted(false) +{ +} + +CrashedApplication::~CrashedApplication() +{ +} + +QString CrashedApplication::name() const +{ + return m_name; +} + +QFileInfo CrashedApplication::executable() const +{ + return m_executable; +} + +QString CrashedApplication::fakeExecutableBaseName() const +{ + if (!m_fakeBaseName.isEmpty()) { + return m_fakeBaseName; + } else { + return m_executable.baseName(); + } +} + +QString CrashedApplication::version() const +{ + return m_version; +} + +BugReportAddress CrashedApplication::bugReportAddress() const +{ + return m_reportAddress; +} + +int CrashedApplication::pid() const +{ + return m_pid; +} + +int CrashedApplication::signalNumber() const +{ + return m_signalNumber; +} + +QString CrashedApplication::signalName() const +{ +#if defined(HAVE_STRSIGNAL) && defined(Q_OS_UNIX) + const char * oldLocale = std::setlocale(LC_MESSAGES, NULL); + char * savedLocale; + if (oldLocale) { + savedLocale = strdup(oldLocale); + } else { + savedLocale = NULL; + } + std::setlocale(LC_MESSAGES, "C"); + const char *name = strsignal(m_signalNumber); + std::setlocale(LC_MESSAGES, savedLocale); + std::free(savedLocale); + return QString::fromLocal8Bit(name != NULL ? name : "Unknown"); +#else + switch (m_signalNumber) { +# if defined(Q_OS_UNIX) + case SIGILL: return QLatin1String("SIGILL"); + case SIGABRT: return QLatin1String("SIGABRT"); + case SIGFPE: return QLatin1String("SIGFPE"); + case SIGSEGV: return QLatin1String("SIGSEGV"); + case SIGBUS: return QLatin1String("SIGBUS"); +# else + case EXCEPTION_ACCESS_VIOLATION: return QLatin1String("EXCEPTION_ACCESS_VIOLATION"); + case EXCEPTION_DATATYPE_MISALIGNMENT: return QLatin1String("EXCEPTION_DATATYPE_MISALIGNMENT"); + case EXCEPTION_BREAKPOINT: return QLatin1String("EXCEPTION_BREAKPOINT"); + case EXCEPTION_SINGLE_STEP: return QLatin1String("EXCEPTION_SINGLE_STEP"); + case EXCEPTION_ARRAY_BOUNDS_EXCEEDED: return QLatin1String("EXCEPTION_ARRAY_BOUNDS_EXCEEDED"); + case EXCEPTION_FLT_DENORMAL_OPERAND: return QLatin1String("EXCEPTION_FLT_DENORMAL_OPERAND"); + case EXCEPTION_FLT_DIVIDE_BY_ZERO: return QLatin1String("EXCEPTION_FLT_DIVIDE_BY_ZERO"); + case EXCEPTION_FLT_INEXACT_RESULT: return QLatin1String("EXCEPTION_FLT_INEXACT_RESULT"); + case EXCEPTION_FLT_INVALID_OPERATION: return QLatin1String("EXCEPTION_FLT_INVALID_OPERATION"); + case EXCEPTION_FLT_OVERFLOW: return QLatin1String("EXCEPTION_FLT_OVERFLOW"); + case EXCEPTION_FLT_STACK_CHECK: return QLatin1String("EXCEPTION_FLT_STACK_CHECK"); + case EXCEPTION_FLT_UNDERFLOW: return QLatin1String("EXCEPTION_FLT_UNDERFLOW"); + case EXCEPTION_INT_DIVIDE_BY_ZERO: return QLatin1String("EXCEPTION_INT_DIVIDE_BY_ZERO"); + case EXCEPTION_INT_OVERFLOW: return QLatin1String("EXCEPTION_INT_OVERFLOW"); + case EXCEPTION_PRIV_INSTRUCTION: return QLatin1String("EXCEPTION_PRIV_INSTRUCTION"); + case EXCEPTION_IN_PAGE_ERROR: return QLatin1String("EXCEPTION_IN_PAGE_ERROR"); + case EXCEPTION_ILLEGAL_INSTRUCTION: return QLatin1String("EXCEPTION_ILLEGAL_INSTRUCTION"); + case EXCEPTION_NONCONTINUABLE_EXCEPTION: return QLatin1String("EXCEPTION_NONCONTINUABLE_EXCEPTION"); + case EXCEPTION_STACK_OVERFLOW: return QLatin1String("EXCEPTION_STACK_OVERFLOW"); + case EXCEPTION_INVALID_DISPOSITION: return QLatin1String("EXCEPTION_INVALID_DISPOSITION"); +# endif + default: return QLatin1String("Unknown"); + } +#endif +} + +bool CrashedApplication::hasBeenRestarted() const +{ + return m_restarted; +} + +int CrashedApplication::thread() const +{ + return m_thread; +} + +const QDateTime& CrashedApplication::datetime() const +{ + return m_datetime; +} + +void CrashedApplication::restart() +{ + if (m_restarted) { + return; + } + + int ret = -1; + + //start the application via kdeinit, as it needs to have a pristine environment and + //KProcess::startDetached() can't start a new process with custom environment variables. + if (!m_fakeBaseName.isEmpty()) { + // if m_fakeBaseName is set, this means m_executable is the path to kdeinit4 + // so we need to use the fakeBaseName to restart the app + ret = KToolInvocation::kdeinitExec(m_fakeBaseName); + } else { + ret = KToolInvocation::kdeinitExec(m_executable.absoluteFilePath()); + } + + const bool success = (ret == 0); + + m_restarted = success; + emit restarted(success); +} + +QString getSuggestedKCrashFilename(const CrashedApplication* app) +{ + QString filename = app->fakeExecutableBaseName() + '-' + + app->datetime().toString("yyyyMMdd-hhmmss") + + ".kcrash.txt"; + + if (filename.contains('/')) { + filename = filename.mid(filename.lastIndexOf('/') + 1); + } + + return filename; +} + +#include "crashedapplication.moc" diff --git a/drkonqi/crashedapplication.h b/drkonqi/crashedapplication.h new file mode 100644 index 00000000..59672f87 --- /dev/null +++ b/drkonqi/crashedapplication.h @@ -0,0 +1,93 @@ +/* + Copyright (C) 2009 George Kiagiadakis + + 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, see . +*/ +#ifndef CRASHEDAPPLICATION_H +#define CRASHEDAPPLICATION_H + +#include +#include +#include + +#include "bugreportaddress.h" + +class KCrashBackend; + +class CrashedApplication : public QObject +{ + Q_OBJECT +public: + virtual ~CrashedApplication(); + + /** Returns the crashed program's name, possibly translated (ex. "The KDE Crash Handler") */ + QString name() const; + + /** Returns a QFileInfo with information about the executable that crashed */ + QFileInfo executable() const; + + /** When an application is run via kdeinit, the executable() method returns kdeinit4, but + * we still need a way to know which is the application that was loaded by kdeinit. So, + * this method returns the base name of the executable that would have been launched if + * the app had not been loaded by kdeinit (ex. "plasma-desktop"). If the application was + * not launched via kdeinit, this method returns executable().baseName(); + */ + QString fakeExecutableBaseName() const; + + /** Returns the version of the crashed program */ + QString version() const; + + /** Returns the address where the bug report for this application should go */ + BugReportAddress bugReportAddress() const; + + /** Returns the pid of the crashed program */ + int pid() const; + + /** Returns the signal number that the crashed program received */ + int signalNumber() const; + + /** Returns the name of the signal (ex. SIGSEGV) */ + QString signalName() const; + + bool hasBeenRestarted() const; + + int thread() const; + + const QDateTime& datetime() const; + +public slots: + void restart(); + +signals: + void restarted(bool success); + +protected: + friend class KCrashBackend; + CrashedApplication(QObject *parent = 0); + + int m_pid; + int m_signalNumber; + QString m_name; + QFileInfo m_executable; + QString m_fakeBaseName; + QString m_version; + BugReportAddress m_reportAddress; + bool m_restarted; + int m_thread; + QDateTime m_datetime; +}; + +QString getSuggestedKCrashFilename(const CrashedApplication* app); + +#endif // CRASHEDAPPLICATION_H diff --git a/drkonqi/data/CMakeLists.txt b/drkonqi/data/CMakeLists.txt new file mode 100644 index 00000000..917e0386 --- /dev/null +++ b/drkonqi/data/CMakeLists.txt @@ -0,0 +1,3 @@ +install(FILES crash.png DESTINATION ${DATA_INSTALL_DIR}/drkonqi/pics) +install(FILES mappings DESTINATION ${DATA_INSTALL_DIR}/drkonqi) +install(DIRECTORY debuggers DESTINATION ${DATA_INSTALL_DIR}/drkonqi PATTERN ".svn" EXCLUDE) diff --git a/drkonqi/data/crash.png b/drkonqi/data/crash.png new file mode 100644 index 00000000..c2f7ca30 Binary files /dev/null and b/drkonqi/data/crash.png differ diff --git a/drkonqi/data/debuggers/external/gdbrc b/drkonqi/data/debuggers/external/gdbrc new file mode 100644 index 00000000..70f715a6 --- /dev/null +++ b/drkonqi/data/debuggers/external/gdbrc @@ -0,0 +1,80 @@ +[General] +Name=gdb +Name[ar]=gdb +Name[ast]=gdb +Name[bg]=gdb +Name[bn]=gdb +Name[bs]=GDB +Name[ca]=gdb +Name[ca@valencia]=gdb +Name[cs]=gdb +Name[csb]=gdb +Name[da]=gdb +Name[de]=gdb +Name[el]=gdb +Name[en_GB]=gdb +Name[eo]=gdb +Name[es]=gdb +Name[et]=gdb +Name[eu]=gdb +Name[fa]=gdb +Name[fi]=gdb +Name[fr]=gdb +Name[fy]=gdb +Name[ga]=gdb +Name[gl]=gdb +Name[gu]=gdb +Name[he]=gdb +Name[hi]=gdb +Name[hr]=gdb +Name[hu]=gdb +Name[ia]=gdb +Name[id]=gdb +Name[is]=gdb +Name[it]=gdb +Name[ja]=gdb +Name[ka]=gdb +Name[kk]=gdb +Name[km]=gdb +Name[kn]=gdb +Name[ko]=gdb +Name[lt]=gdb +Name[lv]=gdb +Name[mai]=gdb +Name[mk]=gdb +Name[ml]=ജിഡിബി +Name[mr]=gdb +Name[nb]=gdb +Name[nds]=gdb +Name[nl]=gdb +Name[nn]=gdb +Name[pa]=gdb +Name[pl]=gdb +Name[pt]=gdb +Name[pt_BR]=gdb +Name[ro]=gdb +Name[ru]=gdb +Name[si]=gdb +Name[sk]=gdb +Name[sl]=gdb +Name[sr]=ГДБ +Name[sr@ijekavian]=ГДБ +Name[sr@ijekavianlatin]=GDB +Name[sr@latin]=GDB +Name[sv]=gdb +Name[tg]=gdb +Name[th]=gdb +Name[tr]=gdb +Name[ug]=gdb +Name[uk]=gdb +Name[vi]=gdb +Name[wa]=gdb +Name[x-test]=xxgdbxx +Name[zh_CN]=gdb +Name[zh_TW]=gdb +TryExec=gdb +Backends=KCrash + +[KCrash] +Exec=konsole --nofork -e gdb -nw -p %pid %execpath +Terminal=true diff --git a/drkonqi/data/debuggers/external/kdbgrc b/drkonqi/data/debuggers/external/kdbgrc new file mode 100644 index 00000000..3e3d9487 --- /dev/null +++ b/drkonqi/data/debuggers/external/kdbgrc @@ -0,0 +1,79 @@ +[General] +Name=kdbg +Name[ar]=kdbg +Name[ast]=kdbg +Name[bg]=kdbg +Name[bn]=kdbg +Name[bs]=Kdbg +Name[ca]=kdbg +Name[ca@valencia]=kdbg +Name[cs]=kdbg +Name[csb]=kdbg +Name[da]=kdbg +Name[de]=kdbg +Name[el]=kdbg +Name[en_GB]=kdbg +Name[eo]=kdbg +Name[es]=kdbg +Name[et]=kdbg +Name[eu]=kdbg +Name[fa]=kdbg +Name[fi]=kdbg +Name[fr]=kdbg +Name[fy]=kdbg +Name[ga]=kdbg +Name[gl]=kdbg +Name[gu]=kdbg +Name[he]=kdbg +Name[hi]=kdbg +Name[hr]=kdbg +Name[hu]=kdbg +Name[ia]=kdbg +Name[id]=kdbg +Name[is]=kdbg +Name[it]=kdbg +Name[ja]=kdbg +Name[ka]=kdbg +Name[kk]=kdbg +Name[km]=kdbg +Name[kn]=kdbg +Name[ko]=kdbg +Name[lt]=kdbg +Name[lv]=kdbg +Name[mai]=kdbg +Name[mk]=kdbg +Name[ml]=കെഡിബിജി +Name[mr]=kdbg +Name[nb]=kdbg +Name[nds]=kgdb +Name[nl]=kdbg +Name[nn]=kdbg +Name[pa]=kdbg +Name[pl]=kdbg +Name[pt]=kdbg +Name[pt_BR]=kdbg +Name[ro]=kdbg +Name[ru]=kdbg +Name[si]=kdbg +Name[sk]=kdbg +Name[sl]=kdbg +Name[sr]=Кдбг +Name[sr@ijekavian]=Кдбг +Name[sr@ijekavianlatin]=KDbg +Name[sr@latin]=KDbg +Name[sv]=kdbg +Name[tg]=kdbg +Name[th]=kdbg +Name[tr]=kdbg +Name[ug]=kdbg +Name[uk]=kdbg +Name[vi]=kdbg +Name[wa]=kdbg +Name[x-test]=xxkdbgxx +Name[zh_CN]=kdbg +Name[zh_TW]=kdbg +TryExec=kdbg +Backends=KCrash + +[KCrash] +Exec=kdbg -p %pid %execpath diff --git a/drkonqi/data/debuggers/internal/dbxrc b/drkonqi/data/debuggers/internal/dbxrc new file mode 100644 index 00000000..2cea7087 --- /dev/null +++ b/drkonqi/data/debuggers/internal/dbxrc @@ -0,0 +1,76 @@ +[General] +Name=dbx +Name[ar]=dbx +Name[ast]=dbx +Name[bg]=dbx +Name[bn]=dbx +Name[bs]=DBX +Name[ca]=dbx +Name[ca@valencia]=dbx +Name[cs]=dbx +Name[da]=dbx +Name[de]=dbx +Name[el]=dbx +Name[en_GB]=dbx +Name[eo]=dbx +Name[es]=dbx +Name[et]=dbx +Name[eu]=dbx +Name[fa]=dbx +Name[fi]=dbx +Name[fr]=dbx +Name[ga]=dbx +Name[gl]=dbx +Name[gu]=dbx +Name[he]=dbx +Name[hi]=dbx +Name[hr]=dbx +Name[hu]=dbx +Name[ia]=dbx +Name[id]=dbx +Name[is]=dbx +Name[it]=dbx +Name[ja]=dbx +Name[kk]=dbx +Name[km]=dbx +Name[kn]=dbx +Name[ko]=dbx +Name[lt]=dbx +Name[lv]=dbx +Name[mai]=dbx +Name[mr]=dbx +Name[nb]=gdb +Name[nds]=dbx +Name[nl]=dbx +Name[nn]=dbx +Name[pa]=dbx +Name[pl]=dbx +Name[pt]=dbx +Name[pt_BR]=dbx +Name[ro]=dbx +Name[ru]=dbx +Name[si]=dbx +Name[sk]=dbx +Name[sl]=dbx +Name[sr]=ДБИкс +Name[sr@ijekavian]=ДБИкс +Name[sr@ijekavianlatin]=DBX +Name[sr@latin]=DBX +Name[sv]=dbx +Name[tg]=dbx +Name[th]=dbx +Name[tr]=dbx +Name[ug]=dbx +Name[uk]=dbx +Name[vi]=dbx +Name[wa]=dbx +Name[x-test]=xxdbxxx +Name[zh_CN]=dbx +Name[zh_TW]=dbx +TryExec=dbx +Backends=KCrash + +[KCrash] +Exec=dbx -c "where -l -v -h;quit" - %pid +BatchCommands=where + diff --git a/drkonqi/data/debuggers/internal/gdbrc b/drkonqi/data/debuggers/internal/gdbrc new file mode 100644 index 00000000..322c5b3c --- /dev/null +++ b/drkonqi/data/debuggers/internal/gdbrc @@ -0,0 +1,80 @@ +[General] +Name=gdb +Name[ar]=gdb +Name[ast]=gdb +Name[bg]=gdb +Name[bn]=gdb +Name[bs]=GDB +Name[ca]=gdb +Name[ca@valencia]=gdb +Name[cs]=gdb +Name[csb]=gdb +Name[da]=gdb +Name[de]=gdb +Name[el]=gdb +Name[en_GB]=gdb +Name[eo]=gdb +Name[es]=gdb +Name[et]=gdb +Name[eu]=gdb +Name[fa]=gdb +Name[fi]=gdb +Name[fr]=gdb +Name[fy]=gdb +Name[ga]=gdb +Name[gl]=gdb +Name[gu]=gdb +Name[he]=gdb +Name[hi]=gdb +Name[hr]=gdb +Name[hu]=gdb +Name[ia]=gdb +Name[id]=gdb +Name[is]=gdb +Name[it]=gdb +Name[ja]=gdb +Name[ka]=gdb +Name[kk]=gdb +Name[km]=gdb +Name[kn]=gdb +Name[ko]=gdb +Name[lt]=gdb +Name[lv]=gdb +Name[mai]=gdb +Name[mk]=gdb +Name[ml]=ജിഡിബി +Name[mr]=gdb +Name[nb]=gdb +Name[nds]=gdb +Name[nl]=gdb +Name[nn]=gdb +Name[pa]=gdb +Name[pl]=gdb +Name[pt]=gdb +Name[pt_BR]=gdb +Name[ro]=gdb +Name[ru]=gdb +Name[si]=gdb +Name[sk]=gdb +Name[sl]=gdb +Name[sr]=ГДБ +Name[sr@ijekavian]=ГДБ +Name[sr@ijekavianlatin]=GDB +Name[sr@latin]=GDB +Name[sv]=gdb +Name[tg]=gdb +Name[th]=gdb +Name[tr]=gdb +Name[ug]=gdb +Name[uk]=gdb +Name[vi]=gdb +Name[wa]=gdb +Name[x-test]=xxgdbxx +Name[zh_CN]=gdb +Name[zh_TW]=gdb +TryExec=gdb +Backends=KCrash + +[KCrash] +Exec=gdb -nw -n -batch -x %tempfile -p %pid %execpath +BatchCommands=set width 200\nthread\nthread apply all bt diff --git a/drkonqi/data/debuggers/internal/kdbgwinrc b/drkonqi/data/debuggers/internal/kdbgwinrc new file mode 100644 index 00000000..1b30c94a --- /dev/null +++ b/drkonqi/data/debuggers/internal/kdbgwinrc @@ -0,0 +1,75 @@ +[General] +Name=kdbgwin +Name[ar]=kdbgwin +Name[ast]=kdbgwin +Name[bg]=kdbgwin +Name[bn]=kdbgwin +Name[bs]=Kdbgwin +Name[ca]=kdbgwin +Name[ca@valencia]=kdbgwin +Name[cs]=kdbgwin +Name[da]=kdbgwin +Name[de]=kdbgwin +Name[el]=kdbgwin +Name[en_GB]=kdbgwin +Name[eo]=kdbgwin +Name[es]=kdbgwin +Name[et]=kdbgwin +Name[eu]=kdbgwin +Name[fa]=kdbgwin +Name[fi]=kdbgwin +Name[fr]=kdbgwin +Name[ga]=kdbgwin +Name[gl]=kdbgwin +Name[gu]=kdbgwin +Name[he]=kdbgwin +Name[hi]=kdbgwin +Name[hr]=kdbgwin +Name[hu]=kdbgwin +Name[ia]=kdbgwin +Name[id]=kdbgwin +Name[is]=kdbgwin +Name[it]=kdbgwin +Name[ja]=kdbgwin +Name[ka]=kdbgwin +Name[kk]=kdbgwin +Name[km]=kdbgwin +Name[kn]=kdbgwin +Name[ko]=kdbgwin +Name[lt]=kdbgwin +Name[lv]=kdbgwin +Name[mai]=kdbgwin +Name[mr]=kdbgwin +Name[nb]=kdbgwin +Name[nds]=kdbgwin +Name[nl]=kdbgwin +Name[nn]=kdbgwin +Name[pa]=kdbgwin +Name[pl]=kdbgwin +Name[pt]=kdbgwin +Name[pt_BR]=kdbgwin +Name[ro]=kdbgwin +Name[ru]=kdbgwin +Name[si]=kdbgwin +Name[sk]=kdbgwin +Name[sl]=kdbgwin +Name[sr]=Кдбг‑вин +Name[sr@ijekavian]=Кдбг‑вин +Name[sr@ijekavianlatin]=KDbgWin +Name[sr@latin]=KDbgWin +Name[sv]=kdbgwin +Name[tg]=kdbgwin +Name[th]=kdbgwin +Name[tr]=kdbgwin +Name[ug]=kdbgwin +Name[uk]=kdbgwin +Name[vi]=kdbgwin +Name[wa]=kdbgwin +Name[x-test]=xxkdbgwinxx +Name[zh_CN]=kdbgwin +Name[zh_TW]=kdbgwin +TryExec=kdbgwin +Backends=KCrash + +[KCrash] +Exec=kdbgwin %pid %thread diff --git a/drkonqi/data/mappings b/drkonqi/data/mappings new file mode 100644 index 00000000..782e3036 --- /dev/null +++ b/drkonqi/data/mappings @@ -0,0 +1,286 @@ +#--- +#Binary name -> Bugzilla product|component mapping +#--- + +[Mappings] + +#KDE Platform (kdelibs) +kdebugdialog=kdelibs|general +kdeinit4=kdelibs|general +kdepasswd=kdelibs|kpasswdserver +kdialog=kdelibs|general +keditfiletype=kdelibs|general +kfmclient=kdelibs|general +kglobalaccel=kdelibs|general +kiconfinder=kdelibs|general +kuiserver=kdelibs|general +kded4=kdelibs|kded +kcmshell4=systemsettings|general +kwalletd=kdelibs|kwallet +kwrited=konsole|kwrited +kbuildsycoca4=kdelibs|ksycoca +knotify4=kdelibs|knotify +kcminit=kde|general + +#KDE Platform (KIO) +kioclient=kio|general +ktrash=kio|trash + +#KDE Platform (Solid) +solid-action-desktop-gen=solid|general +bluedevil-audio=solid|bluetooth +bluedevil-helper=solid|bluetooth +bluedevil-input=solid|bluetooth +bluedevil-monolithic=solid|bluetooth +bluedevil-network-dun=solid|bluetooth +bluedevil-network-panu=solid|bluetooth +bluedevil-sendfile=solid|bluetooth +bluedevil-wizard=solid|bluetooth + +#KDE Platform (Nepomuk) +nepomukbackup=nepomuk|backupservice +nepomukcleaner=nepomuk|general +nepomukcontroller=nepomuk|controller +nepomukindexer=nepomuk|fileindexer +nepomukfileindexer=nepomuk|fileindexer +nepomukfilewatch=nepomuk|filewatch +nepomukstorage=nepomuk|storage +nepomukserver=nepomuk|general +nepomukservicestub=nepomuk|general +nepomukshell=nepomukshell|Misc +metadataextractor=nepomuk|general + +#KDE Plasma Desktop (Plasma & KRunner) +plasma-desktop=plasma|general +plasma-mid=plasma|general +plasma-overlay=plasma|general +plasma2jolie=plasma|general +plasmagik=plasma|general +plasmapkg=plasma|general +knotificationareaitemtest=plasma|widget-systemtray +knotificationicontest=plasma|widget-systemtray +lancelot=plasma|widget-lancelot +plasma-netbook=plasma|plasma-netbook +kactivitymanagerd=kactivities|general +plasma-windowed=plasma|general +plasma-device=Active|General + +#KDE Plasma SDK (Plasmate) +plasmaengineexplorer=plasmate|general +plasmawallpaperviewer=plasmate|general +plasmoidviewer=plasmate|general + +#KDE Plasma Desktop (KWin) +kwin_gles=kwin|general +kwinactive=kwin|general +kwinactive_gles=kwin|general + +#KDE Kontact (Akonadi) +akonadi_archivemail_agent=Akonadi|Archive Mail Agent +akonadi_benchmarker=Akonadi|general +akonadi_birthdays_resource=Akonadi|general +akonadi_contacts_resource=Akonadi|Contacts resource +akonadi_control=Akonadi|general +akonadi_davgroupware_resource=Akonadi|DAV Resource +akonadi_distlist_resource=Akonadi|general +akonadi_facebook_resource=Akonadi|Facebook Resource +akonadi_gcal_resource=Akonadi|Google Resource +akonadi_googledata_resource=Akonadi|GoogleData Resource +akonadi_googlecalendar_resource=Akonadi|Google Resource +akonadi_googlecontacts_resource=Akonadi|Google Resource +akonadi_ical_resource=Akonadi|ICal file resource +akonadi_imap_resource=Akonadi|IMAP resource +akonadi_kabc_resource=Akonadi|KResource compat Bridges +akonadi_kcal_resource=Akonadi|KResource compat Bridges +akonadi_knut_resource=Akonadi|Knut resource +akonadi_kolabproxy_resource=Akonadi|Kolab resource +akonadi_localbookmarks_resource=Akonadi|Local Bookmark Resource +akonadi_maildir_resource=Akonadi|Maildir Resource +akonadi_maildispatcher_agent=Akonadi|Mail Dispatcher Agent +akonadi_mailfilter_agent=Akonadi|Mail Filter Agent +akonadi_mailthreader_agent=Akonadi|general +akonadi_mixedmaildir_resource=Akonadi|Mixed Maildir resource +akonadi_nepomuk_feeder=Akonadi|Nepomuk Feeder Agents +akonadi_nepomuk_calendar_feeder=Akonadi|Nepomuk Feeder Agents +akonadi_nepomuk_contact_feeder=Akonadi|Nepomuk Feeder Agents +akonadi_nepomuk_email_feeder=Akonadi|Nepomuk Feeder Agents +akonadi_nepomuktag_resource=Akonadi|Nepomuk Feeder Agents +akonadi_nntp_resource=Akonadi|general +akonadi_pop3_resource=Akonadi|POP3 Resource +akonadi_strigi_feeder=Akonadi|general +akonadi_sendlater_agent=Akonadi|SendLaterAgent +akonadi_vcard_resource=Akonadi|VCard file resource +akonadi_vcarddir_resource=Akonadi|VCard dir resource +akonadiconsole=Akonadi|akonadiconsole +akonadictl=Akonadi|general +akonadiserver=Akonadi|server +akonaditest=Akonadi|general +akonaditray=Akonadi|general +accountwizard=Akonadi|Account Wizard +kres-migrator=Akonadi|Migration +akonadi_openxchange_resource=Akonadi|OpenXchange Resource +akonadi_newmailnotifier_agent=Akonadi|New Mail Notifier + +#KDE Kontact (PIM) +importwizard=kdepim|importwizard +kalarmautostart=kalarm|general +kpilotDaemon=kpilot|kpilotDaemon +korgac=korgac|general +kmail=kmail2|general +kmail-migrator=kmail2|general +kaddressbook-mobile=KDE PIM Mobile|general +backupmail=kdepim|backupmail + + +#KDE Konqueror +kjscmd=konqueror|kjs +nspluginscan=konqueror|nsplugins +nspluginviewer=konqueror|nspluginviewer + +# KDE Telepathy +ktp-contactlist=telepathy|contactlist +ktp-send-file=telepathy|send-file +ktp-text-ui=telepathy|text-ui +ktp-call-ui=telepathy|call-ui +ktp-filetransfer-handler=telepathy|filetransfer-handler +ktp-auth-handler=telepathy|auth-handler +ktp-log-viewer=telepathy|log-viewer + +# KDE Calligra Suite +braindump=braindump|application +kritagemini=krita|general +kritasketch=krita|krita sketch + + +# KDE Kipi-plugins +dngconverter=kipiplugins|DngConverter +expoblending=kipiplugins|ExpoBlending +panoramagui=kipiplugins|Panorama +photolayoutseditor=kipiplugins|PhotoLayoutsEditor +scangui=kipiplugins|AcquireImages + + +# Gluon +gluoncreator=gluon|gluoncreator +gluon_kdeplayer=gluon|gluonplayer +gluon_kdeextplayer=gluon|gluonplayer + +#Other KDE Applications and Technologies +kmixctrl=kmix|general +kwrite=kate|kwrite +dragon=dragonplayer|general +kaccess=systemsettings|kcm_accessibility +kfontinst=systemsettings|kcm_fontinst +kfontview=systemsettings|kcm_fontinst +polkit-kde-manager=policykit-kde|manager +polkit-kde-authentication-agent-1=policykit-kde|polkit-kde-authentication-agent-1 +kepastray=kepas|general +apper-sentinel=apper|general +muon=muon|muon +muon-discover=muon|discover +muon-installer=muon|installer +muon-updater=muon|updater +printer-applet-kde=printer-applet|general +kde-add-printer=print-manager|general +kde-print-queue=print-manager|general +partitionmanager-bin=partitionmanager|general +krandrtray=krandr|krandrtray +kmymoney=kmymoney4|general +kdevdesigner=kdevelop|Qt Designer Integration +kdevelop.bin=kdevelop|general +kscreenlocker=kscreensaver|locker +gwenview_importer=gwenview|importer +kdmgreet=kdm|general +kaffeine-xbu=kaffeine|general +networkmanagement_configshell=Network Management|general +krcdnotifieritem=kremotecontrol|tray +khipu=khipu|core +mangonel=Mangonel|mangonel +kde-nm-connection-editor=plasma-nm|editor +pairseditor=pairs|editor + +kwatchgnupg=kleopatra|general +homerunviewer=homerun|general + +ksecretsync=ksecretservice|ksecretsync +cvsservice=cervisia|general + + +# applicaitons not using bugs.kde.org +aku=unknown|general +compiz=unknown|general +firefox=unknown|general +firefox-bin=unknown|general +iqfile=unknown|general +kanyremote=unknown|general +kde4-window-decorator=unknown|general +kdesudo=unknown|general +kdialogd4=unknown|general +kguitar=unknown|general +klog=unknown|general +klog-bin=unknown|general +kmozillahelper=unknown|general +konstructor=unknown|general +kraft=unknown|general +kuroo=unknown|general +kvirc=unknown|general +loopy=unknown|general +leechcraft=unknown|general +nateon=unknown|general +opera=unknown|general +pcSoftwareManager=unknown|general +qutim=unknown|general +semantik=unknown|general +squeeze=unknown|general +subtitlecomposer=unknown|general +synaptiks=unknown|general +shaman=unknown|general +tribe=unknown|general +xulrunner-stub=unknown|general + +#--- +#This section relates a product groupt to a product +#--- + +[ProductGroup] +kontact=kdepim-base|kdepim-apps +korganizer=kdepim-base +kaddressbook=kdepim-base +akregator=kdepim-base +kmail=kdepim-base +KMail 2=kdepim-base +Akonadi=kdepim-base +kword=koffice +koshell=koffice +kdevelop=kdevelop +kdevdesigner=kdevelop +plasma=kdebindings +amarok=multimedia +digikam=imaging +gwenview=imaging +kaffeine=multimedia +juk=multimedia +knetworkmanager=networkmanager +Skanlite=scanner +konqueror=filemanagement +kcells=koffice +kplato=calligraplan +kpresenter=calligrastage +kspread=calligratables + +#--- +#This section describes several bugzilla products groups. +#--- + +[BZGroups] +kdeplatform=kde|kdelibs|kio|kfile|Oxygen|solid|Phonon|Akonadi +kdepim-base=kontact|kdepimlibs|kdepim|kresources|konqueror +kdepim-apps=kontact|korganizer|kaddressbook|akregator|kmail +koffice=koffice|koshell|kspread|kword|krita|karbon|kchart|kplato|kpresenter +kdevelop=kdevelop|kdevplatform +kdebindings=bindings +multimedia=kdemultimedia|taglib +imaging=digikam|digikamimageplugins|kipiplugins +networkmanager=knetworkmanager|Network Management|solid +scanner=libksane +filemanagement=konqueror|dolphin|nepomuk diff --git a/drkonqi/debugger.cpp b/drkonqi/debugger.cpp new file mode 100644 index 00000000..26ca3389 --- /dev/null +++ b/drkonqi/debugger.cpp @@ -0,0 +1,147 @@ +/* + Copyright (C) 2009 George Kiagiadakis + + 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, see . +*/ +#include "debugger.h" + +#include +#include +#include +#include +#include +#include + +#include "crashedapplication.h" +#include "drkonqi.h" + +//static +QList Debugger::availableInternalDebuggers(const QString & backend) +{ + return availableDebuggers("debuggers/internal/*", backend); +} + +//static +QList Debugger::availableExternalDebuggers(const QString & backend) +{ + return availableDebuggers("debuggers/external/*", backend); +} + +bool Debugger::isValid() const +{ + return !m_config.isNull(); +} + +bool Debugger::isInstalled() const +{ + QString tryexec = tryExec(); + return !tryexec.isEmpty() && !KStandardDirs::findExe(tryexec).isEmpty(); +} + +QString Debugger::name() const +{ + return isValid() ? m_config->group("General").readEntry("Name") : QString(); +} + +QString Debugger::codeName() const +{ + //fall back to the "TryExec" string if "CodeName" is not specified. + //for most debuggers those strings should be the same + return isValid() ? m_config->group("General").readEntry("CodeName", tryExec()) : QString(); +} + +QString Debugger::tryExec() const +{ + return isValid() ? m_config->group("General").readEntry("TryExec") : QString(); +} + +QStringList Debugger::supportedBackends() const +{ + return isValid() ? m_config->group("General").readEntry("Backends") + .split('|', QString::SkipEmptyParts) : QStringList(); +} + +void Debugger::setUsedBackend(const QString & backendName) +{ + if (supportedBackends().contains(backendName)) { + m_backend = backendName; + } +} + +QString Debugger::command() const +{ + if (!isValid() || !m_config->hasGroup(m_backend)) { + return QString(); + } else { + return m_config->group(m_backend).readPathEntry("Exec", QString()); + } +} + +QString Debugger::backtraceBatchCommands() const +{ + if (!isValid() || !m_config->hasGroup(m_backend)) { + return QString(); + } else { + return m_config->group(m_backend).readEntry("BatchCommands"); + } +} + +bool Debugger::runInTerminal() const +{ + if (!isValid() || !m_config->hasGroup(m_backend)) { + return false; + } else { + return m_config->group(m_backend).readEntry("Terminal", false); + } +} + +//static +void Debugger::expandString(QString & str, ExpandStringUsage usage, const QString & tempFile) +{ + const CrashedApplication *appInfo = DrKonqi::crashedApplication(); + QHash map; + map[QLatin1String("progname")] = appInfo->name(); + map[QLatin1String("execname")] = appInfo->fakeExecutableBaseName(); + map[QLatin1String("execpath")] = appInfo->executable().absoluteFilePath(); + map[QLatin1String("signum")] = QString::number(appInfo->signalNumber()); + map[QLatin1String("signame")] = appInfo->signalName(); + map[QLatin1String("pid")] = QString::number(appInfo->pid()); + map[QLatin1String("tempfile")] = tempFile; + map[QLatin1String("thread")] = QString::number(appInfo->thread()); + + if (usage == ExpansionUsageShell) { + str = KMacroExpander::expandMacrosShellQuote(str, map); + } else { + str = KMacroExpander::expandMacros(str, map); + } +} + +//static +QList Debugger::availableDebuggers(const char *regexp, const QString & backend) +{ + KStandardDirs *dirs = KGlobal::dirs(); + QStringList debuggers = dirs->findAllResources("appdata", QLatin1String(regexp), + KStandardDirs::NoDuplicates); + + QList result; + foreach (const QString & debuggerFile, debuggers) { + Debugger debugger; + debugger.m_config = KSharedConfig::openConfig(debuggerFile); + if (debugger.supportedBackends().contains(backend)) { + debugger.setUsedBackend(backend); + result.append(debugger); + } + } + return result; +} diff --git a/drkonqi/debugger.h b/drkonqi/debugger.h new file mode 100644 index 00000000..1451397e --- /dev/null +++ b/drkonqi/debugger.h @@ -0,0 +1,88 @@ +/* + Copyright (C) 2009 George Kiagiadakis + + 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, see . +*/ +#ifndef DEBUGGER_H +#define DEBUGGER_H + +#include + +#include + +class Debugger +{ +public: + static QList availableInternalDebuggers(const QString & backend); + static QList availableExternalDebuggers(const QString & backend); + + /** Returns true if this Debugger instance is valid, or false otherwise. + * Debugger instances are valid only if they have been constructed from + * availableInternalDebuggers() or availableExternalDebuggers(). If they + * have been constructed directly using the Debugger constructor, they are invalid. + */ + bool isValid() const; + + /** Returns true if this debugger is installed. This is determined by + * looking for the executable that tryExec() returns. If it is in $PATH, + * this method returns true. + */ + bool isInstalled() const; + + /** Returns the translatable name of the debugger (eg. "GDB") */ + QString name() const; + + /** Returns the code name of the debugger (eg. "gdb"). */ + QString codeName() const; + + /** Returns the executable name that drkonqi should check if it exists + * to determine whether the debugger is installed + */ + QString tryExec() const; + + /** Returns a list with the drkonqi backends that this debugger supports */ + QStringList supportedBackends() const; + + /** Sets the backend to be used. This function must be called before using + * command(), backtraceBatchCommands() or runInTerminal(). + */ + void setUsedBackend(const QString & backendName); + + /** Returns the command that should be run to use the debugger */ + QString command() const; + + /** Returns the commands that should be given to the debugger when + * run in batch mode in order to generate a backtrace + */ + QString backtraceBatchCommands() const; + + /** If this is an external debugger, it returns whether it should be run in a terminal or not */ + bool runInTerminal() const; + + + enum ExpandStringUsage { + ExpansionUsagePlainText, + ExpansionUsageShell + }; + + static void expandString(QString & str, ExpandStringUsage usage = ExpansionUsagePlainText, + const QString & tempFile = QString()); + +private: + static QList availableDebuggers(const char *regexp, const QString & backend); + KSharedConfig::Ptr m_config; + QString m_backend; +}; + +#endif diff --git a/drkonqi/debuggerlaunchers.cpp b/drkonqi/debuggerlaunchers.cpp new file mode 100644 index 00000000..6bdb52d3 --- /dev/null +++ b/drkonqi/debuggerlaunchers.cpp @@ -0,0 +1,117 @@ +/* + Copyright (C) 2009 George Kiagiadakis + + 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, see . +*/ +#include "debuggerlaunchers.h" + +#include + +#include +#include +#include + +#include "detachedprocessmonitor.h" +#include "drkonqi.h" +#include "crashedapplication.h" + +DefaultDebuggerLauncher::DefaultDebuggerLauncher(const Debugger & debugger, DebuggerManager *parent) + : AbstractDebuggerLauncher(parent), m_debugger(debugger) +{ + m_monitor = new DetachedProcessMonitor(this); + connect(m_monitor, SIGNAL(processFinished()), SLOT(onProcessFinished())); +} + +QString DefaultDebuggerLauncher::name() const +{ + return m_debugger.name(); +} + +void DefaultDebuggerLauncher::start() +{ + if ( qobject_cast(parent())->debuggerIsRunning() ) { + kWarning() << "Another debugger is already running"; + return; + } + + QString str = m_debugger.command(); + Debugger::expandString(str, Debugger::ExpansionUsageShell); + + emit starting(); + int pid = KProcess::startDetached(KShell::splitArgs(str)); + if ( pid > 0 ) { + m_monitor->startMonitoring(pid); + } else { + kError() << "Could not start debugger:" << name(); + emit finished(); + } +} + +void DefaultDebuggerLauncher::onProcessFinished() +{ + emit finished(); +} + +#if 0 +TerminalDebuggerLauncher::TerminalDebuggerLauncher(const Debugger & debugger, DebuggerManager *parent) + : DefaultDebuggerLauncher(debugger, parent) +{ +} + +void TerminalDebuggerLauncher::start() +{ + DefaultDebuggerLauncher::start(); //FIXME +} +#endif + + +DBusOldInterfaceLauncher::DBusOldInterfaceLauncher(DebuggerManager *parent) + : AbstractDebuggerLauncher(parent) +{ + m_adaptor = new DBusOldInterfaceAdaptor(this); + QDBusConnection::sessionBus().registerObject("/krashinfo", this); +} + +QString DBusOldInterfaceLauncher::name() const +{ + return m_name; +} + +void DBusOldInterfaceLauncher::start() +{ + emit starting(); + emit m_adaptor->acceptDebuggingApplication(); +} + + +DBusOldInterfaceAdaptor::DBusOldInterfaceAdaptor(DBusOldInterfaceLauncher *parent) + : QDBusAbstractAdaptor(parent) +{ + Q_ASSERT(parent); +} + +int DBusOldInterfaceAdaptor::pid() +{ + return DrKonqi::crashedApplication()->pid(); +} + +void DBusOldInterfaceAdaptor::registerDebuggingApplication(const QString & name) +{ + if ( static_cast(parent())->m_name.isEmpty() && !name.isEmpty() ) { + static_cast(parent())->m_name = name; + emit static_cast(parent())->available(); + } +} + +#include "debuggerlaunchers.moc" diff --git a/drkonqi/debuggerlaunchers.h b/drkonqi/debuggerlaunchers.h new file mode 100644 index 00000000..ad6e3d59 --- /dev/null +++ b/drkonqi/debuggerlaunchers.h @@ -0,0 +1,112 @@ +/* + Copyright (C) 2009 George Kiagiadakis + + 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, see . +*/ +#ifndef DEBUGGERLAUNCHERS_H +#define DEBUGGERLAUNCHERS_H + +#include + +#include "debugger.h" +#include "debuggermanager.h" + +class DetachedProcessMonitor; + +class AbstractDebuggerLauncher : public QObject +{ + Q_OBJECT + Q_PROPERTY(QString name READ name) +public: + explicit AbstractDebuggerLauncher(DebuggerManager *parent = 0) : QObject(parent) {} + virtual QString name() const = 0; + +public slots: + virtual void start() = 0; + +signals: + void starting(); + void finished(); + void invalidated(); +}; + +class DefaultDebuggerLauncher : public AbstractDebuggerLauncher +{ + Q_OBJECT +public: + explicit DefaultDebuggerLauncher(const Debugger & debugger, DebuggerManager *parent = 0); + virtual QString name() const; + +public slots: + virtual void start(); + +private slots: + void onProcessFinished(); + +private: + const Debugger m_debugger; + DetachedProcessMonitor *m_monitor; +}; + +#if 0 +class TerminalDebuggerLauncher : public DefaultDebuggerLauncher +{ + Q_OBJECT +public: + explicit TerminalDebuggerLauncher(const Debugger & debugger, DebuggerManager *parent = 0); + +public slots: + virtual void start(); +}; +#endif + +class DBusOldInterfaceAdaptor; + +/** This class handles the old drkonqi dbus interface used by kdevelop */ +class DBusOldInterfaceLauncher : public AbstractDebuggerLauncher +{ + Q_OBJECT + friend class DBusOldInterfaceAdaptor; +public: + explicit DBusOldInterfaceLauncher(DebuggerManager *parent = 0); + virtual QString name() const; + +public slots: + virtual void start(); + +signals: + void available(); + +private: + QString m_name; + DBusOldInterfaceAdaptor *m_adaptor; +}; + +class DBusOldInterfaceAdaptor : public QDBusAbstractAdaptor +{ + Q_OBJECT + Q_CLASSINFO("D-Bus Interface", "org.kde.Krash") + friend class DBusOldInterfaceLauncher; +public: + explicit DBusOldInterfaceAdaptor(DBusOldInterfaceLauncher *parent); + +public slots: + int pid(); + Q_NOREPLY void registerDebuggingApplication(const QString & name); + +signals: + void acceptDebuggingApplication(); +}; + +#endif // DEBUGGERLAUNCHERS_H diff --git a/drkonqi/debuggermanager.cpp b/drkonqi/debuggermanager.cpp new file mode 100644 index 00000000..11cd4dbe --- /dev/null +++ b/drkonqi/debuggermanager.cpp @@ -0,0 +1,139 @@ +/* + Copyright (C) 2009 George Kiagiadakis + + 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, see . +*/ +#include "debuggermanager.h" + +#include +#include + +#include "debugger.h" +#include "debuggerlaunchers.h" +#include "backtracegenerator.h" + +struct DebuggerManager::Private +{ + BacktraceGenerator *btGenerator; + bool debuggerRunning; + QList externalDebuggers; + DBusOldInterfaceLauncher *dbusOldInterfaceLauncher; +}; + +DebuggerManager::DebuggerManager(const Debugger & internalDebugger, + const QList & externalDebuggers, + QObject *parent) + : QObject(parent), d(new Private) +{ + d->debuggerRunning = false; + d->btGenerator = new BacktraceGenerator(internalDebugger, this); + connect(d->btGenerator, SIGNAL(starting()), SLOT(onDebuggerStarting())); + connect(d->btGenerator, SIGNAL(done()), SLOT(onDebuggerFinished())); + connect(d->btGenerator, SIGNAL(someError()), SLOT(onDebuggerFinished())); + connect(d->btGenerator, SIGNAL(failedToStart()), SLOT(onDebuggerFinished())); + + foreach(const Debugger & debugger, externalDebuggers) { + if (debugger.isInstalled()) { + AbstractDebuggerLauncher *l = new DefaultDebuggerLauncher(debugger, this); //FIXME + d->externalDebuggers.append(l); + connect(l, SIGNAL(starting()), SLOT(onDebuggerStarting())); + connect(l, SIGNAL(finished()), SLOT(onDebuggerFinished())); + connect(l, SIGNAL(invalidated()), SLOT(onDebuggerInvalidated())); + } + } + + //setup kdevelop compatibility + d->dbusOldInterfaceLauncher = new DBusOldInterfaceLauncher(this); + connect(d->dbusOldInterfaceLauncher, SIGNAL(starting()), SLOT(onDebuggerStarting())); + connect(d->dbusOldInterfaceLauncher, SIGNAL(available()), SLOT(onDBusOldInterfaceDebuggerAvailable())); +} + +DebuggerManager::~DebuggerManager() +{ + if (d->btGenerator->state() == BacktraceGenerator::Loading) { + //if the debugger is running, kill it and continue the process. + delete d->btGenerator; + onDebuggerFinished(); + } + + delete d; +} + +bool DebuggerManager::debuggerIsRunning() const +{ + return d->debuggerRunning; +} + +bool DebuggerManager::showExternalDebuggers() const +{ + KConfigGroup config(KGlobal::config(), "DrKonqi"); + bool showDebugger = config.readEntry("ShowDebugButton", false); + + // TODO: remove all these compatibility code when KDE SC 4.11 + // is considered as totally outdated + // + //for compatibility with drkonqi 1.0, if "ShowDebugButton" is not specified in the config + //and the old "ConfigName" key exists and is set to "developer", we show the debug button. + if (!config.hasKey("ShowDebugButton") && + config.readEntry("ConfigName") == "developer") { + showDebugger = true; + // migrate and remove the long deprecated entry + config.writeEntry("ShowDebugButton", true); + config.deleteEntry("ConfigName"); + } + + return showDebugger; +} + +QList DebuggerManager::availableExternalDebuggers() const +{ + return d->externalDebuggers; +} + +BacktraceGenerator* DebuggerManager::backtraceGenerator() const +{ + return d->btGenerator; +} + +void DebuggerManager::onDebuggerStarting() +{ + d->debuggerRunning = true; + emit debuggerStarting(); + emit debuggerRunning(true); +} + +void DebuggerManager::onDebuggerFinished() +{ + d->debuggerRunning = false; + emit debuggerFinished(); + emit debuggerRunning(false); +} + +void DebuggerManager::onDebuggerInvalidated() +{ + AbstractDebuggerLauncher *launcher = qobject_cast(sender()); + Q_ASSERT(launcher); + int index = d->externalDebuggers.indexOf(launcher); + Q_ASSERT(index >= 0); + d->externalDebuggers.removeAt(index); + emit externalDebuggerRemoved(launcher); +} + +void DebuggerManager::onDBusOldInterfaceDebuggerAvailable() +{ + d->externalDebuggers.append(d->dbusOldInterfaceLauncher); + emit externalDebuggerAdded(d->dbusOldInterfaceLauncher); +} + +#include "debuggermanager.moc" diff --git a/drkonqi/debuggermanager.h b/drkonqi/debuggermanager.h new file mode 100644 index 00000000..49f5c4df --- /dev/null +++ b/drkonqi/debuggermanager.h @@ -0,0 +1,58 @@ +/* + Copyright (C) 2009 George Kiagiadakis + + 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, see . +*/ +#ifndef DEBUGGERMANAGER_H +#define DEBUGGERMANAGER_H + +#include + +class BacktraceGenerator; +class Debugger; +class AbstractDebuggerLauncher; + +class DebuggerManager : public QObject +{ + Q_OBJECT +public: + DebuggerManager(const Debugger & internalDebugger, + const QList & externalDebuggers, + QObject *parent = 0); + virtual ~DebuggerManager(); + + bool debuggerIsRunning() const; + bool showExternalDebuggers() const; + QList availableExternalDebuggers() const; + BacktraceGenerator *backtraceGenerator() const; + +signals: + void debuggerStarting(); + void debuggerFinished(); + void debuggerRunning(bool running); + void externalDebuggerAdded(AbstractDebuggerLauncher *launcher); + void externalDebuggerRemoved(AbstractDebuggerLauncher *launcher); + +private slots: + void onDebuggerStarting(); + void onDebuggerFinished(); + void onDebuggerInvalidated(); + void onDBusOldInterfaceDebuggerAvailable(); + +private: + struct Private; + Private *const d; +}; + +#endif // DEBUGGERMANAGER_H diff --git a/drkonqi/debugpackageinstaller.cpp b/drkonqi/debugpackageinstaller.cpp new file mode 100644 index 00000000..86429343 --- /dev/null +++ b/drkonqi/debugpackageinstaller.cpp @@ -0,0 +1,128 @@ +/******************************************************************* +* debugpackageinstaller.cpp +* Copyright 2009 Dario Andres Rodriguez +* +* 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, see . +* +******************************************************************/ + +#include + +#include "debugpackageinstaller.h" + +#include +#include +#include +#include +#include + +#include "drkonqi.h" +#include "crashedapplication.h" + +DebugPackageInstaller::DebugPackageInstaller(QObject *parent) + : QObject(parent), m_installerProcess(0), m_progressDialog(0) +{ + m_executablePath = KStandardDirs::findExe(DEBUG_PACKAGE_INSTALLER_NAME); //defined from CMakeLists.txt +} + +bool DebugPackageInstaller::canInstallDebugPackages() const +{ + return !m_executablePath.isEmpty(); +} + +void DebugPackageInstaller::setMissingLibraries(const QStringList & libraries) +{ + m_missingLibraries = libraries; +} + +void DebugPackageInstaller::installDebugPackages() +{ + Q_ASSERT(canInstallDebugPackages()); + + if (!m_installerProcess) { + //Run process + m_installerProcess = new KProcess(this); + connect(m_installerProcess, SIGNAL(finished(int,QProcess::ExitStatus)), + this, SLOT(processFinished(int,QProcess::ExitStatus))); + + *m_installerProcess << m_executablePath + << DrKonqi::crashedApplication()->executable().absoluteFilePath() + << m_missingLibraries; + m_installerProcess->start(); + + //Show dialog + m_progressDialog = new KProgressDialog(qobject_cast(parent())); + connect(m_progressDialog, SIGNAL(cancelClicked()), this, SLOT(progressDialogCanceled())); + m_progressDialog->progressBar()->setRange(0,0); + m_progressDialog->setWindowTitle(i18nc("@title:window", "Missing debug symbols")); + m_progressDialog->setLabelText(i18nc("@info:progress", "Requesting installation of missing " + "debug symbols packages...")); + m_progressDialog->show(); + } +} + +void DebugPackageInstaller::progressDialogCanceled() +{ + m_progressDialog->deleteLater(); + m_progressDialog = 0; + + if (m_installerProcess) { + if (m_installerProcess->state() == QProcess::Running) { + disconnect(m_installerProcess, SIGNAL(finished(int,QProcess::ExitStatus)), + this, SLOT(processFinished(int,QProcess::ExitStatus))); + m_installerProcess->kill(); + disconnect(m_installerProcess, SIGNAL(finished(int,QProcess::ExitStatus)), + m_installerProcess, SLOT(deleteLater())); + } + m_installerProcess = 0; + } + + emit canceled(); +} + +void DebugPackageInstaller::processFinished(int exitCode, QProcess::ExitStatus) +{ + switch(exitCode) { + case ResultInstalled: + { + emit packagesInstalled(); + break; + } + case ResultSymbolsNotFound: + { + emit error(i18nc("@info", "Could not find debug symbol packages for this application.")); + break; + } + case ResultCanceled: + { + emit canceled(); + break; + } + case ResultError: + default: + { + emit error(i18nc("@info", "An error was encountered during the installation " + "of the debug symbol packages.")); + break; + } + } + + m_progressDialog->reject(); + + delete m_progressDialog; + m_progressDialog = 0; + + delete m_installerProcess; + m_installerProcess = 0; +} diff --git a/drkonqi/debugpackageinstaller.h b/drkonqi/debugpackageinstaller.h new file mode 100644 index 00000000..d1cdbc08 --- /dev/null +++ b/drkonqi/debugpackageinstaller.h @@ -0,0 +1,57 @@ +/******************************************************************* +* debugpackageinstaller.h +* Copyright 2009 Dario Andres Rodriguez +* +* 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, see . +* +******************************************************************/ +#ifndef DEBUGPACKAGEINSTALLER__H +#define DEBUGPACKAGEINSTALLER__H + +#include +#include + +class KProcess; +class KProgressDialog; + +class DebugPackageInstaller: public QObject +{ + Q_OBJECT + + enum Results { ResultInstalled = 0, ResultError = 1, + ResultSymbolsNotFound = 2, ResultCanceled = 3 }; + + public: + explicit DebugPackageInstaller(QObject *parent = 0); + bool canInstallDebugPackages() const; + void setMissingLibraries(const QStringList &); + void installDebugPackages(); + + private Q_SLOTS: + void processFinished(int, QProcess::ExitStatus); + void progressDialogCanceled(); + + Q_SIGNALS: + void packagesInstalled(); + void error(const QString &); + void canceled(); + + private: + KProcess * m_installerProcess; + KProgressDialog * m_progressDialog; + QString m_executablePath; + QStringList m_missingLibraries; +}; + +#endif diff --git a/drkonqi/detachedprocessmonitor.cpp b/drkonqi/detachedprocessmonitor.cpp new file mode 100644 index 00000000..214e136f --- /dev/null +++ b/drkonqi/detachedprocessmonitor.cpp @@ -0,0 +1,47 @@ +/* + Copyright (C) 2009 George Kiagiadakis + + 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, see . +*/ +#include "detachedprocessmonitor.h" + +#include + +#include + +#include + +DetachedProcessMonitor::DetachedProcessMonitor(QObject *parent) + : QObject(parent), m_pid(0) +{ +} + +void DetachedProcessMonitor::startMonitoring(int pid) +{ + m_pid = pid; + startTimer(10); +} + +void DetachedProcessMonitor::timerEvent(QTimerEvent *event) +{ + Q_ASSERT(m_pid != 0); + if (::kill(m_pid, 0) < 0) { + kDebug() << "Process" << m_pid << "finished. kill(2) returned errno:" << perror; + killTimer(event->timerId()); + m_pid = 0; + emit processFinished(); + } +} + +#include "detachedprocessmonitor.moc" diff --git a/drkonqi/detachedprocessmonitor.h b/drkonqi/detachedprocessmonitor.h new file mode 100644 index 00000000..1d8244e1 --- /dev/null +++ b/drkonqi/detachedprocessmonitor.h @@ -0,0 +1,39 @@ +/* + Copyright (C) 2009 George Kiagiadakis + + 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, see . +*/ +#ifndef DETACHEDPROCESSMONITOR_H +#define DETACHEDPROCESSMONITOR_H + +#include + +class DetachedProcessMonitor : public QObject +{ + Q_OBJECT +public: + explicit DetachedProcessMonitor(QObject *parent = 0); + void startMonitoring(int pid); + +signals: + void processFinished(); + +protected: + virtual void timerEvent(QTimerEvent *); + +private: + int m_pid; +}; + +#endif diff --git a/drkonqi/doc/debug_package_installer.txt b/drkonqi/doc/debug_package_installer.txt new file mode 100644 index 00000000..ce1178da --- /dev/null +++ b/drkonqi/doc/debug_package_installer.txt @@ -0,0 +1,86 @@ +This version of DrKonqi supports automatic installation of debug symbols packages +when it finds that debug symbols are missing. This document is to explain what is +needed from packagers to do in order to enable this functionality for their distribution. + +If your distribution does not ship packages with debug symbols you can safely ignore +the rest of this document. In this case, DrKonqi will not offer the ability to install +debug symbol packages. + +If your distribution does ship packages with debug symbols, then in order for DrKonqi +to offer the ability to install them automatically, you need to provide a script that +will do the work. This is because the packaging systems vary a lot among different +distributions and DrKonqi cannot implement distro-specific functionality in its main +code for all distributions. + +Please note that I chose to use the word "script" here having in mind a shell script, +but you may as well provide a python script, a perl script, or whatever else, even a +compiled binary written in any language you want. DrKonqi will use KProcess for +launching it, so as long as it is executable, it will work. + + +Name of the script +================== +By default DrKonqi looks for a shell script called "installdbgsymbols.sh". It expects +it to be in PATH, or somewhere that it is possible to be located by KStandardDirs::findExe(). +For example, the path where DrKonqi itself is installed (`kde4-config --path libexec`), +is a valid path to install this script, although it is not in PATH. + +If you wish to provide a script with a different name, you can change the name by setting +the cmake variable DEBUG_PACKAGE_INSTALLER_NAME to the name that you want. For example, +configuring kdebase-runtime with: + + cmake -DDEBUG_PACKAGE_INSTALLER_NAME="installdbgsymbols.py" + +will use "installdbgsymbols.py" as the script for installing debug packages. + + +Interface of the script +======================= + +1. Arguments +------------ +The script is called with arguments all the filenames of the binaries that are clearly +missing symbols. The first argument (argv[1]) is always supplied and is the path to +the executable that crashed itself. The rest of the arguments are optional and are filenames +of libraries that are missing symbols (for example, "/usr/lib/libkio.so.5"). All the +paths are absolute, but they will probably point to symlinks (at least for libraries). +The paths are taken from gdb. For each stack frame that is missing details, if gdb can +tell where is this symbol from, the path to the library that gdb specifies is passed +as is to the script. Note that for applications that were launched via kdeinit, argv[1] +is the path to kdeinit4, not the path to the executable that would be launched if there +was no kdeinit involved. + +2. Return values +---------------- +0 - Debug packages installed successfully +1 - Some kind of error was encountered +2 - Debug symbols not found +3 - User canceled the operation + + +Testing +======= +In order to test your script you can try the following: +1) Find a kde application and remove its debug symbols package. I will use konqueror + in this example. +2) Run the application and then kill it with a signal that drkonqi can catch. + For example, "killall -6 konqueror". +3) In drkonqi's main dialog, switch to the "Backtrace" tab and wait for it to + generate a backtrace. +4) After the backtrace has been generated, if drkonqi can find your script, a button + saying "Install debug symbols" will appear in the bottom left side of the backtrace tab. +5) Click on it and your script will be launched. + + +Examples +======== +I have written example scripts for Debian, OpenSuSE and Fedora, which are available +in the examples/ subdirectory of the drkonqi source code directory. These were +developed as a proof of concept, to test that this script model and interface will +work for most distributions. You may use them as is, or you may use them as references +to write your own scripts. Just note that I am not going to maintain those scripts +or fix bugs in them. + +-- +George Kiagiadakis +Last updated: 25 Semptember 2009 diff --git a/drkonqi/doc/examples/installdbgsymbols_debian.sh b/drkonqi/doc/examples/installdbgsymbols_debian.sh new file mode 100644 index 00000000..e1eaa552 --- /dev/null +++ b/drkonqi/doc/examples/installdbgsymbols_debian.sh @@ -0,0 +1,151 @@ +#!/bin/sh +# +# Copyright (C) 2009 George Kiagiadakis +# +# 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, see . + + +# This function runs a command in a terminal +# The first argument ($1) must be the full command to run. +# It returns 0 if the command finished or 1 if the user closed +# the terminal without waiting for the command to finish. +# The return value of the command is saved in the $exit_status variable. +run_in_terminal() +{ + local fifo=/tmp/drkonqi-fifo-$$ + mkfifo $fifo + + # start terminal + x-terminal-emulator -e sh -c "echo \$\$ > $fifo; $1; exit_status=\$?; sleep 1; rm $fifo; echo \$exit_status > $fifo" & + + # wait for it to finish + local pid=`cat $fifo` + while [ "$?" = "0" ]; do + sleep 1 + kill -0 $pid 2>/dev/null + done + + # check if terminal has finished succesfully and return the command's exit status + local canceled=0 + if [ -p $fifo ]; then + # terminal was closed before finishing execution + canceled=1 + else + exit_status=`cat $fifo` + #echo "\"$1\" returned: $exit_status" + fi + rm $fifo + return $canceled +} + +# check for availability of kdialog +which kdialog >/dev/null +if [ "$?" != "0" ]; then + xmessage -center "Could not find kdialog (part of kdebase). Please install kdialog and try again." + exit 1 +fi + +# check misc script dependencies +check_dep() +{ + which $1 >/dev/null + if [ "$?" != "0" ]; then + kdialog --sorry "$1 was not found on your system. Please install $1 and try again." + exit 1 + fi +} + +check_dep apt-file +check_dep qdbus + +# update apt-file database +run_in_terminal "apt-file update" + +if [ "$?" = "1" ]; then + exit 3 +elif [ "$exit_status" != "0" ]; then + kdialog --sorry "apt-file failed to update package lists." + exit 1 +fi + +# start searching for packages +packages="" +progress_counter=0 +dbus_handle=`kdialog --progressbar "Searching for packages that contain the requested debug symbols..." $#` + +while [ "$1" != "" ]; +do + # dereference symlinks + cur_file=$1 + while [ -L "$cur_file" ]; do + cur_file="`dirname $cur_file`/`ls -l $cur_file | cut -d ' ' -f 10`" + done + + # look for the package + expr match "$cur_file" ".*libQt.*" >/dev/null + if [ "$?" = "0" ]; then + # HACK for Qt, which doesn't install debug symbols in /usr/lib/debug like everybody else + package="libqt4-dbg" + else + package=`apt-file search --non-interactive --package-only --fixed-string "/usr/lib/debug$cur_file"` + fi + packages="$packages $package" + + # update progress dialog + progress_counter=$(($progress_counter+1)) + qdbus $dbus_handle Set org.kde.kdialog.ProgressDialog value $progress_counter + + # check if dialog was closed + if [ "$?" != "0" ]; then + exit 3 + fi + + shift +done + +# filter out duplicates +packages=`echo "$packages" | tr " " "\n" | sort | uniq | tr "\n" " "` + +# close the progress dialog +qdbus $dbus_handle close + +# if there are no packages to install, exit +trimmed_packages=`echo $packages | tr -d "[:blank:]"` +if [ -z "$trimmed_packages" ]; then + exit 2 # note that we don't need to display an error message here. drkonqi will do it for us. +fi + +kdialog --yesno "You need to install the following packages: $packages +Would you like drkonqi to attempt to install them now?" + +if [ "$?" = "0" ]; then + # determine package manager + package_manager=aptitude + which $package_manager >/dev/null + if [ "$?" != "0" ]; then + package_manager=apt-get + fi + + run_in_terminal "su-to-root -c '$package_manager install $packages'" + + if [ "$?" = "1" ]; then + exit 3 + elif [ "$exit_status" = "0" ]; then + exit 0 + else + exit 1 + fi +else + exit 3 +fi diff --git a/drkonqi/doc/examples/installdbgsymbols_fedora.sh b/drkonqi/doc/examples/installdbgsymbols_fedora.sh new file mode 100644 index 00000000..4a1254ab --- /dev/null +++ b/drkonqi/doc/examples/installdbgsymbols_fedora.sh @@ -0,0 +1,91 @@ +#!/bin/sh +# +# Copyright (C) 2009 George Kiagiadakis +# +# 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, see . + + +# This function runs a command in a terminal +# The first argument ($1) must be the full command to run. +# It returns 0 if the command finished or 1 if the user closed +# the terminal without waiting for the command to finish. +# The return value of the command is saved in the $exit_status variable. +run_in_terminal() +{ + local fifo=/tmp/drkonqi-fifo-$$ + mkfifo $fifo + + # start terminal + konsole -e sh -c "echo \$\$ > $fifo; $1; exit_status=\$?; sleep 1; rm $fifo; echo \$exit_status > $fifo" & + + # wait for it to finish + local pid=`cat $fifo` + while [ "$?" = "0" ]; do + sleep 1 + kill -0 $pid 2>/dev/null + done + + # check if terminal has finished succesfully and return the command's exit status + local canceled=0 + if [ -p $fifo ]; then + # terminal was closed before finishing execution + canceled=1 + else + exit_status=`cat $fifo` + #echo "\"$1\" returned: $exit_status" + fi + rm $fifo + return $canceled +} + +# check misc script dependencies +check_dep() +{ + which $1 >/dev/null + if [ "$?" != "0" ]; then + # check for availability of kdialog + which kdialog >/dev/null + if [ "$?" != "0" ]; then + xmessage -center "$1 was not found on your system. Please install $1 and try again." + else + kdialog --sorry "$1 was not found on your system. Please install $1 and try again." + fi + exit 1 + fi +} + +check_dep debuginfo-install +check_dep konsole + +# start searching for packages +packages="" +while [ "$1" != "" ]; +do + package=`rpm -q --whatprovides "$1" --queryformat "%{NAME}"` + packages="$packages $package" + shift +done + +# filter out duplicates +packages=`echo "$packages" | tr " " "\n" | sort | uniq | tr "\n" " "` + +run_in_terminal "su -c \"debuginfo-install $packages\"" + +if [ "$?" = "1" ]; then + exit 3 +elif [ "$exit_status" = "0" ]; then + exit 0 +else + exit 1 +fi diff --git a/drkonqi/doc/examples/installdbgsymbols_suse.sh b/drkonqi/doc/examples/installdbgsymbols_suse.sh new file mode 100644 index 00000000..dbc7468f --- /dev/null +++ b/drkonqi/doc/examples/installdbgsymbols_suse.sh @@ -0,0 +1,94 @@ +#!/bin/sh +# +# Copyright (C) 2009 George Kiagiadakis +# +# 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, see . + + +# This function runs a command in a terminal +# The first argument ($1) must be the full command to run. +# It returns 0 if the command finished or 1 if the user closed +# the terminal without waiting for the command to finish. +# The return value of the command is saved in the $exit_status variable. +run_in_terminal() +{ + local fifo=/tmp/drkonqi-fifo-$$ + mkfifo $fifo + + # start terminal + konsole -e sh -c "echo \$\$ > $fifo; $1; exit_status=\$?; sleep 1; rm $fifo; echo \$exit_status > $fifo" & + + # wait for it to finish + local pid=`cat $fifo` + while [ "$?" = "0" ]; do + sleep 1 + kill -0 $pid 2>/dev/null + done + + # check if terminal has finished succesfully and return the command's exit status + local canceled=0 + if [ -p $fifo ]; then + # terminal was closed before finishing execution + canceled=1 + else + exit_status=`cat $fifo` + #echo "\"$1\" returned: $exit_status" + fi + rm $fifo + return $canceled +} + +# check misc script dependencies +check_dep() +{ + which $1 >/dev/null + if [ "$?" != "0" ]; then + # check for availability of kdialog + which kdialog >/dev/null + if [ "$?" != "0" ]; then + xmessage -center "$1 was not found on your system. Please install $1 and try again." + else + kdialog --sorry "$1 was not found on your system. Please install $1 and try again." + fi + exit 1 + fi +} + +check_dep pbuildid +check_dep konsole + +# start searching for packages +packages="" +while [ "$1" != "" ]; +do + # look for the build id + file -L "$1" | grep ELF >/dev/null + if [ "$?" = "0" ]; then + buildid=`pbuildid "$1" | cut -d ' ' -f 2` + package="\"debuginfo(build-id)=$buildid\"" + packages="$packages $package" + fi + + shift +done + +run_in_terminal "sudo zypper install -C $packages" + +if [ "$?" = "1" ]; then + exit 3 +elif [ "$exit_status" = "0" ]; then + exit 0 +else + exit 1 +fi diff --git a/drkonqi/drkonqi-rename-config-section.upd b/drkonqi/drkonqi-rename-config-section.upd new file mode 100644 index 00000000..413908f7 --- /dev/null +++ b/drkonqi/drkonqi-rename-config-section.upd @@ -0,0 +1,5 @@ +# the [drkonqi] section has been renamed to "[DrKonqi]" +Id=kde-4.11 +File=drkonqirc +Group=drkonqi, DrKonqi +AllKeys diff --git a/drkonqi/drkonqi.cpp b/drkonqi/drkonqi.cpp new file mode 100644 index 00000000..7be87d74 --- /dev/null +++ b/drkonqi/drkonqi.cpp @@ -0,0 +1,197 @@ +/* + Copyright (C) 2009 George Kiagiadakis + + 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, see . + + Parts of this code were originally under the following license: + + * Copyright (C) 2000-2003 Hans Petter Bieker + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +#include "drkonqi.h" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "systeminformation.h" +#include "crashedapplication.h" +#include "drkonqibackends.h" + +DrKonqi::DrKonqi() +{ + m_backend = new KCrashBackend(); + m_systemInformation = new SystemInformation(); +} + +DrKonqi::~DrKonqi() +{ + delete m_systemInformation; + delete m_backend; +} + +//static +DrKonqi *DrKonqi::instance() +{ + static DrKonqi *drKonqiInstance = NULL; + if (!drKonqiInstance) { + drKonqiInstance = new DrKonqi(); + } + return drKonqiInstance; +} + +//based on KCrashDelaySetHandler from kdeui/util/kcrash.cpp +class EnableCrashCatchingDelayed : public QObject +{ +public: + EnableCrashCatchingDelayed() { + startTimer(10000); // 10 s + } +protected: + void timerEvent(QTimerEvent *event) { + kDebug() << "Enabling drkonqi crash catching"; + KCrash::setDrKonqiEnabled(true); + killTimer(event->timerId()); + this->deleteLater(); + } +}; + +bool DrKonqi::init() +{ + if (!instance()->m_backend->init()) { + cleanup(); + return false; + } else { //all ok, continue initialization + // Set drkonqi to handle its own crashes, but only if the crashed app + // is not drkonqi already. If it is drkonqi, delay enabling crash catching + // to prevent recursive crashes (in case it crashes at startup) + if (crashedApplication()->fakeExecutableBaseName() != "drkonqi") { + kDebug() << "Enabling drkonqi crash catching"; + KCrash::setDrKonqiEnabled(true); + } else { + new EnableCrashCatchingDelayed; + } + return true; + } +} + +void DrKonqi::cleanup() +{ + delete instance(); +} + +//static +SystemInformation *DrKonqi::systemInformation() +{ + return instance()->m_systemInformation; +} + +//static +DebuggerManager* DrKonqi::debuggerManager() +{ + return instance()->m_backend->debuggerManager(); +} + +//static +CrashedApplication *DrKonqi::crashedApplication() +{ + return instance()->m_backend->crashedApplication(); +} + +//static +void DrKonqi::saveReport(const QString & reportText, QWidget *parent) +{ + if (KCmdLineArgs::parsedArgs()->isSet("safer")) { + KTemporaryFile tf; + tf.setSuffix(".kcrash.txt"); + tf.setAutoRemove(false); + + if (tf.open()) { + QTextStream textStream(&tf); + textStream << reportText; + textStream.flush(); + KMessageBox::information(parent, i18nc("@info", + "Report saved to %1.", + tf.fileName())); + } else { + KMessageBox::sorry(parent, i18nc("@info","Could not create a file in which to save the report.")); + } + } else { + QString defname = getSuggestedKCrashFilename(crashedApplication()); + + QWeakPointer dlg = new KFileDialog(defname, QString(), parent); + dlg.data()->setSelection(defname); + dlg.data()->setCaption(i18nc("@title:window","Select Filename")); + dlg.data()->setOperationMode(KFileDialog::Saving); + dlg.data()->setMode(KFile::File); + dlg.data()->setConfirmOverwrite(true); + dlg.data()->exec(); + + if (dlg.isNull()) { + //Dialog is invalid, it was probably deleted (ex. via DBus call) + //return and do not crash + return; + } + + KUrl fileUrl = dlg.data()->selectedUrl(); + delete dlg.data(); + + if (fileUrl.isValid()) { + KTemporaryFile tf; + if (tf.open()) { + QTextStream ts(&tf); + ts << reportText; + ts.flush(); + } else { + KMessageBox::sorry(parent, i18nc("@info","Cannot open file %1 " + "for writing.", tf.fileName())); + return; + } + + if (!KIO::NetAccess::upload(tf.fileName(), fileUrl, parent)) { + KMessageBox::sorry(parent, KIO::NetAccess::lastErrorString()); + } + } + } +} + diff --git a/drkonqi/drkonqi.h b/drkonqi/drkonqi.h new file mode 100644 index 00000000..95e64dc3 --- /dev/null +++ b/drkonqi/drkonqi.h @@ -0,0 +1,49 @@ +/* + Copyright (C) 2009 George Kiagiadakis + + 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, see . +*/ +#ifndef DRKONQI_H +#define DRKONQI_H + +class QString; +class QWidget; + +class SystemInformation; +class DebuggerManager; +class CrashedApplication; +class AbstractDrKonqiBackend; + +class DrKonqi +{ +public: + static bool init(); + static void cleanup(); + + static SystemInformation *systemInformation(); + static DebuggerManager *debuggerManager(); + static CrashedApplication *crashedApplication(); + + static void saveReport(const QString & reportText, QWidget *parent = 0); + +private: + DrKonqi(); + ~DrKonqi(); + static DrKonqi *instance(); + + SystemInformation *m_systemInformation; + AbstractDrKonqiBackend *m_backend; +}; + +#endif diff --git a/drkonqi/drkonqi_globals.h b/drkonqi/drkonqi_globals.h new file mode 100644 index 00000000..d5f098a8 --- /dev/null +++ b/drkonqi/drkonqi_globals.h @@ -0,0 +1,52 @@ +/* + Copyright (C) 2009 George Kiagiadakis + + 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, see . +*/ +#ifndef DRKONQI_GLOBALS_H +#define DRKONQI_GLOBALS_H + +#include +#include + +/** This class provides a custom constructor to fill the "toolTip" + * and "whatsThis" texts of KGuiItem with the same text. + */ +class KGuiItem2 : public KGuiItem +{ +public: + inline KGuiItem2(const QString &text, const KIcon &icon, const QString &toolTip) + : KGuiItem(text, icon, toolTip, toolTip) {} +}; + +/* Urls are defined globally here, so that they can change easily */ +#define KDE_BUGZILLA_URL "https://bugs.kde.org/" +#define KDE_BUGZILLA_CREATE_ACCOUNT_URL KDE_BUGZILLA_URL "createaccount.cgi" +#define KDE_BUGZILLA_SHORT_URL "bugs.kde.org" +#define TECHBASE_HOWTO_DOC "http://techbase.kde.org/Development/Tutorials/Debugging/How_to_create_useful_crash_reports#Preparing_your_KDE_packages" + +/* IDs for bugreport assistant pages -> help anchors */ +#define PAGE_INTRODUCTION_ID "IntroductionID" +#define PAGE_CRASHINFORMATION_ID "BacktraceID" +#define PAGE_AWARENESS_ID "AwarenessID" +#define PAGE_CONCLUSIONS_ID "ConclusionsID" +#define PAGE_BZLOGIN_ID "BugzillaLoginID" +#define PAGE_BZDUPLICATES_ID "BugzillaDuplicatesID" +#define PAGE_BZDETAILS_ID "BugzillaDetailsID" +#define PAGE_BZPREVIEW_ID "BugzillaPreviewID" +#define PAGE_BZSEND_ID "BugzillaSendID" + +#define PAGE_HELP_BEGIN_ID "Begin" + +#endif diff --git a/drkonqi/drkonqibackends.cpp b/drkonqi/drkonqibackends.cpp new file mode 100644 index 00000000..064d07d4 --- /dev/null +++ b/drkonqi/drkonqibackends.cpp @@ -0,0 +1,243 @@ +/* + Copyright (C) 2009 George Kiagiadakis + + 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, see . +*/ +#include "drkonqibackends.h" + +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "crashedapplication.h" +#include "debugger.h" +#include "debuggermanager.h" +#include "backtracegenerator.h" + +AbstractDrKonqiBackend::~AbstractDrKonqiBackend() +{ +} + +bool AbstractDrKonqiBackend::init() +{ + m_crashedApplication = constructCrashedApplication(); + m_debuggerManager = constructDebuggerManager(); + return true; +} + + +KCrashBackend::KCrashBackend() + : QObject(), AbstractDrKonqiBackend(), m_state(ProcessRunning) +{ +} + +KCrashBackend::~KCrashBackend() +{ + continueAttachedProcess(); +} + +bool KCrashBackend::init() +{ + AbstractDrKonqiBackend::init(); + + QString startupId(KCmdLineArgs::parsedArgs()->getOption("startupid")); + if (!startupId.isEmpty()) { // stop startup notification + KStartupInfoId id; + id.initId(startupId.toLocal8Bit()); + KStartupInfo::sendFinish(id); + } + + //check whether the attached process exists and whether we have permissions to inspect it + if (crashedApplication()->pid() <= 0) { + kError() << "Invalid pid specified"; + return false; + } + +#if !defined(Q_OS_WIN32) + if (::kill(crashedApplication()->pid(), 0) < 0) { + switch (errno) { + case EPERM: + kError() << "DrKonqi doesn't have permissions to inspect the specified process"; + break; + case ESRCH: + kError() << "The specified process does not exist."; + break; + default: + break; + } + return false; + } + + //--keeprunning means: generate backtrace instantly and let the process continue execution + if(KCmdLineArgs::parsedArgs()->isSet("keeprunning")) { + stopAttachedProcess(); + debuggerManager()->backtraceGenerator()->start(); + connect(debuggerManager(), SIGNAL(debuggerFinished()), SLOT(continueAttachedProcess())); + } else { + connect(debuggerManager(), SIGNAL(debuggerStarting()), SLOT(onDebuggerStarting())); + connect(debuggerManager(), SIGNAL(debuggerFinished()), SLOT(onDebuggerFinished())); + + //stop the process to avoid high cpu usage by other threads (bug 175362). + //if the process was started by kdeinit, we need to wait a bit for KCrash + //to reach the alarm(0); call in kdeui/util/kcrash.cpp line 406 or else + //if we stop it before this call, pending alarm signals will kill the + //process when we try to continue it. + QTimer::singleShot(2000, this, SLOT(stopAttachedProcess())); + } +#endif + + //Handle drkonqi crashes + s_pid = crashedApplication()->pid(); //copy pid for use by the crash handler, so that it is safer + KCrash::setEmergencySaveFunction(emergencySaveFunction); + + return true; +} + +CrashedApplication *KCrashBackend::constructCrashedApplication() +{ + CrashedApplication *a = new CrashedApplication(this); + a->m_datetime = QDateTime::currentDateTime(); + KCmdLineArgs *args = KCmdLineArgs::parsedArgs(); + a->m_name = args->getOption("programname"); + a->m_version = args->getOption("appversion").toUtf8(); + a->m_reportAddress = BugReportAddress(args->getOption("bugaddress").toUtf8()); + a->m_pid = args->getOption("pid").toInt(); + a->m_signalNumber = args->getOption("signal").toInt(); + a->m_restarted = args->isSet("restarted"); + a->m_thread = args->getOption("thread").toInt(); + + //try to determine the executable that crashed + if ( QFileInfo(QString("/proc/%1/exe").arg(a->m_pid)).exists() ) { + //on linux, the fastest and most reliable way is to get the path from /proc + kDebug() << "Using /proc to determine executable path"; + a->m_executable.setFile(QFile::symLinkTarget(QString("/proc/%1/exe").arg(a->m_pid))); + + if (args->isSet("kdeinit") || + a->m_executable.fileName().startsWith("python") ) { + + a->m_fakeBaseName = args->getOption("appname"); + } + } else { + if ( args->isSet("kdeinit") ) { + a->m_executable = QFileInfo(KStandardDirs::findExe("kdeinit4")); + a->m_fakeBaseName = args->getOption("appname"); + } else { + QFileInfo execPath(args->getOption("appname")); + if ( execPath.isAbsolute() ) { + a->m_executable = execPath; + } else if ( !args->getOption("apppath").isEmpty() ) { + QDir execDir(args->getOption("apppath")); + a->m_executable = execDir.absoluteFilePath(execPath.fileName()); + } else { + a->m_executable = QFileInfo(KStandardDirs::findExe(execPath.fileName())); + } + } + } + + kDebug() << "Executable is:" << a->m_executable.absoluteFilePath(); + kDebug() << "Executable exists:" << a->m_executable.exists(); + + return a; +} + +DebuggerManager *KCrashBackend::constructDebuggerManager() +{ + QList internalDebuggers = Debugger::availableInternalDebuggers("KCrash"); + KConfigGroup config(KGlobal::config(), "DrKonqi"); +#ifndef Q_OS_WIN + QString defaultDebuggerName = config.readEntry("Debugger", QString("gdb")); +#else + QString defaultDebuggerName = config.readEntry("Debugger", QString("kdbgwin")); +#endif + + Debugger firstKnownGoodDebugger, preferredDebugger; + foreach (const Debugger & debugger, internalDebuggers) { + if (!firstKnownGoodDebugger.isValid() && debugger.isInstalled()) { + firstKnownGoodDebugger = debugger; + } + if (debugger.codeName() == defaultDebuggerName) { + preferredDebugger = debugger; + } + if (firstKnownGoodDebugger.isValid() && preferredDebugger.isValid()) { + break; + } + } + + if (!preferredDebugger.isInstalled()) { + if (firstKnownGoodDebugger.isValid()) { + preferredDebugger = firstKnownGoodDebugger; + } else { + kError() << "Unable to find an internal debugger that can work with the KCrash backend"; + } + } + + return new DebuggerManager(preferredDebugger, Debugger::availableExternalDebuggers("KCrash"), this); +} + +void KCrashBackend::stopAttachedProcess() +{ + if (m_state == ProcessRunning) { + kDebug() << "Sending SIGSTOP to process"; + ::kill(crashedApplication()->pid(), SIGSTOP); + m_state = ProcessStopped; + } +} + +void KCrashBackend::continueAttachedProcess() +{ + if (m_state == ProcessStopped) { + kDebug() << "Sending SIGCONT to process"; + ::kill(crashedApplication()->pid(), SIGCONT); + m_state = ProcessRunning; + } +} + +void KCrashBackend::onDebuggerStarting() +{ + continueAttachedProcess(); + m_state = DebuggerRunning; +} + +void KCrashBackend::onDebuggerFinished() +{ + m_state = ProcessRunning; + stopAttachedProcess(); +} + +//static +qint64 KCrashBackend::s_pid = 0; + +//static +void KCrashBackend::emergencySaveFunction(int signal) +{ + // In case drkonqi itself crashes, we need to get rid of the process being debugged, + // so we kill it, no matter what its state was. + Q_UNUSED(signal); + ::kill(s_pid, SIGKILL); +} + +#include "drkonqibackends.moc" diff --git a/drkonqi/drkonqibackends.h b/drkonqi/drkonqibackends.h new file mode 100644 index 00000000..99b8a523 --- /dev/null +++ b/drkonqi/drkonqibackends.h @@ -0,0 +1,74 @@ +/* + Copyright (C) 2009 George Kiagiadakis + + 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, see . +*/ +#ifndef DRKONQIBACKENDS_H +#define DRKONQIBACKENDS_H + +#include + +class CrashedApplication; +class DebuggerManager; + +class AbstractDrKonqiBackend +{ +public: + virtual ~AbstractDrKonqiBackend(); + virtual bool init(); + + inline CrashedApplication *crashedApplication() const { + return m_crashedApplication; + } + + inline DebuggerManager *debuggerManager() const { + return m_debuggerManager; + } + +protected: + virtual CrashedApplication *constructCrashedApplication() = 0; + virtual DebuggerManager *constructDebuggerManager() = 0; + +private: + CrashedApplication *m_crashedApplication; + DebuggerManager *m_debuggerManager; +}; + +class KCrashBackend : public QObject, public AbstractDrKonqiBackend +{ + Q_OBJECT +public: + KCrashBackend(); + virtual ~KCrashBackend(); + virtual bool init(); + +protected: + virtual CrashedApplication *constructCrashedApplication(); + virtual DebuggerManager *constructDebuggerManager(); + +private slots: + void stopAttachedProcess(); + void continueAttachedProcess(); + void onDebuggerStarting(); + void onDebuggerFinished(); + +private: + static void emergencySaveFunction(int signal); + static qint64 s_pid; //for use by the emergencySaveFunction + + enum State { ProcessRunning, ProcessStopped, DebuggerRunning }; + State m_state; +}; + +#endif // DRKONQIBACKENDS_H diff --git a/drkonqi/drkonqidialog.cpp b/drkonqi/drkonqidialog.cpp new file mode 100644 index 00000000..0ea39319 --- /dev/null +++ b/drkonqi/drkonqidialog.cpp @@ -0,0 +1,284 @@ +/******************************************************************* +* drkonqidialog.cpp +* Copyright 2009 Dario Andres Rodriguez +* +* 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, see . +* +******************************************************************/ + +#include "drkonqidialog.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "drkonqi.h" +#include "backtracewidget.h" +#include "reportassistantdialog.h" +#include "aboutbugreportingdialog.h" +#include "crashedapplication.h" +#include "debuggermanager.h" +#include "debuggerlaunchers.h" +#include "drkonqi_globals.h" + +static const char ABOUT_BUG_REPORTING_URL[] = "#aboutbugreporting"; +static const char DRKONQI_REPORT_BUG_URL[] = + KDE_BUGZILLA_URL "enter_bug.cgi?product=drkonqi&format=guided"; + +DrKonqiDialog::DrKonqiDialog(QWidget * parent) : + KDialog(parent), + m_aboutBugReportingDialog(0), + m_backtraceWidget(0) +{ + KGlobal::ref(); + setAttribute(Qt::WA_DeleteOnClose, true); + + //Setting dialog title and icon + setCaption(DrKonqi::crashedApplication()->name()); + setWindowIcon(KIcon("tools-report-bug")); + + m_tabWidget = new KTabWidget(this); + setMainWidget(m_tabWidget); + + connect(m_tabWidget, SIGNAL(currentChanged(int)), this, SLOT(tabIndexChanged(int))); + + buildIntroWidget(); + m_tabWidget->addTab(m_introWidget, i18nc("@title:tab general information", "&General")); + + m_backtraceWidget = new BacktraceWidget(DrKonqi::debuggerManager()->backtraceGenerator(), this); + m_backtraceWidget->setMinimumSize(QSize(575, 240)); + m_tabWidget->addTab(m_backtraceWidget, i18nc("@title:tab", "&Developer Information")); + + buildDialogButtons(); + + setMinimumSize(QSize(640,320)); + resize(minimumSize()); + KConfigGroup config(KGlobal::config(), "General"); + restoreDialogSize(config); +} + +DrKonqiDialog::~DrKonqiDialog() +{ + KConfigGroup config(KGlobal::config(), "General"); + saveDialogSize(config); + + KGlobal::deref(); +} + +void DrKonqiDialog::tabIndexChanged(int index) +{ + if (index == m_tabWidget->indexOf(m_backtraceWidget)) { + m_backtraceWidget->generateBacktrace(); + } +} + +void DrKonqiDialog::buildIntroWidget() +{ + const CrashedApplication *crashedApp = DrKonqi::crashedApplication(); + + m_introWidget = new QWidget(this); + ui.setupUi(m_introWidget); + + ui.titleLabel->setText(i18nc("@info", "We are sorry, %1 " + "closed unexpectedly.", crashedApp->name())); + + QString reportMessage; + if (!crashedApp->bugReportAddress().isEmpty()) { + if (crashedApp->fakeExecutableBaseName() == QLatin1String("drkonqi")) { //Handle own crashes + reportMessage = i18nc("@info", "As the Crash Handler itself has failed, the " + "automatic reporting process is disabled to reduce the " + "risks of failing again." + "Please, manually report this error " + "to the KDE bug tracking system. Do not forget to include " + "the backtrace from the Developer Information " + "tab.", + QLatin1String(DRKONQI_REPORT_BUG_URL)); + } else if (KCmdLineArgs::parsedArgs()->isSet("safer")) { + reportMessage = i18nc("@info", "The reporting assistant is disabled because " + "the crash handler dialog was started in safe mode." + "You can manually report this bug to %1 " + "(including the backtrace from the " + "Developer Information " + "tab.)", crashedApp->bugReportAddress()); + } else { + reportMessage = i18nc("@info", "You can help us improve KDE Software by reporting " + "this error.Learn " + "more about bug reporting.It is " + "safe to close this dialog if you do not want to report " + "this bug.", + QLatin1String(ABOUT_BUG_REPORTING_URL) + ); + } + } else { + reportMessage = i18nc("@info", "You cannot report this error, because " + "%1 does not provide a bug reporting " + "address.", + crashedApp->name() + ); + } + ui.infoLabel->setText(reportMessage); + connect(ui.infoLabel, SIGNAL(linkActivated(QString)), this, SLOT(linkActivated(QString))); + + ui.iconLabel->setPixmap( + QPixmap(KStandardDirs::locate("appdata", QLatin1String("pics/crash.png")))); + + ui.detailsTitleLabel->setText(QString("%1").arg(i18nc("@label","Details:"))); + + ui.detailsLabel->setText(i18nc("@info Note the time information is divided into date and time parts", + "Executable: %1" + " PID: %2 Signal: %3 (%4) " + "Time: %5 %6", + crashedApp->fakeExecutableBaseName(), + crashedApp->pid(), + crashedApp->signalName(), + #if defined(Q_OS_UNIX) + crashedApp->signalNumber(), + #else + //windows uses weird big numbers for exception codes, + //so it doesn't make sense to display them in decimal + QString().sprintf("0x%8x", crashedApp->signalNumber()), + #endif + KGlobal::locale()->formatDate(crashedApp->datetime().date(), KLocale::ShortDate), + + KGlobal::locale()->formatTime(crashedApp->datetime().time(), true) + )); +} + +void DrKonqiDialog::buildDialogButtons() +{ + const CrashedApplication *crashedApp = DrKonqi::crashedApplication(); + + //Set kdialog buttons + setButtons(KDialog::User3 | KDialog::User2 | KDialog::User1 | KDialog::Close); + + //Report bug button + setButtonGuiItem(KDialog::User1, KGuiItem2(i18nc("@action:button", "Report &Bug"), + KIcon("tools-report-bug"), + i18nc("@info:tooltip", + "Starts the bug report assistant."))); + + bool enableReportAssistant = !crashedApp->bugReportAddress().isEmpty() && + crashedApp->fakeExecutableBaseName() != QLatin1String("drkonqi") && + !KCmdLineArgs::parsedArgs()->isSet("safer"); + enableButton(KDialog::User1, enableReportAssistant); + connect(this, SIGNAL(user1Clicked()), this, SLOT(startBugReportAssistant())); + + //Default debugger button and menu (only for developer mode) + DebuggerManager *debuggerManager = DrKonqi::debuggerManager(); + setButtonGuiItem(KDialog::User2, KGuiItem2(i18nc("@action:button this is the debug menu button " + "label which contains the debugging applications", + "&Debug"), KIcon("applications-development"), + i18nc("@info:tooltip", "Starts a program to debug " + "the crashed application."))); + showButton(KDialog::User2, debuggerManager->showExternalDebuggers()); + + m_debugMenu = new KMenu(this); + setButtonMenu(KDialog::User2, m_debugMenu); + + QList debuggers = debuggerManager->availableExternalDebuggers(); + foreach(AbstractDebuggerLauncher *launcher, debuggers) { + addDebugger(launcher); + } + + connect(debuggerManager, SIGNAL(externalDebuggerAdded(AbstractDebuggerLauncher*)), + SLOT(addDebugger(AbstractDebuggerLauncher*))); + connect(debuggerManager, SIGNAL(externalDebuggerRemoved(AbstractDebuggerLauncher*)), + SLOT(removeDebugger(AbstractDebuggerLauncher*))); + connect(debuggerManager, SIGNAL(debuggerRunning(bool)), SLOT(enableDebugMenu(bool))); + + //Restart application button + setButtonGuiItem(KDialog::User3, KGuiItem2(i18nc("@action:button", "&Restart Application"), + KIcon("system-reboot"), + i18nc("@info:tooltip", "Use this button to restart " + "the crashed application."))); + enableButton(KDialog::User3, !crashedApp->hasBeenRestarted() && + crashedApp->fakeExecutableBaseName() != QLatin1String("drkonqi")); + connect(this, SIGNAL(user3Clicked()), crashedApp, SLOT(restart())); + connect(crashedApp, SIGNAL(restarted(bool)), this, SLOT(applicationRestarted(bool))); + + //Close button + QString tooltipText = i18nc("@info:tooltip", + "Close this dialog (you will lose the crash information.)"); + setButtonToolTip(KDialog::Close, tooltipText); + setButtonWhatsThis(KDialog::Close, tooltipText); + setDefaultButton(KDialog::Close); + setButtonFocus(KDialog::Close); +} + +void DrKonqiDialog::addDebugger(AbstractDebuggerLauncher *launcher) +{ + QAction *action = new QAction(KIcon("applications-development"), + i18nc("@action:inmenu 1 is the debugger name", + "Debug in %1", + launcher->name()), m_debugMenu); + m_debugMenu->addAction(action); + connect(action, SIGNAL(triggered()), launcher, SLOT(start())); + m_debugMenuActions.insert(launcher, action); +} + +void DrKonqiDialog::removeDebugger(AbstractDebuggerLauncher *launcher) +{ + QAction *action = m_debugMenuActions.take(launcher); + if ( action ) { + m_debugMenu->removeAction(action); + action->deleteLater(); + } else { + kError() << "Invalid launcher"; + } +} + +void DrKonqiDialog::enableDebugMenu(bool debuggerRunning) +{ + enableButton(KDialog::User2, !debuggerRunning); +} + +void DrKonqiDialog::startBugReportAssistant() +{ + ReportAssistantDialog * bugReportAssistant = new ReportAssistantDialog(); + close(); + bugReportAssistant->show(); +} + +void DrKonqiDialog::linkActivated(const QString& link) +{ + if (link == QLatin1String(ABOUT_BUG_REPORTING_URL)) { + showAboutBugReporting(); + } else if (link == QLatin1String(DRKONQI_REPORT_BUG_URL)) { + KToolInvocation::invokeBrowser(link); + } else if (link.startsWith(QLatin1String("http"))) { + kWarning() << "unexpected link"; + KToolInvocation::invokeBrowser(link); + } +} + +void DrKonqiDialog::showAboutBugReporting() +{ + if (!m_aboutBugReportingDialog) { + m_aboutBugReportingDialog = new AboutBugReportingDialog(); + connect(this, SIGNAL(destroyed(QObject*)), m_aboutBugReportingDialog, SLOT(close())); + } + m_aboutBugReportingDialog->show(); + m_aboutBugReportingDialog->raise(); + m_aboutBugReportingDialog->activateWindow(); +} + +void DrKonqiDialog::applicationRestarted(bool success) +{ + enableButton(KDialog::User3, !success); +} diff --git a/drkonqi/drkonqidialog.h b/drkonqi/drkonqidialog.h new file mode 100644 index 00000000..e118f37d --- /dev/null +++ b/drkonqi/drkonqidialog.h @@ -0,0 +1,76 @@ +/******************************************************************* +* drkonqidialog.h +* Copyright 2009 Dario Andres Rodriguez +* +* 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, see . +* +******************************************************************/ + +#ifndef DRKONQIDIALOG__H +#define DRKONQIDIALOG__H + +#include +#include + +#include + +#include "ui_maindialog.h" + +class BacktraceWidget; +class AboutBugReportingDialog; +class KTabWidget; +class AbstractDebuggerLauncher; +class KMenu; + +class DrKonqiDialog: public KDialog +{ + Q_OBJECT + +public: + explicit DrKonqiDialog(QWidget * parent = 0); + ~DrKonqiDialog(); + +private Q_SLOTS: + void linkActivated(const QString&); + void startBugReportAssistant(); + + void applicationRestarted(bool success); + + void addDebugger(AbstractDebuggerLauncher *launcher); + void removeDebugger(AbstractDebuggerLauncher *launcher); + void enableDebugMenu(bool); + + //GUI + void buildIntroWidget(); + void buildDialogButtons(); + + void tabIndexChanged(int); + +private: + void showAboutBugReporting(); + + KTabWidget * m_tabWidget; + + QPointer m_aboutBugReportingDialog; + + QWidget * m_introWidget; + Ui::MainWidget ui; + + BacktraceWidget * m_backtraceWidget; + + KMenu *m_debugMenu; + QHash m_debugMenuActions; +}; + +#endif diff --git a/drkonqi/findconfigdatajob.cpp b/drkonqi/findconfigdatajob.cpp new file mode 100644 index 00000000..6b20700c --- /dev/null +++ b/drkonqi/findconfigdatajob.cpp @@ -0,0 +1,97 @@ +/******************************************************************* +* findconfigdatajob.cpp +* Copyright 2011 Matthias Fuchs +* +* 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, see . +* +******************************************************************/ + +#include "findconfigdatajob.h" + +#include +#include +#include + +FindConfigDataJob::FindConfigDataJob(const QString &productName, const KUrl &bugtrackerBaseUrl, QObject *parent) + : KJob(parent), + m_job(0), + m_url(bugtrackerBaseUrl) +{ + m_url.addPath("config.cgi"); + m_url.addQueryItem("product", productName); +} + +FindConfigDataJob::~FindConfigDataJob() +{ + if (m_job) { + m_job->kill(); + } +} + +void FindConfigDataJob::start() +{ + m_job = KIO::storedGet(m_url, KIO::Reload, KIO::HideProgressInfo); + connect(m_job, SIGNAL(result(KJob*)), this, SLOT(receivedData(KJob*))); + connect(m_job, SIGNAL(infoMessage(KJob*,QString,QString)), this, SIGNAL(infoMessage(KJob*,QString,QString))); + connect(m_job, SIGNAL(warning(KJob*,QString,QString)), this, SIGNAL(warning(KJob*,QString,QString))); + + m_job->start(); +} + +QString FindConfigDataJob::errorString() const +{ + return m_errorString; +} + +void FindConfigDataJob::receivedData(KJob *job) +{ + Q_UNUSED(job); + + if (m_job->error()) { + setError(m_job->error()); + m_errorString = i18n("Failed to retrieve the config data."); + } else { + m_data = m_job->data(); + } + m_job = 0; + emitResult(); +} + +QStringList FindConfigDataJob::data(InformationType type) +{ + QStringList result; + QString key; + + switch (type) { + case Version: + key = "version\\['[^\']+'\\]"; + break; + default: + Q_ASSERT(false); + break; + } + + QRegExp rx(key + " = \\[ (('[^\']+', )+) \\];"); + if (rx.indexIn(m_data) != -1) { + QString temp = rx.cap(1); + temp.remove('\''); + temp.remove(' '); + result = temp.split(',', QString::SkipEmptyParts); + } + + kDebug() << "Found data for " + key + ':' << result << result.count(); + return result; +} + +#include "findconfigdatajob.moc" diff --git a/drkonqi/findconfigdatajob.h b/drkonqi/findconfigdatajob.h new file mode 100644 index 00000000..63f77614 --- /dev/null +++ b/drkonqi/findconfigdatajob.h @@ -0,0 +1,70 @@ +/******************************************************************* +* findconfigdatajob.h +* Copyright 2011 Matthias Fuchs +* +* 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, see . +* +******************************************************************/ + +#ifndef DRKONQI_FIND_VERSIONS_JOB_H +#define DRKONQI_FIND_VERSIONS_JOB_H + +#include + +#include +#include + +namespace KIO { + class StoredTransferJob; +} + +/** + * This job downloads config.cgi for a specified product, + * looking for the information you want to retrieve + */ +class FindConfigDataJob : public KJob +{ + Q_OBJECT + public: + /** + * @param productName e.g. "plasma" + * @param bugtrackerBaseUrl e.g. "https://bugs.kde.org" + */ + explicit FindConfigDataJob(const QString &productName, const KUrl &bugtrackerBaseUrl, QObject *parent = 0); + virtual ~FindConfigDataJob(); + + virtual void start(); + virtual QString errorString() const; + + enum InformationType { + Version + }; + + /** + * Call this after the job finished to retrieve the + * specified data + */ + QStringList data(InformationType type); + + private slots: + void receivedData(KJob *job); + + private: + KIO::StoredTransferJob *m_job; + KUrl m_url; + QString m_data; + QString m_errorString; +}; + +#endif diff --git a/drkonqi/gdbhighlighter.cpp b/drkonqi/gdbhighlighter.cpp new file mode 100644 index 00000000..1dd84820 --- /dev/null +++ b/drkonqi/gdbhighlighter.cpp @@ -0,0 +1,141 @@ +/* + Copyright (C) 2010 Milian Wolff + + 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 "gdbhighlighter.h" + +#include + +#include + +GdbHighlighter::GdbHighlighter(QTextDocument* parent, const QList & gdbLines) + : QSyntaxHighlighter(parent) +{ + // setup line lookup + int l = 0; + foreach(const BacktraceLine& line, gdbLines) { + lines.insert(l, line); + l += line.toString().count('\n'); + } + // Add a dummy, in case the last backtrace line has more than 1 '\n' char. + const BacktraceLine dummy; + lines.insert(l, dummy); + + // setup formates + KColorScheme scheme(QPalette::Active); + + crashFormat.setForeground(scheme.foreground(KColorScheme::NegativeText)); + nullptrFormat.setForeground(scheme.foreground(KColorScheme::NegativeText)); + nullptrFormat.setFontWeight(QFont::Bold); + assertFormat = nullptrFormat; + threadFormat.setForeground(scheme.foreground(KColorScheme::NeutralText)); + urlFormat.setForeground(scheme.foreground(KColorScheme::LinkText)); + funcFormat.setForeground(scheme.foreground(KColorScheme::VisitedText)); + funcFormat.setFontWeight(QFont::Bold); + otheridFormat.setForeground(scheme.foreground(KColorScheme::PositiveText)); + crapFormat.setForeground(scheme.foreground(KColorScheme::InactiveText)); +} + +void GdbHighlighter::highlightBlock(const QString& text) +{ + int cur = 0; + int next; + int diff; + const QRegExp hexptrPattern("0x[0-9a-f]+", Qt::CaseSensitive, QRegExp::RegExp2); + int lineNr = currentBlock().firstLineNumber(); + while ( cur < text.length() ) { + next = text.indexOf('\n', cur); + if (next == -1) { + next = text.length(); + } + if (lineNr == 0) { + // line that contains 'Application: ...' + ++lineNr; + cur = next; + continue; + } + + diff = next - cur; + + QString lineStr = text.mid(cur, diff).append('\n'); + // -1 since we skip the first line + QMap< int, BacktraceLine >::iterator it = lines.lowerBound(lineNr - 1); + Q_ASSERT(it != lines.end()); + // QMap::lowerBound() returns the next higher item or + // the dummy item, but we want the one before that. + if (it.key() > lineNr - 1) { + --it; + } + const BacktraceLine& line = it.value(); + + if (line.type() == BacktraceLine::KCrash) { + setFormat(cur, diff, crashFormat); + } else if (line.type() == BacktraceLine::ThreadStart || line.type() == BacktraceLine::ThreadIndicator) { + setFormat(cur, diff, threadFormat); + } else if (line.type() == BacktraceLine::Crap) { + setFormat(cur, diff, crapFormat); + } else if (line.type() == BacktraceLine::StackFrame) { + if (!line.fileName().isEmpty()) { + int colonPos = line.fileName().lastIndexOf(':'); + setFormat(lineStr.indexOf(line.fileName()), colonPos == -1 ? line.fileName().length() : colonPos, urlFormat); + } + if (!line.libraryName().isEmpty()) { + setFormat(lineStr.indexOf(line.libraryName()), line.libraryName().length(), urlFormat); + } + if (!line.functionName().isEmpty()) { + int idx = lineStr.indexOf(line.functionName()); + if (idx != -1) { + // highlight Id::Id::Id::Func + // Id should have otheridFormat, :: no format and Func funcFormat + int i = idx; + int from = idx; + while (i < idx + line.functionName().length()) { + if (lineStr.at(i) == ':') { + setFormat(from, i - from, otheridFormat); + // skip :: + i += 2; + from = i; + continue; + } else if (lineStr.at(i) == '<' || lineStr.at(i) == '>') { + setFormat(from, i - from, otheridFormat); + ++i; + from = i; + continue; + } + ++i; + } + if (line.functionName() == "qFatal" || line.functionName() == "abort" || line.functionName() == "__assert_fail" + || line.functionName() == "*__GI___assert_fail" || line.functionName() == "*__GI_abort") { + setFormat(from, i - from, assertFormat); + } else { + setFormat(from, i - from, funcFormat); + } + } + } + // highlight hexadecimal ptrs + int idx = 0; + while ((idx = hexptrPattern.indexIn(lineStr, idx)) != -1) { + if (hexptrPattern.cap() == "0x0") { + setFormat(idx, hexptrPattern.matchedLength(), nullptrFormat); + } + idx += hexptrPattern.matchedLength(); + } + } + + cur = next; + ++lineNr; + } +} diff --git a/drkonqi/gdbhighlighter.h b/drkonqi/gdbhighlighter.h new file mode 100644 index 00000000..6d26b2ab --- /dev/null +++ b/drkonqi/gdbhighlighter.h @@ -0,0 +1,45 @@ +/* + Copyright (C) 2010 Milian Wolff + + 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. +*/ +#ifndef GDBHIGHLIGHTER_H +#define GDBHIGHLIGHTER_H + +#include + +#include "parser/backtraceline.h" + +class GdbHighlighter : public QSyntaxHighlighter +{ +public: + GdbHighlighter(QTextDocument* parent, const QList & gdbLines); + +protected: + virtual void highlightBlock(const QString& text); + +private: + QMap lines; + QTextCharFormat crashFormat; + QTextCharFormat nullptrFormat; + QTextCharFormat assertFormat; + QTextCharFormat threadFormat; + QTextCharFormat urlFormat; + QTextCharFormat funcFormat; + QTextCharFormat otheridFormat; + QTextCharFormat crapFormat; +}; + +#endif // GDBHIGHLIGHTER_H diff --git a/drkonqi/kdbgwin/CMakeLists.txt b/drkonqi/kdbgwin/CMakeLists.txt new file mode 100644 index 00000000..7c39a248 --- /dev/null +++ b/drkonqi/kdbgwin/CMakeLists.txt @@ -0,0 +1,29 @@ +project(kdbgwin) + +set(kdbgwin_SRCS + common.h + main.cpp + process.h + process.cpp + abstract_generator.h + abstract_generator.cpp + callbacks.h + callbacks.cpp + outputters.h + outputters.cpp +) + +set(COMMON_LIBS ${KDE4_KDECORE_LIBS} ${KDE4_KDEUI_LIBS} dbghelp psapi shlwapi) + +if ( MINGW ) + # FIXME this should be handled in a higher level cmake with proper find + # scripts and configuration + kde4_add_executable(kdbgwin ${kdbgwin_SRCS} mingw_generator.h mingw_generator.cpp) + target_link_libraries(kdbgwin ${COMMON_LIBS} bfd iberty intl z) +endif ( MINGW ) +if ( MSVC OR ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Intel")) + kde4_add_executable(kdbgwin ${kdbgwin_SRCS} msvc_generator.h msvc_generator.cpp) + target_link_libraries(kdbgwin ${COMMON_LIBS}) +endif ( MSVC OR ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Intel")) + +install(TARGETS kdbgwin DESTINATION ${LIBEXEC_INSTALL_DIR}) diff --git a/drkonqi/kdbgwin/Doxyfile b/drkonqi/kdbgwin/Doxyfile new file mode 100644 index 00000000..d583734b --- /dev/null +++ b/drkonqi/kdbgwin/Doxyfile @@ -0,0 +1,286 @@ + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- +DOXYFILE_ENCODING = UTF-8 +PROJECT_NAME = kdbgwin +PROJECT_NUMBER = +OUTPUT_DIRECTORY = n:\kde\svn\trunk\KDE\kdebase\runtime\drkonqi\kdbgwin\doc +CREATE_SUBDIRS = NO +OUTPUT_LANGUAGE = English +BRIEF_MEMBER_DESC = YES +REPEAT_BRIEF = YES +ABBREVIATE_BRIEF = "The $name class" \ + "The $name widget" \ + "The $name file" \ + is \ + provides \ + specifies \ + contains \ + represents \ + a \ + an \ + the +ALWAYS_DETAILED_SEC = YES +INLINE_INHERITED_MEMB = NO +FULL_PATH_NAMES = NO +STRIP_FROM_PATH = +STRIP_FROM_INC_PATH = +SHORT_NAMES = NO +JAVADOC_AUTOBRIEF = NO +QT_AUTOBRIEF = NO +MULTILINE_CPP_IS_BRIEF = NO +INHERIT_DOCS = YES +SEPARATE_MEMBER_PAGES = NO +TAB_SIZE = 8 +ALIASES = +OPTIMIZE_OUTPUT_FOR_C = NO +OPTIMIZE_OUTPUT_JAVA = NO +OPTIMIZE_FOR_FORTRAN = NO +OPTIMIZE_OUTPUT_VHDL = NO +EXTENSION_MAPPING = +BUILTIN_STL_SUPPORT = NO +CPP_CLI_SUPPORT = NO +SIP_SUPPORT = NO +IDL_PROPERTY_SUPPORT = YES +DISTRIBUTE_GROUP_DOC = NO +SUBGROUPING = YES +TYPEDEF_HIDES_STRUCT = NO +SYMBOL_CACHE_SIZE = 0 + +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- +EXTRACT_ALL = NO +EXTRACT_PRIVATE = NO +EXTRACT_STATIC = YES +EXTRACT_LOCAL_CLASSES = YES +EXTRACT_LOCAL_METHODS = YES +EXTRACT_ANON_NSPACES = NO +HIDE_UNDOC_MEMBERS = NO +HIDE_UNDOC_CLASSES = NO +HIDE_FRIEND_COMPOUNDS = NO +HIDE_IN_BODY_DOCS = NO +INTERNAL_DOCS = NO +CASE_SENSE_NAMES = NO +HIDE_SCOPE_NAMES = NO +SHOW_INCLUDE_FILES = YES +FORCE_LOCAL_INCLUDES = NO +INLINE_INFO = YES +SORT_MEMBER_DOCS = YES +SORT_BRIEF_DOCS = NO +SORT_MEMBERS_CTORS_1ST = NO +SORT_GROUP_NAMES = NO +SORT_BY_SCOPE_NAME = NO +GENERATE_TODOLIST = YES +GENERATE_TESTLIST = YES +GENERATE_BUGLIST = YES +GENERATE_DEPRECATEDLIST= YES +ENABLED_SECTIONS = +MAX_INITIALIZER_LINES = 30 +SHOW_USED_FILES = YES +SHOW_DIRECTORIES = NO +SHOW_FILES = YES +SHOW_NAMESPACES = YES +FILE_VERSION_FILTER = +LAYOUT_FILE = + +#--------------------------------------------------------------------------- +# configuration options related to warning and progress messages +#--------------------------------------------------------------------------- +QUIET = NO +WARNINGS = YES +WARN_IF_UNDOCUMENTED = YES +WARN_IF_DOC_ERROR = YES +WARN_NO_PARAMDOC = NO +WARN_FORMAT = "$file:$line: $text" +WARN_LOGFILE = + +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- +INPUT = n:\kde\svn\trunk\KDE\kdebase\runtime\drkonqi\kdbgwin +INPUT_ENCODING = UTF-8 +FILE_PATTERNS = *.h +RECURSIVE = NO +EXCLUDE = +EXCLUDE_SYMLINKS = NO +EXCLUDE_PATTERNS = +EXCLUDE_SYMBOLS = +EXAMPLE_PATH = +EXAMPLE_PATTERNS = * +EXAMPLE_RECURSIVE = NO +IMAGE_PATH = +INPUT_FILTER = +FILTER_PATTERNS = +FILTER_SOURCE_FILES = NO + +#--------------------------------------------------------------------------- +# configuration options related to source browsing +#--------------------------------------------------------------------------- +SOURCE_BROWSER = NO +INLINE_SOURCES = NO +STRIP_CODE_COMMENTS = YES +REFERENCED_BY_RELATION = NO +REFERENCES_RELATION = NO +REFERENCES_LINK_SOURCE = YES +USE_HTAGS = NO +VERBATIM_HEADERS = YES + +#--------------------------------------------------------------------------- +# configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- +ALPHABETICAL_INDEX = YES +COLS_IN_ALPHA_INDEX = 5 +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- +GENERATE_HTML = YES +HTML_OUTPUT = html +HTML_FILE_EXTENSION = .html +HTML_HEADER = +HTML_FOOTER = +HTML_STYLESHEET = +HTML_TIMESTAMP = NO +HTML_ALIGN_MEMBERS = YES +HTML_DYNAMIC_SECTIONS = NO +GENERATE_DOCSET = NO +DOCSET_FEEDNAME = "Doxygen generated docs" +DOCSET_BUNDLE_ID = org.doxygen.Project +GENERATE_HTMLHELP = NO +CHM_FILE = +HHC_LOCATION = +GENERATE_CHI = NO +CHM_INDEX_ENCODING = +BINARY_TOC = NO +TOC_EXPAND = NO +GENERATE_QHP = NO +QCH_FILE = +QHP_NAMESPACE = org.doxygen.Project +QHP_VIRTUAL_FOLDER = doc +QHP_CUST_FILTER_NAME = +QHP_CUST_FILTER_ATTRS = +QHP_SECT_FILTER_ATTRS = +QHG_LOCATION = +GENERATE_ECLIPSEHELP = NO +ECLIPSE_DOC_ID = org.doxygen.Project +DISABLE_INDEX = NO +ENUM_VALUES_PER_LINE = 4 +GENERATE_TREEVIEW = NO +USE_INLINE_TREES = NO +TREEVIEW_WIDTH = 250 +FORMULA_FONTSIZE = 10 +SEARCHENGINE = YES +SERVER_BASED_SEARCH = NO + +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- +GENERATE_LATEX = NO +LATEX_OUTPUT = latex +LATEX_CMD_NAME = latex +MAKEINDEX_CMD_NAME = makeindex +COMPACT_LATEX = NO +PAPER_TYPE = a4wide +EXTRA_PACKAGES = +LATEX_HEADER = +PDF_HYPERLINKS = YES +USE_PDFLATEX = YES +LATEX_BATCHMODE = NO +LATEX_HIDE_INDICES = NO +LATEX_SOURCE_CODE = NO + +#--------------------------------------------------------------------------- +# configuration options related to the RTF output +#--------------------------------------------------------------------------- +GENERATE_RTF = NO +RTF_OUTPUT = rtf +COMPACT_RTF = NO +RTF_HYPERLINKS = NO +RTF_STYLESHEET_FILE = +RTF_EXTENSIONS_FILE = + +#--------------------------------------------------------------------------- +# configuration options related to the man page output +#--------------------------------------------------------------------------- +GENERATE_MAN = NO +MAN_OUTPUT = man +MAN_EXTENSION = .3 +MAN_LINKS = NO + +#--------------------------------------------------------------------------- +# configuration options related to the XML output +#--------------------------------------------------------------------------- +GENERATE_XML = NO +XML_OUTPUT = xml +XML_SCHEMA = +XML_DTD = +XML_PROGRAMLISTING = YES + +#--------------------------------------------------------------------------- +# configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- +GENERATE_AUTOGEN_DEF = NO + +#--------------------------------------------------------------------------- +# configuration options related to the Perl module output +#--------------------------------------------------------------------------- +GENERATE_PERLMOD = NO +PERLMOD_LATEX = NO +PERLMOD_PRETTY = YES +PERLMOD_MAKEVAR_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- +ENABLE_PREPROCESSING = NO +MACRO_EXPANSION = NO +EXPAND_ONLY_PREDEF = NO +SEARCH_INCLUDES = YES +INCLUDE_PATH = +INCLUDE_FILE_PATTERNS = +PREDEFINED = +EXPAND_AS_DEFINED = +SKIP_FUNCTION_MACROS = YES + +#--------------------------------------------------------------------------- +# Configuration::additions related to external references +#--------------------------------------------------------------------------- +TAGFILES = +GENERATE_TAGFILE = +ALLEXTERNALS = NO +EXTERNAL_GROUPS = YES +PERL_PATH = /usr/bin/perl + +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- +CLASS_DIAGRAMS = YES +MSCGEN_PATH = +HIDE_UNDOC_RELATIONS = YES +HAVE_DOT = NO +DOT_FONTNAME = FreeSans +DOT_FONTSIZE = 10 +DOT_FONTPATH = +CLASS_GRAPH = YES +COLLABORATION_GRAPH = YES +GROUP_GRAPHS = YES +UML_LOOK = NO +TEMPLATE_RELATIONS = NO +INCLUDE_GRAPH = YES +INCLUDED_BY_GRAPH = YES +CALL_GRAPH = NO +CALLER_GRAPH = NO +GRAPHICAL_HIERARCHY = YES +DIRECTORY_GRAPH = YES +DOT_IMAGE_FORMAT = png +DOT_PATH = +DOTFILE_DIRS = +DOT_GRAPH_MAX_NODES = 50 +MAX_DOT_GRAPH_DEPTH = 0 +DOT_TRANSPARENT = NO +DOT_MULTI_TARGETS = NO +GENERATE_LEGEND = YES +DOT_CLEANUP = YES diff --git a/drkonqi/kdbgwin/abstract_generator.cpp b/drkonqi/kdbgwin/abstract_generator.cpp new file mode 100644 index 00000000..1fa937be --- /dev/null +++ b/drkonqi/kdbgwin/abstract_generator.cpp @@ -0,0 +1,240 @@ +/****************************************************************** + * + * kdbgwin - Helper application for DrKonqi + * + * This file is part of the KDE project + * + * Copyright (C) 2010 Ilie Halip + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 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 6 of version 3 of the license. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see + *****************************************************************/ + +#include "abstract_generator.h" +#include "callbacks.h" + +#include + +AbstractBTGenerator::AbstractBTGenerator(const Process& process) + : m_process(process) +{ + assert(process.IsValid()); +} + +AbstractBTGenerator::~AbstractBTGenerator() +{ +} + +QString AbstractBTGenerator::GetModuleName() +{ + IMAGEHLP_MODULE64 module; + ZeroMemory(&module, sizeof(module)); + module.SizeOfStruct = sizeof(IMAGEHLP_MODULE64); + + if (!SymGetModuleInfo64(m_process.GetHandle(), m_currentFrame.AddrPC.Offset, &module)) + { + kError() << "SymGetModuleInfo64 failed: " << GetLastError(); + return QLatin1String(DEFAULT_MODULE); + } + + QStringList list = QString(module.ImageName).split("\\"); + return list[list.size() - 1]; +} + +QString AbstractBTGenerator::GetModulePath() +{ + IMAGEHLP_MODULE64 module; + ZeroMemory(&module, sizeof(module)); + module.SizeOfStruct = sizeof(IMAGEHLP_MODULE64); + + if (!SymGetModuleInfo64(m_process.GetHandle(), m_currentFrame.AddrPC.Offset, &module)) + { + kError() << "SymGetModuleInfo64 failed: " << GetLastError(); + return QLatin1String(DEFAULT_MODULE); + } + + return QString(module.ImageName); +} + +void AbstractBTGenerator::Run(HANDLE hThread, bool bFaultingThread) +{ + assert(m_process.IsValid()); + assert(hThread); + + if (!Init()) + { + assert(false); + return; + } + + //HANDLE hFile = CreateFile(L"C:\\test\\test.dmp", FILE_ALL_ACCESS, FILE_SHARE_WRITE|FILE_SHARE_READ, NULL, CREATE_ALWAYS, 0, NULL); + //if (!MiniDumpWriteDump(m_process.GetHandle(), m_process.GetId(), hFile, + // MiniDumpNormal, NULL, NULL, NULL)) + //{ + // HRESULT hres = (HRESULT) GetLastError(); + // printf("%08X\n\n", hres); + //} + //SafeCloseHandle(hFile); + + DWORD dw = SuspendThread(hThread); + assert(dw != DWORD(-1)); + if (dw == DWORD(-1)) + { + kError() << "SuspendThread() failed: " << GetLastError(); + return; + } + + CONTEXT context; + ZeroMemory(&context, sizeof(context)); + if (!bFaultingThread) + { + // if it's not the faulting thread, get its context + context.ContextFlags = CONTEXT_FULL; + if (!GetThreadContext(hThread, &context)) + { + ResumeThread(hThread); + assert(false); + kError() << "GetThreadContext() failed: " << GetLastError(); + return; + } + } + else + { + // if it is, get it from KCrash + HANDLE hMapFile = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, L"Local\\KCrashShared"); + if (hMapFile == NULL) + { + kError() << "OpenFileMapping() failed: " << GetLastError(); + return; + } + CONTEXT *othercontext = (CONTEXT*) MapViewOfFile(hMapFile, FILE_MAP_ALL_ACCESS, 0, 0, sizeof(CONTEXT)); + if (othercontext == NULL) + { + kError() << "MapViewOfFile() failed: " << GetLastError(); + SafeCloseHandle(hMapFile); + return; + } + CopyMemory(&context, othercontext, sizeof(CONTEXT)); + UnmapViewOfFile(othercontext); // continue even if it fails + SafeCloseHandle(hMapFile); + } + + // some of this stuff is taken from StackWalker + ZeroMemory(&m_currentFrame, sizeof(m_currentFrame)); + DWORD machineType = IMAGE_FILE_MACHINE_UNKNOWN; +#if defined(_M_IX86) + machineType = IMAGE_FILE_MACHINE_I386; + m_currentFrame.AddrPC.Offset = context.Eip; + m_currentFrame.AddrFrame.Offset = context.Ebp; + m_currentFrame.AddrStack.Offset = context.Esp; +#elif defined(_M_X64) + machineType = IMAGE_FILE_MACHINE_AMD64; + m_currentFrame.AddrPC.Offset = context.Rip; + m_currentFrame.AddrFrame.Offset = context.Rbp; + m_currentFrame.AddrStack.Offset = context.Rsp; +#else +# error This architecture is not supported. +#endif + m_currentFrame.AddrPC.Mode = AddrModeFlat; + m_currentFrame.AddrFrame.Mode = AddrModeFlat; + m_currentFrame.AddrStack.Mode = AddrModeFlat; + + SymSetOptions(SymGetOptions() | SYMOPT_UNDNAME | SYMOPT_LOAD_LINES); + SymInitialize(m_process.GetHandle(), NULL, FALSE); + + LoadSymbols(); + + for (int i = 0; /*nothing*/; i++) + { + SetLastError(0); + + if (!StackWalk64( + machineType, + m_process.GetHandle(), + hThread, + &m_currentFrame, + &context, + &Callbacks::ReadProcessMemory, + &Callbacks::SymFunctionTableAccess64, + &Callbacks::SymGetModuleBase64, + NULL)) + { + emit Finished(); + kDebug() << "Stackwalk finished; GetLastError=" << GetLastError(); + break; + } + + FrameChanged(); + + QString modulename = GetModuleName(); + QString functionname = GetFunctionName(); + QString file = GetFile(); + int line = GetLine(); + QString address = QString::number(m_currentFrame.AddrPC.Offset, 16); + + QString debugLine = QString::fromLatin1(BACKTRACE_FORMAT). + arg(modulename).arg(functionname).arg(file).arg(line).arg(address); + + emit DebugLine(debugLine); + } + + // Resume the target thread now, or else the crashing process will not + // be terminated + ResumeThread(hThread); + + SymCleanup(m_process.GetHandle()); +} + +bool AbstractBTGenerator::IsSymbolLoaded(const QString& module) +{ + if (m_symbolsMap.contains(module)) + { + return m_symbolsMap[module]; + } + return false; +} + +void AbstractBTGenerator::LoadSymbols() +{ + TModulesMap modules = m_process.GetModules(); + for (TModulesMap::iterator i = modules.begin(); i != modules.end(); i++) + { + MODULEINFO modInfo; + ZeroMemory(&modInfo, sizeof(modInfo)); + + QString strModule = i.key(); + + GetModuleInformation(m_process.GetHandle(), i.value(), &modInfo, sizeof(modInfo)); + SymLoadModuleEx( + m_process.GetHandle(), + NULL, + (CHAR*) i.key().toLatin1().constData(), + (CHAR*) i.key().toLatin1().constData(), + (DWORD64) modInfo.lpBaseOfDll, + modInfo.SizeOfImage, + NULL, + 0); + + LoadSymbol(strModule, (DWORD64) modInfo.lpBaseOfDll); + + if (!IsSymbolLoaded(strModule)) + { + emit MissingSymbol(strModule); + } + } + emit DebugLine(QString()); + emit DebugLine(QString()); +} diff --git a/drkonqi/kdbgwin/abstract_generator.h b/drkonqi/kdbgwin/abstract_generator.h new file mode 100644 index 00000000..271b6e0d --- /dev/null +++ b/drkonqi/kdbgwin/abstract_generator.h @@ -0,0 +1,121 @@ +/****************************************************************** + * + * kdbgwin - Helper application for DrKonqi + * + * This file is part of the KDE project + * + * Copyright (C) 2010 Ilie Halip + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 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 6 of version 3 of the license. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see + *****************************************************************/ + +#pragma once + +#include "common.h" +#include "process.h" + +const static char* BACKTRACE_FORMAT = "%1!%2() [%3 @ %4] at 0x%5"; +// module.dll!KClass::function() [c:\file.cpp @ 10] at 0x0001000 + +const static char* DEFAULT_MODULE = "[unknown]"; +const static char* DEFAULT_FUNC = "[unknown]"; +const static char* DEFAULT_FILE = "[unknown]"; +const static int DEFAULT_LINE = -1; + +/** + * \brief Base generator class + * + * This class gives the definition of a backtrace generator. There are 2 subclasses: one for + * MSVC and one for MinGW. The reason why implementation differs is the fact that executables + * use different debugging formats: PDBs (for MSVC) and Dwarf-2/Stabs and possibly more I don't + * know too much about for MinGW, which are embedded in the executable itself. + */ +class AbstractBTGenerator : public QObject +{ + Q_OBJECT +protected: + /// A Process instance, corresponding to the process for which we generate the backtrace + Process m_process; + + /// The current stack frame. It is kept as a member + STACKFRAME64 m_currentFrame; + + /// The definition of a map of symbols + typedef QMap TSymbolsMap; + /// A map of symbols (the full path to the module, and a bool which specifies if + /// symbols were loaded for it) + TSymbolsMap m_symbolsMap; + +public: + /// Constructor + AbstractBTGenerator(const Process& process); + virtual ~AbstractBTGenerator(); + + /// Abstract virtual: Initialize this generator + virtual bool Init() = 0; + + /// Abstract virtual: Uninitialize this generator + virtual void UnInit() = 0; + + /// Start generating the backtrace + virtual void Run(HANDLE hTread, bool bFaultingThread); + + /// This method acts like a callback and will be called when the stack frame changed + virtual void FrameChanged() = 0; + + /// Abstract virtual: get current module name + /// @return the name of the current module (eg: kdecore.dll) + virtual QString GetModuleName(); + + /// Abstract virtual: get current module path + /// @return the full path to the current module (eg: N:\\kde\\bin\\kdecore.dll) + virtual QString GetModulePath(); + + /// Abstract virtual: get current function/method name. The name is undecorated internally by this method. + /// @return the current function or method (eg: KCmdLineArgs::args) + virtual QString GetFunctionName() = 0; + + /// Abstract virtual: get the full path to the current file + /// @return the path to the file (eg: N:\\kde\\svn\\KDE\\trunk\\kdelibs\\kcmdlineargs\\kcmdlineargs.cpp) + virtual QString GetFile() = 0; + + /// Abstract virtual: get current line + /// @return the current line in the file + virtual int GetLine() = 0; + + /// Checks if symbols are loaded for the specified module + /// @return true if symbols are loaded + virtual bool IsSymbolLoaded(const QString& module); + + /// Tries to load symbols for all loaded modules + virtual void LoadSymbols(); + + /// Tries to load a symbol file for a module loaded at dwBaseAddr + virtual void LoadSymbol(const QString& module, DWORD64 dwBaseAddr) = 0; +signals: + /// This will be emitted whenever the generator wishes to output information. It can either be + /// module information (in the form: "Loaded C:\path\to.dll (symbols loaded)", a stack frame line, + /// or newlines + void DebugLine(const QString&); + + /// This signal is emitted when a module is loaded, and its symbols are missing. This is + /// caught by the PackageSuggester + void MissingSymbol(const QString&); + + /// Will be emitted when the generation finishes + void Finished(); +}; diff --git a/drkonqi/kdbgwin/callbacks.cpp b/drkonqi/kdbgwin/callbacks.cpp new file mode 100644 index 00000000..2d5a1865 --- /dev/null +++ b/drkonqi/kdbgwin/callbacks.cpp @@ -0,0 +1,49 @@ +/****************************************************************** + * + * kdbgwin - Helper application for DrKonqi + * + * This file is part of the KDE project + * + * Copyright (C) 2010 Ilie Halip + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 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 6 of version 3 of the license. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see + *****************************************************************/ + +#include "callbacks.h" + +BOOL Callbacks::ReadProcessMemory(HANDLE hProcess, DWORD64 qwBaseAddr, PVOID lpBuf, DWORD nSize, LPDWORD lpBytesRead) +{ + SIZE_T st; + BOOL bRet = ::ReadProcessMemory(hProcess, (LPVOID) qwBaseAddr, (LPVOID) lpBuf, nSize, &st); + *lpBytesRead = (DWORD) st; + //kDebug() << "bytes read=" << st << "; bRet=" << bRet << "; LastError: " << GetLastError(); + return bRet; +} + +PVOID Callbacks::SymFunctionTableAccess64(HANDLE hProcess, DWORD64 qwAddr) +{ + PVOID ret = ::SymFunctionTableAccess64(hProcess, qwAddr); + //kDebug() << "ret=" << ret << "; LastError: " << GetLastError(); + return ret; +} + +DWORD64 Callbacks::SymGetModuleBase64(HANDLE hProcess, DWORD64 qwAddr) +{ + DWORD64 ret = ::SymGetModuleBase64(hProcess, qwAddr); + //kDebug() << "ret=" << ret << "; LastError: " << GetLastError(); + return ret; +} diff --git a/drkonqi/kdbgwin/callbacks.h b/drkonqi/kdbgwin/callbacks.h new file mode 100644 index 00000000..77b71218 --- /dev/null +++ b/drkonqi/kdbgwin/callbacks.h @@ -0,0 +1,44 @@ +/****************************************************************** + * + * kdbgwin - Helper application for DrKonqi + * + * This file is part of the KDE project + * + * Copyright (C) 2010 Ilie Halip + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 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 6 of version 3 of the license. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see + *****************************************************************/ + +#pragma once + +#include "common.h" + +#define KDBGWIN_CALL_TYPE __stdcall + +/** + * \brief StackWalk64 callbacks. + * + * This class encapsulates 3 callbacks used by StackWalk64. ReadProcessMemory is the only + * one really needed here, but I kept all three for debugging purposes. + */ +class Callbacks +{ +public: + static BOOL KDBGWIN_CALL_TYPE ReadProcessMemory(HANDLE, DWORD64, PVOID, DWORD, LPDWORD); + static PVOID KDBGWIN_CALL_TYPE SymFunctionTableAccess64(HANDLE, DWORD64); + static DWORD64 KDBGWIN_CALL_TYPE SymGetModuleBase64(HANDLE, DWORD64); +}; diff --git a/drkonqi/kdbgwin/common.h b/drkonqi/kdbgwin/common.h new file mode 100644 index 00000000..82fc8a6f --- /dev/null +++ b/drkonqi/kdbgwin/common.h @@ -0,0 +1,74 @@ +/****************************************************************** + * + * kdbgwin - Helper application for DrKonqi + * + * This file is part of the KDE project + * + * Copyright (C) 2010 Ilie Halip + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 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 6 of version 3 of the license. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see + *****************************************************************/ + +#pragma once + +// the compiler only provides UNICODE. tchar.h checks for the _UNICODE macro +#if defined(UNICODE) +#define _UNICODE +#endif + +// first: windows & compiler includes +#include +#include +#include +#include +#include +#include +#include + + +// second: Qt includes +#include +#include + + +// third: KDE includes +#include + + +// common defines +#define SafeCloseHandle(h) \ + CloseHandle(h); \ + h = NULL; + +#define ArrayCount(x) (sizeof(x) / sizeof(x[0])) + + + + +// Documentation +/** +\mainpage KDbgWin + +KDbgWin (KDE Debugger for Windows) is a helper application for DrKonqi. Because KDE-Windows supports +2 compilers (MSVC and MinGW), and there is no debugger that supports them both, a simple debugger was needed +to make DrKonqi able to generate backtraces - Windows only. + +MSVC generates .pdb files for its binaries, and GNU GCC embeds debugging information in executables. However, +with MinGW, debugging information can be stripped into external files and then loaded on demand. So the only +difference between the two is how symbols are handled. DbgHelp and LibBfd were used for manipulating and getting +the required information from each debugging format. +*/ diff --git a/drkonqi/kdbgwin/main.cpp b/drkonqi/kdbgwin/main.cpp new file mode 100644 index 00000000..2ca2c689 --- /dev/null +++ b/drkonqi/kdbgwin/main.cpp @@ -0,0 +1,79 @@ +/****************************************************************** + * + * kdbgwin - Helper application for DrKonqi + * + * This file is part of the KDE project + * + * Copyright (C) 2010 Ilie Halip + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 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 6 of version 3 of the license. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see + *****************************************************************/ + +#include "msvc_generator.h" +#include "mingw_generator.h" +#include "outputters.h" +#include "process.h" +#include + +int main(int argc, char *argv[]) +{ + QCoreApplication app(argc, argv); + QCoreApplication::setApplicationName("kdbgwin"); + + if (argc != 3) + { + kFatal() << "Parameters are incorrect"; + return -1; + } + + if (!Process::EnableDebugPrivilege()) + { + kFatal() << "Cannot enable debug privilege, exiting"; + return -1; + } + + // ok, argv[1] is the pid of the failing process, + // and argv[2] the current thread id - let's get the info we need + Process proc; + if (!proc.GetInfo(argv[1], argv[2])) + { + kFatal() << "Cannot attach to process, exiting"; + return -1; + } + +#if defined(Q_CC_MSVC) + MsvcGenerator generator(proc); +#elif defined(Q_CC_GNU) + MingwGenerator generator(proc); +#endif + + Outputter outputter; + + QObject::connect + ( + &generator, + SIGNAL(DebugLine(QString)), + &outputter, + SLOT(OnDebugLine(QString)) + ); + + TThreadsMap::const_iterator it; + for (it = proc.GetThreads().constBegin(); it != proc.GetThreads().constEnd(); it++) + { + generator.Run(it.value(), (it.key() == proc.GetThreadId())? true : false); + } +} diff --git a/drkonqi/kdbgwin/mingw_generator.cpp b/drkonqi/kdbgwin/mingw_generator.cpp new file mode 100644 index 00000000..34752268 --- /dev/null +++ b/drkonqi/kdbgwin/mingw_generator.cpp @@ -0,0 +1,168 @@ +/****************************************************************** + * + * kdbgwin - Helper application for DrKonqi + * + * This file is part of the KDE project + * + * Copyright (C) 2010 Ilie Halip + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 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 6 of version 3 of the license. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see + *****************************************************************/ + +#include "mingw_generator.h" +#include +#include + +MingwGenerator::MingwGenerator(const Process& process) + : AbstractBTGenerator(process), file(NULL), func(NULL), line(0) +{} + +struct MyBFD +{ + QString module; + bfd* abfd; + asymbol** syms; + MyBFD() : abfd(0), syms(0) + {} + MyBFD(const QString& module, bfd* abfd, asymbol** syms) + { this->module = module; this->abfd = abfd; this->syms = syms; } + bool operator==(const MyBFD& other) + { return module == other.module; } +}; + +typedef QList TBFDList; +TBFDList bfds; + +asection* text = NULL; + +bool MingwGenerator::Init() +{ + bfd_init(); + return true; +} + +void MingwGenerator::UnInit() +{ +} + +void MingwGenerator::FrameChanged() +{ + QString modPath = GetModulePath(); + bool existsSymbol = false; + TSymbolsMap::const_iterator i = m_symbolsMap.find(modPath); + if (i == m_symbolsMap.end()) + { + return; + } + MyBFD dummy(modPath, NULL, NULL); + int pos = bfds.indexOf(dummy); + if (pos == -1) + { + return; + } + MyBFD bfd = bfds[pos]; + text = bfd_get_section_by_name(bfd.abfd, ".text"); + long offset = m_currentFrame.AddrPC.Offset - text->vma; + file = DEFAULT_FILE; + func = DEFAULT_FUNC; + line = DEFAULT_LINE; + if (offset > 0) + { + bfd_find_nearest_line(bfd.abfd, text, bfd.syms, offset, &file, &func, (unsigned int*) &line); + } +} + +QString MingwGenerator::GetFunctionName() +{ + if (func != NULL) + { + char* realname = abi::__cxa_demangle(func, NULL, NULL, NULL); + if (realname != NULL) + { + QString strReturn = QString::fromLatin1(realname); + free(realname); + return strReturn; + } + else + { + return QString::fromLatin1(func); + } + } + return QString::fromLatin1(DEFAULT_FUNC); +} + +QString MingwGenerator::GetFile() +{ + if (file != NULL) + { + return QString::fromLatin1(file); + } + return QString::fromLatin1(DEFAULT_FILE); +} + +int MingwGenerator::GetLine() +{ + if (line > 0) + { + return line; + } + return -1; +} + +void MingwGenerator::LoadSymbol(const QString& module, DWORD64 dwBaseAddr) +{ + QString symbolFile = module; + symbolFile.truncate(symbolFile.length() - 4); + symbolFile.append(".sym"); + + m_symbolsMap[module] = false; // default + QString symbolType; + do + { + bfd* abfd = bfd_openr(symbolFile.toLatin1(), NULL); + if (abfd == NULL) + { + symbolType = QString::fromLatin1("no symbols loaded"); + break; + } + bfd_check_format(abfd, bfd_object); + unsigned storage_needed = bfd_get_symtab_upper_bound(abfd); + assert(storage_needed > 4); + if (storage_needed <= 4) + { + // i don't know why the minimum value for this var is 4... + symbolType = QString::fromLatin1("no symbols loaded"); + break; + } + asymbol** syms = (asymbol **) malloc(storage_needed); + assert(syms); + if (syms == NULL) + { + symbolType = QString::fromLatin1("no symbols loaded"); + break; + } + symbolType = QString::fromLatin1("symbols loaded"); + m_symbolsMap[module] = true; + + bfds.push_back(MyBFD(module, abfd, syms)); + } + while (0); + + QString strOutput = QString::fromLatin1("Loaded %1 (%2)") + .arg(module).arg(symbolType); + emit DebugLine(strOutput); +} diff --git a/drkonqi/kdbgwin/mingw_generator.h b/drkonqi/kdbgwin/mingw_generator.h new file mode 100644 index 00000000..a232b672 --- /dev/null +++ b/drkonqi/kdbgwin/mingw_generator.h @@ -0,0 +1,62 @@ +/****************************************************************** + * + * kdbgwin - Helper application for DrKonqi + * + * This file is part of the KDE project + * + * Copyright (C) 2010 Ilie Halip + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 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 6 of version 3 of the license. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see + *****************************************************************/ + +#pragma once + +#include "abstract_generator.h" + +/** + * \brief Generator for MinGW. + * + * This class allows generating backtraces for executables created with the MinGW compiler. + * It assumes that symbols are stored in .sym files in the same directory as the corresponding + * binary (eg. N:\\kde\\bin\\libkdecore.dll and N:\\kde\\bin\\libkdecore.sym). It uses libbfd to + * find and extract the information it needs from the symbols it loads. + */ +class MingwGenerator : public AbstractBTGenerator +{ + Q_OBJECT +protected: + /// The current file + const char* file; + /// The current function + const char* func; + /// The current line + int line; +public: + /// Constructor + MingwGenerator(const Process& process); + + virtual bool Init(); + virtual void UnInit(); + + virtual void FrameChanged(); + + virtual QString GetFunctionName(); + virtual QString GetFile(); + virtual int GetLine(); + + virtual void LoadSymbol(const QString& module, DWORD64 dwBaseAddr); +}; diff --git a/drkonqi/kdbgwin/msvc_generator.cpp b/drkonqi/kdbgwin/msvc_generator.cpp new file mode 100644 index 00000000..7d72c12e --- /dev/null +++ b/drkonqi/kdbgwin/msvc_generator.cpp @@ -0,0 +1,139 @@ +/****************************************************************** + * + * kdbgwin - Helper application for DrKonqi + * + * This file is part of the KDE project + * + * Copyright (C) 2010 Ilie Halip + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 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 6 of version 3 of the license. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see + *****************************************************************/ + +#include "msvc_generator.h" + +MsvcGenerator::MsvcGenerator(const Process& process) + : AbstractBTGenerator(process) +{} + +bool MsvcGenerator::Init() +{ + return true; +} + +void MsvcGenerator::UnInit() +{ +} + +QString MsvcGenerator::GetFunctionName() +{ + PSYMBOL_INFO symbol = + (PSYMBOL_INFO) malloc(sizeof(SYMBOL_INFO) + MAX_SYMBOL_NAME); + ZeroMemory(symbol, sizeof(symbol) + MAX_SYMBOL_NAME); + symbol->SizeOfStruct = sizeof(SYMBOL_INFO); + symbol->MaxNameLen = MAX_SYMBOL_NAME; + + DWORD64 dwDisplacement = 0; + + if (!SymFromAddr(m_process.GetHandle(), m_currentFrame.AddrPC.Offset, &dwDisplacement, symbol)) + { + kError() << "SymFromAddr() failed: " << GetLastError(); + return QString::fromLatin1(DEFAULT_FUNC); + } + + char undecoratedName[MAX_PATH] = {0}; + if (!UnDecorateSymbolName(symbol->Name, undecoratedName, MAX_PATH, UNDNAME_COMPLETE)) + { + // if this fails, show the decorated name anyway, don't fail + kError() << "UnDecorateSymbolName() failed: " << GetLastError(); + return QString::fromLatin1(symbol->Name); + } + + return QString::fromLatin1(undecoratedName); +} + +QString MsvcGenerator::GetFile() +{ + IMAGEHLP_LINE64 line; + ZeroMemory(&line, sizeof(line)); + line.SizeOfStruct = sizeof(IMAGEHLP_LINE64); + DWORD dwDisplacement = 0; + + if (!SymGetLineFromAddr64(m_process.GetHandle(), m_currentFrame.AddrPC.Offset, &dwDisplacement, &line)) + { + kError() << "SymGetLineFromAddr64 failed: " << GetLastError(); + return QString::fromLatin1(DEFAULT_FILE); + } + + return QString(line.FileName); +} + +int MsvcGenerator::GetLine() +{ + IMAGEHLP_LINE64 line; + ZeroMemory(&line, sizeof(line)); + line.SizeOfStruct = sizeof(IMAGEHLP_LINE64); + DWORD dwDisplacement = 0; + + if (!SymGetLineFromAddr64(m_process.GetHandle(), m_currentFrame.AddrPC.Offset, &dwDisplacement, &line)) + { + //kError() << "SymGetLineFromAddr64 failed: " << GetLastError(); + return DEFAULT_LINE; + } + + return (int) line.LineNumber; +} + +void MsvcGenerator::LoadSymbol(const QString& module, DWORD64 dwBaseAddr) +{ + QString strOutput; + + IMAGEHLP_MODULE64 moduleInfo; + ZeroMemory(&moduleInfo, sizeof(moduleInfo)); + moduleInfo.SizeOfStruct = sizeof(moduleInfo); + SymGetModuleInfo64(m_process.GetHandle(), dwBaseAddr, &moduleInfo); + + m_symbolsMap[module] = false; // default + QString symbolType; + switch (moduleInfo.SymType) + { + case SymNone: + symbolType = QString::fromLatin1("no symbols loaded"); + break; + case SymCoff: + case SymCv: + case SymPdb: + case SymSym: + case SymDia: + symbolType = QString::fromLatin1("symbols loaded"); + m_symbolsMap[module] = true; + break; + case SymExport: + symbolType = QString::fromLatin1("export table only"); + break; + case SymDeferred: + symbolType = QString::fromLatin1("deferred (not loaded currently)"); + break; + case SymVirtual: + symbolType = QString::fromLatin1("virtual"); + break; + } + + strOutput = QString::fromLatin1("Loaded %1 (%2)") + .arg(module).arg(symbolType); + + emit DebugLine(strOutput); +} diff --git a/drkonqi/kdbgwin/msvc_generator.h b/drkonqi/kdbgwin/msvc_generator.h new file mode 100644 index 00000000..acdefc35 --- /dev/null +++ b/drkonqi/kdbgwin/msvc_generator.h @@ -0,0 +1,58 @@ +/****************************************************************** + * + * kdbgwin - Helper application for DrKonqi + * + * This file is part of the KDE project + * + * Copyright (C) 2010 Ilie Halip + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 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 6 of version 3 of the license. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see + *****************************************************************/ + +#pragma once + +#include "abstract_generator.h" + +const static DWORD MAX_SYMBOL_NAME = 256 * sizeof(TCHAR); + +/** + * \brief Generator for MSVC. + * + * This class implements a backtrace generator for executables created with Microsoft's + * Visual C++. The fundamental difference of executables created with MSVC and MinGW is + * the debugging format. MSVC uses a proprietary debugging format called PDB (Program + * Database), which can be manipulated with DbgHelp API. + * + */ +class MsvcGenerator : public AbstractBTGenerator +{ + Q_OBJECT +public: + /// Constructor + MsvcGenerator(const Process& process); + + virtual bool Init(); + virtual void UnInit(); + + virtual void FrameChanged() {}; + + virtual QString GetFunctionName(); + virtual QString GetFile(); + virtual int GetLine(); + + virtual void LoadSymbol(const QString& module, DWORD64 dwBaseAddr); +}; diff --git a/drkonqi/kdbgwin/outputters.cpp b/drkonqi/kdbgwin/outputters.cpp new file mode 100644 index 00000000..bff788f0 --- /dev/null +++ b/drkonqi/kdbgwin/outputters.cpp @@ -0,0 +1,35 @@ +/****************************************************************** + * + * kdbgwin - Helper application for DrKonqi + * + * This file is part of the KDE project + * + * Copyright (C) 2010 Ilie Halip + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 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 6 of version 3 of the license. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see + *****************************************************************/ + +#include "outputters.h" + +Outputter::Outputter() : stream(stdout) +{ +} + +void Outputter::OnDebugLine(const QString& line) +{ + stream << line << '\n'; +} diff --git a/drkonqi/kdbgwin/outputters.h b/drkonqi/kdbgwin/outputters.h new file mode 100644 index 00000000..02fc37c5 --- /dev/null +++ b/drkonqi/kdbgwin/outputters.h @@ -0,0 +1,50 @@ +/****************************************************************** + * + * kdbgwin - Helper application for DrKonqi + * + * This file is part of the KDE project + * + * Copyright (C) 2010 Ilie Halip + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 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 6 of version 3 of the license. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see + *****************************************************************/ + +#pragma once + +#include "common.h" +#include + +/** + * \brief Basic outputter. + * + * This class will output the information from a backtrace generator. + */ +class Outputter : public QObject +{ + Q_OBJECT + +protected: + QTextStream stream; + +public: + Outputter(); + +public slots: + /// The slot that will be called for each line emitted by the generator. This method + /// sends the string to stdout and kDebug() + void OnDebugLine(const QString&); +}; diff --git a/drkonqi/kdbgwin/process.cpp b/drkonqi/kdbgwin/process.cpp new file mode 100644 index 00000000..ad6bfd2d --- /dev/null +++ b/drkonqi/kdbgwin/process.cpp @@ -0,0 +1,181 @@ +/****************************************************************** + * + * kdbgwin - Helper application for DrKonqi + * + * This file is part of the KDE project + * + * Copyright (C) 2010 Ilie Halip + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 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 6 of version 3 of the license. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see + *****************************************************************/ + +#include "common.h" +#include "process.h" + +Process::Process() + : m_bValid(FALSE) +{ +} + +// we need debug privileges to open the proces with PROCESS_ALL_ACCESS, and +// to successfully use ReadProcessMemory() +BOOL Process::EnableDebugPrivilege() +{ + kDebug() << "Enabling debug privilege"; + HANDLE hToken = NULL; + + if (!OpenThreadToken(GetCurrentThread(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, FALSE, &hToken)) + { + if (GetLastError() == ERROR_NO_TOKEN) + { + if (!ImpersonateSelf(SecurityImpersonation)) + { + kError() << "ImpersonateSelf() failed: " << GetLastError(); + return FALSE; + } + if (!OpenThreadToken(GetCurrentThread(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, FALSE, &hToken)) + { + kError() << "OpenThreadToken() #2 failed: " << GetLastError(); + return FALSE; + } + } + else + { + kError() << "OpenThreadToken() #1 failed: " << GetLastError(); + return FALSE; + } + } + + LUID luid; + if (!LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &luid)) + { + assert(false); + kError() << "Cannot lookup privilege: " << GetLastError(); + SafeCloseHandle(hToken); + return FALSE; + } + + TOKEN_PRIVILEGES tp; + tp.PrivilegeCount = 1; + tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; + tp.Privileges[0].Luid = luid; + + if (!AdjustTokenPrivileges(hToken, FALSE, &tp, NULL, (PTOKEN_PRIVILEGES) NULL, (PDWORD) NULL)) + { + assert(false); + kError() << "Cannot adjust privilege: " << GetLastError(); + SafeCloseHandle(hToken); + return FALSE; + } + + SafeCloseHandle(hToken); + return TRUE; +} + +BOOL Process::GetInfo(const char* pid, const char* threadId) +{ + kDebug() << "Trying to get info about pid=" << pid; + + DWORD dwPid = DWORD(atoi(pid)); + DWORD dwThread = DWORD(atoi(threadId)); + + // get handle to the process + HANDLE hProcess = NULL; + hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwPid); + assert(hProcess); + if (hProcess == NULL) + { + kError() << "Cannot open process " << dwPid << ": " << GetLastError(); + return m_bValid; + } + m_dwPid = dwPid; + m_hProcess = hProcess; + m_dwThread = dwThread; + + TCHAR procPath[MAX_PATH * 2 + 1] = {0}; + GetModuleFileNameEx(hProcess, NULL, procPath, MAX_PATH*2 + 1); + m_path = QString::fromWCharArray(procPath); + + // we can't get the threads for a single process, so get all system's + // threads, and enumerate through them + HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, NULL); + if (hSnapshot == INVALID_HANDLE_VALUE) + { + kError() << "CreateToolhelp32Snapshot() failed: " << GetLastError(); + assert(false); + return m_bValid; + } + + // get process threads + THREADENTRY32 te; + ZeroMemory(&te, sizeof(te)); + te.dwSize = sizeof(te); + if (Thread32First(hSnapshot, &te)) + { + do + { + if (te.th32OwnerProcessID == dwPid) + { + kDebug() << "Found thread " << te.th32ThreadID << ", adding to list"; + + HANDLE hThread = NULL; + hThread = OpenThread(THREAD_ALL_ACCESS, FALSE, te.th32ThreadID); + assert(hThread); + if (hThread == NULL) + { + kError() << "Cannot open thread " << te.th32ThreadID << ": " << GetLastError(); + continue; + } + + m_threads[te.th32ThreadID] = hThread; + // we have at least 1 thread, make this valid + m_bValid = TRUE; + } + } + while (Thread32Next(hSnapshot, &te)); + } + SafeCloseHandle(hSnapshot); + + assert(m_threads.size() > 0); + + // get process modules + HMODULE hMods[1024]; + DWORD cbNeeded = 0; + if (!EnumProcessModules(hProcess, hMods, ArrayCount(hMods), &cbNeeded)) + { + kError() << "Cannot enumerate modules: " << GetLastError(); + return m_bValid; + } + for (size_t i = 0; i < (cbNeeded / sizeof(hMods[0])); i++) + { + /* + * In Windows, a wchar_t has 2 bytes; GCC defines wchar_t as int, + * which is 4 bytes; so i can't use TCHAR here; better off using ushort + * and casting when necessary + */ + ushort szModName[MAX_PATH]; + if (GetModuleFileNameEx(hProcess, hMods[i], (LPTSTR) szModName, MAX_PATH)) + { + //QString str = QString::fromUtf16(szModName); + //kDebug() << "Got module: " << str; + //m_modules.push_back(QString::fromUtf16(szModName)); + m_modules[QString::fromUtf16(szModName)] = hMods[i]; + } + } + + return m_bValid; +} diff --git a/drkonqi/kdbgwin/process.h b/drkonqi/kdbgwin/process.h new file mode 100644 index 00000000..ff5d1572 --- /dev/null +++ b/drkonqi/kdbgwin/process.h @@ -0,0 +1,107 @@ +/****************************************************************** + * + * kdbgwin - Helper application for DrKonqi + * + * This file is part of the KDE project + * + * Copyright (C) 2010 Ilie Halip + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 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 6 of version 3 of the license. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see + *****************************************************************/ + +#pragma once + +#include "common.h" + +typedef QMap TThreadsMap; +typedef QMap TModulesMap; + +/** + * \brief Describes a process. + * + * This is a helper class when dealing with another process. When kdbgwin starts, + * it attaches to the crashing process and tries to retrieve useful information: + * pid, threads, modules, image path. These will be used later. + */ +class Process +{ +private: + /// Flag to check if the information about this process is valid and can be used + BOOL m_bValid; + + /// Process ID + DWORD m_dwPid; + + /// Failing thread ID - I need this because for the crashing thread, I need to get + /// the CONTEXT from a piece of shared memory in KCrash + DWORD m_dwThread; + + /// A handle to the process + HANDLE m_hProcess; + + /// A QMap which associates thread IDs with opened handles for each + /// of them + TThreadsMap m_threads; + + /// The full path to the executable file which started this process + QString m_path; + + /// A QMap which contains the paths to the loaded modules and + /// handles to each of them + TModulesMap m_modules; + +public: + Process(); + +public: + /// kdbgwin needs to enable the debug privilege in order to read from + /// another process's memory. + static BOOL EnableDebugPrivilege(); + +public: + /// Attaches to the process and gets all required information + /// @return TRUE if operation succeeds + BOOL GetInfo(const char* pid, const char* threadId); + + /// Checks if the information is valid + BOOL IsValid() const + { assert(m_bValid); return m_bValid; } + + /// Get the process ID + DWORD GetId() const + { assert(m_dwPid); return m_dwPid; } + + /// Returns an open handle to the process (opened with PROCESS_ALL_ACCESS) + HANDLE GetHandle() const + { assert(m_hProcess); return m_hProcess; } + + /// Returns the thread ID of the thread that caused the exception + DWORD GetThreadId() const + { assert(m_dwThread); return m_dwThread; } + + /// Returns the threads map + const TThreadsMap& GetThreads() const + { return m_threads; } + + /// Returns the full path to the executable on the disk + const QString& GetPath() const + { return m_path; } + + /// Returns a map of all the loaded modules + const TModulesMap& GetModules() const + { return m_modules; } +}; diff --git a/drkonqi/main.cpp b/drkonqi/main.cpp new file mode 100644 index 00000000..4deed2c9 --- /dev/null +++ b/drkonqi/main.cpp @@ -0,0 +1,121 @@ +/***************************************************************** + * drkonqi - The KDE Crash Handler + * + * Copyright (C) 2000-2003 Hans Petter Bieker + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *****************************************************************/ + +#include +#include + +#include +#include +#include +#include +#include + +#include "drkonqi.h" +#include "drkonqidialog.h" + +static const char version[] = "2.1.5"; +static const char description[] = I18N_NOOP("The KDE Crash Handler gives the user feedback " + "if a program has crashed."); + +int main(int argc, char* argv[]) +{ +#ifndef Q_OS_WIN //krazy:exclude=cpp +// TODO - Investigate and fix this, or work around it as follows... +// #if !defined(Q_OS_WIN) && !defined(Q_OS_MAC) +// When starting Dr Konqi via kdeinit4, Apple OS X aborts us unconditionally for +// using setgid/setuid, even if the privs were those of the logged-in user. +// Drop privs. + setgid(getgid()); + if (setuid(getuid()) < 0 && geteuid() != getuid()) { + exit(255); + } +#endif + + // Prevent KApplication from setting the crash handler. We will set it later... + setenv("KDE_DEBUG", "true", 1); + // Session management is not needed, do not even connect in order to survive longer than ksmserver. + unsetenv("SESSION_MANAGER"); + + KAboutData aboutData("drkonqi", 0, ki18n("The KDE Crash Handler"), + version, ki18n(description), + KAboutData::License_GPL, + ki18n("(C) 2000-2009, The DrKonqi Authors")); + aboutData.addAuthor(ki18nc("@info:credit","Hans Petter Bieker"), KLocalizedString(), + "bieker@kde.org"); + aboutData.addAuthor(ki18nc("@info:credit","Dario Andres Rodriguez"), KLocalizedString(), + "andresbajotierra@gmail.com"); + aboutData.addAuthor(ki18nc("@info:credit","George Kiagiadakis"), KLocalizedString(), + "gkiagia@users.sourceforge.net"); + aboutData.addAuthor(ki18nc("@info:credit","A. L. Spehr"), KLocalizedString(), + "spehr@kde.org"); + aboutData.setProgramIconName("tools-report-bug"); + + KCmdLineArgs::init(argc, argv, &aboutData); + + KCmdLineOptions options; + options.add("signal ", ki18nc("@info:shell","The signal number that was caught")); + options.add("appname ", ki18nc("@info:shell","Name of the program")); + options.add("apppath ", ki18nc("@info:shell","Path to the executable")); + options.add("appversion ", ki18nc("@info:shell","The version of the program")); + options.add("bugaddress
", ki18nc("@info:shell","The bug address to use")); + options.add("programname ", ki18nc("@info:shell","Translated name of the program")); + options.add("pid ", ki18nc("@info:shell","The PID of the program")); + options.add("startupid ", ki18nc("@info:shell","Startup ID of the program")); + options.add("kdeinit", ki18nc("@info:shell","The program was started by kdeinit")); + options.add("safer", ki18nc("@info:shell","Disable arbitrary disk access")); + options.add("restarted", ki18nc("@info:shell","The program has already been restarted")); + options.add("keeprunning", ki18nc("@info:shell","Keep the program running and generate " + "the backtrace at startup")); + options.add("thread ", ki18nc("@info:shell","The thread id of the failing thread")); + KCmdLineArgs::addCmdLineOptions(options); + + KComponentData inst(KCmdLineArgs::aboutData()); + QApplication *qa = + KCmdLineArgs::parsedArgs()->isSet("safer") ? + new QApplication(KCmdLineArgs::qtArgc(), KCmdLineArgs::qtArgv()) : + new KApplication; + qa->setApplicationName(inst.componentName()); + + if (!DrKonqi::init()) { + delete qa; + return 1; + } + + qa->setQuitOnLastWindowClosed(false); + KGlobal::setAllowQuit(true); + + DrKonqiDialog *w = new DrKonqiDialog(); + w->show(); + // Make sure the Dr Konqi dialog comes to the front, whatever the platform + // or window manager, but especially on Apple OS X. + w->raise(); + int ret = qa->exec(); + + DrKonqi::cleanup(); + delete qa; + return ret; +} diff --git a/drkonqi/parser/CMakeLists.txt b/drkonqi/parser/CMakeLists.txt new file mode 100644 index 00000000..d08d0d7f --- /dev/null +++ b/drkonqi/parser/CMakeLists.txt @@ -0,0 +1,9 @@ +set(BACKTRACEPARSER_SRCS + backtraceparser.cpp + backtraceparsergdb.cpp + backtraceparserkdbgwin.cpp + backtraceparsernull.cpp +) + +kde4_add_library(drkonqi_backtrace_parser STATIC ${BACKTRACEPARSER_SRCS}) +target_link_libraries(drkonqi_backtrace_parser ${KDE4_KDECORE_LIBS}) diff --git a/drkonqi/parser/backtraceline.h b/drkonqi/parser/backtraceline.h new file mode 100644 index 00000000..672faeed --- /dev/null +++ b/drkonqi/parser/backtraceline.h @@ -0,0 +1,96 @@ +/* + Copyright (C) 2009-2010 George Kiagiadakis + + 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. +*/ +#ifndef BACKTRACELINE_H +#define BACKTRACELINE_H + +#include +#include + +class BacktraceLine +{ +public: + enum LineType { + Unknown, //unknown type. the default + EmptyLine, //line is empty + Crap, //line is gdb's crap (like "(no debugging symbols found)", + //"[New Thread 0x4275c950 (LWP 11931)]", etc...) + KCrash, //line is "[KCrash Handler]" + ThreadIndicator, //line indicates the current thread, + //ex. "[Current thread is 0 (process 11313)]" + ThreadStart, //line indicates the start of a thread's stack. + SignalHandlerStart, //line indicates the signal handler start + //(contains "") + StackFrame //line is a normal stack frame + }; + + enum LineRating { + /* RATING -- EXAMPLE */ + MissingEverything = 0, // #0 0x0000dead in ?? () + MissingFunction = 1, // #0 0x0000dead in ?? () from /usr/lib/libfoobar.so.4 + MissingLibrary = 2, // #0 0x0000dead in foobar() + MissingSourceFile = 3, // #0 0x0000dead in FooBar::FooBar () from /usr/lib/libfoobar.so.4 + Good = 4, // #0 0x0000dead in FooBar::crash (this=0x0) at /home/user/foobar.cpp:204 + InvalidRating = -1 // (dummy invalid value) + }; + + static const LineRating BestRating = Good; + + BacktraceLine() : d(new Data) {} + + QString toString() const { + return d->m_line; + } + LineType type() const { + return d->m_type; + } + LineRating rating() const { + return d->m_rating; + } + + int frameNumber() const { + return d->m_stackFrameNumber; + } + QString functionName() const { + return d->m_functionName; + } + QString fileName() const { + return d->m_file; + } + QString libraryName() const { + return d->m_library; + } + +protected: + class Data : public QSharedData + { + public: + Data() : m_type(Unknown), m_rating(InvalidRating), + m_stackFrameNumber(-1) {} + + QString m_line; + LineType m_type; + LineRating m_rating; + int m_stackFrameNumber; + QString m_functionName; + QString m_file; + QString m_library; + }; + QExplicitlySharedDataPointer d; +}; + +#endif // BACKTRACELINE_H diff --git a/drkonqi/parser/backtraceparser.cpp b/drkonqi/parser/backtraceparser.cpp new file mode 100644 index 00000000..7f62c979 --- /dev/null +++ b/drkonqi/parser/backtraceparser.cpp @@ -0,0 +1,394 @@ +/* + Copyright (C) 2009-2010 George Kiagiadakis + + 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 "backtraceparser_p.h" +#include "backtraceparsergdb.h" +#include "backtraceparserkdbgwin.h" +#include "backtraceparsernull.h" +#include +#include +#include + +//factory +BacktraceParser *BacktraceParser::newParser(const QString & debuggerName, QObject *parent) +{ + if (debuggerName == "gdb") { + return new BacktraceParserGdb(parent); + } else if (debuggerName == "kdbgwin") { + return new BacktraceParserKdbgwin(parent); + } else { + return new BacktraceParserNull(parent); + } +} + +BacktraceParser::BacktraceParser(QObject *parent) : QObject(parent), d_ptr(NULL) {} +BacktraceParser::~BacktraceParser() { delete d_ptr; } + +void BacktraceParser::connectToGenerator(QObject *generator) +{ + connect(generator, SIGNAL(starting()), this, SLOT(resetState())); + connect(generator, SIGNAL(newLine(QString)), this, SLOT(newLine(QString))); +} + +QString BacktraceParser::parsedBacktrace() const +{ + Q_D(const BacktraceParser); + + QString result; + if (d) { + QList::const_iterator i; + for (i = d->m_linesList.constBegin(); i != d->m_linesList.constEnd(); ++i) { + result += i->toString(); + } + } + return result; +} + +QList BacktraceParser::parsedBacktraceLines() const +{ + Q_D(const BacktraceParser); + return d ? d->m_linesList : QList(); +} + +QString BacktraceParser::simplifiedBacktrace() const +{ + Q_D(const BacktraceParser); + + //if there is no cached usefulness, the data calculation function has not run yet. + if (d && d->m_usefulness == InvalidUsefulness) { + const_cast(this)->calculateRatingData(); + } + + //if there is no d, the debugger has not run yet, so we have no backtrace. + return d ? d->m_simplifiedBacktrace : QString(); +} + +BacktraceParser::Usefulness BacktraceParser::backtraceUsefulness() const +{ + Q_D(const BacktraceParser); + + //if there is no cached usefulness, the data calculation function has not run yet. + if (d && d->m_usefulness == InvalidUsefulness) { + const_cast(this)->calculateRatingData(); + } + + //if there is no d, the debugger has not run yet, + //so we can say that the (inexistent) backtrace is Useless. + return d ? d->m_usefulness : Useless; +} + +QStringList BacktraceParser::firstValidFunctions() const +{ + Q_D(const BacktraceParser); + + //if there is no cached usefulness, the data calculation function has not run yet. + if (d && d->m_usefulness == InvalidUsefulness) { + const_cast(this)->calculateRatingData(); + } + + //if there is no d, the debugger has not run yet, so we have no functions to return. + return d ? d->m_firstUsefulFunctions : QStringList(); +} + + +QSet BacktraceParser::librariesWithMissingDebugSymbols() const +{ + Q_D(const BacktraceParser); + + //if there is no cached usefulness, the data calculation function has not run yet. + if (d && d->m_usefulness == InvalidUsefulness) { + const_cast(this)->calculateRatingData(); + } + + //if there is no d, the debugger has not run yet, so we have no libraries. + return d ? d->m_librariesWithMissingDebugSymbols : QSet(); +} + +void BacktraceParser::resetState() +{ + //reset the state of the parser by getting a new instance of Private + delete d_ptr; + d_ptr = constructPrivate(); +} + +BacktraceParserPrivate *BacktraceParser::constructPrivate() const +{ + return new BacktraceParserPrivate; +} + + +/* This function returns true if the given stack frame line is the base of the backtrace + and thus the parser should not rate any frames below that one. */ +static bool lineIsStackBase(const BacktraceLine & line) +{ + //optimization. if there is no function name, do not bother to check it + if ( line.rating() == BacktraceLine::MissingEverything + || line.rating() == BacktraceLine::MissingFunction ) + return false; + + //this is the base frame for all threads except the main thread + //FIXME that probably works only on linux + if ( line.functionName() == "start_thread" ) + return true; + + QRegExp regExp; + regExp.setPattern("(kde)?main"); //main() or kdemain() is the base for the main thread + if ( regExp.exactMatch(line.functionName()) ) + return true; + + //HACK for better rating. we ignore all stack frames below any function that matches + //the following regular expression. The functions that match this expression are usually + //"QApplicationPrivate::notify_helper", "QApplication::notify" and similar, which + //are used to send any kind of event to the Qt application. All stack frames below this, + //with or without debug symbols, are useless to KDE developers, so we ignore them. + regExp.setPattern("(Q|K)(Core)?Application(Private)?::notify.*"); + if ( regExp.exactMatch(line.functionName()) ) + return true; + + //attempt to recognize crashes that happen after main has returned (bug 200993) + if ( line.functionName() == "~KCleanUpGlobalStatic" || + line.functionName() == "~QGlobalStatic" || + line.functionName() == "exit" || + line.functionName() == "*__GI_exit" ) + return true; + + return false; +} + +/* This function returns true if the given stack frame line is the top of the bactrace + and thus the parser should not rate any frames above that one. This is used to avoid + rating the stack frames of abort(), assert(), Q_ASSERT() and qFatal() */ +static bool lineIsStackTop(const BacktraceLine & line) +{ + //optimization. if there is no function name, do not bother to check it + if ( line.rating() == BacktraceLine::MissingEverything + || line.rating() == BacktraceLine::MissingFunction ) + return false; + + if ( line.functionName().startsWith(QLatin1String("qt_assert")) //qt_assert and qt_assert_x + || line.functionName() == "qFatal" + || line.functionName() == "abort" + || line.functionName() == "*__GI_abort" + || line.functionName() == "*__GI___assert_fail" ) + return true; + + return false; +} + +/* This function returns true if the given stack frame line should be ignored from rating + for some reason. Currently it ignores all libc/libstdc++/libpthread functions. */ +static bool lineShouldBeIgnored(const BacktraceLine & line) +{ + if ( line.libraryName().contains("libc.so") + || line.libraryName().contains("libstdc++.so") + || line.functionName().startsWith(QLatin1String("*__GI_")) //glibc2.9 uses *__GI_ as prefix + || line.libraryName().contains("libpthread.so") + || line.libraryName().contains("libglib-2.0.so") + || line.libraryName().contains("ntdll.dll") + || line.libraryName().contains("kernel32.dll") + || line.functionName().contains("_tmain") + || line.functionName() == QLatin1String("WinMain") ) + return true; + + return false; +} + +static bool isFunctionUseful(const BacktraceLine & line) +{ + //We need the function name + if ( line.rating() == BacktraceLine::MissingEverything + || line.rating() == BacktraceLine::MissingFunction ) { + return false; + } + + //Misc ignores + if ( line.functionName() == "__kernel_vsyscall" + || line.functionName() == "raise" + || line.functionName() == "abort" + || line.functionName() == "__libc_message" + || line.functionName() == "thr_kill" /* *BSD */) { + return false; + } + + //Ignore core Qt functions + //(QObject can be useful in some cases) + if ( line.functionName().startsWith(QLatin1String("QBasicAtomicInt::")) + || line.functionName().startsWith(QLatin1String("QBasicAtomicPointer::")) + || line.functionName().startsWith(QLatin1String("QAtomicInt::")) + || line.functionName().startsWith(QLatin1String("QAtomicPointer::")) + || line.functionName().startsWith(QLatin1String("QMetaObject::")) + || line.functionName().startsWith(QLatin1String("QPointer::")) + || line.functionName().startsWith(QLatin1String("QWeakPointer::")) + || line.functionName().startsWith(QLatin1String("QSharedPointer::")) + || line.functionName().startsWith(QLatin1String("QScopedPointer::")) + || line.functionName().startsWith(QLatin1String("QMetaCallEvent::")) ) { + return false; + } + + //Ignore core Qt containers misc functions + if ( line.functionName().endsWith(QLatin1String("detach")) + || line.functionName().endsWith(QLatin1String("detach_helper")) + || line.functionName().endsWith(QLatin1String("node_create")) + || line.functionName().endsWith(QLatin1String("deref")) + || line.functionName().endsWith(QLatin1String("ref")) + || line.functionName().endsWith(QLatin1String("node_copy")) + || line.functionName().endsWith(QLatin1String("d_func")) ) { + return false; + } + + //Misc Qt stuff + if ( line.functionName() == "qt_message_output" + || line.functionName() == "qt_message" + || line.functionName() == "qFatal" + || line.functionName().startsWith(QLatin1String("qGetPtrHelper")) + || line.functionName().startsWith(QLatin1String("qt_meta_")) ) { + return false; + } + + return true; +} + +static bool isFunctionUsefulForSearch(const BacktraceLine & line) +{ + //Ignore Qt containers (and iterators Q*Iterator) + if ( line.functionName().startsWith(QLatin1String("QList")) + || line.functionName().startsWith(QLatin1String("QLinkedList")) + || line.functionName().startsWith(QLatin1String("QVector")) + || line.functionName().startsWith(QLatin1String("QStack")) + || line.functionName().startsWith(QLatin1String("QQueue")) + || line.functionName().startsWith(QLatin1String("QSet")) + || line.functionName().startsWith(QLatin1String("QMap")) + || line.functionName().startsWith(QLatin1String("QMultiMap")) + || line.functionName().startsWith(QLatin1String("QMapData")) + || line.functionName().startsWith(QLatin1String("QHash")) + || line.functionName().startsWith(QLatin1String("QMultiHash")) + || line.functionName().startsWith(QLatin1String("QHashData")) ) { + return false; + } + + return true; +} + +void BacktraceParser::calculateRatingData() +{ + Q_D(BacktraceParser); + + uint rating = 0, bestPossibleRating = 0, counter = 0; + bool haveSeenStackBase = false; + + QListIterator i(d->m_linesToRate); + i.toBack(); //start from the end of the list + + while( i.hasPrevious() ) { + const BacktraceLine & line = i.previous(); + + if ( !i.hasPrevious() && line.rating() == BacktraceLine::MissingEverything ) { + //Under some circumstances, the very first stack frame is invalid (ex, calling a function + //at an invalid address could result in a stack frame like "0x00000000 in ?? ()"), + //which however does not necessarily mean that the backtrace has a missing symbol on + //the first line. Here we make sure to ignore this line from rating. (bug 190882) + break; //there are no more items anyway, just break the loop + } + + if ( lineIsStackBase(line) ) { + rating = bestPossibleRating = counter = 0; //restart rating ignoring any previous frames + haveSeenStackBase = true; + } else if ( lineIsStackTop(line) ) { + break; //we have reached the top, no need to inspect any more frames + } + + if ( lineShouldBeIgnored(line) ) { + continue; + } + + if ( line.rating() == BacktraceLine::MissingFunction + || line.rating() == BacktraceLine::MissingSourceFile) { + d->m_librariesWithMissingDebugSymbols.insert(line.libraryName().trimmed()); + } + + uint multiplier = ++counter; //give weight to the first lines + rating += static_cast(line.rating()) * multiplier; + bestPossibleRating += static_cast(BacktraceLine::BestRating) * multiplier; + + kDebug() << line.rating() << line.toString(); + } + + //Generate a simplified backtrace + //- Starts from the first useful function + //- Max of 5 lines + //- Replaces garbage with [...] + //At the same time, grab the first three useful functions for search queries + + i.toFront(); //Reuse the list iterator + int functionIndex = 0; + int usefulFunctionsCount = 0; + bool firstUsefulFound = false; + while( i.hasNext() && functionIndex < 5 ) { + const BacktraceLine & line = i.next(); + if ( !lineShouldBeIgnored(line) && isFunctionUseful(line) ) { //Line is not garbage to use + if (!firstUsefulFound) { + firstUsefulFound = true; + } + //Save simplified backtrace line + d->m_simplifiedBacktrace += line.toString(); + + //Fetch three useful functions (only functionName) for search queries + if (usefulFunctionsCount < 3 && isFunctionUsefulForSearch(line) && + !d->m_firstUsefulFunctions.contains(line.functionName())) { + d->m_firstUsefulFunctions.append(line.functionName()); + usefulFunctionsCount++; + } + + functionIndex++; + } else if (firstUsefulFound) { + //Add "[...]" if there are invalid functions in the middle + if (!d->m_simplifiedBacktrace.endsWith(QLatin1String("[...]\n"))) { + d->m_simplifiedBacktrace += QLatin1String("[...]\n"); + } + } + } + + //calculate rating + d->m_usefulness = Useless; + if (rating >= (bestPossibleRating*0.90)) { + d->m_usefulness = ReallyUseful; + } else if (rating >= (bestPossibleRating*0.70)) { + d->m_usefulness = MayBeUseful; + } else if (rating >= (bestPossibleRating*0.40)) { + d->m_usefulness = ProbablyUseless; + } + + //if there is no stack base, the executable is probably stripped, + //so we need to be more strict with rating + if ( !haveSeenStackBase ) { + //less than 4 stack frames is useless + if ( counter < 4 ) { + d->m_usefulness = Useless; + //more than 4 stack frames might have some value, so let's not be so strict, just lower the rating + } else if ( d->m_usefulness > Useless ) { + d->m_usefulness = (Usefulness) (d->m_usefulness - 1); + } + } + + kDebug() << "Rating:" << rating << "out of" << bestPossibleRating << "Usefulness:" + << staticMetaObject.enumerator(staticMetaObject.indexOfEnumerator("Usefulness")).valueToKey(d->m_usefulness); + kDebug() << "90%:" << (bestPossibleRating*0.90) << "70%:" << (bestPossibleRating*0.70) + << "40%:" << (bestPossibleRating*0.40); + kDebug() << "Have seen stack base:" << haveSeenStackBase << "Lines counted:" << counter; +} + +#include "backtraceparser.moc" diff --git a/drkonqi/parser/backtraceparser.h b/drkonqi/parser/backtraceparser.h new file mode 100644 index 00000000..a8554486 --- /dev/null +++ b/drkonqi/parser/backtraceparser.h @@ -0,0 +1,99 @@ +/* + Copyright (C) 2009-2010 George Kiagiadakis + + 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. +*/ +#ifndef BACKTRACEPARSER_H +#define BACKTRACEPARSER_H + +#include "backtraceline.h" +#include +#include +#include +#include +class BacktraceParserPrivate; + +class BacktraceParser : public QObject +{ + Q_OBJECT + Q_DECLARE_PRIVATE(BacktraceParser) + Q_ENUMS(Usefulness) +public: + enum Usefulness { InvalidUsefulness, Useless, ProbablyUseless, MayBeUseful, ReallyUseful }; + + static BacktraceParser *newParser(const QString & debuggerName, QObject *parent = 0); + virtual ~BacktraceParser(); + + /*! Connects the parser to the backtrace generator. + * Any QObject that defines the starting() and newLine(QString) signals will do. + */ + void connectToGenerator(QObject *generator); + + /*! Returns the parsed backtrace. Any garbage that should not be shown to the user is removed. */ + virtual QString parsedBacktrace() const; + + /*! Same as parsedBacktrace(), but the backtrace here is returned as a list of + * BacktraceLine objects, which provide extra information on each line. + */ + virtual QList parsedBacktraceLines() const; + + /*! Returns a simplified version of the backtrace. This backtrace: + * \li Starts from the first useful function + * \li Has maximum 5 lines + * \li Replaces garbage with [...] + */ + virtual QString simplifiedBacktrace() const; + + /*! Returns a value that indicates how much useful is the backtrace that we got */ + virtual Usefulness backtraceUsefulness() const; + + /*! Returns a short list of the first good functions that appear in the backtrace + * (in the crashing thread). This is used for quering for duplicate reports. + */ + virtual QStringList firstValidFunctions() const; + + /*! Returns a list of libraries/executables that are missing debug symbols. */ + virtual QSet librariesWithMissingDebugSymbols() const; + +private Q_SLOTS: + void resetState(); + +protected Q_SLOTS: + /*! Called every time there is a new line from the generator. Subclasses should parse + * the line here and insert it in the m_linesList field of BacktraceParserPrivate. + * If the line is useful for rating as well, it should also be inserted in the m_linesToRate + * field, so that calculateRatingData() can use it. + */ + virtual void newLine(const QString & lineStr) = 0; + +protected: + explicit BacktraceParser(QObject *parent = 0); + + /*! Subclasses should override to provide their own BacktraceParserPrivate instance */ + virtual BacktraceParserPrivate *constructPrivate() const; + + /*! This method should fill the m_usefulness, m_simplifiedBacktrace, m_firstValidFunctions + * and m_librariesWithMissingDebugSymbols members of the BacktraceParserPrivate instance. + * The default implementation uses the lines inserted in m_linesToRate and applies a + * generic algorithm that should work for many debuggers. + */ + virtual void calculateRatingData(); + + BacktraceParserPrivate *d_ptr; +}; + +Q_DECLARE_METATYPE(BacktraceParser::Usefulness) + +#endif // BACKTRACEPARSER_H diff --git a/drkonqi/parser/backtraceparser_p.h b/drkonqi/parser/backtraceparser_p.h new file mode 100644 index 00000000..735efe76 --- /dev/null +++ b/drkonqi/parser/backtraceparser_p.h @@ -0,0 +1,37 @@ +/* + Copyright (C) 2009-2010 George Kiagiadakis + + 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. +*/ +#ifndef BACKTRACEPARSER_P_H +#define BACKTRACEPARSER_P_H + +#include "backtraceparser.h" + +class BacktraceParserPrivate +{ +public: + BacktraceParserPrivate() : m_usefulness(BacktraceParser::InvalidUsefulness) {} + virtual ~BacktraceParserPrivate() {} + + QList m_linesList; + QList m_linesToRate; + QStringList m_firstUsefulFunctions; + QString m_simplifiedBacktrace; + QSet m_librariesWithMissingDebugSymbols; + BacktraceParser::Usefulness m_usefulness; +}; + +#endif //BACKTRACEPARSER_P_H diff --git a/drkonqi/parser/backtraceparsergdb.cpp b/drkonqi/parser/backtraceparsergdb.cpp new file mode 100644 index 00000000..5a6b9199 --- /dev/null +++ b/drkonqi/parser/backtraceparsergdb.cpp @@ -0,0 +1,294 @@ +/* + Copyright (C) 2009-2010 George Kiagiadakis + + 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 "backtraceparsergdb.h" +#include "backtraceparser_p.h" +#include +#include + +//BEGIN BacktraceLineGdb + +class BacktraceLineGdb : public BacktraceLine +{ +public: + BacktraceLineGdb(const QString & line); + +private: + void parse(); + void rate(); +}; + +BacktraceLineGdb::BacktraceLineGdb(const QString & lineStr) + : BacktraceLine() +{ + d->m_line = lineStr; + d->m_functionName = QLatin1String("??"); + parse(); + if (d->m_type == StackFrame) { + rate(); + } +} + +void BacktraceLineGdb::parse() +{ + QRegExp regExp; + + if (d->m_line == "\n") { + d->m_type = EmptyLine; + return; + } else if (d->m_line == "[KCrash Handler]\n") { + d->m_type = KCrash; + return; + } else if (d->m_line.contains("")) { + d->m_type = SignalHandlerStart; + return; + } + + regExp.setPattern("^#([0-9]+)" //matches the stack frame number, ex. "#0" + "[\\s]+(0x[0-9a-f]+[\\s]+in[\\s]+)?" // matches " 0x0000dead in " (optionally) + "((\\(anonymous namespace\\)::)?[^\\(]+)" //matches the function name + //(anything except left parenthesis, which is the start of the arguments section) + //and optionally the prefix "(anonymous namespace)::" + "(\\(.*\\))?" //matches the function arguments + //(when the app doesn't have debugging symbols) + "[\\s]+(const[\\s]+)?" //matches a traling const, if it exists + "\\(.*\\)" //matches the arguments of the function with their values + //(when the app has debugging symbols) + "([\\s]+" //beginning of optional file information + "(from|at)[\\s]+" //matches "from " or "at " + "(.+)" //matches the filename (source file or shared library file) + ")?\n$"); //matches trailing newline. + //the )? at the end closes the parenthesis before [\\s]+(from|at) and + //notes that the whole expression from there is optional. + + if (regExp.exactMatch(d->m_line)) { + d->m_type = StackFrame; + d->m_stackFrameNumber = regExp.cap(1).toInt(); + d->m_functionName = regExp.cap(3).trimmed(); + + if (!regExp.cap(7).isEmpty()) { //we have file information (stuff after from|at) + if (regExp.cap(8) == "at") { //'at' means we have a source file + d->m_file = regExp.cap(9); + } else { //'from' means we have a library + d->m_library = regExp.cap(9); + } + } + + kDebug() << d->m_stackFrameNumber << d->m_functionName << d->m_file << d->m_library; + return; + } + + regExp.setPattern(".*\\(no debugging symbols found\\).*|" + ".*\\[Thread debugging using libthread_db enabled\\].*|" + ".*\\[New .*|" + "0x[0-9a-f]+.*|" + "Current language:.*"); + if (regExp.exactMatch(d->m_line)) { + kDebug() << "garbage detected:" << d->m_line; + d->m_type = Crap; + return; + } + + regExp.setPattern("Thread [0-9]+\\s+\\(Thread [0-9a-fx]+\\s+\\(.*\\)\\):\n"); + if (regExp.exactMatch(d->m_line)) { + kDebug() << "thread start detected:" << d->m_line; + d->m_type = ThreadStart; + return; + } + + regExp.setPattern("\\[Current thread is [0-9]+ \\(.*\\)\\]\n"); + if (regExp.exactMatch(d->m_line)) { + kDebug() << "thread indicator detected:" << d->m_line; + d->m_type = ThreadIndicator; + return; + } + + kDebug() << "line" << d->m_line << "did not match"; +} + +void BacktraceLineGdb::rate() +{ + LineRating r; + + //for explanations, see the LineRating enum definition + if (!fileName().isEmpty()) { + r = Good; + } else if (!libraryName().isEmpty()) { + if (functionName() == "??") { + r = MissingFunction; + } else { + r = MissingSourceFile; + } + } else { + if (functionName() == "??") { + r = MissingEverything; + } else { + r = MissingLibrary; + } + } + + d->m_rating = r; +} + +//END BacktraceLineGdb + +//BEGIN BacktraceParserGdb + +class BacktraceParserGdbPrivate : public BacktraceParserPrivate +{ +public: + BacktraceParserGdbPrivate() + : BacktraceParserPrivate(), + m_possibleKCrashStart(0), m_threadsCount(0), + m_isBelowSignalHandler(false), m_frameZeroAppeared(false) {} + + QString m_lineInputBuffer; + int m_possibleKCrashStart; + int m_threadsCount; + bool m_isBelowSignalHandler; + bool m_frameZeroAppeared; +}; + +BacktraceParserGdb::BacktraceParserGdb(QObject *parent) + : BacktraceParser(parent) +{ +} + +BacktraceParserPrivate* BacktraceParserGdb::constructPrivate() const +{ + return new BacktraceParserGdbPrivate; +} + +void BacktraceParserGdb::newLine(const QString & lineStr) +{ + Q_D(BacktraceParserGdb); + + //when the line is too long, gdb splits it into two lines. + //This breaks parsing and results in two Unknown lines instead of a StackFrame one. + //Here we workaround this by joining the two lines when such a scenario is detected. + if (d->m_lineInputBuffer.isEmpty()) { + d->m_lineInputBuffer = lineStr; + } else if (lineStr.startsWith(QLatin1Char(' ')) || lineStr.startsWith(QLatin1Char('\t'))) { + //gdb always adds some whitespace at the beginning of the second line + d->m_lineInputBuffer.append(lineStr); + } else { + parseLine(d->m_lineInputBuffer); + d->m_lineInputBuffer = lineStr; + } +} + +void BacktraceParserGdb::parseLine(const QString & lineStr) +{ + Q_D(BacktraceParserGdb); + + BacktraceLineGdb line(lineStr); + switch (line.type()) { + case BacktraceLine::Crap: + break; //we don't want crap in the backtrace ;) + case BacktraceLine::ThreadStart: + d->m_linesList.append(line); + d->m_possibleKCrashStart = d->m_linesList.size(); + d->m_threadsCount++; + //reset the state of the flags that need to be per-thread + d->m_isBelowSignalHandler = false; + d->m_frameZeroAppeared = false; // gdb bug workaround flag, see below + break; + case BacktraceLine::SignalHandlerStart: + if (!d->m_isBelowSignalHandler) { + //replace the stack frames of KCrash with a nice message + d->m_linesList.erase(d->m_linesList.begin() + d->m_possibleKCrashStart, d->m_linesList.end()); + d->m_linesList.insert(d->m_possibleKCrashStart, BacktraceLineGdb("[KCrash Handler]\n")); + d->m_isBelowSignalHandler = true; //next line is the first below the signal handler + } else { + //this is not the first time we see a crash handler frame on the same thread, + //so we just add it to the list + d->m_linesList.append(line); + } + break; + case BacktraceLine::StackFrame: + // gdb workaround - (v6.8 at least) - 'thread apply all bt' writes + // the #0 stack frame again at the end. + // Here we ignore this frame by using a flag that tells us whether + // this is the first or the second time that the #0 frame appears in this thread. + // The flag is cleared on each thread start. + if (line.frameNumber() == 0) { + if (d->m_frameZeroAppeared) { + break; //break from the switch so that the frame is not added to the list. + } else { + d->m_frameZeroAppeared = true; + } + } + + //rate the stack frame if we are below the signal handler + if (d->m_isBelowSignalHandler) { + d->m_linesToRate.append(line); + } + + //fall through and append the line to the list + default: + d->m_linesList.append(line); + break; + } +} + +QString BacktraceParserGdb::parsedBacktrace() const +{ + Q_D(const BacktraceParserGdb); + + QString result; + if (d) { + QList::const_iterator i; + for (i = d->m_linesList.constBegin(); i != d->m_linesList.constEnd(); ++i) { + //if there is only one thread, we can omit the thread indicator, + //the thread header and all the empty lines. + if (d->m_threadsCount == 1 && ((*i).type() == BacktraceLine::ThreadIndicator + || (*i).type() == BacktraceLine::ThreadStart + || (*i).type() == BacktraceLine::EmptyLine)) + { + continue; + } + result += i->toString(); + } + } + return result; +} + +QList BacktraceParserGdb::parsedBacktraceLines() const +{ + Q_D(const BacktraceParserGdb); + + QList result; + if (d) { + QList::const_iterator i; + for (i = d->m_linesList.constBegin(); i != d->m_linesList.constEnd(); ++i) { + //if there is only one thread, we can omit the thread indicator, + //the thread header and all the empty lines. + if (d->m_threadsCount == 1 && ((*i).type() == BacktraceLine::ThreadIndicator + || (*i).type() == BacktraceLine::ThreadStart + || (*i).type() == BacktraceLine::EmptyLine)) + { + continue; + } + result.append(*i); + } + } + return result; +} + +//END BacktraceParserGdb + +#include "backtraceparsergdb.moc" diff --git a/drkonqi/parser/backtraceparsergdb.h b/drkonqi/parser/backtraceparsergdb.h new file mode 100644 index 00000000..2991df82 --- /dev/null +++ b/drkonqi/parser/backtraceparsergdb.h @@ -0,0 +1,44 @@ +/* + Copyright (C) 2009-2010 George Kiagiadakis + + 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. +*/ +#ifndef BACKTRACEPARSERGDB_H +#define BACKTRACEPARSERGDB_H + +#include "backtraceparser.h" +class BacktraceParserGdbPrivate; + +class BacktraceParserGdb : public BacktraceParser +{ + Q_OBJECT + Q_DECLARE_PRIVATE(BacktraceParserGdb) +public: + explicit BacktraceParserGdb(QObject *parent = 0); + + virtual QString parsedBacktrace() const; + virtual QList parsedBacktraceLines() const; + +protected: + virtual BacktraceParserPrivate *constructPrivate() const; + +protected Q_SLOTS: + virtual void newLine(const QString & lineStr); + +private: + void parseLine(const QString & lineStr); +}; + +#endif // BACKTRACEPARSERGDB_H diff --git a/drkonqi/parser/backtraceparserkdbgwin.cpp b/drkonqi/parser/backtraceparserkdbgwin.cpp new file mode 100644 index 00000000..739c5e8d --- /dev/null +++ b/drkonqi/parser/backtraceparserkdbgwin.cpp @@ -0,0 +1,126 @@ +/* + Copyright (C) 2010 George Kiagiadakis + + 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 "backtraceparserkdbgwin.h" +#include "backtraceparser_p.h" +#include + +//BEGIN BacktraceLineKdbgwin + +class BacktraceLineKdbgwin : public BacktraceLine +{ +public: + BacktraceLineKdbgwin(const QString & line); + +private: + void parse(); + void rate(); +}; + +BacktraceLineKdbgwin::BacktraceLineKdbgwin(const QString & line) + : BacktraceLine() +{ + d->m_line = line; + parse(); + if (d->m_type == StackFrame) { + rate(); + } +} + +void BacktraceLineKdbgwin::parse() +{ + if (d->m_line == "\n") { + d->m_type = EmptyLine; + return; + } else if (d->m_line == "[KCrash Handler]\n") { + d->m_type = KCrash; + return; + } else if (d->m_line.startsWith(QLatin1String("Loaded"))) { + d->m_type = Crap; //FIXME that's not exactly crap + return; + } + + QRegExp regExp; + regExp.setPattern("([^!]+)!" //match the module name, followed by ! + "([^\\(]+)\\(\\) " //match the function name, followed by () + "\\[([^@]+)@ [\\-\\d]+\\] " // [filename @ line] + "at 0x.*"); //at 0xdeadbeef + + if (regExp.exactMatch(d->m_line)) { + d->m_type = StackFrame; + d->m_library = regExp.cap(1); + d->m_functionName = regExp.cap(2); + d->m_file = regExp.cap(3).trimmed(); + + kDebug() << d->m_functionName << d->m_file << d->m_library; + return; + } + + kDebug() << "line" << d->m_line << "did not match"; +} + +void BacktraceLineKdbgwin::rate() +{ + LineRating r; + + //for explanations, see the LineRating enum definition + if (fileName() != "[unknown]") { + r = Good; + } else if (libraryName() != "[unknown]") { + if (functionName() == "[unknown]") { + r = MissingFunction; + } else { + r = MissingSourceFile; + } + } else { + if (functionName() == "[unknown]") { + r = MissingEverything; + } else { + r = MissingLibrary; + } + } + + d->m_rating = r; +} + +//END BacktraceLineKdbgwin + +//BEGIN BacktraceParserKdbgwin + +BacktraceParserKdbgwin::BacktraceParserKdbgwin(QObject *parent) + : BacktraceParser(parent) +{ +} + +void BacktraceParserKdbgwin::newLine(const QString & lineStr) +{ + Q_D(BacktraceParser); + + BacktraceLineKdbgwin line(lineStr); + switch(line.type()) { + case BacktraceLine::Crap: + break; //we don't want crap in the backtrace ;) + case BacktraceLine::StackFrame: + d->m_linesToRate.append(line); + default: + d->m_linesList.append(line); + } +} + +//END BacktraceParserKdbgwin + +#include "backtraceparserkdbgwin.moc" diff --git a/drkonqi/parser/backtraceparserkdbgwin.h b/drkonqi/parser/backtraceparserkdbgwin.h new file mode 100644 index 00000000..5db30048 --- /dev/null +++ b/drkonqi/parser/backtraceparserkdbgwin.h @@ -0,0 +1,34 @@ +/* + Copyright (C) 2010 George Kiagiadakis + + 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. +*/ +#ifndef BACKTRACEPARSERKDBGWIN_H +#define BACKTRACEPARSERKDBGWIN_H + +#include "backtraceparser.h" + +class BacktraceParserKdbgwin : public BacktraceParser +{ + Q_OBJECT + Q_DECLARE_PRIVATE(BacktraceParser) +public: + explicit BacktraceParserKdbgwin(QObject *parent = 0); + +protected Q_SLOTS: + virtual void newLine(const QString & lineStr); +}; + +#endif // BACKTRACEPARSERKDBGWIN_H diff --git a/drkonqi/parser/backtraceparsernull.cpp b/drkonqi/parser/backtraceparsernull.cpp new file mode 100644 index 00000000..1056a8eb --- /dev/null +++ b/drkonqi/parser/backtraceparsernull.cpp @@ -0,0 +1,57 @@ +/* + Copyright (C) 2009-2010 George Kiagiadakis + + 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 "backtraceparsernull.h" +#include "backtraceparser_p.h" + +//BEGIN BacktraceLineNull + +class BacktraceLineNull : public BacktraceLine +{ +public: + BacktraceLineNull(const QString & line); +}; + +BacktraceLineNull::BacktraceLineNull(const QString & line) + : BacktraceLine() +{ + d->m_line = line; + d->m_rating = MissingEverything; +} + +//END BacktraceLineNull + +//BEGIN BacktraceParserNull + +BacktraceParserNull::BacktraceParserNull(QObject *parent) : BacktraceParser(parent) {} + +BacktraceParserPrivate *BacktraceParserNull::constructPrivate() const +{ + BacktraceParserPrivate *d = BacktraceParser::constructPrivate(); + d->m_usefulness = MayBeUseful; + return d; +} + +void BacktraceParserNull::newLine(const QString & lineStr) +{ + d_ptr->m_linesList.append(BacktraceLineNull(lineStr)); +} + + +//END BacktraceParserNull + +#include "backtraceparsernull.moc" diff --git a/drkonqi/parser/backtraceparsernull.h b/drkonqi/parser/backtraceparsernull.h new file mode 100644 index 00000000..247d0e60 --- /dev/null +++ b/drkonqi/parser/backtraceparsernull.h @@ -0,0 +1,36 @@ +/* + Copyright (C) 2009-2010 George Kiagiadakis + + 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. +*/ +#ifndef BACKTRACEPARSERNULL_H +#define BACKTRACEPARSERNULL_H + +#include "backtraceparser.h" + +class BacktraceParserNull : public BacktraceParser +{ + Q_OBJECT +public: + explicit BacktraceParserNull(QObject *parent = 0); + +protected Q_SLOTS: + virtual void newLine(const QString & lineStr); + +protected: + virtual BacktraceParserPrivate *constructPrivate() const; +}; + +#endif // BACKTRACEPARSERNULL_H diff --git a/drkonqi/reportassistantdialog.cpp b/drkonqi/reportassistantdialog.cpp new file mode 100644 index 00000000..fe8ff4cf --- /dev/null +++ b/drkonqi/reportassistantdialog.cpp @@ -0,0 +1,328 @@ +/******************************************************************* +* reportassistantdialog.cpp +* Copyright 2009,2010 Dario Andres Rodriguez +* +* 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, see . +* +******************************************************************/ + +#include "reportassistantdialog.h" + +#include + +#include + +#include "drkonqi.h" + +#include "parser/backtraceparser.h" +#include "debuggermanager.h" +#include "backtracegenerator.h" + +#include "crashedapplication.h" +#include "aboutbugreportingdialog.h" +#include "reportassistantpages_base.h" +#include "reportinterface.h" + +ReportAssistantDialog::ReportAssistantDialog(QWidget * parent) : + KAssistantDialog(parent), + m_aboutBugReportingDialog(0), + m_reportInterface(new ReportInterface(this)), + m_canClose(false) +{ + KGlobal::ref(); + setAttribute(Qt::WA_DeleteOnClose, true); + + //Set window properties + setWindowTitle(i18nc("@title:window","Crash Reporting Assistant")); + setWindowIcon(KIcon("tools-report-bug")); + + connect(this, SIGNAL(currentPageChanged(KPageWidgetItem*,KPageWidgetItem*)), + this, SLOT(currentPageChanged_slot(KPageWidgetItem*,KPageWidgetItem*))); + connect(this, SIGNAL(helpClicked()), this, SLOT(showHelp())); + + //Create the assistant pages + + //-Introduction Page + KConfigGroup group(KGlobal::config(), "ReportAssistant"); + const bool skipIntroduction = group.readEntry("SkipIntroduction", false); + + if (!skipIntroduction) { + IntroductionPage * m_introduction = new IntroductionPage(this); + + KPageWidgetItem * m_introductionPage = new KPageWidgetItem(m_introduction, + QLatin1String(PAGE_INTRODUCTION_ID)); + m_pageWidgetMap.insert(QLatin1String(PAGE_INTRODUCTION_ID),m_introductionPage); + m_introductionPage->setHeader(i18nc("@title","Welcome to the Reporting Assistant")); + m_introductionPage->setIcon(KIcon("tools-report-bug")); + + addPage(m_introductionPage); + } + + //-Bug Awareness Page + BugAwarenessPage * m_awareness = new BugAwarenessPage(this); + connectSignals(m_awareness); + + KPageWidgetItem * m_awarenessPage = new KPageWidgetItem(m_awareness, + QLatin1String(PAGE_AWARENESS_ID)); + m_pageWidgetMap.insert(QLatin1String(PAGE_AWARENESS_ID),m_awarenessPage); + m_awarenessPage->setHeader(i18nc("@title","What do you know about the crash?")); + m_awarenessPage->setIcon(KIcon("checkbox")); + + //-Crash Information Page + CrashInformationPage * m_backtrace = new CrashInformationPage(this); + connectSignals(m_backtrace); + + KPageWidgetItem * m_backtracePage = new KPageWidgetItem(m_backtrace, + QLatin1String(PAGE_CRASHINFORMATION_ID)); + m_pageWidgetMap.insert(QLatin1String(PAGE_CRASHINFORMATION_ID),m_backtracePage); + m_backtracePage->setHeader(i18nc("@title","Fetching the Backtrace (Automatic Crash Information)")); + m_backtracePage->setIcon(KIcon("run-build")); + + //-Results Page + ConclusionPage * m_conclusions = new ConclusionPage(this); + connectSignals(m_conclusions); + + KPageWidgetItem * m_conclusionsPage = new KPageWidgetItem(m_conclusions, + QLatin1String(PAGE_CONCLUSIONS_ID)); + m_pageWidgetMap.insert(QLatin1String(PAGE_CONCLUSIONS_ID),m_conclusionsPage); + m_conclusionsPage->setHeader(i18nc("@title","Results of the Analyzed Crash Details")); + m_conclusionsPage->setIcon(KIcon("dialog-information")); + connect(m_conclusions, SIGNAL(finished(bool)), this, SLOT(assistantFinished(bool))); + + //TODO Remember to keep the pages ordered + addPage(m_awarenessPage); + addPage(m_backtracePage); + addPage(m_conclusionsPage); + + setMinimumSize(QSize(600, 400)); + resize(minimumSize()); +} + +ReportAssistantDialog::~ReportAssistantDialog() +{ + KGlobal::deref(); +} + +void ReportAssistantDialog::connectSignals(ReportAssistantPage * page) +{ + //React to the changes in the assistant pages + connect(page, SIGNAL(completeChanged(ReportAssistantPage*,bool)), + this, SLOT(completeChanged(ReportAssistantPage*,bool))); +} + +void ReportAssistantDialog::currentPageChanged_slot(KPageWidgetItem * current , KPageWidgetItem * before) +{ + //Page changed + + enableButton(KDialog::Cancel, true); + m_canClose = false; + + //Save data of the previous page + if (before) { + ReportAssistantPage* beforePage = dynamic_cast(before->widget()); + beforePage->aboutToHide(); + } + + //Load data of the current(new) page + if (current) { + ReportAssistantPage* currentPage = dynamic_cast(current->widget()); + enableNextButton(currentPage->isComplete()); + currentPage->aboutToShow(); + } + + //If the current page is the last one, disable all the buttons until the bug is sent + if (current->name() == QLatin1String(PAGE_BZSEND_ID)) { + enableNextButton(false); + enableButton(KDialog::User3, false); //Back button + enableButton(KDialog::User1, false); + } +} + +void ReportAssistantDialog::completeChanged(ReportAssistantPage* page, bool isComplete) +{ + if (page == dynamic_cast(currentPage()->widget())) { + enableNextButton(isComplete); + } +} + +void ReportAssistantDialog::assistantFinished(bool showBack) +{ + //The assistant finished: allow the user to close the dialog normally + + enableNextButton(false); + enableButton(KDialog::User3, showBack); //Back button + enableButton(KDialog::User1, true); + enableButton(KDialog::Cancel, false); + + m_canClose = true; +} + +void ReportAssistantDialog::loginFinished() +{ + //Bugzilla login finished, go to the next page + if (currentPage()->name() == QLatin1String(PAGE_BZLOGIN_ID)) { + next(); + } +} + +void ReportAssistantDialog::showHelp() +{ + //Show the bug reporting guide dialog + if (!m_aboutBugReportingDialog) { + m_aboutBugReportingDialog = new AboutBugReportingDialog(); + } + m_aboutBugReportingDialog->show(); + m_aboutBugReportingDialog->raise(); + m_aboutBugReportingDialog->activateWindow(); + m_aboutBugReportingDialog->showSection(QLatin1String(PAGE_HELP_BEGIN_ID)); + m_aboutBugReportingDialog->showSection(currentPage()->name()); +} + +//Override KAssistantDialog "next" page implementation +void ReportAssistantDialog::next() +{ + //Allow the widget to Ask a question to the user before changing the page + ReportAssistantPage * page = dynamic_cast(currentPage()->widget()); + if (page) { + if (!page->showNextPage()) { + return; + } + } + + const QString name = currentPage()->name(); + + //If the information the user can provide is not useful, skip the backtrace page + if (name == QLatin1String(PAGE_AWARENESS_ID)) + { + //Force save settings in the current page + page->aboutToHide(); + + if (!(m_reportInterface->isBugAwarenessPageDataUseful())) + { + setCurrentPage(m_pageWidgetMap.value(QLatin1String(PAGE_CONCLUSIONS_ID))); + return; + } + } else if (name == QLatin1String(PAGE_CRASHINFORMATION_ID)){ + //Force save settings in current page + page->aboutToHide(); + + //If the crash is worth reporting and it is BKO, skip the Conclusions page + if (m_reportInterface->isWorthReporting() && + DrKonqi::crashedApplication()->bugReportAddress().isKdeBugzilla()) + { + setCurrentPage(m_pageWidgetMap.value(QLatin1String(PAGE_BZLOGIN_ID))); + return; + } + } else if (name == QLatin1String(PAGE_BZDUPLICATES_ID)) { + //a duplicate has been found, yet the report is not being attached + if (m_reportInterface->duplicateId() && !m_reportInterface->attachToBugNumber()) { + setCurrentPage(m_pageWidgetMap.value(QLatin1String(PAGE_CONCLUSIONS_ID))); + return; + } + } + + KAssistantDialog::next(); +} + +//Override KAssistantDialog "back"(previous) page implementation +//It has to mirror the custom next() implementation +void ReportAssistantDialog::back() + { + if (currentPage()->name() == QLatin1String(PAGE_CONCLUSIONS_ID)) + { + if (m_reportInterface->duplicateId() && !m_reportInterface->attachToBugNumber()) { + setCurrentPage(m_pageWidgetMap.value(QLatin1String(PAGE_BZDUPLICATES_ID))); + return; + } + if (!(m_reportInterface->isBugAwarenessPageDataUseful())) + { + setCurrentPage(m_pageWidgetMap.value(QLatin1String(PAGE_AWARENESS_ID))); + return; + } + } + + if (currentPage()->name() == QLatin1String(PAGE_BZLOGIN_ID)) + { + if (m_reportInterface->isWorthReporting() && + DrKonqi::crashedApplication()->bugReportAddress().isKdeBugzilla()) + { + setCurrentPage(m_pageWidgetMap.value(QLatin1String(PAGE_CRASHINFORMATION_ID))); + return; + } + } + + KAssistantDialog::back(); +} + +void ReportAssistantDialog::enableNextButton(bool enabled) +{ + enableButton(KDialog::User2, enabled); +} + +void ReportAssistantDialog::reject() +{ + close(); +} + +void ReportAssistantDialog::closeEvent(QCloseEvent * event) +{ + //Handle the close event + if (!m_canClose) { + //If the assistant didn't finished yet, offer the user the possibilities to + //Close, Cancel, or Save the bug report and Close" + + KGuiItem closeItem = KStandardGuiItem::close(); + closeItem.setText(i18nc("@action:button", "Close the assistant")); + + KGuiItem keepOpenItem = KStandardGuiItem::cancel(); + keepOpenItem.setText(i18nc("@action:button", "Cancel")); + + BacktraceParser::Usefulness use = + DrKonqi::debuggerManager()->backtraceGenerator()->parser()->backtraceUsefulness(); + if (use == BacktraceParser::ReallyUseful || use == BacktraceParser::MayBeUseful) { + //Backtrace is still useful, let the user save it. + KGuiItem saveBacktraceItem = KStandardGuiItem::save(); + saveBacktraceItem.setText(i18nc("@action:button", "Save information and close")); + + int ret = KMessageBox::questionYesNoCancel(this, + i18nc("@info","Do you really want to close the bug reporting assistant? " + "The crash information is still valid, so " + "you can save the report before closing if you want."), + i18nc("@title:window","Close the Assistant"), + closeItem, saveBacktraceItem, keepOpenItem, QString(), KMessageBox::Dangerous); + if(ret == KMessageBox::Yes) + { + event->accept(); + } else if (ret == KMessageBox::No) { + //Save backtrace and accept event (dialog will be closed) + DrKonqi::saveReport(reportInterface()->generateReportFullText(false)); + event->accept(); + } else { + event->ignore(); + } + } else { + if (KMessageBox::questionYesNo(this, i18nc("@info","Do you really want to close the bug " + "reporting assistant?"), + i18nc("@title:window","Close the Assistant"), + closeItem, keepOpenItem, QString(), KMessageBox::Dangerous) + == KMessageBox::Yes) { + event->accept(); + } else { + event->ignore(); + } + } + } else { + event->accept(); + } +} diff --git a/drkonqi/reportassistantdialog.h b/drkonqi/reportassistantdialog.h new file mode 100644 index 00000000..497078ce --- /dev/null +++ b/drkonqi/reportassistantdialog.h @@ -0,0 +1,75 @@ +/******************************************************************* +* reportassistantdialog.h +* Copyright 2009 Dario Andres Rodriguez +* +* 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, see . +* +******************************************************************/ + +#ifndef REPORTASSISTANTDIALOG__H +#define REPORTASSISTANTDIALOG__H + +#include + +#include + +class ReportAssistantPage; +class AboutBugReportingDialog; +class ReportInterface; +class QCloseEvent; + +class ReportAssistantDialog: public KAssistantDialog +{ + Q_OBJECT + +public: + explicit ReportAssistantDialog(QWidget * parent = 0); + ~ReportAssistantDialog(); + + ReportInterface *reportInterface() const { + return m_reportInterface; + } + +private Q_SLOTS: + void currentPageChanged_slot(KPageWidgetItem *, KPageWidgetItem *); + + void completeChanged(ReportAssistantPage*, bool); + + void loginFinished(); + + void assistantFinished(bool); + + void enableNextButton(bool); + + void showHelp(); + + void next(); + void back(); + + //Override default reject method + void reject(); + +private: + void connectSignals(ReportAssistantPage *); + void closeEvent(QCloseEvent*); + + QHash m_pageWidgetMap; + + QPointer m_aboutBugReportingDialog; + ReportInterface * m_reportInterface; + + bool m_canClose; +}; + +#endif diff --git a/drkonqi/reportassistantpage.cpp b/drkonqi/reportassistantpage.cpp new file mode 100644 index 00000000..c4ce69d3 --- /dev/null +++ b/drkonqi/reportassistantpage.cpp @@ -0,0 +1,51 @@ +/******************************************************************* +* reportassistantpage.cpp +* Copyright 2009 Dario Andres Rodriguez +* +* 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, see . +* +******************************************************************/ + +#include "reportassistantpage.h" +#include "reportinterface.h" + +ReportAssistantPage::ReportAssistantPage(ReportAssistantDialog * parent) + : QWidget(parent), m_assistant(parent) +{ +} + +bool ReportAssistantPage::isComplete() +{ + return true; +} + +bool ReportAssistantPage::showNextPage() +{ + return true; +} + +ReportInterface * ReportAssistantPage::reportInterface() const +{ + return m_assistant->reportInterface(); +} + +ReportAssistantDialog * ReportAssistantPage::assistant() const +{ + return m_assistant; +} + +void ReportAssistantPage::emitCompleteChanged() +{ + emit completeChanged(this, isComplete()); +} diff --git a/drkonqi/reportassistantpage.h b/drkonqi/reportassistantpage.h new file mode 100644 index 00000000..d2fb150a --- /dev/null +++ b/drkonqi/reportassistantpage.h @@ -0,0 +1,63 @@ +/******************************************************************* +* reportassistantpage.h +* Copyright 2009 Dario Andres Rodriguez +* +* 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, see . +* +******************************************************************/ + +#ifndef REPORTASSISTANTPAGE__H +#define REPORTASSISTANTPAGE__H + +#include + +#include "reportassistantdialog.h" + +class BugzillaManager; + +/** BASE interface which implements some signals, and +** aboutTo(Show|Hide) functions (also reimplements QWizard behaviour) **/ +class ReportAssistantPage: public QWidget +{ + Q_OBJECT + +public: + explicit ReportAssistantPage(ReportAssistantDialog * parent); + + /** Load the widget data if empty **/ + virtual void aboutToShow() {} + /** Save the widget data **/ + virtual void aboutToHide() {} + /** Tells the KAssistantDialog to enable the Next button **/ + virtual bool isComplete(); + + /** Last time checks to see if you can turn the page **/ + virtual bool showNextPage(); + + ReportInterface *reportInterface() const; + BugzillaManager *bugzillaManager() const; + ReportAssistantDialog * assistant() const; + +public Q_SLOTS: + void emitCompleteChanged(); + +Q_SIGNALS: + /** Tells the KAssistantDialog that the isComplete function changed value **/ + void completeChanged(ReportAssistantPage*, bool); + +private: + ReportAssistantDialog * const m_assistant; +}; + +#endif diff --git a/drkonqi/reportassistantpages_base.cpp b/drkonqi/reportassistantpages_base.cpp new file mode 100644 index 00000000..b8228cf8 --- /dev/null +++ b/drkonqi/reportassistantpages_base.cpp @@ -0,0 +1,465 @@ +/******************************************************************* +* reportassistantpages_base.cpp +* Copyright 2009 Dario Andres Rodriguez +* Copyright 2009 A. L. Spehr +* +* 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, see . +* +******************************************************************/ + +#include "reportassistantpages_base.h" + +#include +#include +#include + +#include +#include +#include +#include + +#include "drkonqi.h" +#include "debuggermanager.h" +#include "crashedapplication.h" +#include "reportinterface.h" +#include "parser/backtraceparser.h" +#include "backtracegenerator.h" +#include "backtracewidget.h" +#include "drkonqi_globals.h" +#include "applicationdetailsexamples.h" + +//BEGIN IntroductionPage + +IntroductionPage::IntroductionPage(ReportAssistantDialog * parent) + : ReportAssistantPage(parent) +{ + ui.setupUi(this); + ui.m_warningIcon->setPixmap(KIcon("dialog-warning").pixmap(64,64)); +} + +//END IntroductionPage + +//BEGIN CrashInformationPage + +CrashInformationPage::CrashInformationPage(ReportAssistantDialog * parent) + : ReportAssistantPage(parent) +{ + m_backtraceWidget = new BacktraceWidget(DrKonqi::debuggerManager()->backtraceGenerator(), this, true); + connect(m_backtraceWidget, SIGNAL(stateChanged()) , this, SLOT(emitCompleteChanged())); + + QVBoxLayout *layout = new QVBoxLayout(this); + layout->setContentsMargins(0,0,0,0); + layout->addWidget(m_backtraceWidget); + layout->addSpacing(10); //We need this for better usability until we get something better + + //If the backtrace was already fetched on the main dialog, save it. + BacktraceGenerator *btGenerator = DrKonqi::debuggerManager()->backtraceGenerator(); + if (btGenerator->state() == BacktraceGenerator::Loaded) { + BacktraceParser::Usefulness use = btGenerator->parser()->backtraceUsefulness(); + if (use != BacktraceParser::Useless && use != BacktraceParser::InvalidUsefulness) { + reportInterface()->setBacktrace(btGenerator->backtrace()); + } + } +} + +void CrashInformationPage::aboutToShow() +{ + m_backtraceWidget->generateBacktrace(); + m_backtraceWidget->hilightExtraDetailsLabel(false); + emitCompleteChanged(); +} + +void CrashInformationPage::aboutToHide() +{ + BacktraceGenerator *btGenerator = DrKonqi::debuggerManager()->backtraceGenerator(); + BacktraceParser::Usefulness use = btGenerator->parser()->backtraceUsefulness(); + + if (use != BacktraceParser::Useless && use != BacktraceParser::InvalidUsefulness) { + reportInterface()->setBacktrace(btGenerator->backtrace()); + } + reportInterface()->setFirstBacktraceFunctions(btGenerator->parser()->firstValidFunctions()); +} + +bool CrashInformationPage::isComplete() +{ + BacktraceGenerator *generator = DrKonqi::debuggerManager()->backtraceGenerator(); + return (generator->state() != BacktraceGenerator::NotLoaded && + generator->state() != BacktraceGenerator::Loading); +} + +bool CrashInformationPage::showNextPage() +{ + BacktraceParser::Usefulness use = + DrKonqi::debuggerManager()->backtraceGenerator()->parser()->backtraceUsefulness(); + + if ((use == BacktraceParser::InvalidUsefulness || use == BacktraceParser::ProbablyUseless + || use == BacktraceParser::Useless) && m_backtraceWidget->canInstallDebugPackages()) { + if ( KMessageBox::Yes == KMessageBox::questionYesNo(this, + i18nc("@info","This crash information is not useful enough, " + "do you want to try to improve it? You will need " + "to install some debugging packages."), + i18nc("@title:window","Crash Information is not useful enough")) ) { + m_backtraceWidget->hilightExtraDetailsLabel(true); + m_backtraceWidget->focusImproveBacktraceButton(); + return false; //Cancel show next, to allow the user to write more + } else { + return true; //Allow to continue + } + } else { + return true; + } +} + +//END CrashInformationPage + +//BEGIN BugAwarenessPage + +BugAwarenessPage::BugAwarenessPage(ReportAssistantDialog * parent) + : ReportAssistantPage(parent) +{ + ui.setupUi(this); + + ui.m_actionsInsideApp->setText(i18nc("@option:check kind of information the user can provide " + "about the crash, %1 is the application name", + "What I was doing when the application \"%1\" crashed", + DrKonqi::crashedApplication()->name())); + + connect(ui.m_rememberGroup, SIGNAL(buttonClicked(int)), this, SLOT(updateCheckBoxes())); + + ui.m_appSpecificDetailsExamples->setVisible(reportInterface()->appDetailsExamples()->hasExamples()); + + connect(ui.m_appSpecificDetailsExamples, SIGNAL(linkActivated(QString)), this, + SLOT(showApplicationDetailsExamples())); +} + +void BugAwarenessPage::aboutToShow() +{ + updateCheckBoxes(); +} + +void BugAwarenessPage::aboutToHide() +{ + //Save data + ReportInterface::Reproducible reproducible = ReportInterface::ReproducibleUnsure; + switch(ui.m_reproducibleBox->currentIndex()) { + case 0: { + reproducible = ReportInterface::ReproducibleUnsure; + break; + } + case 1: { + reproducible = ReportInterface::ReproducibleNever; + break; + } + case 2: { + reproducible = ReportInterface::ReproducibleSometimes; + break; + } + case 3: { + reproducible = ReportInterface::ReproducibleEverytime; + break; + } + } + + reportInterface()->setBugAwarenessPageData(ui.m_rememberCrashSituationYes->isChecked(), + reproducible, + ui.m_actionsInsideApp->isChecked(), + ui.m_unusualSituation->isChecked(), + ui.m_appSpecificDetails->isChecked()); +} + +void BugAwarenessPage::updateCheckBoxes() +{ + const bool rememberSituation = ui.m_rememberCrashSituationYes->isChecked(); + + ui.m_reproducibleLabel->setEnabled(rememberSituation); + ui.m_reproducibleBox->setEnabled(rememberSituation); + + ui.m_informationLabel->setEnabled(rememberSituation); + ui.m_actionsInsideApp->setEnabled(rememberSituation); + ui.m_unusualSituation->setEnabled(rememberSituation); + + ui.m_appSpecificDetails->setEnabled(rememberSituation); + ui.m_appSpecificDetailsExamples->setEnabled(rememberSituation); +} + +void BugAwarenessPage::showApplicationDetailsExamples() +{ + QToolTip::showText(QCursor::pos(), + i18nc("@label examples about information the user can provide", + "Examples: %1", reportInterface()->appDetailsExamples()->examples()), + this); +} + +//END BugAwarenessPage + +//BEGIN ConclusionPage + +ConclusionPage::ConclusionPage(ReportAssistantDialog * parent) + : ReportAssistantPage(parent) + , m_needToReport(false) +{ + m_isBKO = DrKonqi::crashedApplication()->bugReportAddress().isKdeBugzilla(); + + ui.setupUi(this); + + ui.m_showReportInformationButton->setGuiItem( + KGuiItem2(i18nc("@action:button", "&Show Contents of the Report"), + KIcon("document-preview"), + i18nc("@info:tooltip", "Use this button to show the generated " + "report information about this crash."))); + connect(ui.m_showReportInformationButton, SIGNAL(clicked()), + this, SLOT(openReportInformation())); + + ui.m_restartAppOnFinish->setVisible(false); +} + +void ConclusionPage::finishClicked() +{ + //Manual report + if (m_needToReport && !m_isBKO) { + const CrashedApplication *crashedApp = DrKonqi::crashedApplication(); + BugReportAddress reportAddress = crashedApp->bugReportAddress(); + QString report = reportInterface()->generateReportFullText(false); + + if (reportAddress.isEmail()) { + QString subject = "[%1] [%2] Automatic crash report generated by DrKonqi"; + subject= subject.arg(crashedApp->name()); + subject= subject.arg(crashedApp->datetime().toString("yyyy-MM-dd")); + KToolInvocation::invokeMailer(reportAddress, "", "" , subject, report); + } else { + if (KUrl(reportAddress).isRelative()) { //Scheme is missing + reportAddress = QString::fromLatin1("http://%1").arg(reportAddress); + } + KToolInvocation::invokeBrowser(reportAddress); + } + + //Show a copy of the bug reported + openReportInformation(); + } + + //Restart application + if (ui.m_restartAppOnFinish->isChecked()) { + DrKonqi::crashedApplication()->restart(); + } +} + +void ConclusionPage::aboutToShow() +{ + connect(assistant(), SIGNAL(user1Clicked()), this, SLOT(finishClicked())); + ui.m_restartAppOnFinish->setVisible(false); + ui.m_restartAppOnFinish->setChecked(false); + + const bool isDuplicate = reportInterface()->duplicateId() && !reportInterface()->attachToBugNumber(); + m_needToReport = reportInterface()->isWorthReporting() && !isDuplicate; + emitCompleteChanged(); + + BugReportAddress reportAddress = DrKonqi::crashedApplication()->bugReportAddress(); + BacktraceParser::Usefulness use = + DrKonqi::debuggerManager()->backtraceGenerator()->parser()->backtraceUsefulness(); + + QString explanationHTML = QLatin1String("

    "); + + bool backtraceGenerated = true; + switch (use) { + case BacktraceParser::ReallyUseful: { + explanationHTML += QString("
  • %1
  • ").arg(i18nc("@info","The automatically generated " + "crash information is useful.")); + break; + } + case BacktraceParser::MayBeUseful: { + explanationHTML += QString("
  • %1
  • ").arg(i18nc("@info","The automatically generated " + "crash information lacks some " + "details " + "but may be still be useful.")); + break; + } + case BacktraceParser::ProbablyUseless: { + explanationHTML += QString("
  • %1
  • ").arg(i18nc("@info","The automatically generated " + "crash information lacks important details " + "and it is probably not helpful.")); + break; + } + case BacktraceParser::Useless: + case BacktraceParser::InvalidUsefulness: { + BacktraceGenerator::State state = DrKonqi::debuggerManager()->backtraceGenerator()->state(); + if (state == BacktraceGenerator::NotLoaded) { + backtraceGenerated = false; + explanationHTML += QString("
  • %1
  • ").arg(i18nc("@info","The crash information was " + "not generated because it was not needed.")); + } else { + explanationHTML += QString("
  • %1
    %2
  • ").arg( + i18nc("@info","The automatically generated crash " + "information does not contain enough information to be " + "helpful."), + i18nc("@info","You can improve it by " + "installing debugging packages and reloading the crash on " + "the Crash Information page. You can get help with the Bug " + "Reporting Guide by clicking on the " + "Help button.")); + //but this guide doesn't mention bt packages? that's techbase + //->>and the help guide mention techbase page... + } + break; + } + } + + //User can provide enough information + if (reportInterface()->isBugAwarenessPageDataUseful()) { + explanationHTML += QString("
  • %1
  • ").arg(i18nc("@info","The information you can " + "provide could be considered helpful.")); + } else { + explanationHTML += QString("
  • %1
  • ").arg(i18nc("@info","The information you can " + "provide is not considered helpful enough in this case.")); + } + + if (isDuplicate) { + explanationHTML += QString("
  • %1
  • ").arg(i18nc("@info","Your problem has already been " + "reported as bug %1.", reportInterface()->duplicateId())); + } + + explanationHTML += QLatin1String("

"); + + ui.m_explanationLabel->setText(explanationHTML); + + //Hide the "Show contents of the report" button if the backtrace was not generated + ui.m_showReportInformationButton->setVisible(backtraceGenerated); + + if (m_needToReport) { + ui.m_conclusionsLabel->setText(QString("

%1").arg(i18nc("@info","This " + "report is considered helpful."))); + + if (m_isBKO) { + emitCompleteChanged(); + ui.m_howToProceedLabel->setText(i18nc("@info","This application's bugs are reported " + "to the KDE bug tracking system: click Next" + " to start the reporting process. " + "You can manually report at %1", + reportAddress)); + + } else { + if (!DrKonqi::crashedApplication()->hasBeenRestarted()) { + ui.m_restartAppOnFinish->setVisible(true); + } + + ui.m_howToProceedLabel->setText(i18nc("@info","This application is not supported in the " + "KDE bug tracking system. Click " + "Finish to report this bug to " + "the application maintainer. Also, you can manually " + "report at %1.", reportAddress)); + + emit finished(false); + } + + } else { // (m_needToReport) + if (!DrKonqi::crashedApplication()->hasBeenRestarted()) { + ui.m_restartAppOnFinish->setVisible(true); + } + + ui.m_conclusionsLabel->setText(QString("

%1
%2

").arg( + i18nc("@info","This report does not contain enough information for the " + "developers, so the automated bug reporting process is not " + "enabled for this crash."), + i18nc("@info","If you wish, you can go back and change your " + "answers. "))); + + //Only mention "manual reporting" if the backtrace was generated. + //FIXME separate the texts "manual reporting" / "click finish to close" + //"manual reporting" should be ~"manual report using the contents of the report".... + //FIXME for 4.5 (workflow, see ToDo) + if (backtraceGenerated) { + if (m_isBKO) { + ui.m_howToProceedLabel->setText(i18nc("@info","You can manually report this bug " + "at %1. " + "Click Finish to close the " + "assistant.", + reportAddress)); + } else { + ui.m_howToProceedLabel->setText(i18nc("@info","You can manually report this " + "bug to its maintainer at %1. " + "Click Finish to close the " + "assistant.", reportAddress)); + } + } + emit finished(true); + } +} + +void ConclusionPage::aboutToHide() +{ + assistant()->disconnect(SIGNAL(user1Clicked()), this, SLOT(finishClicked())); +} + +void ConclusionPage::openReportInformation() +{ + if (!m_infoDialog) { + QString info = reportInterface()->generateReportFullText(false) + QLatin1Char('\n') + + i18nc("@info/plain report to url/mail address","Report to %1", + DrKonqi::crashedApplication()->bugReportAddress()); + + m_infoDialog = new ReportInformationDialog(info); + } + m_infoDialog->show(); + m_infoDialog->raise(); + m_infoDialog->activateWindow(); +} + +bool ConclusionPage::isComplete() +{ + return (m_isBKO && m_needToReport); +} + +//END ConclusionPage + +//BEGIN ReportInformationDialog + +ReportInformationDialog::ReportInformationDialog(const QString & reportText) + : KDialog() +{ + KGlobal::ref(); + setAttribute(Qt::WA_DeleteOnClose, true); + + setButtons(KDialog::Close | KDialog::User1); + setDefaultButton(KDialog::Close); + setCaption(i18nc("@title:window","Contents of the Report")); + + ui.setupUi(mainWidget()); + ui.m_reportInformationBrowser->setPlainText(reportText); + + setButtonGuiItem(KDialog::User1, KGuiItem2(i18nc("@action:button", "&Save to File..."), + KIcon("document-save"), + i18nc("@info:tooltip", "Use this button to save the " + "generated crash report information to " + "a file. You can use this option to report the " + "bug later."))); + connect(this, SIGNAL(user1Clicked()), this, SLOT(saveReport())); + + setInitialSize(QSize(800, 600)); + KConfigGroup config(KGlobal::config(), "ReportInformationDialog"); + restoreDialogSize(config); +} + +ReportInformationDialog::~ReportInformationDialog() +{ + KConfigGroup config(KGlobal::config(), "ReportInformationDialog"); + saveDialogSize(config); + KGlobal::deref(); +} + +void ReportInformationDialog::saveReport() +{ + DrKonqi::saveReport(ui.m_reportInformationBrowser->toPlainText(), this); +} + +//END ReportInformationDialog + diff --git a/drkonqi/reportassistantpages_base.h b/drkonqi/reportassistantpages_base.h new file mode 100644 index 00000000..148351ae --- /dev/null +++ b/drkonqi/reportassistantpages_base.h @@ -0,0 +1,128 @@ +/******************************************************************* +* reportassistantpages_base.h +* Copyright 2009 Dario Andres Rodriguez +* +* 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, see . +* +******************************************************************/ + +#ifndef REPORTASSISTANTPAGES__BASE__H +#define REPORTASSISTANTPAGES__BASE__H + +#include + +#include "reportassistantdialog.h" +#include "reportassistantpage.h" + +#include "ui_assistantpage_introduction.h" +#include "ui_assistantpage_bugawareness.h" +#include "ui_assistantpage_conclusions.h" +#include "ui_assistantpage_conclusions_dialog.h" + +class BacktraceWidget; + +/** Introduction page **/ +class IntroductionPage: public ReportAssistantPage +{ + Q_OBJECT + +public: + explicit IntroductionPage(ReportAssistantDialog *); + +private: + Ui::AssistantPageIntroduction ui; +}; + +/** Backtrace page **/ +class CrashInformationPage: public ReportAssistantPage +{ + Q_OBJECT + +public: + explicit CrashInformationPage(ReportAssistantDialog *); + + void aboutToShow(); + void aboutToHide(); + bool isComplete(); + bool showNextPage(); + +private: + BacktraceWidget * m_backtraceWidget; +}; + +/** Bug Awareness page **/ +class BugAwarenessPage: public ReportAssistantPage +{ + Q_OBJECT + +public: + explicit BugAwarenessPage(ReportAssistantDialog *); + + void aboutToShow(); + void aboutToHide(); + +private Q_SLOTS: + void showApplicationDetailsExamples(); + + void updateCheckBoxes(); + +private: + Ui::AssistantPageBugAwareness ui; +}; + +/** Conclusions page **/ +class ConclusionPage : public ReportAssistantPage +{ + Q_OBJECT + +public: + explicit ConclusionPage(ReportAssistantDialog *); + + void aboutToShow(); + void aboutToHide(); + + bool isComplete(); + +private Q_SLOTS: + void finishClicked(); + + void openReportInformation(); + +private: + Ui::AssistantPageConclusions ui; + + QPointer m_infoDialog; + + bool m_isBKO; + bool m_needToReport; + +Q_SIGNALS: + void finished(bool); +}; + +class ReportInformationDialog : public KDialog +{ + Q_OBJECT +public: + explicit ReportInformationDialog(const QString & reportText); + ~ReportInformationDialog(); + +private Q_SLOTS: + void saveReport(); + +private: + Ui::AssistantPageConclusionsDialog ui; +}; + +#endif diff --git a/drkonqi/reportinterface.cpp b/drkonqi/reportinterface.cpp new file mode 100644 index 00000000..a91644d8 --- /dev/null +++ b/drkonqi/reportinterface.cpp @@ -0,0 +1,326 @@ +/******************************************************************* +* reportinterface.cpp +* Copyright 2009,2010, 2011 Dario Andres Rodriguez +* Copyright 2009 George Kiagiadakis +* +* 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, see . +* +******************************************************************/ + +#include "reportinterface.h" + +#include +#include + +#include "drkonqi.h" +#include "systeminformation.h" +#include "crashedapplication.h" +#include "debuggermanager.h" +#include "parser/backtraceparser.h" +#include "backtracegenerator.h" +#include "applicationdetailsexamples.h" + +ReportInterface::ReportInterface(QObject *parent) + : QObject(parent), + m_duplicate(0) +{ + m_appDetailsExamples = new ApplicationDetailsExamples(this); + + //Information the user can provide about the crash + m_userRememberCrashSituation = false; + m_reproducible = ReproducibleUnsure; + m_provideActionsApplicationDesktop = false; + m_provideUnusualBehavior = false; + m_provideApplicationConfigurationDetails = false; + + //Do not attach the bug report to any other existent report (create a new one) + m_attachToBugNumber = 0; +} + +void ReportInterface::setBugAwarenessPageData(bool rememberSituation, + Reproducible reproducible, bool actions, + bool unusual, bool configuration) +{ + //Save the information the user can provide about the crash from the assistant page + m_userRememberCrashSituation = rememberSituation; + m_reproducible = reproducible; + m_provideActionsApplicationDesktop = actions; + m_provideUnusualBehavior = unusual; + m_provideApplicationConfigurationDetails = configuration; +} + +bool ReportInterface::isBugAwarenessPageDataUseful() const +{ + //Determine if the assistant should proceed, considering the amount of information + //the user can provide + int rating = selectedOptionsRating(); + + //Minimum information required even for a good backtrace. + bool useful = m_userRememberCrashSituation && + (rating >= 2 || (m_reproducible==ReproducibleSometimes || + m_reproducible==ReproducibleEverytime)); + return useful; +} + +int ReportInterface::selectedOptionsRating() const +{ + //Check how many information the user can provide and generate a rating + int rating = 0; + if (m_provideActionsApplicationDesktop) { + rating += 3; + } + if (m_provideApplicationConfigurationDetails) { + rating += 2; + } + if (m_provideUnusualBehavior) { + rating += 1; + } + return rating; +} + +QString ReportInterface::backtrace() const +{ + return m_backtrace; +} + +void ReportInterface::setBacktrace(const QString & backtrace) +{ + m_backtrace = backtrace; +} + +QStringList ReportInterface::firstBacktraceFunctions() const +{ + return m_firstBacktraceFunctions; +} + +void ReportInterface::setFirstBacktraceFunctions(const QStringList & functions) +{ + m_firstBacktraceFunctions = functions; +} + +QString ReportInterface::title() const +{ + return m_reportTitle; +} + +void ReportInterface::setTitle(const QString & text) +{ + m_reportTitle = text; +} + +void ReportInterface::setDetailText(const QString & text) +{ + m_reportDetailText = text; +} + +void ReportInterface::setPossibleDuplicates(const QStringList & list) +{ + m_possibleDuplicates = list; +} + +QString ReportInterface::generateReportFullText(bool drKonqiStamp) const +{ + //Note: no translations should be done in this function's strings + + const CrashedApplication * crashedApp = DrKonqi::crashedApplication(); + const SystemInformation * sysInfo = DrKonqi::systemInformation(); + + QString report; + + //Program name and versions + report.append(QString("Application: %1 (%2)\n").arg(crashedApp->fakeExecutableBaseName(), + crashedApp->version())); + report.append(QString("KDE Platform Version: %1").arg(sysInfo->kdeVersion())); + if ( sysInfo->compiledSources() ) { + report.append(QString(" (Compiled from sources)\n")); + } else { + report.append(QString("\n")); + } + report.append(QString("Qt Version: %1\n").arg(sysInfo->qtVersion())); + report.append(QString("Operating System: %1\n").arg(sysInfo->operatingSystem())); + + //LSB output or manually selected distro + if ( !sysInfo->lsbRelease().isEmpty() ) { + report.append(QString("Distribution: %1\n").arg(sysInfo->lsbRelease())); + } + report.append(QLatin1String("\n")); + + //Details of the crash situation + if (isBugAwarenessPageDataUseful()) { + report.append(QString("-- Information about the crash:\n")); + if (!m_reportDetailText.isEmpty()) { + report.append(m_reportDetailText.trimmed()); + } else { + //If the user manual reports this crash, he/she should know what to put in here. + //This message is the only one translated in this function + report.append(i18nc("@info/plain","In detail, tell us what you were doing " + " when the application crashed.")); + } + report.append(QLatin1String("\n\n")); + } + + //Crash reproducibility (only if useful) + if (m_reproducible != ReproducibleUnsure) { + if (m_reproducible == ReproducibleEverytime) { + report.append(QString("The crash can be reproduced every time.\n\n")); + } else if (m_reproducible == ReproducibleSometimes) { + report.append(QString("The crash can be reproduced sometimes.\n\n")); + } else if (m_reproducible == ReproducibleNever) { + report.append(QString("The crash does not seem to be reproducible.\n\n")); + } + } + + //Backtrace + report.append(QString("-- Backtrace:\n")); + if (!m_backtrace.isEmpty()) { + QString formattedBacktrace = m_backtrace.trimmed(); + report.append(formattedBacktrace + QLatin1String("\n")); + } else { + report.append(QString("A useful backtrace could not be generated\n")); + } + + //Possible duplicates (selected by the user) + if (!m_possibleDuplicates.isEmpty()) { + report.append(QLatin1String("\n")); + QString duplicatesString; + Q_FOREACH(const QString & dupe, m_possibleDuplicates) { + duplicatesString += QLatin1String("bug ") + dupe + QLatin1String(", "); + } + duplicatesString = duplicatesString.left(duplicatesString.length()-2) + '.'; + report.append(QString("The reporter indicates this bug may be a duplicate of or related to %1\n") + .arg(duplicatesString)); + } + + //Several possible duplicates (by bugzilla query) + if (!m_allPossibleDuplicatesByQuery.isEmpty()) { + report.append(QLatin1String("\n")); + QString duplicatesString; + int count = m_allPossibleDuplicatesByQuery.count(); + for(int i=0; i < count && i < 5; i++) { + duplicatesString += QLatin1String("bug ") + m_allPossibleDuplicatesByQuery.at(i) + + QLatin1String(", "); + } + duplicatesString = duplicatesString.left(duplicatesString.length()-2) + '.'; + report.append(QString("Possible duplicates by query: %1\n").arg(duplicatesString)); + } + + if (drKonqiStamp) { + report.append(QLatin1String("\nReported using DrKonqi")); + } + + return report; +} + +QString ReportInterface::generateAttachmentComment() const +{ + //Note: no translations should be done in this function's strings + + const CrashedApplication * crashedApp = DrKonqi::crashedApplication(); + const SystemInformation * sysInfo = DrKonqi::systemInformation(); + + QString comment; + + //Program name and versions + comment.append(QString("%1 (%2) on KDE Platform %3 using Qt %4\n\n") + .arg(crashedApp->fakeExecutableBaseName()) + .arg(crashedApp->version()) + .arg(sysInfo->kdeVersion()) + .arg(sysInfo->qtVersion())); + + //Details of the crash situation + if (isBugAwarenessPageDataUseful()) { + comment.append(QString("%1\n\n").arg(m_reportDetailText.trimmed())); + } + + //Backtrace (only 6 lines) + comment.append(QString("-- Backtrace (Reduced):\n")); + QString reducedBacktrace = + DrKonqi::debuggerManager()->backtraceGenerator()->parser()->simplifiedBacktrace(); + comment.append(reducedBacktrace.trimmed()); + + return comment; +} + +bool ReportInterface::isWorthReporting() const +{ + //Evaluate if the provided information is useful enough to enable the automatic report + bool needToReport = false; + + if (!m_userRememberCrashSituation) { + //This should never happen... but... + return false; + } + + int rating = selectedOptionsRating(); + + BacktraceParser::Usefulness use = + DrKonqi::debuggerManager()->backtraceGenerator()->parser()->backtraceUsefulness(); + + switch (use) { + case BacktraceParser::ReallyUseful: { + //Perfect backtrace: require at least one option or a 100%-50% reproducible crash + needToReport = (rating >=2) || + (m_reproducible == ReproducibleEverytime || m_reproducible == ReproducibleSometimes); + break; + } + case BacktraceParser::MayBeUseful: { + //Not perfect backtrace: require at least two options or a 100% reproducible crash + needToReport = (rating >=3) || (m_reproducible == ReproducibleEverytime); + break; + } + case BacktraceParser::ProbablyUseless: + //Bad backtrace: require at least two options and always reproducible (strict) + needToReport = (rating >=5) && (m_reproducible == ReproducibleEverytime); + break; + case BacktraceParser::Useless: + case BacktraceParser::InvalidUsefulness: { + needToReport = false; + } + } + + return needToReport; +} + +void ReportInterface::setAttachToBugNumber(uint bugNumber) +{ + //If bugNumber>0, the report is going to be attached to bugNumber + m_attachToBugNumber = bugNumber; +} + +uint ReportInterface::attachToBugNumber() const +{ + return m_attachToBugNumber; +} + +void ReportInterface::setDuplicateId(uint duplicate) +{ + m_duplicate = duplicate; +} + +uint ReportInterface::duplicateId() const +{ + return m_duplicate; +} + +void ReportInterface::setPossibleDuplicatesByQuery(const QStringList & list) +{ + m_allPossibleDuplicatesByQuery = list; +} + +ApplicationDetailsExamples * ReportInterface::appDetailsExamples() const +{ + return m_appDetailsExamples; +} + +#include "reportinterface.moc" diff --git a/drkonqi/reportinterface.h b/drkonqi/reportinterface.h new file mode 100644 index 00000000..3f05c6bd --- /dev/null +++ b/drkonqi/reportinterface.h @@ -0,0 +1,122 @@ +/******************************************************************* +* reportinterface.h +* Copyright 2009, 2011 Dario Andres Rodriguez +* Copyright 2009 George Kiagiadakis +* +* 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, see . +* +******************************************************************/ + +#ifndef REPORTINTERFACE__H +#define REPORTINTERFACE__H + +#include +#include + +class BugReport; + +class ProductMapping; +class ApplicationDetailsExamples; + +class ReportInterface : public QObject +{ + Q_OBJECT +public: + enum Reproducible { ReproducibleUnsure, ReproducibleNever, + ReproducibleSometimes, ReproducibleEverytime }; + + explicit ReportInterface(QObject *parent = 0); + + void setBugAwarenessPageData(bool, Reproducible, bool, bool, bool); + bool isBugAwarenessPageDataUseful() const; + + int selectedOptionsRating() const; + + QStringList firstBacktraceFunctions() const; + void setFirstBacktraceFunctions(const QStringList & functions); + + QString backtrace() const; + void setBacktrace(const QString & backtrace); + + QString title() const; + void setTitle(const QString & text); + + void setDetailText(const QString & text); + void setPossibleDuplicates(const QStringList & duplicatesList); + + QString generateReportFullText(bool drKonqiStamp) const; + + BugReport newBugReportTemplate() const; + void sendBugReport() const; + + QStringList relatedBugzillaProducts() const; + + bool isWorthReporting() const; + + //Zero means creating a new bug report + void setAttachToBugNumber(uint); + uint attachToBugNumber() const; + + //Zero means there is no duplicate + void setDuplicateId(uint); + uint duplicateId() const; + + void setPossibleDuplicatesByQuery(const QStringList &); + + ApplicationDetailsExamples * appDetailsExamples() const; + + bool userCanProvideActionsAppDesktop() const { + return m_provideActionsApplicationDesktop; + } + + bool userCanProvideUnusualBehavior() const { + return m_provideUnusualBehavior; + } + + bool userCanProvideApplicationConfigDetails() const { + return m_provideApplicationConfigurationDetails; + } + +Q_SIGNALS: + void reportSent(int); + void sendReportError(const QString &, const QString &); + +private: + QString generateAttachmentComment() const; + + //Information the user can provide + bool m_userRememberCrashSituation; + Reproducible m_reproducible; + bool m_provideActionsApplicationDesktop; + bool m_provideUnusualBehavior; + bool m_provideApplicationConfigurationDetails; + + + QString m_backtrace; + QStringList m_firstBacktraceFunctions; + + QString m_reportTitle; + QString m_reportDetailText; + QStringList m_possibleDuplicates; + + QStringList m_allPossibleDuplicatesByQuery; + + uint m_attachToBugNumber; + uint m_duplicate; + + ProductMapping * m_productMapping; + ApplicationDetailsExamples * m_appDetailsExamples; +}; + +#endif diff --git a/drkonqi/statuswidget.cpp b/drkonqi/statuswidget.cpp new file mode 100644 index 00000000..2994f5ae --- /dev/null +++ b/drkonqi/statuswidget.cpp @@ -0,0 +1,124 @@ +/******************************************************************* +* statuswidget.cpp +* Copyright 2009,2010 Dario Andres Rodriguez +* +* 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, see . +* +******************************************************************/ +#include "statuswidget.h" + +#include +#include +#include + +#include +#include + +StatusWidget::StatusWidget(QWidget * parent) : + QStackedWidget(parent), + m_cursorStackCount(0), + m_busy(false) +{ + setSizePolicy(QSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed)); + + //Main layout + m_statusPage = new QWidget(this); + m_busyPage = new QWidget(this); + + addWidget(m_statusPage); + addWidget(m_busyPage); + + //Status widget + m_statusLabel = new WrapLabel(); + m_statusLabel->setOpenExternalLinks(true); + m_statusLabel->setTextFormat(Qt::RichText); + //m_statusLabel->setSizePolicy(QSizePolicy(QSizePolicy::Preferred, QSizePolicy::Maximum)); + + QHBoxLayout * statusLayout = new QHBoxLayout(); + statusLayout->setContentsMargins(0,0,0,0); + m_statusPage->setLayout(statusLayout); + + statusLayout->addWidget(m_statusLabel); + + //Busy widget + m_throbberWidget = new KPixmapSequenceWidget(); + m_throbberWidget->setSequence(KPixmapSequence("process-working", 22)); + m_throbberWidget->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed)); + + m_busyLabel = new WrapLabel(); + //m_busyLabel->setSizePolicy(QSizePolicy(QSizePolicy::Preferred, QSizePolicy::Maximum)); + + QHBoxLayout * busyLayout = new QHBoxLayout(); + busyLayout->setContentsMargins(0,0,0,0); + m_busyPage->setLayout(busyLayout); + + busyLayout->addWidget(m_busyLabel); + busyLayout->addWidget(m_throbberWidget); + busyLayout->setAlignment(m_throbberWidget,Qt::AlignVCenter); +} + +void StatusWidget::setBusy(const QString& busyMessage) +{ + m_statusLabel->clear(); + m_busyLabel->setText(busyMessage); + setCurrentWidget(m_busyPage); + setBusyCursor(); + m_busy = true; +} + +void StatusWidget::setIdle(const QString& idleMessage) +{ + m_busyLabel->clear(); + m_statusLabel->setText(idleMessage); + setCurrentWidget(m_statusPage); + setIdleCursor(); + m_busy = false; +} + +void StatusWidget::addCustomStatusWidget(QWidget * widget) +{ + QHBoxLayout * statusLayout = static_cast(m_statusPage->layout()); + + statusLayout->addWidget(widget); + statusLayout->setAlignment(widget,Qt::AlignVCenter); + widget->setSizePolicy(QSizePolicy(QSizePolicy::Maximum, QSizePolicy::Fixed)); +} + +void StatusWidget::setBusyCursor() +{ + QApplication::setOverrideCursor(Qt::WaitCursor); + m_cursorStackCount++; +} + +void StatusWidget::setIdleCursor() +{ + while (m_cursorStackCount!=0) { + QApplication::restoreOverrideCursor(); + m_cursorStackCount--; + } +} + +void StatusWidget::hideEvent(QHideEvent *) +{ + if (m_busy) { + setIdleCursor(); + } +} + +void StatusWidget::showEvent(QShowEvent *) +{ + if (m_busy) { + setBusyCursor(); + } +} diff --git a/drkonqi/statuswidget.h b/drkonqi/statuswidget.h new file mode 100644 index 00000000..60d259e2 --- /dev/null +++ b/drkonqi/statuswidget.h @@ -0,0 +1,91 @@ +/******************************************************************* +* statuswidget.h +* Copyright 2009,2010 Dario Andres Rodriguez +* +* 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, see . +* +******************************************************************/ +#ifndef STATUSWIDGET__H +#define STATUSWIDGET__H + +#include +#include +#include +#include + +class WrapLabel; +class KPixmapSequenceWidget; +class QHideEvent; + +class StatusWidget: public QStackedWidget +{ + Q_OBJECT +public: + explicit StatusWidget(QWidget * parent = 0); + + void setBusy(const QString&); + void setIdle(const QString&); + + void addCustomStatusWidget(QWidget *); + +private: + void showEvent(QShowEvent *); + void hideEvent(QHideEvent *); + + void setBusyCursor(); + void setIdleCursor(); + + WrapLabel * m_statusLabel; + + KPixmapSequenceWidget * m_throbberWidget; + WrapLabel * m_busyLabel; + + QWidget * m_statusPage; + QWidget * m_busyPage; + + int m_cursorStackCount; + bool m_busy; +}; + +//Dummy class to avoid a QLabel+wordWrap height bug +class WrapLabel: public QLabel +{ + Q_OBJECT +public: + explicit WrapLabel(QWidget * parent = 0) : QLabel(parent){ + setWordWrap(true); + } + + void setText(const QString & text) { + QLabel::setText(text); + adjustHeight(); + } + + bool event(QEvent * e) { + if (e->type() == QEvent::ApplicationFontChange || e->type() == QEvent::Resize) { + adjustHeight(); + } + return QLabel::event(e); + } + +private: + void adjustHeight() { + QTextDocument document(text()); + document.setTextWidth(width()); + setMaximumHeight(document.size().height()); + } + +}; + +#endif diff --git a/drkonqi/systeminformation.cpp b/drkonqi/systeminformation.cpp new file mode 100644 index 00000000..86f15460 --- /dev/null +++ b/drkonqi/systeminformation.cpp @@ -0,0 +1,300 @@ +/******************************************************************* +* systeminformation.cpp +* Copyright 2009 Dario Andres Rodriguez +* Copyright 2009 George Kiagiadakis +* +* 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, see . +* +******************************************************************/ + +#include + +#include "systeminformation.h" + +#ifdef HAVE_UNAME +# include +#endif + +#include + +#include +#include +#include +#include +#include +#include + +static const QString OS_UNSPECIFIED = "unspecified"; +static const QString PLATFORM_UNSPECIFIED = "unspecified"; + +SystemInformation::SystemInformation(QObject * parent) + : QObject(parent) + , m_bugzillaOperatingSystem(OS_UNSPECIFIED) + , m_bugzillaPlatform(PLATFORM_UNSPECIFIED) +{ + // NOTE: the relative order is important here + m_bugzillaOperatingSystem = fetchOSBasicInformation(); + m_operatingSystem = fetchOSDetailInformation(); + + tryToSetBugzillaPlatform(); + + KConfigGroup config(KGlobal::config(), "SystemInformation"); + m_compiledSources = config.readEntry("CompiledSources", false); +} + +SystemInformation::~SystemInformation() +{ + KConfigGroup config(KGlobal::config(), "SystemInformation"); + config.writeEntry("CompiledSources", m_compiledSources); + config.sync(); +} + +void SystemInformation::tryToSetBugzillaPlatform() +{ + QString platform = PLATFORM_UNSPECIFIED; + // first, try to guess bugzilla platfrom from the internal OS information + // this should work for BSDs, solaris and windows. + platform = guessBugzillaPlatform(m_bugzillaOperatingSystem); + + // if the internal information is not enough, refer to external information + if (platform == PLATFORM_UNSPECIFIED) { + tryToSetBugzillaPlatformFromExternalInfo(); + } else { + setBugzillaPlatform(platform); + } +} + +void SystemInformation::tryToSetBugzillaPlatformFromExternalInfo() +{ + //Run lsb_release async + QString lsb_release = KStandardDirs::findExe(QLatin1String("lsb_release")); + if ( !lsb_release.isEmpty() ) { + kDebug() << "found lsb_release"; + KProcess *process = new KProcess(); + process->setOutputChannelMode(KProcess::OnlyStdoutChannel); + process->setEnv("LC_ALL", "C"); + *process << lsb_release << "-sd"; + connect(process, SIGNAL(finished(int,QProcess::ExitStatus)), SLOT(lsbReleaseFinished())); + process->start(); + } else { + // when lsb_release is unavailable, turn to /etc/os-release + const QString& osReleaseInfo = fetchOSReleaseInformation(); + const QString& platform = guessBugzillaPlatform(osReleaseInfo); + setBugzillaPlatform(platform); + } +} + +void SystemInformation::lsbReleaseFinished() +{ + KProcess *process = qobject_cast(sender()); + Q_ASSERT(process); + m_lsbRelease = QString::fromLocal8Bit(process->readAllStandardOutput().trimmed()); + process->deleteLater(); + + //Guess distro string + QString platform = guessBugzillaPlatform(m_lsbRelease); + + // if lsb_release doesn't work well, turn to the /etc/os-release file + if (platform == PLATFORM_UNSPECIFIED) { + const QString& osReleaseInfo = fetchOSReleaseInformation(); + platform = guessBugzillaPlatform(osReleaseInfo); + } + + setBugzillaPlatform(platform); +} + +//this function maps the distribution information to an "Hardware Platform" . +//value that is accepted by bugs.kde.org. If the values change on the server . +//side, they need to be updated here as well . +QString SystemInformation::guessBugzillaPlatform(const QString& distroInfo) const +{ + if ( distroInfo.contains("suse",Qt::CaseInsensitive) ) { + return (QLatin1String("openSUSE RPMs")); + } else if ( distroInfo.contains("mint",Qt::CaseInsensitive) ) { + return (QLatin1String("Mint (Ubuntu Based)")); + } else if ( distroInfo.contains("lmde",Qt::CaseInsensitive) ) { + return (QLatin1String("Mint (Debian Based)")); + } else if ( distroInfo.contains("ubuntu",Qt::CaseInsensitive) ) { + return (QLatin1String("Ubuntu Packages")); + } else if ( distroInfo.contains("fedora",Qt::CaseInsensitive) ) { + return (QLatin1String("Fedora RPMs")); + } else if ( distroInfo.contains("redhat",Qt::CaseInsensitive) ) { + return (QLatin1String("RedHat RPMs")); + } else if ( distroInfo.contains("gentoo",Qt::CaseInsensitive) ) { + return (QLatin1String("Gentoo Packages")); + } else if ( distroInfo.contains("mandriva",Qt::CaseInsensitive) ) { + return (QLatin1String("Mandriva RPMs")); + } else if ( distroInfo.contains("mageia",Qt::CaseInsensitive) ) { + return (QLatin1String("Mageia RPMs")); + } else if ( distroInfo.contains("slack",Qt::CaseInsensitive) ) { + return (QLatin1String("Slackware Packages")); + } else if ( distroInfo.contains("pclinuxos",Qt::CaseInsensitive) ) { + return (QLatin1String("PCLinuxOS")); + } else if ( distroInfo.contains("pardus",Qt::CaseInsensitive) ) { + return (QLatin1String("Pardus Packages")); + } else if ( distroInfo.contains("freebsd",Qt::CaseInsensitive) ) { + return (QLatin1String("FreeBSD Ports")); + } else if ( distroInfo.contains("netbsd",Qt::CaseInsensitive) ) { + return (QLatin1String("NetBSD pkgsrc")); + } else if ( distroInfo.contains("openbsd",Qt::CaseInsensitive) ) { + return (QLatin1String("OpenBSD Packages")); + } else if ( distroInfo.contains("solaris",Qt::CaseInsensitive) ) { + return (QLatin1String("Solaris Packages")); + } else if ( distroInfo.contains("chakra",Qt::CaseInsensitive) ) { + return (QLatin1String("Chakra")); + } else if ( distroInfo.contains("ms windows",Qt::CaseInsensitive) ) { + return (QLatin1String("MS Windows")); + } else if ( distroInfo.contains("arch",Qt::CaseInsensitive) ) { + return (QLatin1String("Archlinux Packages")); + } else if ( distroInfo.contains("debian",Qt::CaseInsensitive) ) { + if ( distroInfo.contains("unstable",Qt::CaseInsensitive) ) { + return (QLatin1String("Debian unstable")); + } else if ( distroInfo.contains("testing",Qt::CaseInsensitive) ) { + return (QLatin1String("Debian testing")); + } else { + return (QLatin1String("Debian stable")); + } + } else { + return PLATFORM_UNSPECIFIED; + } +} + +//this function maps the operating system to an OS value that is accepted by bugs.kde.org. +//if the values change on the server side, they need to be updated here as well. +QString SystemInformation::fetchOSBasicInformation() const +{ + //krazy:excludeall=cpp + //Get the base OS string (bugzillaOS) +#if defined(Q_OS_LINUX) + return QLatin1String("Linux"); +#elif defined(Q_OS_FREEBSD) + return QLatin1String("FreeBSD"); +#elif defined(Q_OS_NETBSD) + return QLatin1String("NetBSD"); +#elif defined(Q_OS_OPENBSD) + return QLatin1String("OpenBSD"); +#elif defined(Q_OS_AIX) + return QLatin1String("AIX"); +#elif defined(Q_OS_HPUX) + return QLatin1String("HP-UX"); +#elif defined(Q_OS_IRIX) + return QLatin1String("IRIX"); +#elif defined(Q_OS_OSF) + return QLatin1String("Tru64"); +#elif defined(Q_OS_SOLARIS) + return QLatin1String("Solaris"); +#elif defined(Q_OS_CYGWIN) + return QLatin1String("Cygwin"); +#elif defined(Q_OS_DARWIN) + return QLatin1String("OS X"); +#elif defined(Q_OS_WIN32) + return QLatin1String("MS Windows"); +#else + return OS_UNSPECIFIED; +#endif + +} + +QString SystemInformation::fetchOSDetailInformation() const +{ + //Get complete OS string (and fallback to base string) + QString operatingSystem = m_bugzillaOperatingSystem; + +#ifdef HAVE_UNAME + struct utsname buf; + if (uname(&buf) == -1) { + kDebug() << "call to uname failed" << perror; + } else { + operatingSystem = QString::fromLocal8Bit(buf.sysname) + ' ' + + QString::fromLocal8Bit(buf.release) + ' ' + + QString::fromLocal8Bit(buf.machine); + } +#endif + + return operatingSystem; +} + +QString SystemInformation::fetchOSReleaseInformation() const +{ + QFile data("/etc/os-release"); + if (!data.open(QIODevice::ReadOnly | QIODevice::Text)) { + return QString(); + } + + QMap distroInfos; + + QTextStream in(&data); + while (!in.atEnd()) { + const QString line = in.readLine(); + + // its format is one simple NAME=VALUE per line + // don't use QString.split() here since its value might contain '='' + const int index = line.indexOf('='); + if ( index != -1 ) { + const QString key = line.left(index); + const QString value = line.mid(index+1); + distroInfos.insert(key, value); + } + } + + // the PRETTY_NAME entry should be the most appropriate one, + // but I could be wrong. + const QString prettyName = distroInfos.value("PRETTY_NAME", "Linux"); + return prettyName; +} + +QString SystemInformation::operatingSystem() const +{ + return m_operatingSystem; +} + +QString SystemInformation::bugzillaOperatingSystem() const +{ + return m_bugzillaOperatingSystem; +} + +QString SystemInformation::bugzillaPlatform() const +{ + return m_bugzillaPlatform; +} + +void SystemInformation::setBugzillaPlatform(const QString & platform) +{ + m_bugzillaPlatform = platform; +} + +QString SystemInformation::lsbRelease() const +{ + return m_lsbRelease; +} + +bool SystemInformation::compiledSources() const +{ + return m_compiledSources; +} + +void SystemInformation::setCompiledSources(bool compiled) +{ + m_compiledSources = compiled; +} + +QString SystemInformation::kdeVersion() const +{ + return KDE::versionString(); +} + +QString SystemInformation::qtVersion() const +{ + return qVersion(); +} diff --git a/drkonqi/systeminformation.h b/drkonqi/systeminformation.h new file mode 100644 index 00000000..1ab2e9a3 --- /dev/null +++ b/drkonqi/systeminformation.h @@ -0,0 +1,68 @@ +/******************************************************************* +* systeminformation.h +* Copyright 2009 Dario Andres Rodriguez +* +* 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, see . +* +******************************************************************/ + +#ifndef SYSTEMINFORMATION__H +#define SYSTEMINFORMATION__H + +#include + +class SystemInformation: public QObject +{ + Q_OBJECT + public: + explicit SystemInformation(QObject * parent = 0); + ~SystemInformation(); + + QString bugzillaPlatform() const; + void setBugzillaPlatform(const QString &); + + QString operatingSystem() const; + QString bugzillaOperatingSystem() const; + + QString lsbRelease() const; + + bool compiledSources() const; + void setCompiledSources(bool); + + QString kdeVersion() const; + QString qtVersion() const; + + private Q_SLOTS: + void lsbReleaseFinished(); + + private: + QString fetchOSBasicInformation() const; + QString fetchOSDetailInformation() const; + QString fetchOSReleaseInformation() const; + + QString guessBugzillaPlatform(const QString&) const; + + void tryToSetBugzillaPlatform(); + void tryToSetBugzillaPlatformFromExternalInfo(); + + QString m_operatingSystem; + QString m_bugzillaOperatingSystem; + QString m_bugzillaPlatform; + + QString m_lsbRelease; + + bool m_compiledSources; +}; + +#endif diff --git a/drkonqi/tests/CMakeLists.txt b/drkonqi/tests/CMakeLists.txt new file mode 100644 index 00000000..22b6568a --- /dev/null +++ b/drkonqi/tests/CMakeLists.txt @@ -0,0 +1,2 @@ +add_subdirectory(crashtest) +add_subdirectory(backtraceparsertest) diff --git a/drkonqi/tests/backtraceparsertest/CMakeLists.txt b/drkonqi/tests/backtraceparsertest/CMakeLists.txt new file mode 100644 index 00000000..98c0e58d --- /dev/null +++ b/drkonqi/tests/backtraceparsertest/CMakeLists.txt @@ -0,0 +1,16 @@ +kde4_add_unit_test( backtraceparsertest fakebacktracegenerator.cpp backtraceparsertest.cpp) +target_link_libraries( backtraceparsertest ${QT_QTTEST_LIBRARY} ${QT_QTCORE_LIBRARY} drkonqi_backtrace_parser) + +kde4_add_executable(backtraceparsertest_manual TEST fakebacktracegenerator.cpp backtraceparsertest_manual.cpp) +target_link_libraries(backtraceparsertest_manual drkonqi_backtrace_parser) + +# create a link so that the data directory can be accessed from the build directory, where the test runs +if( NOT WIN32 ) + if ( NOT ${CMAKE_CURRENT_BINARY_DIR} EQUAL ${CMAKE_CURRENT_SOURCE_DIR} ) + add_custom_command(TARGET backtraceparsertest POST_BUILD + COMMAND ${CMAKE_COMMAND} -E create_symlink + ${CMAKE_CURRENT_SOURCE_DIR}/backtraceparsertest_data backtraceparsertest_data + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + ) + endif ( NOT ${CMAKE_CURRENT_BINARY_DIR} EQUAL ${CMAKE_CURRENT_SOURCE_DIR} ) +endif( NOT WIN32 ) diff --git a/drkonqi/tests/backtraceparsertest/README b/drkonqi/tests/backtraceparsertest/README new file mode 100644 index 00000000..2f29e423 --- /dev/null +++ b/drkonqi/tests/backtraceparsertest/README @@ -0,0 +1,25 @@ +This is a unit test for the BacktraceInfo class, which is used in drkonqi +to rate the usefulness of a backtrace. + +This test dynamically loads test data from the "backtraceinfotest_data" directory. +To add new data, simply create a file starting with the "test_" prefix and paste +a backtrace in it. Then, in the "usefulness_map" file, add a line with the following format: + + test_file: UsefulnessValue + +where "test_file" is the exact filename of the file containing the backtrace and +UsefulnessValue is the usefulness value that you expect the backtrace to get. +Whitespaces do not matter, they are ignored. Valid usefulness values can be seen +in backtraceinfotest.h, in the enum BacktraceInfoTest::Usefulness. + +The UsefulnessValue has to be the enum's text representation of the +value and not an integer. For example, having the enum like this: + + enum Usefulness { ReallyUseful = 0, MayBeUseful=1, ProbablyUseless=2, Useless = 3 }; + +"ReallyUseful" is a valid value, but "0" isn't. + + +All files in the "backtraceinfotest_data" directory that do not start with the +"test_" prefix are ignored (except the "usefulness_map" file, which has a special +purpose, as described above) diff --git a/drkonqi/tests/backtraceparsertest/backtraceparsertest.cpp b/drkonqi/tests/backtraceparsertest/backtraceparsertest.cpp new file mode 100644 index 00000000..4cfbbf6b --- /dev/null +++ b/drkonqi/tests/backtraceparsertest/backtraceparsertest.cpp @@ -0,0 +1,129 @@ +/* + Copyright (C) 2009 George Kiagiadakis + + 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, see . +*/ +#include "backtraceparsertest.h" +#include +#include +#include +#include +#include +#include + +#define DATA_DIR "backtraceparsertest_data" +#define SETTINGS_FILE "data.ini" + +BacktraceParserTest::BacktraceParserTest(QObject *parent) + : QObject(parent), + m_settings(DATA_DIR "/" SETTINGS_FILE, QSettings::IniFormat), + m_generator(new FakeBacktraceGenerator(this)) +{ +} + +void BacktraceParserTest::fetchData(const QString & group) +{ + QTest::addColumn("filename"); + QTest::addColumn("result"); + QTest::addColumn("debugger"); + + m_settings.beginGroup(group); + QStringList keys = m_settings.allKeys(); + m_settings.endGroup(); + + foreach(const QString & key, keys) { + QTest::newRow(key.toLocal8Bit()) + << QString(DATA_DIR"/" + key) + << m_settings.value(group + "/" + key).toString() + << m_settings.value("debugger/" + key).toString(); + } +} + +void BacktraceParserTest::btParserUsefulnessTest_data() +{ + fetchData("usefulness"); +} + +void BacktraceParserTest::btParserUsefulnessTest() +{ + QFETCH(QString, filename); + QFETCH(QString, result); + QFETCH(QString, debugger); + + //parse + QSharedPointer parser(BacktraceParser::newParser(debugger)); + parser->connectToGenerator(m_generator); + m_generator->sendData(filename); + + //convert usefulness to string + QMetaEnum metaUsefulness = BacktraceParser::staticMetaObject.enumerator( + BacktraceParser::staticMetaObject.indexOfEnumerator("Usefulness")); + QString btUsefulness = metaUsefulness.valueToKey(parser->backtraceUsefulness()); + + //compare + QEXPECT_FAIL("test_e", "Working on it", Continue); + QCOMPARE(btUsefulness, result); +} + +void BacktraceParserTest::btParserFunctionsTest_data() +{ + fetchData("firstValidFunctions"); +} + +void BacktraceParserTest::btParserFunctionsTest() +{ + QFETCH(QString, filename); + QFETCH(QString, result); + QFETCH(QString, debugger); + + //parse + QSharedPointer parser(BacktraceParser::newParser(debugger)); + parser->connectToGenerator(m_generator); + m_generator->sendData(filename); + + //compare + QString functions = parser->firstValidFunctions().join("|"); + QCOMPARE(functions, result); +} + +void BacktraceParserTest::btParserBenchmark_data() +{ + QTest::addColumn("filename"); + QTest::addColumn("debugger"); + + m_settings.beginGroup("debugger"); + QStringList keys = m_settings.allKeys(); + foreach(const QString & key, keys) { + QTest::newRow(key.toLocal8Bit()) + << QString(DATA_DIR"/" + key) + << m_settings.value(key).toString(); + } + m_settings.endGroup(); +} + +void BacktraceParserTest::btParserBenchmark() +{ + QFETCH(QString, filename); + QFETCH(QString, debugger); + + QSharedPointer parser(BacktraceParser::newParser(debugger)); + parser->connectToGenerator(m_generator); + + QBENCHMARK { + m_generator->sendData(filename); + } +} + +QTEST_MAIN(BacktraceParserTest) +#include "backtraceparsertest.moc" diff --git a/drkonqi/tests/backtraceparsertest/backtraceparsertest.h b/drkonqi/tests/backtraceparsertest/backtraceparsertest.h new file mode 100644 index 00000000..31ff6bb2 --- /dev/null +++ b/drkonqi/tests/backtraceparsertest/backtraceparsertest.h @@ -0,0 +1,45 @@ +/* + Copyright (C) 2009 George Kiagiadakis + + 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, see . +*/ +#ifndef BACKTRACEPARSERTEST_H +#define BACKTRACEPARSERTEST_H + +#include +#include "fakebacktracegenerator.h" +#include "../../parser/backtraceparser.h" + +class BacktraceParserTest : public QObject +{ + Q_OBJECT +public: + BacktraceParserTest(QObject *parent = 0); + +private slots: + void btParserUsefulnessTest_data(); + void btParserUsefulnessTest(); + void btParserFunctionsTest_data(); + void btParserFunctionsTest(); + void btParserBenchmark_data(); + void btParserBenchmark(); + +private: + void fetchData(const QString & group); + + QSettings m_settings; + FakeBacktraceGenerator *m_generator; +}; + +#endif diff --git a/drkonqi/tests/backtraceparsertest/backtraceparsertest_data/data.ini b/drkonqi/tests/backtraceparsertest/backtraceparsertest_data/data.ini new file mode 100644 index 00000000..9b56ab7a --- /dev/null +++ b/drkonqi/tests/backtraceparsertest/backtraceparsertest_data/data.ini @@ -0,0 +1,46 @@ +[usefulness] +test_a=Useless +test_b=MayBeUseful +test_c=ProbablyUseless +test_d=ReallyUseful +test_e=ProbablyUseless +test_f=ProbablyUseless +test_g=ReallyUseful +test_h=ProbablyUseless +test_bug190882=ReallyUseful +test_bug192412_a=Useless +test_bug192412_b=Useless +test_bug168000=MayBeUseful +test_bug200993=ReallyUseful + +[firstValidFunctions] +test_usefulfunctions=SqlQueryMaker::handleTracks|SqlQueryMaker::handleResult|SqlWorkerThread::run +test_usefulfunctions2=Digikam::Album::removeExtraData|~TreeAlbumItem|~TreeAlbumCheckListItem +;should qt_assert appear here?? +test_usefulfunctions3=qt_assert|ExceptionGuard|QMenuPrivate::activateCausedStack +test_usefulfunctions4=KarbonPart::addShape|KoShapeDeleteCommand::undo|QUndoCommand::undo +test_usefulfunctions5=qt_assert|KMetaDataWidget::Private::slotLoadingFinished|KMetaDataWidget::qt_metacall +test_trailing_const=QString::operator==|qStringComparisonHelper|QString::operator!= +test_anon_namespace=formatICalInvitationHelper|KCal::IncidenceFormatter::formatICalInvitationNoHtml|(anonymous namespace)::Formatter::format + +[debugger] +test_a=gdb +test_b=gdb +test_c=gdb +test_d=gdb +test_e=gdb +test_f=gdb +test_g=gdb +test_h=gdb +test_bug190882=gdb +test_bug192412_a=gdb +test_bug192412_b=gdb +test_bug168000=gdb +test_bug200993=gdb +test_usefulfunctions=gdb +test_usefulfunctions2=gdb +test_usefulfunctions3=gdb +test_usefulfunctions4=gdb +test_usefulfunctions5=gdb +test_trailing_const=gdb +test_anon_namespace=gdb diff --git a/drkonqi/tests/backtraceparsertest/backtraceparsertest_data/test_a b/drkonqi/tests/backtraceparsertest/backtraceparsertest_data/test_a new file mode 100644 index 00000000..529c44c7 --- /dev/null +++ b/drkonqi/tests/backtraceparsertest/backtraceparsertest_data/test_a @@ -0,0 +1,140 @@ +[?1034h(no debugging symbols found) +(no debugging symbols found) +(no debugging symbols found) +(no debugging symbols found) +(no debugging symbols found) +(no debugging symbols found) +(no debugging symbols found) +(no debugging symbols found) +[Thread debugging using libthread_db enabled] +(no debugging symbols found) +(no debugging symbols found) +(no debugging symbols found) +(no debugging symbols found) +(no debugging symbols found) +(no debugging symbols found) +(no debugging symbols found) +(no debugging symbols found) +(no debugging symbols found) +(no debugging symbols found) +(no debugging symbols found) +(no debugging symbols found) +(no debugging symbols found) +(no debugging symbols found) +(no debugging symbols found) +(no debugging symbols found) +(no debugging symbols found) +(no debugging symbols found) +(no debugging symbols found) +(no debugging symbols found) +(no debugging symbols found) +(no debugging symbols found) +(no debugging symbols found) +(no debugging symbols found) +(no debugging symbols found) +(no debugging symbols found) +(no debugging symbols found) +(no debugging symbols found) +(no debugging symbols found) +(no debugging symbols found) +(no debugging symbols found) +(no debugging symbols found) +(no debugging symbols found) +(no debugging symbols found) +(no debugging symbols found) +(no debugging symbols found) +(no debugging symbols found) +(no debugging symbols found) +(no debugging symbols found) +(no debugging symbols found) +(no debugging symbols found) +(no debugging symbols found) +(no debugging symbols found) +(no debugging symbols found) +(no debugging symbols found) +(no debugging symbols found) +(no debugging symbols found) +(no debugging symbols found) +(no debugging symbols found) +(no debugging symbols found) +(no debugging symbols found) +(no debugging symbols found) +(no debugging symbols found) +(no debugging symbols found) +(no debugging symbols found) +(no debugging symbols found) +(no debugging symbols found) +(no debugging symbols found) +(no debugging symbols found) +(no debugging symbols found) +(no debugging symbols found) +(no debugging symbols found) +(no debugging symbols found) +(no debugging symbols found) +(no debugging symbols found) +(no debugging symbols found) +(no debugging symbols found) +(no debugging symbols found) +(no debugging symbols found) +(no debugging symbols found) +(no debugging symbols found) +(no debugging symbols found) +(no debugging symbols found) +(no debugging symbols found) +(no debugging symbols found) +(no debugging symbols found) +(no debugging symbols found) +(no debugging symbols found) +0x00007fdda985f5b5 in waitpid () from /lib/libpthread.so.0 +[Current thread is 0 (process 12545)] + +Thread 1 (Thread 0x7fddaac76740 (LWP 12545)): +#0 0x00007fdda985f5b5 in waitpid () from /lib/libpthread.so.0 +#1 0x00007fddaa7e660d in KCrash::startDirectly (argv=0x7fffb2db2800) at /home/gkiagia/kde/src/KDE/kdelibs/kdeui/util/kcrash.cpp:436 +#2 0x00007fddaa7e7581 in KCrash::defaultCrashHandler (sig=11) at /home/gkiagia/kde/src/KDE/kdelibs/kdeui/util/kcrash.cpp:340 +#3 +#5 0x00007f8c3562e645 in raise () from /lib64/libc.so.6 +#6 0x00007f8c3562fc33 in abort () from /lib64/libc.so.6 +#7 0x00007f8c37500df9 in ?? () from /usr/X11R6/lib64/libGL.so.1 +#8 0x00007f8c333f1abe in ?? () from /usr/X11R6/lib64/libGLcore.so.1 +#9 0x00007f8c333f2423 in ?? () from /usr/X11R6/lib64/libGLcore.so.1 +#10 0x00007f8c331493c4 in ?? () from /usr/X11R6/lib64/libGLcore.so.1 +#11 0x00007f8c32de6aa6 in ?? () from /usr/X11R6/lib64/libGLcore.so.1 +#12 0x00007f8c3b6e1c23 in ?? () from /usr/lib64/libkdeinit4_kwin.so +#13 0x00007f8c3b6e23bc in ?? () from /usr/lib64/libkdeinit4_kwin.so +#14 0x00007f8c3b6d2316 in ?? () from /usr/lib64/libkdeinit4_kwin.so +#15 0x00007f8c3b67c2ca in ?? () from /usr/lib64/libkdeinit4_kwin.so +#16 0x00007f8c3a8ca454 in QMetaObject::activate(QObject*, int, int, void**) () + from /usr/lib64/libQtCore.so.4 +#17 0x00007f8c3a8c4da3 in QObject::event(QEvent*) () + from /usr/lib64/libQtCore.so.4 +#18 0x00007f8c37e871bd in QApplicationPrivate::notify_helper(QObject*, QEvent*) + () from /usr/lib64/libQtGui.so.4 +#19 0x00007f8c37e8ef8a in QApplication::notify(QObject*, QEvent*) () + from /usr/lib64/libQtGui.so.4 +#20 0x00007f8c362c2bab in KApplication::notify(QObject*, QEvent*) () + from /usr/lib64/libkdeui.so.5 +#21 0x00007f8c3a8b6091 in QCoreApplication::notifyInternal(QObject*, QEvent*) + () from /usr/lib64/libQtCore.so.4 +#22 0x00007f8c3a8e21c0 in ?? () from /usr/lib64/libQtCore.so.4 +#23 0x00007f8c3a8de58d in ?? () from /usr/lib64/libQtCore.so.4 +#24 0x00007f8c344760db in g_main_context_dispatch () + from /usr/lib64/libglib-2.0.so.0 +#25 0x00007f8c344798ad in ?? () from /usr/lib64/libglib-2.0.so.0 +#26 0x00007f8c34479a6b in g_main_context_iteration () + from /usr/lib64/libglib-2.0.so.0 +#27 0x00007f8c3a8de4ef in + QEventDispatcherGlib::processEvents(QFlags) () + from /usr/lib64/libQtCore.so.4 +#28 0x00007f8c37f179bf in ?? () from /usr/lib64/libQtGui.so.4 +#29 0x00007f8c3a8b49a2 in + QEventLoop::processEvents(QFlags) () from + /usr/lib64/libQtCore.so.4 +#30 0x00007f8c3a8b4b2d in + QEventLoop::exec(QFlags) () from + /usr/lib64/libQtCore.so.4 +#31 0x00007f8c3a8b6ffd in QCoreApplication::exec() () + from /usr/lib64/libQtCore.so.4 +#32 0x00007f8c3b691c21 in kdemain () from /usr/lib64/libkdeinit4_kwin.so +#33 0x00007f8c3561a586 in __libc_start_main () from /lib64/libc.so.6 +#34 0x0000000000400889 in _start () \ No newline at end of file diff --git a/drkonqi/tests/backtraceparsertest/backtraceparsertest_data/test_anon_namespace b/drkonqi/tests/backtraceparsertest/backtraceparsertest_data/test_anon_namespace new file mode 100644 index 00000000..a9ea1337 --- /dev/null +++ b/drkonqi/tests/backtraceparsertest/backtraceparsertest_data/test_anon_namespace @@ -0,0 +1,53 @@ +Thread 1 (Thread 0x7fe4756407f0 (LWP 9487)): +#0 0x00007fdda985f5b5 in waitpid () from /lib/libpthread.so.0 +#1 0x00007fddaa7e660d in KCrash::startDirectly (argv=0x7fffb2db2800) at /home/gkiagia/kde/src/KDE/kdelibs/kdeui/util/kcrash.cpp:436 +#2 0x00007fddaa7e7581 in KCrash::defaultCrashHandler (sig=11) at /home/gkiagia/kde/src/KDE/kdelibs/kdeui/util/kcrash.cpp:340 +#3 +#6 0x00007fe46fd0ac57 in formatICalInvitationHelper(QString, KCal::Calendar*, KCal::InvitationFormatterHelper*, bool, KDateTime::Spec) () from /usr/lib64/libkcal.so.4 +#7 0x00007fe46fd0d130 in KCal::IncidenceFormatter::formatICalInvitationNoHtml(QString, KCal::Calendar*, KCal::InvitationFormatterHelper*) () from /usr/lib64/libkcal.so.4 +#8 0x00007fe451a3d7d0 in (anonymous namespace)::Formatter::format(KMail::Interface::BodyPart*, KMail::HtmlWriter*) const () from /usr/lib64/kde4/kmail_bodypartformatter_text_calendar.so +#9 0x00007fe45d93a319 in KMail::ObjectTreeParser::parseObjectTree(partNode*) () from /usr/lib64/libkmailprivate.so.4 +#10 0x00007fe45d93ad55 in KMail::ObjectTreeParser::stdChildHandling(partNode*) () from /usr/lib64/libkmailprivate.so.4 +#11 0x00007fe45d93b006 in KMail::ObjectTreeParser::processMultiPartAlternativeSubtype(partNode*, KMail::ProcessResult&) () from /usr/lib64/libkmailprivate.so.4 +#12 0x00007fe45d93aa31 in KMail::ObjectTreeParser::parseObjectTree(partNode*) () from /usr/lib64/libkmailprivate.so.4 +#13 0x00007fe45d93ad55 in KMail::ObjectTreeParser::stdChildHandling(partNode*) () from /usr/lib64/libkmailprivate.so.4 +#14 0x00007fe45d93b094 in KMail::ObjectTreeParser::processMultiPartMixedSubtype(partNode*, KMail::ProcessResult&) () from /usr/lib64/libkmailprivate.so.4 +#15 0x00007fe45d93aa31 in KMail::ObjectTreeParser::parseObjectTree(partNode*) () from /usr/lib64/libkmailprivate.so.4 +#16 0x00007fe45d7bf3e6 in KMReaderWin::parseMsg(KMMessage*) () from /usr/lib64/libkmailprivate.so.4 +#17 0x00007fe45d7b45e1 in KMReaderWin::displayMessage() () from /usr/lib64/libkmailprivate.so.4 +#18 0x00007fe45d7b47ce in KMReaderWin::updateReaderWin() () from /usr/lib64/libkmailprivate.so.4 +#19 0x00007fe45d7b50d5 in KMReaderWin::update(KMail::Interface::Observable*) () from /usr/lib64/libkmailprivate.so.4 +#20 0x00007fe45d9da719 in KMail::ISubject::notify() () from /usr/lib64/libkmailprivate.so.4 +#21 0x00007fe45d6d980c in KMMessage::updateBodyPart(QString, QByteArray const&) () from /usr/lib64/libkmailprivate.so.4 +#22 0x00007fe45d9b0f59 in KMail::ImapJob::slotGetMessageResult(KJob*) () from /usr/lib64/libkmailprivate.so.4 +#23 0x00007fe45d9b2b1b in KMail::ImapJob::qt_metacall(QMetaObject::Call, int, void**) () from /usr/lib64/libkmailprivate.so.4 +#24 0x00007fe473b8a19a in QMetaObject::activate(QObject*, QMetaObject const*, int, void**) () from /usr/lib64/libQtCore.so.4 +#25 0x00007fe473f7b382 in KJob::result(KJob*) () from /usr/lib64/libkdecore.so.5 +#26 0x00007fe473f7b60f in KJob::emitResult() () from /usr/lib64/libkdecore.so.5 +#27 0x00007fe4713c1733 in KIO::SimpleJob::slotFinished() () from /usr/lib64/libkio.so.5 +#28 0x00007fe4713c1bf3 in KIO::TransferJob::slotFinished() () from /usr/lib64/libkio.so.5 +#29 0x00007fe4713bfbb1 in KIO::TransferJob::qt_metacall(QMetaObject::Call, int, void**) () from /usr/lib64/libkio.so.5 +#30 0x00007fe473b8a19a in QMetaObject::activate(QObject*, QMetaObject const*, int, void**) () from /usr/lib64/libQtCore.so.4 +#31 0x00007fe471480301 in KIO::SlaveInterface::dispatch(int, QByteArray const&) () from /usr/lib64/libkio.so.5 +#32 0x00007fe47147d693 in KIO::SlaveInterface::dispatch() () from /usr/lib64/libkio.so.5 +#33 0x00007fe47147158d in KIO::Slave::gotInput() () from /usr/lib64/libkio.so.5 +#34 0x00007fe471471bcc in KIO::Slave::qt_metacall(QMetaObject::Call, int, void**) () from /usr/lib64/libkio.so.5 +#35 0x00007fe473b8a19a in QMetaObject::activate(QObject*, QMetaObject const*, int, void**) () from /usr/lib64/libQtCore.so.4 +#36 0x00007fe4713914d7 in KIO::ConnectionPrivate::dequeue() () from /usr/lib64/libkio.so.5 +#37 0x00007fe4713915fd in KIO::Connection::qt_metacall(QMetaObject::Call, int, void**) () from /usr/lib64/libkio.so.5 +#38 0x00007fe473b86d89 in QObject::event(QEvent*) () from /usr/lib64/libQtCore.so.4 +#39 0x00007fe472f8a4bc in QApplicationPrivate::notify_helper(QObject*, QEvent*) () from /usr/lib64/libQtGui.so.4 +#40 0x00007fe472f90914 in QApplication::notify(QObject*, QEvent*) () from /usr/lib64/libQtGui.so.4 +#41 0x00007fe47452da86 in KApplication::notify(QObject*, QEvent*) () from /usr/lib64/libkdeui.so.5 +#42 0x00007fe473b7718c in QCoreApplication::notifyInternal(QObject*, QEvent*) () from /usr/lib64/libQtCore.so.4 +#43 0x00007fe473b79907 in QCoreApplicationPrivate::sendPostedEvents(QObject*, int, QThreadData*) () from /usr/lib64/libQtCore.so.4 +#44 0x00007fe473ba0a03 in postEventSourceDispatch(_GSource*, int (*)(void*), void*) () from /usr/lib64/libQtCore.so.4 +#45 0x00007fe46b430e6e in g_main_context_dispatch () from /usr/lib64/libglib-2.0.so.0 +#46 0x00007fe46b434838 in ?? () from /usr/lib64/libglib-2.0.so.0 +#47 0x00007fe46b434960 in g_main_context_iteration () from /usr/lib64/libglib-2.0.so.0 +#48 0x00007fe473ba0543 in QEventDispatcherGlib::processEvents(QFlags) () from /usr/lib64/libQtCore.so.4 +#49 0x00007fe47302711e in QGuiEventDispatcherGlib::processEvents(QFlags) () from /usr/lib64/libQtGui.so.4 +#50 0x00007fe473b75ab2 in QEventLoop::processEvents(QFlags) () from /usr/lib64/libQtCore.so.4 +#51 0x00007fe473b75e8c in QEventLoop::exec(QFlags) () from /usr/lib64/libQtCore.so.4 +#52 0x00007fe473b79bcb in QCoreApplication::exec() () from /usr/lib64/libQtCore.so.4 +#53 0x00000000004041f7 in main () diff --git a/drkonqi/tests/backtraceparsertest/backtraceparsertest_data/test_b b/drkonqi/tests/backtraceparsertest/backtraceparsertest_data/test_b new file mode 100644 index 00000000..51ac8a48 --- /dev/null +++ b/drkonqi/tests/backtraceparsertest/backtraceparsertest_data/test_b @@ -0,0 +1,70 @@ +[Current thread is 0 (LWP 2636)] + +Thread 4 (Thread 0xa9226b90 (LWP 2637)): +#0 0xb8076424 in __kernel_vsyscall () +#1 0xb6982c55 in pthread_cond_wait@@GLIBC_2.3.2 () from /lib/libpthread.so.0 +#2 0xb69fa6a2 in QWaitCondition::wait () from /usr/lib/libQtCore.so.4 +#3 0xb7af1a0a in ?? () from /usr/lib/libQtNetwork.so.4 +#4 0x0923ebb0 in ?? () +#5 0x0923ebac in ?? () +#6 0xffffffff in ?? () +#7 0xb6b72000 in ?? () +#8 0xa92262f0 in ?? () +#9 0xb808541b in _dl_fixup () from /lib/ld-linux.so.2 +#10 0xb69f9910 in ?? () from /usr/lib/libQtCore.so.4 +#11 0x0923eba0 in ?? () +#12 0x00000000 in ?? () + +Thread 3 (Thread 0xa892ab90 (LWP 2648)): +#0 0xb8076424 in __kernel_vsyscall () +#1 0xb6982c55 in pthread_cond_wait@@GLIBC_2.3.2 () from /lib/libpthread.so.0 +#2 0xb69fa6a2 in QWaitCondition::wait () from /usr/lib/libQtCore.so.4 +#3 0xa949380a in RenderThread::run () from + /usr/lib/kde4/plasma_wallpaper_image.so +#4 0xb69f9910 in ?? () from /usr/lib/libQtCore.so.4 +#5 0x08f7ee5c in ?? () +#6 0x00000000 in ?? () + +Thread 2 (Thread 0xa714fb90 (LWP 2703)): +#0 0xb8076424 in __kernel_vsyscall () +#1 0xb67d7ab1 in select () from /lib/libc.so.6 +#2 0xb6ab7bf7 in ?? () from /usr/lib/libQtCore.so.4 +#3 0x00000008 in ?? () +#4 0xa714f278 in ?? () +#5 0x00000000 in ?? () + +Thread 1 (Thread 0xb4909730 (LWP 2636)): +#0 0xa985f5b5 in waitpid () from /lib/libpthread.so.0 +#1 0xaa7e660d in KCrash::startDirectly (argv=0x7fffb2db2800) at /home/gkiagia/kde/src/KDE/kdelibs/kdeui/util/kcrash.cpp:436 +#2 0xaa7e7581 in KCrash::defaultCrashHandler (sig=11) at /home/gkiagia/kde/src/KDE/kdelibs/kdeui/util/kcrash.cpp:340 +#3 +#6 0xb721455d in QGraphicsLinearLayout::removeItem () from + /usr/lib/libQtGui.so.4 +#7 0xb804c3f0 in PanelAppletOverlay::mousePressEvent () from + /usr/lib/libkdeinit4_plasma.so +#8 0xb6d2fd1a in QWidget::event () from /usr/lib/libQtGui.so.4 +#9 0xb6cddaec in QApplicationPrivate::notify_helper () from + /usr/lib/libQtGui.so.4 +#10 0xb6ce4863 in QApplication::notify () from /usr/lib/libQtGui.so.4 +#11 0xb78a7f2d in KApplication::notify () from /usr/lib/libkdeui.so.5 +#12 0xb6ad3f31 in QCoreApplication::notifyInternal () from + /usr/lib/libQtCore.so.4 +#13 0xb6ce5be3 in QApplicationPrivate::sendMouseEvent () from + /usr/lib/libQtGui.so.4 +#14 0xb6d42715 in ?? () from /usr/lib/libQtGui.so.4 +#15 0x09b3eb08 in ?? () +#16 0xbfb933dc in ?? () +#17 0x09b3eb08 in ?? () +#18 0x092de818 in ?? () +#19 0xb7310bd0 in ?? () from /usr/lib/libQtGui.so.4 +#20 0xb7310bd4 in ?? () from /usr/lib/libQtGui.so.4 +#21 0xbfb9345c in ?? () +#22 0x00000028 in ?? () +#23 0x09a53f60 in ?? () +#24 0x09a53000 in ?? () +#25 0xb6779bae in mem2chunk_check () from /lib/libc.so.6 +#26 0xb6d41bcd in QApplication::x11ProcessEvent () from /usr/lib/libQtGui.so.4 +#27 0xb6d67172 in ?? () from /usr/lib/libQtGui.so.4 +#28 0x08dbb988 in ?? () +#29 0xbfb938bc in ?? () +#30 0x00000000 in ?? () \ No newline at end of file diff --git a/drkonqi/tests/backtraceparsertest/backtraceparsertest_data/test_bug168000 b/drkonqi/tests/backtraceparsertest/backtraceparsertest_data/test_bug168000 new file mode 100644 index 00000000..ae9a4538 --- /dev/null +++ b/drkonqi/tests/backtraceparsertest/backtraceparsertest_data/test_bug168000 @@ -0,0 +1,16 @@ +[Current thread is 0 (process 12545)] + +Thread 1 (Thread 0x7fddaac76740 (LWP 12545)): +#0 0x00007fdda985f5b5 in waitpid () from /lib/libpthread.so.0 +#1 0x00007fddaa7e660d in KCrash::startDirectly (argv=0x7fffb2db2800) at /home/gkiagia/kde/src/KDE/kdelibs/kdeui/util/kcrash.cpp:436 +#2 0x00007fddaa7e7581 in KCrash::defaultCrashHandler (sig=11) at /home/gkiagia/kde/src/KDE/kdelibs/kdeui/util/kcrash.cpp:340 +#3 +#5 0x00007f50e99f776f in QWidget::testAttribute_helper (this=0x6e6440, + attribute=Qt::WA_WState_Created) at kernel/qwidget.cpp:9081 +#6 0x00007f50e9a37d51 in QWidget::mapFromGlobal (this=0x6e6440, + pos=@0x7ffff350ff90) + at ../../include/QtGui/../../src/gui/kernel/qwidget.h:991 +#7 0x00007f50e9a37e79 in QWidget::mapFromGlobal (this=0x6e6450, + pos=@0x7ffff350ff90) at kernel/qwidget_x11.cpp:1069 +#8 0x000000000041fb6c in _start () +#0 0x00007f50e75ff241 in nanosleep () from /lib/libc.so.6 diff --git a/drkonqi/tests/backtraceparsertest/backtraceparsertest_data/test_bug190882 b/drkonqi/tests/backtraceparsertest/backtraceparsertest_data/test_bug190882 new file mode 100644 index 00000000..52be7b3c --- /dev/null +++ b/drkonqi/tests/backtraceparsertest/backtraceparsertest_data/test_bug190882 @@ -0,0 +1,78 @@ +[Current thread is 0 (process 12545)] + +Thread 1 (Thread 0x7fddaac76740 (LWP 12545)): +#0 0x00007fdda985f5b5 in waitpid () from /lib/libpthread.so.0 +#1 0x00007fddaa7e660d in KCrash::startDirectly (argv=0x7fffb2db2800) at /home/gkiagia/kde/src/KDE/kdelibs/kdeui/util/kcrash.cpp:436 +#2 0x00007fddaa7e7581 in KCrash::defaultCrashHandler (sig=11) at /home/gkiagia/kde/src/KDE/kdelibs/kdeui/util/kcrash.cpp:340 +#3 +#6 0x00000000 in ?? () +#7 0xb74b192b in QGLWidget::glDraw (this=0xad928a8) at /local/src/qt-x11-opensource-src-4.5.1/src/opengl/qgl.cpp:3458 +#8 0xb74b041e in QGLWidget::paintEvent (this=0xad928a8) at /local/src/qt-x11-opensource-src-4.5.1/src/opengl/qgl.cpp:3261 +#9 0xb5b8d942 in QWidget::event (this=0xad928a8, event=0xbffe9924) at /local/src/qt-x11-opensource-src-4.5.1/src/gui/kernel/qwidget.cpp:7659 +#10 0xb74b36bc in QGLWidget::event (this=0xad928a8, e=0xbffe9924) at /local/src/qt-x11-opensource-src-4.5.1/src/opengl/qgl.cpp:3244 +#11 0xb5b3827c in QApplicationPrivate::notify_helper (this=0x8088b68, receiver=0xad928a8, e=0xbffe9924) at /local/src/qt-x11-opensource-src-4.5.1/src/gui/kernel/qapplication.cpp:4057 +#12 0xb5b3fa54 in QApplication::notify (this=0xbffec4bc, receiver=0xad928a8, e=0xbffe9924) at /local/src/qt-x11-opensource-src-4.5.1/src/gui/kernel/qapplication.cpp:4022 +#13 0xb69ee93b in KApplication::notify (this=0xbffec4bc, receiver=0xad928a8, event=0xbffe9924) at /local/svn/kde/trunk/KDE/kdelibs/kdeui/kernel/kapplication.cpp:307 +#14 0xb7fcddcb in QCoreApplication::notifyInternal (this=0xbffec4bc, receiver=0xad928a8, event=0xbffe9924) at /local/src/qt-x11-opensource-src-4.5.1/src/corelib/kernel/qcoreapplication.cpp:610 +#15 0xb5b96205 in QCoreApplication::sendSpontaneousEvent (event=, receiver=) + at ../../include/QtCore/../../../../src/qt-x11-opensource-src-4.5.1/src/corelib/kernel/qcoreapplication.h:216 +#16 QWidgetPrivate::drawWidget (event=, receiver=) at /local/src/qt-x11-opensource-src-4.5.1/src/gui/kernel/qwidget.cpp:5052 +#17 0xb5d5133d in QWidgetPrivate::repaint_sys (this=0xad928f0, rgn=...) at /local/src/qt-x11-opensource-src-4.5.1/src/gui/painting/qbackingstore.cpp:1536 +#18 0xb5b86d5e in QWidgetPrivate::syncBackingStore (this=0xad928f0) at /local/src/qt-x11-opensource-src-4.5.1/src/gui/kernel/qwidget.cpp:1599 +#19 0xb5b8e123 in QWidget::event (this=0xad928a8, event=0x874e6b0) at /local/src/qt-x11-opensource-src-4.5.1/src/gui/kernel/qwidget.cpp:7799 +#20 0xb74b36bc in QGLWidget::event (this=0xad928a8, e=0x874e6b0) at /local/src/qt-x11-opensource-src-4.5.1/src/opengl/qgl.cpp:3244 +#21 0xb5b3827c in QApplicationPrivate::notify_helper (this=0x8088b68, receiver=0xad928a8, e=0x874e6b0) at /local/src/qt-x11-opensource-src-4.5.1/src/gui/kernel/qapplication.cpp:4057 +#22 0xb5b3fa54 in QApplication::notify (this=0xbffec4bc, receiver=0xad928a8, e=0x874e6b0) at /local/src/qt-x11-opensource-src-4.5.1/src/gui/kernel/qapplication.cpp:4022 +#23 0xb69ee93b in KApplication::notify (this=0xbffec4bc, receiver=0xad928a8, event=0x874e6b0) at /local/svn/kde/trunk/KDE/kdelibs/kdeui/kernel/kapplication.cpp:307 +#24 0xb7fcddcb in QCoreApplication::notifyInternal (this=0xbffec4bc, receiver=0xad928a8, event=0x874e6b0) at /local/src/qt-x11-opensource-src-4.5.1/src/corelib/kernel/qcoreapplication.cpp:610 +#25 0xb7fce898 in QCoreApplication::sendEvent (event=, receiver=) + at ../../include/QtCore/../../../../src/qt-x11-opensource-src-4.5.1/src/corelib/kernel/qcoreapplication.h:213 +#26 QCoreApplicationPrivate::sendPostedEvents (event=, receiver=) at /local/src/qt-x11-opensource-src-4.5.1/src/corelib/kernel/qcoreapplication.cpp:1247 +#27 0xb7fcea6d in QCoreApplication::sendPostedEvents (receiver=0x0, event_type=0) at /local/src/qt-x11-opensource-src-4.5.1/src/corelib/kernel/qcoreapplication.cpp:1140 +#28 0xb7ff952f in QCoreApplication::sendPostedEvents () at ../../include/QtCore/../../../../src/qt-x11-opensource-src-4.5.1/src/corelib/kernel/qcoreapplication.h:218 +#29 postEventSourceDispatch () at /local/src/qt-x11-opensource-src-4.5.1/src/corelib/kernel/qeventdispatcher_glib.cpp:209 +#30 0xb56839c8 in g_main_context_dispatch () from /usr/lib/libglib-2.0.so.0 +#31 0xb5687083 in ?? () from /usr/lib/libglib-2.0.so.0 +#32 0xb5687241 in g_main_context_iteration () from /usr/lib/libglib-2.0.so.0 +#33 0xb7ff915c in QEventDispatcherGlib::processEvents (this=0x80506a8, flags=...) at /local/src/qt-x11-opensource-src-4.5.1/src/corelib/kernel/qeventdispatcher_glib.cpp:324 +#34 0xb5bd7845 in QGuiEventDispatcherGlib::processEvents (this=0x80506a8, flags=...) at /local/src/qt-x11-opensource-src-4.5.1/src/gui/kernel/qguieventdispatcher_glib.cpp:202 +#35 0xb7fcc359 in QEventLoop::processEvents (this=0xbffea210, flags=...) at /local/src/qt-x11-opensource-src-4.5.1/src/corelib/kernel/qeventloop.cpp:149 +#36 0xb7fcc7a2 in QEventLoop::exec (this=0xbffea210, flags=...) at /local/src/qt-x11-opensource-src-4.5.1/src/corelib/kernel/qeventloop.cpp:200 +#37 0xb6057bb3 in QDialog::exec (this=0xbffea250) at /local/src/qt-x11-opensource-src-4.5.1/src/gui/dialogs/qdialog.cpp:498 +#38 0xad36ef3c in Glsl::slotActivate (this=0xa47fc40) at /local/svn/kde/trunk/koffice/krita/plugins/extensions/glsl/glsl.cc:71 +#39 0xad36efb5 in Glsl::qt_metacall (this=0xa47fc40, _c=QMetaObject::InvokeMetaMethod, _id=4, _a=0xbffea3e8) at /local/build/koffice/krita/plugins/extensions/glsl/glsl.moc:68 +#40 0xb7fe3ef8 in QMetaObject::activate (sender=0xa4825d8, from_signal_index=5, to_signal_index=6, argv=0xbffea3e8) at /local/src/qt-x11-opensource-src-4.5.1/src/corelib/kernel/qobject.cpp:3111 +#41 0xb7fe4388 in QMetaObject::activate (sender=0xa4825d8, m=0xb63cc108, from_local_signal_index=1, to_local_signal_index=2, argv=0xbffea3e8) + at /local/src/qt-x11-opensource-src-4.5.1/src/corelib/kernel/qobject.cpp:3205 +#42 0xb5b31b91 in QAction::triggered (this=0xa4825d8, _t1=false) at .moc/release-shared/moc_qaction.cpp:236 +#43 0xb5b33112 in QAction::activate (this=0xa4825d8, event=QAction::Trigger) at /local/src/qt-x11-opensource-src-4.5.1/src/gui/kernel/qaction.cpp:1160 +#44 0xb5fb25cc in QMenuPrivate::activateCausedStack (this=0xa5b6370, causedStack=..., action=0xa4825d8, action_e=QAction::Trigger, self=true) + at /local/src/qt-x11-opensource-src-4.5.1/src/gui/widgets/qmenu.cpp:967 +#45 0xb5fb8ceb in QMenuPrivate::activateAction (this=0xa5b6370, action=0xa4825d8, action_e=QAction::Trigger, self=) + at /local/src/qt-x11-opensource-src-4.5.1/src/gui/widgets/qmenu.cpp:1060 +#46 0xb5fb98b7 in QMenu::mouseReleaseEvent (this=0xa5ae708, e=0xbffeac44) at /local/src/qt-x11-opensource-src-4.5.1/src/gui/widgets/qmenu.cpp:2254 +#47 0xb6ac8fc2 in KMenu::mouseReleaseEvent (this=0xa5ae708, e=0xbffeac44) at /local/svn/kde/trunk/KDE/kdelibs/kdeui/widgets/kmenu.cpp:456 +#48 0xb5b8db77 in QWidget::event (this=0xa5ae708, event=0xbffeac44) at /local/src/qt-x11-opensource-src-4.5.1/src/gui/kernel/qwidget.cpp:7521 +#49 0xb5fbbbbc in QMenu::event (this=0xa5ae708, e=0xbffeac44) at /local/src/qt-x11-opensource-src-4.5.1/src/gui/widgets/qmenu.cpp:2353 +#50 0xb5b3827c in QApplicationPrivate::notify_helper (this=0x8088b68, receiver=0xa5ae708, e=0xbffeac44) at /local/src/qt-x11-opensource-src-4.5.1/src/gui/kernel/qapplication.cpp:4057 +#51 0xb5b4032b in QApplication::notify (this=0xbffec4bc, receiver=0xa5ae708, e=0xbffeac44) at /local/src/qt-x11-opensource-src-4.5.1/src/gui/kernel/qapplication.cpp:3759 +#52 0xb69ee93b in KApplication::notify (this=0xbffec4bc, receiver=0xa5ae708, event=0xbffeac44) at /local/svn/kde/trunk/KDE/kdelibs/kdeui/kernel/kapplication.cpp:307 +#53 0xb7fcddcb in QCoreApplication::notifyInternal (this=0xbffec4bc,receiver=0xa5ae708, event=0xbffeac44) at /local/src/qt-x11-opensource-src-4.5.1/src/corelib/kernel/qcoreapplication.cpp:610 +#54 0xb5b3f3ae in QCoreApplication::sendSpontaneousEvent (event=, receiver=) + at ../../include/QtCore/../../../../src/qt-x11-opensource-src-4.5.1/src/corelib/kernel/qcoreapplication.h:216 +#55 QApplicationPrivate::sendMouseEvent (event=,receiver=) at /local/src/qt-x11-opensource-src-4.5.1/src/gui/kernel/qapplication.cpp:2925 +#56 0xb5bae8c0 in QETWidget::translateMouseEvent (this=0xa5ae708, event=0xbffec1a0) at /local/src/qt-x11-opensource-src-4.5.1/src/gui/kernel/qapplication_x11.cpp:4382 +#57 0xb5bad8cc in QApplication::x11ProcessEvent (this=0xbffec4bc,event=0xbffec1a0) at /local/src/qt-x11-opensource-src-4.5.1/src/gui/kernel/qapplication_x11.cpp:3444 +#58 0xb5bd8112 in x11EventSourceDispatch (s=0x808ba38, callback=0,user_data=0x0) at /local/src/qt-x11-opensource-src-4.5.1/src/gui/kernel/qguieventdispatcher_glib.cpp:146 +#59 0xb56839c8 in g_main_context_dispatch () from /usr/lib/libglib-2.0.so.0 +#60 0xb5687083 in ?? () from /usr/lib/libglib-2.0.so.0 +#61 0xb5687241 in g_main_context_iteration () from /usr/lib/libglib-2.0.so.0 +#62 0xb7ff915c in QEventDispatcherGlib::processEvents (this=0x80506a8,flags=...) at /local/src/qt-x11-opensource-src-4.5.1/src/corelib/kernel/qeventdispatcher_glib.cpp:324 +#63 0xb5bd7845 in QGuiEventDispatcherGlib::processEvents (this=0x80506a8,flags=...) at /local/src/qt-x11-opensource-src-4.5.1/src/gui/kernel/qguieventdispatcher_glib.cpp:202 +#64 0xb7fcc359 in QEventLoop::processEvents (this=0xbffec444, flags=...) at /local/src/qt-x11-opensource-src-4.5.1/src/corelib/kernel/qeventloop.cpp:149 +#65 0xb7fcc7a2 in QEventLoop::exec (this=0xbffec444, flags=...) at /local/src/qt-x11-opensource-src-4.5.1/src/corelib/kernel/qeventloop.cpp:200 +#66 0xb7fceb2f in QCoreApplication::exec () at /local/src/qt-x11-opensource-src-4.5.1/src/corelib/kernel/qcoreapplication.cpp:888 +#67 0xb5b380f7 in QApplication::exec () at /local/src/qt-x11-opensource-src-4.5.1/src/gui/kernel/qapplication.cpp:3526 +#68 0xb80c5591 in kdemain (argc=1, argv=0xbffec5b4) at /local/svn/kde/trunk/koffice/krita/main.cc:44 +#69 0x0804887b in main (argc=1, argv=0xbffec5b4) at /local/build/koffice/krita/krita_dummy.cpp:3 + diff --git a/drkonqi/tests/backtraceparsertest/backtraceparsertest_data/test_bug192412_a b/drkonqi/tests/backtraceparsertest/backtraceparsertest_data/test_bug192412_a new file mode 100644 index 00000000..400f4011 --- /dev/null +++ b/drkonqi/tests/backtraceparsertest/backtraceparsertest_data/test_bug192412_a @@ -0,0 +1,9 @@ +[Current thread is 0 (process 12545)] + +Thread 1 (Thread 0x7fddaac76740 (LWP 12545)): +#0 0x00007fdda985f5b5 in waitpid () from /lib/libpthread.so.0 +#1 0x00007fddaa7e660d in KCrash::startDirectly (argv=0x7fffb2db2800) at /home/gkiagia/kde/src/KDE/kdelibs/kdeui/util/kcrash.cpp:436 +#2 0x00007fddaa7e7581 in KCrash::defaultCrashHandler (sig=11) at /home/gkiagia/kde/src/KDE/kdelibs/kdeui/util/kcrash.cpp:340 +#3 +#6 0x0805a0eb in ?? () +#7 0x08050ac4 in _start () diff --git a/drkonqi/tests/backtraceparsertest/backtraceparsertest_data/test_bug192412_b b/drkonqi/tests/backtraceparsertest/backtraceparsertest_data/test_bug192412_b new file mode 100644 index 00000000..7817eacf --- /dev/null +++ b/drkonqi/tests/backtraceparsertest/backtraceparsertest_data/test_bug192412_b @@ -0,0 +1,9 @@ +[Current thread is 0 (process 12545)] + +Thread 1 (Thread 0x7fddaac76740 (LWP 12545)): +#0 0x00007fdda985f5b5 in waitpid () from /lib/libpthread.so.0 +#1 0x00007fddaa7e660d in KCrash::startDirectly (argv=0x7fffb2db2800) at /home/gkiagia/kde/src/KDE/kdelibs/kdeui/util/kcrash.cpp:436 +#2 0x00007fddaa7e7581 in KCrash::defaultCrashHandler (sig=11) at /home/gkiagia/kde/src/KDE/kdelibs/kdeui/util/kcrash.cpp:340 +#3 +#4 KCmdLineArgs::arg (this=0x0, n=0) at /home/gkiagia/kde/src/KDE/kdelibs/kdecore/kernel/kcmdlineargs.cpp:1530 +#5 0x00000000004023af in _start () diff --git a/drkonqi/tests/backtraceparsertest/backtraceparsertest_data/test_bug200993 b/drkonqi/tests/backtraceparsertest/backtraceparsertest_data/test_bug200993 new file mode 100644 index 00000000..d92cede9 --- /dev/null +++ b/drkonqi/tests/backtraceparsertest/backtraceparsertest_data/test_bug200993 @@ -0,0 +1,20 @@ +Thread 1 (Thread 0x7fe4756407f0 (LWP 9487)): +#0 0x00007fdda985f5b5 in waitpid () from /lib/libpthread.so.0 +#1 0x00007fddaa7e660d in KCrash::startDirectly (argv=0x7fffb2db2800) at /home/gkiagia/kde/src/KDE/kdelibs/kdeui/util/kcrash.cpp:436 +#2 0x00007fddaa7e7581 in KCrash::defaultCrashHandler (sig=11) at /home/gkiagia/kde/src/KDE/kdelibs/kdeui/util/kcrash.cpp:340 +#3 +#6 0xffffe430 in __kernel_vsyscall () +#7 0xb617b990 in *__GI_raise (sig=6) at ../nptl/sysdeps/unix/sysv/linux/raise.c:64 +#8 0xb617d2c8 in *__GI_abort () at abort.c:88 +#9 0xb617478e in *__GI___assert_fail (assertion=0xb3391928 "!s_refcnt", file=0xb3391720 "/local/svn/kde/trunk/KDE/kdelibs/khtml/khtml_global.cpp", line=258, + function=0xb3391ac0 "static void KHTMLGlobal::finalCheck()") at assert.c:78 +#10 0xb2f947d3 in KHTMLGlobal::finalCheck () at /local/svn/kde/trunk/KDE/kdelibs/khtml/khtml_global.cpp:258 +#11 0xb418554d in ~KHTMLFactory (this=0x825fcd0, __in_chrg=) at /local/svn/kde/trunk/KDE/kdelibs/khtml/khtml_factory.cpp:35 +#12 0xb70e8e86 in QObjectCleanupHandler::clear (this=0x825d9e0) at /local/git/Qt/qt/src/corelib/kernel/qobjectcleanuphandler.cpp:140 +#13 0xb70e8ed0 in ~QObjectCleanupHandler (this=0x825d9e0, __in_chrg=) at /local/git/Qt/qt/src/corelib/kernel/qobjectcleanuphandler.cpp:86 +#14 0xb741fc21 in destroy () at /local/svn/kde/trunk/KDE/kdelibs/kdecore/util/kpluginfactory.cpp:29 +#15 0xb72e154b in ~KCleanUpGlobalStatic (this=0xb74d15d4, __in_chrg=) at /local/svn/kde/trunk/KDE/kdelibs/kdecore/kernel/kglobal.h:62 +#16 0xb617e9b1 in *__GI_exit (status=0) at exit.c:75 +#17 0xb616770d in __libc_start_main (main=0x804877e
, argc=1, ubp_av=0xbf97df04, init=0x80487b0 <__libc_csu_init>, fini=0x80487a0 <__libc_csu_fini>, rtld_fini=0xb7f70220 <_dl_fini>, + stack_end=0xbf97defc) at libc-start.c:252 +#18 0x080486d1 in _start () at ../sysdeps/i386/elf/start.S:119 diff --git a/drkonqi/tests/backtraceparsertest/backtraceparsertest_data/test_c b/drkonqi/tests/backtraceparsertest/backtraceparsertest_data/test_c new file mode 100644 index 00000000..bfa2131f --- /dev/null +++ b/drkonqi/tests/backtraceparsertest/backtraceparsertest_data/test_c @@ -0,0 +1,35 @@ +0x00007fd2f44f4001 in nanosleep () from /lib/libc.so.6 +[Current thread is 0 (LWP 4414)] + +Thread 3 (Thread 0x7fd2c7276950 (LWP 4425)): +#0 0x00007fd2f451bc66 in poll () from /lib/libc.so.6 +#1 0x00007fd2f6bbbc61 in net::DownloadThread::waitForSocketReady () from /usr/lib/libbtcore.so.7 +#2 0x00007fd2f6bbbccc in net::DownloadThread::update () from /usr/lib/libbtcore.so.7 +#3 0x00007fd2f6bbc6d9 in net::NetworkThread::run () from /usr/lib/libbtcore.so.7 +#4 0x00007fd2fba5ad79 in ?? () from /usr/lib/libQtCore.so.4 +#5 0x00007fd2fb7e9fc7 in start_thread () from /lib/libpthread.so.0 +#6 0x00007fd2f45245dd in clone () from /lib/libc.so.6 +#7 0x0000000000000000 in ?? () + +Thread 2 (Thread 0x7fd2c6a75950 (LWP 4426)): +#0 0x00007fd2fb7edd69 in pthread_cond_wait@@GLIBC_2.3.2 () from /lib/libpthread.so.0 +#1 0x00007fd2fba5bb09 in QWaitCondition::wait () from /usr/lib/libQtCore.so.4 +#2 0x00007fd2f6bbb7a4 in net::UploadThread::update () from /usr/lib/libbtcore.so.7 +#3 0x00007fd2f6bbc6d9 in net::NetworkThread::run () from /usr/lib/libbtcore.so.7 +#4 0x00007fd2fba5ad79 in ?? () from /usr/lib/libQtCore.so.4 +#5 0x00007fd2fb7e9fc7 in start_thread () from /lib/libpthread.so.0 +#6 0x00007fd2f45245dd in clone () from /lib/libc.so.6 +#7 0x0000000000000000 in ?? () + +Thread 1 (Thread 0x7fd2fc35f750 (LWP 4414)): +#0 0x00007fdda985f5b5 in waitpid () from /lib/libpthread.so.0 +#1 0x00007fddaa7e660d in KCrash::startDirectly (argv=0x7fffb2db2800) at /home/gkiagia/kde/src/KDE/kdelibs/kdeui/util/kcrash.cpp:436 +#2 0x00007fddaa7e7581 in KCrash::defaultCrashHandler (sig=11) at /home/gkiagia/kde/src/KDE/kdelibs/kdeui/util/kcrash.cpp:340 +#3 +#5 0x00007fd2f44d272b in memcpy () from /lib/libc.so.6 +#6 0x00007fd2f6bd4add in bt::WebSeed::handleData () from /usr/lib/libbtcore.so.7 +#7 0x00007fd2f6bd5703 in bt::WebSeed::update () from /usr/lib/libbtcore.so.7 +#8 0x00007fd2f6bdc120 in bt::Downloader::update () from /usr/lib/libbtcore.so.7 +#9 0x00007fd2f6bfee5b in bt::TorrentControl::update () from /usr/lib/libbtcore.so.7 +#10 0x000000000042996a in _start () + diff --git a/drkonqi/tests/backtraceparsertest/backtraceparsertest_data/test_d b/drkonqi/tests/backtraceparsertest/backtraceparsertest_data/test_d new file mode 100644 index 00000000..5ac7675e --- /dev/null +++ b/drkonqi/tests/backtraceparsertest/backtraceparsertest_data/test_d @@ -0,0 +1,104 @@ +0x00007fdda985f5b5 in waitpid () from /lib/libpthread.so.0 +[Current thread is 0 (process 12545)] + +Thread 1 (Thread 0xb59786c0 (LWP 6637)): +#0 0xa985f5b5 in waitpid () from /lib/libpthread.so.0 +#1 0xaa7e660d in KCrash::startDirectly (argv=0x7fffb2db2800) at /home/gkiagia/kde/src/KDE/kdelibs/kdeui/util/kcrash.cpp:436 +#2 0xaa7e7581 in KCrash::defaultCrashHandler (sig=11) at /home/gkiagia/kde/src/KDE/kdelibs/kdeui/util/kcrash.cpp:340 +#3 +#6 0xb3fe1ac0 in QBasicAtomicInt::ref (this=0xc) at + /home/tz/develop/kde/svn/qt-copy/include/QtCore/../../src/corelib/arch/qatomic_i386.h:116 +#7 0xb40010e6 in QHash (this=0xbfb999fc, other=@0x84afe24) at + /home/tz/develop/kde/svn/qt-copy/include/QtCore/../../src/corelib/tools/qhash.h:264 +#8 0xb400111c in QSet (this=0xbfb999fc, other=@0x84afe24) at + /home/tz/develop/kde/svn/qt-copy/include/QtCore/../../src/corelib/tools/qset.h:56 +#9 0xb4001136 in QForeachContainer (this=0xbfb999fc, t=@0x84afe24) at + /home/tz/develop/kde/svn/qt-copy/include/QtCore/../../src/corelib/global/qglobal.h:1964 +#10 0xb3ffa778 in KoShape::notifyChanged (this=0x84a4538) at + /home/tz/develop/kde/svn/koffice/libs/flake/KoShape.cpp:458 +#11 0xb3ffb773 in KoShape::setParent (this=0x84a4538, parent=0x0) at + /home/tz/develop/kde/svn/koffice/libs/flake/KoShape.cpp:375 +#12 0xb40032de in ~Private (this=0x84a0ca0) at + /home/tz/develop/kde/svn/koffice/libs/flake/KoShapeContainer.cpp:36 +#13 0xb4002aa8 in ~KoShapeContainer (this=0x84b4bf8) at + /home/tz/develop/kde/svn/koffice/libs/flake/KoShapeContainer.cpp:56 +#14 0xb4240152 in ~MagicCurtain (this=0x84b4bf8) at + /home/tz/develop/kde/svn/koffice/kword/part/KWDocument.cpp:80 +#15 0xb423ab9e in ~KWDocument (this=0x81a34e0) at + /home/tz/develop/kde/svn/koffice/kword/part/KWDocument.cpp:154 +#16 0xb77b7849 in KoMainWindow::setRootDocument (this=0x8200b38, doc=0x0) at + /home/tz/develop/kde/svn/koffice/libs/main/KoMainWindow.cpp:501 +#17 0xb77ba45b in KoMainWindow::slotFileClose (this=0x8200b38) at + /home/tz/develop/kde/svn/koffice/libs/main/KoMainWindow.cpp:1283 +#18 0xb77ba922 in KoMainWindow::qt_metacall (this=0x8200b38, + _c=QMetaObject::InvokeMetaMethod, _id=13, _a=0xbfb99c7c) at + /home/ko2/koffice-build/libs/main/KoMainWindow.moc:135 +#19 0xb6c8a635 in QMetaObject::activate (sender=0x8207500, from_signal_index=5, + to_signal_index=6, argv=0xbfb99c7c) at kernel/qobject.cpp:3028 +#20 0xb6c8a83e in QMetaObject::activate (sender=0x8207500, m=0xb7730af8, + from_local_signal_index=1, to_local_signal_index=2, argv=0xbfb99c7c) at + kernel/qobject.cpp:3121 +#21 0xb702cb16 in QAction::triggered (this=0x8207500, _t1=false) at + .moc/debug-shared/moc_qaction.cpp:216 +#22 0xb702e6b8 in QAction::activate (this=0x8207500, event=QAction::Trigger) at + kernel/qaction.cpp:1125 +#23 0xb702e857 in QAction::event (this=0x8207500, e=0xbfb9a0d4) at + kernel/qaction.cpp:1044 +#24 0xb709d70a in QWidgetAction::event (this=0x8207500, event=0xbfb9a0d4) at + kernel/qwidgetaction.cpp:230 +#25 0xb70348c5 in QApplicationPrivate::notify_helper (this=0x805afa0, + receiver=0x8207500, e=0xbfb9a0d4) at kernel/qapplication.cpp:3803 +#26 0xb7034bab in QApplication::notify (this=0xbfb9ae7c, receiver=0x8207500, + e=0xbfb9a0d4) at kernel/qapplication.cpp:3393 +#27 0xb79f6ebb in KApplication::notify (this=0xbfb9ae7c, receiver=0x8207500, + event=0xbfb9a0d4) at + /home/tz/develop/kde/svn/kdelibs/kdeui/kernel/kapplication.cpp:311 +#28 0xb6c7570a in QCoreApplication::notifyInternal (this=0xbfb9ae7c, + receiver=0x8207500, event=0xbfb9a0d4) at kernel/qcoreapplication.cpp:583 +#29 0xb703153d in QCoreApplication::sendEvent (receiver=0x8207500, + event=0xbfb9a0d4) at + ../../include/QtCore/../../src/corelib/kernel/qcoreapplication.h:209 +#30 0xb7074325 in QShortcutMap::dispatchEvent (this=0x805b03c, e=0xbfb9a4f4) at + kernel/qshortcutmap.cpp:771 +#31 0xb7075364 in QShortcutMap::tryShortcutEvent (this=0x805b03c, w=0x893ac60, + e=0xbfb9a4f4) at kernel/qshortcutmap.cpp:362 +#32 0xb7034dc6 in QApplication::notify (this=0xbfb9ae7c, receiver=0x893ac60, + e=0xbfb9a4f4) at kernel/qapplication.cpp:3430 +#33 0xb79f6ebb in KApplication::notify (this=0xbfb9ae7c, receiver=0x893ac60, + event=0xbfb9a4f4) at + /home/tz/develop/kde/svn/kdelibs/kdeui/kernel/kapplication.cpp:311 +#34 0xb6c7570a in QCoreApplication::notifyInternal (this=0xbfb9ae7c, + receiver=0x893ac60, event=0xbfb9a4f4) at kernel/qcoreapplication.cpp:583 +#35 0xb704079f in QCoreApplication::sendSpontaneousEvent (receiver=0x893ac60, + event=0xbfb9a4f4) at + ../../include/QtCore/../../src/corelib/kernel/qcoreapplication.h:212 +#36 0xb70a00ce in qt_sendSpontaneousEvent (receiver=0x893ac60, + event=0xbfb9a4f4) at kernel/qapplication_x11.cpp:4588 +#37 0xb70da5b4 in QKeyMapper::sendKeyEvent (keyWidget=0x893ac60, grab=false, + type=QEvent::KeyPress, code=87, modifiers=@0xbfb9a658, text=@0xbfb9a68c, + autorepeat=false, count=1, nativeScanCode=25, + nativeVirtualKey=119, nativeModifiers=4) at kernel/qkeymapper_x11.cpp:1652 +#38 0xb70db921 in QKeyMapperPrivate::translateKeyEvent (this=0x807ef50, + keyWidget=0x893ac60, event=0xbfb9abdc, grab=false) at + kernel/qkeymapper_x11.cpp:1623 +#39 0xb70b15af in QApplication::x11ProcessEvent (this=0xbfb9ae7c, + event=0xbfb9abdc) at kernel/qapplication_x11.cpp:3053 +#40 0xb70dde71 in x11EventSourceDispatch (s=0x805df20, callback=0, + user_data=0x0) at kernel/qguieventdispatcher_glib.cpp:142 +#41 0xb670ecc6 in g_main_context_dispatch () from /usr/lib/libglib-2.0.so.0 +#42 0xb6712083 in ?? () from /usr/lib/libglib-2.0.so.0 +#43 0xb671263e in g_main_context_iteration () from /usr/lib/libglib-2.0.so.0 +#44 0xb6ca4b8c in QEventDispatcherGlib::processEvents (this=0x805b0d8, + flags=@0xbfb9ad74) at kernel/qeventdispatcher_glib.cpp:319 +#45 0xb70dd68c in QGuiEventDispatcherGlib::processEvents (this=0x805b0d8, + flags=@0xbfb9ada4) at kernel/qguieventdispatcher_glib.cpp:198 +#46 0xb6c725ca in QEventLoop::processEvents (this=0xbfb9ae20, + flags=@0xbfb9ade4) at kernel/qeventloop.cpp:143 +#47 0xb6c72809 in QEventLoop::exec (this=0xbfb9ae20, flags=@0xbfb9ae28) at + kernel/qeventloop.cpp:190 +#48 0xb6c75ef3 in QCoreApplication::exec () at kernel/qcoreapplication.cpp:845 +#49 0xb70345de in QApplication::exec () at kernel/qapplication.cpp:3331 +#50 0xb7f3be82 in kdemain (argc=1, argv=0xbfb9af74) at + /home/tz/develop/kde/svn/koffice/kword/part/main.cpp:38 +#51 0x08048736 in main (argc=139070860, argv=0x0) at + /home/ko2/koffice-build/kword/part/kword_dummy.cpp:3 \ No newline at end of file diff --git a/drkonqi/tests/backtraceparsertest/backtraceparsertest_data/test_e b/drkonqi/tests/backtraceparsertest/backtraceparsertest_data/test_e new file mode 100644 index 00000000..f7fe2d04 --- /dev/null +++ b/drkonqi/tests/backtraceparsertest/backtraceparsertest_data/test_e @@ -0,0 +1,21 @@ +Thread 1 (Thread 0xb4eda700 (LWP 9067)): +#0 0xa985f5b5 in waitpid () from /lib/libpthread.so.0 +#1 0xaa7e660d in KCrash::startDirectly (argv=0x7fffb2db2800) at /home/gkiagia/kde/src/KDE/kdelibs/kdeui/util/kcrash.cpp:436 +#2 0xaa7e7581 in KCrash::defaultCrashHandler (sig=11) at /home/gkiagia/kde/src/KDE/kdelibs/kdeui/util/kcrash.cpp:340 +#3 +#6 0xffffe430 in __kernel_vsyscall () +#7 0xb5f05990 in raise () from /lib/libc.so.6 +#8 0xb5f072c8 in abort () from /lib/libc.so.6 +#9 0xb5f47683 in ?? () from /lib/libc.so.6 +#10 0xb5f48edb in free () from /lib/libc.so.6 +#11 0xb6128ec1 in operator delete(void*) () from /usr/lib/libstdc++.so.6 +#12 0x08054227 in ?? () +#13 0xb7c6466a in K3StaticDeleterPrivate::deleteStaticDeleters () at + /usr/src/debug/kdelibs-4.2.0/kde3support/kdecore/k3staticdeleter.cpp:56 +#14 0xb6ce9efb in qt_call_post_routines() () from /usr/lib/libQtCore.so.4 +#15 0xb6289c18 in QApplication::~QApplication() () from /usr/lib/libQtGui.so.4 +#16 0xb7eb019e in ~KApplication (this=0xbfbdb0a0) at + /usr/src/debug/kdelibs-4.2.0/kdeui/kernel/kapplication.cpp:928 +#17 0xb7eb7318 in ~KUniqueApplication (this=0xbfbdb0a0) at + /usr/src/debug/kdelibs-4.2.0/kdeui/kernel/kuniqueapplication.cpp:372 +#18 0x0805116a in _start () \ No newline at end of file diff --git a/drkonqi/tests/backtraceparsertest/backtraceparsertest_data/test_f b/drkonqi/tests/backtraceparsertest/backtraceparsertest_data/test_f new file mode 100644 index 00000000..ad6409f0 --- /dev/null +++ b/drkonqi/tests/backtraceparsertest/backtraceparsertest_data/test_f @@ -0,0 +1,53 @@ +(no debugging symbols found) +[Thread debugging using libthread_db enabled] +[New Thread 0x7f085740d780 (LWP 11923)] +[New Thread 0x4275c950 (LWP 11931)] +0x00007fdda985f5b5 in waitpid () from /lib/libpthread.so.0 +[Current thread is 0 (process 12545)] + +Thread 1 (Thread 0x7fddaac76740 (LWP 12545)): +#0 0x00007fdda985f5b5 in waitpid () from /lib/libpthread.so.0 +#1 0x00007fddaa7e660d in KCrash::startDirectly (argv=0x7fffb2db2800) at /home/gkiagia/kde/src/KDE/kdelibs/kdeui/util/kcrash.cpp:436 +#2 0x00007fddaa7e7581 in KCrash::defaultCrashHandler (sig=11) at /home/gkiagia/kde/src/KDE/kdelibs/kdeui/util/kcrash.cpp:340 +#3 +#5 0x00007f0856662a3c in Kopete::MetaContact::metaContactId () + from /usr/lib/libkopete.so.4 +#6 0x00007f0842c975cc in ?? () from /usr/lib/kde4/kopete_statistics.so +#7 0x00007f0842c97944 in ?? () from /usr/lib/kde4/kopete_statistics.so +#8 0x00007f0842c88a61 in ?? () from /usr/lib/kde4/kopete_statistics.so +#9 0x00007f085389842d in QObject::event (this=0xc220a0, e=0x98d950) + at kernel/qobject.cpp:1124 +#10 0x00007f08544cae5d in QApplicationPrivate::notify_helper (this=0x69a640, + receiver=0xc220a0, e=0x2ad1350) at kernel/qapplication.cpp:3772 +#11 0x00007f08544d2b2a in QApplication::notify (this=0x7fff5f54d0f0, + receiver=0xc220a0, e=0x2ad1350) at kernel/qapplication.cpp:3739 +#12 0x00007f08554b9b7b in KApplication::notify (this=0x7fff5f54d0f0, + receiver=0xc220a0, event=0x2ad1350) + at /build/buildd/kde4libs-4.0.98+svn833207/kdeui/kernel/kapplication.cpp:311 +#13 0x00007f0853889411 in QCoreApplication::notifyInternal ( + this=0x7fff5f54d0f0, receiver=0xc220a0, event=0x2ad1350) + at kernel/qcoreapplication.cpp:587 +#14 0x00007f085388a0ba in QCoreApplicationPrivate::sendPostedEvents ( + receiver=0x0, event_type=0, data=0x675580) + at ../../include/QtCore/../../src/corelib/kernel/qcoreapplication.h:215 +#15 0x00007f08538b1bb3 in postEventSourceDispatch (s=) + at ../../include/QtCore/../../src/corelib/kernel/qcoreapplication.h:220 +#16 0x00007f084f4840f2 in g_main_context_dispatch () + from /usr/lib/libglib-2.0.so.0 +#17 0x00007f084f487396 in ?? () from /usr/lib/libglib-2.0.so.0 +#18 0x00007f084f48782f in g_main_context_iteration () + from /usr/lib/libglib-2.0.so.0 +#19 0x00007f08538b183f in QEventDispatcherGlib::processEvents (this=0x688fb0, + flags=) at kernel/qeventdispatcher_glib.cpp:325 +#20 0x00007f085455c16f in QGuiEventDispatcherGlib::processEvents ( + this=0x7fff5f54c5a0, flags=) + at kernel/qguieventdispatcher_glib.cpp:204 +#21 0x00007f0853887d22 in QEventLoop::processEvents ( + this=, flags={i = 1599393824}) + at kernel/qeventloop.cpp:149 +#22 0x00007f0853887ead in QEventLoop::exec (this=0x7fff5f54d060, flags= + {i = 1599393904}) at kernel/qeventloop.cpp:200 +#23 0x00007f085388a37d in QCoreApplication::exec () + at kernel/qcoreapplication.cpp:845 +#24 0x0000000000448c6c in _start () +#0 0x00007f0853178241 in nanosleep () from /lib/libc.so.6 diff --git a/drkonqi/tests/backtraceparsertest/backtraceparsertest_data/test_g b/drkonqi/tests/backtraceparsertest/backtraceparsertest_data/test_g new file mode 100644 index 00000000..b627e961 --- /dev/null +++ b/drkonqi/tests/backtraceparsertest/backtraceparsertest_data/test_g @@ -0,0 +1,76 @@ +[Thread debugging using libthread_db enabled] +[New Thread 0x7fd180c72740 (LWP 24313)] +[New Thread 0x42f84950 (LWP 24317)] +[New Thread 0x42783950 (LWP 24316)] +[New Thread 0x41f82950 (LWP 24315)] +0x00007fd17fb15bf2 in QString::operator== (this=0x687e90, + other=) at tools/qstring.cpp:1928 + in tools/qstring.cpp +[Current thread is 0 (LWP 24313)] + +Thread 4 (Thread 0x41f82950 (LWP 24315)): +#0 map_function (s=@0x687e88) at /home/gkiagia/kde/src/drkonqi/tests/crashtest/crashtest.cpp:71 +#1 0x0000000000402dbb in QtConcurrent::MapKernel::iterator, QtConcurrent::FunctionWrapper1 >::runIteration (this=, it=) + at /usr/include/qt4/QtCore/qtconcurrentmapkernel.h:73 +#2 0x0000000000402e3a in QtConcurrent::MapKernel::iterator, QtConcurrent::FunctionWrapper1 >::runIterations (this=0x67f220, + sequenceBeginIterator=, beginIndex=, endIndex=1) at /usr/include/qt4/QtCore/qtconcurrentmapkernel.h:82 +#3 0x0000000000403882 in QtConcurrent::IterateKernel::iterator, void>::forThreadFunction (this=0x67f220) at /usr/include/qt4/QtCore/qtconcurrentiteratekernel.h:247 +#4 0x00007fd17fac8f79 in QtConcurrent::ThreadEngineBase::run (this=0x67f260) at concurrent/qtconcurrentthreadengine.cpp:184 +#5 0x00007fd17facc251 in QThreadPoolThread::run (this=0x685b20) at concurrent/qthreadpool.cpp:106 +#6 0x00007fd17fad5802 in QThreadPrivate::start (arg=0x685b20) at thread/qthread_unix.cpp:189 +#7 0x00007fd17f853fc7 in start_thread () from /lib/libpthread.so.0 +#8 0x00007fd17df8e5ad in clone () from /lib/libc.so.6 +#9 0x0000000000000000 in ?? () + +Thread 3 (Thread 0x42783950 (LWP 24316)): +#0 0x00007fd17f85b5ef in waitpid () from /lib/libpthread.so.0 +#1 0x00007fd1807e260d in KCrash::startDirectly (argv=0x42782890) at /home/gkiagia/kde/src/KDE/kdelibs/kdeui/util/kcrash.cpp:436 +#2 0x00007fd1807e3581 in KCrash::defaultCrashHandler (sig=11) at /home/gkiagia/kde/src/KDE/kdelibs/kdeui/util/kcrash.cpp:340 +#3 +#4 KCmdLineArgs::arg (this=0x0, n=0) at /home/gkiagia/kde/src/KDE/kdelibs/kdecore/kernel/kcmdlineargs.cpp:1516 +#5 0x000000000040233f in do_crash () at /home/gkiagia/kde/src/drkonqi/tests/crashtest/crashtest.cpp:42 +#6 0x0000000000402dbb in QtConcurrent::MapKernel::iterator, QtConcurrent::FunctionWrapper1 >::runIteration (this=, it=) + at /usr/include/qt4/QtCore/qtconcurrentmapkernel.h:73 +#7 0x0000000000402e3a in QtConcurrent::MapKernel::iterator, QtConcurrent::FunctionWrapper1 >::runIterations (this=0x67f220, + sequenceBeginIterator=, beginIndex=, endIndex=4) at /usr/include/qt4/QtCore/qtconcurrentmapkernel.h:82 +#8 0x0000000000403882 in QtConcurrent::IterateKernel::iterator, void>::forThreadFunction (this=0x67f220) at /usr/include/qt4/QtCore/qtconcurrentiteratekernel.h:247 +#9 0x00007fd17fac8f79 in QtConcurrent::ThreadEngineBase::run (this=0x67f260) at concurrent/qtconcurrentthreadengine.cpp:184 +#10 0x00007fd17facc251 in QThreadPoolThread::run (this=0x67ec30) at concurrent/qthreadpool.cpp:106 +#11 0x00007fd17fad5802 in QThreadPrivate::start (arg=0x67ec30) at thread/qthread_unix.cpp:189 +#12 0x00007fd17f853fc7 in start_thread () from /lib/libpthread.so.0 +#13 0x00007fd17df8e5ad in clone () from /lib/libc.so.6 +#14 0x0000000000000000 in ?? () + +Thread 2 (Thread 0x42f84950 (LWP 24317)): +#0 0x0000000000403b3b in qStringComparisonHelper (s1=@0x687e98, s2=) at /usr/include/qt4/QtCore/qstring.h:905 +#1 0x0000000000403b69 in QString::operator!= (this=0x687e98, s=0x68816a "") at /usr/include/qt4/QtCore/qstring.h:910 +#2 0x00000000004027e5 in map_function (s=@0x687e98) at /home/gkiagia/kde/src/drkonqi/tests/crashtest/crashtest.cpp:71 +#3 0x0000000000402dbb in QtConcurrent::MapKernel::iterator, QtConcurrent::FunctionWrapper1 >::runIteration (this=, it=) + at /usr/include/qt4/QtCore/qtconcurrentmapkernel.h:73 +#4 0x0000000000402e3a in QtConcurrent::MapKernel::iterator, QtConcurrent::FunctionWrapper1 >::runIterations (this=0x67f220, + sequenceBeginIterator=, beginIndex=, endIndex=3) at /usr/include/qt4/QtCore/qtconcurrentmapkernel.h:82 +#5 0x0000000000403882 in QtConcurrent::IterateKernel::iterator, void>::forThreadFunction (this=0x67f220) at /usr/include/qt4/QtCore/qtconcurrentiteratekernel.h:247 +#6 0x00007fd17fac8f79 in QtConcurrent::ThreadEngineBase::run (this=0x67f260) at concurrent/qtconcurrentthreadengine.cpp:184 +#7 0x00007fd17facc251 in QThreadPoolThread::run (this=0x654a30) at concurrent/qthreadpool.cpp:106 +#8 0x00007fd17fad5802 in QThreadPrivate::start (arg=0x654a30) at thread/qthread_unix.cpp:189 +#9 0x00007fd17f853fc7 in start_thread () from /lib/libpthread.so.0 +#10 0x00007fd17df8e5ad in clone () from /lib/libc.so.6 +#11 0x0000000000000000 in ?? () + +Thread 1 (Thread 0x7fd180c72740 (LWP 24313)): +#0 0x00007fd17fb15bf2 in QString::operator== (this=0x687e90, other=) at tools/qstring.cpp:1928 +#1 0x0000000000403b3b in qStringComparisonHelper (s1=@0x687e90, s2=) at /usr/include/qt4/QtCore/qstring.h:905 +#2 0x0000000000403b69 in QString::operator!= (this=0x687e90, s=0x6880ba "") at /usr/include/qt4/QtCore/qstring.h:910 +#3 0x00000000004027e5 in map_function (s=@0x687e90) at /home/gkiagia/kde/src/drkonqi/tests/crashtest/crashtest.cpp:71 +#4 0x0000000000402dbb in QtConcurrent::MapKernel::iterator, QtConcurrent::FunctionWrapper1 >::runIteration (this=, it=) + at /usr/include/qt4/QtCore/qtconcurrentmapkernel.h:73 +#5 0x0000000000402e3a in QtConcurrent::MapKernel::iterator, QtConcurrent::FunctionWrapper1 >::runIterations (this=0x67f220, + sequenceBeginIterator=, beginIndex=, endIndex=2) at /usr/include/qt4/QtCore/qtconcurrentmapkernel.h:82 +#6 0x0000000000403882 in QtConcurrent::IterateKernel::iterator, void>::forThreadFunction (this=0x67f220) at /usr/include/qt4/QtCore/qtconcurrentiteratekernel.h:247 +#7 0x00007fd17fac9261 in QtConcurrent::ThreadEngineBase::startBlocking (this=0x67f260) at concurrent/qtconcurrentthreadengine.cpp:76 +#8 0x0000000000403a30 in QtConcurrent::ThreadEngine::startBlocking (this=0x67f220) at /usr/include/qt4/QtCore/qtconcurrentthreadengine.h:185 +#9 0x0000000000403a4c in QtConcurrent::ThreadEngineStarter::startBlocking (this=0x7fff88daed20) at /usr/include/qt4/QtCore/qtconcurrentthreadengine.h:286 +#10 0x0000000000403acb in QtConcurrent::blockingMap (sequence=@0x7fff88daedd0, map=) at /usr/include/qt4/QtCore/qtconcurrentmap.h:386 +#11 0x0000000000402283 in do_threads () at /home/gkiagia/kde/src/drkonqi/tests/crashtest/crashtest.cpp:79 +#12 0x0000000000402785 in main (argc=2, argv=0x7fff88daf0e8) at /home/gkiagia/kde/src/drkonqi/tests/crashtest/crashtest.cpp:141 +0x00007fd17fb15bf2 1928 in tools/qstring.cpp diff --git a/drkonqi/tests/backtraceparsertest/backtraceparsertest_data/test_h b/drkonqi/tests/backtraceparsertest/backtraceparsertest_data/test_h new file mode 100644 index 00000000..1fb066df --- /dev/null +++ b/drkonqi/tests/backtraceparsertest/backtraceparsertest_data/test_h @@ -0,0 +1,12 @@ +[Current thread is 0 (process 12545)] + +Thread 1 (Thread 0x7fddaac76740 (LWP 12545)): +#0 0x00007fdda985f5b5 in waitpid () from /lib/libpthread.so.0 +#1 0x00007fddaa7e660d in KCrash::startDirectly (argv=0x7fffb2db2800) at /home/gkiagia/kde/src/KDE/kdelibs/kdeui/util/kcrash.cpp:436 +#2 0x00007fddaa7e7581 in KCrash::defaultCrashHandler (sig=11) at /home/gkiagia/kde/src/KDE/kdelibs/kdeui/util/kcrash.cpp:340 +#3 +#4 0x00007f44eff82065 in *__GI_raise (sig=) at ../nptl/sysdeps/unix/sysv/linux/raise.c:64 +#5 0x00007f44eff85153 in *__GI_abort () at abort.c:88 +#6 0x00007f44f1b6d775 in qt_message_output (msgType=QtFatalMsg, buf=) at global/qglobal.cpp:2017 +#7 0x00007f44f1b6d8bb in qFatal (msg=) at global/qglobal.cpp:2216 +#8 0x0000000000402815 in main () diff --git a/drkonqi/tests/backtraceparsertest/backtraceparsertest_data/test_trailing_const b/drkonqi/tests/backtraceparsertest/backtraceparsertest_data/test_trailing_const new file mode 100644 index 00000000..f6be80ab --- /dev/null +++ b/drkonqi/tests/backtraceparsertest/backtraceparsertest_data/test_trailing_const @@ -0,0 +1,22 @@ +Thread 4 (Thread 0x7feabc3ea710 (LWP 23321)): +#0 0x00007fdda985f5b5 in waitpid () from /lib/libpthread.so.0 +#1 0x00007fddaa7e660d in KCrash::startDirectly (argv=0x7fffb2db2800) at /home/gkiagia/kde/src/KDE/kdelibs/kdeui/util/kcrash.cpp:436 +#2 0x00007fddaa7e7581 in KCrash::defaultCrashHandler (sig=11) at /home/gkiagia/kde/src/KDE/kdelibs/kdeui/util/kcrash.cpp:340 +#3 +#4 0x00007feac3c101ed in QString::operator==(QLatin1String const&) const () from /usr/lib/libQtCore.so.4 +#5 0x0000000000402e7b in qStringComparisonHelper (s1=..., s2=0x404957 "thread 4") at /usr/include/QtCore/qstring.h:908 +#6 0x0000000000402ea9 in QString::operator!= (this=0x21ef798, s=0x404957 "thread 4") at /usr/include/QtCore/qstring.h:913 +#7 0x00000000004023d0 in map_function (s=...) at /home/milian/projects/kde4/drkonqi/tests/crashtest/crashtest.cpp:78 +#8 0x00000000004040c4 in QtConcurrent::FunctionWrapper1::operator() (this=0x21ef6d8, u=...) at /usr/include/QtCore/qtconcurrentfunctionwrappers.h:86 +#9 0x0000000000403e0c in QtConcurrent::MapKernel::iterator, QtConcurrent::FunctionWrapper1 >::runIteration (this=0x21ef6a0, it=...) + at /usr/include/QtCore/qtconcurrentmapkernel.h:73 +#10 0x0000000000403e97 in QtConcurrent::MapKernel::iterator, QtConcurrent::FunctionWrapper1 >::runIterations (this=0x21ef6a0, sequenceBeginIterator=..., + beginIndex=2, endIndex=3) at /usr/include/QtCore/qtconcurrentmapkernel.h:82 +#11 0x000000000040433e in QtConcurrent::IterateKernel::iterator, void>::forThreadFunction (this=0x21ef6a0) at /usr/include/QtCore/qtconcurrentiteratekernel.h:266 +#12 0x0000000000404010 in QtConcurrent::IterateKernel::iterator, void>::threadFunction (this=0x21ef6a0) at /usr/include/QtCore/qtconcurrentiteratekernel.h:228 +#13 0x00007feac3bc2dc5 in QtConcurrent::ThreadEngineBase::run() () from /usr/lib/libQtCore.so.4 +#14 0x00007feac3bc4b05 in ?? () from /usr/lib/libQtCore.so.4 +#15 0x00007feac3bce485 in ?? () from /usr/lib/libQtCore.so.4 +#16 0x00007feac3946cb0 in start_thread () from /lib/libpthread.so.0 +#17 0x00007feac205e7ad in clone () from /lib/libc.so.6 +#18 0x0000000000000000 in ?? () diff --git a/drkonqi/tests/backtraceparsertest/backtraceparsertest_data/test_usefulfunctions b/drkonqi/tests/backtraceparsertest/backtraceparsertest_data/test_usefulfunctions new file mode 100644 index 00000000..a4fb43c8 --- /dev/null +++ b/drkonqi/tests/backtraceparsertest/backtraceparsertest_data/test_usefulfunctions @@ -0,0 +1,22 @@ +[Current thread is 0 (process 12545)] + +Thread 1 (Thread 0x7fddaac76740 (LWP 12545)): +#0 0x00007fdda985f5b5 in waitpid () from /lib/libpthread.so.0 +#1 0x00007fddaa7e660d in KCrash::startDirectly (argv=0x7fffb2db2800) at /home/gkiagia/kde/src/KDE/kdelibs/kdeui/util/kcrash.cpp:436 +#2 0x00007fddaa7e7581 in KCrash::defaultCrashHandler (sig=11) at /home/gkiagia/kde/src/KDE/kdelibs/kdeui/util/kcrash.cpp:340 +#3 +#6 0x00000000 in ?? () +#6 QBasicAtomicInt::operator!= (this=0xa6bf968, result=...) at /usr/include/qt4/QtCore/qbasicatomic.h:69 +#7 QList >::detach (this=0xa6bf968, result=...) at /usr/include/qt4/QtCore/qlist.h:119 +#8 QList >::append (this=0xa6bf968, result=...) at /usr/include/qt4/QtCore/qlist.h:424 +#9 QList >::operator<< (this=0xa6bf968, result=...) at /usr/include/qt4/QtCore/qlist.h:304 +#10 SqlQueryMaker::handleTracks (this=0xa6bf968, result=...) at /build/buildd/amarok-2.2.0/src/collection/sqlcollection/SqlQueryMaker.cpp:975 +#11 0xb443a084 in SqlQueryMaker::handleResult (this=0xa6bf968, result=...) at /build/buildd/amarok-2.2.0/src/collection/sqlcollection/SqlQueryMaker.cpp:671 +#12 0xb443c32b in SqlWorkerThread::run() () from /usr/lib/kde4/amarok_collection-mysqlecollection.so +#13 0x02b2137d in ThreadWeaver::JobRunHelper::runTheJob (this=0xb299a26c, th=0x9aeb9b8, job=0xa6c0e20) at ../../../threadweaver/Weaver/Job.cpp:106 +#14 0x02b216e1 in ThreadWeaver::Job::execute (this=0xa6c0e20, th=0x9aeb9b8) at ../../../threadweaver/Weaver/Job.cpp:135 +#15 0x02b2038a in ThreadWeaver::ThreadRunHelper::run (this=0xb299a2f4, parent=0x992bf40, th=0x9aeb9b8) at ../../../threadweaver/Weaver/Thread.cpp:95 +#16 0x02b209db in ThreadWeaver::Thread::run (this=0x9aeb9b8) at ../../../threadweaver/Weaver/Thread.cpp:142 +#17 0x089bfe32 in QThreadPrivate::start (arg=0x9aeb9b8) at thread/qthread_unix.cpp:188 +#18 0x06e2d80e in start_thread () from /lib/tls/i686/cmov/libpthread.so.0 +#19 0x086be8de in clone () from /lib/tls/i686/cmov/libc.so.6 diff --git a/drkonqi/tests/backtraceparsertest/backtraceparsertest_data/test_usefulfunctions2 b/drkonqi/tests/backtraceparsertest/backtraceparsertest_data/test_usefulfunctions2 new file mode 100644 index 00000000..45595c1a --- /dev/null +++ b/drkonqi/tests/backtraceparsertest/backtraceparsertest_data/test_usefulfunctions2 @@ -0,0 +1,23 @@ +[Current thread is 0 (process 12545)] + +Thread 1 (Thread 0x7fddaac76740 (LWP 12545)): +#0 0x00007fdda985f5b5 in waitpid () from /lib/libpthread.so.0 +#1 0x00007fddaa7e660d in KCrash::startDirectly (argv=0x7fffb2db2800) at /home/gkiagia/kde/src/KDE/kdelibs/kdeui/util/kcrash.cpp:436 +#2 0x00007fddaa7e7581 in KCrash::defaultCrashHandler (sig=11) at /home/gkiagia/kde/src/KDE/kdelibs/kdeui/util/kcrash.cpp:340 +#3 +#6 0x00000000 in ?? () +#6 0x0824add1 in QMap::node_create (this=0xbd74808,key=0x0) at /usr/include/qt4/QtCore/qmap.h:420 +#7 QMap::detach_helper (this=0xbd74808, key=0x0) at /usr/include/qt4/QtCore/qmap.h:708 +#8 QMap::detach (this=0xbd74808, key=0x0) at /usr/include/qt4/QtCore/qmap.h:172 +#9 QMap::remove (this=0xbd74808, key=0x0) at /usr/include/qt4/QtCore/qmap.h:609 +#10 Digikam::Album::removeExtraData (this=0xbd74808, key=0x0) at /build/buildd/digikam-1.0.0/digikam/album.cpp:215 +#11 0x0833cfb6 in ~TreeAlbumItem (this=0xc098ea0, __in_chrg=) at /build/buildd/digikam-1.0.0/digikam/treefolderitem.cpp:160 +#12 0x0833cff8 in ~TreeAlbumCheckListItem (this=0xc098ea0, __in_chrg=) at /build/buildd/digikam-1.0.0/digikam/treefolderitem.cpp:191 +#13 0x02ecff6c in ~QTreeWidgetItem (this=0xc098cd8, __in_chrg=) at itemviews/qtreewidget.cpp:1514 +#14 0x0833cff8 in ~TreeAlbumCheckListItem (this=0xc098cd8, __in_chrg=) at /build/buildd/digikam-1.0.0/digikam/treefolderitem.cpp:191 +#15 0x02ecff6c in ~QTreeWidgetItem (this=0xc098758, __in_chrg=) at itemviews/qtreewidget.cpp:1514 +#16 0x0833cff8 in ~TreeAlbumCheckListItem (this=0xc098758, __in_chrg=) at /build/buildd/digikam-1.0.0/digikam/treefolderitem.cpp:191 +#17 0x02ecff6c in ~QTreeWidgetItem (this=0xc0966e8, __in_chrg=) at itemviews/qtreewidget.cpp:1514 +#18 0x0833cff8 in ~TreeAlbumCheckListItem (this=0xc0966e8, __in_chrg=) at /build/buildd/digikam-1.0.0/digikam/treefolderitem.cpp:191 +#19 0x02ecff6c in ~QTreeWidgetItem (this=0xc08ec10, __in_chrg=) at itemviews/qtreewidget.cpp:1514 +#95 0x083bcb2b in main (argc=5, argv=0xbfede9b4) at /build/buildd/digikam-1.0.0/digikam/main.cpp:195 diff --git a/drkonqi/tests/backtraceparsertest/backtraceparsertest_data/test_usefulfunctions3 b/drkonqi/tests/backtraceparsertest/backtraceparsertest_data/test_usefulfunctions3 new file mode 100644 index 00000000..76939ceb --- /dev/null +++ b/drkonqi/tests/backtraceparsertest/backtraceparsertest_data/test_usefulfunctions3 @@ -0,0 +1,26 @@ +[Current thread is 0 (process 12545)] + +Thread 1 (Thread 0x7fddaac76740 (LWP 12545)): +#0 0x00007fdda985f5b5 in waitpid () from /lib/libpthread.so.0 +#1 0x00007fddaa7e660d in KCrash::startDirectly (argv=0x7fffb2db2800) at /home/gkiagia/kde/src/KDE/kdelibs/kdeui/util/kcrash.cpp:436 +#2 0x00007fddaa7e7581 in KCrash::defaultCrashHandler (sig=11) at /home/gkiagia/kde/src/KDE/kdelibs/kdeui/util/kcrash.cpp:340 +#3 +#5 0x00007f57c1a6e4b5 in *__GI_raise (sig=) at ../nptl/sysdeps/unix/sysv/linux/raise.c:64 +#6 0x00007f57c1a71f50 in *__GI_abort () at abort.c:92 +#7 0x00007f57c3de6e0d in qt_message_output (msgType=QtFatalMsg, buf=0x22c9138 "ASSERT: \"!(*watched)\" in file /home/w00t/kdesvn/qt-copy/src/gui/widgets/qmenu.cpp, line 997") at /home/w00t/kdesvn/qt-copy/src/corelib/global/qglobal.cpp:2248 +#8 0x00007f57c3de700f in qt_message (msgType=QtFatalMsg, msg=0x7f57c3fa9f90 "ASSERT: \"%s\" in file %s, line %d", ap=0x7fff621502b0) at +/home/w00t/kdesvn/qt-copy/src/corelib/global/qglobal.cpp:2294 +#9 0x00007f57c3de787c in qFatal (msg=0x7f57c3fa9f90 "ASSERT: \"%s\" in file %s, line %d") at /home/w00t/kdesvn/qt-copy/src/corelib/global/qglobal.cpp:2477 +#10 0x00007f57c3de699f in qt_assert (assertion=0x7f57c3653b74 "!(*watched)", file=0x7f57c3653b40 "/home/w00t/kdesvn/qt-copy/src/gui/widgets/qmenu.cpp", line=997) at /home/w00t/kdesvn/qt-copy/src/corelib/global/qglobal.cpp:2011 +#11 0x00007f57c32fb473 in ExceptionGuard (this=0x7fff62150420, w=0x202e2c1) at /home/w00t/kdesvn/qt-copy/src/gui/widgets/qmenu.cpp:997 +#12 0x00007f57c32f07fa in QMenuPrivate::activateCausedStack (this=0x202e0b0, causedStack=..., action=0x202ec60, action_e=QAction::Hover, self=true) at /home/w00t/kdesvn/qt-copy/src/gui/widgets/qmenu.cpp:1006 +#13 0x00007f57c32f0d23 in QMenuPrivate::activateAction (this=0x202e0b0, action=0x202ec60, action_e=QAction::Hover, self=true) at /home/w00t/kdesvn/qt-copy/src/gui/widgets/qmenu.cpp:1103 +#14 0x00007f57c32eea8c in QMenuPrivate::setCurrentAction (this=0x202e0b0, action=0x202ec60, popup=96, reason=QMenuPrivate::SelectedFromElsewhere, activateFirst=false) at /home/w00t/kdesvn/qt-copy/src/gui/widgets/qmenu.cpp:571 +#15 0x00007f57c32f7c18 in QMenu::mouseMoveEvent (this=0x202e070, e=0x7fff62151190) at /home/w00t/kdesvn/qt-copy/src/gui/widgets/qmenu.cpp:2824 +#16 0x00007f57c2dc4c19 in QWidget::event (this=0x202e070, event=0x7fff62151190) at /home/w00t/kdesvn/qt-copy/src/gui/kernel/qwidget.cpp:7999 +#17 0x00007f57c32f5c12 in QMenu::event (this=0x202e070, e=0x7fff62151190) at /home/w00t/kdesvn/qt-copy/src/gui/widgets/qmenu.cpp:2428 +#18 0x00007f57bc81d605 in Oxygen::MenuBarDataV1::eventFilter (this=0x20ccc00, object=0x202e070, event=0x7fff62151190) at /home/w00t/kdesvn/kdebase/runtime/kstyles/oxygen/animations/oxygenmenubardata.cpp:83 +#19 0x00007f57c3f1f5db in QCoreApplicationPrivate::sendThroughObjectEventFilters (this=0x1c95380, receiver=0x202e070, event=0x7fff62151190) at /home/w00t/kdesvn/qt-copy/src/corelib/kernel/qcoreapplication.cpp:819 +#20 0x00007f57c2d51785 in QApplicationPrivate::notify_helper (this=0x1c95380, receiver=0x202e070, e=0x7fff62151190) at /home/w00t/kdesvn/qt-copy/src/gui/kernel/qapplication.cpp:4296 +#21 0x00007f57c2d4f656 in QApplication::notify (this=0x7fff62157f70, receiver=0x202e070, e=0x7fff62151190) at /home/w00t/kdesvn/qt-copy/src/gui/kernel/qapplication.cpp:3865 +#22 0x00007f57c580e9f6 in KApplication::notify (this=0x7fff62157f70, receiver=0x202e070, event=0x7fff62151190) at /home/w00t/kdesvn/kdelibs/kdeui/kernel/kapplication.cpp:302 diff --git a/drkonqi/tests/backtraceparsertest/backtraceparsertest_data/test_usefulfunctions4 b/drkonqi/tests/backtraceparsertest/backtraceparsertest_data/test_usefulfunctions4 new file mode 100644 index 00000000..91e80803 --- /dev/null +++ b/drkonqi/tests/backtraceparsertest/backtraceparsertest_data/test_usefulfunctions4 @@ -0,0 +1,17 @@ +[Current thread is 0 (process 12545)] + +Thread 1 (Thread 0x7fddaac76740 (LWP 12545)): +#0 0x00007fdda985f5b5 in waitpid () from /lib/libpthread.so.0 +#1 0x00007fddaa7e660d in KCrash::startDirectly (argv=0x7fffb2db2800) at /home/gkiagia/kde/src/KDE/kdelibs/kdeui/util/kcrash.cpp:436 +#2 0x00007fddaa7e7581 in KCrash::defaultCrashHandler (sig=11) at /home/gkiagia/kde/src/KDE/kdelibs/kdeui/util/kcrash.cpp:340 +#3 +#6 0x00471f42 in qt_meta_stringdata_QAnimationGroup () from /usr/lib/libQtCore.so.4 +#7 0x0087f7fc in __dynamic_cast () from /usr/lib/libstdc++.so.6 +#8 0x0521ae26 in KarbonPart::addShape(KoShape*) () from /usr/lib/libkarbonui.so.6 +#9 0x0437c9b0 in KoShapeDeleteCommand::undo() () from /usr/lib/libflake.so.6 +#10 0x089e4a78 in QUndoCommand::undo (this=0xa70abb0) at util/qundostack.cpp:226 +#11 0x0437c562 in KoShapeCreateCommand::undo() () from /usr/lib/libflake.so.6 +#12 0x089e6147 in QUndoStack::undo (this=0x9e107d8) at util/qundostack.cpp:659 +#13 0x08a0d703 in QUndoStack::qt_metacall (this=0x9e107d8, _c=QMetaObject::InvokeMetaMethod, _id=8, _a=0xbfba6d28) at .moc/release-shared/moc_qundostack.cpp:105 +#14 0x011b5482 in KUndoStack::qt_metacall (this=0x9e107d8, _c=QMetaObject::InvokeMetaMethod, _id=12, _a=0xbfba6d28) at ./kundostack.moc:64 +#15 0x07398a52 in KoUndoStack::qt_metacall(QMetaObject::Call, int, void**) () from /usr/lib/libkotext.so.6 diff --git a/drkonqi/tests/backtraceparsertest/backtraceparsertest_data/test_usefulfunctions5 b/drkonqi/tests/backtraceparsertest/backtraceparsertest_data/test_usefulfunctions5 new file mode 100644 index 00000000..e3e03acb --- /dev/null +++ b/drkonqi/tests/backtraceparsertest/backtraceparsertest_data/test_usefulfunctions5 @@ -0,0 +1,25 @@ +[Current thread is 0 (process 12545)] + +Thread 1 (Thread 0x7fddaac76740 (LWP 12545)): +#0 0x00007fdda985f5b5 in waitpid () from /lib/libpthread.so.0 +#1 0x00007fddaa7e660d in KCrash::startDirectly (argv=0x7fffb2db2800) at /home/gkiagia/kde/src/KDE/kdelibs/kdeui/util/kcrash.cpp:436 +#2 0x00007fddaa7e7581 in KCrash::defaultCrashHandler (sig=11) at /home/gkiagia/kde/src/KDE/kdelibs/kdeui/util/kcrash.cpp:340 +#3 +#6 0xffffe424 in __kernel_vsyscall () +#7 0xb57400cf in raise (sig=6) at ../nptl/sysdeps/unix/sysv/linux/raise.c:64 +#8 0xb57419e7 in abort () at abort.c:88 +#9 0xb660f7f4 in qt_message_output (msgType=QtFatalMsg, buf=0x6
) at global/qglobal.cpp:2248 +#10 0xb660fa13 in qt_message (msgType=QtFatalMsg, msg=0xb678c85c "ASSERT: \"%s\" in file %s, line %d", ap=0xbfb81204 "\203\234\f\b\354\233\f\bw\001") at global/qglobal.cpp:2294 +#11 0xb660fb38 in qFatal (msg=0xb678c85c "ASSERT: \"%s\" in file %s, line %d") at global/qglobal.cpp:2477 +#12 0xb660fbb5 in qt_assert (assertion=0x80c9c83 "rowCount >= usedRowCnt", file=0x80c9bec "/local/svn/kde/trunk/KDE/kdebase/apps/dolphin/src/panels/information/kmetadatawidget.cpp", line=375) at global/qglobal.cpp:2011 +#13 0x08083a65 in KMetaDataWidget::Private::slotLoadingFinished (this=0x82f7a90) at /local/svn/kde/trunk/KDE/kdebase/apps/dolphin/src/panels/information/kmetadatawidget.cpp:375 +#14 0x08085757 in KMetaDataWidget::qt_metacall (this=0x8124650, _c=InvokeMetaMethod, _id=1, _a=0x839a290) at /local/build/KDE/kdebase/apps/dolphin/src/kmetadatawidget.moc:89 +#15 0xb6726efd in QMetaObject::metacall (object=0x8124650, cl=8929, idx=28, argv=0x839a290) at kernel/qmetaobject.cpp:237 +#16 0xb6731855 in QMetaCallEvent::placeMetaCall (this=0x8247550, object=0x8124650) at kernel/qobject.cpp:561 +#17 0xb67329ff in QObject::event (this=0x8124650, e=0x8247550) at kernel/qobject.cpp:1240 +#18 0xb5cb6330 in QWidget::event (this=0x8124650, event=0x8247550) at kernel/qwidget.cpp:8471 +#19 0x0808564e in KMetaDataWidget::event (this=0x8124650, event=0x8247550) at /local/svn/kde/trunk/KDE/kdebase/apps/dolphin/src/panels/information/kmetadatawidget.cpp:700 +#20 0xb5c5615c in QApplicationPrivate::notify_helper (this=0x811ab60, receiver=0x8124650, e=0x8247550) at kernel/qapplication.cpp:4300 +#21 0xb5c5d038 in QApplication::notify (this=0x8124650, receiver=0x8124650, e=0x8247550) at kernel/qapplication.cpp:4265 +#22 0xb6da6dd4 in KApplication::notify (this=0xbfb81d04, receiver=0x8124650, event=0x8247550) at /local/svn/kde/trunk/KDE/kdelibs/kdeui/kernel/kapplication.cpp:302 +#23 0xb6721b8e in QCoreApplication::notifyInternal (this=0xbfb81d04, receiver=0x8124650, event=0x8247550) at kernel/qcoreapplication.cpp:704 diff --git a/drkonqi/tests/backtraceparsertest/backtraceparsertest_manual.cpp b/drkonqi/tests/backtraceparsertest/backtraceparsertest_manual.cpp new file mode 100644 index 00000000..3cc03a31 --- /dev/null +++ b/drkonqi/tests/backtraceparsertest/backtraceparsertest_manual.cpp @@ -0,0 +1,65 @@ +/* + Copyright (C) 2010 George Kiagiadakis + + 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, see . +*/ +#include "fakebacktracegenerator.h" +#include "../../parser/backtraceparser.h" +#include +#include +#include +#include +#include +#include +#include +#include + +int main(int argc, char **argv) +{ + KAboutData aboutData("backtraceparsertest_manual", 0, + ki18n("backtraceparsertest_manual"), "1.0"); + KCmdLineArgs::init(argc, argv, &aboutData); + + KCmdLineOptions options; + options.add("debugger ", ki18n("The debugger name passed to the parser factory"), "gdb"); + options.add("+file", ki18n("A file containing the backtrace.")); + KCmdLineArgs::addCmdLineOptions(options); + + QCoreApplication app(KCmdLineArgs::qtArgc(), KCmdLineArgs::qtArgv()); + QCoreApplication::setApplicationName(QLatin1String("backtraceparsertest_manual")); + + KCmdLineArgs *args = KCmdLineArgs::parsedArgs(); + QString debugger = args->getOption("debugger"); + QString file = args->arg(0); + + if (!QFile::exists(file)) { + QTextStream(stderr) << "The specified file does not exist" << endl; + return 1; + } + + FakeBacktraceGenerator generator; + QSharedPointer parser(BacktraceParser::newParser(debugger)); + parser->connectToGenerator(&generator); + generator.sendData(file); + + QMetaEnum metaUsefulness = BacktraceParser::staticMetaObject.enumerator( + BacktraceParser::staticMetaObject.indexOfEnumerator("Usefulness")); + QTextStream(stdout) << "Usefulness: " << metaUsefulness.valueToKey(parser->backtraceUsefulness()) << endl; + QTextStream(stdout) << "First valid functions: " << parser->firstValidFunctions().join(" ") << endl; + QTextStream(stdout) << "Simplified backtrace:\n" << parser->simplifiedBacktrace() << endl; + QStringList l = static_cast(parser->librariesWithMissingDebugSymbols().toList()); + QTextStream(stdout) << "Missing dbgsym libs: " << l.join(" ") << endl; + + return 0; +} diff --git a/drkonqi/tests/backtraceparsertest/fakebacktracegenerator.cpp b/drkonqi/tests/backtraceparsertest/fakebacktracegenerator.cpp new file mode 100644 index 00000000..33c9d79c --- /dev/null +++ b/drkonqi/tests/backtraceparsertest/fakebacktracegenerator.cpp @@ -0,0 +1,35 @@ +/* + Copyright (C) 2009 George Kiagiadakis + + 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 "fakebacktracegenerator.h" +#include +#include + +void FakeBacktraceGenerator::sendData(const QString & filename) +{ + QFile file(filename); + file.open(QIODevice::ReadOnly | QIODevice::Text); + QTextStream stream(&file); + + emit starting(); + while (!stream.atEnd()) { + emit newLine(stream.readLine() + '\n'); + } + emit newLine(QString()); +} + +#include "fakebacktracegenerator.moc" diff --git a/drkonqi/tests/backtraceparsertest/fakebacktracegenerator.h b/drkonqi/tests/backtraceparsertest/fakebacktracegenerator.h new file mode 100644 index 00000000..cda1ee22 --- /dev/null +++ b/drkonqi/tests/backtraceparsertest/fakebacktracegenerator.h @@ -0,0 +1,36 @@ +/* + Copyright (C) 2009 George Kiagiadakis + + 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. +*/ + +#ifndef FAKEBACKTRACEGENERATOR_H +#define FAKEBACKTRACEGENERATOR_H + +#include + +class FakeBacktraceGenerator : public QObject +{ + Q_OBJECT +public: + FakeBacktraceGenerator(QObject *parent = 0) : QObject(parent) {} + void sendData(const QString & filename); + +signals: + void starting(); + void newLine(const QString & line); +}; + +#endif // FAKEBACKTRACEGENERATOR_H diff --git a/drkonqi/tests/crashtest/CMakeLists.txt b/drkonqi/tests/crashtest/CMakeLists.txt new file mode 100644 index 00000000..fdb26371 --- /dev/null +++ b/drkonqi/tests/crashtest/CMakeLists.txt @@ -0,0 +1,9 @@ +set( EXECUTABLE_OUTPUT_PATH ${CMAKE_CURRENT_BINARY_DIR} ) + +set(crashtest_SRCS crashtest.cpp ) + + +kde4_add_executable(crashtest TEST ${crashtest_SRCS}) + +target_link_libraries(crashtest ${KDE4_KDEUI_LIBS} ) + diff --git a/drkonqi/tests/crashtest/crashtest.cpp b/drkonqi/tests/crashtest/crashtest.cpp new file mode 100644 index 00000000..1eb8d166 --- /dev/null +++ b/drkonqi/tests/crashtest/crashtest.cpp @@ -0,0 +1,161 @@ +/***************************************************************** + * drkonqi - The KDE Crash Handler + * + * Copyright (C) 2000-2002 David Faure + * Copyright (C) 2000-2002 Waldo Bastian + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *****************************************************************/ + +// Let's crash. +#include +#include +#include +#include +#include +#include +#include +#include + +enum CrashType { Crash, Malloc, Div0, Assert, QAssert, Threads }; + +struct SomeStruct +{ + int foo() { return ret; } + int ret; +}; + +void do_crash() +{ + SomeStruct *obj = 0; + int ret = obj->foo(); + printf("result = %d\n", ret); +} + +void do_malloc() +{ + delete (char*)0xdead; +} + +void do_div0() +{ + volatile int a = 99; + volatile int b = 10; + volatile int c = a / ( b - 10 ); + printf("result = %d\n", c); +} + +void do_assert() +{ + assert(false); +} + +void do_qassert() +{ + Q_ASSERT(false); +} + +void map_function(const QString & s) +{ + while ( s != "thread 4" ) {} + do_crash(); +} + +void do_threads() +{ + QStringList foo; + foo << "thread 1" << "thread 2" << "thread 3" << "thread 4" << "thread 5"; + QThreadPool::globalInstance()->setMaxThreadCount(5); + QtConcurrent::blockingMap(foo, map_function); +} + +void level4(int t) +{ + if (t == Malloc) + do_malloc(); + else if (t == Div0) + do_div0(); + else if (t == Assert) + do_assert(); + else if (t == QAssert) + do_qassert(); + else if (t == Threads) + do_threads(); + else + do_crash(); +} + +void level3(int t) +{ + level4(t); +} + +void level2(int t) +{ + level3(t); +} + +void level1(int t) +{ + level2(t); +} + +int main(int argc, char *argv[]) +{ + KAboutData aboutData("crashtext", 0, ki18n("Crash Test for DrKonqi"), + "1.1", + ki18n("Crash Test for DrKonqi"), + KAboutData::License_GPL, + ki18n("(c) 2000-2002 David Faure, Waldo Bastian")); + + KCmdLineArgs::init(argc, argv, &aboutData); + + KCmdLineOptions options; + options.add("autorestart", ki18n("Automatically restart")); + options.add("+crash|malloc|div0|assert|threads", ki18n("Type of crash.")); + KCmdLineArgs::addCmdLineOptions(options); + + KApplication app(false); + KCmdLineArgs *args = KCmdLineArgs::parsedArgs(); + + //start drkonqi directly so that drkonqi's output goes to the console + KCrash::CrashFlags flags = KCrash::AlwaysDirectly; + if (args->isSet("autorestart")) + flags |= KCrash::AutoRestart; + KCrash::setFlags(flags); + kDebug() << flags; + + QByteArray type = args->count() ? args->arg(0).toUtf8() : ""; + int crashtype = Crash; + if (type == "malloc") + crashtype = Malloc; + else if (type == "div0") + crashtype = Div0; + else if (type == "assert") + crashtype = Assert; + else if (type == "qassert") + crashtype = QAssert; + else if (type == "threads") + crashtype = Threads; + level1(crashtype); + return app.exec(); +} diff --git a/drkonqi/ui/assistantpage_bugawareness.ui b/drkonqi/ui/assistantpage_bugawareness.ui new file mode 100644 index 00000000..edf67cc9 --- /dev/null +++ b/drkonqi/ui/assistantpage_bugawareness.ui @@ -0,0 +1,334 @@ + + + AssistantPageBugAwareness + + + + 0 + 0 + 508 + 319 + + + + + + + <strong>Do you remember what you were doing prior to the crash?</strong> + + + + + + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 20 + 20 + + + + + + + + + + Yes + + + m_rememberGroup + + + + + + + No + + + true + + + m_rememberGroup + + + + + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 10 + + + + + + + + false + + + <strong>Does the application crash again if you repeat the same situation?</strong> + + + + + + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 20 + 20 + + + + + + + + false + + + If you tried to repeat the situation, select how often the application crashes + + + If you tried to repeat the situation, select how often the application crashes + + + + I did not try again + + + + + Never + + + + + Sometimes + + + + + Every time + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 10 + + + + + + + + false + + + <strong>Please select which additional information you can provide:</strong> + + + + + + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 20 + 20 + + + + + + + + + + false + + + Check this option if you can describe what were you doing inside the application before it crashed + + + Check this option if you can describe what were you doing inside the application before it crashed + + + + + + + false + + + Check this option if you can describe any unusual behavior or appearance in the application or the whole desktop + + + Check this option if you can describe any unusual behavior or appearance in the application or the whole desktop + + + Unusual desktop behavior I noticed + + + + + + + 0 + + + + + false + + + Check this option if you can provide application specific details or settings that may be related to the crash. You can check the examples (if available.) + + + Check this option if you can provide application specific details or settings that may be related to the crash. You can check the examples (if available.) + + + Custom settings of the application that may be related + + + + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 10 + 20 + + + + + + + + false + + + + 0 + 0 + + + + <a href="#">Examples</a> + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + KComboBox + QComboBox +
kcombobox.h
+
+
+ + + + + +
diff --git a/drkonqi/ui/assistantpage_bugzilla_duplicates.ui b/drkonqi/ui/assistantpage_bugzilla_duplicates.ui new file mode 100644 index 00000000..977e2d7a --- /dev/null +++ b/drkonqi/ui/assistantpage_bugzilla_duplicates.ui @@ -0,0 +1,222 @@ + + + AssistantPageBugzillaDuplicates + + + + 0 + 0 + 563 + 517 + + + + + + + See if your bug has already been reported. Double click a report in the list and compare it to yours. You can suggest that your crash is a duplicate of that report or directly attach your information to it. + + + true + + + + + + + + + + 0 + 0 + + + + + + + + false + + + + + + + false + + + + + + + + + + + 2 + + + + + true + + + false + + + true + + + + Bug ID + + + + + Description + + + + + + + + 2 + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + false + + + + + + + + + + + 2 + + + + + Possible duplicates: + + + + + + + + 0 + 0 + + + + + 100 + 0 + + + + + 120 + 16777215 + + + + + + + + 2 + + + + + Qt::Horizontal + + + QSizePolicy::Minimum + + + + 0 + 0 + + + + + + + + + + + + + + + + + + + + true + + + + + + + + + + 0 + 0 + + + + + + + + + + + + + + + + + KPushButton + QPushButton +
kpushbutton.h
+
+ + StatusWidget + QWidget +
statuswidget.h
+ 1 +
+
+ + +
diff --git a/drkonqi/ui/assistantpage_bugzilla_duplicates_dialog.ui b/drkonqi/ui/assistantpage_bugzilla_duplicates_dialog.ui new file mode 100644 index 00000000..2f35584c --- /dev/null +++ b/drkonqi/ui/assistantpage_bugzilla_duplicates_dialog.ui @@ -0,0 +1,123 @@ + + + AssistantPageBugzillaDuplicatesDialog + + + + 0 + 0 + 592 + 345 + + + + + 400 + 300 + + + + + + + + + + 0 + 0 + + + + + + + + + 0 + 0 + + + + true + + + + + + + + 0 + 0 + + + + + + + + + + Qt::Horizontal + + + + + + + + + + + + + + + + + + + + + Show the backtrace of the crash I experienced to compare (advanced) + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 10 + + + + + + + + + KPushButton + QPushButton +
kpushbutton.h
+
+ + KTextBrowser + QTextBrowser +
ktextbrowser.h
+
+ + StatusWidget + QWidget +
statuswidget.h
+ 1 +
+
+ + +
diff --git a/drkonqi/ui/assistantpage_bugzilla_duplicates_dialog_confirmation.ui b/drkonqi/ui/assistantpage_bugzilla_duplicates_dialog_confirmation.ui new file mode 100644 index 00000000..046908c5 --- /dev/null +++ b/drkonqi/ui/assistantpage_bugzilla_duplicates_dialog_confirmation.ui @@ -0,0 +1,251 @@ + + + ConfirmationDialog + + + + 0 + 0 + 548 + 486 + + + + + + + false + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 17 + 5 + + + + + + + + + + This is likely to be a <strong>common crash</strong>, and a lot of different cases' details may have been provided already. <i>Proceed only if you can add new information (not already mentioned). </i> + + + true + + + + + + + true + + + + + + + + 0 + 0 + + + + + 22 + 22 + + + + true + + + + + + + + 0 + 0 + + + + + 22 + 22 + + + + true + + + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 5 + + + + + + + + <strong>Do you want to proceed with the reporting process?</strong> + + + + + + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 20 + 20 + + + + + + + + + + No, do not file a new bug report, and cancel the assistant + + + buttonGroupProceedQuestion + + + + + + + Proceed with reporting the bug + + + buttonGroupProceedQuestion + + + + + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 5 + + + + + + + + <strong>Are you sure this report matches your crash situation?</strong> + + + + + + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 20 + 20 + + + + + + + + + + Not really sure: mark as a possible duplicate + + + buttonGroupProceed + + + + + + + Completely sure: attach my information to this report + + + buttonGroupProceed + + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + + + diff --git a/drkonqi/ui/assistantpage_bugzilla_information.ui b/drkonqi/ui/assistantpage_bugzilla_information.ui new file mode 100644 index 00000000..b402b492 --- /dev/null +++ b/drkonqi/ui/assistantpage_bugzilla_information.ui @@ -0,0 +1,122 @@ + + + AssistantPageBugzillaInformation + + + + 0 + 0 + 513 + 345 + + + + + + + <strong>Please provide the following information in English.</strong> + + + true + + + + + + + <strong>Title of the bug report:</strong> (<a href="#">examples</a>) + + + + + + + + + + + + <strong>Information about the crash:</strong> (<a href="#">help and examples</a>) + + + + + + + + + false + + + + + + + Distribution method: + + + + + + + + + + + KDE Platform is compiled from sources + + + + + + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 10 + + + + + + + + <note>The crash and system information will be automatically added to the bug report.</note> + + + true + + + + + + + + KLineEdit + QLineEdit +
klineedit.h
+
+ + KComboBox + QComboBox +
kcombobox.h
+
+ + KTextEdit + QTextEdit +
ktextedit.h
+
+
+ + +
diff --git a/drkonqi/ui/assistantpage_bugzilla_login.ui b/drkonqi/ui/assistantpage_bugzilla_login.ui new file mode 100644 index 00000000..7a05bd3f --- /dev/null +++ b/drkonqi/ui/assistantpage_bugzilla_login.ui @@ -0,0 +1,162 @@ + + + AssistantPageBugzillaLogin + + + + 0 + 0 + 488 + 472 + + + + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 5 + + + + + + + + + + Username: + + + + + + + Password: + + + + + + + true + + + true + + + + + + + true + + + + + + + + + Save login information using the KDE Wallet system + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 10 + + + + + + + + true + + + true + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + KPushButton + QPushButton +
kpushbutton.h
+
+ + KLineEdit + QLineEdit +
klineedit.h
+
+ + StatusWidget + QWidget +
statuswidget.h
+ 1 +
+
+ + m_userEdit + m_passwordEdit + m_savePasswordCheckBox + m_loginButton + + + +
diff --git a/drkonqi/ui/assistantpage_bugzilla_preview.ui b/drkonqi/ui/assistantpage_bugzilla_preview.ui new file mode 100644 index 00000000..0b9d7421 --- /dev/null +++ b/drkonqi/ui/assistantpage_bugzilla_preview.ui @@ -0,0 +1,36 @@ + + + AssistantPageBugzillaPreview + + + + 0 + 0 + 545 + 300 + + + + + + + This is a preview of the report's contents which will be sent. <nl /> +If you want to modify it go to the previous pages. + + + true + + + + + + + true + + + + + + + + diff --git a/drkonqi/ui/assistantpage_bugzilla_send.ui b/drkonqi/ui/assistantpage_bugzilla_send.ui new file mode 100644 index 00000000..2b05cef8 --- /dev/null +++ b/drkonqi/ui/assistantpage_bugzilla_send.ui @@ -0,0 +1,132 @@ + + + AssistantPageBugzillaSend + + + + 0 + 0 + 545 + 300 + + + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + + + + Qt::RichText + + + true + + + true + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 10 + + + + + + + + Open the bug report page when clicking the Finish button + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 5 + + + + + + + + Restart the application when clicking the Finish button + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + KPushButton + QPushButton +
kpushbutton.h
+
+ + StatusWidget + QWidget +
statuswidget.h
+ 1 +
+
+ + +
diff --git a/drkonqi/ui/assistantpage_conclusions.ui b/drkonqi/ui/assistantpage_conclusions.ui new file mode 100644 index 00000000..d0a97f13 --- /dev/null +++ b/drkonqi/ui/assistantpage_conclusions.ui @@ -0,0 +1,137 @@ + + + AssistantPageConclusions + + + + 0 + 0 + 506 + 460 + + + + + + + true + + + + + + + true + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + true + + + true + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 5 + + + + + + + + Restart the application when clicking the Finish button + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 5 + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + KPushButton + QPushButton +
kpushbutton.h
+
+
+ + +
diff --git a/drkonqi/ui/assistantpage_conclusions_dialog.ui b/drkonqi/ui/assistantpage_conclusions_dialog.ui new file mode 100644 index 00000000..e7695f2f --- /dev/null +++ b/drkonqi/ui/assistantpage_conclusions_dialog.ui @@ -0,0 +1,34 @@ + + + AssistantPageConclusionsDialog + + + + 0 + 0 + 466 + 385 + + + + + 450 + 350 + + + + + + + + + + + KTextBrowser + QTextBrowser +
ktextbrowser.h
+
+
+ + +
diff --git a/drkonqi/ui/assistantpage_introduction.ui b/drkonqi/ui/assistantpage_introduction.ui new file mode 100644 index 00000000..bed37be8 --- /dev/null +++ b/drkonqi/ui/assistantpage_introduction.ui @@ -0,0 +1,103 @@ + + + AssistantPageIntroduction + + + + 0 + 0 + 536 + 364 + + + + + + + This assistant will analyze the crash information and guide you through the bug reporting process. + + + true + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 10 + + + + + + + + + + + 0 + 0 + + + + + 64 + 64 + + + + + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 10 + 5 + + + + + + + + <p><note>Since communication between you and the developers is required for effective debugging, to continue reporting this bug <strong>it is required for you to agree that developers may contact you.</strong></note></p><p>Feel free to close this dialog if you do not accept this.</p> + + + true + + + + + + + + + Qt::Vertical + + + + 20 + 249 + + + + + + + + + diff --git a/drkonqi/ui/backtracewidget.ui b/drkonqi/ui/backtracewidget.ui new file mode 100644 index 00000000..c94abe3f --- /dev/null +++ b/drkonqi/ui/backtracewidget.ui @@ -0,0 +1,180 @@ + + + Form + + + + 0 + 0 + 511 + 476 + + + + GetBacktraceWidget + + + + + + + + + + + + + 1 + + + + + 0 + + + 0 + + + + + + + + + + 4 + + + + + 10 + + + + + + 0 + 0 + + + + + 48 + 48 + + + + true + + + + + + + true + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + + Show backtrace content (advanced) + + + + + + + + + + + false + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + + + + + + Qt::RichText + + + true + + + false + + + + + + + + + + + + KPushButton + QPushButton +
kpushbutton.h
+
+ + KTextBrowser + QTextBrowser +
ktextbrowser.h
+
+ + StatusWidget + QWidget +
statuswidget.h
+ 1 +
+
+ + +
diff --git a/drkonqi/ui/maindialog.ui b/drkonqi/ui/maindialog.ui new file mode 100644 index 00000000..6f9c38f5 --- /dev/null +++ b/drkonqi/ui/maindialog.ui @@ -0,0 +1,137 @@ + + + MainWidget + + + + 0 + 0 + 404 + 289 + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 20 + + + + + + + + + + + + + + + true + + + + + + + + + + true + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + + + 0 + 0 + + + + + 64 + 64 + + + + + + + + + + + Qt::Vertical + + + QSizePolicy::MinimumExpanding + + + + 20 + 40 + + + + + + + + + + + + + + + true + + + + + + + + + + true + + + Qt::TextBrowserInteraction + + + + + + + + diff --git a/kcmshell/CMakeLists.txt b/kcmshell/CMakeLists.txt new file mode 100644 index 00000000..7943c98d --- /dev/null +++ b/kcmshell/CMakeLists.txt @@ -0,0 +1,9 @@ + +set(kcmshell_KDEINIT_SRCS main.cpp ) + +kde4_add_kdeinit_executable( kcmshell4 ${kcmshell_KDEINIT_SRCS}) + +target_link_libraries(kdeinit_kcmshell4 ${KDE4_KCMUTILS_LIBS} ${KDE4_KDEUI_LIBS} ) + +install(TARGETS kdeinit_kcmshell4 ${INSTALL_TARGETS_DEFAULT_ARGS}) +install(TARGETS kcmshell4 ${INSTALL_TARGETS_DEFAULT_ARGS}) diff --git a/kcmshell/Mainpage.dox b/kcmshell/Mainpage.dox new file mode 100644 index 00000000..0e1abebb --- /dev/null +++ b/kcmshell/Mainpage.dox @@ -0,0 +1,21 @@ +/** @mainpage ./kcmshell + +KCMShell is a small utility to host KDE control modules independently of +SystemSettings. + +@authors +Matthias Hoelzer-Kluepfel \
+Matthias Elter \
+Waldo Bastian \
+Frans Englich \ + +@maintainers +[Unknown/None] + +@licenses +@gpl + +*/ + +// DOXYGEN_SET_PROJECT_NAME = KCMShell +// vim:ts=4:sw=4:expandtab:filetype=doxygen diff --git a/kcmshell/Messages.sh b/kcmshell/Messages.sh new file mode 100644 index 00000000..9805021e --- /dev/null +++ b/kcmshell/Messages.sh @@ -0,0 +1,2 @@ +#! /usr/bin/env bash +$XGETTEXT *.cpp -o $podir/kcmshell.pot diff --git a/kcmshell/main.cpp b/kcmshell/main.cpp new file mode 100644 index 00000000..dab8fc6d --- /dev/null +++ b/kcmshell/main.cpp @@ -0,0 +1,302 @@ +/* + Copyright (c) 1999 Matthias Hoelzer-Kluepfel + Copyright (c) 2000 Matthias Elter + Copyright (c) 2004 Frans Englich + + 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 "main.h" + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "main.moc" + +using namespace std; + +KService::List m_modules; + +static int debugArea() { + static int s_area = KDebug::registerArea("kcmshell"); + return s_area; +} + +static bool caseInsensitiveLessThan(const KService::Ptr s1, const KService::Ptr s2) +{ + const int compare = QString::compare(s1->desktopEntryName(), + s2->desktopEntryName(), + Qt::CaseInsensitive); + return (compare < 0); +} + +static void listModules() +{ + const KService::List services = KServiceTypeTrader::self()->query( "KCModule", "[X-KDE-ParentApp] == 'kcontrol' or [X-KDE-ParentApp] == 'kinfocenter'" ); + for( KService::List::const_iterator it = services.begin(); + it != services.end(); ++it) + { + const KService::Ptr s = (*it); + if (!KAuthorized::authorizeControlModule(s->menuId())) + continue; + m_modules.append(s); + } + + qStableSort(m_modules.begin(), m_modules.end(), caseInsensitiveLessThan); +} + +static KService::Ptr locateModule(const QString& module) +{ + QString path = module; + + if (!path.endsWith(QLatin1String(".desktop"))) + path += ".desktop"; + + KService::Ptr service = KService::serviceByStorageId( path ); + if (!service) { + return KService::Ptr(); + } + + if (!service->hasServiceType("KCModule")) { + // Not a KCModule. E.g. "kcmshell4 akonadi" finds services/kresources/kabc/akonadi.desktop, unrelated. + return KService::Ptr(); + } + + if ( service->noDisplay() ) { + kDebug(debugArea()) << module << " should not be loaded."; + return KService::Ptr(); + } + + return service; +} + +bool KCMShell::isRunning() +{ + QString owner = QDBusConnection::sessionBus().interface()->serviceOwner(m_serviceName); + if( owner == QDBusConnection::sessionBus().baseService() ) + return false; // We are the one and only. + + kDebug(debugArea()) << "kcmshell4 with modules '" << + m_serviceName << "' is already running." << endl; + + QDBusInterface iface(m_serviceName, "/KCModule/dialog", "org.kde.KCMShellMultiDialog"); + QDBusReply reply = iface.call("activate", kapp->startupId()); + if (!reply.isValid()) + { + kDebug(debugArea()) << "Calling D-Bus function dialog::activate() failed."; + return false; // Error, we have to do it ourselves. + } + + return true; +} + +KCMShellMultiDialog::KCMShellMultiDialog(KPageDialog::FaceType dialogFace, QWidget *parent) + : KCMultiDialog(parent) +{ + setFaceType(dialogFace); + setModal(true); + + QDBusConnection::sessionBus().registerObject("/KCModule/dialog", this, QDBusConnection::ExportScriptableSlots); +} + +void KCMShellMultiDialog::activate( const QByteArray& asn_id ) +{ + kDebug(debugArea()) ; + +#ifdef Q_WS_X11 + KStartupInfo::setNewStartupId( this, asn_id ); +#endif +} + +void KCMShell::setServiceName(const QString &dbusName ) +{ + m_serviceName = QLatin1String( "org.kde.kcmshell_" ) + dbusName; + QDBusConnection::sessionBus().registerService(m_serviceName); +} + +void KCMShell::waitForExit() +{ + kDebug(debugArea()); + + QDBusServiceWatcher *watcher = new QDBusServiceWatcher(this); + watcher->setConnection(QDBusConnection::sessionBus()); + watcher->setWatchMode(QDBusServiceWatcher::WatchForOwnerChange); + watcher->addWatchedService(m_serviceName); + connect(watcher, SIGNAL(serviceOwnerChanged(QString,QString,QString)), + SLOT(appExit(QString,QString,QString))); + exec(); +} + +void KCMShell::appExit(const QString &appId, const QString &oldName, const QString &newName) +{ + Q_UNUSED(appId); + Q_UNUSED(newName); + kDebug(debugArea()); + + if (!oldName.isEmpty()) + { + kDebug(debugArea()) << "'" << appId << "' closed, dereferencing."; + KGlobal::deref(); + } +} + +extern "C" KDE_EXPORT int kdemain(int _argc, char *_argv[]) +{ + KAboutData aboutData( "kcmshell", 0, ki18n("KDE Control Module"), + KDE_VERSION_STRING, + ki18n("A tool to start single KDE control modules"), + KAboutData::License_GPL, + ki18n("(c) 1999-2004, The KDE Developers") ); + + aboutData.addAuthor(ki18n("Frans Englich"), ki18n("Maintainer"), "frans.englich@kde.org"); + aboutData.addAuthor(ki18n("Daniel Molkentin"), KLocalizedString(), "molkentin@kde.org"); + aboutData.addAuthor(ki18n("Matthias Hoelzer-Kluepfel"),KLocalizedString(), "hoelzer@kde.org"); + aboutData.addAuthor(ki18n("Matthias Elter"),KLocalizedString(), "elter@kde.org"); + aboutData.addAuthor(ki18n("Matthias Ettrich"),KLocalizedString(), "ettrich@kde.org"); + aboutData.addAuthor(ki18n("Waldo Bastian"),KLocalizedString(), "bastian@kde.org"); + + KCmdLineArgs::init(_argc, _argv, &aboutData); + + KCmdLineOptions options; + options.add("list", ki18n("List all possible modules")); + options.add("+module", ki18n("Configuration module to open")); + options.add("lang ", ki18n("Specify a particular language")); + options.add("silent", ki18n("Do not display main window")); + options.add("args ", ki18n("Arguments for the module")); + KCmdLineArgs::addCmdLineOptions( options ); // Add our own options. + KCMShell app; + + const KCmdLineArgs *args = KCmdLineArgs::parsedArgs(); + + const QString lang = args->getOption("lang"); + if( !lang.isEmpty() ) { + KGlobal::setLocale(new KLocale(aboutData.catalogName(), lang)); + } + + if (args->isSet("list")) + { + cout << i18n("The following modules are available:").toLocal8Bit().data() << endl; + + listModules(); + + int maxLen=0; + + for( KService::List::ConstIterator it = m_modules.constBegin(); it != m_modules.constEnd(); ++it) + { + int len = (*it)->desktopEntryName().length(); + if (len > maxLen) + maxLen = len; + } + + for( KService::List::ConstIterator it = m_modules.constBegin(); it != m_modules.constEnd(); ++it) + { + QString entry("%1 - %2"); + + entry = entry.arg((*it)->desktopEntryName().leftJustified(maxLen, ' ')) + .arg(!(*it)->comment().isEmpty() ? (*it)->comment() + : i18n("No description available")); + + cout << entry.toLocal8Bit().data() << endl; + } + return 0; + } + + if (args->count() < 1) + { + args->usage(); + return -1; + } + + QString serviceName; + KService::List modules; + for (int i = 0; i < args->count(); i++) + { + const QString arg = args->arg(i); + KService::Ptr service = locateModule(arg); + if (!service) { + service = locateModule("kcm_" + arg); + } + if (!service) { + service = locateModule("kcm" + arg); + } + + if (service) { + modules.append(service); + if( !serviceName.isEmpty() ) + serviceName += '_'; + serviceName += args->arg(i); + } else { + fprintf(stderr, "%s\n", i18n("Could not find module '%1'. See kcmshell4 --list for the full list of modules.", arg).toLocal8Bit().constData()); + } + } + + /* Check if this particular module combination is already running */ + app.setServiceName(serviceName); + if( app.isRunning() ) { + app.waitForExit(); + return 0; + } + + KPageDialog::FaceType ftype = KPageDialog::Plain; + + if (modules.count() < 1) { + return 0; + } else if (modules.count() > 1) { + ftype = KPageDialog::List; + } + + QStringList moduleArgs; + QString x = args->getOption("args"); + moduleArgs << x.split(QRegExp(" +")); + + KCMShellMultiDialog *dlg = new KCMShellMultiDialog(ftype); + KCmdLineArgs *kdeargs = KCmdLineArgs::parsedArgs("kde"); + if (kdeargs && kdeargs->isSet("caption")) { + dlg->setCaption(QString()); + kdeargs->clear(); + } else if (modules.count() == 1) { + dlg->setCaption(modules.first()->name()); + } + + for (KService::List::ConstIterator it = modules.constBegin(); it != modules.constEnd(); ++it) + dlg->addModule(*it, 0, moduleArgs); + + if ( !args->isSet( "icon" ) && modules.count() == 1) + { + QString iconName = KCModuleInfo(modules.first()).icon(); + dlg->setWindowIcon( KIcon(iconName) ); + } + dlg->exec(); + delete dlg; + + return 0; +} +// vim: sw=4 et sts=4 diff --git a/kcmshell/main.h b/kcmshell/main.h new file mode 100644 index 00000000..30cb4f7a --- /dev/null +++ b/kcmshell/main.h @@ -0,0 +1,104 @@ +/* + Copyright (c) 2001 Waldo Bastian + Copyright (c) 2004 Frans Englich + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. + +*/ + +#ifndef MAIN_H +#define MAIN_H + +#include +#include +#include + +/** + * The KApplication instance for kcmshell. + */ +class KCMShell : public KApplication +{ + Q_OBJECT + +public: + + /** + * Sets m_serviceName basically to @p serviceName, + * and then registers with D-BUS. + * + * @param serviceName name to set the D-BUS name to + */ + void setServiceName(const QString &serviceName ); + + /** + * Waits until the last instance of kcmshell with the same + * module as this one exits, and then exits. + */ + void waitForExit(); + + /** + * @return true if the shell is running + */ + bool isRunning(); + +private Q_SLOTS: + + /** + */ + void appExit( const QString &appId, const QString &, const QString & ); + +private: + + /** + * The D-Bus name which actually is registered. + * For example "kcmshell_mouse". + */ + QString m_serviceName; + +}; + + +/** + * Essentially a plain KCMultiDialog, but has the additional functionality + * of allowing it to be told to request windows focus. + * + * @author Waldo Bastian + */ +class KCMShellMultiDialog : public KCMultiDialog +{ + Q_OBJECT + Q_CLASSINFO("D-Bus Interface", "org.kde.KCMShellMultiDialog") + +public: + + /** + * Constructor. Parameter @p dialogFace is passed to KCMultiDialog + * unchanged. + */ + explicit KCMShellMultiDialog(KPageDialog::FaceType dialogFace, QWidget *parent = 0); + +public Q_SLOTS: + + /** + * Activate a module with id @p asn_id . This is used when + * black helicopters are spotted overhead. + */ + virtual Q_SCRIPTABLE void activate( const QByteArray& asn_id ); + +}; + +// vim: sw=4 et sts=4 +#endif // MAIN_H diff --git a/kde-menu/CMakeLists.txt b/kde-menu/CMakeLists.txt new file mode 100644 index 00000000..57444a1a --- /dev/null +++ b/kde-menu/CMakeLists.txt @@ -0,0 +1,7 @@ + +kde4_add_executable(kde4-menu NOGUI kde-menu.cpp) + +target_link_libraries(kde4-menu ${KDE4_KIO_LIBS}) + +install(TARGETS kde4-menu ${INSTALL_TARGETS_DEFAULT_ARGS} ) + diff --git a/kde-menu/Messages.sh b/kde-menu/Messages.sh new file mode 100755 index 00000000..9acf20e0 --- /dev/null +++ b/kde-menu/Messages.sh @@ -0,0 +1,2 @@ +#! /usr/bin/env bash +$XGETTEXT *.cpp -o $podir/kde-menu.pot diff --git a/kde-menu/kde-menu.cpp b/kde-menu/kde-menu.cpp new file mode 100644 index 00000000..bb692a34 --- /dev/null +++ b/kde-menu/kde-menu.cpp @@ -0,0 +1,171 @@ +// -*- c-basic-offset: 3 -*- +/* This file is part of the KDE libraries + * Copyright (C) 2003 Waldo Bastian + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License version 2 as published by the Free Software Foundation; + * + * This library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + **/ + +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "klauncher_iface.h" +#include + +static const char appName[] = "kde-menu"; +static const char appVersion[] = "1.0"; +static bool utf8; + +static bool bPrintMenuId; +static bool bPrintMenuName; +static bool bHighlight; + +static void result(const QString &txt) +{ + if (utf8) + puts( txt.toUtf8() ); + else + puts( txt.toLocal8Bit() ); +} + +static void error(int exitCode, const QString &txt) +{ + qWarning("kde-menu: %s", txt.toLocal8Bit().data()); + exit(exitCode); +} + +static void findMenuEntry(KServiceGroup::Ptr parent, const QString &name, const QString &menuId) +{ + const KServiceGroup::List list = parent->entries(true, true, false); + KServiceGroup::List::ConstIterator it = list.constBegin(); + for (; it != list.constEnd(); ++it) + { + KSycocaEntry::Ptr e = (*it); + + if (e->isType(KST_KServiceGroup)) + { + KServiceGroup::Ptr g = KServiceGroup::Ptr::staticCast( e ); + + findMenuEntry(g, name.isEmpty() ? g->caption() : name+'/'+g->caption(), menuId); + } + else if (e->isType(KST_KService)) + { + KService::Ptr s = KService::Ptr::staticCast( e ); + if (s->menuId() == menuId) + { + if (bPrintMenuId) + { + result(parent->relPath()); + } + if (bPrintMenuName) + { + result(name); + } +#if 0 +#ifdef Q_WS_X11 + if (bHighlight) + { + QDBusInterface kicker( "org.kde.kicker", "/kicker", "org.kde.Kicker" ); + QDBusReply result = kicker.call( "highlightMenuItem", menuId ); + if (!result.isValid()) + error(3, i18n("Menu item '%1' could not be highlighted.", menuId).toLocal8Bit()); + } +#endif +#endif + exit(0); + } + } + } +} + + +int main(int argc, char **argv) +{ + const char *description = I18N_NOOP("KDE Menu query tool.\n" + "This tool can be used to find in which menu a specific application is shown.\n" + "The --highlight option can be used to visually indicate to the user where\n" + "in the KDE menu a specific application is located."); + + KAboutData d(appName, "kde-menu", ki18n("kde-menu"), appVersion, + ki18n(description), + KAboutData::License_GPL, ki18n("(c) 2003 Waldo Bastian")); + d.addAuthor(ki18n("Waldo Bastian"), ki18n("Author"), "bastian@kde.org"); + + KCmdLineArgs::init(argc, argv, &d); + + KCmdLineOptions options; + options.add("utf8", ki18n("Output data in UTF-8 instead of local encoding")); + options.add("print-menu-id", ki18n("Print menu-id of the menu that contains\nthe application")); + options.add("print-menu-name", ki18n("Print menu name (caption) of the menu that\ncontains the application")); + options.add("highlight", ki18n("Highlight the entry in the menu")); + options.add("nocache-update", ki18n("Do not check if sycoca database is up to date")); + options.add("+", ki18n("The id of the menu entry to locate")); + KCmdLineArgs::addCmdLineOptions(options); + +// KApplication k(false, false); + KApplication k(false); + k.disableSessionManagement(); + + KCmdLineArgs *args = KCmdLineArgs::parsedArgs(); + if (args->count() != 1) + KCmdLineArgs::usageError(i18n("You must specify an application-id such as 'kde4-konsole.desktop'")); + + utf8 = args->isSet("utf8"); + + bPrintMenuId = args->isSet("print-menu-id"); + bPrintMenuName = args->isSet("print-menu-name"); + bHighlight = args->isSet("highlight"); + + if (!bPrintMenuId && !bPrintMenuName && !bHighlight) + KCmdLineArgs::usageError(i18n("You must specify at least one of --print-menu-id, --print-menu-name or --highlight")); + + if (args->isSet("cache-update")) + { + QStringList args; + args.append("--incremental"); + args.append("--checkstamps"); + QString command = KStandardDirs::findExe(KBUILDSYCOCA_EXENAME); + QDBusMessage reply = KToolInvocation::klauncher()->call("kdeinit_exec_wait", command, args, QStringList(), QString()); + if (reply.type() != QDBusMessage::ReplyMessage) + { + qWarning("Can not talk to klauncher!"); + command = KGlobal::dirs()->findExe(command); + command += ' ' + args.join(" "); + system(command.toLocal8Bit()); + } + } + + QString menuId = args->arg(0); + KService::Ptr s = KService::serviceByMenuId(menuId); + + if (!s) + error(1, i18n("No menu item '%1'.", menuId)); + + findMenuEntry(KServiceGroup::root(), "", menuId); + + error(2, i18n("Menu item '%1' not found in menu.", menuId)); + return 2; +} + diff --git a/kdebugdialog/CMakeLists.txt b/kdebugdialog/CMakeLists.txt new file mode 100644 index 00000000..64dee72e --- /dev/null +++ b/kdebugdialog/CMakeLists.txt @@ -0,0 +1,20 @@ + + + + +########### next target ############### + +set(kdebugdialog_SRCS + main.cpp + kabstractdebugdialog.cpp + kdebugdialog.cpp + klistdebugdialog.cpp ) + +kde4_add_ui_files(kdebugdialog_SRCS kdebugdialog.ui) + +kde4_add_executable(kdebugdialog ${kdebugdialog_SRCS}) + +target_link_libraries(kdebugdialog ${KDE4_KDEUI_LIBS} ) + +install(TARGETS kdebugdialog ${INSTALL_TARGETS_DEFAULT_ARGS}) + diff --git a/kdebugdialog/Messages.sh b/kdebugdialog/Messages.sh new file mode 100644 index 00000000..8d44d418 --- /dev/null +++ b/kdebugdialog/Messages.sh @@ -0,0 +1,4 @@ +#! /usr/bin/env bash +$EXTRACTRC *.ui >> rc.cpp || exit 11 +$XGETTEXT *.cpp -o $podir/kdebugdialog.pot +rm -f rc.cpp diff --git a/kdebugdialog/README b/kdebugdialog/README new file mode 100644 index 00000000..e1d23922 --- /dev/null +++ b/kdebugdialog/README @@ -0,0 +1,12 @@ +kdebugdialog +------------ + +In --fullmode, you can choose to dump debug output to a file. +But keep in mind that multiple programs may be writing to that +area (and therefore to that file), so they will always be appending +to it and never clearing it. So don't forget to empty it once in a +while! + +Your configuration will of course be stored in + $HOME/.kde/share/config/kdebugrc + diff --git a/kdebugdialog/kabstractdebugdialog.cpp b/kdebugdialog/kabstractdebugdialog.cpp new file mode 100644 index 00000000..a6c34653 --- /dev/null +++ b/kdebugdialog/kabstractdebugdialog.cpp @@ -0,0 +1,75 @@ +/* This file is part of the KDE libraries + Copyright (C) 2000 David Faure + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "kabstractdebugdialog.h" +#include +#include +#include +#include +#include +#include +#include + +KAbstractDebugDialog::KAbstractDebugDialog(QWidget *parent) + : KDialog(parent) +{ + pConfig = new KConfig( "kdebugrc", KConfig::NoGlobals ); +} + +KAbstractDebugDialog::~KAbstractDebugDialog() +{ + delete pConfig; +} + +void KAbstractDebugDialog::buildButtons() +{ + setButtons(KDialog::Help | KDialog::Ok | KDialog::Apply | KDialog::Cancel); + + connect(this, SIGNAL(helpClicked()), SLOT( slotShowHelp() )); + connect(this, SIGNAL(okClicked()), SLOT( accept() )); + connect(this, SIGNAL(applyClicked()), SLOT( slotApply() )); + connect(this, SIGNAL(cancelClicked()), SLOT( reject() )); +} + +void KAbstractDebugDialog::slotShowHelp() +{ + KToolInvocation::invokeHelp(); +} + +void KAbstractDebugDialog::slotApply() +{ + save(); + pConfig->sync(); +} + +void KAbstractDebugDialog::save() +{ + doSave(); + KConfigGroup topGroup(pConfig, QString()); + topGroup.writeEntry("DisableAll", m_disableAll->isChecked()); +} + +void KAbstractDebugDialog::load() +{ + doLoad(); + KConfigGroup topGroup(pConfig, QString()); + m_disableAll->setChecked(topGroup.readEntry("DisableAll", false)); +} + +#include "kabstractdebugdialog.moc" diff --git a/kdebugdialog/kabstractdebugdialog.h b/kdebugdialog/kabstractdebugdialog.h new file mode 100644 index 00000000..25f0bd42 --- /dev/null +++ b/kdebugdialog/kabstractdebugdialog.h @@ -0,0 +1,57 @@ +/* This file is part of the KDE libraries + Copyright (C) 2000 David Faure + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef KABSTRACTDEBUGDIALOG__H +#define KABSTRACTDEBUGDIALOG__H + +#include + +class QCheckBox; +class KConfig; +class QVBoxLayout; +class KPushButton; + +class KAbstractDebugDialog : public KDialog +{ + Q_OBJECT +public: + explicit KAbstractDebugDialog(QWidget *parent); + + virtual ~KAbstractDebugDialog(); + + void buildButtons(); + + void load(); + void save(); + virtual void doLoad() = 0; + virtual void doSave() = 0; + KConfig * config() { return pConfig; } + + typedef QMap AreaMap; + +protected Q_SLOTS: + void slotShowHelp(); + void slotApply(); + +protected: + KConfig* pConfig; + QCheckBox* m_disableAll; +}; + +#endif diff --git a/kdebugdialog/kdebugdialog.cpp b/kdebugdialog/kdebugdialog.cpp new file mode 100644 index 00000000..7b9ddee0 --- /dev/null +++ b/kdebugdialog/kdebugdialog.cpp @@ -0,0 +1,187 @@ +/* This file is part of the KDE libraries + Copyright (C) 1997 Matthias Kalle Dalheimer (kalle@kde.org) + Copyright (C) 1999 David Faure (faure@kde.org) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "kdebugdialog.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +KDebugDialog::KDebugDialog(const AreaMap& areaMap, QWidget* parent) + : KAbstractDebugDialog(parent) +{ + setCaption(i18n("Debug Settings")); + setButtons(None); + + setupUi(mainWidget()); + mainWidget()->layout()->setContentsMargins(0, 0, 0, 0); + + // Debug area tree + m_incrSearch->searchLine()->addTreeWidget(m_areaWidget); + + for( QMap::const_iterator it = areaMap.begin(); it != areaMap.end(); ++it ) { + QTreeWidgetItem* item = new QTreeWidgetItem(m_areaWidget, QStringList() << it.value()); + item->setData(0, Qt::UserRole, it.key().simplified()); + } + + QStringList destList; + destList.append( i18n("File") ); + destList.append( i18n("Message Box") ); + destList.append( i18n("Shell") ); + destList.append( i18n("Syslog") ); + destList.append( i18n("None") ); + + // + // Upper left frame + // + connect(pInfoCombo, SIGNAL(activated(int)), + this, SLOT(slotDestinationChanged())); + pInfoCombo->addItems( destList ); + + // + // Upper right frame + // + connect(pWarnCombo, SIGNAL(activated(int)), + this, SLOT(slotDestinationChanged())); + pWarnCombo->addItems( destList ); + + // + // Lower left frame + // + connect(pErrorCombo, SIGNAL(activated(int)), + this, SLOT(slotDestinationChanged())); + pErrorCombo->addItems( destList ); + + // + // Lower right frame + // + connect(pFatalCombo, SIGNAL(activated(int)), + this, SLOT(slotDestinationChanged())); + pFatalCombo->addItems( destList ); + + // Hack! + m_disableAll = m_disableAll2; + connect(m_disableAll, SIGNAL(toggled(bool)), this, SLOT(disableAllClicked())); + + showButtonSeparator(true); + buildButtons(); + + connect( m_areaWidget, SIGNAL(currentItemChanged(QTreeWidgetItem*, QTreeWidgetItem*)), + SLOT(slotDebugAreaChanged(QTreeWidgetItem*)) ); + + // Get initial values + showArea(QString("0")); + + load(); + + resize(600, height()); +} + +KDebugDialog::~KDebugDialog() +{ +} + +void KDebugDialog::slotDebugAreaChanged(QTreeWidgetItem* item) +{ + // Save settings from previous page + save(); + + const QString areaName = item->data(0, Qt::UserRole).toString(); + showArea(areaName); +} + +void KDebugDialog::showArea(const QString& areaName) +{ + /* Fill dialog fields with values from config data */ + mCurrentDebugArea = areaName; + KConfigGroup group = pConfig->group(areaName); + pInfoCombo->setCurrentIndex( group.readEntry( "InfoOutput", 2 ) ); + pInfoFile->setText( group.readPathEntry( "InfoFilename","kdebug.dbg" ) ); + //pInfoShow->setText( group.readEntry( "InfoShow" ) ); + pWarnCombo->setCurrentIndex( group.readEntry( "WarnOutput", 2 ) ); + pWarnFile->setText( group.readPathEntry( "WarnFilename","kdebug.dbg" ) ); + //pWarnShow->setText( group.readEntry( "WarnShow" ) ); + pErrorCombo->setCurrentIndex( group.readEntry( "ErrorOutput", 2 ) ); + pErrorFile->setText( group.readPathEntry( "ErrorFilename","kdebug.dbg") ); + //pErrorShow->setText( group.readEntry( "ErrorShow" ) ); + pFatalCombo->setCurrentIndex( group.readEntry( "FatalOutput", 2 ) ); + pFatalFile->setText( group.readPathEntry("FatalFilename","kdebug.dbg") ); + //pFatalShow->setText( group.readEntry( "FatalShow" ) ); + pAbortFatal->setChecked( group.readEntry( "AbortFatal", 1 ) ); + slotDestinationChanged(); +} + +void KDebugDialog::doSave() +{ + KConfigGroup group = pConfig->group( mCurrentDebugArea ); // Group name = debug area code + group.writeEntry( "InfoOutput", pInfoCombo->currentIndex() ); + group.writePathEntry( "InfoFilename", pInfoFile->text() ); + //group.writeEntry( "InfoShow", pInfoShow->text() ); + group.writeEntry( "WarnOutput", pWarnCombo->currentIndex() ); + group.writePathEntry( "WarnFilename", pWarnFile->text() ); + //group.writeEntry( "WarnShow", pWarnShow->text() ); + group.writeEntry( "ErrorOutput", pErrorCombo->currentIndex() ); + group.writePathEntry( "ErrorFilename", pErrorFile->text() ); + //group.writeEntry( "ErrorShow", pErrorShow->text() ); + group.writeEntry( "FatalOutput", pFatalCombo->currentIndex() ); + group.writePathEntry( "FatalFilename", pFatalFile->text() ); + //group.writeEntry( "FatalShow", pFatalShow->text() ); + group.writeEntry( "AbortFatal", pAbortFatal->isChecked() ); + + QDBusMessage msg = QDBusMessage::createSignal("/", "org.kde.KDebug", "configChanged"); + if (!QDBusConnection::sessionBus().send(msg)) + { + kError() << "Unable to send D-BUS message" << endl; + } +} + +void KDebugDialog::slotDestinationChanged() +{ + pInfoFile->setEnabled(pInfoCombo->currentIndex() == 0); + pWarnFile->setEnabled(pWarnCombo->currentIndex() == 0); + pErrorFile->setEnabled(pErrorCombo->currentIndex() == 0); + pFatalFile->setEnabled(pFatalCombo->currentIndex() == 0); +} + +void KDebugDialog::disableAllClicked() +{ + kDebug(); + bool enabled = !m_disableAll->isChecked(); + m_areaWidget->setEnabled(enabled); + pInfoGroup->setEnabled(enabled); + pWarnGroup->setEnabled(enabled); + pErrorGroup->setEnabled(enabled); + pFatalGroup->setEnabled(enabled); + pAbortFatal->setEnabled(enabled); +} + +#include "kdebugdialog.moc" diff --git a/kdebugdialog/kdebugdialog.h b/kdebugdialog/kdebugdialog.h new file mode 100644 index 00000000..0f68d934 --- /dev/null +++ b/kdebugdialog/kdebugdialog.h @@ -0,0 +1,66 @@ +/* This file is part of the KDE libraries + Copyright (C) 1997 Matthias Kalle Dalheimer (kalle@kde.org) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ +#ifndef _KDEBUGDIALOG +#define _KDEBUGDIALOG + +#include "kabstractdebugdialog.h" + +#include "ui_kdebugdialog.h" + +class QLineEdit; +class QComboBox; +class QLabel; +class QGroupBox; +class QCheckBox; + +/** + * Control debug/warning/error/fatal output of KDE applications + * + * This dialog allows control of debugging output for all KDE apps. + * + * @author Kalle Dalheimer (kalle@kde.org) + */ +class KDebugDialog : public KAbstractDebugDialog, public Ui_KDebugDialog +{ + Q_OBJECT + +public: + explicit KDebugDialog(const AreaMap& areaMap, QWidget *parent = 0); + virtual ~KDebugDialog(); + + void doLoad() {} + void doSave(); + +protected Q_SLOTS: + void slotDebugAreaChanged(QTreeWidgetItem*); + void slotDestinationChanged(); + void disableAllClicked(); + +private: + void showArea(const QString& areaName); + + QString mCurrentDebugArea; + +private: + // Disallow assignment and copy-construction + KDebugDialog( const KDebugDialog& ); + KDebugDialog& operator= ( const KDebugDialog& ); +}; + +#endif diff --git a/kdebugdialog/kdebugdialog.ui b/kdebugdialog/kdebugdialog.ui new file mode 100644 index 00000000..6ff4d5a5 --- /dev/null +++ b/kdebugdialog/kdebugdialog.ui @@ -0,0 +1,246 @@ + + + KDebugDialog + + + + 0 + 0 + 481 + 447 + + + + + + + + + + + + QAbstractItemView::NoEditTriggers + + + false + + + true + + + false + + + false + + + + 1 + + + + + + + + + + Information + + + + + + Output to: + + + pInfoCombo + + + + + + + + + + Filename: + + + pInfoFile + + + + + + + + + + + + + Error + + + + + + Output to: + + + pErrorCombo + + + + + + + + + + Filename: + + + pErrorFile + + + + + + + + + + + + + Abort on fatal errors + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + Disable all debug output + + + + + + + Warning + + + + + + Output to: + + + pWarnCombo + + + + + + + + + + Filename: + + + pWarnFile + + + + + + + + + + + + + Fatal Error + + + + + + Output to: + + + pFatalCombo + + + + + + + + + + Filename: + + + pFatalFile + + + + + + + + + + + + + + KComboBox + QComboBox +
kcombobox.h
+
+ + KLineEdit + QLineEdit +
klineedit.h
+
+ + KTreeWidgetSearchLineWidget + QWidget +
ktreewidgetsearchline.h
+
+
+ + m_disableAll2 + m_areaWidget + pInfoCombo + pInfoFile + pWarnCombo + pWarnFile + pErrorCombo + pErrorFile + pFatalCombo + pFatalFile + pAbortFatal + + + +
diff --git a/kdebugdialog/klistdebugdialog.cpp b/kdebugdialog/klistdebugdialog.cpp new file mode 100644 index 00000000..2b64e41a --- /dev/null +++ b/kdebugdialog/klistdebugdialog.cpp @@ -0,0 +1,172 @@ +/* This file is part of the KDE libraries + Copyright (C) 2000 David Faure + Copyright (C) 2005 Hamish Rodda + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "klistdebugdialog.h" + +#include +#include +#include +#include + +#include +#include +#include +#include + +KListDebugDialog::KListDebugDialog(const AreaMap& areaMap, QWidget *parent) + : KAbstractDebugDialog(parent) +{ + setCaption(i18n("Debug Settings")); + QWidget* mainWidget = new QWidget( this ); + QVBoxLayout *lay = new QVBoxLayout( mainWidget ); + lay->setMargin( KDialog::marginHint() ); + lay->setSpacing( KDialog::spacingHint() ); + + m_incrSearch = new KTreeWidgetSearchLineWidget(); + m_incrSearch->searchLine()->setClearButtonShown(true); + lay->addWidget( m_incrSearch ); + // connect( m_incrSearch, SIGNAL( textChanged( const QString& ) ), + // SLOT( filterCheckBoxes( const QString& ) ) ); + + //@TODO: Change back to QListWidget once Trolltech fixed the task: #214420 + //See http://trolltech.com/developer/task-tracker/index_html?id=214420&method=entry + m_areaWidget = new QTreeWidget(); + m_areaWidget->setHeaderHidden(true); + m_areaWidget->setItemsExpandable(false); + m_areaWidget->setRootIsDecorated(false); + m_areaWidget->setUniformRowHeights(true); + lay->addWidget(m_areaWidget); + + m_incrSearch->searchLine()->addTreeWidget(m_areaWidget); + + for( QMap::const_iterator it = areaMap.begin(); it != areaMap.end(); ++it ) { + QTreeWidgetItem* item = new QTreeWidgetItem(m_areaWidget, QStringList() << it.value()); + item->setData(0, Qt::UserRole, it.key().simplified()); + } + + m_buttonContainer = new QWidget(mainWidget); + QHBoxLayout* selectButs = new QHBoxLayout(m_buttonContainer); + lay->addWidget(m_buttonContainer); + QPushButton* all = new QPushButton(i18n("&Select All"), m_buttonContainer); + QPushButton* none = new QPushButton(i18n("&Deselect All"), m_buttonContainer); + selectButs->addWidget( all ); + selectButs->addWidget( none ); + + connect( all, SIGNAL( clicked() ), this, SLOT( selectAll() ) ); + connect( none, SIGNAL( clicked() ), this, SLOT( deSelectAll() ) ); + + m_disableAll = new QCheckBox(mainWidget); + m_disableAll->setText(i18n("Disable all debug output")); + connect(m_disableAll, SIGNAL(toggled(bool)), this, SLOT(disableAllClicked())); + lay->addWidget(m_disableAll); + + load(); + + buildButtons(); + resize( 350, 400 ); + setMainWidget( mainWidget ); + m_incrSearch->searchLine()->setFocus(); +} + +void KListDebugDialog::selectAll() +{ + for (int i = 0; i < m_areaWidget->topLevelItemCount(); ++i) { + QTreeWidgetItem* item = m_areaWidget->topLevelItem(i); + if (!m_areaWidget->isItemHidden(item)) { + item->setCheckState(0, Qt::Checked); + } + } +} + +void KListDebugDialog::deSelectAll() +{ + for (int i = 0; i < m_areaWidget->topLevelItemCount(); ++i) { + QTreeWidgetItem* item = m_areaWidget->topLevelItem(i); + if (!m_areaWidget->isItemHidden(item)) { + item->setCheckState(0, Qt::Unchecked); + } + } +} + +void KListDebugDialog::doLoad() +{ + for (int i = 0; i < m_areaWidget->topLevelItemCount(); ++i) { + QTreeWidgetItem* item = m_areaWidget->topLevelItem(i); + KConfigGroup group = pConfig->group( item->data(0, Qt::UserRole).toByteArray() ); // Group name = debug area code = cb's name + + int setting = group.readEntry("InfoOutput", -1); + + switch (setting) { + case 4: // off + item->setCheckState(0, Qt::Unchecked); + break; + case -1: // default + case 2: //shell + item->setCheckState(0, Qt::Checked); + break; + case 3: //syslog + case 1: //msgbox + case 0: //file + default: + item->setCheckState(0, Qt::PartiallyChecked); + /////// Uses the triState capability of checkboxes + break; + } + } +} + +void KListDebugDialog::doSave() +{ + for (int i = 0; i < m_areaWidget->topLevelItemCount(); ++i) { + QTreeWidgetItem* item = m_areaWidget->topLevelItem(i); + KConfigGroup group = pConfig->group( item->data(0, Qt::UserRole).toByteArray() ); // Group name = debug area code = cb's name + if (item->checkState(0) != Qt::PartiallyChecked) + { + int setting = (item->checkState(0) == Qt::Checked) ? 2 : 4; + group.writeEntry( "InfoOutput", setting ); + } + } + //sync done by main.cpp + + // send DBus message to all clients + QDBusMessage msg = QDBusMessage::createSignal("/", "org.kde.KDebug", "configChanged" ); + if (!QDBusConnection::sessionBus().send(msg)) + { + kError() << "Unable to send D-BUS message" << endl; + } +} + +void KListDebugDialog::activateArea( const QByteArray& area, bool activate ) +{ + foreach(QTreeWidgetItem* item, m_areaWidget->findItems(area, Qt::MatchContains)) { + item->setCheckState( 0, activate ? Qt::Checked : Qt::Unchecked ); + return; + } +} + +void KListDebugDialog::disableAllClicked() +{ + bool allDisabled = m_disableAll->isChecked(); + m_incrSearch->setEnabled(!allDisabled); + m_areaWidget->setEnabled(!allDisabled); + m_buttonContainer->setEnabled(!allDisabled); +} + +#include "klistdebugdialog.moc" diff --git a/kdebugdialog/klistdebugdialog.h b/kdebugdialog/klistdebugdialog.h new file mode 100644 index 00000000..7508e026 --- /dev/null +++ b/kdebugdialog/klistdebugdialog.h @@ -0,0 +1,61 @@ +/* This file is part of the KDE libraries + Copyright (C) 2000 David Faure + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef KLISTDEBUGDIALOG__H +#define KLISTDEBUGDIALOG__H + +#include "kabstractdebugdialog.h" +#include + +class KTreeWidgetSearchLineWidget; +class QTreeWidget; + +/** + * Control debug output of KDE applications + * This dialog offers a reduced functionality compared to the full KDebugDialog + * class, but allows to set debug output on or off to several areas much more easily. + * + * @author David Faure + */ +class KListDebugDialog : public KAbstractDebugDialog +{ + Q_OBJECT + +public: + explicit KListDebugDialog(const AreaMap& areaMap, QWidget *parent = 0); + virtual ~KListDebugDialog() {} + + void activateArea( const QByteArray& area, bool activate ); + +protected Q_SLOTS: + void selectAll(); + void deSelectAll(); + void disableAllClicked(); + +protected: + virtual void doSave(); + virtual void doLoad(); + +private: + QTreeWidget* m_areaWidget; + KTreeWidgetSearchLineWidget *m_incrSearch; + QWidget* m_buttonContainer; +}; + +#endif diff --git a/kdebugdialog/main.cpp b/kdebugdialog/main.cpp new file mode 100644 index 00000000..7ee22b9f --- /dev/null +++ b/kdebugdialog/main.cpp @@ -0,0 +1,146 @@ +/* This file is part of the KDE libraries + Copyright (C) 2000, 2009 David Faure + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "kdebugdialog.h" +#include "klistdebugdialog.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +static KAbstractDebugDialog::AreaMap readAreas() +{ + KAbstractDebugDialog::AreaMap areas; + // Group 0 is not used anymore. kDebug() uses the area named after the appname. + //areas.insert( " 0" /*cf rightJustified below*/, "0 (generic)" ); + + const QString confAreasFile = KStandardDirs::locate("config", "kdebug.areas"); + QFile file( confAreasFile ); + if (!file.open(QIODevice::ReadOnly)) { + kWarning() << "Couldn't open" << confAreasFile; + } else { + QString data; + + QTextStream ts(&file); + ts.setCodec( "ISO-8859-1" ); + while (!ts.atEnd()) { + data = ts.readLine().simplified(); + + int pos = data.indexOf("#"); + if ( pos != -1 ) { + data.truncate( pos ); + data = data.simplified(); + } + + if (data.isEmpty()) + continue; + + const int space = data.indexOf(' '); + if (space == -1) + kError() << "No space:" << data << endl; + + bool longOK; + unsigned long number = data.left(space).toULong(&longOK); + if (!longOK) + kError() << "The first part wasn't a number : " << data << endl; + + const QString description = data.mid(space).simplified(); + + // In the key, right-align the area number to 6 digits for proper sorting + const QString key = QString::number(number).rightJustified(6); + areas.insert( key, QString("%1 %2").arg(number).arg(description) ); + } + } + + bool ok; +#ifndef NDEBUG + // Builtin unittest for our expectations of QString::toInt + QString("4a").toInt(&ok); + Q_ASSERT(!ok); +#endif + + KConfig config("kdebugrc", KConfig::NoGlobals); + Q_FOREACH(const QString& groupName, config.groupList()) { + groupName.toInt(&ok); + if (ok) + continue; // we are not interested in old-style number-only groups + areas.insert(groupName, groupName); // ID == description + } + + return areas; +} + +int main(int argc, char ** argv) +{ + KAboutData data( "kdebugdialog", 0, ki18n( "KDebugDialog"), + "1.0", ki18n("A dialog box for setting preferences for debug output"), + KAboutData::License_GPL, ki18n("Copyright 1999-2009, David Faure faure@kde.org")); + data.addAuthor(ki18n("David Faure"), ki18n("Maintainer"), "faure@kde.org"); + data.setProgramIconName("tools-report-bug"); + KCmdLineArgs::init( argc, argv, &data ); + + KCmdLineOptions options; + options.add("fullmode", ki18n("Show the fully-fledged dialog instead of the default list dialog")); + options.add("on ", ki18n(/*I18N_NOOP TODO*/ "Turn area on")); + options.add("off ", ki18n(/*I18N_NOOP TODO*/ "Turn area off")); + KCmdLineArgs::addCmdLineOptions( options ); + KUniqueApplication::addCmdLineOptions(); + KUniqueApplication app; + KCmdLineArgs *args = KCmdLineArgs::parsedArgs(); + + KAbstractDebugDialog * dialog; + if (args->isSet("fullmode")) { + dialog = new KDebugDialog(readAreas()); + } else { + KListDebugDialog * listdialog = new KListDebugDialog(readAreas()); + if (args->isSet("on")) + { + listdialog->activateArea( args->getOption("on").toUtf8(), true ); + /*listdialog->save(); + listdialog->config()->sync(); + return 0;*/ + } else if ( args->isSet("off") ) + { + listdialog->activateArea( args->getOption("off").toUtf8(), false ); + /*listdialog->save(); + listdialog->config()->sync(); + return 0;*/ + } + dialog = listdialog; + } + + /* Show dialog */ + int nRet = dialog->exec(); + if( nRet == QDialog::Accepted ) + { + dialog->save(); + dialog->config()->sync(); + } + else + dialog->config()->markAsClean(); + + return 0; +} diff --git a/kdeeject/CMakeLists.txt b/kdeeject/CMakeLists.txt new file mode 100644 index 00000000..ba0cb791 --- /dev/null +++ b/kdeeject/CMakeLists.txt @@ -0,0 +1 @@ +install(PROGRAMS kdeeject DESTINATION ${LIBEXEC_INSTALL_DIR}) diff --git a/kdeeject/kdeeject b/kdeeject/kdeeject new file mode 100755 index 00000000..e9307dc6 --- /dev/null +++ b/kdeeject/kdeeject @@ -0,0 +1,37 @@ +#!/bin/sh +# Script used by kdesktop to eject a removable media (CDROM/Tape/SCSI/Floppy) +# Relies on the 'eject' program, 'cdcontrol' on *BSD +# +# Copyright GPL v2 by David Faure +# +if test $# -ge 1 -a "$1" != "--help"; then + quiet=0 + if test "$1" = "-q"; then + quiet=1 + shift + fi + # Checking for stuff in the PATH is ugly with sh. + # I guess this is the reason for making this a kde app... + OS=`uname -s` + case "$OS" in + OpenBSD) + cdio -f $1 eject >/dev/null 2>&1 + ;; + *BSD) + dev=`echo $1 | sed -E -e 's#/dev/##' -e 's/([0-9])./\1/'` + cdcontrol -f $dev eject >/dev/null 2>&1 + ;; + *) + eject $1 >/dev/null 2>&1 + ;; + esac + if test $? -eq 0; then + qdbus org.kde.kdesktop /Desktop refreshIcons + exit 0 + elif test $quiet -eq 0; then + kdialog --title "KDE Eject" --error "Eject $1 failed!" + fi +else + kdialog --title "KDE Eject" --msgbox "Usage: $0 where name is a device or a mountpoint." +fi +exit 1 diff --git a/kdontchangethehostname/CMakeLists.txt b/kdontchangethehostname/CMakeLists.txt new file mode 100644 index 00000000..be88d199 --- /dev/null +++ b/kdontchangethehostname/CMakeLists.txt @@ -0,0 +1,5 @@ +set(kdontchangethehostname_SRCS khostname.cpp ) +kde4_add_executable(kdontchangethehostname NOGUI ${kdontchangethehostname_SRCS}) +target_link_libraries(kdontchangethehostname ${KDE4_KDECORE_LIBS} ) +install(TARGETS kdontchangethehostname DESTINATION ${LIBEXEC_INSTALL_DIR} ) + diff --git a/kdontchangethehostname/Messages.sh b/kdontchangethehostname/Messages.sh new file mode 100755 index 00000000..9ac9ca0a --- /dev/null +++ b/kdontchangethehostname/Messages.sh @@ -0,0 +1,2 @@ +#! /usr/bin/env bash +$XGETTEXT *.cpp -o $podir/kdontchangethehostname.pot diff --git a/kdontchangethehostname/khostname.cpp b/kdontchangethehostname/khostname.cpp new file mode 100644 index 00000000..41955fae --- /dev/null +++ b/kdontchangethehostname/khostname.cpp @@ -0,0 +1,238 @@ +/* This file is part of the KDE libraries + * Copyright (C) 2001 Waldo Bastian + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License version 2 as published by the Free Software Foundation; + * + * This library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + **/ + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static const char appName[] = "kdontchangethehostname"; +static const char appVersion[] = "1.1"; + +class KHostName +{ +public: + KHostName(); + + void changeX(); + void changeStdDirs(const QByteArray &type); + void changeSessionManager(); + +protected: + QString oldName; + QString newName; + QString display; + QByteArray home; +}; + +KHostName::KHostName() +{ + KCmdLineArgs *args = KCmdLineArgs::parsedArgs(); + if (args->count() != 2) + args->usage(); + oldName = args->arg(0); + newName = args->arg(1); + if (oldName == newName) + exit(0); + + home = qgetenv("HOME"); + if (home.isEmpty()) + { + fprintf(stderr, "%s", i18n("Error: HOME environment variable not set.\n").toLocal8Bit().data()); + exit(1); + } + + display = QString::fromLocal8Bit(qgetenv("DISPLAY")); + // strip the screen number from the display + display.remove(QRegExp("\\.[0-9]+$")); +#if defined(Q_WS_X11) || defined(Q_WS_QWS) + if (display.isEmpty()) + { + fprintf(stderr, "%s", i18n("Error: DISPLAY environment variable not set.\n").toLocal8Bit().data()); + exit(1); + } +#endif +} + +static QList split(const QByteArray &str) +{ + const char *s = str.data(); + QList result; + while (*s) + { + const char *i = strchr(s, ' '); + if (!i) + { + result.append(QByteArray(s)); + return result; + } + result.append(QByteArray(s, i-s+1)); + s = i; + while (*s == ' ') s++; + } + return result; +} + +void KHostName::changeX() +{ + QProcess proc; + proc.start("xauth", QStringList() << "-n" << "list"); + if (!proc.waitForFinished()) + { + fprintf(stderr, "Warning: Can not run xauth.\n"); + return; + } + QList lines; + { + while (!proc.atEnd()) + { + QByteArray line = proc.readLine(); + if (line.length()) + line.truncate(line.length()-1); // Strip LF. + if (!line.isEmpty()) + lines.append(line); + } + } + + foreach ( const QByteArray &it, lines ) + { + QList entries = split(it); + if (entries.count() != 3) + continue; + + QByteArray netId = entries[0]; + QByteArray authName = entries[1]; + QByteArray authKey = entries[2]; + + int i = netId.lastIndexOf(':'); + if (i == -1) + continue; + QByteArray netDisplay = netId.mid(i); + if (netDisplay != display) + continue; + + i = netId.indexOf('/'); + if (i == -1) + continue; + + QString newNetId = newName+netId.mid(i); + QString oldNetId = netId.left(i); + + if (oldNetId != oldName) + continue; + + QProcess::execute("xauth", QStringList() << "-n" << "remove" << netId); + QProcess::execute("xauth", QStringList() << "-n" << "add" << newNetId << authName << authKey); + } +} + +void KHostName::changeStdDirs(const QByteArray &type) +{ + // We make links to the old dirs cause we can't delete the old dirs. + QByteArray oldDir = QFile::encodeName(QString("%1%2-%3").arg(KGlobal::dirs()->localkdedir()).arg(QString( type )).arg(QString( oldName ))); + QByteArray newDir = QFile::encodeName(QString("%1%2-%3").arg(KGlobal::dirs()->localkdedir()).arg(QString( type )).arg(QString( newName ))); + + KDE_struct_stat st_buf; + + int result = KDE_lstat(oldDir.data(), &st_buf); + if (result == 0) + { + if (S_ISLNK(st_buf.st_mode)) + { + char buf[4096+1]; + result = readlink(oldDir.data(), buf, 4096); + if (result >= 0) + { + buf[result] = 0; + result = symlink(buf, newDir.data()); + } + } + else if (S_ISDIR(st_buf.st_mode)) + { + result = symlink(oldDir.data(), newDir.data()); + } + else + { + result = -1; + } + } + if (result != 0) + { + const QString lnusertemp = KGlobal::dirs()->findExe( "lnusertemp" ); + QProcess::execute( lnusertemp, QStringList() << type ); + } +} + +void KHostName::changeSessionManager() +{ + QString sm = QString::fromLocal8Bit(qgetenv("SESSION_MANAGER")); + if (sm.isEmpty()) + { + fprintf(stderr, "Warning: No session management specified.\n"); + return; + } + int i = sm.lastIndexOf(':'); + if ((i == -1) || (sm.left(6) != "local/")) + { + fprintf(stderr, "Warning: Session Management socket '%s' has unexpected format.\n", sm.toLocal8Bit().constData()); + return; + } + sm = "local/"+newName+sm.mid(i); + KToolInvocation::klauncher()->call(QDBus::NoBlock, "setLaunchEnv", QByteArray("SESSION_MANAGER"), sm); +} + +int main(int argc, char **argv) +{ + KAboutData d(appName, "kdelibs4", ki18n("KDontChangeTheHostName"), appVersion, + ki18n("Informs KDE about a change in hostname"), + KAboutData::License_GPL, ki18n("(c) 2001 Waldo Bastian")); + d.addAuthor(ki18n("Waldo Bastian"), ki18n("Author"), "bastian@kde.org"); + + KCmdLineOptions options; + options.add("+old", ki18n("Old hostname")); + options.add("+new", ki18n("New hostname")); + + KCmdLineArgs::init(argc, argv, &d); + KCmdLineArgs::addCmdLineOptions(options); + + KComponentData k(&d); + + KHostName hn; + + hn.changeX(); + hn.changeStdDirs("socket"); + hn.changeStdDirs("tmp"); + hn.changeSessionManager(); +} + diff --git a/keditfiletype/CMakeLists.txt b/keditfiletype/CMakeLists.txt new file mode 100644 index 00000000..040733ea --- /dev/null +++ b/keditfiletype/CMakeLists.txt @@ -0,0 +1,41 @@ +add_subdirectory(tests) + + +set(libfiletypes_SRCS + filetypedetails.cpp + filegroupdetails.cpp + kservicelistwidget.cpp + typeslistitem.cpp + mimetypedata.cpp + mimetypewriter.cpp + newtypedlg.cpp + kserviceselectdlg.cpp + sharedmimeinfoversion.cpp +) + +########### next target ############### + +set(kcm_filetypes_SRCS filetypesview.cpp ${libfiletypes_SRCS}) + +kde4_add_plugin(kcm_filetypes ${kcm_filetypes_SRCS}) + +target_link_libraries(kcm_filetypes ${KDE4_KDEUI_LIBS} ${KDE4_KIO_LIBS}) + +install(TARGETS kcm_filetypes DESTINATION ${PLUGIN_INSTALL_DIR} ) + +########### next target ############### + +set(keditfiletype_SRCS keditfiletype.cpp ${libfiletypes_SRCS}) + +kde4_add_executable(keditfiletype ${keditfiletype_SRCS}) + +target_link_libraries(keditfiletype ${KDE4_KIO_LIBS}) +if (Q_WS_X11) + target_link_libraries(keditfiletype ${X11_X11_LIB}) +endif (Q_WS_X11) + +install(TARGETS keditfiletype ${INSTALL_TARGETS_DEFAULT_ARGS}) + +########### install files ############### + +install( FILES filetypes.desktop DESTINATION ${SERVICES_INSTALL_DIR} ) diff --git a/keditfiletype/Messages.sh b/keditfiletype/Messages.sh new file mode 100644 index 00000000..ebf934ae --- /dev/null +++ b/keditfiletype/Messages.sh @@ -0,0 +1,2 @@ +#! /usr/bin/env bash +$XGETTEXT *.cpp -o $podir/filetypes.pot diff --git a/keditfiletype/filegroupdetails.cpp b/keditfiletype/filegroupdetails.cpp new file mode 100644 index 00000000..c733ba48 --- /dev/null +++ b/keditfiletype/filegroupdetails.cpp @@ -0,0 +1,72 @@ +/* This file is part of the KDE project + Copyright (C) 2000, 2007 David Faure + Copyright (C) 2003 Waldo Bastian + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public + License version 2 or at your option version 3 as published by + the Free Software Foundation. + + 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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ +#include "filegroupdetails.h" +#include "mimetypedata.h" + +#include +#include +#include +#include + +#include + +FileGroupDetails::FileGroupDetails(QWidget *parent) + : QWidget( parent ) +{ + QVBoxLayout *secondLayout = new QVBoxLayout(this); + + QGroupBox *autoEmbedBox = new QGroupBox( i18n("Left Click Action (only for Konqueror file manager)") ); + m_autoEmbed = new QButtonGroup( autoEmbedBox ); + secondLayout->addWidget( autoEmbedBox ); + // The order of those two items is very important. If you change it, fix typeslistitem.cpp ! + QRadioButton *r1 = new QRadioButton( i18n("Show file in embedded viewer")); + QRadioButton *r2 = new QRadioButton( i18n("Show file in separate viewer")); + QVBoxLayout *autoEmbedBoxLayout = new QVBoxLayout(autoEmbedBox); + autoEmbedBoxLayout->addWidget(r1); + autoEmbedBoxLayout->addWidget(r2); + m_autoEmbed->addButton(r1, 0); + m_autoEmbed->addButton(r2, 1); + connect(m_autoEmbed, SIGNAL( buttonClicked( int ) ), SLOT( slotAutoEmbedClicked( int ) )); + + autoEmbedBox->setWhatsThis( i18n("Here you can configure what the Konqueror file manager" + " will do when you click on a file belonging to this group. Konqueror can display the file in" + " an embedded viewer or start up a separate application. You can change this setting for a" + " specific file type in the 'Embedding' tab of the file type configuration. Dolphin " + " shows files always in a separate viewer") ); + + secondLayout->addStretch(); +} + +void FileGroupDetails::setMimeTypeData( MimeTypeData * mimeTypeData ) +{ + Q_ASSERT( mimeTypeData->isMeta() ); + m_mimeTypeData = mimeTypeData; + m_autoEmbed->button( m_mimeTypeData->autoEmbed() )->setChecked( true ); +} + +void FileGroupDetails::slotAutoEmbedClicked(int button) +{ + if ( !m_mimeTypeData ) + return; + m_mimeTypeData->setAutoEmbed( (MimeTypeData::AutoEmbed)button ); + emit changed(true); +} + +#include "filegroupdetails.moc" diff --git a/keditfiletype/filegroupdetails.h b/keditfiletype/filegroupdetails.h new file mode 100644 index 00000000..e99449c9 --- /dev/null +++ b/keditfiletype/filegroupdetails.h @@ -0,0 +1,52 @@ +/* This file is part of the KDE project + Copyright (C) 2000, 2007 David Faure + Copyright (C) 2003 Waldo Bastian + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public + License version 2 or at your option version 3 as published by + the Free Software Foundation. + + 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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ +#ifndef FILEGROUPDETAILS_H +#define FILEGROUPDETAILS_H + +#include +class MimeTypeData; +class QButtonGroup; + +/** + * This widget contains the details for a filetype group. + * Currently this only involves the embedding configuration. + */ +class FileGroupDetails : public QWidget +{ + Q_OBJECT +public: + FileGroupDetails(QWidget *parent = 0); + + void setMimeTypeData( MimeTypeData * mimeTypeData ); + +Q_SIGNALS: + void changed(bool); + +protected Q_SLOTS: + void slotAutoEmbedClicked(int button); + +private: + MimeTypeData * m_mimeTypeData; + + // Embedding config + QButtonGroup *m_autoEmbed; +}; + +#endif diff --git a/keditfiletype/filetypedetails.cpp b/keditfiletype/filetypedetails.cpp new file mode 100644 index 00000000..5c735729 --- /dev/null +++ b/keditfiletype/filetypedetails.cpp @@ -0,0 +1,369 @@ +/* This file is part of the KDE project + Copyright (C) 2000, 2007 David Faure + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public + License version 2 or at your option version 3 as published by + the Free Software Foundation. + + 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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +// Own +#include "filetypedetails.h" +#include "sharedmimeinfoversion.h" + +// Qt +#include +#include +#include +#include +#include +#include +#include + +// KDE +#include +#include +#include +#include +#include +#include +#include +#include + +// Local +#include "kservicelistwidget.h" +#include "typeslistitem.h" + +FileTypeDetails::FileTypeDetails( QWidget * parent ) + : QWidget( parent ), m_mimeTypeData(0), m_item(0) +{ + + QVBoxLayout* topLayout = new QVBoxLayout(this); + + m_mimeTypeLabel = new QLabel(this); + topLayout->addWidget(m_mimeTypeLabel, 0, Qt::AlignCenter); + + m_tabWidget = new QTabWidget(this); + topLayout->addWidget(m_tabWidget); + + QString wtstr; + // First tab - General + QWidget * firstWidget = new QWidget(m_tabWidget); + QVBoxLayout *firstLayout = new QVBoxLayout(firstWidget); + + QHBoxLayout *hBox = new QHBoxLayout(); + firstLayout->addLayout(hBox); + + if (SharedMimeInfoVersion::supportsIcon()) { + iconButton = new KIconButton(firstWidget); + iconButton->setIconType(KIconLoader::Desktop, KIconLoader::MimeType); + connect(iconButton, SIGNAL(iconChanged(QString)), SLOT(updateIcon(QString))); + iconButton->setWhatsThis( i18n("This button displays the icon associated" + " with the selected file type. Click on it to choose a different icon.") ); + iconButton->setFixedSize(70, 70); + iconLabel = 0; + hBox->addWidget(iconButton); + } else { + iconButton = 0; + iconLabel = new QLabel(firstWidget); + iconLabel->setWhatsThis( i18n("This is the icon associated with the selected file type. " + "Choosing a different icon requires shared-mime-info to be at least version 0.40.") ); + iconLabel->setFixedSize(70, 70); + hBox->addWidget(iconLabel); + } + + QGroupBox *gb = new QGroupBox(i18n("Filename Patterns"), firstWidget); + hBox->addWidget(gb); + + hBox = new QHBoxLayout(gb); + + extensionLB = new QListWidget(gb); + connect(extensionLB, SIGNAL(itemSelectionChanged()), SLOT(enableExtButtons())); + hBox->addWidget(extensionLB); + + extensionLB->setFixedHeight(extensionLB->minimumSizeHint().height()); + + + extensionLB->setWhatsThis( i18n("This box contains a list of patterns that can be" + " used to identify files of the selected type. For example, the pattern *.txt is" + " associated with the file type 'text/plain'; all files ending in '.txt' are recognized" + " as plain text files.") ); + + QVBoxLayout *vbox = new QVBoxLayout(); + hBox->addLayout(vbox); + + addExtButton = new KPushButton(i18n("Add..."), gb); + addExtButton->setIcon(KIcon("list-add")); + addExtButton->setEnabled(false); + connect(addExtButton, SIGNAL(clicked()), + this, SLOT(addExtension())); + vbox->addWidget(addExtButton); + addExtButton->setWhatsThis( i18n("Add a new pattern for the selected file type.") ); + + removeExtButton = new KPushButton(i18n("Remove"), gb); + removeExtButton->setIcon(KIcon("list-remove")); + removeExtButton->setEnabled(false); + connect(removeExtButton, SIGNAL(clicked()), + this, SLOT(removeExtension())); + vbox->addWidget(removeExtButton); + removeExtButton->setWhatsThis( i18n("Remove the selected filename pattern.") ); + + vbox->addStretch(1); + + gb->setFixedHeight(gb->minimumSizeHint().height()); + + description = new KLineEdit(firstWidget); + description->setClearButtonShown(true); + connect(description, SIGNAL(textChanged(const QString &)), + SLOT(updateDescription(const QString &))); + + QHBoxLayout *descriptionBox = new QHBoxLayout; + descriptionBox->addWidget(new QLabel(i18n("Description:"),firstWidget)); + descriptionBox->addWidget(description); + firstLayout->addLayout(descriptionBox); + + wtstr = i18n("You can enter a short description for files of the selected" + " file type (e.g. 'HTML Page'). This description will be used by applications" + " like Konqueror to display directory content."); + description->setWhatsThis( wtstr ); + + serviceListWidget = new KServiceListWidget( KServiceListWidget::SERVICELIST_APPLICATIONS, firstWidget ); + connect( serviceListWidget, SIGNAL(changed(bool)), this, SIGNAL(changed(bool))); + firstLayout->addWidget(serviceListWidget,5); + + // Second tab - Embedding + QWidget * secondWidget = new QWidget(m_tabWidget); + QVBoxLayout *secondLayout = new QVBoxLayout(secondWidget); + + m_autoEmbedBox = new QGroupBox( i18n("Left Click Action in Konqueror"), secondWidget ); + secondLayout->addWidget( m_autoEmbedBox ); + + m_autoEmbedBox->setSizePolicy( QSizePolicy::Preferred, QSizePolicy::Fixed ); + + QRadioButton *embViewerRadio = new QRadioButton( i18n("Show file in embedded viewer") ); + QRadioButton *sepViewerRadio = new QRadioButton( i18n("Show file in separate viewer") ); + m_rbGroupSettings = new QRadioButton( QString("Use settings for '%1' group") ); + + m_chkAskSave = new QCheckBox( i18n("Ask whether to save to disk instead (only for Konqueror browser)") ); + connect(m_chkAskSave, SIGNAL( toggled(bool) ), SLOT( slotAskSaveToggled(bool) )); + + m_autoEmbedGroup = new QButtonGroup(m_autoEmbedBox); + m_autoEmbedGroup->addButton(embViewerRadio, 0); + m_autoEmbedGroup->addButton(sepViewerRadio, 1); + m_autoEmbedGroup->addButton(m_rbGroupSettings, 2); + connect(m_autoEmbedGroup, SIGNAL( buttonClicked(int) ), SLOT( slotAutoEmbedClicked(int) )); + + vbox = new QVBoxLayout(m_autoEmbedBox); + vbox->addWidget(embViewerRadio); + vbox->addWidget(sepViewerRadio); + vbox->addWidget(m_rbGroupSettings); + vbox->addWidget(m_chkAskSave); + + m_autoEmbedBox->setWhatsThis( i18n("Here you can configure what the Konqueror file manager" + " will do when you click on a file of this type. Konqueror can either display the file in" + " an embedded viewer, or start up a separate application. If set to 'Use settings for G group'," + " the file manager will behave according to the settings of the group G to which this type belongs;" + " for instance, 'image' if the current file type is image/png. Dolphin" + " always shows files in a separate viewer.") ); + + embedServiceListWidget = new KServiceListWidget( KServiceListWidget::SERVICELIST_SERVICES, secondWidget ); +// embedServiceListWidget->setMinimumHeight( serviceListWidget->sizeHint().height() ); + connect( embedServiceListWidget, SIGNAL(changed(bool)), this, SIGNAL(changed(bool))); + secondLayout->addWidget(embedServiceListWidget); + + m_tabWidget->addTab( firstWidget, i18n("&General") ); + m_tabWidget->addTab( secondWidget, i18n("&Embedding") ); +} + +void FileTypeDetails::updateRemoveButton() +{ + removeExtButton->setEnabled(extensionLB->count()>0); +} + +void FileTypeDetails::updateIcon(const QString &icon) +{ + if (!m_mimeTypeData) + return; + + m_mimeTypeData->setUserSpecifiedIcon(icon); + + if (m_item) + m_item->setIcon(icon); + + emit changed(true); +} + +void FileTypeDetails::updateDescription(const QString &desc) +{ + if (!m_mimeTypeData) + return; + + m_mimeTypeData->setComment(desc); + + emit changed(true); +} + +void FileTypeDetails::addExtension() +{ + if ( !m_mimeTypeData ) + return; + + bool ok; + QString ext = KInputDialog::getText( i18n( "Add New Extension" ), + i18n( "Extension:" ), "*.", &ok, this ); + if (ok) { + extensionLB->addItem(ext); + QStringList patt = m_mimeTypeData->patterns(); + patt += ext; + m_mimeTypeData->setPatterns(patt); + updateRemoveButton(); + emit changed(true); + } +} + +void FileTypeDetails::removeExtension() +{ + if (extensionLB->currentRow() == -1) + return; + if ( !m_mimeTypeData ) + return; + QStringList patt = m_mimeTypeData->patterns(); + patt.removeAll(extensionLB->currentItem()->text()); + m_mimeTypeData->setPatterns(patt); + delete extensionLB->takeItem(extensionLB->currentRow()); + updateRemoveButton(); + emit changed(true); +} + +void FileTypeDetails::slotAutoEmbedClicked( int button ) +{ + if ( !m_mimeTypeData || (button > 2)) + return; + + m_mimeTypeData->setAutoEmbed( (MimeTypeData::AutoEmbed) button ); + + updateAskSave(); + + emit changed(true); +} + +void FileTypeDetails::updateAskSave() +{ + if ( !m_mimeTypeData ) + return; + + MimeTypeData::AutoEmbed autoEmbed = m_mimeTypeData->autoEmbed(); + if (m_mimeTypeData->isMeta() && autoEmbed == MimeTypeData::UseGroupSetting) { + // Resolve by looking at group (we could cache groups somewhere to avoid the re-parsing?) + autoEmbed = MimeTypeData(m_mimeTypeData->majorType()).autoEmbed(); + } + + const QString mimeType = m_mimeTypeData->name(); + + QString dontAskAgainName; + if (autoEmbed == MimeTypeData::Yes) // Embedded + dontAskAgainName = "askEmbedOrSave"+mimeType; + else + dontAskAgainName = "askSave"+mimeType; + + KSharedConfig::Ptr config = KSharedConfig::openConfig("filetypesrc", KConfig::NoGlobals); + // default value + bool ask = config->group("Notification Messages").readEntry(dontAskAgainName, QString()).isEmpty(); + // per-mimetype override if there's one + m_mimeTypeData->getAskSave(ask); + + bool neverAsk = false; + + if (autoEmbed == MimeTypeData::Yes) { + const KMimeType::Ptr mime = KMimeType::mimeType( mimeType ); + if (mime) { + // SYNC SYNC SYNC SYNC SYNC SYNC SYNC SYNC SYNC SYNC SYNC SYNC SYNC SYNC + // NOTE: Keep this function in sync with + // kdelibs/kparts/browseropenorsavequestion.cpp BrowserOpenOrSaveQuestionPrivate::autoEmbedMimeType + + // Don't ask for: + // - html (even new tabs would ask, due to about:blank!) + // - dirs obviously (though not common over HTTP :), + // - images (reasoning: no need to save, most of the time, because fast to see) + // e.g. postscript is different, because takes longer to read, so + // it's more likely that the user might want to save it. + // - multipart/* ("server push", see kmultipart) + if ( mime->is( "text/html" ) || + mime->is( "application/xml" ) || + mime->is( "inode/directory" ) || + mimeType.startsWith( QLatin1String("image") ) || + mime->is( "multipart/x-mixed-replace" ) || + mime->is( "multipart/replace" ) ) + { + neverAsk = true; + } + } + } + + m_chkAskSave->blockSignals(true); + m_chkAskSave->setChecked(ask && !neverAsk); + m_chkAskSave->setEnabled(!neverAsk); + m_chkAskSave->blockSignals(false); +} + +void FileTypeDetails::slotAskSaveToggled(bool askSave) +{ + if (!m_mimeTypeData) + return; + + m_mimeTypeData->setAskSave(askSave); + emit changed(true); +} + +void FileTypeDetails::setMimeTypeData( MimeTypeData * mimeTypeData, TypesListItem* item ) +{ + m_mimeTypeData = mimeTypeData; + m_item = item; // can be 0 + Q_ASSERT(mimeTypeData); + m_mimeTypeLabel->setText(i18n("File type %1", mimeTypeData->name())); + if (iconButton) + iconButton->setIcon(mimeTypeData->icon()); + else + iconLabel->setPixmap(DesktopIcon(mimeTypeData->icon())); + description->setText(mimeTypeData->comment()); + m_rbGroupSettings->setText( i18n("Use settings for '%1' group", mimeTypeData->majorType() ) ); + extensionLB->clear(); + addExtButton->setEnabled(true); + removeExtButton->setEnabled(false); + + serviceListWidget->setMimeTypeData( mimeTypeData ); + embedServiceListWidget->setMimeTypeData( mimeTypeData ); + m_autoEmbedGroup->button(mimeTypeData->autoEmbed())->setChecked(true); + m_rbGroupSettings->setEnabled( mimeTypeData->canUseGroupSetting() ); + + extensionLB->addItems(mimeTypeData->patterns()); + + updateAskSave(); +} + +void FileTypeDetails::enableExtButtons() +{ + removeExtButton->setEnabled(true); +} + +void FileTypeDetails::refresh() +{ + if (!m_mimeTypeData) + return; + + // Called when ksycoca has been updated -> refresh data, then widgets + m_mimeTypeData->refresh(); + setMimeTypeData(m_mimeTypeData, m_item); +} + +#include "filetypedetails.moc" diff --git a/keditfiletype/filetypedetails.h b/keditfiletype/filetypedetails.h new file mode 100644 index 00000000..7c0abb4e --- /dev/null +++ b/keditfiletype/filetypedetails.h @@ -0,0 +1,104 @@ +/* This file is part of the KDE project + Copyright (C) 2000, 2007 David Faure + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public + License version 2 or at your option version 3 as published by + the Free Software Foundation. + + 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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef FILETYPEDETAILS_H +#define FILETYPEDETAILS_H + +#include + +class KIconButton; +class MimeTypeData; +class TypesListItem; +class QLabel; +class QListWidget; +class QGroupBox; +class QButtonGroup; +class QCheckBox; +class QRadioButton; +class KLineEdit; +class KPushButton; +class KServiceListWidget; + +/** + * This widget contains the right part of the file type configuration + * dialog, that shows the details for a file type. + * It is implemented as a separate class so that it can be used by + * the keditfiletype program to show the details of a single mimetype. + */ +class FileTypeDetails : public QWidget +{ + Q_OBJECT +public: + FileTypeDetails(QWidget *parent = 0); + + /** + * Set a non-gui "mimetype data" to work on, + * and optionally a gui "treeview item", to update its icon if set. + */ + void setMimeTypeData( MimeTypeData * mimeTypeData, TypesListItem* item = 0 ); + + /** + * Called when ksycoca has changed + */ + void refresh(); + +protected: + void updateRemoveButton(); + void updateAskSave(); + +Q_SIGNALS: + void embedMajor(const QString &major, bool &embed); // To adjust whether major type is being embedded + void changed(bool); + +protected Q_SLOTS: + void updateIcon(const QString &icon); + void updateDescription(const QString &desc); + void addExtension(); + void removeExtension(); + void enableExtButtons(); + void slotAutoEmbedClicked(int button); + void slotAskSaveToggled(bool); + +private: + MimeTypeData* m_mimeTypeData; + TypesListItem* m_item; // can be 0, in keditfiletype! + + QLabel* m_mimeTypeLabel; + + QTabWidget* m_tabWidget; + + // First tab - General + KIconButton* iconButton; + QLabel* iconLabel; // if icon cannot be changed + + QListWidget *extensionLB; + KPushButton *addExtButton, *removeExtButton; + KLineEdit *description; + KServiceListWidget *serviceListWidget; + + // Second tab - Embedding + QGroupBox *m_autoEmbedBox; + QButtonGroup *m_autoEmbedGroup; + KServiceListWidget *embedServiceListWidget; + QRadioButton *m_rbOpenSeparate; + QCheckBox *m_chkAskSave; + QRadioButton *m_rbGroupSettings; +}; + +#endif diff --git a/keditfiletype/filetypes.desktop b/keditfiletype/filetypes.desktop new file mode 100644 index 00000000..aa8f8d2a --- /dev/null +++ b/keditfiletype/filetypes.desktop @@ -0,0 +1,256 @@ +[Desktop Entry] +Icon=preferences-desktop-filetype-association +Type=Service +X-KDE-ServiceTypes=KCModule +Exec=kcmshell4 filetypes +X-DocPath=kcontrol/filetypes/index.html + +X-KDE-Library=kcm_filetypes +X-KDE-ParentApp=kcontrol +X-KDE-System-Settings-Parent-Category=application-appearance-and-behavior + +Name=File Associations +Name[af]=Lêer Assosiasies +Name[ar]=ارتباطات الملفات +Name[as]=নথিপত্ৰৰ সম্বন্ধ +Name[ast]=Asociaciones de ficheru +Name[be]=Асацыяцыі файлаў +Name[be@latin]=Poviazi dla fajłaŭ +Name[bg]=Файлови асоциации +Name[bn]=ফাইল অ্যাসোসিয়েশন +Name[bn_IN]=ফাইল-অ্যাপ্লিকেশন জুটি +Name[br]=Kevreañ restroù +Name[bs]=Pridruženja datotekema +Name[ca]=Associacions de fitxers +Name[ca@valencia]=Associacions de fitxers +Name[cs]=Asociace souborů +Name[csb]=Pòwiązania lopków +Name[cy]=Cysylltiadau Ffeiliau +Name[da]=Filassociationer +Name[de]=Dateizuordnungen +Name[el]=Συσχετίσεις αρχείων +Name[en_GB]=File Associations +Name[eo]=Dosierasocioj +Name[es]=Asociaciones de archivos +Name[et]=Failide seosed +Name[eu]=Fitxategi-asoziazioak +Name[fa]=تداعی کاربردهای پرونده +Name[fi]=Tiedostosidokset +Name[fr]=Associations de fichiers +Name[fy]=Triemassosjaasjes +Name[ga]=Comhcheangail Chomhaid +Name[gl]=Asociacións de ficheiros +Name[gu]=ફાઇલ જોડાણો +Name[he]=שיוכי קבצים +Name[hi]=फ़ाइल असोसिएशन +Name[hne]=फाइल असोसिएसन +Name[hr]=Pridruživanje datoteka +Name[hsb]=Datajowe asociacije +Name[hu]=Fájltársítások +Name[ia]=Associationes de file +Name[id]=Asosiasi Berkas +Name[is]=Skráavensl +Name[it]=Associazioni dei file +Name[ja]=ファイルの関連付け +Name[ka]=ფაილთა მიბმა +Name[kk]=Файл сәйкестіктері +Name[km]=​ទំនាក់​ទំនង​ឯកសារ +Name[kn]=ಕಡತ ಸಾಹಚರ್ಯಗಳು +Name[ko]=파일 연결 +Name[ku]=Têkiliyên Pelan +Name[lt]=Failų sąsajos +Name[lv]=Failu asociācijas +Name[mai]=फाइल असोसिएशन +Name[mk]=Асоцијации на датотеки +Name[ml]=ഫയല്‍ ബന്ധപ്പെടുത്തലുകള്‍ +Name[mr]=फाईल संलग्नता +Name[nb]=Filtilknytninger +Name[nds]=Datei-Toornen +Name[ne]=फाइल संयोजन +Name[nl]=Bestandsassociaties +Name[nn]=Filtilknytingar +Name[oc]=Associacions de fichièrs +Name[or]=ଫାଇଲ ସଂସ୍ଥା +Name[pa]=ਫਾਇਲ ਸਬੰਧ +Name[pl]=Skojarzenia plików +Name[pt]=Associação de Ficheiros +Name[pt_BR]=Associações de arquivos +Name[ro]=Asociere fișiere +Name[ru]=Привязки файлов +Name[se]=Fiilačatnagasat +Name[si]=ගොනු සහායක +Name[sk]=Asociácie súborov +Name[sl]=Datotečne povezave +Name[sr]=Придружења фајловима +Name[sr@ijekavian]=Придружења фајловима +Name[sr@ijekavianlatin]=Pridruženja fajlovima +Name[sr@latin]=Pridruženja fajlovima +Name[sv]=Filbindningar +Name[ta]=கோப்பு தொடர்புகள் +Name[te]=దస్త్రపు సంభందములు +Name[tg]=Мувофиқати файлҳо +Name[th]=กำหนดการใช้แฟ้ม +Name[tr]=Dosya İlişkileri +Name[ug]=ھۆججەت باغلىنىش +Name[uk]=Прив’язка файлів +Name[uz]=Fayl turi bilan\nbogʻliqlar +Name[uz@cyrillic]=Файл тури билан\nбоғлиқлар +Name[vi]=Tập tin tương ứng +Name[wa]=Assoçnaedje des fitchîs +Name[xh]=Uyelemaniso Lwefayile +Name[x-test]=xxFile Associationsxx +Name[zh_CN]=文件关联 +Name[zh_TW]=檔案關聯 + +Comment=Configure file associations +Comment[af]=Konfigureer lêer assosiasies +Comment[ar]=إضبط ارتباطات الملفات +Comment[as]=নথিপত্ৰৰ সম্বন্ধ বিন্যাস কৰক +Comment[ast]=Configuración d'asociaciones de ficheros +Comment[be]=Настаўленні асацыяцыяў файлаў +Comment[be@latin]=Naładź poviazi dla fajłaŭ +Comment[bg]=Настройване и асоцииране на файлови типове с програми +Comment[bn]=ফাইল অ্যাসোসিয়েশন কনফিগার করুন +Comment[bn_IN]=ফাইলের সাথে ব্যবহারযোগ্য অ্যাপ্লিকেশন কনফিগার করুন +Comment[br]=Kefluniañ kevreañ restroù +Comment[bs]=Podešavanje pridruženja datotekema +Comment[ca]=Configura les associacions de fitxers +Comment[ca@valencia]=Configura les associacions de fitxers +Comment[cs]=Nastavení asociací souborů +Comment[csb]=Konfigùracëjô pòwiązaniów lopków +Comment[cy]=Ffurfweddu cysylltiadau ffeiliau +Comment[da]=Indstil filassociationer +Comment[de]=Dateizuordnungen vornehmen +Comment[el]=Διαμόρφωση των συσχετίσεων αρχείων +Comment[en_GB]=Configure file associations +Comment[eo]=Agordi dosierasociojn +Comment[es]=Configuración de asociaciones de archivos +Comment[et]=Failide seoste seadistamine +Comment[eu]=Fitxategi-asoziazioak konfiguratzea +Comment[fa]=پیکربندی تداعی کاربردهای پرونده +Comment[fi]=Tiedostosidosten asetukset +Comment[fr]=Configuration des associations de fichiers +Comment[fy]=Hjir kinne jo de triemassosjaasjes ynstelle +Comment[ga]=Cumraigh comhcheangail chomhaid +Comment[gl]=Configurar as asociacións de ficheiros +Comment[gu]=ફાઇલ જોડાણો રૂપરેખાંકિત કરો +Comment[he]=שינוי הגדרות שיוכי הקבצים +Comment[hi]=फ़ाइल असोसिएशन कॉन्फ़िगर करें +Comment[hne]=फाइल असोसिएसन कान्फिगर करव +Comment[hr]=Određivanje koji programi otvaraju koje tipove datoteka +Comment[hsb]=Konfiguracija datajowych asociacijow +Comment[hu]=A fájlhozzárendelések módosítása +Comment[ia]=Configura associationes de file +Comment[id]=Atur asosiasi berkas +Comment[is]=Stilla skráavensl +Comment[it]=Configura le associazioni dei file +Comment[ja]=ファイルの関連付けを設定 +Comment[ka]=ფაილთა მიბმის კონფიგურირება +Comment[kk]=Файл сәйкестіктерін баптау +Comment[km]=កំណត់​រចនាសម្ព័ន្ធ​​ទំនាក់ទំនង​ឯកសារ +Comment[kn]=ಕಡತ ಸಾಹಚರ್ಯಗಳನ್ನು ಸಂರಚಿಸು +Comment[ko]=파일 연결 설정 +Comment[ku]=Têkiliyên pelan ava bike +Comment[lt]=Konfigūruoti failų sąsajas +Comment[lv]=Konfigurēt failu asociācijas +Comment[mai]=फाइल असोसिएशन बिन्यस्त करू +Comment[mk]=Конфигурирајте ги асоцијациите на датотеките +Comment[ml]=ഫയല്‍ ബന്ധപ്പെടുത്തലുകള്‍ സജ്ജീകരിയ്ക്കുക +Comment[mr]=फाईल संलग्नता संयोजीत करा +Comment[nb]=Tilpass filtilknytninger +Comment[nds]=Instellen, welk Dateitypen welk Programmen tohöört +Comment[ne]=फाइल संयोजन कन्फिगर गर्नुहोस् +Comment[nl]=Hier kunt u de bestandsassociaties instellen +Comment[nn]=Set opp filassosiasjonar +Comment[or]=ଫାଇଲ ସଂସ୍ଥା ବିନ୍ୟାସ କରନ୍ତୁ +Comment[pa]=ਫਾਇਲ ਸਬੰਧ ਸੰਰਚਨਾ +Comment[pl]=Ustawienia skojarzeń plików +Comment[pt]=Configuração das associações de ficheiros +Comment[pt_BR]=Configura as associações dos arquivos +Comment[ro]=Configurează asocierea fișierelor cu aplicații +Comment[ru]=Настройка привязки файлов +Comment[se]=Heivet fiilačatnagasaid +Comment[si]=ගොනු සහායක සැකසුම් +Comment[sk]=Nastavenie asociácií súborov +Comment[sl]=Nastavi datotečne povezave +Comment[sr]=Подешавање придружења фајловима +Comment[sr@ijekavian]=Подешавање придружења фајловима +Comment[sr@ijekavianlatin]=Podešavanje pridruženja fajlovima +Comment[sr@latin]=Podešavanje pridruženja fajlovima +Comment[sv]=Anpassa filbindningar +Comment[ta]=கோப்பு தொடர்புகளை வடிவமை +Comment[te]=దస్త్రపు సంభందములను ఆకృతీకరించుము +Comment[tg]=Танзимоти мувофиқати файлҳо +Comment[th]=ปรับแต่งการเรียกใช้งานแฟ้ม +Comment[tr]=Dosya ilişkilerini yapılandır +Comment[ug]=ھۆججەت باغلىنىش سەپلىمە +Comment[uk]=Налаштування прив’язки файлів +Comment[uz]=Fayl turi bilan bogʻliqlarni moslash +Comment[uz@cyrillic]=Файл тури билан боғлиқларни мослаш +Comment[vi]=Cấu hình tập tin tương ứng +Comment[wa]=Apontyî les assoçnaedjes des fitchîs +Comment[xh]=Qwalasela uloyamiso lwefayile +Comment[x-test]=xxConfigure file associationsxx +Comment[zh_CN]=配置文件关联 +Comment[zh_TW]=設定檔案關聯 + +X-KDE-Keywords=Filetypes,File Associations,Mime Types,File Patterns,Files,Pattern +X-KDE-Keywords[ar]=نوع الملفات,ارتباطات الملفات,نوع بيبي,أنماط الملفات,ملفات,نمط +X-KDE-Keywords[bg]=Filetypes,File Associations,Mime Types,File Patterns,Files,Pattern,Файлове,Видове,Асоциации,Шаблони +X-KDE-Keywords[bn]=Filetypes,File Associations,Mime Types,File Patterns,Files,Pattern +X-KDE-Keywords[bs]=Filetypes,File Associations,Mime Types,File Patterns,Files,Pattern,tipovi datoteka,pridruživanje datoteka,uzorci datoteka,uzorci +X-KDE-Keywords[ca]=Tipus de fitxers,Associacions de fitxer,tipus MIME,patrons de fitxers,fitxers,patró +X-KDE-Keywords[ca@valencia]=Tipus de fitxers,Associacions de fitxer,tipus MIME,patrons de fitxers,fitxers,patró +X-KDE-Keywords[cs]=Typy souborů,Asociace souborů, Typy MIME,Vzory souborů,Soubory,Vzor +X-KDE-Keywords[da]=Filtyper,Filassociationer,MIME-typer,filmønstre,filer,mønstre +X-KDE-Keywords[de]=Dateitypen,Dateizuordnungen,MIME-Typen,Dateimuster,Filter,Muster,Dateien +X-KDE-Keywords[el]=Τύποι αρχείων,συσχετίσεις αρχείων,τύποι mime,μοτίβα αρχείων,αρχεία,μοτίβο +X-KDE-Keywords[en_GB]=Filetypes,File Associations,Mime Types,File Patterns,Files,Pattern +X-KDE-Keywords[eo]=Dosieraranĝoj,Dosierasocioj,MIME-tipoj,Dosierŝablonoj,Dosieroj,Ŝablono +X-KDE-Keywords[es]=Tipos de archivo,Asociaciones de archivos,tipos Mime,Patrones de archivo,Archivos,Patrón +X-KDE-Keywords[et]=failitüübid,failiseosed,MIME tüübid,failimustrid,failid,muster +X-KDE-Keywords[eu]=Fitxategi motak,Fitxategi-asoziazioak,MIME motak,Fitxategi-ereduak,Fitxategiak,Eredua +X-KDE-Keywords[fa]=Filetypes,File Associations,Mime Types,File Patterns,Files,Pattern +X-KDE-Keywords[fi]=Tiedostotyypit,Tiedostosidokset,Mime-tyypit,Tiedostopäätteet,Tiedostot,Pääte +X-KDE-Keywords[fr]=Types de fichiers, associations de fichiers, modèles de fichiers, fichiers, modèle +X-KDE-Keywords[ga]=Cineálacha,Comhcheangail,MIME,Patrúin,Patrún,Comhaid +X-KDE-Keywords[gl]=Tipos de ficheiro, asociacións de ficheiros, tipos mime, ficheiros, patrón +X-KDE-Keywords[gu]=ફાઇલપ્રકારો,ફાઇલ જોડાણો,માઇમ પ્રકારો,ફાઇલ ભાતો,ફાઇલો,ભાતો +X-KDE-Keywords[hi]=फ़ाइल प्रकार, फ़ाइल संघ, माइम प्रकार, फ़ाइल पैटर्न, फ़ाइलें, पैटर्न +X-KDE-Keywords[hu]=Fájltípusok,Fájltársítások,MIME-típusok,Fájlminták,Fájlok,Minta +X-KDE-Keywords[ia]=Typos de file,Associationes de file,Typos Mime,Patronos de File,Files,Patrono +X-KDE-Keywords[id]=Tipe Berkas,Asosiasi Berkas,Tipe Mime,Pola Berkas,Berkas,Pola +X-KDE-Keywords[is]=Skráagerðir,Skráavensl,Mime-tegund,Skráamynstur,Skrár,Mynstur +X-KDE-Keywords[it]=Tipi di file,associazioni di file,tipi mime,schemi di file,file,schema +X-KDE-Keywords[ja]=Filetypes,File Associations,Mime Types,File Patterns,Files,Pattern +X-KDE-Keywords[kk]=Filetypes,File Associations,Mime Types,File Patterns,Files,Pattern +X-KDE-Keywords[km]=Filetypes,File Associations,Mime Types,File Patterns,Files,Pattern +X-KDE-Keywords[ko]=Filetypes,File Associations,Mime Types,File Patterns,Files,Pattern,파일 형식,파일 연결,MIME 형식 +X-KDE-Keywords[lv]=Failu tipi,failu asociācijas,mime tipi,failu paraugi,failu,paraugs +X-KDE-Keywords[mr]=फाईल प्रकार, फाईल संलग्नता, माइम प्रकार, फाईल नमूना +X-KDE-Keywords[nb]=Filtyper,Filtilknytninger,Mimetyper,Filnavnmønstre,Filer,Mønster +X-KDE-Keywords[nds]=Dateitypen,Dateitoornen,MIME-Typen,Dateimustern,Dateien,Muster +X-KDE-Keywords[nl]=Bestandstypen,bestandsassociaties,Mime-typen,bestandspatronen,bestanden,patroon +X-KDE-Keywords[nn]=Filtypar,filetternamn,etternamn,filtilknytingar,MIME-typar,filmønster,filer,mønster +X-KDE-Keywords[pa]=ਫਾਇਲਕਿਸਮ,ਫਾਇਲ ਸਬੰਧ,ਮਾਈਮ ਕਿਸਮ,ਫਾਇਲ ਪੈਟਰਨ,ਫਾਇਲਾਂ,ਪੈਟਰਨ +X-KDE-Keywords[pl]=typy plików,skojarzenia plików,typy mime,wzorce plików,pliki,wzorzec +X-KDE-Keywords[pt]=Tipos de ficheiros,Associações de ficheiros,Tipos MIME,Padrões de ficheiros,Ficheiros,Padrão +X-KDE-Keywords[pt_BR]=Tipos de arquivos,Associações de arquivos,Tipos MIME,Padrões de arquivos,Arquivos,Padrão +X-KDE-Keywords[ro]=tipuri de fișier,asociere de fișiere,tipuri mime,fișiere,model +X-KDE-Keywords[ru]=Filetypes,File Associations,Mime Types,File Patterns,Files,Pattern,типы файлов,привязки файлов,типы MIME,шаблоны файлов,файлы,шаблон +X-KDE-Keywords[sk]=Filetypes,File Associations,Mime Typy,File Patterns,Súbory,Vzory +X-KDE-Keywords[sl]=vrste datotek,datotečne vrste,vrste mime,zvrsti mime,datotečne povezave,datoteke,vzorci,datotečni vzorci +X-KDE-Keywords[sr]=Filetypes,File Associations,Mime Types,File Patterns,Files,Pattern,тип фајла,придружења фајла,МИМЕ тип,образац фајла,образац +X-KDE-Keywords[sr@ijekavian]=Filetypes,File Associations,Mime Types,File Patterns,Files,Pattern,тип фајла,придружења фајла,МИМЕ тип,образац фајла,образац +X-KDE-Keywords[sr@ijekavianlatin]=Filetypes,File Associations,Mime Types,File Patterns,Files,Pattern,tip fajla,pridruženja fajla,MIME tip,obrazac fajla,obrazac +X-KDE-Keywords[sr@latin]=Filetypes,File Associations,Mime Types,File Patterns,Files,Pattern,tip fajla,pridruženja fajla,MIME tip,obrazac fajla,obrazac +X-KDE-Keywords[sv]=Filtyper,Filbindningar,Mime-typer,Filmönster,Filer,Mönster +X-KDE-Keywords[tg]=Намуди файлҳо,Муносиби файлҳо,Намудҳои Mime,Қолабҳои файл,Файлҳо,Қолабҳо +X-KDE-Keywords[tr]=Dosya tipleri,Dosya İlişkileri, Mime Tipleri,Dosya Desenleri,Dosyalar,Desen +X-KDE-Keywords[ug]=ھۆججەت تىپى، ھۆججەت مۇناسىۋەتلىرى، Mime تىپلىرى، ھۆججەت ئەندىزىلىرى، ھۆججەتلەر، ئەندىزە +X-KDE-Keywords[uk]=Filetypes;File Associations;Mime Types;File Patterns;Files;Pattern;файл;файли;типи файлів;тип;прив’язка;прив’язування;відповідність;взірці;шаблон;файли;взірець;файла +X-KDE-Keywords[vi]=Kiểu tập tin,Tập tin tương ứng,Kiểu MIME,Mẫu tập tin,Tập tin, Mẫu,Filetypes,File Associations,Mime Types,File Patterns,Files,Pattern +X-KDE-Keywords[wa]=Sôres di fitchîs,assoçnaedjes des fitchîs,assoçnaedjes di fitchîs,sôres mime,patrons di fitchîs,patron d' fitchîs,modeles di fitchîs,fitchîs,patron,modele +X-KDE-Keywords[x-test]=xxFiletypes,File Associations,Mime Types,File Patterns,Files,Patternxx +X-KDE-Keywords[zh_CN]=Filetypes,File Associations,Mime Types,File Patterns,Files,Pattern,文件类型,文件关联,后缀名,文件 +X-KDE-Keywords[zh_TW]=Filetypes,File Associations,Mime Types,File Patterns,Files,Pattern diff --git a/keditfiletype/filetypesview.cpp b/keditfiletype/filetypesview.cpp new file mode 100644 index 00000000..cf7a9213 --- /dev/null +++ b/keditfiletype/filetypesview.cpp @@ -0,0 +1,496 @@ +/* This file is part of the KDE project + Copyright (C) 2000 - 2008 David Faure + Copyright (C) 2008 Urs Wolfer + + 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, at the discretion of KDE e.V. ( which shall + act as a proxy as in section 14 of the GPLv3 ), 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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +// Own +#include "filetypesview.h" +#include "mimetypewriter.h" + +// Qt +#include +#include +#include +#include +#include +#include + +// KDE +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// Local +#include "newtypedlg.h" +#include "filetypedetails.h" +#include "filegroupdetails.h" + + +K_PLUGIN_FACTORY(FileTypesViewFactory, registerPlugin();) +K_EXPORT_PLUGIN(FileTypesViewFactory("filetypes")) + + +FileTypesView::FileTypesView(QWidget *parent, const QVariantList &) + : KCModule(FileTypesViewFactory::componentData(), parent) +{ + m_fileTypesConfig = KSharedConfig::openConfig("filetypesrc", KConfig::NoGlobals); + + setQuickHelp( i18n("

File Associations

" + " This module allows you to choose which applications are associated" + " with a given type of file. File types are also referred to as MIME types" + " (MIME is an acronym which stands for \"Multipurpose Internet Mail" + " Extensions\").

A file association consists of the following:" + "

  • Rules for determining the MIME-type of a file, for example" + " the filename pattern *.png, which means 'all files with names that end" + " in .png', is associated with the MIME type \"image/png\";
  • " + "
  • A short description of the MIME-type, for example the description" + " of the MIME type \"image/png\" is simply 'PNG image';
  • " + "
  • An icon to be used for displaying files of the given MIME-type," + " so that you can easily identify the type of file in a file" + " manager or file-selection dialog (at least for the types you use often);
  • " + "
  • A list of the applications which can be used to open files of the" + " given MIME-type -- if more than one application can be used then the" + " list is ordered by priority.
" + " You may be surprised to find that some MIME types have no associated" + " filename patterns; in these cases, KDE is able to determine the" + " MIME-type by directly examining the contents of the file.

")); + + KServiceTypeProfile::setConfigurationMode(); + setButtons(Help | Apply); + QString wtstr; + + QHBoxLayout* l = new QHBoxLayout(this); + QVBoxLayout* leftLayout = new QVBoxLayout(); + l->addLayout( leftLayout ); + + patternFilterLE = new KLineEdit(this); + patternFilterLE->setClearButtonShown(true); + patternFilterLE->setTrapReturnKey(true); + patternFilterLE->setClickMessage(i18n("Find file type or filename pattern")); + leftLayout->addWidget(patternFilterLE); + + connect(patternFilterLE, SIGNAL(textChanged(const QString &)), + this, SLOT(slotFilter(const QString &))); + + wtstr = i18n("Enter a part of a filename pattern, and only file types with a " + "matching file pattern will appear in the list. Alternatively, enter " + "a part of a file type name as it appears in the list."); + + patternFilterLE->setWhatsThis( wtstr ); + + typesLV = new TypesListTreeWidget(this); + + typesLV->setHeaderLabel(i18n("Known Types")); + leftLayout->addWidget(typesLV); + connect(typesLV, SIGNAL(currentItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)), + this, SLOT(updateDisplay(QTreeWidgetItem *))); + connect(typesLV, SIGNAL(itemDoubleClicked(QTreeWidgetItem *, int)), + this, SLOT(slotDoubleClicked(QTreeWidgetItem *))); + + typesLV->setWhatsThis( i18n("Here you can see a hierarchical list of" + " the file types which are known on your system. Click on the '+' sign" + " to expand a category, or the '-' sign to collapse it. Select a file type" + " (e.g. text/html for HTML files) to view/edit the information for that" + " file type using the controls on the right.") ); + + QHBoxLayout* btnsLay = new QHBoxLayout(); + leftLayout->addLayout(btnsLay); + btnsLay->addStretch(1); + KPushButton *addTypeB = new KPushButton(i18n("Add..."), this); + addTypeB->setIcon(KIcon("list-add")); + connect(addTypeB, SIGNAL(clicked()), SLOT(addType())); + btnsLay->addWidget(addTypeB); + + addTypeB->setWhatsThis( i18n("Click here to add a new file type.") ); + + m_removeTypeB = new KPushButton(i18n("&Remove"), this); + m_removeTypeB->setIcon(KIcon("list-remove")); + connect(m_removeTypeB, SIGNAL(clicked()), SLOT(removeType())); + btnsLay->addWidget(m_removeTypeB); + m_removeTypeB->setEnabled(false); + m_removeButtonSaysRevert = false; + + // For the right panel, prepare a widget stack + m_widgetStack = new QStackedWidget(this); + + l->addWidget( m_widgetStack ); + + // File Type Details + m_details = new FileTypeDetails( m_widgetStack ); + connect( m_details, SIGNAL( changed(bool) ), + this, SLOT( setDirty(bool) ) ); + connect( m_details, SIGNAL( embedMajor(const QString &, bool &) ), + this, SLOT( slotEmbedMajor(const QString &, bool &))); + m_widgetStack->insertWidget( 1, m_details /*id*/ ); + + // File Group Details + m_groupDetails = new FileGroupDetails( m_widgetStack ); + connect( m_groupDetails, SIGNAL( changed(bool) ), + this, SLOT( setDirty(bool) ) ); + m_widgetStack->insertWidget( 2,m_groupDetails /*id*/ ); + + // Widget shown on startup + m_emptyWidget = new QLabel( i18n("Select a file type by name or by extension"), m_widgetStack); + m_emptyWidget->setAlignment( Qt::AlignCenter ); + m_widgetStack->insertWidget( 3,m_emptyWidget ); + + m_widgetStack->setCurrentWidget( m_emptyWidget ); + + connect(KSycoca::self(), SIGNAL(databaseChanged(QStringList)), SLOT(slotDatabaseChanged(QStringList))); +} + +FileTypesView::~FileTypesView() +{ +} + +void FileTypesView::setDirty(bool state) +{ + emit changed(state); + m_dirty = state; +} + +// To order the mimetype list +static bool mimeTypeLessThan(const KMimeType::Ptr& m1, const KMimeType::Ptr& m2) +{ + return m1->name() < m2->name(); +} + +// Note that this method loses any newly-added (and not saved yet) mimetypes. +// So this is really only for load(). +void FileTypesView::readFileTypes() +{ + typesLV->clear(); + m_majorMap.clear(); + m_itemList.clear(); + + KMimeType::List mimetypes = KMimeType::allMimeTypes(); + qSort(mimetypes.begin(), mimetypes.end(), mimeTypeLessThan); + KMimeType::List::const_iterator it2(mimetypes.constBegin()); + for (; it2 != mimetypes.constEnd(); ++it2) { + const QString mimetype = (*it2)->name(); + const int index = mimetype.indexOf('/'); + const QString maj = mimetype.left(index); + const QString min = mimetype.right(mimetype.length() - index+1); + + TypesListItem* groupItem = m_majorMap.value(maj); + if ( !groupItem ) { + groupItem = new TypesListItem(typesLV, maj); + m_majorMap.insert(maj, groupItem); + } + + TypesListItem *item = new TypesListItem(groupItem, (*it2)); + m_itemList.append( item ); + } + updateDisplay(0L); +} + +void FileTypesView::slotEmbedMajor(const QString &major, bool &embed) +{ + TypesListItem *groupItem = m_majorMap.value(major); + if (!groupItem) + return; + + embed = (groupItem->mimeTypeData().autoEmbed() == MimeTypeData::Yes); +} + +void FileTypesView::slotFilter(const QString & patternFilter) +{ + for (int i = 0; i < typesLV->topLevelItemCount(); ++i) { + typesLV->topLevelItem(i)->setHidden(true); + } + + // insert all items and their group that match the filter + Q_FOREACH(TypesListItem* it, m_itemList) { + const MimeTypeData& mimeTypeData = it->mimeTypeData(); + if ( patternFilter.isEmpty() || mimeTypeData.matchesFilter(patternFilter) ) { + TypesListItem *group = m_majorMap.value( mimeTypeData.majorType() ); + Q_ASSERT(group); + if (group) { + group->setHidden(false); + it->setHidden(false); + } + } else { + it->setHidden(true); + } + } +} + +void FileTypesView::addType() +{ + const QStringList allGroups = m_majorMap.keys(); + + NewTypeDialog dialog(allGroups, this); + + if (dialog.exec()) { + const QString newMimeType = dialog.group() + '/' + dialog.text(); + + QTreeWidgetItemIterator it(typesLV); + + TypesListItem *group = m_majorMap.value(dialog.group()); + if ( !group ) { + group = new TypesListItem(typesLV, dialog.group()); + m_majorMap.insert(dialog.group(), group); + } + + // find out if our group has been filtered out -> insert if necessary + QTreeWidgetItem *item = typesLV->topLevelItem(0); + bool insert = true; + while ( item ) { + if ( item == group ) { + insert = false; + break; + } + item = typesLV->itemBelow(item); + } + if ( insert ) + typesLV->addTopLevelItem( group ); + + TypesListItem *tli = new TypesListItem(group, newMimeType); + m_itemList.append( tli ); + + group->setExpanded(true); + tli->setSelected(true); + + setDirty(true); + } +} + +void FileTypesView::removeType() +{ + TypesListItem *current = static_cast(typesLV->currentItem()); + + if (!current) { + return; + } + + const MimeTypeData& mimeTypeData = current->mimeTypeData(); + + // Can't delete groups nor essential mimetypes (but the button should be + // disabled already in these cases, so this is just extra safety). + if (mimeTypeData.isMeta() || mimeTypeData.isEssential()) { + return; + } + + if (!mimeTypeData.isNew()) { + removedList.append(mimeTypeData.name()); + } + if (m_removeButtonSaysRevert) { + // Nothing else to do for now, until saving + updateDisplay(current); + } else { + QTreeWidgetItem *li = typesLV->itemAbove(current); + if (!li) + li = typesLV->itemBelow(current); + if (!li) + li = current->parent(); + + current->parent()->takeChild(current->parent()->indexOfChild(current)); + m_itemList.removeAll(current); + if (li) { + li->setSelected(true); + } + } + setDirty(true); +} + +void FileTypesView::slotDoubleClicked(QTreeWidgetItem *item) +{ + if ( !item ) return; + item->setExpanded( !item->isExpanded() ); +} + +void FileTypesView::updateDisplay(QTreeWidgetItem *item) +{ + TypesListItem *tlitem = static_cast(item); + updateRemoveButton(tlitem); + + if (!item) { + m_widgetStack->setCurrentWidget(m_emptyWidget); + return; + } + + const bool wasDirty = m_dirty; + + MimeTypeData& mimeTypeData = tlitem->mimeTypeData(); + + if (mimeTypeData.isMeta()) { // is a group + m_widgetStack->setCurrentWidget(m_groupDetails); + m_groupDetails->setMimeTypeData(&mimeTypeData); + } else { + m_widgetStack->setCurrentWidget(m_details); + m_details->setMimeTypeData(&mimeTypeData); + } + + // Updating the display indirectly called change(true) + if (!wasDirty) { + setDirty(false); + } +} + +void FileTypesView::updateRemoveButton(TypesListItem* tlitem) +{ + bool canRemove = false; + m_removeButtonSaysRevert = false; + + if (tlitem) { + const MimeTypeData& mimeTypeData = tlitem->mimeTypeData(); + if (!mimeTypeData.isMeta() && !mimeTypeData.isEssential()) { + if (mimeTypeData.isNew()) { + canRemove = true; + } else { + // We can only remove mimetypes that we defined ourselves, not those from freedesktop.org + const QString mimeType = mimeTypeData.name(); + kDebug() << mimeType << "hasDefinitionFile:" << MimeTypeWriter::hasDefinitionFile(mimeType); + if (MimeTypeWriter::hasDefinitionFile(mimeType)) { + canRemove = true; + + // Is there a global definition for it? + const QStringList mimeFiles = KGlobal::dirs()->findAllResources( "xdgdata-mime", mimeType + ".xml" ); + kDebug() << mimeFiles; + if (mimeFiles.count() >= 2 /*a local and a global*/) { + m_removeButtonSaysRevert = true; + kDebug() << removedList; + if (removedList.contains(mimeType)) { + canRemove = false; // already on the "to be reverted" list, user needs to save now + } + } + } + } + } + } + + if (m_removeButtonSaysRevert) { + m_removeTypeB->setText(i18n("&Revert")); + m_removeTypeB->setToolTip(i18n("Revert this file type to its initial system-wide definition")); + m_removeTypeB->setWhatsThis(i18n("Click here to revert this file type to its initial system-wide definition, which undoes any changes made to the file type. Note that system-wide file types cannot be deleted. You can however empty their pattern list, to minimize the chances of them being used (but the file type determination from file contents can still end up using them).")); + } else { + m_removeTypeB->setText(i18n("&Remove")); + m_removeTypeB->setToolTip(i18n("Delete this file type definition completely")); + m_removeTypeB->setWhatsThis(i18n("Click here to delete this file type definition completely. This is only possible for user-defined file types. System-wide file types cannot be deleted. You can however empty their pattern list, to minimize the chances of them being used (but the file type determination from file contents can still end up using them).")); + } + + m_removeTypeB->setEnabled(canRemove); +} + + +void FileTypesView::save() +{ + bool needUpdateMimeDb = false; + bool needUpdateSycoca = false; + bool didIt = false; + // first, remove those items which we are asked to remove. + Q_FOREACH(const QString& mime, removedList) { + MimeTypeWriter::removeOwnMimeType(mime); + didIt = true; + needUpdateMimeDb = true; + needUpdateSycoca = true; // remove offers for this mimetype + } + removedList.clear(); + + // now go through all entries and sync those which are dirty. + // don't use typesLV, it may be filtered + QMap::iterator it1 = m_majorMap.begin(); + while ( it1 != m_majorMap.end() ) { + TypesListItem *tli = *it1; + if (tli->mimeTypeData().isDirty()) { + kDebug() << "Entry " << tli->name() << " is dirty. Saving."; + if (tli->mimeTypeData().sync()) + needUpdateMimeDb = true; + didIt = true; + } + ++it1; + } + Q_FOREACH(TypesListItem* tli, m_itemList) { + if (tli->mimeTypeData().isDirty()) { + if (tli->mimeTypeData().isServiceListDirty()) + needUpdateSycoca = true; + kDebug() << "Entry " << tli->name() << " is dirty. Saving."; + if (tli->mimeTypeData().sync()) + needUpdateMimeDb = true; + didIt = true; + } + } + + m_fileTypesConfig->sync(); + + setDirty(false); + + if (needUpdateMimeDb) { + MimeTypeWriter::runUpdateMimeDatabase(); + } + if (needUpdateSycoca) { + KBuildSycocaProgressDialog::rebuildKSycoca(this); + } + + if (didIt) { // TODO make more specific: only if autoEmbed changed? Well, maybe this is useful for icon and glob changes too... + // Trigger reparseConfiguration of filetypesrc in konqueror + // TODO: the same for dolphin. Or we should probably define a global signal for this. + // Or a KGlobalSettings thing. + QDBusMessage message = + QDBusMessage::createSignal("/KonqMain", "org.kde.Konqueror.Main", "reparseConfiguration"); + QDBusConnection::sessionBus().send(message); + } + + updateDisplay(typesLV->currentItem()); +} + +void FileTypesView::load() +{ + setEnabled(false); + setCursor( Qt::WaitCursor ); + + readFileTypes(); + + unsetCursor(); + setDirty(false); + setEnabled(true); +} + +void FileTypesView::slotDatabaseChanged(const QStringList& changedResources) +{ + kDebug() << changedResources; + if ( changedResources.contains("xdgdata-mime") // changes in mimetype definitions + || changedResources.contains("services") ) { // changes in .desktop files + + m_details->refresh(); + + // ksycoca has new KMimeTypes objects for us, make sure to update + // our 'copies' to be in sync with it. Not important for OK, but + // important for Apply (how to differentiate those 2?). + // See BR 35071. + + Q_FOREACH(TypesListItem* tli, m_itemList) { + tli->mimeTypeData().refresh(); + } + } +} + +void FileTypesView::defaults() +{ +} + +#include "filetypesview.moc" + + diff --git a/keditfiletype/filetypesview.h b/keditfiletype/filetypesview.h new file mode 100644 index 00000000..82fd0ab3 --- /dev/null +++ b/keditfiletype/filetypesview.h @@ -0,0 +1,108 @@ +/* This file is part of the KDE project + Copyright (C) 2000 - 2008 David Faure + Copyright (C) 2008 Urs Wolfer + + 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, at the discretion of KDE e.V. ( which shall + act as a proxy as in section 14 of the GPLv3 ), 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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef FILETYPESVIEW_H +#define FILETYPESVIEW_H + +#include +#include +#include +#include + +#include +#include + +#include "typeslistitem.h" + +class QLabel; +class QTreeWidget; +class QTreeWidgetItem; +class KPushButton; +class KLineEdit; +class FileTypeDetails; +class FileGroupDetails; +class QStackedWidget; + +class FileTypesView : public KCModule +{ + Q_OBJECT +public: + FileTypesView(QWidget *parent, const QVariantList &args); + ~FileTypesView(); + + void load(); + void save(); + void defaults(); + +protected Q_SLOTS: + void addType(); + void removeType(); + void updateDisplay(QTreeWidgetItem *); + void slotDoubleClicked(QTreeWidgetItem *); + void slotFilter(const QString &patternFilter); + void setDirty(bool state); + + void slotDatabaseChanged(const QStringList& changedResources); + void slotEmbedMajor(const QString &major, bool &embed); + +private: + void readFileTypes(); + void updateRemoveButton(TypesListItem* item); + +private: + QTreeWidget *typesLV; + KPushButton *m_removeTypeB; + + QStackedWidget * m_widgetStack; + FileTypeDetails * m_details; + FileGroupDetails * m_groupDetails; + QLabel * m_emptyWidget; + + KLineEdit *patternFilterLE; + QStringList removedList; + bool m_dirty; + bool m_removeButtonSaysRevert; + QMap m_majorMap; // groups + QList m_itemList; + + KSharedConfig::Ptr m_fileTypesConfig; +}; + + +// helper class for loading the icon on request instead of preloading lots of probably +// unused icons which takes quite a lot of time +class TypesListTreeWidget : public QTreeWidget +{ + Q_OBJECT +public: + TypesListTreeWidget(QWidget *parent) + : QTreeWidget(parent) { + } + +protected: + void drawRow(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const { + static_cast(itemFromIndex(index))->loadIcon(); + + QTreeWidget::drawRow(painter, option, index); + } +}; + +#endif diff --git a/keditfiletype/keditfiletype.cpp b/keditfiletype/keditfiletype.cpp new file mode 100644 index 00000000..700f34e5 --- /dev/null +++ b/keditfiletype/keditfiletype.cpp @@ -0,0 +1,200 @@ +/* This file is part of the KDE project + Copyright (C) 2000, 2007 David Faure + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public + License version 2 or at your option version 3 as published by + the Free Software Foundation. + + 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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +// Own +#include "keditfiletype.h" +#include "mimetypewriter.h" + +// Qt +#include +#include +#include + +// KDE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// Local +#include "filetypedetails.h" +#include "typeslistitem.h" + + +FileTypeDialog::FileTypeDialog( MimeTypeData* mime ) + : KDialog( 0 ), + m_mimeTypeData(mime) +{ + setButtons( Cancel | Apply | Ok ); + + init(); +} + +FileTypeDialog::~FileTypeDialog() +{ + delete m_details; +} + +void FileTypeDialog::init() +{ + m_details = new FileTypeDetails( this ); + m_details->setMimeTypeData( m_mimeTypeData ); + + // This code is very similar to kcdialog.cpp + setMainWidget( m_details ); + connect(m_details, SIGNAL(changed(bool)), this, SLOT(clientChanged(bool))); + // TODO setHelp() + enableButton(Apply, false); + + connect(KSycoca::self(), SIGNAL(databaseChanged(QStringList)), SLOT(slotDatabaseChanged(QStringList))); + connect( this, SIGNAL( okClicked() ), SLOT( slotOk() ) ); + connect( this, SIGNAL( applyClicked() ), SLOT( slotApply() ) ); +} + +void FileTypeDialog::save() +{ + if (m_mimeTypeData->isDirty()) { + const bool servicesDirty = m_mimeTypeData->isServiceListDirty(); + if (m_mimeTypeData->sync()) + MimeTypeWriter::runUpdateMimeDatabase(); + if (servicesDirty) + KBuildSycocaProgressDialog::rebuildKSycoca(this); + // Trigger reparseConfiguration of filetypesrc in konqueror + QDBusMessage message = + QDBusMessage::createSignal("/KonqMain", "org.kde.Konqueror.Main", "reparseConfiguration"); + QDBusConnection::sessionBus().send(message); + } +} + +void FileTypeDialog::slotOk() +{ + save(); + accept(); +} + +void FileTypeDialog::slotApply() +{ + save(); +} + +void FileTypeDialog::clientChanged(bool state) +{ + // enable/disable buttons + enableButton(User1, state); + enableButton(Apply, state); +} + +void FileTypeDialog::slotDatabaseChanged(const QStringList& changedResources) +{ + kDebug() << changedResources; + if ( changedResources.contains("xdgdata-mime") // changes in mimetype definitions + || changedResources.contains("services") ) { // changes in .desktop files + m_details->refresh(); + } +} + +#include "keditfiletype.moc" + +int main(int argc, char ** argv) +{ + KServiceTypeProfile::setConfigurationMode(); + KAboutData aboutData( "keditfiletype", "filetypes", ki18n("KEditFileType"), "1.0", + ki18n("KDE file type editor - simplified version for editing a single file type"), + KAboutData::License_GPL, + ki18n("(c) 2000, KDE developers") ); + aboutData.addAuthor(ki18n("Preston Brown"),KLocalizedString(), "pbrown@kde.org"); + aboutData.addAuthor(ki18n("David Faure"),KLocalizedString(), "faure@kde.org"); + aboutData.setProgramIconName("preferences-desktop-filetype-association"); + + KCmdLineArgs::init( argc, argv, &aboutData ); + + KCmdLineOptions options; + options.add("parent ", ki18n("Makes the dialog transient for the window specified by winid")); + options.add("+mimetype", ki18n("File type to edit (e.g. text/html)")); + KCmdLineArgs::addCmdLineOptions( options ); // Add our own options. + KApplication app; + KCmdLineArgs *args = KCmdLineArgs::parsedArgs(); + + if (args->count() == 0) + KCmdLineArgs::usage(); + + QString arg = args->arg(0); + MimeTypeData* mimeTypeData = 0; + const bool createType = arg.startsWith('*'); + if ( createType ) { + QString mimeString = "application/x-kdeuser%1"; + QString mimeTypeName; + int inc = 0; + bool ok = false; + do { + ++inc; + mimeTypeName = mimeString.arg(inc); + ok = !KMimeType::mimeType(mimeTypeName); + } while (!ok); + + QStringList patterns; + if ( arg.length() > 2 ) + patterns << arg.toLower() << arg.toUpper(); + QString comment; + if ( arg.startsWith( QLatin1String("*.") ) && arg.length() >= 3 ) { + const QString type = arg.mid( 3 ).prepend( arg[2].toUpper() ); + comment = i18n( "%1 File", type ); + } + + mimeTypeData = new MimeTypeData(mimeTypeName, true); // new mimetype + mimeTypeData->setComment(comment); + mimeTypeData->setPatterns(patterns); + } + else { + const QString mimeTypeName = arg; + KMimeType::Ptr mime = KMimeType::mimeType(mimeTypeName, KMimeType::ResolveAliases); + if (!mime) { + kError() << "Mimetype" << mimeTypeName << "not found" ; + return 1; + } + + mimeTypeData = new MimeTypeData(mime); + } + + FileTypeDialog dlg( mimeTypeData ); + if( args->isSet( "parent" )) { + bool ok; + long id = QString(args->getOption("parent")).toLong(&ok); + if (ok) + KWindowSystem::setMainWindow( &dlg, (WId)id ); + } + args->clear(); + if ( !createType ) + dlg.setCaption( i18n("Edit File Type %1", mimeTypeData->name()) ); + else { + dlg.setCaption( i18n("Create New File Type %1", mimeTypeData->name()) ); + dlg.enableButton( KDialog::Apply, true ); + } + + dlg.show(); // non-modal + + return app.exec(); +} + diff --git a/keditfiletype/keditfiletype.h b/keditfiletype/keditfiletype.h new file mode 100644 index 00000000..0b235ced --- /dev/null +++ b/keditfiletype/keditfiletype.h @@ -0,0 +1,53 @@ +/* This file is part of the KDE project + Copyright (C) 2000, 2007 David Faure + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public + License version 2 or at your option version 3 as published by + the Free Software Foundation. + + 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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef __keditfiletype_h +#define __keditfiletype_h + +#include +#include + +class MimeTypeData; +class FileTypeDetails; + +// A dialog for ONE file type to be edited. +class FileTypeDialog : public KDialog +{ + Q_OBJECT +public: + FileTypeDialog(MimeTypeData* mime); + ~FileTypeDialog(); + +protected Q_SLOTS: + virtual void slotOk(); + virtual void slotApply(); + void clientChanged(bool state); + void slotDatabaseChanged(const QStringList& changedResources); + +protected: + void save(); + +private: + void init(); + FileTypeDetails * m_details; + MimeTypeData* m_mimeTypeData; +}; + +#endif + diff --git a/keditfiletype/kservicelistwidget.cpp b/keditfiletype/kservicelistwidget.cpp new file mode 100644 index 00000000..2deec10b --- /dev/null +++ b/keditfiletype/kservicelistwidget.cpp @@ -0,0 +1,435 @@ +/* This file is part of the KDE project + Copyright (C) 2003 Waldo Bastian + Copyright (C) 2003 David Faure + Copyright (C) 2002 Daniel Molkentin + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public + License version 2 as published by the Free Software Foundation. + + 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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +// Own +#include "kservicelistwidget.h" + +// std +#include + +// Qt +#include +#include + +// KDE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// Local +#include "kserviceselectdlg.h" +#include "mimetypedata.h" + +KServiceListItem::KServiceListItem( const KService::Ptr& pService, int kind ) + : QListWidgetItem(), storageId(pService->storageId()), desktopPath(pService->entryPath()) +{ + if ( kind == KServiceListWidget::SERVICELIST_APPLICATIONS ) + setText( pService->name() ); + else + setText( i18n( "%1 (%2)", pService->name(), pService->desktopEntryName() ) ); + + if (!pService->isApplication()) + localPath = KStandardDirs::locateLocal("services", desktopPath); + else + localPath = pService->locateLocal(); +} + +bool KServiceListItem::isImmutable() const +{ + return !KStandardDirs::checkAccess(localPath, W_OK); +} + + + + + +KServiceListWidget::KServiceListWidget(int kind, QWidget *parent) + : QGroupBox( kind == SERVICELIST_APPLICATIONS ? i18n("Application Preference Order") + : i18n("Services Preference Order"), parent ), + m_kind( kind ), m_mimeTypeData( 0L ) +{ + QHBoxLayout *lay= new QHBoxLayout(this); + + servicesLB = new QListWidget(this); + connect(servicesLB, SIGNAL(itemSelectionChanged()), SLOT(enableMoveButtons())); + lay->addWidget(servicesLB); + connect( servicesLB, SIGNAL( itemDoubleClicked(QListWidgetItem*)), this, SLOT( editService())); + + QString wtstr = + (kind == SERVICELIST_APPLICATIONS ? + i18n("This is a list of applications associated with files of the selected" + " file type. This list is shown in Konqueror's context menus when you select" + " \"Open With...\". If more than one application is associated with this file type," + " then the list is ordered by priority with the uppermost item taking precedence" + " over the others.") : + i18n("This is a list of services associated with files of the selected" + " file type. This list is shown in Konqueror's context menus when you select" + " a \"Preview with...\" option. If more than one service is associated with this file type," + " then the list is ordered by priority with the uppermost item taking precedence" + " over the others.")); + + setWhatsThis( wtstr ); + servicesLB->setWhatsThis( wtstr ); + + QVBoxLayout *btnsLay= new QVBoxLayout(); + lay->addLayout(btnsLay); + + servUpButton = new KPushButton(i18n("Move &Up"), this); + servUpButton->setIcon(KIcon("arrow-up")); + servUpButton->setEnabled(false); + connect(servUpButton, SIGNAL(clicked()), SLOT(promoteService())); + btnsLay->addWidget(servUpButton); + + servUpButton->setWhatsThis( kind == SERVICELIST_APPLICATIONS ? + i18n("Assigns a higher priority to the selected\n" + "application, moving it up in the list. Note: This\n" + "only affects the selected application if the file type is\n" + "associated with more than one application.") : + i18n("Assigns a higher priority to the selected\n" + "service, moving it up in the list.")); + + servDownButton = new KPushButton(i18n("Move &Down"), this); + servDownButton->setIcon(KIcon("arrow-down")); + servDownButton->setEnabled(false); + connect(servDownButton, SIGNAL(clicked()), SLOT(demoteService())); + btnsLay->addWidget(servDownButton); + servDownButton->setWhatsThis( kind == SERVICELIST_APPLICATIONS ? + i18n("Assigns a lower priority to the selected\n" + "application, moving it down in the list. Note: This \n" + "only affects the selected application if the file type is\n" + "associated with more than one application."): + i18n("Assigns a lower priority to the selected\n" + "service, moving it down in the list.")); + + servNewButton = new KPushButton(i18n("Add..."), this); + servNewButton->setIcon(KIcon("list-add")); + servNewButton->setEnabled(false); + connect(servNewButton, SIGNAL(clicked()), SLOT(addService())); + btnsLay->addWidget(servNewButton); + servNewButton->setWhatsThis( i18n( "Add a new application for this file type." ) ); + + + servEditButton = new KPushButton(i18n("Edit..."), this); + servEditButton->setIcon(KIcon("edit-rename")); + servEditButton->setEnabled(false); + connect(servEditButton, SIGNAL(clicked()), SLOT(editService())); + btnsLay->addWidget(servEditButton); + servEditButton->setWhatsThis( i18n( "Edit command line of the selected application." ) ); + + + servRemoveButton = new KPushButton(i18n("Remove"), this); + servRemoveButton->setIcon(KIcon("list-remove")); + servRemoveButton->setEnabled(false); + connect(servRemoveButton, SIGNAL(clicked()), SLOT(removeService())); + btnsLay->addWidget(servRemoveButton); + servRemoveButton->setWhatsThis( i18n( "Remove the selected application from the list." ) ); + + btnsLay->addStretch(1); +} + +void KServiceListWidget::setMimeTypeData( MimeTypeData * mimeTypeData ) +{ + m_mimeTypeData = mimeTypeData; + if ( servNewButton ) + servNewButton->setEnabled(true); + // will need a selection + servUpButton->setEnabled(false); + servDownButton->setEnabled(false); + + servicesLB->clear(); + servicesLB->setEnabled(false); + + if (m_mimeTypeData) { + const QStringList services = ( m_kind == SERVICELIST_APPLICATIONS ) + ? m_mimeTypeData->appServices() + : m_mimeTypeData->embedServices(); + + if (services.isEmpty()) { + if (m_kind == SERVICELIST_APPLICATIONS) + servicesLB->addItem(i18nc("No applications associated with this file type", "None")); + else + servicesLB->addItem(i18nc("No components associated with this file type", "None")); + } else { + Q_FOREACH(const QString& service, services) { + KService::Ptr pService = KService::serviceByStorageId(service); + if (pService) + servicesLB->addItem( new KServiceListItem(pService, m_kind) ); + } + servicesLB->setEnabled(true); + } + } + + if (servRemoveButton) + servRemoveButton->setEnabled(servicesLB->currentRow() > -1); + if (servEditButton) + servEditButton->setEnabled(servicesLB->currentRow() > -1); +} + +void KServiceListWidget::promoteService() +{ + if (!servicesLB->isEnabled()) { + KNotification::beep(); + return; + } + + int selIndex = servicesLB->currentRow(); + if (selIndex == 0) { + KNotification::beep(); + return; + } + + QListWidgetItem *selItem = servicesLB->item(selIndex); + servicesLB->takeItem(selIndex); + servicesLB->insertItem(selIndex-1,selItem); + servicesLB->setCurrentRow(selIndex - 1); + + updatePreferredServices(); + + emit changed(true); +} + +void KServiceListWidget::demoteService() +{ + if (!servicesLB->isEnabled()) { + KNotification::beep(); + return; + } + + int selIndex = servicesLB->currentRow(); + if (selIndex == servicesLB->count() - 1) { + KNotification::beep(); + return; + } + + QListWidgetItem *selItem = servicesLB->item(selIndex); + servicesLB->takeItem(selIndex); + servicesLB->insertItem(selIndex + 1, selItem); + servicesLB->setCurrentRow(selIndex + 1); + + updatePreferredServices(); + + emit changed(true); +} + +void KServiceListWidget::addService() +{ + if (!m_mimeTypeData) + return; + + KService::Ptr service; + if ( m_kind == SERVICELIST_APPLICATIONS ) + { + KOpenWithDialog dlg(m_mimeTypeData->name(), QString(), this); + dlg.setSaveNewApplications(true); + if (dlg.exec() != QDialog::Accepted) + return; + + service = dlg.service(); + + Q_ASSERT(service); + if (!service) + return; // Don't crash if KOpenWith wasn't able to create service. + } + else + { + KServiceSelectDlg dlg(m_mimeTypeData->name(), QString(), this); + if (dlg.exec() != QDialog::Accepted) + return; + service = dlg.service(); + Q_ASSERT(service); + if (!service) + return; + } + + // Did the list simply show "None"? + const bool hadDummyEntry = ( m_kind == SERVICELIST_APPLICATIONS ) + ? m_mimeTypeData->appServices().isEmpty() + : m_mimeTypeData->embedServices().isEmpty(); + + if (hadDummyEntry) { + delete servicesLB->takeItem(0); // Remove the "None" item. + servicesLB->setEnabled(true); + } else { + // check if it is a duplicate entry + for (int index = 0; index < servicesLB->count(); index++) { + if (static_cast( servicesLB->item(index) )->desktopPath + == service->entryPath()) { + // ##### shouldn't we make the existing entry the default one? + return; + } + } + } + + servicesLB->insertItem(0, new KServiceListItem(service, m_kind)); + servicesLB->setCurrentItem(0); + + updatePreferredServices(); + + emit changed(true); +} + +void KServiceListWidget::editService() +{ + if (!m_mimeTypeData) + return; + const int selected = servicesLB->currentRow(); + if (selected < 0) + return; + + // Only edit applications, not services as + // they don't have any parameters + if (m_kind != SERVICELIST_APPLICATIONS) + return; + + // Just like popping up an add dialog except that we + // pass the current command line as a default + KServiceListItem *selItem = (KServiceListItem*)servicesLB->item(selected); + const QString desktopPath = selItem->desktopPath; + + KService::Ptr service = KService::serviceByDesktopPath(desktopPath); + if (!service) + return; + + QString path = service->entryPath(); + + // If the path to the desktop file is relative, try to get the full + // path from KStandardDirs. + path = KStandardDirs::locate("apps", path); // TODO use xdgdata-apps instead? + + KFileItem item(KUrl(path), "application/x-desktop", KFileItem::Unknown); + KPropertiesDialog dlg(item, this); + if (dlg.exec() != QDialog::Accepted) + return; + + // Note that at this point, ksycoca has been updated, + // and setMimeTypeData has been called again, so all the items have been recreated. + + // Reload service + service = KService::serviceByDesktopPath(desktopPath); + if (!service) + return; + + // Remove the old one... + delete servicesLB->takeItem(selected); + + // ...check that it's not a duplicate entry... + bool addIt = true; + for (int index = 0; index < servicesLB->count(); index++) { + if (static_cast(servicesLB->item(index))->desktopPath + == service->entryPath()) { + addIt = false; + break; + } + } + + // ...and add it in the same place as the old one: + if (addIt) { + servicesLB->insertItem(selected, new KServiceListItem(service, m_kind)); + servicesLB->setCurrentRow(selected); + } + + updatePreferredServices(); + + emit changed(true); +} + +void KServiceListWidget::removeService() +{ + if (!m_mimeTypeData) return; + + int selected = servicesLB->currentRow(); + + if ( selected >= 0 ) { + // Check if service is associated with this mimetype or with one of its parents + KServiceListItem *serviceItem = static_cast(servicesLB->item(selected)); + if (serviceItem->isImmutable()) + { + KMessageBox::sorry(this, i18n("You are not authorized to remove this service.")); + } + else + { + delete servicesLB->takeItem( selected ); + updatePreferredServices(); + + emit changed(true); + } + } + + // Update buttons and service list again (e.g. to re-add "None") + setMimeTypeData(m_mimeTypeData); +} + +void KServiceListWidget::updatePreferredServices() +{ + if (!m_mimeTypeData) + return; + QStringList sl; + unsigned int count = servicesLB->count(); + + for (unsigned int i = 0; i < count; i++) { + KServiceListItem *sli = (KServiceListItem *) servicesLB->item(i); + sl.append( sli->storageId ); + } + sl.removeDuplicates(); + if ( m_kind == SERVICELIST_APPLICATIONS ) + m_mimeTypeData->setAppServices(sl); + else + m_mimeTypeData->setEmbedServices(sl); +} + +void KServiceListWidget::enableMoveButtons() +{ + int idx = servicesLB->currentRow(); + if (servicesLB->model()->rowCount() <= 1) + { + servUpButton->setEnabled(false); + servDownButton->setEnabled(false); + } + else if ( idx == (servicesLB->model()->rowCount() - 1) ) + { + servUpButton->setEnabled(true); + servDownButton->setEnabled(false); + } + else if (idx == 0) + { + servUpButton->setEnabled(false); + servDownButton->setEnabled(true); + } + else + { + servUpButton->setEnabled(true); + servDownButton->setEnabled(true); + } + + if ( servRemoveButton ) + servRemoveButton->setEnabled(true); + + if ( servEditButton ) + servEditButton->setEnabled( m_kind == SERVICELIST_APPLICATIONS ); +} + +#include "kservicelistwidget.moc" diff --git a/keditfiletype/kservicelistwidget.h b/keditfiletype/kservicelistwidget.h new file mode 100644 index 00000000..c817d24b --- /dev/null +++ b/keditfiletype/kservicelistwidget.h @@ -0,0 +1,79 @@ +/* This file is part of the KDE project + Copyright (C) 2003 Waldo Bastian + Copyright (C) 2003 David Faure + Copyright (C) 2002 Daniel Molkentin + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public + License version 2 or at your option version 3 as published + by the Free Software Foundation. + + 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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef _KSERVICELISTWIDGET_H +#define _KSERVICELISTWIDGET_H + +#include +#include +#include +class MimeTypeData; +class KPushButton; +class KService; + +class KServiceListItem : public QListWidgetItem +{ +public: + KServiceListItem( const KService::Ptr& pService, int kind ); + bool isImmutable() const; + QString storageId; + QString desktopPath; + QString localPath; +}; + +/** + * This widget holds a list of services, with 5 buttons to manage it. + * It's a separate class so that it can be used by both tabs of the + * module, once for applications and once for services. + * The "kind" is determined by the argument given to the constructor. + */ +class KServiceListWidget : public QGroupBox +{ + Q_OBJECT +public: + enum { SERVICELIST_APPLICATIONS, SERVICELIST_SERVICES }; + explicit KServiceListWidget(int kind, QWidget *parent = 0); + + void setMimeTypeData( MimeTypeData * item ); + +Q_SIGNALS: + void changed(bool); + +protected Q_SLOTS: + void promoteService(); + void demoteService(); + void addService(); + void editService(); + void removeService(); + void enableMoveButtons(); + +protected: + void updatePreferredServices(); + +private: + int m_kind; + QListWidget *servicesLB; + KPushButton *servUpButton, *servDownButton; + KPushButton *servNewButton, *servEditButton, *servRemoveButton; + MimeTypeData *m_mimeTypeData; +}; + +#endif diff --git a/keditfiletype/kserviceselectdlg.cpp b/keditfiletype/kserviceselectdlg.cpp new file mode 100644 index 00000000..09c7c5d6 --- /dev/null +++ b/keditfiletype/kserviceselectdlg.cpp @@ -0,0 +1,75 @@ +/* This file is part of the KDE project + Copyright (C) 2000 David Faure + + 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, see . +*/ + +#include "kserviceselectdlg.h" +#include "kserviceselectdlg.moc" +#include "kservicelistwidget.h" + +#include +#include +#include + +KServiceSelectDlg::KServiceSelectDlg( const QString& /*serviceType*/, const QString& /*value*/, QWidget *parent ) + : KDialog( parent ) +{ + setObjectName( QLatin1String( "serviceSelectDlg" ) ); + setModal( true ); + setCaption( i18n( "Add Service" ) ); + setButtons( Ok | Cancel ); + + QWidget *vbox = new QWidget( this ); + QVBoxLayout *layout = new QVBoxLayout( vbox ); + + layout->addWidget( new QLabel( i18n( "Select service:" ), vbox ) ); + m_listbox=new KListWidget( vbox ); + + // Can't make a KTrader query since we don't have a servicetype to give, + // we want all services that are not applications....... + // So we have to do it the slow way + // ### Why can't we query for KParts/ReadOnlyPart as the servicetype? Should work fine! + const KService::List allServices = KService::allServices(); + KService::List::const_iterator it(allServices.constBegin()); + for ( ; it != allServices.constEnd() ; ++it ) + if ( (*it)->hasServiceType( "KParts/ReadOnlyPart" ) ) + { + m_listbox->addItem( new KServiceListItem( (*it), KServiceListWidget::SERVICELIST_SERVICES ) ); + } + + m_listbox->model()->sort(0); + m_listbox->setMinimumHeight(350); + m_listbox->setMinimumWidth(400); + layout->addWidget( m_listbox ); + connect(m_listbox,SIGNAL(itemDoubleClicked(QListWidgetItem*)),SLOT(slotOk())); + connect( this, SIGNAL(okClicked()), this, SLOT(slotOk()) ); + setMainWidget(vbox); +} + +KServiceSelectDlg::~KServiceSelectDlg() +{ +} + +void KServiceSelectDlg::slotOk() +{ + accept(); +} + +KService::Ptr KServiceSelectDlg::service() +{ + int selIndex = m_listbox->currentRow(); + KServiceListItem *selItem = static_cast(m_listbox->item(selIndex)); + return KService::serviceByDesktopPath( selItem->desktopPath ); +} diff --git a/keditfiletype/kserviceselectdlg.h b/keditfiletype/kserviceselectdlg.h new file mode 100644 index 00000000..8e6d0d00 --- /dev/null +++ b/keditfiletype/kserviceselectdlg.h @@ -0,0 +1,50 @@ +/* This file is part of the KDE project + Copyright (C) 2000 David Faure + + 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, see . +*/ + +#ifndef __kserviceselectdlg_h +#define __kserviceselectdlg_h +#include +#include +#include +class KServiceSelectDlg : public KDialog +{ + Q_OBJECT +public: + /** + * Create a dialog to select a service (not application) for a given service type. + * + * @param serviceType the service type we want to choose a service for. + * @param value is the initial service to select (not implemented currently) + * @param parent parent widget + */ + explicit KServiceSelectDlg( const QString& serviceType, + const QString& value = QString(), + QWidget *parent = 0L ); + + ~KServiceSelectDlg(); + + /** + * @return the chosen service + */ + KService::Ptr service(); +protected slots: + void slotOk(); +private: + KListWidget * m_listbox; +}; + +#endif diff --git a/keditfiletype/mimetypedata.cpp b/keditfiletype/mimetypedata.cpp new file mode 100644 index 00000000..18e2c9fa --- /dev/null +++ b/keditfiletype/mimetypedata.cpp @@ -0,0 +1,479 @@ +/* This file is part of the KDE project + Copyright (C) 2003 Waldo Bastian + Copyright (C) 2003, 2007 David Faure + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public + License version 2 or at your option version 3 as published by + the Free Software Foundation. + + 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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "mimetypedata.h" +#include "sharedmimeinfoversion.h" +#include +#include "mimetypewriter.h" +#include +#include +#include +#include +#include + +MimeTypeData::MimeTypeData(const QString& major) + : m_askSave(AskSaveDefault), + m_bNewItem(false), + m_bFullInit(true), + m_isGroup(true), + m_appServicesModified(false), + m_embedServicesModified(false), + m_major(major) +{ + m_autoEmbed = readAutoEmbed(); +} + +MimeTypeData::MimeTypeData(const KMimeType::Ptr mime) + : m_mimetype(mime), + m_askSave(AskSaveDefault), // TODO: the code for initializing this is missing. FileTypeDetails initializes the checkbox instead... + m_bNewItem(false), + m_bFullInit(false), + m_isGroup(false), + m_appServicesModified(false), + m_embedServicesModified(false) +{ + const QString mimeName = m_mimetype->name(); + const int index = mimeName.indexOf('/'); + if (index != -1) { + m_major = mimeName.left(index); + m_minor = mimeName.mid(index+1); + } else { + m_major = mimeName; + } + initFromKMimeType(); +} + +MimeTypeData::MimeTypeData(const QString& mimeName, bool) + : m_mimetype(0), + m_askSave(AskSaveDefault), + m_bNewItem(true), + m_bFullInit(false), + m_isGroup(false), + m_appServicesModified(false), + m_embedServicesModified(false) +{ + const int index = mimeName.indexOf('/'); + if (index != -1) { + m_major = mimeName.left(index); + m_minor = mimeName.mid(index+1); + } else { + m_major = mimeName; + } + m_autoEmbed = UseGroupSetting; + // all the rest is empty by default +} + +void MimeTypeData::initFromKMimeType() +{ + m_comment = m_mimetype->comment(); + m_userSpecifiedIcon = m_mimetype->userSpecifiedIconName(); + setPatterns(m_mimetype->patterns()); + m_autoEmbed = readAutoEmbed(); +} + +MimeTypeData::AutoEmbed MimeTypeData::readAutoEmbed() const +{ + const KSharedConfig::Ptr config = KSharedConfig::openConfig("filetypesrc", KConfig::NoGlobals); + const QString key = QString("embed-") + name(); + const KConfigGroup group(config, "EmbedSettings"); + if (m_isGroup) { + // embedding is false by default except for image/*, multipart/* and inode/* (hardcoded in konq) + const bool defaultValue = (m_major == "image" || m_major == "multipart" || m_major == "inode"); + return group.readEntry(key, defaultValue) ? Yes : No; + } else { + if (group.hasKey(key)) + return group.readEntry(key, false) ? Yes : No; + // TODO if ( !mimetype->property( "X-KDE-LocalProtocol" ).toString().isEmpty() ) + // TODO return MimeTypeData::Yes; // embed by default for zip, tar etc. + return MimeTypeData::UseGroupSetting; + } +} + +void MimeTypeData::writeAutoEmbed() +{ + KSharedConfig::Ptr config = KSharedConfig::openConfig("filetypesrc", KConfig::NoGlobals); + if (!config->isConfigWritable(true)) + return; + + const QString key = QString("embed-") + name(); + KConfigGroup group(config, "EmbedSettings"); + if (m_isGroup) { + group.writeEntry(key, m_autoEmbed == Yes); + } else { + if (m_autoEmbed == UseGroupSetting) + group.deleteEntry(key); + else + group.writeEntry(key, m_autoEmbed == Yes); + } +} + +bool MimeTypeData::isEssential() const +{ + // Keep in sync with KMimeType::checkEssentialMimeTypes + const QString n = name(); + if ( n == "application/octet-stream" ) + return true; + if ( n == "inode/directory" ) + return true; + if ( n == "inode/blockdevice" ) + return true; + if ( n == "inode/chardevice" ) + return true; + if ( n == "inode/socket" ) + return true; + if ( n == "inode/fifo" ) + return true; + if ( n == "application/x-shellscript" ) + return true; + if ( n == "application/x-executable" ) + return true; + if ( n == "application/x-desktop" ) + return true; + return false; +} + +void MimeTypeData::setUserSpecifiedIcon(const QString& icon) +{ + m_userSpecifiedIcon = icon; +} + +QStringList MimeTypeData::getAppOffers() const +{ + QStringList services; + const KService::List offerList = + KMimeTypeTrader::self()->query(name(), "Application"); + KService::List::const_iterator it(offerList.begin()); + for (; it != offerList.constEnd(); ++it) { + if ((*it)->allowAsDefault()) + services.append((*it)->storageId()); + } + return services; +} + +QStringList MimeTypeData::getPartOffers() const +{ + QStringList services; + const KService::List partOfferList = + KMimeTypeTrader::self()->query(name(), "KParts/ReadOnlyPart"); + for ( KService::List::const_iterator it = partOfferList.begin(); it != partOfferList.constEnd(); ++it) + services.append((*it)->storageId()); + return services; +} + +void MimeTypeData::getMyServiceOffers() const +{ + m_appServices = getAppOffers(); + m_embedServices = getPartOffers(); + m_bFullInit = true; +} + +QStringList MimeTypeData::appServices() const +{ + if (!m_bFullInit) { + getMyServiceOffers(); + } + return m_appServices; +} + +QStringList MimeTypeData::embedServices() const +{ + if (!m_bFullInit) { + getMyServiceOffers(); + } + return m_embedServices; +} + +bool MimeTypeData::isMimeTypeDirty() const +{ + Q_ASSERT(!m_isGroup); + if (m_bNewItem) + return true; + + if (!m_mimetype) { + kWarning() << "MimeTypeData for" << name() << "says 'not new' but is without a mimetype? Should not happen."; + return true; + } + + if (m_mimetype->comment() != m_comment) { + kDebug() << "Mimetype Comment Dirty: old=" << m_mimetype->comment() << "m_comment=" << m_comment; + return true; + } + if (m_mimetype->userSpecifiedIconName() != m_userSpecifiedIcon) { + kDebug() << "Mimetype Icon Dirty: old=" << m_mimetype->iconName() << "m_userSpecifiedIcon=" << m_userSpecifiedIcon; + return true; + } + + QStringList storedPatterns = m_mimetype->patterns(); + storedPatterns.sort(); // see ctor + if ( storedPatterns != m_patterns) { + kDebug() << "Mimetype Patterns Dirty: old=" << storedPatterns + << "m_patterns=" << m_patterns; + return true; + } + + if (readAutoEmbed() != m_autoEmbed) + return true; + return false; +} + +bool MimeTypeData::isServiceListDirty() const +{ + return !m_isGroup && (m_appServicesModified || m_embedServicesModified); +} + +bool MimeTypeData::isDirty() const +{ + if ( m_bNewItem ) { + kDebug() << "New item, need to save it"; + return true; + } + + if ( !m_isGroup ) { + if (isServiceListDirty()) + return true; + if (isMimeTypeDirty()) + return true; + } + else // is a group + { + if (readAutoEmbed() != m_autoEmbed) + return true; + } + + if (m_askSave != AskSaveDefault) + return true; + + // nothing seems to have changed, it's not dirty. + return false; +} + +bool MimeTypeData::sync() +{ + if (m_isGroup) { + writeAutoEmbed(); + return false; + } + + if (m_askSave != AskSaveDefault) { + KSharedConfig::Ptr config = KSharedConfig::openConfig("filetypesrc", KConfig::NoGlobals); + if (!config->isConfigWritable(true)) + return false; + KConfigGroup cg = config->group("Notification Messages"); + if (m_askSave == AskSaveYes) { + // Ask + cg.deleteEntry("askSave"+name()); + cg.deleteEntry("askEmbedOrSave"+name()); + } else { + // Do not ask, open + cg.writeEntry("askSave"+name(), "no" ); + cg.writeEntry("askEmbedOrSave"+name(), "no" ); + } + } + + writeAutoEmbed(); + + bool needUpdateMimeDb = false; + if (isMimeTypeDirty()) { + MimeTypeWriter mimeTypeWriter(name()); + mimeTypeWriter.setComment(m_comment); + if (SharedMimeInfoVersion::supportsIcon()) { + // Very important: don't write if shared-mime-info doesn't support it, + // it would abort on it! + if (!m_userSpecifiedIcon.isEmpty()) { + mimeTypeWriter.setIconName(m_userSpecifiedIcon); + } + } + mimeTypeWriter.setPatterns(m_patterns); + if (!mimeTypeWriter.write()) + return false; + + needUpdateMimeDb = true; + } + + syncServices(); + + return needUpdateMimeDb; +} + +void MimeTypeData::syncServices() +{ + if (!m_bFullInit) + return; + + KSharedConfig::Ptr profile = KSharedConfig::openConfig("mimeapps.list", KConfig::NoGlobals, "xdgdata-apps"); + + if (!profile->isConfigWritable(true)) // warn user if mimeapps.list is root-owned (#155126/#94504) + return; + + const QStringList oldAppServices = getAppOffers(); + if (oldAppServices != m_appServices) { + // Save preferred services + KConfigGroup addedApps(profile, "Added Associations"); + saveServices(addedApps, m_appServices); + KConfigGroup removedApps(profile, "Removed Associations"); + saveRemovedServices(removedApps, m_appServices, oldAppServices); + } + + const QStringList oldPartServices = getPartOffers(); + if (oldPartServices != m_embedServices) { + // Handle removed services + KConfigGroup addedParts(profile, "Added KDE Service Associations"); + saveServices(addedParts, m_embedServices); + KConfigGroup removedParts(profile, "Removed KDE Service Associations"); + saveRemovedServices(removedParts, m_embedServices, oldPartServices); + } + + m_appServicesModified = false; + m_embedServicesModified = false; +} + +static QStringList collectStorageIds(const QStringList& services) +{ + QStringList serviceList; + QStringList::const_iterator it(services.begin()); + for (int i = services.count(); it != services.end(); ++it, i--) { + + KService::Ptr pService = KService::serviceByStorageId(*it); + if (!pService) { + kWarning() << "service with storage id" << *it << "not found"; + continue; // Where did that one go? + } + + serviceList.append(pService->storageId()); + } + return serviceList; +} + +void MimeTypeData::saveRemovedServices(KConfigGroup & config, const QStringList& services, const QStringList& oldServices) +{ + QStringList removedServiceList = config.readXdgListEntry(name()); + + Q_FOREACH(const QString& service, services) { + // If removedServiceList.contains(service), then it was previously removed but has been added back + removedServiceList.removeAll(service); + } + Q_FOREACH(const QString& oldService, oldServices) { + if (!services.contains(oldService)) { + // The service was in m_appServices (or m_embedServices) but has been removed + removedServiceList.append(oldService); + } + } + if (removedServiceList.isEmpty()) + config.deleteEntry(name()); + else + config.writeXdgListEntry(name(), removedServiceList); +} + +void MimeTypeData::saveServices(KConfigGroup & config, const QStringList& services) +{ + if (services.isEmpty()) + config.deleteEntry(name()); + else + config.writeXdgListEntry(name(), collectStorageIds(services)); +} + +void MimeTypeData::refresh() +{ + if (m_isGroup) + return; + + m_mimetype = KMimeType::mimeType( name() ); + if (m_mimetype) { + if (m_bNewItem) { + kDebug() << "OK, created" << name(); + m_bNewItem = false; // if this was a new mimetype, we just created it + } + if (!isMimeTypeDirty()) { + // Update from the xml, in case something was changed from out of this kcm + // (e.g. using KOpenWithDialog, or keditfiletype + kcmshell filetypes) + initFromKMimeType(); + } + if (!m_appServicesModified && !m_embedServicesModified) { + m_bFullInit = false; // refresh services too + } + } +} + +void MimeTypeData::getAskSave(bool &_askSave) +{ + if (m_askSave == AskSaveYes) + _askSave = true; + if (m_askSave == AskSaveNo) + _askSave = false; +} + +void MimeTypeData::setAskSave(bool _askSave) +{ + m_askSave = _askSave ? AskSaveYes : AskSaveNo; +} + +bool MimeTypeData::canUseGroupSetting() const +{ + // "Use group settings" isn't available for zip, tar etc.; those have a builtin default... + if (!m_mimetype) // e.g. new mimetype + return true; + const bool hasLocalProtocolRedirect = !KProtocolManager::protocolForArchiveMimetype(name()).isEmpty(); + return !hasLocalProtocolRedirect; +} + +void MimeTypeData::setPatterns(const QStringList &p) +{ + m_patterns = p; + // Sort them, since update-mime-database doesn't respect order (order of globs file != order of xml), + // and this code says things like if (m_mimetype->patterns() == m_patterns). + // We could also sort in KMimeType::setPatterns but this would just slow down the + // normal use case (anything else than this KCM) for no good reason. + m_patterns.sort(); +} + +bool MimeTypeData::matchesFilter(const QString& filter) const +{ + if (name().contains(filter, Qt::CaseInsensitive)) + return true; + + if (m_comment.contains(filter, Qt::CaseInsensitive)) + return true; + + if (!m_patterns.filter(filter, Qt::CaseInsensitive).isEmpty()) + return true; + + return false; +} + +void MimeTypeData::setAppServices(const QStringList &dsl) +{ + m_appServices = dsl; + m_appServicesModified = true; +} + +void MimeTypeData::setEmbedServices(const QStringList &dsl) +{ + m_embedServices = dsl; + m_embedServicesModified = true; +} + +QString MimeTypeData::icon() const +{ + if (!m_userSpecifiedIcon.isEmpty()) + return m_userSpecifiedIcon; + if (m_mimetype) + return m_mimetype->iconName(); + return QString(); +} diff --git a/keditfiletype/mimetypedata.h b/keditfiletype/mimetypedata.h new file mode 100644 index 00000000..042b0431 --- /dev/null +++ b/keditfiletype/mimetypedata.h @@ -0,0 +1,134 @@ +/* This file is part of the KDE project + Copyright (C) 2003 Waldo Bastian + Copyright (C) 2003, 2007 David Faure + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public + License version 2 or at your option version 3 as published by + the Free Software Foundation. + + 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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef MIMETYPEDATA_H +#define MIMETYPEDATA_H + +#include + +/** + * This is a non-gui (data) class, that represents a mimetype. + * It is a KMimeType::Ptr plus the changes we made to it. + */ +class MimeTypeData +{ +public: + // Constructor used for groups + MimeTypeData(const QString& major); + // Real constructor, used for an existing mimetype. + MimeTypeData(const KMimeType::Ptr mime); + // Real constructor, used for a new mimetype. + MimeTypeData(const QString& mimeName, bool /*unused, just to distinguish from the other QString ctor*/); + + QString name() const { return m_isGroup ? m_major : m_major + '/' + m_minor; } + QString majorType() const { return m_major; } + QString minorType() const { return m_minor; } + void setMinor(const QString& m) { m_minor = m; } + QString comment() const { return m_comment; } + void setComment(const QString& c) { m_comment = c; } + + /** + * Returns true if "this" is a group + */ + bool isMeta() const { return m_isGroup; } + + /** + * Returns true if the type is essential, i.e. can't be deleted + * (see KMimeType::checkEssentialMimeTypes) + */ + bool isEssential() const; + QString icon() const; + void setUserSpecifiedIcon(const QString& icon); + QStringList patterns() const { return m_patterns; } + void setPatterns(const QStringList &p); + QStringList appServices() const; + void setAppServices(const QStringList &dsl); + QStringList embedServices() const; + void setEmbedServices(const QStringList &dsl); + + enum AutoEmbed { Yes = 0, No = 1, UseGroupSetting = 2 }; + AutoEmbed autoEmbed() const { return m_autoEmbed; } + void setAutoEmbed( AutoEmbed a ) { m_autoEmbed = a; } + + const KMimeType::Ptr& mimeType() const { return m_mimetype; } + bool canUseGroupSetting() const; + + void getAskSave(bool &); + void setAskSave(bool); + + /** + * Returns true if the mimetype data has any unsaved changes. + */ + bool isDirty() const; + + /** + * Returns true if the mimetype data has any unsaved changes in the service list. + */ + bool isServiceListDirty() const; + + /** + * Save changes to disk. + * Does not check isDirty(), so the common idiom is if (data.isDirty()) { needUpdate = data.sync(); } + * Returns true if update-mime-database needs to be run afterwards + */ + bool sync(); + /** + * Update m_mimetype from the xml when Apply is pressed + */ + void refresh(); + + /** + * Return true if this is a new mimetype, i.e. one that is not yet on disk + */ + bool isNew() const { return m_bNewItem; } + + /** + * Helper method for the filtering in the listview + */ + bool matchesFilter(const QString& filter) const; + +private: + void initFromKMimeType(); + AutoEmbed readAutoEmbed() const; + void writeAutoEmbed(); + bool isMimeTypeDirty() const; // whether the mimetype definition file needs saving + QStringList getAppOffers() const; + QStringList getPartOffers() const; + void getMyServiceOffers() const; + void syncServices(); + void saveServices(KConfigGroup & config, const QStringList& services); + void saveRemovedServices(KConfigGroup & config, const QStringList& services, const QStringList& oldServices); + + KMimeType::Ptr m_mimetype; // 0 if this is data for a mimetype group (m_isGroup==true) + enum AskSave { AskSaveYes = 0, AskSaveNo = 1, AskSaveDefault = 2 }; + AskSave m_askSave:3; + AutoEmbed m_autoEmbed:3; + bool m_bNewItem:1; + mutable bool m_bFullInit:1; // lazy init of m_appServices and m_embedServices + bool m_isGroup:1; + bool m_appServicesModified:1; + bool m_embedServicesModified:1; + QString m_major, m_minor, m_comment, m_userSpecifiedIcon; + QStringList m_patterns; + mutable QStringList m_appServices; + mutable QStringList m_embedServices; +}; + +#endif /* MIMETYPEDATA_H */ diff --git a/keditfiletype/mimetypewriter.cpp b/keditfiletype/mimetypewriter.cpp new file mode 100644 index 00000000..19db75a0 --- /dev/null +++ b/keditfiletype/mimetypewriter.cpp @@ -0,0 +1,183 @@ +/* This file is part of the KDE project + Copyright (C) 2007, 2008 David Faure + + 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, at the discretion of KDE e.V. ( which shall + act as a proxy as in section 14 of the GPLv3 ), 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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "mimetypewriter.h" +#include + +#include +#include +#include +#include + +#include +#include + +/// WARNING: this code is duplicated between apps/nsplugins and runtime/filetypes + +static bool sharedMimeInfoSupportsIcon() +{ + return KMimeType::sharedMimeInfoVersion() >= KDE_MAKE_VERSION(0, 40, 0); +} + +class MimeTypeWriterPrivate +{ +public: + QString localFilePath() const; + + QString m_mimeType; + QString m_comment; + QString m_iconName; + QStringList m_patterns; + QString m_marker; +}; + +MimeTypeWriter::MimeTypeWriter(const QString& mimeType) + : d(new MimeTypeWriterPrivate) +{ + d->m_mimeType = mimeType; + Q_ASSERT(!mimeType.isEmpty()); +} + +MimeTypeWriter::~MimeTypeWriter() +{ + delete d; +} + +void MimeTypeWriter::setComment(const QString& comment) +{ + d->m_comment = comment; +} + +void MimeTypeWriter::setPatterns(const QStringList& patterns) +{ + d->m_patterns = patterns; +} + +void MimeTypeWriter::setIconName(const QString& iconName) +{ + d->m_iconName = iconName; +} + +void MimeTypeWriter::setMarker(const QString& marker) +{ + d->m_marker = marker; +} + +bool MimeTypeWriter::write() +{ + const QString packageFileName = d->localFilePath(); + kDebug() << "writing" << packageFileName; + QFile packageFile(packageFileName); + if (!packageFile.open(QIODevice::WriteOnly)) { + kError() << "Couldn't open" << packageFileName << "for writing"; + return false; + } + QXmlStreamWriter writer(&packageFile); + writer.setAutoFormatting(true); + writer.writeStartDocument(); + if (!d->m_marker.isEmpty()) { + writer.writeComment(d->m_marker); + } + const QString nsUri = "http://www.freedesktop.org/standards/shared-mime-info"; + writer.writeDefaultNamespace(nsUri); + writer.writeStartElement("mime-info"); + writer.writeStartElement(nsUri, "mime-type"); + writer.writeAttribute("type", d->m_mimeType); + + if (!d->m_comment.isEmpty()) { + writer.writeStartElement(nsUri, "comment"); + writer.writeCharacters(d->m_comment); + writer.writeEndElement(); // comment + } + + if (!d->m_iconName.isEmpty()) { + // User-specified icon name + if (sharedMimeInfoSupportsIcon()) { + writer.writeStartElement(nsUri, "icon"); + writer.writeAttribute("name", d->m_iconName); + writer.writeEndElement(); // icon + } + } + + // Allow this local definition to override the global definition + writer.writeStartElement(nsUri, "glob-deleteall"); + writer.writeEndElement(); // glob-deleteall + + foreach(const QString& pattern, d->m_patterns) { + writer.writeStartElement(nsUri, "glob"); + writer.writeAttribute("pattern", pattern); + writer.writeEndElement(); // glob + } + + writer.writeEndElement(); // mime-info + writer.writeEndElement(); // mime-type + writer.writeEndDocument(); + return true; +} + +void MimeTypeWriter::runUpdateMimeDatabase() +{ + const QString localPackageDir = KStandardDirs::locateLocal("xdgdata-mime", QString()); + Q_ASSERT(!localPackageDir.isEmpty()); + KProcess proc; + proc << "update-mime-database"; + proc << localPackageDir; + const int exitCode = proc.execute(); + if (exitCode) { + kWarning() << proc.program() << "exited with error code" << exitCode; + } +} + +QString MimeTypeWriterPrivate::localFilePath() const +{ + // XDG shared mime: we must write into a /share/mime/packages/ file... + // To simplify our job, let's use one "input" file per mimetype, in the user's dir. + // (this writes into $HOME/.local/share/mime by default) + // + // We could also use Override.xml, says the spec, but then we'd need to merge with other mimetypes, + // and in ~/.local we don't really expect other packages to be installed anyway... + QString baseName = m_mimeType; + baseName.replace('/', '-'); + return KStandardDirs::locateLocal( "xdgdata-mime", "packages/" + baseName + ".xml" ); +} + +static QString existingDefinitionFile(const QString& mimeType) +{ + QString baseName = mimeType; + baseName.replace('/', '-'); + return KGlobal::dirs()->findResource( "xdgdata-mime", "packages/" + baseName + ".xml" ); +} + +bool MimeTypeWriter::hasDefinitionFile(const QString& mimeType) +{ + return !existingDefinitionFile(mimeType).isEmpty(); +} + +void MimeTypeWriter::removeOwnMimeType(const QString& mimeType) +{ + const QString file = existingDefinitionFile(mimeType); + Q_ASSERT(!file.isEmpty()); + QFile::remove(file); + // We must also remove the generated XML file, update-mime-database doesn't do that, for unknown media types + QString xmlFile = KGlobal::dirs()->findResource( "xdgdata-mime", mimeType + ".xml" ); + QFile::remove(xmlFile); +} + +/// WARNING: this code is duplicated between apps/nsplugins and runtime/filetypes diff --git a/keditfiletype/mimetypewriter.h b/keditfiletype/mimetypewriter.h new file mode 100644 index 00000000..5a618a6b --- /dev/null +++ b/keditfiletype/mimetypewriter.h @@ -0,0 +1,102 @@ +/* This file is part of the KDE project + Copyright (C) 2007, 2008 David Faure + + 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, at the discretion of KDE e.V. ( which shall + act as a proxy as in section 14 of the GPLv3 ), 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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef MIMETYPEWRITER_H +#define MIMETYPEWRITER_H + +class QStringList; +class QString; +class MimeTypeWriterPrivate; + +/// WARNING: this code is duplicated between apps/nsplugins and runtime/filetypes + +/** + * MimeTypeWriter writes out the definition of a mimetype + * in a XDG shared-mime-info compliant way. + */ +class MimeTypeWriter +{ +public: + MimeTypeWriter(const QString& mimeType); + ~MimeTypeWriter(); + + /** + * Sets the comment describing this mimetype. + * It is strongly recommended to call this. + */ + void setComment(const QString& comment); + + /** + * Define the patterns associated with this mimetype, + * like "*.png" + */ + void setPatterns(const QStringList& patterns); + + /** + * Optional: set a user-specified icon name for this mimetype. + * Otherwise the icon name is based on the mimetype name. + */ + void setIconName(const QString& iconName); + + /** + * Sets a string that will be written out as an XML comment + * in the XML definition file, to make it possible to recognize + * this file later on. Used by nspluginscan. + */ + void setMarker(const QString& marker); + + /** + * Write out the mimetype definition file + * Returns true on success + */ + bool write(); + + /** + * Returns true if a mimetype definition file already exists + * for the given mimetype. + * + * NOTE: this is not the same as testing whether the + * mimetype is defined in general (for instance by freedesktop.org.xml) + * you should use KMimeType::mimeType() for that. + * This method is only for mimetypes generated by MimeTypeWriter. + */ + static bool hasDefinitionFile(const QString& mimeType); + + + /** + * Remove mimetype created by MimeTypeWriter. + * Assumes hasDefinitionFile(mimeType). + * Remember to call runUpdateMimeDatabase afterwards! + */ + static void removeOwnMimeType(const QString& mimeType); + + /** + * Call this once after writing as many mimetypes as you want, + * to let update-mime-database process the new mimetype xml files. + */ + static void runUpdateMimeDatabase(); + +private: + MimeTypeWriterPrivate* const d; +}; + +/// WARNING: this code is duplicated between apps/nsplugins and runtime/filetypes + +#endif /* MIMETYPEWRITER_H */ diff --git a/keditfiletype/newtypedlg.cpp b/keditfiletype/newtypedlg.cpp new file mode 100644 index 00000000..c933a8f7 --- /dev/null +++ b/keditfiletype/newtypedlg.cpp @@ -0,0 +1,82 @@ +/* This file is part of the KDE project + Copyright 2000 Kurt Granroth + 2008 David Faure + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public + License version 2 or at your option version 3 as published by + the Free Software Foundation. + + 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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +// Own +#include "newtypedlg.h" + +// Qt +#include +#include +#include +#include +#include +#include + +// KDE +#include +#include + + +NewTypeDialog::NewTypeDialog(const QStringList &groups, QWidget *parent) + : KDialog( parent ) +{ + setModal( true ); + setCaption( i18n( "Create New File Type" ) ); + setButtons( Ok | Cancel ); + + QWidget* main = mainWidget(); + + QFormLayout *formLayout = new QFormLayout(main); + + QLabel *l = new QLabel(i18n("Group:"), main); + + m_groupCombo = new QComboBox(main); + m_groupCombo->setEditable(true); + m_groupCombo->addItems(groups); + m_groupCombo->setCurrentIndex(m_groupCombo->findText("application")); // certainly a better default than "all" + formLayout->addRow(l, m_groupCombo); + + m_groupCombo->setWhatsThis( i18n("Select the category under which" + " the new file type should be added.") ); + + // Line 1: mimetype name + + l = new QLabel(i18n("Type name:"), main); + + m_typeEd = new KLineEdit(main); + formLayout->addRow(l, m_typeEd); + + m_typeEd->setWhatsThis(i18n("Type the name of the file type. For instance, if you selected 'image' as category and you type 'custom' here, the file type 'image/custom' will be created.")); + + m_typeEd->setFocus(); + + // Set a minimum width so that caption is not half-hidden + setMinimumWidth(300); +} + +QString NewTypeDialog::group() const +{ + return m_groupCombo->currentText(); +} + +QString NewTypeDialog::text() const +{ + return m_typeEd->text(); +} diff --git a/keditfiletype/newtypedlg.h b/keditfiletype/newtypedlg.h new file mode 100644 index 00000000..fba83857 --- /dev/null +++ b/keditfiletype/newtypedlg.h @@ -0,0 +1,46 @@ +/* This file is part of the KDE project + Copyright 2000 Kurt Granroth + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public + License version 2 or at your option version 3 as published by + the Free Software Foundation. + + 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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef _NEWTYPEDLG_H +#define _NEWTYPEDLG_H + +#include + +class QStringList; +class KLineEdit; +class QComboBox; + +/** + * A dialog for creating a new file type, with + * - a combobox for choosing the group + * - a line-edit for entering the name of the file type + * The rest (description, patterns, icon, apps) can be set later in the filetypesview anyway. + */ +class NewTypeDialog : public KDialog +{ +public: + explicit NewTypeDialog(const QStringList &groups, QWidget *parent); + QString group() const; + QString text() const; +private: + KLineEdit *m_typeEd; + QComboBox *m_groupCombo; +}; + +#endif diff --git a/keditfiletype/sharedmimeinfoversion.cpp b/keditfiletype/sharedmimeinfoversion.cpp new file mode 100644 index 00000000..9dabf0e7 --- /dev/null +++ b/keditfiletype/sharedmimeinfoversion.cpp @@ -0,0 +1,28 @@ +/* This file is part of the KDE project + Copyright (C) 2009 David Faure + + 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, at the discretion of KDE e.V. ( which shall + act as a proxy as in section 14 of the GPLv3 ), 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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "sharedmimeinfoversion.h" +#include +#include + +bool SharedMimeInfoVersion::supportsIcon() +{ + return KMimeType::sharedMimeInfoVersion() >= KDE_MAKE_VERSION(0, 40, 0); +} diff --git a/keditfiletype/sharedmimeinfoversion.h b/keditfiletype/sharedmimeinfoversion.h new file mode 100644 index 00000000..9824d7b0 --- /dev/null +++ b/keditfiletype/sharedmimeinfoversion.h @@ -0,0 +1,30 @@ +/* This file is part of the KDE project + Copyright (C) 2009 David Faure + + 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, at the discretion of KDE e.V. ( which shall + act as a proxy as in section 14 of the GPLv3 ), 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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef SHAREDMIMEINFOVERSION_H +#define SHAREDMIMEINFOVERSION_H + +namespace SharedMimeInfoVersion +{ + bool supportsIcon(); +} + +#endif /* SHAREDMIMEINFOVERSION_H */ + diff --git a/keditfiletype/tests/CMakeLists.txt b/keditfiletype/tests/CMakeLists.txt new file mode 100644 index 00000000..73114c54 --- /dev/null +++ b/keditfiletype/tests/CMakeLists.txt @@ -0,0 +1,13 @@ +set( EXECUTABLE_OUTPUT_PATH ${CMAKE_CURRENT_BINARY_DIR} ) +include_directories( ${CMAKE_CURRENT_SOURCE_DIR}/.. ${KDE4_INCLUDES} ) + +########### filetypestest ############### + +kde4_add_unit_test(filetypestest TEST + filetypestest.cpp + ../mimetypedata.cpp + ../mimetypewriter.cpp + ../sharedmimeinfoversion.cpp +) +target_link_libraries(filetypestest ${KDE4_KDECORE_LIBS} ${KDE4_KIO_LIBRARY} ${KDE4_KDEUI_LIBRARIES} + ${QT_QTCORE_LIBRARY} ${QT_QTGUI_LIBRARY} ${QT_QTTEST_LIBRARY}) diff --git a/keditfiletype/tests/filetypestest.cpp b/keditfiletype/tests/filetypestest.cpp new file mode 100644 index 00000000..81183edf --- /dev/null +++ b/keditfiletype/tests/filetypestest.cpp @@ -0,0 +1,402 @@ +/* This file is part of the KDE project + Copyright 2007 David Faure + + 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, at the discretion of KDE e.V. ( which shall + act as a proxy as in section 14 of the GPLv3 ), 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, see . + Boston, MA 02110-1301, USA. +*/ + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + + +class FileTypesTest : public QObject +{ + Q_OBJECT + +private Q_SLOTS: + void initTestCase() + { + m_mimeTypeCreatedSuccessfully = false; + const QString kdehome = QDir::home().canonicalPath() + "/.kde-unit-test"; + QStringList appsDirs = KGlobal::dirs()->resourceDirs("xdgdata-apps"); + //kDebug() << appsDirs; + m_localApps = kdehome + "/xdg/local/applications/"; + QCOMPARE(appsDirs.first(), m_localApps); + QCOMPARE(KGlobal::dirs()->resourceDirs("xdgdata-mime").first(), QString(kdehome + "/xdg/local/mime/")); + + QFile::remove(m_localApps + "mimeapps.list"); + + // Create fake applications for some tests below. + bool mustUpdateKSycoca = false; + fakeApplication = "fakeapplication.desktop"; + if (createDesktopFile(m_localApps + fakeApplication)) + mustUpdateKSycoca = true; + fakeApplication2 = "fakeapplication2.desktop"; + if (createDesktopFile(m_localApps + fakeApplication2)) + mustUpdateKSycoca = true; + + // Cleanup after testMimeTypePatterns if it failed mid-way + const QString packageFileName = KStandardDirs::locateLocal( "xdgdata-mime", "packages/text-plain.xml" ); + if (!packageFileName.isEmpty()) { + QFile::remove(packageFileName); + MimeTypeWriter::runUpdateMimeDatabase(); + mustUpdateKSycoca = true; + } + + QFile::remove(KStandardDirs::locateLocal("config", "filetypesrc")); + + if ( mustUpdateKSycoca ) { + // Update ksycoca in ~/.kde-unit-test after creating the above + runKBuildSycoca(); + } + KService::Ptr fakeApplicationService = KService::serviceByStorageId(fakeApplication); + QVERIFY(fakeApplicationService); + } + + void testMimeTypeGroupAutoEmbed() + { + MimeTypeData data("text"); + QCOMPARE(data.majorType(), QString("text")); + QCOMPARE(data.name(), QString("text")); + QVERIFY(data.isMeta()); + QCOMPARE(data.autoEmbed(), MimeTypeData::No); // text doesn't autoembed by default + QVERIFY(!data.isDirty()); + data.setAutoEmbed(MimeTypeData::Yes); + QCOMPARE(data.autoEmbed(), MimeTypeData::Yes); + QVERIFY(data.isDirty()); + QVERIFY(!data.sync()); // save to disk. Should succeed, but return false (no need to run update-mime-database) + QVERIFY(!data.isDirty()); + // Check what's on disk by creating another MimeTypeData instance + MimeTypeData data2("text"); + QCOMPARE(data2.autoEmbed(), MimeTypeData::Yes); + QVERIFY(!data2.isDirty()); + data2.setAutoEmbed(MimeTypeData::No); // revert to default, for next time + QVERIFY(data2.isDirty()); + QVERIFY(!data2.sync()); + QVERIFY(!data2.isDirty()); + + // TODO test askSave after cleaning up the code + } + + void testMimeTypeAutoEmbed() + { + MimeTypeData data(KMimeType::mimeType("text/plain")); + QCOMPARE(data.majorType(), QString("text")); + QCOMPARE(data.minorType(), QString("plain")); + QCOMPARE(data.name(), QString("text/plain")); + QVERIFY(!data.isMeta()); + QCOMPARE(data.autoEmbed(), MimeTypeData::UseGroupSetting); + QVERIFY(!data.isDirty()); + data.setAutoEmbed(MimeTypeData::Yes); + QCOMPARE(data.autoEmbed(), MimeTypeData::Yes); + QVERIFY(data.isDirty()); + QVERIFY(!data.sync()); // save to disk. Should succeed, but return false (no need to run update-mime-database) + QVERIFY(!data.isDirty()); + // Check what's on disk by creating another MimeTypeData instance + MimeTypeData data2(KMimeType::mimeType("text/plain")); + QCOMPARE(data2.autoEmbed(), MimeTypeData::Yes); + QVERIFY(!data2.isDirty()); + data2.setAutoEmbed(MimeTypeData::UseGroupSetting); // revert to default, for next time + QVERIFY(data2.isDirty()); + QVERIFY(!data2.sync()); + QVERIFY(!data2.isDirty()); + } + + void testMimeTypePatterns() + { + MimeTypeData data(KMimeType::mimeType("text/plain")); + QCOMPARE(data.name(), QString("text/plain")); + QCOMPARE(data.majorType(), QString("text")); + QCOMPARE(data.minorType(), QString("plain")); + QVERIFY(!data.isMeta()); + QStringList patterns = data.patterns(); + QVERIFY(patterns.contains("*.txt")); + QVERIFY(!patterns.contains("*.toto")); + const QStringList origPatterns = patterns; + if (KMimeType::sharedMimeInfoVersion() >= KDE_MAKE_VERSION(0, 61, 0)) { + // is only supported by shared-mime-info > 0.60 + patterns.removeAll("*.txt"); + } + patterns.append("*.toto"); // yes, a french guy wrote this, as you can see + patterns.sort(); // for future comparisons + QVERIFY(!data.isDirty()); + data.setPatterns(patterns); + QVERIFY(data.isDirty()); + bool needUpdateMimeDb = data.sync(); + QVERIFY(needUpdateMimeDb); + MimeTypeWriter::runUpdateMimeDatabase(); + //runKBuildSycoca(); + QCOMPARE(data.patterns(), patterns); + data.refresh(); // reload from the xml + QCOMPARE(data.patterns(), patterns); + // Check what's in ksycoca + QStringList newPatterns = KMimeType::mimeType("text/plain")->patterns(); + newPatterns.sort(); + QCOMPARE(newPatterns, patterns); + QVERIFY(!data.isDirty()); + + // Remove custom file + const QString packageFileName = KStandardDirs::locateLocal( "xdgdata-mime", "packages/text-plain.xml" ); + QVERIFY(!packageFileName.isEmpty()); + QFile::remove(packageFileName); + MimeTypeWriter::runUpdateMimeDatabase(); + //runKBuildSycoca(); + // Check what's in ksycoca + newPatterns = KMimeType::mimeType("text/plain")->patterns(); + newPatterns.sort(); + QCOMPARE(newPatterns, origPatterns); + } + + void testAddService() + { + const char* mimeTypeName = "application/rtf"; // use inherited mimetype to test #321706 + MimeTypeData data(KMimeType::mimeType(mimeTypeName)); + QStringList appServices = data.appServices(); + //kDebug() << appServices; + QVERIFY(!appServices.isEmpty()); + const QString oldPreferredApp = appServices.first(); + QVERIFY(!appServices.contains(fakeApplication)); // already there? hmm can't really test then + QVERIFY(!data.isDirty()); + appServices.prepend(fakeApplication); + data.setAppServices(appServices); + QVERIFY(data.isDirty()); + QVERIFY(!data.sync()); // success, but no need to run update-mime-database + runKBuildSycoca(); + QVERIFY(!data.isDirty()); + // Check what's in ksycoca + checkMimeTypeServices(mimeTypeName, appServices); + // Check what's in mimeapps.list + checkAddedAssociationsContains(mimeTypeName, fakeApplication); + + // Test reordering apps, i.e. move fakeApplication under oldPreferredApp + appServices.removeFirst(); + appServices.insert(1, fakeApplication); + data.setAppServices(appServices); + QVERIFY(!data.sync()); // success, but no need to run update-mime-database + runKBuildSycoca(); + QVERIFY(!data.isDirty()); + // Check what's in ksycoca + checkMimeTypeServices(mimeTypeName, appServices); + // Check what's in mimeapps.list + checkAddedAssociationsContains(mimeTypeName, fakeApplication); + + // Now test removing (in the same test, since it's inter-dependent) + QVERIFY(appServices.removeAll(fakeApplication) > 0); + data.setAppServices(appServices); + QVERIFY(data.isDirty()); + QVERIFY(!data.sync()); // success, but no need to run update-mime-database + runKBuildSycoca(); + // Check what's in ksycoca + checkMimeTypeServices(mimeTypeName, appServices); + // Check what's in mimeapps.list + checkRemovedAssociationsContains(mimeTypeName, fakeApplication); + } + + void testRemoveTwice() + { + // Remove fakeApplication from image/png + const char* mimeTypeName = "image/png"; + MimeTypeData data(KMimeType::mimeType(mimeTypeName)); + QStringList appServices = data.appServices(); + kDebug() << "initial list for" << mimeTypeName << appServices; + QVERIFY(appServices.removeAll(fakeApplication) > 0); + data.setAppServices(appServices); + QVERIFY(!data.sync()); // success, but no need to run update-mime-database + runKBuildSycoca(); + // Check what's in ksycoca + checkMimeTypeServices(mimeTypeName, appServices); + // Check what's in mimeapps.list + checkRemovedAssociationsContains(mimeTypeName, fakeApplication); + + // Remove fakeApplication2 from image/png; must keep the previous entry in "Removed Associations" + kDebug() << "Removing fakeApplication2"; + QVERIFY(appServices.removeAll(fakeApplication2) > 0); + data.setAppServices(appServices); + QVERIFY(!data.sync()); // success, but no need to run update-mime-database + runKBuildSycoca(); + // Check what's in ksycoca + checkMimeTypeServices(mimeTypeName, appServices); + // Check what's in mimeapps.list + checkRemovedAssociationsContains(mimeTypeName, fakeApplication); + // Check what's in mimeapps.list + checkRemovedAssociationsContains(mimeTypeName, fakeApplication2); + + // And now re-add fakeApplication2... + kDebug() << "Re-adding fakeApplication2"; + appServices.prepend(fakeApplication2); + data.setAppServices(appServices); + QVERIFY(!data.sync()); // success, but no need to run update-mime-database + runKBuildSycoca(); + // Check what's in ksycoca + checkMimeTypeServices(mimeTypeName, appServices); + // Check what's in mimeapps.list + checkRemovedAssociationsContains(mimeTypeName, fakeApplication); + checkRemovedAssociationsDoesNotContain(mimeTypeName, fakeApplication2); + } + + void testCreateMimeType() + { + const QString mimeTypeName = "fake/unit-test-fake-mimetype"; + // Clean up after previous runs if necessary + if (MimeTypeWriter::hasDefinitionFile(mimeTypeName)) + MimeTypeWriter::removeOwnMimeType(mimeTypeName); + + MimeTypeData data(mimeTypeName, true); + data.setComment("Fake MimeType"); + QStringList patterns = QStringList() << "*.pkg.tar.gz"; + data.setPatterns(patterns); + QVERIFY(data.isDirty()); + QVERIFY(data.sync()); + MimeTypeWriter::runUpdateMimeDatabase(); + //runKBuildSycoca(); + KMimeType::Ptr mime = KMimeType::mimeType(mimeTypeName); + QVERIFY(mime); + QCOMPARE(mime->comment(), QString("Fake MimeType")); + QCOMPARE(mime->patterns(), patterns); // must sort them if more than one + + // Testcase for the shaman.xml bug + QCOMPARE(KMimeType::findByPath("/whatever/foo.pkg.tar.gz")->name(), QString("fake/unit-test-fake-mimetype")); + + m_mimeTypeCreatedSuccessfully = true; + } + + void testDeleteMimeType() + { + if (!m_mimeTypeCreatedSuccessfully) + QSKIP("This test relies on testCreateMimeType", SkipAll); + const QString mimeTypeName = "fake/unit-test-fake-mimetype"; + QVERIFY(MimeTypeWriter::hasDefinitionFile(mimeTypeName)); + MimeTypeWriter::removeOwnMimeType(mimeTypeName); + MimeTypeWriter::runUpdateMimeDatabase(); + //runKBuildSycoca(); + KMimeType::Ptr mime = KMimeType::mimeType(mimeTypeName); + QVERIFY(!mime); + } + + void testModifyMimeTypeComment() // of a system mimetype. And check that it's re-read correctly. + { + const char* mimeTypeName = "image/png"; + MimeTypeData data(KMimeType::mimeType(mimeTypeName)); + QCOMPARE(data.comment(), QString::fromLatin1("PNG image")); + const char* fakeComment = "PNG image [testing]"; + data.setComment(fakeComment); + QVERIFY(data.isDirty()); + QVERIFY(data.sync()); + MimeTypeWriter::runUpdateMimeDatabase(); + //runKBuildSycoca(); + KMimeType::Ptr mime = KMimeType::mimeType(mimeTypeName); + QVERIFY(mime); + QCOMPARE(mime->comment(), QString::fromLatin1(fakeComment)); + + // Cleanup + QVERIFY(MimeTypeWriter::hasDefinitionFile(mimeTypeName)); + MimeTypeWriter::removeOwnMimeType(mimeTypeName); + } + + void cleanupTestCase() + { + // If we remove it, then every run of the unit test has to run kbuildsycoca... slow. + //QFile::remove(KStandardDirs::locateLocal("xdgdata-apps", "fakeapplication.desktop")); + } + +private: // helper methods + + void checkAddedAssociationsContains(const QString& mimeTypeName, const QString& application) + { + const KConfig config(m_localApps + "mimeapps.list", KConfig::NoGlobals); + const KConfigGroup group(&config, "Added Associations"); + const QStringList addedEntries = group.readXdgListEntry(mimeTypeName); + if (!addedEntries.contains(application)) { + kWarning() << addedEntries << "does not contain" << application; + QVERIFY(addedEntries.contains(application)); + } + } + + void checkRemovedAssociationsContains(const QString& mimeTypeName, const QString& application) + { + const KConfig config(m_localApps + "mimeapps.list", KConfig::NoGlobals); + const KConfigGroup group(&config, "Removed Associations"); + const QStringList removedEntries = group.readXdgListEntry(mimeTypeName); + if (!removedEntries.contains(application)) { + kWarning() << removedEntries << "does not contain" << application; + QVERIFY(removedEntries.contains(application)); + } + } + + void checkRemovedAssociationsDoesNotContain(const QString& mimeTypeName, const QString& application) + { + const KConfig config(m_localApps + "mimeapps.list", KConfig::NoGlobals); + const KConfigGroup group(&config, "Removed Associations"); + const QStringList removedEntries = group.readXdgListEntry(mimeTypeName); + if (removedEntries.contains(application)) { + kWarning() << removedEntries << "contains" << application; + QVERIFY(!removedEntries.contains(application)); + } + } + + void runKBuildSycoca() + { + // Wait for notifyDatabaseChanged DBus signal + // (The real KCM code simply does the refresh in a slot, asynchronously) + QEventLoop loop; + QObject::connect(KSycoca::self(), SIGNAL(databaseChanged(QStringList)), &loop, SLOT(quit())); + KProcess proc; + proc << KStandardDirs::findExe(KBUILDSYCOCA_EXENAME); + proc.setOutputChannelMode(KProcess::MergedChannels); // silence kbuildsycoca output + proc.execute(); + loop.exec(); + } + + bool createDesktopFile(const QString& path) + { + if (!QFile::exists(path)) { + KDesktopFile file(path); + KConfigGroup group = file.desktopGroup(); + group.writeEntry("Name", "FakeApplication"); + group.writeEntry("Type", "Application"); + group.writeEntry("Exec", "ls"); + group.writeEntry("MimeType", "image/png"); + return true; + } + return false; + } + + void checkMimeTypeServices(const QString& mimeTypeName, const QStringList& expectedServices) + { + MimeTypeData data2(KMimeType::mimeType(mimeTypeName)); + if (data2.appServices() != expectedServices) + kDebug() << "got" << data2.appServices() << "expected" << expectedServices; + QCOMPARE(data2.appServices(), expectedServices); + } + + QString fakeApplication; // storage id of the fake application + QString fakeApplication2; // storage id of the fake application2 + QString m_localApps; + bool m_mimeTypeCreatedSuccessfully; +}; + +QTEST_KDEMAIN( FileTypesTest, NoGUI ) + +#include "filetypestest.moc" diff --git a/keditfiletype/typeslistitem.cpp b/keditfiletype/typeslistitem.cpp new file mode 100644 index 00000000..97cd3c14 --- /dev/null +++ b/keditfiletype/typeslistitem.cpp @@ -0,0 +1,67 @@ +/* This file is part of the KDE project + Copyright (C) 2003 Waldo Bastian + Copyright (C) 2003, 2007 David Faure + Copyright (C) 2008 Urs Wolfer + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public + License version 2 or at your option version 3 as published by + the Free Software Foundation. + + 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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +// Own +#include "typeslistitem.h" + +// KDE +#include +#include + + +TypesListItem::TypesListItem(QTreeWidget *parent, const QString & major) + : QTreeWidgetItem(parent), + m_mimetypeData(major) +{ + setText(0, major); +} + +TypesListItem::TypesListItem(TypesListItem *parent, KMimeType::Ptr mimetype) + : QTreeWidgetItem(parent), + m_mimetypeData(mimetype) +{ + setText(0, m_mimetypeData.minorType()); +} + +TypesListItem::TypesListItem(TypesListItem *parent, const QString& newMimetype) + : QTreeWidgetItem(parent), + m_mimetypeData(newMimetype, true) +{ + setText(0, m_mimetypeData.minorType()); +} + +TypesListItem::~TypesListItem() +{ +} + +void TypesListItem::setIcon( const QString& icon ) +{ + m_mimetypeData.setUserSpecifiedIcon(icon); + loadIcon(true); +} + +void TypesListItem::loadIcon(bool forceReload) +{ + if ((!m_mimetypeData.icon().isEmpty() && icon(0).isNull()) || forceReload) { + QTreeWidgetItem::setIcon(0, KIcon(m_mimetypeData.icon())); + } +} + diff --git a/keditfiletype/typeslistitem.h b/keditfiletype/typeslistitem.h new file mode 100644 index 00000000..05e425ae --- /dev/null +++ b/keditfiletype/typeslistitem.h @@ -0,0 +1,62 @@ +/* This file is part of the KDE project + Copyright (C) 2003 Waldo Bastian + Copyright (C) 2003 David Faure + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public + License version 2 or at your option version 3 as published by + the Free Software Foundation. + + 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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef TYPESLISTITEM_H +#define TYPESLISTITEM_H + +#include "mimetypedata.h" +#include + +#include + +// TODO different subclasses for mimetypes and groups? +class TypesListItem : public QTreeWidgetItem +{ +public: + /** + * Create a filetype group + */ + TypesListItem(QTreeWidget *parent, const QString &major); + + /** + * Create a filetype item inside a group, for an existing mimetype + */ + TypesListItem(TypesListItem *parent, KMimeType::Ptr mimetype); + + /** + * Create a filetype item inside a group, for a new mimetype + */ + TypesListItem(TypesListItem *parent, const QString& newMimetype); + + ~TypesListItem(); + + void setIcon( const QString& icon ); + + QString name() const { return m_mimetypeData.name(); } + const MimeTypeData& mimeTypeData() const { return m_mimetypeData; } + MimeTypeData& mimeTypeData() { return m_mimetypeData; } + + void loadIcon(bool forceReload = false); + +private: + MimeTypeData m_mimetypeData; +}; + +#endif diff --git a/kfile/CMakeLists.txt b/kfile/CMakeLists.txt new file mode 100644 index 00000000..79fcf80f --- /dev/null +++ b/kfile/CMakeLists.txt @@ -0,0 +1,11 @@ +########### kfile4 ############### +# Named this way to fix conflict with kdelibs3. +# Distros can add a kfile symlink if kdelibs3 isn't installed. + +set(kfile_SRCS fileprops.cpp ) + +kde4_add_executable(kfile4 NOGUI ${kfile_SRCS}) + +target_link_libraries(kfile4 ${KDE4_KIO_LIBS} ) + +install(TARGETS kfile4 ${INSTALL_TARGETS_DEFAULT_ARGS} ) diff --git a/kfile/Messages.sh b/kfile/Messages.sh new file mode 100755 index 00000000..de3b89bc --- /dev/null +++ b/kfile/Messages.sh @@ -0,0 +1,2 @@ +#! /usr/bin/env bash +$XGETTEXT *.cpp -o $podir/kfile.pot diff --git a/kfile/README b/kfile/README new file mode 100644 index 00000000..d063b6d5 --- /dev/null +++ b/kfile/README @@ -0,0 +1,4 @@ +This is a commandline frontend to KFileMetaInfo. It allows +to read and write meta information of files. + +Carsten Pfeiffer diff --git a/kfile/fileprops.cpp b/kfile/fileprops.cpp new file mode 100644 index 00000000..2bb452f6 --- /dev/null +++ b/kfile/fileprops.cpp @@ -0,0 +1,309 @@ +/* This file is part of the KDE libraries + Copyright (C) 2002,2003 Carsten Pfeiffer + + library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation, version 2. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "fileprops.h" + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include + +#define KFILEVERSION "0.2" +#define INDENT "\t" + +using namespace std; + +static QString beatifyValue( const QString& value ) +{ + if ( value.isNull() ) + return QString("(no value for key available)"); + else if ( value.isEmpty() ) + return QString("(empty)"); + + return value; +} + +FileProps::FileProps( const QString& path ) + : m_dirty( false ) +{ + m_info = new KFileMetaInfo(path, QString(), KFileMetaInfo::Everything); +} + +FileProps::~FileProps() +{ + sync(); + delete m_info; +} + +bool FileProps::sync() +{ + if ( !m_dirty ) + return true; + + return m_info->applyChanges(); +} + +bool FileProps::isValid() const +{ + return m_info->isValid(); +} + +QStringList FileProps::supportedKeys() const +{ + return QStringList(); +} + +QStringList FileProps::availableKeys() const +{ + return m_info->keys(); +} + +QString FileProps::getValue( const QString& key ) const +{ + return FileProps::createKeyValue( m_info->item(key) ); +} + +bool FileProps::setValue( const QString& key, const QString &value ) +{ + bool ok = m_info->item(key).setValue( value ); + m_dirty |= ok; + return ok; +} + +QStringList FileProps::allValues() const +{ + return FileProps::createKeyValueList( m_info->items().values() ); +} + +// static helper: +// creates strings like +// "group: translatedKey: value" +QString FileProps::createKeyValue( const KFileMetaInfoItem& item ) +{ + static const int MAX_SPACE = 25; + + QString result("%1"); + result = result.arg(item.name() + ':', -MAX_SPACE ); + result.append( beatifyValue( item.value().toString() ) ); + + return result; +} + +// static +QStringList FileProps::createKeyValueList( const KFileMetaInfoItemList& items ) +{ + QStringList result; + KFileMetaInfoItemList::ConstIterator it = items.begin(); + + for ( ; it != items.end(); ++it ) + result.append( FileProps::createKeyValue( *it ) ); + + return result; +} + +/////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////// + + + +// kfile --mimetype --listsupported --listavailable --listwritable --getValue "key" --setValue "key=value" --allValues --dialog --quiet file [file...] +// "key" may be a list of keys, separated by commas + +// +// helper functions +// + +// Caller needs to delete the items in the list after use! +static KFileItemList fileItemList( const KCmdLineArgs *args ) +{ + KFileItemList items; + for ( int i = 0; i < args->count(); i++ ) + items.append( KFileItem( KFileItem::Unknown, + KFileItem::Unknown, + args->url( i ) )); + return items; +} + +static void showPropertiesDialog( const KCmdLineArgs *args ) { + const KFileItemList items = fileItemList( args ); + KPropertiesDialog::showDialog( items, 0, true ); +} +/* +static void printMimeTypes( const KCmdLineArgs *args ) +{ + for ( int i = 0; i < args->count(); i++ ) + { + KUrl url = args->url( i ); + KMimeType::Ptr mt = KMimeType::findByUrl( url ); + kDebug() << args->arg(i) << ": " << mt->comment().toLocal8Bit() << " (" + << mt->name().toLocal8Bit() << ")" << endl; + } +}*/ + +static void printList( const QStringList& list ) +{ + QStringList::ConstIterator it = list.begin(); + for ( ; it != list.end(); ++it ) + kDebug() << (*it).toLocal8Bit(); + kDebug(); +} + +static void processMetaDataOptions( const QList propList, + KCmdLineArgs *args ) +{ +// kfile --mimetype --listsupported --listavailable --listwritable --getValue "key" --setValue "key=value" --allValues --dialog --quiet file [file...] +// "key" may be a list of keys, separated by commas + + QString line("-- -------------------------------------------------------"); + foreach ( FileProps *props, propList ) + { + QString file = props->fileName() + ' '; + QString fileString = line; + fileString.replace( 3, file.length(), file ); + kDebug() << QFile::encodeName( fileString ); + + if ( args->isSet( "listsupported" ) ) + { + kDebug() << "=Supported Keys="; + printList( props->supportedKeys() ); + } + if ( args->isSet( "listavailable" ) ) + { + kDebug() << "=Available Keys="; + printList( props->availableKeys() ); + } +// if ( args->isSet( "listwritable" ) ) +// { +// kDebug() << "TODO :)"; +// } + if ( args->isSet( "getValue" ) ) + { + kDebug() << "=Value="; + QString key = args->getOption("getValue"); + kDebug() << props->getValue( key ).toLocal8Bit(); + } + + if ( args->isSet( "setValue" ) ) + { + // separate key and value from the line "key=value" + QString cmd = args->getOption("setValue"); + QString key = cmd.section( '=', 0, 0 ); + QString value = cmd.section( '=', 1 ); + + props->setValue(key, value); + } + + if ( args->isSet( "allValues" ) ) + { + kDebug() << "=All Values="; + printList( props->allValues() ); + } + } + +} + +int main( int argc, char **argv ) +{ + KAboutData about( + "kfile", 0, ki18n( "kfile" ), KFILEVERSION, + ki18n("A command-line tool to read and modify metadata of files."), + KAboutData::License_LGPL, ki18n("(c) 2002, Carsten Pfeiffer"), + ki18n(0 /*text*/), "http://devel-home.kde.org/~pfeiffer/", + "pfeiffer@kde.org" ); + + about.addAuthor( ki18n("Carsten Pfeiffer"), KLocalizedString(), "pfeiffer@kde.org", + "http://devel-home.kde.org/~pfeiffer/" ); + + KCmdLineArgs::init( argc, argv, &about ); + + + KCmdLineOptions options; + + options.add("m"); // short option for --mimetype + options.add("nomimetype", ki18n("Do not print the mimetype of the given file(s)")); + options.add("ls"); // short option for --listsupported + options.add("listsupported", ki18n("List all supported metadata keys." )); + options.add("la"); // short option for --listavailable + options.add("listavailable", ki18n("List all metadata keys which have a value in the given " + "file(s).")); + options.add("q"); // short option for --quiet + options.add("quiet", ki18n("Do not print a warning when more than one file was given " + "and they do not all have the same mimetype.")); + options.add("av"); // short option for --allValues + options.add("allValues", ki18n("Prints all metadata values, available in the given " + "file(s).")); + options.add("dialog", ki18n("Opens a KDE properties dialog to allow viewing and " + "modifying of metadata of the given file(s)")); + options.add("getValue ", ki18n("Prints the value for 'key' of the given file(s). 'key' " + "may also be a comma-separated list of keys")); + options.add("setValue ", ki18n("Attempts to set the value 'value' for the metadata key " + "'key' for the given file(s)")); + options.add("+[files]", ki18n("The file (or a number of files) to operate on.")); + KCmdLineArgs::addCmdLineOptions( options ); + + KCmdLineArgs *args = KCmdLineArgs::parsedArgs(); + bool useGUI = args->isSet( "dialog" ); + + KApplication app( useGUI ); + + QList m_props; + + bool quiet = args->isSet( "quiet" ); + + int files = args->count(); + if ( files == 0 ) { + KCmdLineArgs::usageError( i18n("No files specified") ); // exit()s + } + + if ( args->isSet( "dialog" ) ) { + showPropertiesDialog( args ); + return 0; + } + + QString mimeType; + + for ( int i = 0; i < files; i++ ) { + //if ( args->isSet( "mimetype" ) ) + //printMimeTypes( args ); + + FileProps *props = new FileProps( args->url(i).path()); + if ( props->isValid() ) { + m_props.append( props ); + } else { + if ( !quiet ) { + kWarning() << args->arg(i) << ": " << + i18n("Cannot determine metadata").toLocal8Bit() << endl; + } + delete props; + } + } + + + processMetaDataOptions( m_props, args ); + + qDeleteAll(m_props); // force destruction/sync of props + + return 0; +} diff --git a/kfile/fileprops.h b/kfile/fileprops.h new file mode 100644 index 00000000..c8f4e260 --- /dev/null +++ b/kfile/fileprops.h @@ -0,0 +1,57 @@ +/* This file is part of the KDE libraries + Copyright (C) 2002 Carsten Pfeiffer + + library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation, version 2. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef KFILEPROPS_H +#define KFILEPROPS_H + +#include + +#include +#include + +class FileProps +{ +public: + FileProps( const QString& path); + virtual ~FileProps(); + + bool isValid() const; + + QString fileName() const { return m_info->url().path(); } + + QStringList supportedKeys() const; + QStringList availableKeys() const; + + QString getValue( const QString& key ) const; + bool setValue( const QString& key, const QString &value ); + + QStringList allValues() const; + + bool isReadOnly( const QString& key ); + +private: + static QString createKeyValue( const KFileMetaInfoItem& item ); + static QStringList createKeyValueList( const KFileMetaInfoItemList& items); + bool sync(); + + KFileMetaInfo *m_info; + bool m_dirty; + +}; + +#endif // KFILEPROPS_H diff --git a/kglobalaccel/CMakeLists.txt b/kglobalaccel/CMakeLists.txt new file mode 100644 index 00000000..692c339f --- /dev/null +++ b/kglobalaccel/CMakeLists.txt @@ -0,0 +1,73 @@ +project(kglobalaccel) + +############################################################################### +### KDED Global Accel Daemon + +include_directories( ${KDE4_KDEUI_INCLUDES} ) + +set(kglobalaccel_SRCS + main.cpp + kglobalacceld.cpp + component.cpp + globalshortcut.cpp + globalshortcutsregistry.cpp + globalshortcutcontext.cpp) + +if ( Q_WS_X11 ) + set( kglobalaccel_SRCS ${kglobalaccel_SRCS} kglobalaccel_x11.cpp ) +endif ( Q_WS_X11 ) +if ( Q_WS_MAC ) + set( kglobalaccel_SRCS ${kglobalaccel_SRCS} kglobalaccel_mac.cpp ) +endif ( Q_WS_MAC ) +if ( Q_WS_WIN ) + set( kglobalaccel_SRCS ${kglobalaccel_SRCS} kglobalaccel_win.cpp ) +endif ( Q_WS_WIN ) +if ( Q_WS_QWS ) + set( kglobalaccel_SRCS ${kglobalaccel_SRCS} kglobalaccel_qws.cpp ) +endif ( Q_WS_QWS ) + +kde4_add_kdeinit_executable( kglobalaccel NOGUI ${kglobalaccel_SRCS} ) +target_link_libraries(kdeinit_kglobalaccel ${KDE4_KDEUI_LIBS} ${KDE4_KIO_LIBS} ${X11_LIBRARIES}) +if(Q_WS_MAC) + target_link_libraries(kdeinit_kglobalaccel ${CARBON_LIBRARY}) +endif(Q_WS_MAC) +target_link_libraries(kglobalaccel kdeinit_kglobalaccel) + +# Install application and configuration +install( TARGETS kdeinit_kglobalaccel ${INSTALL_TARGETS_DEFAULT_ARGS} ) +install( TARGETS kglobalaccel ${INSTALL_TARGETS_DEFAULT_ARGS} ) +# install( FILES kglobalaccel.desktop DESTINATION ${AUTOSTART_INSTALL_DIR}) +install( FILES kglobalaccel.desktop DESTINATION ${SERVICES_INSTALL_DIR}) +# KNotify configuration +install( FILES kglobalaccel.notifyrc DESTINATION ${DATA_INSTALL_DIR}/kglobalaccel ) + +# Install some update file (not yet working) +#install( FILES kconf/kdedglobalaccel_kde42.upd DESTINATION ${DATA_INSTALL_DIR}/kconf_update) + +### +### KDE 4.2 > 4.3 Migration Start +### +### Uninstall the kde 4.0 - 4.2 kdedglobalaccel files +find_file( + KDEBASE_KGLOBALACCEL_REMOVE_OBSOLETE_KDED_DESKTOP_FILE + kdedglobalaccel.desktop + PATHS ${SERVICES_INSTALL_DIR}/kded + NO_DEFAULT_PATH) +find_file( + KDEBASE_KGLOBALACCEL_REMOVE_OBSOLETE_KDED_PLUGIN + kded_globalaccel.so + PATHS ${PLUGIN_INSTALL_DIR} + NO_DEFAULT_PATH) +if(KDEBASE_KGLOBALACCEL_REMOVE_OBSOLETE_KDED_DESKTOP_FILE) + install(CODE "MESSAGE(\"Removing kdedglobalaccel desktop file\")") + install(CODE "file(REMOVE ${KDEBASE_KGLOBALACCEL_REMOVE_OBSOLETE_KDED_DESKTOP_FILE})") +endif(KDEBASE_KGLOBALACCEL_REMOVE_OBSOLETE_KDED_DESKTOP_FILE) +if(KDEBASE_KGLOBALACCEL_REMOVE_OBSOLETE_KDED_PLUGIN) + install(CODE "MESSAGE(\"Removing kdedglobalaccel plugin\")") + install(CODE "file(REMOVE ${KDEBASE_KGLOBALACCEL_REMOVE_OBSOLETE_KDED_PLUGIN})") +endif(KDEBASE_KGLOBALACCEL_REMOVE_OBSOLETE_KDED_PLUGIN) + +### +### KDE 4.2 > 4.3 Migration End +### + diff --git a/kglobalaccel/Messages.sh b/kglobalaccel/Messages.sh new file mode 100644 index 00000000..59fbd0b1 --- /dev/null +++ b/kglobalaccel/Messages.sh @@ -0,0 +1,2 @@ +#! /usr/bin/env bash +$XGETTEXT *.cpp -o $podir/kglobalaccel.pot diff --git a/kglobalaccel/component.cpp b/kglobalaccel/component.cpp new file mode 100644 index 00000000..0c29bfe6 --- /dev/null +++ b/kglobalaccel/component.cpp @@ -0,0 +1,501 @@ +/* Copyright (C) 2008 Michael Jansen + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "component.h" + +#include "globalshortcut.h" +#include "globalshortcutcontext.h" +#include "globalshortcutsregistry.h" + +#include +#include + +#include +#include + +#ifdef Q_WS_X11 +#include +#include +#endif + +static QList keysFromString(const QString &str) +{ + QList ret; + if (str == "none") { + return ret; + } + const QStringList strList = str.split('\t'); + foreach (const QString &s, strList) { + int key = QKeySequence(s)[0]; + if (key != -1) { //sanity check just in case + ret.append(key); + } + } + return ret; +} + + +static QString stringFromKeys(const QList &keys) +{ + if (keys.isEmpty()) { + return "none"; + } + QString ret; + foreach (int key, keys) { + ret.append(QKeySequence(key).toString()); + ret.append('\t'); + } + ret.chop(1); + return ret; +} + +namespace KdeDGlobalAccel { + +Component::Component( + const QString &uniqueName, + const QString &friendlyName, + GlobalShortcutsRegistry *registry) + : _uniqueName(uniqueName) + ,_friendlyName(friendlyName) + ,_registry(registry) + { + // Make sure we do no get uniquenames still containing the context + Q_ASSERT(uniqueName.indexOf("|")==-1); + + // Register ourselve with the registry + if (_registry) + { + _registry->addComponent(this); + } + + createGlobalShortcutContext("default", "Default Context"); + _current = _contexts.value("default"); + } + + +Component::~Component() + { + // Remove ourselve from the registry + if (_registry) + { + _registry->takeComponent(this); + } + + // We delete all shortcuts from all contexts + qDeleteAll(_contexts); + } + + +bool Component::activateGlobalShortcutContext( + const QString &uniqueName) + { + if (!_contexts.value(uniqueName)) + { + createGlobalShortcutContext(uniqueName, "TODO4"); + return false; + } + + // Deactivate the current contexts shortcuts + deactivateShortcuts(); + + // Switch the context + _current = _contexts.value(uniqueName); + + return true; + } + + +void Component::activateShortcuts() + { + Q_FOREACH (GlobalShortcut *shortcut, _current->_actions) + { + shortcut->setActive(); + } + } + + +QList Component::allShortcuts(const QString &contextName) const + { + GlobalShortcutContext *context = _contexts.value(contextName); + if (context) + { + return context->_actions.values(); + } + else + { + Q_ASSERT(false); // Unknown context + return QList (); + } + } + + +QList Component::allShortcutInfos(const QString &contextName) const + { + QList rc; + + GlobalShortcutContext *context = _contexts.value(contextName); + if (!context) + { + Q_ASSERT(false); // Unknown context + return rc; + } + + return context->allShortcutInfos(); + } + + +bool Component::cleanUp() + { + bool changed = false;; + + Q_FOREACH (GlobalShortcut *shortcut, _current->_actions) + { + kDebug() << _current->_actions.size(); + if (!shortcut->isPresent()) + { + changed = true; + shortcut->unRegister(); + } + } + + if (changed) + { + _registry->writeSettings(); + // We could be destroyed after this call! + } + + return changed; + } + + +bool Component::createGlobalShortcutContext( + const QString &uniqueName, + const QString &friendlyName) + { + if (_contexts.value(uniqueName)) + { + kDebug() << "Shortcut Context " << uniqueName << "already exists for component " << _uniqueName; + return false; + } + _contexts.insert(uniqueName, new GlobalShortcutContext(uniqueName, friendlyName, this)); + return true; + } + + +GlobalShortcutContext *Component::currentContext() + { + return _current; + } + + +QDBusObjectPath Component::dbusPath() const + { + QString dbusPath = _uniqueName; + // Clean up for dbus usage: any non-alphanumeric char should be turned into '_' + const int len = dbusPath.length(); + for ( int i = 0; i < len; ++i ) + { + if ( !dbusPath[i].isLetterOrNumber() ) + dbusPath[i] = QLatin1Char('_'); + } + // QDBusObjectPath could be a little bit easier to handle :-) + return QDBusObjectPath( _registry->dbusPath().path() + "component/" + dbusPath); + } + + +void Component::deactivateShortcuts(bool temporarily) + { + Q_FOREACH (GlobalShortcut *shortcut, _current->_actions) + { + if (temporarily + && uniqueName() == "kwin" + && shortcut->uniqueName() == "Block Global Shortcuts") + { + continue; + } + shortcut->setInactive(); + } + } + + +void Component::emitGlobalShortcutPressed( const GlobalShortcut &shortcut ) + { +#ifdef Q_WS_X11 + // pass X11 timestamp + long timestamp = QX11Info::appTime(); + // Make sure kglobalacceld has ungrabbed the keyboard after receiving the + // keypress, otherwise actions in application that try to grab the + // keyboard (e.g. in kwin) may fail to do so. There is still a small race + // condition with this being out-of-process. + qApp->syncX(); +#else + long timestamp = 0; +#endif + + // Make sure it is one of ours + if (shortcut.context()->component() != this) + { + Q_ASSERT(shortcut.context()->component() == this); + // In production mode do nothing + return; + } + + emit globalShortcutPressed( + shortcut.context()->component()->uniqueName(), + shortcut.uniqueName(), + timestamp); + } + +void Component::invokeShortcut(const QString &shortcutName, const QString &context) + { + GlobalShortcut *shortcut = getShortcutByName(shortcutName, context); + if (shortcut) emitGlobalShortcutPressed(*shortcut); + } + +QString Component::friendlyName() const + { + if (_friendlyName.isEmpty()) + return _uniqueName; + return _friendlyName; + } + + +GlobalShortcut *Component::getShortcutByKey(int key) const + { + return _current->getShortcutByKey(key); + } + + +QList Component::getShortcutsByKey(int key) const + { + QList rc; + Q_FOREACH(GlobalShortcutContext *context, _contexts) + { + GlobalShortcut *sc = context->getShortcutByKey(key); + if (sc) rc.append(sc); + } + return rc; + } + + +GlobalShortcut *Component::getShortcutByName(const QString &uniqueName, const QString &context) const + { + if (!_contexts.value(context)) + { + return NULL; + } + + return _contexts.value(context)->_actions.value(uniqueName); + } + + +QStringList Component::getShortcutContexts() const + { + return _contexts.keys(); + } + + +bool Component::isActive() const + { + // The component is active if at least one of it's global shortcuts is + // present. + Q_FOREACH (GlobalShortcut *shortcut, _current->_actions) + { + if (shortcut->isPresent()) return true; + } + return false; + } + + +bool Component::isShortcutAvailable( + int key, + const QString &component, + const QString &context) const + { + kDebug() << QKeySequence(key).toString() << component; + + // if this component asks for the key. only check the keys in the same + // context + if (component==uniqueName()) + { + Q_FOREACH(GlobalShortcut *sc, shortcutContext(context)->_actions) + { + if (sc->keys().contains(key)) return false; + } + } + else + { + Q_FOREACH(GlobalShortcutContext *ctx, _contexts) + { + Q_FOREACH(GlobalShortcut *sc, ctx->_actions) + { + if (sc->keys().contains(key)) return false; + } + } + } + return true; + } + + +void Component::loadSettings(KConfigGroup &configGroup) + { + // GlobalShortcutsRegistry::loadSettings handles contexts. + Q_FOREACH (const QString &confKey, configGroup.keyList()) + { + const QStringList entry = configGroup.readEntry(confKey, QStringList()); + if (entry.size() != 3) + { + continue; + } + + // The shortcut will register itself with us + GlobalShortcut *shortcut = new GlobalShortcut( + confKey, + entry[2], + _current); + + QList keys = keysFromString(entry[0]); + shortcut->setDefaultKeys(keysFromString(entry[1])); + shortcut->setIsFresh(false); + + Q_FOREACH (int key, keys) + { + if (key != 0) + { + if (GlobalShortcutsRegistry::self()->getShortcutByKey(key)) + { + // The shortcut is already used. The config file is + // broken. Ignore the request. + keys.removeAll(key); + kWarning() << "Shortcut found twice in kglobalshortcutsrc."; + } + } + } + shortcut->setKeys(keys); + } + } + + +void Component::setFriendlyName(const QString &name) + { + _friendlyName = name; + } + + +GlobalShortcutContext *Component::shortcutContext( const QString &contextName ) + { + return _contexts.value(contextName); + } + + +GlobalShortcutContext const *Component::shortcutContext( const QString &contextName ) const + { + return _contexts.value(contextName); + } + + +QStringList Component::shortcutNames( const QString &contextName) const + { + GlobalShortcutContext *context = _contexts.value(contextName); + if (!context) + { + Q_ASSERT(false); // Unknown context + return QStringList(); + } + + return context->_actions.keys(); + } + + +bool Component::showKCM() + { + return KRun::runCommand("kcmshell4 keys", NULL); + } + + +QString Component::uniqueName() const + { + return _uniqueName; + } + + +void Component::unregisterShortcut(const QString &uniqueName) + { + // Now wrote all contexts + Q_FOREACH( GlobalShortcutContext *context, _contexts) + { + if (context->_actions.value(uniqueName)) + { + delete context->takeShortcut(context->_actions.value(uniqueName)); + } + } + } + + +void Component::writeSettings(KConfigGroup& configGroup) const + { + // If we don't delete the current content global shortcut + // registrations will never not deleted after forgetGlobalShortcut() + configGroup.deleteGroup(); + + + // Now write all contexts + Q_FOREACH( GlobalShortcutContext *context, _contexts) + { + KConfigGroup contextGroup; + + if (context->uniqueName() == "default") + { + contextGroup = configGroup; + // Write the friendly name + contextGroup.writeEntry("_k_friendly_name", friendlyName()); + } + else + { + contextGroup = KConfigGroup(&configGroup, context->uniqueName()); + // Write the friendly name + contextGroup.writeEntry("_k_friendly_name", context->friendlyName()); + } + + // kDebug() << "writing group " << _uniqueName << ":" << context->uniqueName(); + + Q_FOREACH(const GlobalShortcut *shortcut, context->_actions) + { + // kDebug() << "writing" << shortcut->uniqueName(); + + // We do not write fresh shortcuts. + // We do not write session shortcuts + if (shortcut->isFresh() || shortcut->isSessionShortcut()) + { + continue; + } + // kDebug() << "really writing" << shortcut->uniqueName(); + + QStringList entry(stringFromKeys(shortcut->keys())); + entry.append(stringFromKeys(shortcut->defaultKeys())); + entry.append(shortcut->friendlyName()); + + contextGroup.writeEntry(shortcut->uniqueName(), entry); + } + } + } + +#include "moc_component.cpp" + +} // namespace KdeDGlobalAccel + diff --git a/kglobalaccel/component.h b/kglobalaccel/component.h new file mode 100644 index 00000000..019c3153 --- /dev/null +++ b/kglobalaccel/component.h @@ -0,0 +1,184 @@ +#ifndef COMPONENT_H +#define COMPONENT_H +/* Copyright (C) 2008 Michael Jansen + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "globalshortcut.h" +#include "kglobalshortcutinfo.h" + +#include "kconfiggroup.h" + +#include +#include + +class GlobalShortcut; +class GlobalShortcutContext; +class GlobalShortcutsRegistry; + + +namespace KdeDGlobalAccel { + +/** + * @author Michael Jansen + */ +class Component : public QObject + { + Q_OBJECT + + Q_CLASSINFO("D-Bus Interface", "org.kde.kglobalaccel.Component") + + Q_SCRIPTABLE Q_PROPERTY( QString friendlyName READ friendlyName ) + Q_SCRIPTABLE Q_PROPERTY( QString uniqueName READ uniqueName ) + +public: + + //! Creates a new component. The component will be registered with @p + //! registry if specified and registered with dbus. + Component( + const QString &uniqueName, + const QString &friendlyName, + GlobalShortcutsRegistry *registry = NULL); + + ~Component(); + + bool activateGlobalShortcutContext(const QString &uniqueName); + + void activateShortcuts(); + + //! Returns all shortcuts in context @context + QList allShortcuts(const QString &context = "default") const; + + //! Creates the new global shortcut context @p context + bool createGlobalShortcutContext(const QString &context, const QString &friendlyName=""); + + //! Return the current context + GlobalShortcutContext* currentContext(); + + //! Return uniqueName converted to a valid dbus path + QDBusObjectPath dbusPath() const; + + //! Deactivate all currently active shortcuts + void deactivateShortcuts(bool temporarily=false); + + //! Returns the friendly name + QString friendlyName() const; + + //! Returns the currently active shortcut for key + GlobalShortcut *getShortcutByKey(int key) const; + + //! Returns the shortcut context @p name or NULL + GlobalShortcutContext *shortcutContext(const QString &name); + GlobalShortcutContext const *shortcutContext(const QString &name) const; + + /** + * Returns the list of shortcuts (different context) registered with @p + * key. + */ + QList getShortcutsByKey(int key) const; + + //! Returns the shortcut by unique name. Only the active context is + //! searched. + GlobalShortcut *getShortcutByName( + const QString &uniqueName, + const QString &context = "default") const; + + /** + * Check if @a key is available for component @p component + */ + bool isShortcutAvailable( + int key, + const QString &component, + const QString &context) const; + + //! Load the settings from config group @p config + void loadSettings(KConfigGroup &config); + + //! Sets the human readable name for this component. + void setFriendlyName(const QString &); + + QString uniqueName() const; + + //! Unregister @a shortcut. This will remove its siblings from all contexts + void unregisterShortcut(const QString &uniqueName); + + void writeSettings(KConfigGroup &config) const; + +public Q_SLOTS: + + // For dbus Q_SCRIPTABLE has to be on slots. Scriptable methods are not + // exported. + + /** + * Remove all currently not used global shortcuts registrations for this + * component and if nothing is left the component too. + * + * If the method returns true consider all information previously acquired + * from this component as void. + * + * The method will cleanup in all contexts. + * + * @return @c true if a change was made, @c false if not. + */ + Q_SCRIPTABLE bool cleanUp(); + + /** + * Check if the component is currently active. + * + * A component is active if at least one of it's global shortcuts is + * currently present. + */ + Q_SCRIPTABLE bool isActive() const; + + //! Get all shortcutnames living in @a context + Q_SCRIPTABLE QStringList shortcutNames(const QString &context = "default") const; + + //! Returns all shortcut in @a context + Q_SCRIPTABLE QList allShortcutInfos(const QString &context = "default") const; + + //! Returns the shortcut contexts available for the component. + Q_SCRIPTABLE QStringList getShortcutContexts() const; + + //! Start the global shortcuts kcm and show this component. + Q_SCRIPTABLE bool showKCM(); + + void emitGlobalShortcutPressed(const GlobalShortcut &shortcut); + + Q_SCRIPTABLE void invokeShortcut(const QString &shortcutName, const QString &context = "default"); + +Q_SIGNALS: + + //! Signals that a action for this component was triggered + Q_SCRIPTABLE void globalShortcutPressed(const QString &componentUnique, const QString &shortcutUnique, qlonglong timestamp); + +private: + + QString _uniqueName; + //the name as it would be found in a magazine article about the application, + //possibly localized if a localized name exists. + QString _friendlyName; + + GlobalShortcutsRegistry *_registry; + + GlobalShortcutContext *_current; + QHash _contexts; + }; + +} + + +#endif /* #ifndef COMPONENT_H */ diff --git a/kglobalaccel/dbus/org.kde.kglobalaccel.service.in b/kglobalaccel/dbus/org.kde.kglobalaccel.service.in new file mode 100644 index 00000000..d8576b0a --- /dev/null +++ b/kglobalaccel/dbus/org.kde.kglobalaccel.service.in @@ -0,0 +1,3 @@ +[D-BUS Service] +Name=org.kde.kglobalaccel +Exec=@CMAKE_INSTALL_PREFIX@/bin/kglobalaccel diff --git a/kglobalaccel/globalshortcut.cpp b/kglobalaccel/globalshortcut.cpp new file mode 100644 index 00000000..2a41e9bc --- /dev/null +++ b/kglobalaccel/globalshortcut.cpp @@ -0,0 +1,249 @@ +/* Copyright (C) 2008 Michael Jansen + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "globalshortcut.h" + +#include "component.h" +#include "globalshortcutcontext.h" +#include "globalshortcutsregistry.h" + +#include + +#include + + +GlobalShortcut::GlobalShortcut() + : _isPresent(false) + ,_isRegistered(false) + ,_isFresh(true) + ,_context(NULL) + ,_uniqueName() + ,_friendlyName() + ,_keys() + ,_defaultKeys() + {} + + +GlobalShortcut::GlobalShortcut( + const QString &uniqueName, + const QString &friendlyName, + GlobalShortcutContext *context) + : _isPresent(false) + ,_isRegistered(false) + ,_isFresh(true) + ,_context(context) + ,_uniqueName(uniqueName) + ,_friendlyName(friendlyName) + ,_keys() + ,_defaultKeys() + { + context->addShortcut(this); + } + + +GlobalShortcut::~GlobalShortcut() + { + setInactive(); + } + + +GlobalShortcut::operator KGlobalShortcutInfo () const + { + KGlobalShortcutInfo info; + info.d->uniqueName = _uniqueName; + info.d->friendlyName = _friendlyName; + info.d->contextUniqueName = context()->uniqueName(); + info.d->contextFriendlyName = context()->friendlyName(); + info.d->componentUniqueName = context()->component()->uniqueName(); + info.d->componentFriendlyName = context()->component()->friendlyName(); + Q_FOREACH (int key, _keys) + { + info.d->keys.append(QKeySequence(key)); + } + Q_FOREACH (int key, _defaultKeys) + { + info.d->defaultKeys.append(QKeySequence(key)); + } + return info; + } + + +bool GlobalShortcut::isActive() const + { + return _isRegistered; + } + + +bool GlobalShortcut::isFresh() const + { + return _isFresh; + } + + +bool GlobalShortcut::isPresent() const + { + return _isPresent; + } + + +bool GlobalShortcut::isSessionShortcut() const + { + return uniqueName().startsWith(QLatin1String("_k_session:")); + } + + +void GlobalShortcut::setIsFresh(bool value) + { + _isFresh = value; + } + + +void GlobalShortcut::setIsPresent(bool value) + { + // (de)activate depending on old/new value + _isPresent = value; + value + ? setActive() + : setInactive(); + } + + +GlobalShortcutContext *GlobalShortcut::context() + { + return _context; + } + + +GlobalShortcutContext const *GlobalShortcut::context() const + { + return _context; + } + + +QString GlobalShortcut::uniqueName() const + { + return _uniqueName; + } + + +void GlobalShortcut::unRegister() + { + return _context->component()->unregisterShortcut(uniqueName()); + } + + +QString GlobalShortcut::friendlyName() const + { + return _friendlyName; + } + + +void GlobalShortcut::setFriendlyName(const QString &name) + { + _friendlyName = name; + } + + +QList GlobalShortcut::keys() const + { + return _keys; + } + + +void GlobalShortcut::setKeys(const QList newKeys) + { + bool active = _isRegistered; + if (active) + { + setInactive(); + } + + _keys = QList(); + + Q_FOREACH(int key, newKeys) + { + if (key!=0 && !GlobalShortcutsRegistry::self()->getShortcutByKey(key)) + { + _keys.append(key); + } + else + { + kDebug() << _uniqueName << "skipping because key" << QKeySequence(key).toString() << "is already taken"; + _keys.append(0); + } + } + + if (active) + { + setActive(); + } + } + + +QList GlobalShortcut::defaultKeys() const + { + return _defaultKeys; + } + + +void GlobalShortcut::setDefaultKeys(const QList newKeys) + { + _defaultKeys = newKeys; + } + + +void GlobalShortcut::setActive() + { + if (!_isPresent || _isRegistered) + { + // The corresponding application is not present or the keys are + // already grabbed + return; + } + + Q_FOREACH( int key, _keys) + { + if (key != 0 && !GlobalShortcutsRegistry::self()->registerKey(key, this)) + { + kDebug() << uniqueName() << ": Failed to register " << QKeySequence(key).toString(); + } + } + + _isRegistered = true; + } + + +void GlobalShortcut::setInactive() + { + if (!_isRegistered) + { + // The keys are not grabbed currently + return; + } + + Q_FOREACH( int key, _keys) + { + if (key != 0 && !GlobalShortcutsRegistry::self()->unregisterKey(key, this)) + { + kDebug() << uniqueName() << ": Failed to unregister " << QKeySequence(key).toString(); + } + } + + _isRegistered = false; + } + diff --git a/kglobalaccel/globalshortcut.h b/kglobalaccel/globalshortcut.h new file mode 100644 index 00000000..c2989dba --- /dev/null +++ b/kglobalaccel/globalshortcut.h @@ -0,0 +1,121 @@ +#ifndef GLOBALSHORTCUT_H +#define GLOBALSHORTCUT_H +/* Copyright (C) 2008 Michael Jansen + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "kglobalshortcutinfo_p.h" + +#include + + +class GlobalShortcutContext; + +/** + * Represents a global shortcut. + * + * @internal + * + * \note This class can handle multiple keys (default and active). This + * feature isn't used currently. kde4 only allows setting one key per global + * shortcut. + * + * @author Michael Jansen + */ +class GlobalShortcut + { +public: + + GlobalShortcut(const QString &uniqueName, const QString &friendlyName, GlobalShortcutContext *context); + GlobalShortcut(); + + ~GlobalShortcut(); + + //! Returns the context the shortcuts belongs to + GlobalShortcutContext *context(); + GlobalShortcutContext const *context() const; + + //! Returns the default keys for this shortcut. + QList defaultKeys() const; + + //! Return the friendly display name for this shortcut. + QString friendlyName() const; + + //! Check if the shortcut is active. It's keys are grabbed + bool isActive() const; + + //! Check if the shortcut is fresh/new. Is an internal state + bool isFresh() const; + + //! Check if the shortcut is present. It application is running. + bool isPresent() const; + + //! Returns true if the shortcut is a session shortcut + bool isSessionShortcut() const; + + //! Returns a list of keys associated with this shortcut. + QList keys() const; + + //! Activates the shortcut. The keys are grabbed. + void setActive(); + + //! Sets the default keys for this shortcut. + void setDefaultKeys(const QList); + + //! Sets the friendly name for the shortcut. For display. + void setFriendlyName(const QString &); + + //! Sets the shortcut inactive. No longer grabs the keys. + void setInactive(); + + void setIsPresent(bool); + void setIsFresh(bool); + + //! Sets the keys activated with this shortcut. The old keys are freed. + void setKeys(const QList); + + //! Returns the unique name aka id for the shortcuts. + QString uniqueName() const; + + operator KGlobalShortcutInfo () const; + + //! Remove this shortcut and it's siblings + void unRegister(); + +private: + + //! means the associated application is present. + bool _isPresent:1; + + //! means the shortcut is registered with GlobalShortcutsRegistry + bool _isRegistered:1; + + //! means the shortcut is new + bool _isFresh:1; + + //! The context the shortcut belongs too + GlobalShortcutContext *_context; + + QString _uniqueName; + QString _friendlyName; //usually localized + + QList _keys; + QList _defaultKeys; + }; + + +#endif /* #ifndef GLOBALSHORTCUT_H */ diff --git a/kglobalaccel/globalshortcutcontext.cpp b/kglobalaccel/globalshortcutcontext.cpp new file mode 100644 index 00000000..f1779326 --- /dev/null +++ b/kglobalaccel/globalshortcutcontext.cpp @@ -0,0 +1,116 @@ +/* Copyright (C) 2008 Michael Jansen + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "globalshortcutcontext.h" + +#include "globalshortcut.h" + +#include "kdebug.h" + +GlobalShortcutContext::GlobalShortcutContext( + const QString &uniqueName, + const QString &friendlyName, + KdeDGlobalAccel::Component *component) + + : _uniqueName(uniqueName), + _friendlyName(friendlyName), + _component(component), + _actions() + {} + + +GlobalShortcutContext::~GlobalShortcutContext() + { + qDeleteAll(_actions); _actions.clear(); + } + + +void GlobalShortcutContext::addShortcut(GlobalShortcut *shortcut) + { + _actions.insert(shortcut->uniqueName(), shortcut); + } + + +QList GlobalShortcutContext::allShortcutInfos() const + { + QList rc; + Q_FOREACH (GlobalShortcut *shortcut, _actions) + { + rc.append(static_cast(*shortcut)); + } + return rc; + } + + +KdeDGlobalAccel::Component const *GlobalShortcutContext::component() const + { + return _component; + } + + +KdeDGlobalAccel::Component *GlobalShortcutContext::component() + { + return _component; + } + + +QString GlobalShortcutContext::friendlyName() const + { + return _friendlyName; + } + + +GlobalShortcut *GlobalShortcutContext::getShortcutByKey(int key) const + { + // Qt triggers both shortcuts that include Shift+Backtab and Shift+Tab + // when user presses Shift+Tab. Do the same here. + int keySym = key & ~Qt::KeyboardModifierMask; + int keyMod = key & Qt::KeyboardModifierMask; + if ((keyMod & Qt::SHIFT) && (keySym == Qt::Key_Backtab || + keySym == Qt::Key_Tab)) + { + Q_FOREACH(GlobalShortcut *sc, _actions) + { + if (sc->keys().contains(keyMod | Qt::Key_Tab) || + sc->keys().contains(keyMod | Qt::Key_Backtab)) + return sc; + } + } + else + { + Q_FOREACH(GlobalShortcut *sc, _actions) + { + if (sc->keys().contains(key)) return sc; + } + } + return NULL; + } + + +GlobalShortcut *GlobalShortcutContext::takeShortcut(GlobalShortcut *shortcut) + { + // Try to take the shortcut. Result could be null if the shortcut doesn't + // belong to this component. + return _actions.take(shortcut->uniqueName()); + } + + +QString GlobalShortcutContext::uniqueName() const + { + return _uniqueName; + } diff --git a/kglobalaccel/globalshortcutcontext.h b/kglobalaccel/globalshortcutcontext.h new file mode 100644 index 00000000..74ff94c4 --- /dev/null +++ b/kglobalaccel/globalshortcutcontext.h @@ -0,0 +1,91 @@ +#ifndef GLOBALSHORTCUTCONTEXT_H +#define GLOBALSHORTCUTCONTEXT_H +/* Copyright (C) 2008 Michael Jansen + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "kglobalshortcutinfo.h" + +#include +#include + +namespace KdeDGlobalAccel { + class Component; +} + +class GlobalShortcut; + +/** + * @author Michael Jansen + */ +class GlobalShortcutContext + { +public: + + /** + * Default constructor + */ + GlobalShortcutContext( + const QString &uniqueName, + const QString &friendlyName, + KdeDGlobalAccel::Component *component ); + + /** + * Destructor + */ + virtual ~GlobalShortcutContext(); + + //! Adds @p shortcut to the context + void addShortcut(GlobalShortcut *shortcut); + + //! Return KGlobalShortcutInfos for all shortcuts + QList allShortcutInfos() const; + + /** + * Get the name for the context + */ + QString uniqueName() const; + QString friendlyName() const; + + KdeDGlobalAccel::Component *component(); + KdeDGlobalAccel::Component const *component() const; + + //! Get shortcut for @p key or NULL + GlobalShortcut *getShortcutByKey(int key) const; + + //! Remove @p shortcut from the context. The shortcut is not deleted. + GlobalShortcut *takeShortcut(GlobalShortcut *shortcut); + +private: + + friend class KdeDGlobalAccel::Component; + + //! The unique name for this context + QString _uniqueName; + + //! The unique name for this context + QString _friendlyName; + + //! The component the context belongs too + KdeDGlobalAccel::Component *_component; + + //! The actions associated with this context + QHash _actions; +}; + + +#endif /* #ifndef GLOBALSHORTCUTCONTEXT_H */ diff --git a/kglobalaccel/globalshortcutsregistry.cpp b/kglobalaccel/globalshortcutsregistry.cpp new file mode 100644 index 00000000..985ab31e --- /dev/null +++ b/kglobalaccel/globalshortcutsregistry.cpp @@ -0,0 +1,390 @@ +/* Copyright (C) 2008 Michael Jansen + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "globalshortcutsregistry.h" +#include "component.h" +#include "globalshortcut.h" +#include "globalshortcutcontext.h" + +#include "kdebug.h" +#include "kglobal.h" +#include "klocale.h" +#include "knotification.h" + +#include +#include + +#ifdef Q_WS_X11 +#include "kglobalaccel_x11.h" +#include +#include +#elif defined(Q_WS_MACX) +#include "kglobalaccel_mac.h" +#elif defined(Q_WS_WIN) +#include "kglobalaccel_win.h" +#else +#include "kglobalaccel_qws.h" +#endif + +GlobalShortcutsRegistry::GlobalShortcutsRegistry() + : QObject() + ,_active_keys() + ,_components() + ,_manager(new KGlobalAccelImpl(this)) + ,_config("kglobalshortcutsrc", KConfig::SimpleConfig) + { + _manager->setEnabled(true); + } + + +GlobalShortcutsRegistry::~GlobalShortcutsRegistry() + { + _manager->setEnabled(false); + + // Ungrab all keys. We don't go over GlobalShortcuts because + // GlobalShortcutsRegistry::self() doesn't work anymore. + Q_FOREACH (const int key, _active_keys.keys()) + { + _manager->grabKey(key, false); + } + _active_keys.clear(); + } + + +KdeDGlobalAccel::Component *GlobalShortcutsRegistry::addComponent(KdeDGlobalAccel::Component *component) + { + if (_components.value(component->uniqueName())) + { + Q_ASSERT_X(false, "GlobalShortcutsRegistry::addComponent", "component already registered?!?!"); + return _components.value(component->uniqueName()); + } + + _components.insert(component->uniqueName(), component); + QDBusConnection conn(QDBusConnection::sessionBus()); + + conn.registerObject( + component->dbusPath().path(), + component, + QDBusConnection::ExportScriptableContents); + return component; + } + + +void GlobalShortcutsRegistry::activateShortcuts() + { + Q_FOREACH (KdeDGlobalAccel::Component *component, _components) + { + component->activateShortcuts(); + } + } + + +QList GlobalShortcutsRegistry::allMainComponents() const + { + return _components.values(); + } + + +void GlobalShortcutsRegistry::clear() + { + Q_FOREACH(KdeDGlobalAccel::Component *component, _components) + { + delete component; + } + _components.clear(); + + // The shortcuts should have deregistered themselves + Q_ASSERT(_active_keys.isEmpty()); + } + + +QDBusObjectPath GlobalShortcutsRegistry::dbusPath() const + { + return _dbusPath; + } + + +void GlobalShortcutsRegistry::deactivateShortcuts(bool temporarily) + { + Q_FOREACH (KdeDGlobalAccel::Component *component, _components) + { + component->deactivateShortcuts(temporarily); + } + } + + +GlobalShortcut *GlobalShortcutsRegistry::getActiveShortcutByKey(int key) const + { + return _active_keys.value(key); + } + + +KdeDGlobalAccel::Component *GlobalShortcutsRegistry::getComponent(const QString &uniqueName) + { + return _components.value(uniqueName); + } + + +GlobalShortcut *GlobalShortcutsRegistry::getShortcutByKey(int key) const + { + Q_FOREACH (KdeDGlobalAccel::Component *component, _components) + { + GlobalShortcut *rc = component->getShortcutByKey(key); + if (rc) return rc; + } + return NULL; + } + + +QList GlobalShortcutsRegistry::getShortcutsByKey(int key) const + { + QList rc; + + Q_FOREACH (KdeDGlobalAccel::Component *component, _components) + { + rc = component->getShortcutsByKey(key); + if (!rc.isEmpty()) return rc; + } + return rc; + } + + +bool GlobalShortcutsRegistry::isShortcutAvailable( + int shortcut, + const QString &componentName, + const QString &contextName) const + { + Q_FOREACH (KdeDGlobalAccel::Component *component, _components) + { + if (!component->isShortcutAvailable(shortcut, componentName, contextName)) + return false; + } + return true; + } + + +GlobalShortcutsRegistry * GlobalShortcutsRegistry::self() + { + K_GLOBAL_STATIC( GlobalShortcutsRegistry, self ); + return self; + } + + +bool GlobalShortcutsRegistry::keyPressed(int keyQt) + { + GlobalShortcut *shortcut = getShortcutByKey(keyQt); + if (!shortcut) + { + // This can happen for example with the ALT-Print shortcut of kwin. + // ALT+PRINT is SYSREQ on my keyboard. So we grab something we think + // is ALT+PRINT but symXToKeyQt and modXToQt make ALT+SYSREQ of it + // when pressed (correctly). We can't match that. + kDebug() << "Got unknown key" << QKeySequence(keyQt).toString(); + + // In production mode just do nothing. + return false; + } + else if (!shortcut->isActive()) + { + kDebug() << "Got inactive key" << QKeySequence(keyQt).toString(); + + // In production mode just do nothing. + return false; + } + + kDebug() << QKeySequence(keyQt).toString() << "=" << shortcut->uniqueName(); + + QStringList data(shortcut->context()->component()->uniqueName()); + data.append(shortcut->uniqueName()); + data.append(shortcut->context()->component()->friendlyName()); + data.append(shortcut->friendlyName()); +#ifdef Q_WS_X11 + // Make sure kglobalacceld has ungrabbed the keyboard after receiving the + // keypress, otherwise actions in application that try to grab the + // keyboard (e.g. in kwin) may fail to do so. There is still a small race + // condition with this being out-of-process. + qApp->syncX(); +#endif + + // 1st Invoke the action + shortcut->context()->component()->emitGlobalShortcutPressed( *shortcut ); + + // Then do anything else + KNotification *notification = new KNotification( + "globalshortcutpressed", + KNotification::CloseOnTimeout); + + notification->setText( + i18n("The global shortcut for %1 was issued.", shortcut->friendlyName())); + + notification->addContext( "application", shortcut->context()->component()->friendlyName() ); + + notification->sendEvent(); + + return true; +} + + +void GlobalShortcutsRegistry::loadSettings() + { + foreach (const QString &groupName, _config.groupList()) + { + kDebug() << "Loading group " << groupName; + + Q_ASSERT(groupName.indexOf('\x1d')==-1); + + // loadSettings isn't designed to be called in between. Only at the + // beginning. + Q_ASSERT(!getComponent(groupName)); + + KConfigGroup configGroup(&_config, groupName); + + // We previously stored the friendly name in a separate group. migrate + // that + QString friendlyName; + KConfigGroup friendlyGroup(&configGroup, "Friendly Name"); + if (friendlyGroup.isValid()) + { + friendlyName = friendlyGroup.readEntry("Friendly Name"); + friendlyGroup.deleteGroup(); + } + else + { + friendlyName = configGroup.readEntry("_k_friendly_name"); + } + + // Create the component + KdeDGlobalAccel::Component *component = new KdeDGlobalAccel::Component( + groupName, + friendlyName, + this); + + // Now load the contexts + Q_FOREACH(const QString& context, configGroup.groupList()) + { + // Skip the friendly name group + if (context=="Friendly Name") continue; + + KConfigGroup contextGroup(&configGroup, context); + QString contextFriendlyName = contextGroup.readEntry("_k_friendly_name"); + component->createGlobalShortcutContext(context, contextFriendlyName); + component->activateGlobalShortcutContext(context); + component->loadSettings(contextGroup); + } + + // Load the default context + component->activateGlobalShortcutContext("default"); + component->loadSettings(configGroup); + } + } + + +void GlobalShortcutsRegistry::grabKeys() + { + activateShortcuts(); + } + + +bool GlobalShortcutsRegistry::registerKey(int key, GlobalShortcut *shortcut) + { + if (key == 0) + { + kDebug() << shortcut->uniqueName() << ": Key '" << QKeySequence(key).toString() + << "' already taken by " << _active_keys.value(key)->uniqueName() << "."; + return false; + } + else if (_active_keys.value(key)) + { + kDebug() << shortcut->uniqueName() << ": Attempt to register key 0."; + return false; + } + + kDebug() << "Registering key" << QKeySequence(key).toString() << "for" + << shortcut->context()->component()->uniqueName() << ":" << shortcut->uniqueName(); + + _active_keys.insert(key, shortcut); + return _manager->grabKey(key, true); + } + + +void GlobalShortcutsRegistry::setAccelManager(KGlobalAccelImpl *manager) + { + _manager = manager; + } + + +void GlobalShortcutsRegistry::setDBusPath(const QDBusObjectPath &path) + { + _dbusPath = path; + } + + +KdeDGlobalAccel::Component *GlobalShortcutsRegistry::takeComponent(KdeDGlobalAccel::Component *component) + { + QDBusConnection conn(QDBusConnection::sessionBus()); + conn.unregisterObject(component->dbusPath().path()); + return _components.take(component->uniqueName()); + } + + +void GlobalShortcutsRegistry::ungrabKeys() + { + deactivateShortcuts(); + } + + +bool GlobalShortcutsRegistry::unregisterKey(int key, GlobalShortcut *shortcut) + { + if (_active_keys.value(key)!=shortcut) + { + // The shortcut doesn't own the key or the key isn't grabbed + return false; + } + + kDebug() << "Unregistering key" << QKeySequence(key).toString() << "for" + << shortcut->context()->component()->uniqueName() << ":" << shortcut->uniqueName(); + + _manager->grabKey(key, false); + _active_keys.take(key); + return true; + } + + +void GlobalShortcutsRegistry::writeSettings() const + { + Q_FOREACH( + const KdeDGlobalAccel::Component *component, + GlobalShortcutsRegistry::self()->allMainComponents()) + { + KConfigGroup configGroup(&_config, component->uniqueName()); + if (component->allShortcuts().isEmpty()) + { + configGroup.deleteGroup(); + delete component; + } + else + { + component->writeSettings(configGroup); + } + } + + _config.sync(); + } + + +#include "moc_globalshortcutsregistry.cpp" diff --git a/kglobalaccel/globalshortcutsregistry.h b/kglobalaccel/globalshortcutsregistry.h new file mode 100644 index 00000000..9ea2ce38 --- /dev/null +++ b/kglobalaccel/globalshortcutsregistry.h @@ -0,0 +1,169 @@ +#ifndef GLOBALSHORTCUTSREGISTRY_H +#define GLOBALSHORTCUTSREGISTRY_H +/* Copyright (C) 2008 Michael Jansen + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "ksharedconfig.h" + +#include +#include +#include + + +class GlobalShortcut; +class KGlobalAccelImpl; + +namespace KdeDGlobalAccel + { + class Component; + } + +/** + * Global Shortcut Registry. + * + * Shortcuts are registered by component. A component is for example kmail or + * amarok. + * + * A component can have contexts. Currently on plasma is planned to support + * that feature. A context enables plasma to keep track of global shortcut + * settings when switching containments. + * + * A shortcut (WIN+x) can be registered by one component only. The component + * is allowed to register it more than once in different contexts. + * + * @author Michael Jansen + */ +class GlobalShortcutsRegistry : public QObject + { + Q_OBJECT + + Q_CLASSINFO("D-Bus Interface", "org.kde.KdedGlobalAccel.GlobalShortcutsRegistry") + +public: + + /** + * Activate all shortcuts having their application present. + */ + void activateShortcuts(); + + /** + * Return a list of all main components + */ + QList allMainComponents() const; + + /** + * Return the root dbus path for the registry. + */ + QDBusObjectPath dbusPath() const; + + /** + * Deactivate all currently active shortcuts. + */ + void deactivateShortcuts(bool temporarily=false); + + + /** + * Get the shortcut corresponding to key. Only active shortcut are + * considered. + */ + GlobalShortcut *getActiveShortcutByKey(int key) const; + + /** + */ + KdeDGlobalAccel::Component *getComponent(const QString &uniqueName); + + /** + * Get the shortcut corresponding to key. Active and inactive shortcuts + * are considered. But if the matching application uses contexts only one + * shortcut is returned. + * + * @see getShortcutsByKey(int key) + */ + GlobalShortcut *getShortcutByKey(int key) const; + + /** + * Get the shortcuts corresponding to key. Active and inactive shortcuts + * are considered. + * + * @see getShortcutsByKey(int key) + */ + QList getShortcutsByKey(int key) const; + + /** + * Checks if @p shortcut is available for @p component. + * + * It is available if not used by another component in any context or used + * by @p component only in not active contexts. + */ + bool isShortcutAvailable( + int shortcut, + const QString &component, + const QString &context) const; + + static GlobalShortcutsRegistry *self(); + + bool registerKey(int key, GlobalShortcut *shortcut); + + void setAccelManager(KGlobalAccelImpl *manager); + + void setDBusPath(const QDBusObjectPath &path); + + bool unregisterKey(int key, GlobalShortcut *shortcut); + +public Q_SLOTS: + + void clear(); + + void loadSettings(); + + void writeSettings() const; + + // Grab the keys + void grabKeys(); + + // Ungrab the keys + void ungrabKeys(); + +private: + + friend class KdeDGlobalAccel::Component; + friend class KGlobalAccelImpl; + + KdeDGlobalAccel::Component *addComponent(KdeDGlobalAccel::Component *component); + KdeDGlobalAccel::Component *takeComponent(KdeDGlobalAccel::Component *component); + + //called by the implementation to inform us about key presses + //returns true if the key was handled + bool keyPressed(int keyQt); + + GlobalShortcutsRegistry(); + + ~GlobalShortcutsRegistry(); + + QHash _active_keys; + QHash _components; + + KGlobalAccelImpl *_manager; + + mutable KConfig _config; + + QDBusObjectPath _dbusPath; + }; + + +#endif /* #ifndef GLOBALSHORTCUTSREGISTRY_H */ diff --git a/kglobalaccel/kconf/kdedglobalaccel_kde42.upd b/kglobalaccel/kconf/kdedglobalaccel_kde42.upd new file mode 100644 index 00000000..260434aa --- /dev/null +++ b/kglobalaccel/kconf/kdedglobalaccel_kde42.upd @@ -0,0 +1,3 @@ +Id=remove_kde_global_shortcuts +File=kglobalshortcutsrc +RemoveGroup=KDE Global Shortcuts diff --git a/kglobalaccel/kglobalaccel.desktop b/kglobalaccel/kglobalaccel.desktop new file mode 100644 index 00000000..6842a14f --- /dev/null +++ b/kglobalaccel/kglobalaccel.desktop @@ -0,0 +1,88 @@ +[Desktop Entry] +Type=Service +Icon=preferences-desktop-keyboard +Exec=kglobalaccel +X-KDE-autostart-phase=1 +X-DBUS-StartupType=Unique +X-KDE-ServiceTypes= +X-KDE-StartupNotify=false + +Name=KDED Global Shortcuts Server +Name[ar]=خادم اختصارات كدي دي العمومية +Name[ast]=Sirvidor d'accesos rápidos globales KDED +Name[be@latin]=Słužba paŭsiudnych klavijaturnych skarotaŭ dla „KDE” +Name[bg]=Сървър KDED Global Shortcuts +Name[bn]=কে.ডি.ই.ডি গ্লোবাল শর্টকাট সার্ভার +Name[bs]=KDED server globalnih prečica +Name[ca]=Servidor KDED de dreceres globals +Name[ca@valencia]=Servidor KDED de dreceres globals +Name[cs]=Server globálních klávesových zkratek KDE +Name[csb]=Globalnô serwera skrodzënów KDED +Name[da]=KDED global genvejsserver +Name[de]=KDED-Server für globale Tastenkürzel +Name[el]=Εξυπηρετητής καθολικών συντομεύσεων KDED +Name[en_GB]=KDED Global Shortcuts Server +Name[eo]=Servilo de ĉieaj fulmoklavoj de KDED +Name[es]=Servidor de accesos rápidos globales KDED +Name[et]=KDE globaalsete kiirklahvide server +Name[eu]=KDED laster-tekla globalen zerbitzaria +Name[fa]=خادم میان‌برهای سراسری KDED +Name[fi]=KDED:n työpöydänlaajuisten pikanäppäinten palvelin +Name[fr]=Serveur général de raccourcis KDED +Name[fy]=KDED globale fluchtoets tsjinnner +Name[ga]=Freastalaí Aicearraí Comhchoiteanna KDED +Name[gl]=Servidor de atallos de teclado globais de KDED +Name[gu]=KDED વૈશ્વીક ટૂંકાણો સર્વર +Name[he]=שרת קיצורי מקשים גלובליים KDED +Name[hi]=केडीईडी ग्लोबल शॉर्टकट सर्वर +Name[hne]=केडीईडी वैस्विक सार्टकट सर्वर +Name[hr]=KDED Globalni poslužitelj prečaca tipkovnice +Name[hsb]=Serwer za globalne KDE-skrótšenki +Name[hu]=KDE-szolgáltatás a globális billentyűparancsok lekérdezéséhez +Name[ia]=KDED Servitor global de vias breve +Name[id]=Server Jalan Pintas Global KDED +Name[is]=KDED víðtækur tenglaþjónn +Name[it]=Server KDED di scorciatoie globali +Name[ja]=KDED グローバルショートカットサーバ +Name[kk]=Жалпы жүйелік перне тіркесімдер KDED сервері: +Name[km]=ម៉ាស៊ីន​បម្រើ​ផ្លូវកាត់​សកល​របស់ KDED +Name[kn]=KDED ಸಾರ್ವತ್ರಿಕ ಶೀರ್ಘ್ರಮಾರ್ಗಗಳ (ಶಾರ್ಟ್-ಕಟ್) ಪರಿಚಾರಕ +Name[ko]=KDED 전역 단축키 서버 +Name[ku]=KDED Pêşkêşkera Kurterê yên Giştî +Name[lt]=KDED globalinių trumpių serveris +Name[lv]=KDED globālo īsceļu serveris +Name[mai]=केडीईडी ग्लोबल शॉर्टकट सर्वर +Name[mk]=KDED сервер за глобални кратенки +Name[ml]=കെഡിഇഡി ആഗോള കുറക്കുവഴികള്‍ സെര്‍വര്‍ +Name[mr]=केडीईD जागतिक शॉर्टकट सर्व्हर +Name[nb]=KDED-tjener for globale snarveier +Name[nds]=KDED-Tastkombinatschonen-Server +Name[nl]=KDED globale-sneltoetsen-server +Name[nn]=KDED-tenar for globale snøggtastar +Name[or]=KDED ଜାଗତିକ ସଂକ୍ଷିପ୍ତ ପଥଗୁଡ଼ିକର ସର୍ଭର +Name[pa]=KDED ਗਲੋਬਲ ਸ਼ਾਰਟਕੱਟ ਸਰਵਰ +Name[pl]=Globalny serwer skrótów KDED +Name[pt]=Servidor de Atalhos Globais do KDED +Name[pt_BR]=Servidor de atalhos globais do KDED +Name[ro]=Server de scurtături globale KDED +Name[ru]=Поддержка глобальных комбинаций клавиш +Name[se]=KDED-bálvá globála njuolggobálgáid várás +Name[si]=KDED විශ්ව කෙටිමං ධාරකය +Name[sk]=KDED server globálnych skratiek +Name[sl]=Strežnik KDED za globalne bližnjice +Name[sr]=КДЕД сервер глобалних пречица +Name[sr@ijekavian]=КДЕД сервер глобалних пречица +Name[sr@ijekavianlatin]=KDED server globalnih prečica +Name[sr@latin]=KDED server globalnih prečica +Name[sv]=KDED global snabbtangentserver +Name[ta]=KDED பொது சுருக்குவழி வழங்கி +Name[tg]=Сервери умумии миёнбурҳои KDED +Name[th]=แม่ข่าย KDED บริการปุ่มพิมพ์ลัดส่วนรวม +Name[tr]=KDED Genel Kısayol Sunucusu +Name[ug]=KDED ئومۇمىيەت تېزلەتمە مۇلازىمېتىرى +Name[uk]=Сервер загальних клавіатурних скорочень KDED +Name[vi]=Máy chủ phím tắt hệ thống KDED +Name[wa]=Sierveu des rascourtis globås po KDED +Name[x-test]=xxKDED Global Shortcuts Serverxx +Name[zh_CN]=KDED 全局快捷键服务器 +Name[zh_TW]=KDED 全域鍵盤捷徑 diff --git a/kglobalaccel/kglobalaccel.notifyrc b/kglobalaccel/kglobalaccel.notifyrc new file mode 100644 index 00000000..057130bb --- /dev/null +++ b/kglobalaccel/kglobalaccel.notifyrc @@ -0,0 +1,595 @@ +[Global] +IconName=preferences-desktop-keyboard +Comment=Global Keyboard Shortcuts +Comment[ar]=اختصارات لوحة المفاتيح العمومية +Comment[ast]=Accesos rápidos de tecláu globales +Comment[bg]=Глобални бързи клавиши +Comment[bn]=গ্লোবাল কীবোর্ড শর্টকাট +Comment[bs]=Globalne prečice sa tastature +Comment[ca]=Dreceres de teclat globals +Comment[ca@valencia]=Dreceres de teclat globals +Comment[cs]=Globální klávesové zkratky +Comment[da]=Globale tastaturgenveje +Comment[de]=Globale Kurzbefehle +Comment[el]=Καθολικές συντομεύσεις πληκτρολογίου +Comment[en_GB]=Global Keyboard Shortcuts +Comment[eo]=Ĉieaj fulmoklavoj +Comment[es]=Accesos rápidos de teclado globales +Comment[et]=Globaalsed kiirklahvid +Comment[eu]=Laster-tekla globalak +Comment[fa]=میان‌برهای صفحه‌ کلید سراسری +Comment[fi]=Työpöydänlaajuiset pikanäppäimet +Comment[fr]=Raccourcis clavier globaux +Comment[ga]=Aicearraí Comhchoiteanna Méarchláir +Comment[gl]=Atallos de teclado globais +Comment[gu]=વૈશ્વિક કીબોર્ડ ટૂંકાણો +Comment[he]=קיצורי מקלדת גלובליים +Comment[hi]=वैश्विक कुंजीपट शॉर्टकट +Comment[hr]=Globalni tipkovnički prečaci +Comment[hu]=Globális billentyűparancsok +Comment[ia]=Vias breve de claviero global +Comment[id]=Jalan Pintas Papan Ketik Global +Comment[is]=Víðværir flýtilyklar +Comment[it]=Scorciatoie globali della tastiera +Comment[ja]=グローバルキーボードショートカット +Comment[kk]=Жалпы жүйелік перне тіркесімдер +Comment[km]=ផ្លូវកាត់​ក្ដារចចុ​សកល +Comment[kn]=ಸಾರ್ವತ್ರಿಕ ಕೀಲಿಮಣೆ ಶೀಘ್ರಮಾರ್ಗಗಳು (ಶಾರ್ಟ್ ಕಟ್) +Comment[ko]=전역 키보드 단축키 +Comment[lt]=Globalieji spartieji klavišai +Comment[lv]=Globālie tastatūras īsceļi +Comment[mai]=वैश्विक कुंजीपटल शार्टकट +Comment[ml]=ആഗോളമായ കീബോര്‍ഡിലെ കുറക്കുവഴികള്‍ +Comment[mr]=जागतिक कळफलक शॉर्टकट +Comment[nb]=Globale hurtigtaster +Comment[nds]=Globaal Tastkombinatschonen +Comment[nl]=Globale sneltoetsen +Comment[nn]=Globale snøggtastar +Comment[pa]=ਗਲੋਬਲ ਕੀ-ਬੋਰਡ ਸ਼ਾਰਟਕੱਟ +Comment[pl]=Globalne skróty klawiszowe +Comment[pt]=Atalhos Globais do Teclado +Comment[pt_BR]=Atalhos de teclado globais +Comment[ro]=Acceleratori de tastatură globali +Comment[ru]=Глобальные комбинации клавиш +Comment[si]=ගෝලීය යතුරුපුවරු කෙටිමං +Comment[sk]=Globálne klávesové skratky +Comment[sl]=Globalne tipkovne bližnjice +Comment[sr]=Глобалне пречице са тастатуре +Comment[sr@ijekavian]=Глобалне пречице са тастатуре +Comment[sr@ijekavianlatin]=Globalne prečice sa tastature +Comment[sr@latin]=Globalne prečice sa tastature +Comment[sv]=Globala snabbtangenter +Comment[tg]=Миёнбурҳои умумии клавиатура +Comment[th]=ปุ่มพิมพ์ลัดใช้งานส่วนรวม +Comment[tr]=Genel Klavye Kısayolları +Comment[ug]=ئومۇمىيەت ھەرپتاختا تېزلەتمىسى +Comment[uk]=Загальні клавіатурні скорочення +Comment[vi]=Phím tắt hệ thống +Comment[wa]=Rascourtis del taprece po ttavå +Comment[x-test]=xxGlobal Keyboard Shortcutsxx +Comment[zh_CN]=全局键盘快捷键 +Comment[zh_TW]=全域鍵盤捷徑 +Name=kglobalaccel +Name[ar]=kglobalaccel +Name[ast]=kglobalaccel +Name[bg]=kglobalaccel +Name[bn]=kglobalaccel +Name[bs]=K‑globalne-prečice +Name[ca]=kglobalaccel +Name[ca@valencia]=kglobalaccel +Name[cs]=kglobalaccel +Name[csb]=kglobalaccel +Name[da]=kglobalaccel +Name[de]=kglobalaccel +Name[el]=kglobalaccel +Name[en_GB]=kglobalaccel +Name[eo]=kglobalaccel +Name[es]=kglobalaccel +Name[et]=kglobalaccel +Name[eu]=kglobalaccel +Name[fa]=kglobalaccel +Name[fi]=kglobalaccel +Name[fr]=kglobalaccel +Name[fy]=kglobalaccel +Name[ga]=kglobalaccel +Name[gl]=kglobalaccel +Name[gu]=kglobalaccel +Name[he]=kglobalaccel +Name[hi]=kglobalaccel +Name[hr]=kglobalaccel +Name[hu]=kglobalaccel +Name[ia]=kglobalaccel +Name[id]=kglobalaccel +Name[is]=kglobalaccel +Name[it]=kglobalaccel +Name[ja]=kglobalaccel +Name[ka]=kglobalaccel +Name[kk]=kglobalaccel +Name[km]=kglobalaccel +Name[kn]=kglobalaccel +Name[ko]=kglobalaccel +Name[lt]=kglobalaccel +Name[lv]=kglobalaccel +Name[mai]=kglobalaccel +Name[mk]=kglobalaccel +Name[ml]=കെആഗൊളആക്സല്‍ +Name[mr]=kglobalaccel +Name[nb]=kglobalaccel +Name[nds]=kglobalaccel +Name[nl]=kglobalaccel +Name[nn]=kglobalaccel +Name[pa]=kglobalaccel +Name[pl]=kglobalaccel +Name[pt]=kglobalaccel +Name[pt_BR]=kglobalaccel +Name[ro]=kglobalaccel +Name[ru]=kglobalaccel +Name[si]=kglobalaccel +Name[sk]=kglobalaccel +Name[sl]=kglobalaccel +Name[sr]=К‑глобалне-пречице +Name[sr@ijekavian]=К‑глобалне-пречице +Name[sr@ijekavianlatin]=K‑globalne-prečice +Name[sr@latin]=K‑globalne-prečice +Name[sv]=Kglobalsnabbtangent +Name[tg]=kglobalaccel +Name[th]=kglobalaccel +Name[tr]=kglobalaccel +Name[ug]=kglobalaccel +Name[uk]=kglobalaccel +Name[vi]=kglobalaccel +Name[wa]=kglobalaccel +Name[x-test]=xxkglobalaccelxx +Name[zh_CN]=kglobalaccel +Name[zh_TW]=kglobalaccel + +[Context/Application] +Name=Application +Name[ar]=تطبيق +Name[as]=অনুপ্ৰয়োগ +Name[ast]=Aplicación +Name[be@latin]=Aplikacyja +Name[bg]=Програма +Name[bn]=অ্যাপলিকেশন +Name[bn_IN]=অ্যাপ্লিকেশন +Name[bs]=Program +Name[ca]=Aplicació +Name[ca@valencia]=Aplicació +Name[cs]=Aplikace +Name[csb]=Programa +Name[da]=Program +Name[de]=Programm +Name[el]=Εφαρμογή +Name[en_GB]=Application +Name[eo]=Aplikaĵo +Name[es]=Aplicación +Name[et]=Rakendus +Name[eu]=Aplikazioa +Name[fa]=برنامه +Name[fi]=Sovellus +Name[fr]=Application +Name[fy]=Applikaasje +Name[ga]=Feidhmchlár +Name[gl]=Programa +Name[gu]=કાર્યક્રમ +Name[he]=יישום +Name[hi]=अनुप्रयोग +Name[hne]=अनुपरयोग +Name[hr]=Aplikacija +Name[hsb]=Aplikacija +Name[hu]=Alkalmazás +Name[ia]=Application +Name[id]=Aplikasi +Name[is]=Forrit +Name[it]=Applicazione +Name[ja]=アプリケーション +Name[kk]=Қолданба +Name[km]=កម្មវិធី +Name[kn]=ಅನ್ವಯ +Name[ko]=프로그램 +Name[ku]=Sepan +Name[lt]=Programa +Name[lv]=Programma +Name[mai]=अनुप्रयोग +Name[mk]=Апликација +Name[ml]=പ്രയോഗം +Name[mr]=अनुप्रयोग +Name[nb]=Program +Name[nds]=Programm +Name[nl]=Programma +Name[nn]=Program +Name[or]=ପ୍ରୟୋଗ +Name[pa]=ਐਪਲੀਕੇਸ਼ਨ +Name[pl]=Program +Name[pt]=Aplicação +Name[pt_BR]=Aplicativo +Name[ro]=Aplicație +Name[ru]=Приложение +Name[si]=යෙදුම් +Name[sk]=Aplikácia +Name[sl]=Program +Name[sr]=Програм +Name[sr@ijekavian]=Програм +Name[sr@ijekavianlatin]=Program +Name[sr@latin]=Program +Name[sv]=Program +Name[ta]=பயன்பாடுகள் +Name[te]=అనువర్తనము +Name[tg]=Барнома +Name[th]=โปรแกรม +Name[tr]=Uygulama +Name[ug]=پروگرامما +Name[uk]=Програма +Name[uz]=Dastur +Name[uz@cyrillic]=Дастур +Name[vi]=Ứng dụng +Name[wa]=Programe +Name[x-test]=xxApplicationxx +Name[zh_CN]=应用程序 +Name[zh_TW]=應用程式 +Comment=The application name +Comment[ar]=اسم التطبيق +Comment[ast]=Nome de l'aplicación +Comment[bg]=Име на програма +Comment[bn]=অ্যাপলিকেশন-এর নাম +Comment[bs]=Ime programa +Comment[ca]=El nom de l'aplicació +Comment[ca@valencia]=El nom de l'aplicació +Comment[cs]=Název aplikace +Comment[csb]=Miono aplikacëji +Comment[da]=Programnavnet +Comment[de]=Der Name der Anwendung +Comment[el]=Το όνομα εφαρμογής +Comment[en_GB]=The application name +Comment[eo]=La nomo de aplikaĵo +Comment[es]=Nombre de la aplicación +Comment[et]=Rakenduse nimi +Comment[eu]=Aplikazioaren izena +Comment[fa]=نام برنامه +Comment[fi]=Sovelluksen nimi +Comment[fr]=Le nom de l'application +Comment[fy]=De applikaasje namme +Comment[ga]=Ainm an fheidhmchláir +Comment[gl]=O nome do programa +Comment[gu]=કાર્યક્રમ નામ +Comment[he]=שם היישום +Comment[hi]=अनुप्रयोग नाम +Comment[hr]=Ime aplikacije +Comment[hu]=Alkalmazásnév +Comment[ia]=Le nomine de application +Comment[id]=Nama aplikasi +Comment[is]=Heiti forrits +Comment[it]=Il nome dell'applicazione +Comment[ja]=アプリケーションの名前 +Comment[kk]=Қолданбаның атауы +Comment[km]=ឈ្មោះ​កម្មវិធី​ +Comment[kn]=ಅನ್ವಯದ ಹೆಸರು +Comment[ko]=프로그램 이름 +Comment[lt]=Programos pavadinimas +Comment[lv]=Programmas nosaukums +Comment[mai]=अनुप्रयोगक नाम +Comment[mk]=Името на апликацијата +Comment[ml]=പ്രയോഗത്തിന്റെ പേരു് +Comment[mr]=अनुप्रयोगाचे नाव +Comment[nb]=Programnavnet +Comment[nds]=De Programmnaam +Comment[nl]=De programmanaam +Comment[nn]=Programnamnet +Comment[pa]=ਐਪਲੀਕੇਸ਼ਨ ਨਾਂ +Comment[pl]=Nazwa programu +Comment[pt]=O nome da aplicação +Comment[pt_BR]=O nome do aplicativo +Comment[ro]=Denumirea aplicației +Comment[ru]=Имя приложения +Comment[si]=යෙදුම් නාමය +Comment[sk]=Názov aplikácie +Comment[sl]=Ime programa +Comment[sr]=Име програма +Comment[sr@ijekavian]=Име програма +Comment[sr@ijekavianlatin]=Ime programa +Comment[sr@latin]=Ime programa +Comment[sv]=Programnamnet +Comment[tg]=Номи барнома +Comment[th]=ชื่อของโปรแกรม +Comment[tr]=Uygulama adı +Comment[ug]=پروگرامما ئاتى +Comment[uk]=Назва програми +Comment[vi]=Tên ứng dụng +Comment[wa]=Li no do programe +Comment[x-test]=xxThe application namexx +Comment[zh_CN]=应用程序名称 +Comment[zh_TW]=應用程式名稱 + +[Event/newshortcutregistered] +Name=Global Shortcut Registration +Name[ar]=تسجيل الاختصارات العمومية +Name[ast]=Rexistru d'accesu rápidu global +Name[bg]=Централно указване на съкратени клавиши +Name[bn]=গ্লোবাল শর্টকাট নথীভুক্তকরণ +Name[bs]=Registracija globalnih prečica +Name[ca]=Registre de drecera global +Name[ca@valencia]=Registre de drecera global +Name[cs]=Registrace globální klávesové zkratky +Name[csb]=Globalnô registracëjô skrodzënë +Name[da]=Registrering af global genvej +Name[de]=Registrierung für globale Tastenkürzel +Name[el]=Καταχώρηση καθολικών συντομεύσεων +Name[en_GB]=Global Shortcut Registration +Name[eo]=Registriĝo de ĉieaj fulmoklavoj +Name[es]=Registro de acceso rápido global +Name[et]=Globaalsete kiirklahvide registreerimine +Name[eu]=Laster-tekla globalen erregistroa +Name[fa]=ثبت میان‌برهای سراسری +Name[fi]=Työpöydänlaajuisten pikanäppäinten rekisteröinti +Name[fr]=Référencement des raccourcis globaux +Name[fy]=Globale fluchtoets registraasje +Name[ga]=Clárú Aicearraí Comhchoiteanna +Name[gl]=Rexistro de atallo global +Name[gu]=વૈશ્ર્વિક ટૂંકાણ રજીસ્ટ્રેશન +Name[he]=רישום קיצורי מקשים גלובליים +Name[hi]=केडीईडी ग्लोबल शॉर्टकट पंजीकरण +Name[hr]=Prijava globalnih prečaca tipkovnice +Name[hu]=Globális billentyűparancs regisztrálása +Name[ia]=Registration global de via breve +Name[id]=Registrasi Jalan Pintas Global +Name[is]=Víðtækur tenglaþjónn +Name[it]=Registrazione delle scorciatoie globali +Name[ja]=グローバルショートカットの登録 +Name[kk]=Жалпы жүйелік перне тіркесімі тіркелді +Name[km]=ការ​ចុះឈ្មោះ​ផ្លូវកាត់​សកល +Name[kn]=ಸಾರ್ವತ್ರಿಕ ಕೀಲಿಮಣೆ ಶೀಘ್ರಮಾರ್ಗಗಳ (ಶಾರ್ಟ್ ಕಟ್) ನೋಂದಣಿ +Name[ko]=전역 단축키 등록 +Name[lt]=KDE globaliųjų klavišų registracija +Name[lv]=Globālo īsceļu reģistrēšana +Name[mai]=ग्लोबल शॉर्टकट पंजीयन +Name[mk]=Регистрација на глобални кратенки +Name[ml]=ആഗോള കുറക്കുവഴി പേരുചേര്‍ക്കല്‍ +Name[mr]=जागतिक शॉर्टकट नोंदणी +Name[nb]=Global snarveisregistrering +Name[nds]=Globaal Tastkombinatschoon inmeldt +Name[nl]=Globale-sneltoetsen-registratie +Name[nn]=Registrering av globale snøggtastar +Name[pa]=ਗਲੋਬਲ ਸ਼ਾਰਟਕੱਟ ਰਜਿਸਟਰੇਸ਼ਨ +Name[pl]=Rejestracja globalnego skrótu +Name[pt]=Registo de Atalhos Globais +Name[pt_BR]=Registro de atalhos globais +Name[ro]=Înregistrare acceleratori globali +Name[ru]=Регистрация глобальных комбинаций клавиш +Name[si]=ගෝලීය කෙටිමං ලියාපදිංචිය +Name[sk]=Registrácia globálnej skratky +Name[sl]=Registracija globalne bližnjice +Name[sr]=Регистрација глобалних пречица +Name[sr@ijekavian]=Регистрација глобалних пречица +Name[sr@ijekavianlatin]=Registracija globalnih prečica +Name[sr@latin]=Registracija globalnih prečica +Name[sv]=Registrering av globala snabbtangenter +Name[tg]=Қайдкунии миёнбурҳои умумӣ +Name[th]=การลงทะเบียนปุ่มพิมพ์ลัดใช้งานส่วนรวม +Name[tr]=Genel Kısayol Kaydı +Name[ug]=ئومۇمىيەت تېزلەتمە خەتلىتىش +Name[uk]=Реєстрація загальних скорочень +Name[vi]=Đăng ký phím tắt hệ thống +Name[wa]=Rashiaedje do rascourti po ttavå +Name[x-test]=xxGlobal Shortcut Registrationxx +Name[zh_CN]=全局快捷键注册 +Name[zh_TW]=全域捷徑註冊 +Comment=An application registered new global shortcuts. +Comment[ar]=تطبيق مسجل اختصارات عمومية جديدة. +Comment[ast]=Una aplicación rexistró nuevos accesos rápidos globales. +Comment[bg]=Програма регистрира нови общи бързи клавиши. +Comment[bn]=একটি অ্যাপলিকেশন নতুন গ্লোবাল শর্টকাট নথীভুক্ত করেছে। +Comment[bs]=Program je registrovao nove globalne prečice. +Comment[ca]=Una aplicació ha registrat dreceres globals noves. +Comment[ca@valencia]=Una aplicació ha registrat dreceres globals noves. +Comment[cs]=Aplikace zaregistrovala nové globální klávesové zkratky. +Comment[csb]=Aplikacëjô zaregistrowa nową globalną skrodzënã. +Comment[da]=Et program registrerede nye globale genveje. +Comment[de]=Eine Anwendung hat neue globale Tastenkürzel definiert. +Comment[el]=Μια εφαρμογή καταχώρησε νέες καθολικές συντομεύσεις +Comment[en_GB]=An application registered new global shortcuts. +Comment[eo]=Aplikaĵo registris novajn ĉieajn klavkombinojn. +Comment[es]=Una aplicación ha registrado nuevos accesos rápidos globales. +Comment[et]=Rakendus registreeris uued globaalsed kiirklahvid. +Comment[eu]=Aplikazio batek laster-tekla global berriak erregistratu ditu. +Comment[fa]=برنامه‌ای میانبر سراسری جدیدی را ثبت کرد. +Comment[fi]=Sovellus rekisteröi uusia työpöydänlaajuisia pikanäppäimiä. +Comment[fr]=Une application a référencé un nouveau raccourci global. +Comment[fy]=In applikaasje registrearre nije globale fluchtoetsen. +Comment[ga]=Chláraigh feidhmchlár aicearraí nua comhchoiteanna. +Comment[gl]=Un programa rexistrou novos atallos globais. +Comment[gu]=કાર્યક્રમે નવી વૈશ્વિક ટૂંકાણ નોધણી કરી છે. +Comment[he]=יישום רשם קיצורי דרך גלובאלי חדש. +Comment[hi]=अनुप्रयोग नया वैश्विक शॉर्टकट पंजीकृत किया. +Comment[hr]=Aplikacija je prijavila nove globalne prečace. +Comment[hu]=Egy alkalmazás új globális billentyűparancsokat regisztrált. +Comment[ia]=Un application registrava nove vias breve global. +Comment[id]=Sebuah aplikasi yang mendaftarkan jalan pintas global baru. +Comment[is]=Forrit skráði nýja víðværa flýtilykla. +Comment[it]=Un'applicazione ha registrato nuove scorciatoie globali. +Comment[ja]=アプリケーションがグローバルショートカットを登録しました。 +Comment[kk]=Қолданба жалпы жүйелік перне тіркесімін тіркеді +Comment[km]=កម្មវិធី​ដែលបាន​ចុះឈ្មោះ​​ផ្លូវកាត់​សកល​ថ្មី +Comment[kn]=ಒಂದು ಅನ್ವಯವು ಹೊಸ ಸಾರ್ವತ್ರಿಕ ಶೀಘ್ರಮಾರ್ಗ(ಶಾರ್ಟ್ ಕಟ್)ಗಳನ್ನು ನೋಂದಾಯಿಸಿದೆ. +Comment[ko]=프로그램에서 전역 단축키를 등록했습니다. +Comment[lt]=Programa užregistravo naujus globalius sparčiuosius klavišus. +Comment[lv]=Programma reģistrēja jaunus globālos īsceļus. +Comment[mk]=Некоја апликација регистрираше нови глобални кратенки. +Comment[ml]=ഒരു പ്രയോഗം പുതിയ ആഗോള കുറക്കുവഴികളില്‍ പേരു് ചേര്‍ത്തു +Comment[mr]=एका अनुप्रयोगाने नवीन जागतिक शॉर्टकटची नोंदणी केली. +Comment[nb]=Et program registrerte nye globale snarveier. +Comment[nds]=En Programm hett niege globale Tastkombinatschonen inmeldt. +Comment[nl]=Een programma heeft nieuwe globale sneltoetsen geregistreerd. +Comment[nn]=Eit program registrerte nye globale snøggtastar. +Comment[pa]=ਐਪਲੀਕੇਸ਼ਨ ਨੇ ਨਵਾਂ ਗਲੋਬਲ ਸ਼ਾਰਟਕੱਟ ਰਜਿਸਟਰ ਕੀਤਾ ਹੈ। +Comment[pl]=Program zarejestrował nowe globalne skróty. +Comment[pt]=Uma aplicação registou novos atalhos globais. +Comment[pt_BR]=Um aplicativo registrou novos atalhos globais. +Comment[ro]=O aplicație a înregistrat acceleratori globali noi. +Comment[ru]=Приложение добавило новые глобальные комбинации клавиш. +Comment[si]=නව විශ්ව කෙටිමං ලියාපදිංචි කල භාවිතයෙදවුම +Comment[sk]=Aplikácia zaregistrovala nové globálne skratky. +Comment[sl]=Program je registriral nove globalne bližnjice. +Comment[sr]=Програм је регистровао нове глобалне пречице. +Comment[sr@ijekavian]=Програм је регистровао нове глобалне пречице. +Comment[sr@ijekavianlatin]=Program je registrovao nove globalne prečice. +Comment[sr@latin]=Program je registrovao nove globalne prečice. +Comment[sv]=Ett program registrerade nya globala snabbtangenter. +Comment[tg]=Барнома миёнбурҳои умумии навро қайд кард. +Comment[th]=โปรแกรมได้ทำการลงทะเบียนปุ่มพิมพ์ลัดใช้งานส่วนรวม +Comment[tr]=Bir uygulama yeni bir genel kısayol kaydetti. +Comment[ug]=بىر پروگرامما يېڭىدىن ئومۇمىيەت تېزلەتمىلىرىنى خەتلەتتى. +Comment[uk]=Програма зареєструвала нові загальні скорочення. +Comment[vi]=Một ứng dụng đã đăng ký phím tắt hệ thống mới. +Comment[wa]=On programe a eredjistré des noveas rascourtis globås. +Comment[x-test]=xxAn application registered new global shortcuts.xx +Comment[zh_CN]=用于注册新全局快捷键的应用程序。 +Comment[zh_TW]=一個應用程式註冊了新的全域捷徑 +Contexts=Application +Action= + +[Event/globalshortcutpressed] +Name=Global Shortcut Triggered +Name[ar]=تم إطلاق اختصار عمومي +Name[ast]=Activación d'accesu rápidu global +Name[bg]=Задействан е общ бърз клавиш +Name[bn]=গ্লোবাল শর্টকাট ব্যবহৃত হয়েছে +Name[bs]=Okinuta globalna prečica +Name[ca]=Activació de drecera global +Name[ca@valencia]=Activació de drecera global +Name[cs]=Aktivována globální klávesová zkratka +Name[csb]=Zrëszonô globalnô skrodzëna +Name[da]=Global genvej udløst +Name[de]=Globales Tastenkürzel ausgelöst +Name[el]=Ενεργοποίηση καθολικών συντομεύσεων +Name[en_GB]=Global Shortcut Triggered +Name[eo]=Ĉiea fulmoklavo ekagigita +Name[es]=Activación de acceso rápido global +Name[et]=Kasutati globaalset kiirklahvi +Name[eu]=Laster-tekla globalak abiarazita +Name[fa]=میان‌برهای سراسری شروع به کار کردند +Name[fi]=Työpöydänlaajuinen pikanäppäin laukaistu +Name[fr]=Raccourci global déclenché +Name[fy]=Globale fluchtoets aktivearre +Name[ga]=Gníomhachtaíodh Aicearra Comhchoiteann +Name[gl]=Iniciouse un atallo de teclado global +Name[gu]=વૈશ્વીક ટૂંકાણો શરુ કરવામાં આવ્યા +Name[he]=קיצור מקשים גלובלי הופעל +Name[hi]=वैश्विक शॉर्टकट ट्रिगर किया गया +Name[hr]=Globalni prečac je korišten +Name[hu]=Globális billentyűparancs aktiválódott +Name[ia]=Via breve global discatenate +Name[id]=Jalan Pintas Global Dipicu +Name[is]=Víðvær flýtilykill var ræstur +Name[it]=Scorciatoia globale attivata +Name[ja]=グローバルショートカットの使用 +Name[kk]=Жалпы жүйелік перне тіркесімі жұмсалды +Name[km]=បានកេះ​ផ្លូវកាត់​សកល +Name[kn]=ಸಾರ್ವತ್ರಿಕ ಕೀಲಿಮಣೆ ಶೀಘ್ರಮಾರ್ಗ (ಶಾರ್ಟ್ ಕಟ್) ಪ್ರಚೋದಿಸಲ್ಪಟ್ಟಿದೆ +Name[ko]=전역 단축키 눌림 +Name[lt]=Sužadinti globalieji spartieji klavišai +Name[lv]=Globālais īsceļš nospiests +Name[mai]=ग्लोबल शॉर्टकट ट्रिगर कएल गेल +Name[mk]=Активирана е глобална кратенка +Name[ml]=ആഗോള കുറക്കുവഴി തുടങ്ങി +Name[mr]=जागतिक शॉर्टकट सुरु केला +Name[nb]=Global snarvei utløst +Name[nds]=Globaal Tastkombinatschoon utlööst +Name[nl]=Globale sneltoetsen geactiveerd +Name[nn]=Global snøggtast utløyst +Name[pa]=ਗਲੋਬਲ ਸ਼ਾਰਟਕੱਟ ਟਰਿੱਗਰ +Name[pl]=Użyto globalnego skrótu +Name[pt]=Atalho Global Despoletado +Name[pt_BR]=Atalhos globais ativados +Name[ro]=Accelerator global declanșat +Name[ru]=Нажата глобальная комбинация клавиш +Name[si]=ගෝලීය කෙටිමං ක්‍රියාරම්භ කරන ලදි +Name[sk]=Aktivovaná globálna skratka +Name[sl]=Sprožena globalna bližnjica +Name[sr]=Окинута глобална пречица +Name[sr@ijekavian]=Окинута глобална пречица +Name[sr@ijekavianlatin]=Okinuta globalna prečica +Name[sr@latin]=Okinuta globalna prečica +Name[sv]=Global snabbtangent aktiverad +Name[tg]=Миёнбурҳои умумии корандоз +Name[th]=มีการเรียกใช้ปุ่มพิมพ์ลัดใช้งานส่วนรวม +Name[tr]=Genel Kısayol Tetiklendi +Name[ug]=ئومۇمىي تېزلەتمىگە چېقىلدى +Name[uk]=Використано загальне скорочення +Name[vi]=Phím tắt hệ thống đã bật +Name[wa]=Rascourti po ttavå eclitchî +Name[x-test]=xxGlobal Shortcut Triggeredxx +Name[zh_CN]=全局快捷键被触发 +Name[zh_TW]=全域捷徑被觸發 +Comment=The user triggered a global shortcut +Comment[ar]=المستخدم أطلق اختصاراً عمومياً +Comment[ast]=L'usuariu activó un accesu rápidu global +Comment[bg]=Потребителят задейства общ бърз клавиш +Comment[bn]=একটি গ্লোবাল শর্টকাট ব্যবহার করা হয়েছে +Comment[bs]=Korisnik je okinuo globalnu prečicu +Comment[ca]=L'usuari ha activat una drecera global +Comment[ca@valencia]=L'usuari ha activat una drecera global +Comment[cs]=Uživatel aktivoval globální klávesovou zkratku +Comment[csb]=Brëkòwnik zrëszëł globalną skrodzënã +Comment[da]=Brugeren udløste en global genvej +Comment[de]=Der Benutzer hat ein globales Tastenkürzel ausgelöst. +Comment[el]=Ο χρήστης ενεργοποίησε μία καθολική συντόμευση +Comment[en_GB]=The user triggered a global shortcut +Comment[eo]=La uzanto ekagigis ĉiean klavkombinon +Comment[es]=El usuario ha activado un acceso rápido global +Comment[et]=Kasutaja kasutas globaalset kiirklahvi +Comment[eu]=Erabiltzaileak laster-tekla global bat abiarazi du +Comment[fa]=کاربر یک میانبر سراسری را راه اندازی کرد +Comment[fi]=Käyttäjän laukaisema työpöydänlaajuinen pikanäppäin +Comment[fr]=L'utilisateur a déclenché un raccourci global +Comment[fy]=De brûker hat in globale fluchtoets aktivearre +Comment[ga]=Ghníomhachtaigh an t-úsáideoir aicearra comhchoiteann +Comment[gl]=O usuario iniciou un atallo global +Comment[gu]=વપરાશકર્તાએ વૈશ્વિક જોડાણો શરુ કર્યા +Comment[he]=המשתמש הפעיל קיצור מקשים גלובאלי +Comment[hi]=उपयोगकर्ता एक वैश्विक शॉर्टकट को ट्रिगर किया +Comment[hr]=Korisnik je koristio globalni prečac +Comment[hu]=A felhasználó elvégzett egy globális billentyűparancsot +Comment[ia]=Le usator discatenava un via breve global +Comment[id]=Pengguna memicu jalan pintas global +Comment[is]=Notandinn ræsti víðværan flýtilykil +Comment[it]=L'utente ha attivato una scorciatoia globale +Comment[ja]=グローバルショートカットが使用されました。 +Comment[kk]=Пайдаланушы жалпы жүйелік перне тіркесімді жұмсады +Comment[km]=អ្នក​ប្រើ​បានកេះ​ផ្លូវកាត់​សកល +Comment[kn]=ಬಳಕೆದಾರನು ಒಂದು ಸಾರ್ವತ್ರಿಕ ಶೀಘ್ರಮಾರ್ಗ(ಶಾರ್ಟ್ ಕಟ್) ವನ್ನು ಪ್ರಚೋದಿಸಿದ್ದಾನೆ +Comment[ko]=사용자가 전역 단축키를 누름 +Comment[lt]=Naudotojas sužadino globalųjį spartųjį klavišą +Comment[lv]=Lietotājs nospieda globālo īsceļu +Comment[mk]=Корисникот активираше глобална кратенка +Comment[ml]=ഉപയോക്താവ് ഒരു ആഗോള കുറക്കുവഴി ഉപയോഗിച്ചു +Comment[mr]=वापरकर्त्याने जागतिक शॉर्टकट सुरु केला +Comment[nb]=Brukeren utløste en global snarvei +Comment[nds]=De Bruker hett en globaal Tastkombinatschoon utlööst +Comment[nl]=De gebruiker heeft een globale sneltoets geactiveerd +Comment[nn]=Brukaren utløyste ein global snøggtast +Comment[pa]=ਯੂਜ਼ਰ ਨੇ ਗਲੋਬਲ ਸ਼ਾਰਟਕੱਟ ਬਦਲਿਆ +Comment[pl]=Użytkownik skorzystał z globalnego skrótu +Comment[pt]=O utilizador despoletou um atalho global +Comment[pt_BR]=O usuário ativou um atalho global +Comment[ro]=Utilizatorul a declanșat un accelerator global +Comment[ru]=Пользователь нажал глобальную комбинацию клавиш +Comment[si]=සැකසූ විශ්ව කෙටිමඟ භාවිත කරන්න +Comment[sk]=Užívateľ aktivoval globálnu skratku +Comment[sl]=Uporabnik je sprožil globalno bližnjico +Comment[sr]=Корисник је окинуо глобалну пречицу +Comment[sr@ijekavian]=Корисник је окинуо глобалну пречицу +Comment[sr@ijekavianlatin]=Korisnik je okinuo globalnu prečicu +Comment[sr@latin]=Korisnik je okinuo globalnu prečicu +Comment[sv]=Användaren aktiverade en global snabbtangent +Comment[tg]=Корбар миёнбури умумиро таъин кард +Comment[th]=ผู้ใช้ได้ทำการเรียกใช้ปุ่มพิมพ์ลัดใช้งานส่วนรวม +Comment[tr]=Kullanıcı bir genel kısayolu tetikledi +Comment[ug]=ئىشلەتكۈچى ئومۇمىي تېزلەتمىگە چېقىلدى +Comment[uk]=Користувач використав загальне скорочення +Comment[vi]=Người dùng đã bật một phím tắt hệ thống +Comment[wa]=L' uzeu a (e/dis)clitchî on rascourti po ttavå +Comment[x-test]=xxThe user triggered a global shortcutxx +Comment[zh_CN]=用户触发了一个全局快捷键 +Comment[zh_TW]=使用者觸發了一個全域捷徑 +Contexts=Application +Action= diff --git a/kglobalaccel/kglobalaccel_mac.cpp b/kglobalaccel/kglobalaccel_mac.cpp new file mode 100644 index 00000000..17e6a6de --- /dev/null +++ b/kglobalaccel/kglobalaccel_mac.cpp @@ -0,0 +1,158 @@ +/* This file is part of the KDE libraries + Copyright (C) 2001,2002 Ellis Whitehead + Copyright (C) 2006 Marijn Kruisselbrink + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "kglobalaccel_mac.h" + +#include + +#ifdef Q_WS_MAC + +#include +#include + +#include "globalshortcutsregistry.h" +#include "kkeyserver.h" + +OSStatus hotKeyEventHandler(EventHandlerCallRef inHandlerCallRef, EventRef inEvent, void * inUserData) +{ + UInt32 eventKind = GetEventKind(inEvent); + if (eventKind == kEventRawKeyDown) { + UInt32 keycode; + if (GetEventParameter(inEvent, kEventParamKeyCode, typeUInt32, NULL, sizeof(keycode), NULL, &keycode) != noErr) { + kWarning(125) << "Error retrieving keycode parameter from event"; + } + kDebug() << " key down, keycode = " << keycode; + } else if (eventKind == kEventHotKeyPressed) { + KGlobalAccelImpl* impl = static_cast(inUserData); + EventHotKeyID hotkey; + if (GetEventParameter(inEvent, kEventParamDirectObject, typeEventHotKeyID, NULL, sizeof(hotkey), NULL, &hotkey) != noErr) { + kWarning(125) << "Error retrieving hotkey parameter from event"; + return eventNotHandledErr; + } + // Typecasts necesary to prevent a warning from gcc + return (impl->keyPressed(hotkey.id) ? (OSStatus) noErr : (OSStatus) eventNotHandledErr); + } + return eventNotHandledErr; +} + +void layoutChanged(CFNotificationCenterRef center, void *observer, CFStringRef name, const void *object, CFDictionaryRef userInfo) { + static_cast(observer)->keyboardLayoutChanged(); +} + +KGlobalAccelImpl::KGlobalAccelImpl(GlobalShortcutsRegistry* owner) + : m_owner(owner) + , m_eventTarget(GetApplicationEventTarget()) + , m_eventHandler(NewEventHandlerUPP(hotKeyEventHandler)) +{ + m_eventType[0].eventClass = kEventClassKeyboard; + m_eventType[0].eventKind = kEventHotKeyPressed; + m_eventType[1].eventClass = kEventClassKeyboard; // only useful for testing, is not used because count passed in call to InstallEventHandler is 1 + m_eventType[1].eventKind = kEventRawKeyDown; + refs = new QMap >(); + + CFStringRef str = CFStringCreateWithCString(NULL, "AppleKeyboardPreferencesChangedNotification", kCFStringEncodingASCII); + if (str) { + CFNotificationCenterAddObserver(CFNotificationCenterGetDistributedCenter(), this, layoutChanged, str, NULL, CFNotificationSuspensionBehaviorHold); + CFRelease(str); + } else { + kWarning(125) << "Couldn't create CFString to register for keyboard notifications"; + } +} + +KGlobalAccelImpl::~KGlobalAccelImpl() +{ + DisposeEventHandlerUPP(hotKeyEventHandler); + CFNotificationCenterRemoveObserver(CFNotificationCenterGetDistributedCenter(), this, NULL, NULL); + delete refs; +} + +bool KGlobalAccelImpl::grabKey( int keyQt, bool grab ) +{ + if (grab) { + kDebug() << "Grabbing key " << keyQt; + QList keyCodes; + uint mod; + KKeyServer::keyQtToCodeMac( keyQt, keyCodes ); + KKeyServer::keyQtToModMac( keyQt, mod ); + + kDebug() << "keyQt: " << keyQt << " mod: " << mod; + foreach (uint keyCode, keyCodes) { + kDebug() << " keyCode: " << keyCode; + } + + EventHotKeyID ehkid; + ehkid.signature = 'Kgai'; + ehkid.id = keyQt; + QList hotkeys; + foreach (uint keyCode, keyCodes) { + EventHotKeyRef ref; + if (RegisterEventHotKey(keyCode, mod, ehkid, m_eventTarget, 0, &ref) != noErr) { + kWarning(125) << "RegisterEventHotKey failed!"; + } + hotkeys.append(ref); + } + refs->insert(keyQt, hotkeys); + } else { + kDebug() << "Ungrabbing key " << keyQt; + if (refs->count(keyQt) == 0) kWarning(125) << "Trying to ungrab a key thas is not grabbed"; + foreach (const EventHotKeyRef &ref, refs->value(keyQt)) { + if (UnregisterEventHotKey(ref) != noErr) { + kWarning(125) << "UnregisterEventHotKey should not fail!"; + } + } + refs->remove(keyQt); + } + return true; +} + +void KGlobalAccelImpl::setEnabled(bool enable) +{ + if (enable) { + if (InstallEventHandler(m_eventTarget, m_eventHandler, 1, m_eventType, this, &m_curHandler) != noErr) + kWarning(125) << "InstallEventHandler failed!"; + } else { + if (RemoveEventHandler(m_curHandler) != noErr) + kWarning(125) << "RemoveEventHandler failed!"; + } +} + +bool KGlobalAccelImpl::keyPressed( int key ) +{ + return m_owner->keyPressed(key); +} + +void KGlobalAccelImpl::keyboardLayoutChanged() +{ + // Keyboard layout might have changed, first ungrab all keys + QList keys; // Array to store all the keys that were grabbed + while (!refs->empty()) { + int key = refs->begin().key(); + keys.append(key); + grabKey(key, false); + } + // Now re-grab all the keys + foreach (int key, keys) { + grabKey(key, true); + } +} + +#include "kglobalaccel_mac.moc" + +#endif // !Q_WS_MAC diff --git a/kglobalaccel/kglobalaccel_mac.h b/kglobalaccel/kglobalaccel_mac.h new file mode 100644 index 00000000..c36a214c --- /dev/null +++ b/kglobalaccel/kglobalaccel_mac.h @@ -0,0 +1,75 @@ +/* This file is part of the KDE libraries + Copyright (C) 2006 Marijn Kruisselbrink + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef _KGLOBALACCEL_MAC_H +#define _KGLOBALACCEL_MAC_H + +#include + +#include "kshortcut.h" +/* including kglobalaccel.h here because Carbon.h includes AssertMacros.h which + defines check(assertion) as nothing and breaks compilation */ +#include "kglobalaccel.h" + +#include + +template class QMap; +template class QList; + +class GlobalShortcutsRegistry; +class KGlobalAccelImpl: public QWidget +{ + Q_OBJECT +public: + KGlobalAccelImpl(GlobalShortcutsRegistry* owner); + ~KGlobalAccelImpl(); + +public: + /** + * This function registers or unregisters a certain key for global capture, + * depending on \b grab. + * + * Before destruction, every grabbed key will be released, so this + * object does not need to do any tracking. + * + * \param key the Qt keycode to grab or release. + * \param grab true to grab they key, false to release the key. + * + * \return true if successful, otherwise false. + */ + bool grabKey(int key, bool grab); + + /// Enable/disable all shortcuts. There will not be any grabbed shortcuts at this point. + void setEnabled(bool); + + void keyboardLayoutChanged(); +private: + friend OSStatus hotKeyEventHandler(EventHandlerCallRef inHandlerCallRef, EventRef inEvent, void * inUserData); + /// Called by the carbon event handler when a key is pressed. + bool keyPressed(int key); + + GlobalShortcutsRegistry* m_owner; + EventTargetRef m_eventTarget; + EventHandlerUPP m_eventHandler; + EventTypeSpec m_eventType[2]; + EventHandlerRef m_curHandler; + QMap >* refs; +}; + +#endif // _KGLOBALACCEL_MAC_H diff --git a/kglobalaccel/kglobalaccel_qws.cpp b/kglobalaccel/kglobalaccel_qws.cpp new file mode 100644 index 00000000..dd21e5c5 --- /dev/null +++ b/kglobalaccel/kglobalaccel_qws.cpp @@ -0,0 +1,61 @@ +/* This file is part of the KDE libraries + Copyright (C) 2001,2002 Ellis Whitehead + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "kglobalaccel_qws.h" + +#include + +#include +#ifdef Q_WS_QWS + +#include "kglobalaccel.h" + +#include +#include + +KGlobalAccelImpl::KGlobalAccelImpl(GlobalShortcutsRegistry* owner) + : m_owner(owner) +{ +} + +bool KGlobalAccelImpl::grabKey( int keyQt, bool grab ) +{ + if( !keyQt ) { + kWarning(125) << "Tried to grab key with null code."; + return false; + } + + // TODO ... + + return false; +} + +void KGlobalAccelImpl::setEnabled( bool enable ) +{ +#if 0 + if ( enable ) + kapp->installWinEventFilter( this ); + else + kapp->removeWinEventFilter( this ); +#endif +} + +#include "kglobalaccel_qws.moc" + +#endif // Q_WS_QWS diff --git a/kglobalaccel/kglobalaccel_qws.h b/kglobalaccel/kglobalaccel_qws.h new file mode 100644 index 00000000..19bb75f8 --- /dev/null +++ b/kglobalaccel/kglobalaccel_qws.h @@ -0,0 +1,62 @@ +/* This file is part of the KDE libraries + Copyright (C) 2001,2002 Ellis Whitehead + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef _KGLOBALACCEL_QWS_H +#define _KGLOBALACCEL_QWS_H + +#include + +class GlobalShortcutsRegistry; +/** + * @internal + * + * The KGlobalAccel private class handles grabbing of global keys, + * and notification of when these keys are pressed. + */ +class KGlobalAccelImpl : public QWidget +{ + Q_OBJECT + +public: + KGlobalAccelImpl(class GlobalShortcutsRegistry* owner); + +public: + /** + * This function registers or unregisters a certain key for global capture, + * depending on \b grab. + * + * Before destruction, every grabbed key will be released, so this + * object does not need to do any tracking. + * + * \param key the Qt keycode to grab or release. + * \param grab true to grab they key, false to release the key. + * + * \return true if successful, otherwise false. + */ + bool grabKey(int key, bool grab); + + /// Enable/disable all shortcuts. There will not be any grabbed shortcuts at this point. + void setEnabled(bool); + +private: + + GlobalShortcutsRegistry* m_owner; +}; + +#endif // _KGLOBALACCEL_QWS_H diff --git a/kglobalaccel/kglobalaccel_win.cpp b/kglobalaccel/kglobalaccel_win.cpp new file mode 100644 index 00000000..929961fc --- /dev/null +++ b/kglobalaccel/kglobalaccel_win.cpp @@ -0,0 +1,85 @@ +/* This file is part of the KDE libraries + Copyright (C) 2001,2002 Ellis Whitehead + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "kglobalaccel_win.h" + +#include "kkeyserver_win.h" + +#include +#ifdef Q_WS_WIN + +#include "kglobalaccel.h" +#include "globalshortcutsregistry.h" + +#include +#include + +#include + +KGlobalAccelImpl::KGlobalAccelImpl(GlobalShortcutsRegistry* owner) + : m_owner(owner), m_enabled(false) +{ +} + +bool KGlobalAccelImpl::grabKey( int keyQt, bool grab ) +{ + if( !keyQt ) { + kWarning(125) << "Tried to grab key with null code."; + return false; + } + + uint keyCodeW; + uint keyModW; + KKeyServer::keyQtToCodeWin(keyQt, &keyCodeW); + KKeyServer::keyQtToModWin(keyQt, &keyModW); + + ATOM id = GlobalAddAtom(MAKEINTATOM(keyQt)); + bool b; + if (grab) { + b = RegisterHotKey(winId(), id, keyModW, keyCodeW); + } else { + b = UnregisterHotKey(winId(), id); + } + + return b; +} + +void KGlobalAccelImpl::setEnabled( bool enable ) +{ + m_enabled = enable; +} + +bool KGlobalAccelImpl::winEvent( MSG * message, long * result ) +{ + if (message->message == WM_HOTKEY) { + uint keyCodeW = HIWORD(message->lParam); + uint keyModW = LOWORD(message->lParam); + + int keyCodeQt, keyModQt; + KKeyServer::codeWinToKeyQt(keyCodeW, &keyCodeQt); + KKeyServer::modWinToKeyQt(keyModW, &keyModQt); + + return m_owner->keyPressed(keyCodeQt | keyModQt); + } + return false; +} + +#include "kglobalaccel_win.moc" + +#endif // Q_WS_WIN diff --git a/kglobalaccel/kglobalaccel_win.h b/kglobalaccel/kglobalaccel_win.h new file mode 100644 index 00000000..c22e8342 --- /dev/null +++ b/kglobalaccel/kglobalaccel_win.h @@ -0,0 +1,64 @@ +/* This file is part of the KDE libraries + Copyright (C) 2001,2002 Ellis Whitehead + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef _KGLOBALACCEL_WIN_H +#define _KGLOBALACCEL_WIN_H + +#include + +class GlobalShortcutsRegistry; +/** + * @internal + * + * The KGlobalAccel private class handles grabbing of global keys, + * and notification of when these keys are pressed. + */ +class KGlobalAccelImpl : public QWidget +{ + Q_OBJECT + +public: + KGlobalAccelImpl(GlobalShortcutsRegistry* owner); + +public: + /** + * This function registers or unregisters a certain key for global capture, + * depending on \b grab. + * + * Before destruction, every grabbed key will be released, so this + * object does not need to do any tracking. + * + * \param key the Qt keycode to grab or release. + * \param grab true to grab they key, false to release the key. + * + * \return true if successful, otherwise false. + */ + bool grabKey(int key, bool grab); + + /// Enable/disable all shortcuts. There will not be any grabbed shortcuts at this point. + void setEnabled(bool); + +private: + bool winEvent(MSG * message, long * result); + + GlobalShortcutsRegistry* m_owner; + bool m_enabled; +}; + +#endif // _KGLOBALACCEL_WIN_H diff --git a/kglobalaccel/kglobalaccel_x11.cpp b/kglobalaccel/kglobalaccel_x11.cpp new file mode 100644 index 00000000..dbe1f323 --- /dev/null +++ b/kglobalaccel/kglobalaccel_x11.cpp @@ -0,0 +1,271 @@ +/* This file is part of the KDE libraries + Copyright (C) 2001,2002 Ellis Whitehead + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "kglobalaccel_x11.h" + +#include + +#include "kaction.h" +#include "globalshortcutsregistry.h" +#include "kkeyserver.h" + +#include +#include + +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include + +extern "C" { + static int XGrabErrorHandler( Display *, XErrorEvent *e ) { + if ( e->error_code != BadAccess ) { + kWarning() << "grabKey: got X error " << e->type << " instead of BadAccess\n"; + } + return 1; + } +} + +// g_keyModMaskXAccel +// mask of modifiers which can be used in shortcuts +// (meta, alt, ctrl, shift) +// g_keyModMaskXOnOrOff +// mask of modifiers where we don't care whether they are on or off +// (caps lock, num lock, scroll lock) +static uint g_keyModMaskXAccel = 0; +static uint g_keyModMaskXOnOrOff = 0; + +static void calculateGrabMasks() +{ + g_keyModMaskXAccel = KKeyServer::accelModMaskX(); + g_keyModMaskXOnOrOff = + KKeyServer::modXLock() | + KKeyServer::modXNumLock() | + KKeyServer::modXScrollLock() | + KKeyServer::modXModeSwitch(); + //kDebug() << "g_keyModMaskXAccel = " << g_keyModMaskXAccel + // << "g_keyModMaskXOnOrOff = " << g_keyModMaskXOnOrOff << endl; +} + +//---------------------------------------------------- + +KGlobalAccelImpl::KGlobalAccelImpl(GlobalShortcutsRegistry *owner) + : m_owner(owner) +{ + calculateGrabMasks(); +} + +bool KGlobalAccelImpl::grabKey( int keyQt, bool grab ) +{ + if( !keyQt ) { + kDebug() << "Tried to grab key with null code."; + return false; + } + + int keyCodeX; + uint keyModX; + uint keySymX; + + // Resolve the modifier + if( !KKeyServer::keyQtToModX(keyQt, &keyModX) ) { + kDebug() << "keyQt (0x" << hex << keyQt << ") failed to resolve to x11 modifier"; + return false; + } + + // Resolve the X symbol + if( !KKeyServer::keyQtToSymX(keyQt, (int *)&keySymX) ) { + kDebug() << "keyQt (0x" << hex << keyQt << ") failed to resolve to x11 keycode"; + return false; + } + + keyCodeX = XKeysymToKeycode( QX11Info::display(), keySymX ); + + // Check if shift needs to be added to the grab since KKeySequenceWidget + // can remove shift for some keys. (all the %&* and such) + if( !(keyQt & Qt::SHIFT) && + !KKeyServer::isShiftAsModifierAllowed( keyQt ) && + keySymX != XKeycodeToKeysym( QX11Info::display(), keyCodeX, 0 ) && + keySymX == XKeycodeToKeysym( QX11Info::display(), keyCodeX, 1 ) ) + { + kDebug() << "adding shift to the grab"; + keyModX |= KKeyServer::modXShift(); + } + + keyModX &= g_keyModMaskXAccel; // Get rid of any non-relevant bits in mod + + if( !keyCodeX ) { + kDebug() << "keyQt (0x" << hex << keyQt << ") was resolved to x11 keycode 0"; + return false; + } + + KXErrorHandler handler( XGrabErrorHandler ); + + // We'll have to grab 8 key modifier combinations in order to cover all + // combinations of CapsLock, NumLock, ScrollLock. + // Does anyone with more X-savvy know how to set a mask on QX11Info::appRootWindow so that + // the irrelevant bits are always ignored and we can just make one XGrabKey + // call per accelerator? -- ellis +#ifndef NDEBUG + QString sDebug = QString("\tcode: 0x%1 state: 0x%2 | ").arg(keyCodeX,0,16).arg(keyModX,0,16); +#endif + uint keyModMaskX = ~g_keyModMaskXOnOrOff; + for( uint irrelevantBitsMask = 0; irrelevantBitsMask <= 0xff; irrelevantBitsMask++ ) { + if( (irrelevantBitsMask & keyModMaskX) == 0 ) { +#ifndef NDEBUG + sDebug += QString("0x%3, ").arg(irrelevantBitsMask, 0, 16); +#endif + if( grab ) + XGrabKey( QX11Info::display(), keyCodeX, keyModX | irrelevantBitsMask, + QX11Info::appRootWindow(), True, GrabModeAsync, GrabModeSync ); + else + XUngrabKey( QX11Info::display(), keyCodeX, keyModX | irrelevantBitsMask, QX11Info::appRootWindow() ); + } + } + + bool failed = false; + if( grab ) { + failed = handler.error( true ); // sync now + if( failed ) { + kDebug() << "grab failed!\n"; + for( uint m = 0; m <= 0xff; m++ ) { + if(( m & keyModMaskX ) == 0 ) + XUngrabKey( QX11Info::display(), keyCodeX, keyModX | m, QX11Info::appRootWindow() ); + } + } + } + + return !failed; +} + +bool KGlobalAccelImpl::x11Event( XEvent* event ) +{ + switch( event->type ) { + + case MappingNotify: + kDebug() << "Got XMappingNotify event"; + XRefreshKeyboardMapping(&event->xmapping); + x11MappingNotify(); + return true; + + case XKeyPress: + kDebug() << "Got XKeyPress event"; + return x11KeyPress(event); + + default: + // We get all XEvents. Just ignore them. + return false; + } + + Q_ASSERT(false); + return false; +} + +void KGlobalAccelImpl::x11MappingNotify() +{ + // Maybe the X modifier map has been changed. + // uint oldKeyModMaskXAccel = g_keyModMaskXAccel; + // uint oldKeyModMaskXOnOrOff = g_keyModMaskXOnOrOff; + + // First ungrab all currently grabbed keys. This is needed because we + // store the keys as qt keycodes and use KKeyServer to map them to x11 key + // codes. After calling KKeyServer::initializeMods() they could map to + // different keycodes. + m_owner->ungrabKeys(); + + KKeyServer::initializeMods(); + calculateGrabMasks(); + + m_owner->grabKeys(); +} + + +bool KGlobalAccelImpl::x11KeyPress( const XEvent *pEvent ) +{ + if (QWidget::keyboardGrabber() || QApplication::activePopupWidget()) { + kWarning() << "kglobalacceld should be popup and keyboard grabbing free!"; + } + + // Keyboard needs to be ungrabed after XGrabKey() activates the grab, + // otherwise it becomes frozen. + XUngrabKeyboard( QX11Info::display(), CurrentTime ); + XFlush( QX11Info::display()); // avoid X(?) bug + + uchar keyCodeX = pEvent->xkey.keycode; + uint keyModX = pEvent->xkey.state & (g_keyModMaskXAccel | KKeyServer::MODE_SWITCH); + + KeySym keySym; + XLookupString( (XKeyEvent*) pEvent, 0, 0, &keySym, 0 ); + uint keySymX = (uint)keySym; + + // If numlock is active and a keypad key is pressed, XOR the SHIFT state. + // e.g., KP_4 => Shift+KP_Left, and Shift+KP_4 => KP_Left. + if( pEvent->xkey.state & KKeyServer::modXNumLock() ) { + uint sym = XKeycodeToKeysym( QX11Info::display(), keyCodeX, 0 ); + // If this is a keypad key, + if( sym >= XK_KP_Space && sym <= XK_KP_9 ) { + switch( sym ) { + + // Leave the following keys unaltered + // FIXME: The proper solution is to see which keysyms don't change when shifted. + case XK_KP_Multiply: + case XK_KP_Add: + case XK_KP_Subtract: + case XK_KP_Divide: + break; + + default: + keyModX ^= KKeyServer::modXShift(); + } + } + } + + int keyCodeQt; + int keyModQt; + KKeyServer::symXToKeyQt(keySymX, &keyCodeQt); + KKeyServer::modXToQt(keyModX, &keyModQt); + + if( keyModQt & Qt::SHIFT && !KKeyServer::isShiftAsModifierAllowed( keyCodeQt ) ) { + kDebug() << "removing shift modifier"; + keyModQt &= ~Qt::SHIFT; + } + + int keyQt = keyCodeQt | keyModQt; + + // All that work for this hey... argh... + return m_owner->keyPressed(keyQt); +} + +void KGlobalAccelImpl::setEnabled( bool enable ) +{ + if (enable) { + kapp->installX11EventFilter( this ); + } else + kapp->removeX11EventFilter( this ); +} + + +#include "kglobalaccel_x11.moc" diff --git a/kglobalaccel/kglobalaccel_x11.h b/kglobalaccel/kglobalaccel_x11.h new file mode 100644 index 00000000..f2e2717a --- /dev/null +++ b/kglobalaccel/kglobalaccel_x11.h @@ -0,0 +1,72 @@ +/* This file is part of the KDE libraries + Copyright (C) 2001,2002 Ellis Whitehead + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef _KGLOBALACCEL_X11_H +#define _KGLOBALACCEL_X11_H + +#include + +class GlobalShortcutsRegistry; +/** + * @internal + * + * The KGlobalAccel private class handles grabbing of global keys, + * and notification of when these keys are pressed. + */ +class KGlobalAccelImpl : public QWidget +{ + Q_OBJECT + +public: + KGlobalAccelImpl( GlobalShortcutsRegistry *owner); + +public: + /** + * This function registers or unregisters a certain key for global capture, + * depending on \b grab. + * + * Before destruction, every grabbed key will be released, so this + * object does not need to do any tracking. + * + * \param key the Qt keycode to grab or release. + * \param grab true to grab they key, false to release the key. + * + * \return true if successful, otherwise false. + */ + bool grabKey(int key, bool grab); + + /// Enable/disable all shortcuts. There will not be any grabbed shortcuts at this point. + void setEnabled(bool); + +private: + /** + * Filters X11 events ev for key bindings in the accelerator dictionary. + * If a match is found the activated activated is emitted and the function + * returns true. Return false if the event is not processed. + * + * This is public for compatibility only. You do not need to call it. + */ + virtual bool x11Event( XEvent* ); + void x11MappingNotify(); + bool x11KeyPress( const XEvent *pEvent ); + + GlobalShortcutsRegistry *m_owner; +}; + +#endif // _KGLOBALACCEL_X11_H diff --git a/kglobalaccel/kglobalacceld.cpp b/kglobalaccel/kglobalacceld.cpp new file mode 100644 index 00000000..3e228937 --- /dev/null +++ b/kglobalaccel/kglobalacceld.cpp @@ -0,0 +1,635 @@ +/* + This file is part of the KDE libraries + + Copyright (c) 2007 Andreas Hartmetz + Copyright (c) 2007 Michael Jansen + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "kglobalacceld.h" + +#include "component.h" +#include "globalshortcut.h" +#include "globalshortcutcontext.h" +#include "globalshortcutsregistry.h" + +#include +#include +#include +#include + +#include "klocale.h" +#include "kglobalaccel.h" +#include "kglobalsettings.h" +#include "knotification.h" +#include "kdebug.h" + + +struct KGlobalAccelDPrivate + { + + KGlobalAccelDPrivate(KGlobalAccelD *q) + : q(q) + {} + + + GlobalShortcut *findAction(const QStringList &actionId) const; + + /** + * Find the action @a shortcutUnique in @a componentUnique. + * + * @return the action or @c null if doesn't exist + */ + GlobalShortcut *findAction( + const QString &componentUnique, + const QString &shortcutUnique) const; + + GlobalShortcut *addAction(const QStringList &actionId); + KdeDGlobalAccel::Component *component(const QStringList &actionId) const; + + + //! Use KNotification to inform the user new global shortcuts were + //! registered + void _k_newGlobalShortcutNotification(); + + void splitComponent(QString &component, QString &context) const + { + context = "default"; + if (component.indexOf('|')!=-1) + { + QStringList tmp = component.split('|'); + Q_ASSERT(tmp.size()==2); + component= tmp.at(0); + context= tmp.at(1); + } + } + + enum ChangeType + { + NewShortcut + }; + + // List if changed components for _k_globalShortcutNotification + QMap changedComponents; + + //! Timer for delayed popup on new shortcut registration + QTimer popupTimer; + + //! Timer for delayed writing to kglobalshortcutsrc + QTimer writeoutTimer; + + //! Our holder + KGlobalAccelD *q; + }; + + +GlobalShortcut *KGlobalAccelDPrivate::findAction(const QStringList &actionId) const + { + // Check if actionId is valid + if (actionId.size() != 4) + { + kDebug() << "Invalid! '" << actionId << "'"; + return NULL; + } + + return findAction( + actionId.at(KGlobalAccel::ComponentUnique), + actionId.at(KGlobalAccel::ActionUnique)); + } + + +GlobalShortcut *KGlobalAccelDPrivate::findAction( + const QString &_componentUnique, + const QString &shortcutUnique) const + { + QString componentUnique = _componentUnique; + + KdeDGlobalAccel::Component *component; + QString contextUnique; + if (componentUnique.indexOf('|')==-1) + { + component = GlobalShortcutsRegistry::self()->getComponent( componentUnique); + if (component) contextUnique = component->currentContext()->uniqueName(); + } + else + { + splitComponent(componentUnique, contextUnique); + component = GlobalShortcutsRegistry::self()->getComponent( componentUnique); + } + + if (!component) + { +#ifdef KDEDGLOBALACCEL_TRACE + kDebug() << componentUnique << "not found"; +#endif + return NULL; + } + + GlobalShortcut *shortcut = component + ? component->getShortcutByName(shortcutUnique, contextUnique) + : NULL; + +#ifdef KDEDGLOBALACCEL_TRACE + if (shortcut) + { + kDebug() << componentUnique + << contextUnique + << shortcut->uniqueName(); + } + else + { + kDebug() << "No match for" << shortcutUnique; + } +#endif + return shortcut; + } + + +KdeDGlobalAccel::Component *KGlobalAccelDPrivate::component(const QStringList &actionId) const +{ + // Get the component for the action. If we have none create a new one + KdeDGlobalAccel::Component *component = GlobalShortcutsRegistry::self()->getComponent(actionId.at(KGlobalAccel::ComponentUnique)); + if (!component) + { + component = new KdeDGlobalAccel::Component( + actionId.at(KGlobalAccel::ComponentUnique), + actionId.at(KGlobalAccel::ComponentFriendly), + GlobalShortcutsRegistry::self()); + Q_ASSERT(component); + } + return component; +} + + +GlobalShortcut *KGlobalAccelDPrivate::addAction(const QStringList &actionId) +{ + Q_ASSERT(actionId.size() >= 4); + + QString componentUnique = actionId.at(KGlobalAccel::ComponentUnique); + + QString contextUnique = "default"; + + if (componentUnique.indexOf("|")!=-1) { + QStringList tmp = componentUnique.split('|'); + Q_ASSERT(tmp.size()==2); + componentUnique = tmp.at(0); + contextUnique = tmp.at(1); + } + + QStringList actionIdTmp = actionId; + actionIdTmp.replace(KGlobalAccel::ComponentUnique, componentUnique); + + // Create the component if necessary + KdeDGlobalAccel::Component *component = this->component(actionIdTmp); + Q_ASSERT(component); + + // Create the context if necessary + if (component->getShortcutContexts().count(contextUnique)==0) { + component->createGlobalShortcutContext(contextUnique); + } + + Q_ASSERT(!component->getShortcutByName(componentUnique, contextUnique)); + changedComponents.insert(actionId.at(KGlobalAccel::ComponentUnique), NewShortcut); + + if (!popupTimer.isActive()) popupTimer.start(500); + + return new GlobalShortcut( + actionId.at(KGlobalAccel::ActionUnique), + actionId.at(KGlobalAccel::ActionFriendly), + component->shortcutContext(contextUnique)); +} + + +void KGlobalAccelDPrivate::_k_newGlobalShortcutNotification() +{ + Q_FOREACH(const QString &uniqueName, changedComponents.keys()) + { + kDebug() << "Showing Notification for component" << uniqueName; + + KdeDGlobalAccel::Component *component = GlobalShortcutsRegistry::self()->getComponent(uniqueName); + if (!component) + { + // Can happen if a component is removed immediately after + // registering it. kdelibs/kdeui/tests/kglobalshortcuttests does + // it for example. + continue; + } + + KNotification *notification = new KNotification( + "newshortcutregistered", + KNotification::CloseOnTimeout, + q->parent()); + + notification->setText( + i18n("The application %1 has registered a new global shortcut", + component->friendlyName())); + + notification->setActions( QStringList( i18n( "Open Global Shortcuts Editor" ) ) ); + + notification->addContext( "application", component->friendlyName() ); + + QObject::connect(notification, SIGNAL(action1Activated()), + component, SLOT(showKCM())); + + notification->sendEvent(); + } + + changedComponents.clear(); +} + + + + +Q_DECLARE_METATYPE(QStringList) + +KGlobalAccelD::KGlobalAccelD(QObject* parent) +: QObject(parent), + d(new KGlobalAccelDPrivate(this)) +{} + + +bool KGlobalAccelD::init() +{ + qDBusRegisterMetaType< QList >(); + qDBusRegisterMetaType< QList >(); + qDBusRegisterMetaType< QList >(); + qDBusRegisterMetaType(); + qDBusRegisterMetaType(); + qDBusRegisterMetaType< QList >(); + + GlobalShortcutsRegistry *reg = GlobalShortcutsRegistry::self(); + Q_ASSERT(reg); + + d->writeoutTimer.setSingleShot(true); + connect(&d->writeoutTimer, SIGNAL(timeout()), + reg, SLOT(writeSettings())); + + d->popupTimer.setSingleShot(true); + connect(&d->popupTimer, SIGNAL(timeout()), + this, SLOT(_k_newGlobalShortcutNotification())); + + if (!QDBusConnection::sessionBus().registerService(QLatin1String("org.kde.kglobalaccel"))) { + kWarning() << "Failed to register service org.kde.kglobalaccel"; + return false; + } + + if (!QDBusConnection::sessionBus().registerObject( + QLatin1String("/kglobalaccel"), + this, + QDBusConnection::ExportScriptableContents)) { + kWarning() << "Failed to register object kglobalaccel in org.kde.kglobalaccel"; + return false; + } + + GlobalShortcutsRegistry::self()->setDBusPath(QDBusObjectPath("/")); + GlobalShortcutsRegistry::self()->loadSettings(); + + connect(KGlobalSettings::self(), SIGNAL(blockShortcuts(int)), + SLOT(blockGlobalShortcuts(int))); + + return true; +} + + +KGlobalAccelD::~KGlobalAccelD() +{ + GlobalShortcutsRegistry::self()->deactivateShortcuts(); + delete d; +} + +QList KGlobalAccelD::allMainComponents() const +{ + QList ret; + QStringList emptyList; + for (int i = 0; i < 4; i++) { + emptyList.append(QString()); + } + + foreach (const KdeDGlobalAccel::Component *component, GlobalShortcutsRegistry::self()->allMainComponents()) { + QStringList actionId(emptyList); + actionId[KGlobalAccel::ComponentUnique] = component->uniqueName(); + actionId[KGlobalAccel::ComponentFriendly] = component->friendlyName(); + ret.append(actionId); + } + + return ret; +} + + +QList KGlobalAccelD::allActionsForComponent(const QStringList &actionId) const +{ + //### Would it be advantageous to sort the actions by unique name? + QList ret; + + KdeDGlobalAccel::Component *const component = + GlobalShortcutsRegistry::self()->getComponent(actionId[KGlobalAccel::ComponentUnique]); + if (!component) { + return ret; + } + + QStringList partialId(actionId[KGlobalAccel::ComponentUnique]); //ComponentUnique + partialId.append(QString()); //ActionUnique + //Use our internal friendlyName, not the one passed in. We should have the latest data. + partialId.append(component->friendlyName()); //ComponentFriendly + partialId.append(QString()); //ActionFriendly + + foreach (const GlobalShortcut *const shortcut, component->allShortcuts()) { + if (shortcut->isFresh()) { + // isFresh is only an intermediate state, not to be reported outside. + continue; + } + QStringList actionId(partialId); + actionId[KGlobalAccel::ActionUnique] = shortcut->uniqueName(); + actionId[KGlobalAccel::ActionFriendly] = shortcut->friendlyName(); + ret.append(actionId); + } + return ret; +} + + +QStringList KGlobalAccelD::action(int key) const +{ + GlobalShortcut *shortcut = GlobalShortcutsRegistry::self()->getShortcutByKey(key); + QStringList ret; + if (shortcut) { + ret.append(shortcut->context()->component()->uniqueName()); + ret.append(shortcut->uniqueName()); + ret.append(shortcut->context()->component()->friendlyName()); + ret.append(shortcut->friendlyName()); + } + return ret; +} + + +void KGlobalAccelD::activateGlobalShortcutContext( + const QString &component, + const QString &uniqueName) +{ + KdeDGlobalAccel::Component *const comp = + GlobalShortcutsRegistry::self()->getComponent(component); + if (comp) + comp->activateGlobalShortcutContext(uniqueName); +} + + +QList KGlobalAccelD::allComponents() const + { + QList allComp; + + Q_FOREACH (const KdeDGlobalAccel::Component *component, + GlobalShortcutsRegistry::self()->allMainComponents()) + { + allComp.append(component->dbusPath()); + } + + return allComp; + } + + +void KGlobalAccelD::blockGlobalShortcuts(int block) + { +#ifdef KDEDGLOBALACCEL_TRACE + kDebug() << block; +#endif + block + ? GlobalShortcutsRegistry::self()->deactivateShortcuts(true) + : GlobalShortcutsRegistry::self()->activateShortcuts(); + } + + +QList KGlobalAccelD::shortcut(const QStringList &action) const +{ + GlobalShortcut *shortcut = d->findAction(action); + if (shortcut) + return shortcut->keys(); + return QList(); +} + + +QList KGlobalAccelD::defaultShortcut(const QStringList &action) const +{ + GlobalShortcut *shortcut = d->findAction(action); + if (shortcut) + return shortcut->defaultKeys(); + return QList(); +} + + +// This method just registers the action. Nothing else. Shortcut has to be set +// later. +void KGlobalAccelD::doRegister(const QStringList &actionId) +{ +#ifdef KDEDGLOBALACCEL_TRACE + kDebug() << actionId; +#endif + + // Check because we would not want to add a action for an invalid + // actionId. findAction returns NULL in that case. + if (actionId.size() < 4) { + return; + } + + GlobalShortcut *shortcut = d->findAction(actionId); + if (!shortcut) { + shortcut = d->addAction(actionId); + } else { + //a switch of locales is one common reason for a changing friendlyName + if ((!actionId[KGlobalAccel::ActionFriendly].isEmpty()) && shortcut->friendlyName() != actionId[KGlobalAccel::ActionFriendly]) { + shortcut->setFriendlyName(actionId[KGlobalAccel::ActionFriendly]); + scheduleWriteSettings(); + } + if ((!actionId[KGlobalAccel::ComponentFriendly].isEmpty()) + && shortcut->context()->component()->friendlyName() != actionId[KGlobalAccel::ComponentFriendly]) { + shortcut->context()->component()->setFriendlyName(actionId[KGlobalAccel::ComponentFriendly]); + scheduleWriteSettings(); + } + } +} + + +QDBusObjectPath KGlobalAccelD::getComponent(const QString &componentUnique) const + { +#ifdef KDEDGLOBALACCEL_TRACE + kDebug() << componentUnique; +#endif + + KdeDGlobalAccel::Component *component = + GlobalShortcutsRegistry::self()->getComponent(componentUnique); + + if (component) + { + return component->dbusPath(); + } + else + { + sendErrorReply("org.kde.kglobalaccel.NoSuchComponent", QString("The component '%1' doesn't exist.").arg(componentUnique)); + return QDBusObjectPath("/"); + } + } + + +QList KGlobalAccelD::getGlobalShortcutsByKey(int key) const + { +#ifdef KDEDGLOBALACCEL_TRACE + kDebug() << key; +#endif + QList shortcuts = + GlobalShortcutsRegistry::self()->getShortcutsByKey(key); + + QList rc; + Q_FOREACH(const GlobalShortcut *sc, shortcuts) + { +#ifdef KDEDGLOBALACCEL_TRACE + kDebug() << sc->context()->uniqueName() << sc->uniqueName(); +#endif + rc.append(static_cast(*sc)); + } + + return rc; + } + + +bool KGlobalAccelD::isGlobalShortcutAvailable(int shortcut, const QString &component) const + { + QString realComponent = component; + QString context; + d->splitComponent(realComponent, context); + return GlobalShortcutsRegistry::self()->isShortcutAvailable(shortcut, realComponent, context); + } + + +void KGlobalAccelD::setInactive(const QStringList &actionId) + { +#ifdef KDEDGLOBALACCEL_TRACE + kDebug() << actionId; +#endif + + GlobalShortcut *shortcut = d->findAction(actionId); + if (shortcut) + shortcut->setIsPresent(false); + } + + +bool KGlobalAccelD::unregister(const QString &componentUnique, const QString &shortcutUnique) +{ +#ifdef KDEDGLOBALACCEL_TRACE + kDebug() << componentUnique << shortcutUnique; +#endif + + // Stop grabbing the key + GlobalShortcut *shortcut = d->findAction(componentUnique, shortcutUnique); + if (shortcut) { + shortcut->unRegister(); + scheduleWriteSettings(); + } + + return shortcut; + +} + + +void KGlobalAccelD::unRegister(const QStringList &actionId) +{ +#ifdef KDEDGLOBALACCEL_TRACE + kDebug() << actionId; +#endif + + // Stop grabbing the key + GlobalShortcut *shortcut = d->findAction(actionId); + if (shortcut) { + shortcut->unRegister(); + scheduleWriteSettings(); + } + +} + + +QList KGlobalAccelD::setShortcut(const QStringList &actionId, + const QList &keys, uint flags) +{ + //spare the DBus framework some work + const bool setPresent = (flags & SetPresent); + const bool isAutoloading = !(flags & NoAutoloading); + const bool isDefault = (flags & IsDefault); + + GlobalShortcut *shortcut = d->findAction(actionId); + if (!shortcut) { + return QList(); + } + + //default shortcuts cannot clash because they don't do anything + if (isDefault) { + if (shortcut->defaultKeys() != keys) { + shortcut->setDefaultKeys(keys); + scheduleWriteSettings(); + } + return keys; //doesn't matter + } + + if (isAutoloading && !shortcut->isFresh()) { + //the trivial and common case - synchronize the action from our data + //and exit. + if (!shortcut->isPresent() && setPresent) { + shortcut->setIsPresent(true); + } + // We are finished here. Return the list of current active keys. + return shortcut->keys(); + } + + //now we are actually changing the shortcut of the action + shortcut->setKeys(keys); + + if (setPresent) { + shortcut->setIsPresent(true); + } + + //maybe isFresh should really only be set if setPresent, but only two things should use !setPresent: + //- the global shortcuts KCM: very unlikely to catch KWin/etc.'s actions in isFresh state + //- KGlobalAccel::stealGlobalShortcutSystemwide(): only applies to actions with shortcuts + // which can never be fresh if created the usual way + shortcut->setIsFresh(false); + + scheduleWriteSettings(); + + return shortcut->keys(); +} + + +void KGlobalAccelD::setForeignShortcut(const QStringList &actionId, const QList &keys) +{ +#ifdef KDEDGLOBALACCEL_TRACE + kDebug() << actionId; +#endif + + GlobalShortcut *shortcut = d->findAction(actionId); + if (!shortcut) + return; + + QList newKeys = setShortcut(actionId, keys, NoAutoloading); + + emit yourShortcutGotChanged(actionId, newKeys); +} + + +void KGlobalAccelD::scheduleWriteSettings() const + { + if (!d->writeoutTimer.isActive()) + d->writeoutTimer.start(500); + } + + +#include "moc_kglobalacceld.cpp" diff --git a/kglobalaccel/kglobalacceld.h b/kglobalaccel/kglobalacceld.h new file mode 100644 index 00000000..c9b1f9b6 --- /dev/null +++ b/kglobalaccel/kglobalacceld.h @@ -0,0 +1,157 @@ +/* + This file is part of the KDE libraries + + Copyright (c) 2007 Andreas Hartmetz + Copyright (c) 2008 Michael Jansen + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ +#ifndef KGLOBALACCELD_H +#define KGLOBALACCELD_H + +#include +#include + +#include +#include +#include + +struct KGlobalAccelDPrivate; + +/** + * @todo get rid of all of those QStringList parameters. + */ +class KGlobalAccelD : public QObject, protected QDBusContext +{ + Q_OBJECT + Q_CLASSINFO("D-Bus Interface", "org.kde.KGlobalAccel") + Q_ENUMS(SetShortcutFlag) + +public: + + enum SetShortcutFlag + { + SetPresent = 2, + NoAutoloading = 4, + IsDefault = 8 + }; + Q_FLAGS(SetShortcutFlags) + + KGlobalAccelD(QObject* parent = NULL); + ~KGlobalAccelD(); + + bool init(); + +public Q_SLOTS: + + /** + * Get the dbus path for all known components. + * + * The returned path is absolute. No need to prepend anything. + */ + Q_SCRIPTABLE QList allComponents() const; + + Q_SCRIPTABLE QList allMainComponents() const; + + Q_SCRIPTABLE QList allActionsForComponent(const QStringList &actionId) const; + + Q_SCRIPTABLE QStringList action(int key) const; + + //to be called by main components not owning the action + Q_SCRIPTABLE QList shortcut(const QStringList &actionId) const; + + //to be called by main components not owning the action + Q_SCRIPTABLE QList defaultShortcut(const QStringList &actionId) const; + + /** + * Get the dbus path for @ componentUnique + * + * @param componentUnique the components unique identifier + * + * @return the absolute dbus path + */ + Q_SCRIPTABLE QDBusObjectPath getComponent(const QString &componentUnique) const; + + //to be called by main components owning the action + Q_SCRIPTABLE QList setShortcut(const QStringList &actionId, + const QList &keys, uint flags); + + //this is used if application A wants to change shortcuts of application B + Q_SCRIPTABLE void setForeignShortcut(const QStringList &actionId, const QList &keys); + + //to be called when a KAction is destroyed. The shortcut stays in the data structures for + //conflict resolution but won't trigger. + Q_SCRIPTABLE void setInactive(const QStringList &actionId); + + Q_SCRIPTABLE void doRegister(const QStringList &actionId); + + //! @see unregister + Q_SCRIPTABLE KDE_DEPRECATED void unRegister(const QStringList &actionId); + + Q_SCRIPTABLE void activateGlobalShortcutContext( + const QString &component, + const QString &context); + + + /** + * Returns the shortcuts registered for @p key. + * + * If there is more than one shortcut they are guaranteed to be from the + * same component but different contexts. All shortcuts are searched. + */ + Q_SCRIPTABLE QList getGlobalShortcutsByKey(int key) const; + + /** + * Return true if the @p shortcut is available for @p component. + */ + Q_SCRIPTABLE bool isGlobalShortcutAvailable( + int key, + const QString &component) const; + + /** + * Delete the shortcut with @a component and @name. + * + * The shortcut is removed from the registry even if it is currently + * present. It is removed from all contexts. + * + * @param componentUnique the components unique identifier + * @param shortcutUnique the shortcut id + * + * @return @c true if the shortcuts was deleted, @c false if it didn't * exist. + */ + Q_SCRIPTABLE bool unregister( + const QString &componentUnique, + const QString &shortcutUnique); + +Q_SIGNALS: + + Q_SCRIPTABLE void yourShortcutGotChanged(const QStringList &actionId, const QList &newKeys); + +private Q_SLOTS: + + void blockGlobalShortcuts(int); + + +private: + + Q_PRIVATE_SLOT(d, void _k_newGlobalShortcutNotification() ) + + void scheduleWriteSettings() const; + + KGlobalAccelDPrivate *const d; +}; + +#endif //KGLOBALACCELD_H diff --git a/kglobalaccel/main.cpp b/kglobalaccel/main.cpp new file mode 100644 index 00000000..4d230b8d --- /dev/null +++ b/kglobalaccel/main.cpp @@ -0,0 +1,112 @@ +/* + This file is part of the KDE project + + Copyright (c) 2007 Andreas Hartmetz + Copyright (c) 2007 Michael Jansen + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. + */ + +#include "kglobalacceld.h" + +#include +#include +#include +#include +#include +#include +#include + +#include + +static bool isEnabled() + { + // TODO: Check if kglobalaccel can be disabled + return true; + } + + +static void sighandler(int /*sig*/) +{ + if (qApp) + qApp->quit(); +} + + +extern "C" KDE_EXPORT int kdemain(int argc, char **argv) + { + // Disable Session Management the right way (C) + // + // ksmserver has global shortcuts. disableSessionManagement() does not prevent Qt from + // registering the app with the session manager. We remove the address to make sure we do not + // get a hang on kglobalaccel restart (kglobalaccel tries to register with ksmserver, + // ksmserver tries to register with kglobalaccel). + unsetenv( "SESSION_MANAGER" ); + + KAboutData aboutdata( + "kglobalaccel", + 0, + ki18n("KDE Global Shortcuts Service"), + "0.2", + ki18n("KDE Global Shortcuts Service"), + KAboutData::License_LGPL, + ki18n("(C) 2007-2009 Andreas Hartmetz, Michael Jansen")); + aboutdata.addAuthor(ki18n("Andreas Hartmetz"),ki18n("Maintainer"),"ahartmetz@gmail.com"); + aboutdata.addAuthor(ki18n("Michael Jansen"),ki18n("Maintainer"),"kde@michael-jansen.biz"); + + aboutdata.setProgramIconName("kglobalaccel"); + + KCmdLineArgs::init( argc, argv, &aboutdata ); + KUniqueApplication::addCmdLineOptions(); + + // check if kglobalaccel is disabled + if (!isEnabled()) + { + kDebug() << "kglobalaccel is disabled!"; + return 0; + } + + if (!KUniqueApplication::start()) + { + kDebug() << "kglobalaccel is already running!"; + return (0); + } + + // As in the KUniqueApplication example only create a instance AFTER + // calling KUniqueApplication::start() + KUniqueApplication app; + + // This app is started automatically, no need for session management + app.disableSessionManagement(); + app.setQuitOnLastWindowClosed( false ); + + // Stop gracefully + //There is no SIGINT and SIGTERM under wince +#ifndef _WIN32_WCE + KDE_signal(SIGINT, sighandler); + KDE_signal(SIGTERM, sighandler); +#endif + KDE_signal(SIGHUP, sighandler); + + // Restart on a crash + KCrash::setFlags(KCrash::AutoRestart); + + KGlobalAccelD globalaccel; + if (!globalaccel.init()) { + return -1; + } + + return app.exec(); + } diff --git a/khelpcenter/CMakeLists.txt b/khelpcenter/CMakeLists.txt new file mode 100644 index 00000000..62b67555 --- /dev/null +++ b/khelpcenter/CMakeLists.txt @@ -0,0 +1,61 @@ +add_subdirectory( plugins ) +add_subdirectory( searchhandlers ) +add_subdirectory( tests ) + +########### next target ############### + +set(khc_indexbuilder_SRCS khc_indexbuilder.cpp ) + + +kde4_add_executable(khc_indexbuilder NOGUI ${khc_indexbuilder_SRCS}) + +target_link_libraries(khc_indexbuilder ${KDE4_KDECORE_LIBS} ) + +install(TARGETS khc_indexbuilder DESTINATION ${LIBEXEC_INSTALL_DIR}) + + +########### next target ############### + +set(khelpcenter_KDEINIT_SRCS + navigator.cpp + navigatoritem.cpp + navigatorappitem.cpp + view.cpp + searchwidget.cpp + searchengine.cpp + docmetainfo.cpp + docentrytraverser.cpp + formatter.cpp + glossary.cpp + toc.cpp + mainwindow.cpp + docentry.cpp + htmlsearch.cpp + history.cpp + application.cpp + treebuilder.cpp + infotree.cpp + kcmhelpcenter.cpp + htmlsearchconfig.cpp + fontdialog.cpp + plugintraverser.cpp + scrollkeepertreebuilder.cpp + searchhandler.cpp ) + +qt4_add_dbus_adaptor( khelpcenter_KDEINIT_SRCS org.kde.khelpcenter.kcmhelpcenter.xml kcmhelpcenter.h KCMHelpCenter ) + +kde4_add_kcfg_files(khelpcenter_KDEINIT_SRCS prefs.kcfgc ) +kde4_add_app_icon(khelpcenter_KDEINIT_SRCS "${KDE4_INSTALL_DIR}/share/icons/oxygen/*/apps/help-browser.png") + +kde4_add_kdeinit_executable( khelpcenter ${khelpcenter_KDEINIT_SRCS}) +target_link_libraries(kdeinit_khelpcenter ${KDE4_KHTML_LIBS} ${QT_QTXML_LIBRARY} ${KDE4_KCMUTILS_LIBS} ) +install(TARGETS kdeinit_khelpcenter ${INSTALL_TARGETS_DEFAULT_ARGS} ) +install(TARGETS khelpcenter ${INSTALL_TARGETS_DEFAULT_ARGS}) + +########### install files ############### + +install( PROGRAMS Help.desktop DESTINATION ${XDG_APPS_INSTALL_DIR} ) +install( FILES khelpcenter.kcfg DESTINATION ${KCFG_INSTALL_DIR} ) +install( FILES khelpcenter.desktop DESTINATION ${SERVICES_INSTALL_DIR} ) +install( FILES khelpcenterui.rc glossary.html.in table-of-contents.xslt glossary.xslt index.html.in DESTINATION ${DATA_INSTALL_DIR}/khelpcenter ) +install( FILES org.kde.khelpcenter.kcmhelpcenter.xml DESTINATION ${DBUS_INTERFACES_INSTALL_DIR}) diff --git a/khelpcenter/COPYING b/khelpcenter/COPYING new file mode 100644 index 00000000..0b84a43f --- /dev/null +++ b/khelpcenter/COPYING @@ -0,0 +1,339 @@ + 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 Library 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 + + Appendix: 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) 19yy + + 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) 19yy 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 Library General +Public License instead of this License. diff --git a/khelpcenter/DESIGN b/khelpcenter/DESIGN new file mode 100644 index 00000000..c65f3ff9 --- /dev/null +++ b/khelpcenter/DESIGN @@ -0,0 +1,433 @@ +Design for a possible reimplementation of the KDE help center +============================================================= + +Preludium +--------- +This document presents an alternative design for a 'help center' applicaiton +in KDE. Lines which start with a # are supposed to be thoughts I had while +writing this, much like the stuff you write on the side of a page when reading +a book. + +Lines starting with ## were added by my as further comments - Cornelius + +And I'll have the ### lines - Lauri + +General +------- +- main() instantiates a KHC::Application +- KHC::Application() deals with parsing the commandline parameters and + instantiates a KHC::MainWindow +- KHC::MainWindow creates the main UI, setting up actions, using a QSplitter + as it's mainwidget to separate a KHC::Navigator at the left from a KHC::View + at the right + +That's the simple part. ;-) + +## Apparently already done ;-) + +KHC::Navigator +-------------- + +KHC::Navigator inherits QTabWidget and provides, on two tabs, a +KHC::ContentsTab object and a KHC::SearchTab object. + +## KHC::Navigator shouldn't inherit from QTabWidget. This limits flexibility. +## It can create a QTabWidget instance as aggregate just as well. + +# I fear premature generalization ("We could need that bit of flexibility one +# day), aggregation adds a level of indirection through a pointer variable as +# well. I would prefer not making the system more complex as long as we cannot +# predict changes which justify doing so. + +1.) KHC::ContentsTab provides the following entires: + - Welcome to KDE + - KDE user's manual + - KDE FAQ + - Contact information + - Supporting KDE + +# Should we create an extra item for these five and put them in there? +# Something like "General KDE" or so? OTOH that makes them less visible, and +# these are really ought to be seen. - Frerich + +## The items are ok, in principle, but we should have a look at the content of +## the documents they point at. This document could benefit from some attention. + +### Yes, they would. Also, there are license issues with one of them. +### I'd personally like to do an entire rewrite of the User Manual, +### without GPL encumbrance and sans the content that hasn't changed since +### KDE 1.x days. The odds of me getting this done before KDE 3.1, slim to fair. + + + - Application manuals + - Tutorials + - UNIX man pages + - UNIX info pages + - Glossary + +# Do we really need this "Tutorials" item at all? right now it holds only two +# items, perhaps we can get rid of it. - Frerich + +## Yes, please. + +### There should be a "General" area, where documentation that isn't +### attached directly to an application can go. Tutorials might not be +### the best name for it I agree, but there is now some further content to +### add (the DCOP tutorial, for example, or any of the numerous tutorials +### on the websites, documenting things that aren't in the handbooks.q + +# Alright, after some talk on IRC this structure evolved: +# +# - Tasks - contains short, three to four paragraph documents about how to +# solve an everyday task, examples: +# Browsing the web +# Send and receive email +# How to view images +# Playing sound files +# Installing new KDE themes +# How to configure KDE fonts +# Getting in touch with KDE contributors +# Supporting the KDE team +# +# - Guides - slightly longer, Mini-HOWTO style guides (about three to four +# pages long, perhaps) which talk about tackling jobs which don't +# occur very often, examples: +### I don't know about limiting the length. Some of these topics can stand +### a much longer document, but one of the things that differentiates them +### from the references is that they are not specific to a single application, +### nor are they complete references in the manner of the "KDE User Guide" +### Specificaly, the dcop tutorial we have is about 15 pages already, but if +### the user is interested in the topic, that isn't over much, and it's full of +### examples +# How to debug KDE programs +# Sending useful KDE bug reports +# Extending KDE's service menus +# Taking advantage of KDE's DCOP facilities +# Creating panel applets +# Phrasing questions most effectively +# +# - References - references. :-) +# KDE API reference +# KDE application manuals +# Info pages +# Man pages +# FAQ +# User's manual +# +# - Glossary - same as always. +# - By topic +# - Alphabetically +# +# My primary argument for such a structure is that it resembles a +# task-oriented interface much more closely than the simple list of +# application manuals. Imagine a user new to KDE who has a fairly precise +# description of what he's trying to do in mind (think "I want to view an +# image file") but no idea what tool to use for the job. The current list of +# application manuals requires the user to browse all the manuals which seem +# relevant, searching for the information he seeks. A task-oriented list +# solves that issue. +# This effectively enables people new to KDE in less time to become productive +# (a task-oriented list isn't so useful for peoplew ho are familiar with KDE's +# applications, of course). +# Implementation-wise, we should perhaps stop using a K3ListView and use a +# KOffice-style component selection widget like koshell has at the left? + +The first five items are generated by KHC::Navigator itself and are direct +links to KDE documentations. The work of generating each of the last four +items is (with one exception) delegated to four helper classes, which inherit a +'KHC::TreeBuilder' class which has the following interface: + +class KHC::TreeBuilder + virtual void build( K3ListViewItem *parent ) = 0; + +## What about the trees generated as children of the contents list view? + +# Oops, that's a typo, what you mean is what I originally intented: a +# TreeBuilder should take a 'K3ListView' as it's parent, subclasses can then +# overload that method (such as the KHC::TOCBuilder which will want to provide +# a build( K3ListViewItem *parent ) method). + +# This concept of using a TreeBuilder baseclass might make it possible to turn +# all the classes which use that interface into plugins. That way we could +# e.g. have a ScrollKeeper plugin. - Frerich + +## What exactly do you mean by plugin? A shared library loaded at run time or +## the desktop file based insertion of documents into the help center? + +# The former. + +The classes which inherit this interface are: + - KHC::ManualTreeBuilder: responsible for generating the tree below the + "Application manuals" item + - KHC::TOCBuilder: responsible for generating a TOC tree below each of the + manual trees items, so that you can choose Application + Manuals->Editors->KWrite->Using KWrite->Menu bar transparently. This is + the only builder which is not instantiated by KHC::ContentsTab but + instead instantiated by KHC::ManualTreeBuilder + - KHC::TutorialTreeBuilder: responsible for generating the tree below the + "Tutorials" item + - KHC::ManTreeBuilder: responsible for building the tree below the "UNIX + man pages" item + - KHC::InfoTreeBuilder: responsible for building the tree below the "UNIX + info pages" item + - KHC::GlossaryTreeBuilder: guess what + +## - KHC::ScrollkeeperTreeBuilder + +## It's certainly a good idea to move stuff like the info and man pages and +## scrollkeeper support to its own classes. What I consider as important is +## that the concept of representing the documentation by desktop meta files is +## used as far as possible. This makes the system very flexible and extandable. + +2.) KHC::SearchTab provides a widget which lets the search through all +available help repositories, also defining some flags such as 'Search by +regexp' or 'Search case sensitive'. + +# I think this means that we have to create a 'DataCollection' class which +# gets inherited by all classes which are "searchable". DataCollections should +# also be able to contains multiple child DataCollection, so that we have e.g. +# one DataCollection per application manual, and one "Manuals" collection +# which contains all the application manual collections. +# We'd probably also need a DataCollection for the info pages and man pages. +# And later, in the far future, we might extent this concept to web searches, +# so that e.g. Google represents a DataCollection which we can query. +# I'm not yet decided how to do that properly, perhaps using multiple +# inheritance, so that each TOCBuilder is a DataCollection - naw, we'd rather +# have a "TableOfContents" class which contains a TOCBuilder, and is a +# datacollection? Hm, not sure. +# In any case DataCollections should some sort of plugins, so that we can add +# e.g. new web search interfaces lateron. +# - Frerich + +## What you call a DataCollection is currently represented by the DocEntry +## objects. Each DocEntry object represents a document or a collection of +## documents. It has information about the name and description of the +## document, the location and how it can be searched. +## +## Currently this information is based on URLs or file names and is optimized +## to be used by scripts, e.g. CGI scripts. A little exception from this is +## the htdig support where just a keyword "SearchMethod=htdig" is put in the +## desktop file and the help center figures out how to perform that search by +## using a special class. This could be extended to cover other search methods +## like web searches or special search methods optimized for certain kind of +## documents. + +# I just thought about it - isn't that a bit overkill for the web search +# stuff? I just thought about it - all we need to do is to copy the .desktop +# files (at least some of them, like the ones for google, yahoo and excite) +# from the enhanced browsing thing and treat those as plugin .desktop files. +# We could show them in a listview on the Search tab, each found search engine +# being represented by a checkable listview item. So, we just let the user +# enter a term, replace the \{@} placeholder in the URIs specified in the +# selected .desktop files with that term, send out a request via KIO and show +# the results in our KHTMLPart (after all KHC::View is a KHTMLPart already). A +# problem with this: How to display the multiple HTML pages returned by the +# selected search engines? Using a QSplitter to split multiple KHTMLParts? +# Hmm... just wondered... perhaps we can work around that by not showing the +# returned HTML data at all but rather use a XSLT script (that is, one XSLT +# script per web search) which transforms the returned search results into a +# common format - that way, we could also filter out duplicates and then +# transform that filtered output into a nice, uniform HTML page. How about +# that? + +# I like this idea very much, I just thought it and noticed you wrote this +# down already. What I thought of was having a .desktop/.xslt file pair per +# search engine: each .desktop file holds at least the name of the engine (for +# the listview) and a search URI with a placeholder, just like in your scenario. +# In additionl there could be a X-KHelpCenter-XSLT key which defines which .xslt +# stylesheet to use for that particular search engine. We then query that search +# engine by replacing the placeholder in the URI with whatever the user entered +# and hand it to KIO. All the HTML returned by the various search engines gets +# then transformed into a custom, intermediate, XML dialect, using the XSLT +# stylesheets define in the .desktop files. Using that intermediate step we +# can nicely drop duplicate hits, for example, or create a list of hits in the +# sidebar (much like http://www.copernic.com does). After that, we can use +# another XSLT stylesheet to transform that cleaned XML tree into HTML which +# we then feed to our KHTMLView. Since we then have one unified output, we don't +# need to worry about having multiple KHTMLParts, and it's also nice because +# the user doesn't see which search engine returned which hit. + +# A problem with this would be that we cannot tell how a particular search +# engine treats boolean expressions (e.g. some search engines use 'foo AND bar', +# others use '+foo +bar', a third variation is '"foo bar"'). We thus cannot +# replace the placeholder in the URI but first have to translate the syntax +# entered by the user into a syntax which is appropriate for each single news +# engine. Right now I don't know how we could do this with just a .desktop/.xslt +# pair. We could always use fullblown C++ plugins which hold code which is able +# to do that translation, but I would really prefer to stick with .desktop files +# now since they're much easier to create. + +# Another thing which would speak in favor of C++ plugins: different search +# engines support different features (like, google can search more than just the +# web, and you can sometimes tell a search engine to list only results in a +# certain language, or with a certain encoding), so it would be nice if we could +# let the user access those features: through a dialog which has to be tailored +# to the possibilities of the respective search engine. I wonder whether we +# could have some sort of XML tree which defines how an UI should look like, and +# then let KHelpCenter create a dialog using that XML markup, but that idea is +# very vague right now. + +# Hmm, I just tried it and the XSLT idea didn't really take off: the problem +# is that many HTML pages returned by Google, Yahoo & co. don't seem to be +# valid XML, which is why tools such as meinproc or xsltproc refuse to process +# themm. :-/ + +KHC::View +--------- +KHC::View inherits KHTMLPart and does the actual job of showing some sort of +document. Most importantly, it has a slot which passes it a KUrl pointing to a +document to show. KHC::View will invoke kio_help if necessary (if the URL's +protocol == "help") by itself and otherwise use the plain URL. + +# TODO: Things I didn't really think about yet: the interface between the +# navigator and the view. I think this has to be a bidirectional association +# since the navigator can change the view (e.g. by clicking on a manual which +# shows it in the view), but the view can also change the navigator (think of +# clicking on a 'See also' link in the glossary which should also scroll to +# the corresponding entry in the navigator). + +## That's a very important aspect. We should have one central place where all +## document requests are processed and the necessary actions (like updating +## the navigator, loading a new page, caching the search results, etc.) are +## done. +## +## The TreeBuilder might need some interface to tell, if a certain URL exist +## in their tree, to make it possible to select content entries which aren't +## created yet, because they are only created on demand (like the application +## manuals). + +# Very good idea. Perhaps I think iterating over a list of TreeBuilder +# instances and doing something like 'if ((*it)->canHandle(url)) +# (*it)->selectItem(url)' which checks whether a TreeBuilder provides an item +# which corresponds to an URL (hmm, this makes me think, TreeBuilder is a bad +# name. Perhaps just 'Tree'?) and selects it (using +# QListView::ensureItemVisible() or so) if requested. This probably implies. +# that a TreeBuilder needs an internal QMap. + +# Also, the whole search engine needs more thought, that DataCollection idea +# seems promising to me but I'm not yet decided on how to do it properly. + +## See above. We already have something which isn't too bad, I think. + +# I just thought about this a bit, I think KHC::MainWindow should act as the +# interface between KHC::Navigator and KHC::View. + +## I would prefer to have an extra class which does no GUI stuff, but passes +## URL requests around, does the needed processing and stores data, if needed +## (e.g. caching search results). + +# Agreed. + +## One very important aspect of the help center is that it has to be fast. It's +## not acceptable to wait several seconds after clicking on the Help menu of an +## application. We should think about that. Perhaps we can do some tricks like +## showing the main window before creating the other widgets and processing data +## or something similar. We could also think about creating more stuff only on +## demand. + +# My perception is that filling the Navigator's listview takes a significant +# amount of time, just like setting up the KHTML view (loading the stylesheet, +# showing the welcome page). We could easily do taht in the background - show +# the mainwindow, then tell the TreeBuilders to start populating (using a +# QTimer with a timeout of 0, for a snappy GUI). Since they're collapsed at +# the start, the users won't even notice (and we can "fake" that they're +# already populated by calling setExpandable(true) for all of them (or letting +# them do that themselves) at the start. + +## Finally a crazy idea: Wouldn't it be cool, if we would make the manuals more +## interactive. So when you read about a certain menu or a certain dialog of an +## application you can click on a link in the manual and the menu or dialog gets +## opened in the real application, or some widgets get highlghted in the real +## application. Such a feature could also be used to create interactive +## tutorials, where you have a small helpcenter window and the application next +## to each other on the screen and you can go through the tutorial step by step +## and practice with the real application while reading the instructions. +## With the help of DCOP it shouldn't be too hard to implement such an +## interactive help system. Maybe it's even possible to do it in a general way +## in the libs, so that application authors don't have to think about that +## feature. + +# Hmm, that's an interesting idea. That takes KHelpCenter way beyond what it's +# currently doing. I can imagine this: we introduce a virtual "dcop" protocol, +# so that e.g. +# represents the DCOP call 'dcop kfortune KFortuneIface nextfortune'. +# KHelpCenter catches that protocol (oh dear, a lot of special cases with +# gloss, info etc. already - guess another one won't hurt). That looks like a +# good way for encapsulating DCOP calls. +# Now, the problem is - the application has to provide a dedicated +# "documentation" DCOP interface for this, with lots of calls for highlighting +# the various widgets (hm, this probably means taht we can skip the first two +# parts in our 'dcop' URL syntax, the application is known anyway, and the +# interface is hardcoded in KHelpCenter). +# So, what could happen is this: We have a piece of HTML in the documentation +# for our SuperApp application which goes like 'The +#
button labelled Connect makes +# SuperApp establish a connection.' - the user clicks on that link, +# KHelpCenter catches a dcop: URL, checks whether SuperApp has already been +# started. If not, it starts a SuperApp process and does the dcop call 'dcop +# SuperApp DocIface highlightConnectButton' and SuperApp starts highlighting +# that connect button. The thing is that this requires a lot of work on the +# application side. The idea is very cool, but we'd have to think about +# outsourceing parts of that functionality, either to KHelpCenter, or to +# kdelibs. + +## And another idea: The WhatsThis help texts describe all widgets of an +## application (provided that the texts are set by the developers). Currently +## they aren't accessible very easily. You have to go to a special mode and +## can then click on one widget after another to get the help, if there is one. +## There is no visual indication which widgets have help and which not. But the +## application knows about the WhatsThis helps. Perhaps it's possible to use +## the Qt object inspection stuff to extract all the texts and put them on an +## automatically generated screenshot of the corresponding dialog and put this +## graphic into the docs. Maybe it's even possible to do this at run-time and +## decorate dialogs with all WhatsThis helps at once, if the user triggers this +## mode. + +# Hmm yes, that should be possible. Take the toplevel widget, use +# QObject::children() and iterate over all children, use QToolTip::textFor() to +# check whether the given qwidget has a tooltip and if so, use QToolTip::tip() +# to show the tooltip. +# One could probably add a standard dcop call to KMainWindow, like +# "showAllToolTips". KSnapShot could get a QCheckBox "Show all tooltips", and +# if that box is checked it tells the selected window to show all it's +# tooltips via that DCOP call right before it does the snapshot. The thing is +# - is it possible to map the WinID of the window the user clicked on to +# the process name we should send your DCOP call to? + +## One thing we should also keep in mind is that it might be useful to provide +## the help center as a component. FOr example KDevelop has a very similar +## thing. It would be much nicer, if it could reuse the KHelpcenter code. This +## would probbaly also mean to at a DoxygenTreeBuilder or something similar. + +# That probably implies that instead of a QSplitter which holds the Navigator +# and the View, we'd have a KHC::MainWidget KPart which in turn aggregates the +# splitter. The DoxygenTreeBuilder sounds like a reason to make TreeBuilders +# real plugins, with dynamically loaded libraries, so that KDevelop or other +# "IDE"-like applications (perhaps a KOffice help system?) can have their +# customized tree builders. + +Font Configuration +------------------ + +### Many bug reports on KHelpCenter not honouring KHTML font settings, +### which is odd, because the stylesheet is intentionally loose, +### specifying only "sans-serif" as the font face. + +### Ideas to fix: + +### Help pages already make heavy use of the cascading feature of CSS, we +### ought to be able to leverage that by writing to perhaps the +### kde-localized.css file or a copy of it in $KDEHOME. There is already +### code in KControl to create a user CSS stylesheet, and we probably only +### need to configure the size and the face for KHC. + +### Or, fix whatever is the reason KHC doesn't follow the rules. It could +### be encoding related, the help pages specify utf-8 as the encoding, and +### previous incarnations of the KHTML settings allowed fonts set on a +### per-encoding basis (at which time, this was apparently working, the bug +### reports dropped off, and only returned post KDE 3.0 + +# FWIW I added a simple font configuration facility a while back, which should +# IMHO be sufficient for the vast majority of users. + +// vim:tw=78 diff --git a/khelpcenter/Help.desktop b/khelpcenter/Help.desktop new file mode 100755 index 00000000..71505f16 --- /dev/null +++ b/khelpcenter/Help.desktop @@ -0,0 +1,104 @@ +[Desktop Entry] + +Exec=khelpcenter +Icon=help-browser +X-DocPath=khelpcenter/index.html +Type=Application +Terminal=false + +Name=Help +Name[af]=Hulp +Name[ar]=مساعدة +Name[as]=সহায় +Name[ast]=Ayuda +Name[be]=Дапамога +Name[be@latin]=Dapamoha +Name[bg]=Помощ +Name[bn]=সাহায্য +Name[bn_IN]=সাহায্য +Name[br]=Skoazell +Name[bs]=Pomoć +Name[ca]=Ajuda +Name[ca@valencia]=Ajuda +Name[cs]=Nápověda +Name[csb]=Pòmòc +Name[cy]=Cymorth +Name[da]=Hjælp +Name[de]=Hilfe +Name[el]=Βοήθεια +Name[en_GB]=Help +Name[eo]=Helpo +Name[es]=Ayuda +Name[et]=Abi +Name[eu]=Laguntza +Name[fa]=کمک +Name[fi]=Ohjeet +Name[fr]=Aide +Name[fy]=Help +Name[ga]=Cabhair +Name[gl]=Axuda +Name[gu]=મદદ +Name[he]=עזרה +Name[hi]=मदद +Name[hne]=मदद +Name[hr]=Pomoć +Name[hsb]=Pomoc +Name[hu]=Súgó +Name[ia]=Adjuta +Name[id]=Bantuan +Name[is]=Hjálp +Name[it]=Aiuto +Name[ja]=ヘルプ +Name[ka]=დახმარება +Name[kk]=Анықтама +Name[km]=ជំនួយ +Name[kn]=ಸಹಾಯ +Name[ko]=도움말 +Name[ku]=Alîkarî +Name[lt]=Pagalba +Name[lv]=Palīdzība +Name[mai]=मद्दति +Name[mk]=Помош +Name[ml]=സഹായം +Name[mr]=मदत +Name[ms]=Bantuan +Name[nb]=Hjelp +Name[nds]=Hülp +Name[ne]=मद्दत +Name[nl]=Documentatie +Name[nn]=Hjelp +Name[oc]=Ajuda +Name[or]=ସହାୟତା +Name[pa]=ਮੱਦਦ +Name[pl]=Pomoc +Name[pt]=Ajuda +Name[pt_BR]=Ajuda +Name[ro]=Ajutor +Name[ru]=Справка +Name[se]=Veahkki +Name[si]=උදව් +Name[sk]=Pomocník +Name[sl]=Pomoč +Name[sr]=Помоћ +Name[sr@ijekavian]=Помоћ +Name[sr@ijekavianlatin]=Pomoć +Name[sr@latin]=Pomoć +Name[sv]=Hjälp +Name[ta]=உதவி +Name[te]=సహాయం +Name[tg]=Роҳнамо +Name[th]=วิธีใช้ +Name[tr]=Yardım +Name[ug]=ياردەم +Name[uk]=Довідка +Name[uz]=Yordam +Name[uz@cyrillic]=Ёрдам +Name[vi]=Trợ giúp +Name[wa]=Aidance +Name[xh]=Uncedo +Name[x-test]=xxHelpxx +Name[zh_CN]=帮助 +Name[zh_TW]=求助 + +Categories=Qt;KDE;Core; +OnlyShowIn=KDE; diff --git a/khelpcenter/Messages.sh b/khelpcenter/Messages.sh new file mode 100644 index 00000000..435a7f08 --- /dev/null +++ b/khelpcenter/Messages.sh @@ -0,0 +1,4 @@ +#! /usr/bin/env bash +$EXTRACTRC `find . -name "*.kcfg" -o -name "*.rc"` >> rc.cpp || exit 11 +$XGETTEXT *.cpp -o $podir/khelpcenter.pot +rm -f rc.cpp diff --git a/khelpcenter/README.htdig b/khelpcenter/README.htdig new file mode 100644 index 00000000..c4981035 --- /dev/null +++ b/khelpcenter/README.htdig @@ -0,0 +1,14 @@ +To make use of the full-text search function in khelpcenter, +you need ht://dig. + +ht://dig is a HTML indexing and searching tool. + +You can get it from http://www.htdig.org. + +NOTE: If you install htdig from source, make sure +that you put the 'htsearch' as well as the 'htdig' +and 'htmerge' binaries into your PATH. + +Per default, 'htsearch' goes to some cgi-bin +directory. + diff --git a/khelpcenter/README.metadata b/khelpcenter/README.metadata new file mode 100644 index 00000000..6a113cdf --- /dev/null +++ b/khelpcenter/README.metadata @@ -0,0 +1,128 @@ +KHelpCenter documentation meta data structure +============================================= + +KHelpCenter uses meta data files which describe the documentation available in +the system. Each document is represented by a meta data file and shown as an +entry in the KHelpCenter navigation tree view. The meta data contains +information about title and short description of the document, the location of +the document and some more information like how to search the document and +translations of title and description. Document hierarchy is represented as +hierarchy of the meta data files. Directories are also described by a meta data +file which contains the same information as a document meta data file. + +Format of the meta data files +----------------------------- + +The meta files adhere to the Desktop Entry Standard +(http://www.freedesktop.org/Standards/desktop-entry-spec). Documentation +specific extensions are covered by an own namespace using the prefix "X-DOC-". +The following table describes all keys which are currently used by +KHelpCenter: + +Key Value Description + +Name string Title of document +Name[xx] string Translated title for language xx +Comment string Short description of document +Comment[xx] string Translated short description for + Language xx +Icon string Name of icon for document +X-DocPath URI Location of document. In addition to the + standard URI schemes like http: and file: + all schemes which are supported through + kioslaves can be used. In particular the + following non-standard URI schemes are + supported: + help: KDE manual identified by app name + ghelp: GNOME manual identified by app name + man: man page + info: info page + cgi: output of CGI script +X-DocPath[xx] URI Language specific location for + language xx +Lang langcode Language of document +X-DOC-Identifier string Unique identifier for document, if this + entry is not present the base name of the + file is used as identifier +X-DOC-Indexer command Command used for creating a search index + for the document. + The following symbols are replaced by the + corresponding values: + %f - Filename +X-DOC-IndexTestFile filename Name of file whose existence indicates + the existence of a usable search index +X-DOC-Search command Command used for searching, the output + of the command should be HTML which is + shown in KHelpCenter. + The following symbols in the command are + replaced by the corresponding values: + %k - Words to be searched for + %n - Maximum number of results + %m - Method for combining search words, + can be 'and' or 'or' + %l - Language of documents to be searched + %s - Scope of search. This is a list of + identifiers as given by the + X-DOC-Identifier entry or the bas + name of the desktop file if not + present. +X-DOC-SearchMethod string If this entry is 'htdig' htdig is used to + index and search the document. The + Indexer, IndexTestFile and Search entries + aren't required in this case. +X-DOC-SearchEnabledDefault bool If set to 'true' the document is searched + by default, if set to 'false' it is not. + This setting is overridden by user + selected search scopes. +X-DOC-Weight int A number indicating the position of the + document within the list of siblings. A + greater weight indicates that the document + is 'heavier', thus shown below 'lighter' + documents. The default weight is 0. +X-KDE-KHelpcenter string If this entry is set to one of the + following values a set of documents + generated by other means than desktop file + meta info is inserted at the place + specified by the desktop file: + 'apps' manuals of applications + from the start menu + 'scrollkeeper' scrollkeeper docs + 'kinfocenter' kinfocenter docs + 'kcontrol' kcontrol module docs + 'konqueror' konqueror plugin docs + 'kioslave' kioslave docs + 'info' info pages +X-DOC-DocumentType string Type of document. The type is used to look + up corresponding search handlers. + +Meta File Location +------------------ + +A list of directories given by the config entry "MetaInfoDirs" in the "General" +group of the help center configuration file "khelpcenterrc" (at +$KDEDIRS/share/config) is scanned for desktop files. They are merged to a common +hierarchy. If the "MetaInfoDirs" entry is empty the directory at +$KDEDIRS/share/apps/khelpcenter/plugins is used. + +Document Hierarchy +------------------ + +The hierarchy of the documents shown in the help center is reflected by the +hierarchy of the desktop files in the filesystem. Directories can have an +associated desktop file with the name ".directory". It can contain all the +keys described above. + +Language handling +----------------- + +In addition to translation of meta information like title and short description +of documents which is contained in the meta file, translations of whole +documents are handled. Each translation of a document has an own desktop file. +The language of the document is indicated by adding the language code as +additional suffix to the filename of the desktop file. The language suffix +is added before the ".desktop" suffix (Example: 'apache.de.desktop' would be the +file name for the german translation of the apache documentation). + +KHelpCenter shows only the documents whose language is contained in the list of +used languages configured for the desktop in the control center. A document +corresponding to a desktop file without language suffix is always shown. diff --git a/khelpcenter/application.cpp b/khelpcenter/application.cpp new file mode 100644 index 00000000..7f3d8b6a --- /dev/null +++ b/khelpcenter/application.cpp @@ -0,0 +1,90 @@ + +/* + * This file is part of the KDE Help Center + * + * Copyright (c) 2002 Frerich Raabe + * + * 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 "application.h" +#include "mainwindow.h" +#include "version.h" + +#include +#include +#include + +using namespace KHC; + +Application::Application() : KUniqueApplication(), mMainWindow( 0 ) +{ +} + +int Application::newInstance() +{ + if (restoringSession()) return 0; + + KCmdLineArgs *args = KCmdLineArgs::parsedArgs(); + + KUrl url; + if ( args->count() ) + url = args->url( 0 ); + + if( !mMainWindow ) + { + mMainWindow = new MainWindow; + mMainWindow->show(); + } + + mMainWindow->openUrl( url ); + + return KUniqueApplication::newInstance(); +} + +extern "C" int KDE_EXPORT kdemain( int argc, char **argv ) +{ + KAboutData aboutData( "khelpcenter", 0, ki18n("KDE Help Center"), + HELPCENTER_VERSION, + ki18n("The KDE Help Center"), + KAboutData::License_GPL, + ki18n("(c) 1999-2011, The KHelpCenter developers") ); + + aboutData.addAuthor( ki18n("Cornelius Schumacher"), KLocalizedString(), "schumacher@kde.org" ); + aboutData.addAuthor( ki18n("Frerich Raabe"), KLocalizedString(), "raabe@kde.org" ); + aboutData.addAuthor( ki18n("Matthias Elter"), ki18n("Original Author"), + "me@kde.org" ); + aboutData.addAuthor( ki18n("Wojciech Smigaj"), ki18n("Info page support"), + "achu@klub.chip.pl" ); + aboutData.setProgramIconName( "help-browser" ); + + KCmdLineArgs::init( argc, argv, &aboutData ); + + KCmdLineOptions options; + options.add("+[url]", ki18n("URL to display")); + KCmdLineArgs::addCmdLineOptions( options ); + KCmdLineArgs::addStdCmdLineOptions(); + + KHC::Application app; + + if ( app.isSessionRestored() ) + { + RESTORE( MainWindow ); + } + + return app.exec(); +} + +// vim:ts=2:sw=2:et diff --git a/khelpcenter/application.h b/khelpcenter/application.h new file mode 100644 index 00000000..0d5cf416 --- /dev/null +++ b/khelpcenter/application.h @@ -0,0 +1,47 @@ + +/* + * This file is part of the KDE Help Center + * + * Copyright (C) 2002 Frerich Raabe + * + * 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. + */ + +#ifndef KHC_APPLICATION_H +#define KHC_APPLICATION_H + +#include + +namespace KHC { + + class MainWindow; + + class Application : public KUniqueApplication + { + public: + Application(); + + virtual int newInstance(); + + private: + MainWindow *mMainWindow; + }; + +} + +extern "C" { int KDE_EXPORT kdemain(int argc, char **argv); } + +#endif // KHC_APPLICATION_H +// vim:ts=2:sw=2:et diff --git a/khelpcenter/docentry.cpp b/khelpcenter/docentry.cpp new file mode 100644 index 00000000..bd74e226 --- /dev/null +++ b/khelpcenter/docentry.cpp @@ -0,0 +1,359 @@ +#include "docentry.h" + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "prefs.h" + +using namespace KHC; + +DocEntry::DocEntry() +{ + init(); +} + +DocEntry::DocEntry( const QString &name, const QString &url, + const QString &icon ) +{ + init(); + + mName = name; + mUrl = url; + mIcon = icon; +} + +void DocEntry::init() +{ + mWeight = 0; + mSearchEnabled = false; + mDirectory = false; + mParent = 0; + mNextSibling = 0; +} + +void DocEntry::setName( const QString &name ) +{ + mName = name; +} + +QString DocEntry::name() const +{ + return mName; +} + +void DocEntry::setSearch( const QString &search ) +{ + mSearch = search; +} + +QString DocEntry::search() const +{ + return mSearch; +} + +void DocEntry::setIcon( const QString &icon ) +{ + mIcon = icon; +} + +QString DocEntry::icon() const +{ + if ( !mIcon.isEmpty() ) return mIcon; + if ( !docExists() ) return QLatin1String("unknown"); + if ( isDirectory() ) return QLatin1String("help-contents"); + + else return "text-plain"; +} + +void DocEntry::setUrl( const QString &url ) +{ + mUrl = url; +} + +QString DocEntry::url() const +{ + if ( !mUrl.isEmpty() ) return mUrl; + if ( identifier().isEmpty() ) return QString(); + + return "khelpcenter:" + identifier(); +} + +void DocEntry::setInfo( const QString &info ) +{ + mInfo = info; +} + +QString DocEntry::info() const +{ + return mInfo; +} + +void DocEntry::setLang( const QString &lang ) +{ + mLang = lang; +} + +QString DocEntry::lang() const +{ + return mLang; +} + +void DocEntry::setIdentifier( const QString &identifier ) +{ + mIdentifier = identifier; +} + +QString DocEntry::identifier() const +{ + if ( mIdentifier.isEmpty() ) mIdentifier = KRandom::randomString( 15 ); + return mIdentifier; +} + +void DocEntry::setIndexer( const QString &indexer ) +{ + mIndexer = indexer; +} + +QString DocEntry::indexer() const +{ + return mIndexer; +} + +void DocEntry::setIndexTestFile( const QString &indexTestFile ) +{ + mIndexTestFile = indexTestFile; +} + +QString DocEntry::indexTestFile() const +{ + return mIndexTestFile; +} + +void DocEntry::setWeight( int weight ) +{ + mWeight = weight; +} + +int DocEntry::weight() const +{ + return mWeight; +} + +void DocEntry::setSearchMethod( const QString &method ) +{ + mSearchMethod = method; +} + +QString DocEntry::searchMethod() const +{ + return mSearchMethod; +} + +void DocEntry::setDocumentType( const QString &str ) +{ + mDocumentType = str; +} + +QString DocEntry::documentType() const +{ + return mDocumentType; +} + +QString DocEntry::khelpcenterSpecial() const +{ + return mKhelpcenterSpecial; +} + +void DocEntry::enableSearch( bool enabled ) +{ + mSearchEnabled = enabled; +} + +bool DocEntry::searchEnabled() const +{ + return mSearchEnabled; +} + +void DocEntry::setSearchEnabledDefault( bool enabled ) +{ + mSearchEnabledDefault = enabled; +} + +bool DocEntry::searchEnabledDefault() const +{ + return mSearchEnabledDefault; +} + +void DocEntry::setDirectory( bool dir ) +{ + mDirectory = dir; +} + +bool DocEntry::isDirectory() const +{ + return mDirectory; +} + +bool DocEntry::readFromFile( const QString &fileName ) +{ + KDesktopFile file( fileName ); + KConfigGroup desktopGroup = file.desktopGroup(); + + mName = file.readName(); + mSearch = desktopGroup.readEntry( "X-DOC-Search" ); + mIcon = file.readIcon(); + mUrl = file.readDocPath(); + mInfo = desktopGroup.readEntry( "Info" ); + if ( mInfo.isNull() ) + { + mInfo = desktopGroup.readEntry( "Comment" ); + } + mLang = desktopGroup.readEntry( "Lang", "en" ); + mIdentifier = desktopGroup.readEntry( "X-DOC-Identifier" ); + if ( mIdentifier.isEmpty() ) + { + QFileInfo fi( fileName ); + mIdentifier = fi.completeBaseName(); + } + mIndexer = desktopGroup.readEntry( "X-DOC-Indexer" ); + mIndexer.replace( "%f", fileName ); + mIndexTestFile = desktopGroup.readEntry( "X-DOC-IndexTestFile" ); + mSearchEnabledDefault = desktopGroup.readEntry( "X-DOC-SearchEnabledDefault", + false ); + mSearchEnabled = mSearchEnabledDefault; + mWeight = desktopGroup.readEntry( "X-DOC-Weight", 0 ); + mSearchMethod = desktopGroup.readEntry( "X-DOC-SearchMethod" ); + mDocumentType = desktopGroup.readEntry( "X-DOC-DocumentType" ); + + mKhelpcenterSpecial = desktopGroup.readEntry("X-KDE-KHelpcenter-Special"); + + return true; +} + +bool DocEntry::indexExists( const QString &indexDir ) +{ + QString testFile; + if ( mIndexTestFile.isEmpty() ) + { + testFile = identifier() + QLatin1String(".exists"); + } else { + testFile = mIndexTestFile; + } + + if ( !testFile.startsWith( QLatin1Char('/') ) ) testFile = indexDir + QLatin1Char('/') + testFile; + return QFile::exists( testFile ); +} + +bool DocEntry::docExists() const +{ + if ( !mUrl.isEmpty() ) + { + KUrl docUrl( mUrl ); + if ( docUrl.isLocalFile() && !KStandardDirs::exists( docUrl.toLocalFile() ) ) + { + return false; + } + } + + return true; +} + +void DocEntry::addChild( DocEntry *entry ) +{ + entry->setParent( this ); + + int i; + for( i = 0; i < mChildren.count(); ++i ) + { + if ( i == 0 ) { + if ( entry->weight() < mChildren.first()->weight() ) + { + entry->setNextSibling( mChildren.first() ); + mChildren.prepend( entry ); + break; + } + } + if ( i + 1 < mChildren.count() ) + { + if ( entry->weight() >= mChildren[ i ]->weight() && + entry->weight() < mChildren[ i + 1 ]->weight() ) + { + entry->setNextSibling( mChildren[ i + 1 ] ); + mChildren[ i ]->setNextSibling( entry ); + mChildren.insert( mChildren.indexOf(mChildren.at( i + 1 )), entry ); + break; + } + } + } + if ( i == mChildren.count() ) + { + if ( i > 0 ) + { + mChildren.last()->setNextSibling( entry ); + } + mChildren.append( entry ); + } +} + +bool DocEntry::hasChildren() +{ + return mChildren.count(); +} + +DocEntry *DocEntry::firstChild() +{ + return mChildren.first(); +} + +DocEntry::List DocEntry::children() +{ + return mChildren; +} + +void DocEntry::setParent( DocEntry *parent ) +{ + mParent = parent; +} + +DocEntry *DocEntry::parent() +{ + return mParent; +} + +void DocEntry::setNextSibling( DocEntry *next ) +{ + mNextSibling = next; +} + +DocEntry *DocEntry::nextSibling() +{ + return mNextSibling; +} + +bool DocEntry::isSearchable() +{ + return !search().isEmpty() && docExists() && + indexExists( Prefs::indexDirectory() ); +} + +void DocEntry::dump() const +{ + kDebug() << " "; + kDebug() << " " << mName << ""; + kDebug() << " " << mSearchMethod << ""; + kDebug() << " " << mSearch << ""; + kDebug() << " " << mIndexer << ""; + kDebug() << " " << mIndexTestFile << ""; + kDebug() << " " << mIcon << ""; + kDebug() << " " << mUrl << ""; + kDebug() << " " << mDocumentType << ""; + kDebug() << " "; +} +// vim:ts=2:sw=2:et diff --git a/khelpcenter/docentry.h b/khelpcenter/docentry.h new file mode 100644 index 00000000..8af4e779 --- /dev/null +++ b/khelpcenter/docentry.h @@ -0,0 +1,118 @@ + +#ifndef KHC_DOCENTRY_H +#define KHC_DOCENTRY_H + +#include +#include + +namespace KHC { + + class DocEntry + { + public: + typedef QList List; + + DocEntry(); + + explicit DocEntry( const QString &name, const QString &url = QString(), + const QString &icon = QString() ); + + void setName( const QString & ); + QString name() const; + + void setSearch( const QString & ); + QString search() const; + + void setIcon( const QString & ); + QString icon() const; + + void setUrl( const QString & ); + QString url() const; + + void setInfo( const QString & ); + QString info() const; + + void setLang( const QString & ); + QString lang() const; + + void setIdentifier( const QString & ); + QString identifier() const; + + void setIndexer( const QString & ); + QString indexer() const; + + void setIndexTestFile( const QString & ); + QString indexTestFile() const; + + void setWeight( int ); + int weight() const; + + void setSearchMethod( const QString & ); + QString searchMethod() const; + + void enableSearch( bool enabled ); + bool searchEnabled() const; + + void setSearchEnabledDefault( bool enabled ); + bool searchEnabledDefault() const; + + void setDocumentType( const QString & ); + QString documentType() const; + + void setDirectory( bool ); + bool isDirectory() const; + + bool readFromFile( const QString &fileName ); + + bool indexExists( const QString &indexDir ); + + bool docExists() const; + + void addChild( DocEntry * ); + bool hasChildren(); + DocEntry *firstChild(); + List children(); + + void setParent( DocEntry * ); + DocEntry *parent(); + + void setNextSibling( DocEntry * ); + DocEntry *nextSibling(); + + QString khelpcenterSpecial() const; + + bool isSearchable(); + + void dump() const; + + protected: + void init(); + + private: + QString mName; + QString mSearch; + QString mIcon; + QString mUrl; + QString mInfo; + QString mLang; + mutable QString mIdentifier; + QString mIndexer; + QString mIndexTestFile; + int mWeight; + QString mSearchMethod; + bool mSearchEnabled; + bool mSearchEnabledDefault; + QString mDocumentType; + bool mDirectory; + + QString mKhelpcenterSpecial; + + List mChildren; + DocEntry *mParent; + DocEntry *mNextSibling; + }; + +} + +#endif //KHC_DOCENTRY_H +// vim:ts=2:sw=2:et diff --git a/khelpcenter/docentrytraverser.cpp b/khelpcenter/docentrytraverser.cpp new file mode 100644 index 00000000..aa4383ac --- /dev/null +++ b/khelpcenter/docentrytraverser.cpp @@ -0,0 +1,69 @@ + +/* This file is part of the KDE project + * Copyright 2002 Cornelius Schumacher + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License version 2 or at your option version 3 as published + * by the Free Software Foundation. + * + * 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; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "docentrytraverser.h" +#include "docmetainfo.h" + +using namespace KHC; + +void DocEntryTraverser::setNotifyee( DocMetaInfo *n ) +{ + mNotifyee = n; +} + +void DocEntryTraverser::startProcess( DocEntry *entry ) +{ + process( entry ); + mNotifyee->endProcess( entry, this ); +} + +DocEntryTraverser *DocEntryTraverser::childTraverser( DocEntry *parentEntry ) +{ + DocEntryTraverser *child = createChild( parentEntry ); + if (!child) + return 0; + if ( child != this ) + { + child->mParent = this; + child->mNotifyee = mNotifyee; + } + return child; +} + +DocEntryTraverser *DocEntryTraverser::parentTraverser() +{ + return mParent; +} + +void DocEntryTraverser::deleteTraverser() +{ + delete this; +} + +void DocEntryTraverser::setParentEntry( DocEntry *entry ) +{ + mParentEntry = entry; +} + +DocEntry *DocEntryTraverser::parentEntry() +{ + return mParentEntry; +} +// vim:ts=2:sw=2:et diff --git a/khelpcenter/docentrytraverser.h b/khelpcenter/docentrytraverser.h new file mode 100644 index 00000000..ee3ffa48 --- /dev/null +++ b/khelpcenter/docentrytraverser.h @@ -0,0 +1,64 @@ + +/* This file is part of the KDE project + Copyright 2002 Cornelius Schumacher + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public + License version 2 or at your option version 3 as published + by the Free Software Foundation. + + 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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef KHC_DOCENTRYTRAVERSER_H +#define KHC_DOCENTRYTRAVERSER_H + +namespace KHC { + + class DocEntry; + class DocMetaInfo; + + class DocEntryTraverser + { + public: + DocEntryTraverser() : mNotifyee( 0 ), mParent( 0 ), mParentEntry( 0 ) {} + virtual ~DocEntryTraverser() {} + + void setNotifyee( DocMetaInfo * ); + + virtual void process( DocEntry * ) = 0; + + virtual void startProcess( DocEntry * ); + + virtual DocEntryTraverser *createChild( DocEntry *parentEntry ) = 0; + + virtual void deleteTraverser(); + + virtual void finishTraversal() {} + + DocEntryTraverser *childTraverser( DocEntry *parentEntry ); + virtual DocEntryTraverser *parentTraverser(); + + void setParentEntry( DocEntry * ); + DocEntry *parentEntry(); + + protected: + DocMetaInfo *mNotifyee; + DocEntryTraverser *mParent; + + private: + DocEntry *mParentEntry; + }; + +} + +#endif //KHC_DOCENTRYTRAVERSER_H +// vim:ts=2:sw=2:et diff --git a/khelpcenter/docmetainfo.cpp b/khelpcenter/docmetainfo.cpp new file mode 100644 index 00000000..3de13bcb --- /dev/null +++ b/khelpcenter/docmetainfo.cpp @@ -0,0 +1,327 @@ + +/* This file is part of the KDE project + * Copyright 2002 Cornelius Schumacher + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License version 2 or at your option version 3 as published + * by the Free Software Foundation. + * + * 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; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "docmetainfo.h" + +#include + +#include +#include +#include +#include +#include + +#include "htmlsearch.h" +#include "docentrytraverser.h" + +using namespace KHC; + +bool DocMetaInfo::mLoaded = false; + +DocMetaInfo *DocMetaInfo::mSelf = 0; + +DocMetaInfo *DocMetaInfo::self() +{ + if ( !mSelf ) mSelf = new DocMetaInfo; + return mSelf; +} + +DocMetaInfo::DocMetaInfo() +{ + kDebug() << "DocMetaInfo()"; + + mHtmlSearch = new HTMLSearch; + + mRootEntry.setName( i18n("Top-Level Documentation") ); +} + +DocMetaInfo::~DocMetaInfo() +{ + kDebug() << "~DocMetaInfo()"; + + DocEntry::List::ConstIterator it; + for( it = mDocEntries.constBegin(); it != mDocEntries.constEnd(); ++it ) + { + delete *it; + } + + delete mHtmlSearch; + + mLoaded = false; + + mSelf = 0; +} + +DocEntry *DocMetaInfo::addDocEntry( const QString &fileName ) +{ + QFileInfo fi( fileName ); + if ( !fi.exists() ) return 0; + + QString extension = fi.completeSuffix(); + QStringList extensions = extension.split( '.'); + QString lang; + if ( extensions.count() >= 2 ) + { + lang = extensions[ extensions.count() - 2 ]; + } + + if ( !lang.isEmpty() && !mLanguages.contains( lang ) ) + { + return 0; + } + + DocEntry *entry = new DocEntry(); + + if ( entry->readFromFile( fileName ) ) + { + if ( !lang.isEmpty() && lang != mLanguages.first() ) + { + entry->setLang( lang ); + entry->setName( i18nc("doctitle (language)","%1 (%2)", + entry->name() , + mLanguageNames[ lang ] ) ); + } + if ( entry->searchMethod().toLower() == "htdig" ) + { + mHtmlSearch->setupDocEntry( entry ); + } + QString indexer = entry->indexer(); + indexer.replace( "%f", fileName ); + entry->setIndexer( indexer ); + addDocEntry( entry ); + return entry; + } + else + { + delete entry; + return 0; + } +} + +void DocMetaInfo::addDocEntry( DocEntry *entry ) +{ + mDocEntries.append( entry ); + if ( !entry->search().isEmpty() ) mSearchEntries.append( entry ); +} + +DocEntry::List DocMetaInfo::docEntries() +{ + return mDocEntries; +} + +DocEntry::List DocMetaInfo::searchEntries() +{ + return mSearchEntries; +} + +QString DocMetaInfo::languageName( const QString &langcode ) +{ + if ( langcode == "en" ) return i18nc("Describes documentation entries that are in English","English"); + + QString cfgfile = KStandardDirs::locate( "locale", + QString::fromLatin1( "%1/entry.desktop" ).arg( langcode ) ); + + kDebug() << "-- langcode: " << langcode << " cfgfile: " << cfgfile; + + KConfig _cfg( cfgfile, KConfig::SimpleConfig ); + KConfigGroup cfg(&_cfg, "KCM Locale" ); + QString name = cfg.readEntry( "Name", langcode ); + + return name; +} + +void DocMetaInfo::scanMetaInfo( bool force ) +{ + if ( mLoaded && !force ) return; + + mLanguages = KGlobal::locale()->languageList(); + + kDebug( 1400 ) << "LANGS: " << mLanguages.join( QLatin1String(" ") ); + + QStringList::ConstIterator it; + for( it = mLanguages.constBegin(); it != mLanguages.constEnd(); ++it ) + { + mLanguageNames.insert( *it, languageName( *it ) ); + } + + KConfig config( QLatin1String("khelpcenterrc") ); + KConfigGroup cg(&config, "General"); + QStringList metaInfos = cg.readEntry( "MetaInfoDirs" , QStringList() ); + + if ( metaInfos.isEmpty() ) + { + KStandardDirs* kstd = KGlobal::dirs(); + metaInfos = kstd->findDirs( "appdata", "plugins" ); + } + for( it = metaInfos.constBegin(); it != metaInfos.constEnd(); ++it) + { + kDebug() << "DocMetaInfo::scanMetaInfo(): scanning " << *it; + scanMetaInfoDir( *it, &mRootEntry ); + } + + mLoaded = true; +} + +DocEntry *DocMetaInfo::scanMetaInfoDir( const QString &dirName, + DocEntry *parent ) +{ + QDir dir( dirName ); + if ( !dir.exists() ) return 0; + + foreach( const QFileInfo &fi, dir.entryInfoList(QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot) ) + { + DocEntry *entry = 0; + if ( fi.isDir() ) + { + DocEntry *dirEntry = addDirEntry( QDir( fi.absoluteFilePath() ), parent ); + entry = scanMetaInfoDir( fi.absoluteFilePath(), dirEntry ); + } + else if ( fi.suffix() == QLatin1String("desktop") ) + { + entry = addDocEntry( fi.absoluteFilePath() ); + if ( parent && entry ) parent->addChild( entry ); + } + } + + return 0; +} + +DocEntry *DocMetaInfo::addDirEntry( const QDir &dir, DocEntry *parent ) +{ + DocEntry *dirEntry = addDocEntry( dir.absolutePath() + QLatin1String("/.directory") ); + + if ( !dirEntry ) + { + dirEntry = new DocEntry; + dirEntry->setName( dir.dirName() ); + addDocEntry( dirEntry ); + } + + dirEntry->setDirectory( true ); + if ( parent ) parent->addChild( dirEntry ); + + return dirEntry; +} + + +void DocMetaInfo::traverseEntries( DocEntryTraverser *traverser ) +{ + traverseEntry( &mRootEntry, traverser ); +} + +void DocMetaInfo::traverseEntry( DocEntry *entry, DocEntryTraverser *traverser ) +{ + DocEntry::List children = entry->children(); + DocEntry::List::ConstIterator it; + for( it = children.constBegin(); it != children.constEnd(); ++it ) + { + if ( (*it)->isDirectory() && !(*it)->hasChildren() && + (*it)->khelpcenterSpecial().isEmpty() ) continue; + traverser->process( *it ); + if ( (*it)->hasChildren() ) + { + DocEntryTraverser *t = traverser->childTraverser( *it ); + if (t) + { + traverseEntry( *it, t ); + t->deleteTraverser(); + } + } + } +} + +void DocMetaInfo::startTraverseEntries( DocEntryTraverser *traverser ) +{ + kDebug() << "DocMetaInfo::startTraverseEntries()"; + traverser->setNotifyee( this ); + startTraverseEntry( &mRootEntry, traverser ); +} + +void DocMetaInfo::startTraverseEntry( DocEntry *entry, + DocEntryTraverser *traverser ) +{ + if ( !traverser ) + { + kDebug() << "DocMetaInfo::startTraverseEntry(): ERROR. No Traverser." + << endl; + return; + } + + if ( !entry ) + { + kDebug() << "DocMetaInfo::startTraverseEntry(): no entry."; + endTraverseEntries( traverser ); + return; + } + + traverser->startProcess( entry ); +} + +void DocMetaInfo::endProcess( DocEntry *entry, DocEntryTraverser *traverser ) +{ + if ( !entry ) + { + endTraverseEntries( traverser ); + return; + } + + if ( entry->hasChildren() ) + { + startTraverseEntry( entry->firstChild(), traverser->childTraverser( entry ) ); + } else if ( entry->nextSibling() ) + { + startTraverseEntry( entry->nextSibling(), traverser ); + } else + { + DocEntry *parent = entry->parent(); + DocEntryTraverser *parentTraverser = 0; + while ( parent ) { + parentTraverser = traverser->parentTraverser(); + traverser->deleteTraverser(); + if ( parent->nextSibling() ) { + startTraverseEntry( parent->nextSibling(), parentTraverser ); + break; + } + else + { + parent = parent->parent(); + traverser = parentTraverser; + } + } + if ( !parent ) + { + endTraverseEntries( traverser ); + } + } +} + +void DocMetaInfo::endTraverseEntries( DocEntryTraverser *traverser ) +{ + kDebug() << "DocMetaInfo::endTraverseEntries()"; + + if ( !traverser ) + { + kDebug() << " no more traversers."; + return; + } + + traverser->finishTraversal(); +} +// vim:ts=2:sw=2:et diff --git a/khelpcenter/docmetainfo.h b/khelpcenter/docmetainfo.h new file mode 100644 index 00000000..72383ca7 --- /dev/null +++ b/khelpcenter/docmetainfo.h @@ -0,0 +1,97 @@ + +/* This file is part of the KDE project + Copyright 2002 Cornelius Schumacher + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public + License version 2 or at your option version 3 as published + by the Free Software Foundation. + + 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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef KHC_DOCMETAINFO_H +#define KHC_DOCMETAINFO_H + +#include +#include + +#include "docentry.h" + +namespace KHC { + + class HTMLSearch; + class DocEntryTraverser; + + /*! + This class provides some meta information about help documents. + */ + class DocMetaInfo + { + public: + /*! + Return instance of DocMetaInfo. There can only be one instance at a time. + */ + static DocMetaInfo *self(); + + ~DocMetaInfo(); + + void scanMetaInfo( bool force = false ); + + DocEntry *addDocEntry( const QString &fileName ); + + void addDocEntry( DocEntry * ); + + DocEntry::List docEntries(); + + DocEntry::List searchEntries(); + + void traverseEntries( DocEntryTraverser * ); + + void startTraverseEntries( DocEntryTraverser *traverser ); + void startTraverseEntry( DocEntry *entry, DocEntryTraverser *traverser ); + void endProcess( DocEntry *entry, DocEntryTraverser *traverser ); + void endTraverseEntries( DocEntryTraverser * ); + + static QString languageName( const QString &langcode ); + + protected: + DocEntry *scanMetaInfoDir( const QString &filename, DocEntry *parent ); + DocEntry *addDirEntry( const QDir &dir, DocEntry *parent ); + void traverseEntry( DocEntry *, DocEntryTraverser * ); + + private: + /*! + DocMetaInfo is a singleton. Private constructor prevents direct + instantisation. + */ + DocMetaInfo(); + + DocEntry::List mDocEntries; + DocEntry::List mSearchEntries; + + DocEntry mRootEntry; + + QStringList mLanguages; + + QMap mLanguageNames; + + HTMLSearch *mHtmlSearch; + + static bool mLoaded; + + static DocMetaInfo *mSelf; + }; + +} + +#endif //KHC_DOCMETAINFO_H +// vim:ts=2:sw=2:et diff --git a/khelpcenter/fontdialog.cpp b/khelpcenter/fontdialog.cpp new file mode 100644 index 00000000..50a220ba --- /dev/null +++ b/khelpcenter/fontdialog.cpp @@ -0,0 +1,228 @@ + +/* + * This file is part of the KDE Help Center + * + * Copyright (C) 2003 Frerich Raabe + * + * 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 "fontdialog.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +using namespace KHC; + +FontDialog::FontDialog( QWidget *parent ) + : KDialog( parent ) +{ + setModal( true ); + setCaption( i18n( "Font Configuration" ) ); + setButtons( Ok | Cancel ); + + m_mainWidget = new KVBox( this ); + setMainWidget( m_mainWidget ); + + setupFontSizesBox(); + setupFontTypesBox(); + setupFontEncodingBox(); + + load(); + + connect( this, SIGNAL( okClicked() ), SLOT( slotOk() ) ); +} + +void FontDialog::slotOk() +{ + save(); + accept(); +} + +void FontDialog::setupFontSizesBox() +{ + QGroupBox *gb = new QGroupBox( i18n( "Sizes" ), m_mainWidget ); + + QGridLayout *layout = new QGridLayout( gb ); + layout->setSpacing( KDialog::spacingHint() ); + layout->setMargin( KDialog::marginHint() * 2 ); + + QLabel *lMinFontSize = new QLabel( i18nc( "The smallest size a will have", "M&inimum font size:" ), gb ); + layout->addWidget( lMinFontSize, 0, 0 ); + m_minFontSize = new KIntNumInput( gb ); + layout->addWidget( m_minFontSize, 0, 1 ); + m_minFontSize->setRange( 1, 20 ); + lMinFontSize->setBuddy( m_minFontSize ); + + QLabel *lMedFontSize = new QLabel( i18nc( "The normal size a font will have", "M&edium font size:" ), gb ); + layout->addWidget( lMedFontSize, 1, 0 ); + m_medFontSize = new KIntNumInput( gb ); + layout->addWidget( m_medFontSize, 1, 1 ); + m_medFontSize->setRange( 4, 28 ); + lMedFontSize->setBuddy( m_medFontSize ); +} + +void FontDialog::setupFontTypesBox() +{ + QGroupBox *gb = new QGroupBox( i18n( "Fonts" ), m_mainWidget ); + + QGridLayout *layout = new QGridLayout( gb ); + layout->setSpacing( KDialog::spacingHint() ); + layout->setMargin( KDialog::marginHint() * 2 ); + + QLabel *lStandardFont = new QLabel( i18n( "S&tandard font:" ), gb ); + layout->addWidget( lStandardFont, 0, 0 ); + m_standardFontCombo = new KFontComboBox( gb ); + layout->addWidget( m_standardFontCombo, 0, 1 ); + lStandardFont->setBuddy( m_standardFontCombo ); + + QLabel *lFixedFont = new QLabel( i18n( "F&ixed font:" ), gb ); + layout->addWidget( lFixedFont, 1, 0 ); + m_fixedFontCombo = new KFontComboBox( gb ); + layout->addWidget( m_fixedFontCombo, 1, 1 ); + lFixedFont->setBuddy( m_fixedFontCombo ); + + QLabel *lSerifFont = new QLabel( i18n( "S&erif font:" ), gb ); + layout->addWidget( lSerifFont, 2, 0 ); + m_serifFontCombo = new KFontComboBox( gb ); + layout->addWidget( m_serifFontCombo, 2, 1 ); + lSerifFont->setBuddy( m_serifFontCombo ); + + QLabel *lSansSerifFont = new QLabel( i18n( "S&ans serif font:" ), gb ); + layout->addWidget( lSansSerifFont, 3, 0 ); + m_sansSerifFontCombo = new KFontComboBox( gb ); + layout->addWidget( m_sansSerifFontCombo, 3, 1 ); + lSansSerifFont->setBuddy( m_sansSerifFontCombo ); + + QLabel *lItalicFont = new QLabel( i18n( "&Italic font:" ), gb ); + layout->addWidget( lItalicFont, 4, 0 ); + m_italicFontCombo = new KFontComboBox( gb ); + layout->addWidget( m_italicFontCombo, 4, 1 ); + lItalicFont->setBuddy( m_italicFontCombo ); + + QLabel *lFantasyFont = new QLabel( i18n( "&Fantasy font:" ), gb ); + layout->addWidget( lFantasyFont, 5, 0 ); + m_fantasyFontCombo = new KFontComboBox( gb ); + layout->addWidget( m_fantasyFontCombo, 5, 1 ); + lFantasyFont->setBuddy( m_fantasyFontCombo ); +} + +void FontDialog::setupFontEncodingBox() +{ + QGroupBox *gb = new QGroupBox( i18n( "Encoding" ), m_mainWidget ); + + QGridLayout *layout = new QGridLayout( gb ); + layout->setSpacing( KDialog::spacingHint() ); + layout->setMargin( KDialog::marginHint() * 2 ); + + QLabel *lDefaultEncoding = new QLabel( i18n( "&Default encoding:" ), gb ); + layout->addWidget( lDefaultEncoding, 0, 0 ); + m_defaultEncoding = new KComboBox( false, gb ); + layout->addWidget( m_defaultEncoding, 0, 1 ); + QStringList encodings = KGlobal::charsets()->availableEncodingNames(); + encodings.prepend( i18n( "Use Language Encoding" ) ); + m_defaultEncoding->addItems( encodings ); + lDefaultEncoding->setBuddy( m_defaultEncoding ); + + QLabel *lFontSizeAdjustement = new QLabel( i18n( "&Font size adjustment:" ), gb ); + layout->addWidget( lFontSizeAdjustement, 1, 0 ); + m_fontSizeAdjustement = new KIntSpinBox( gb ); + m_fontSizeAdjustement->setRange( -5, 5 ); + m_fontSizeAdjustement->setSingleStep( 1 ); + layout->addWidget( m_fontSizeAdjustement, 1, 1 ); + lFontSizeAdjustement->setBuddy( m_fontSizeAdjustement ); +} + +void FontDialog::load() +{ + KSharedConfig::Ptr cfg = KGlobal::config(); + { + KConfigGroup configGroup( cfg, "HTML Settings" ); + + m_minFontSize->setValue( configGroup.readEntry( "MinimumFontSize", (int)HTML_DEFAULT_MIN_FONT_SIZE ) ); + m_medFontSize->setValue( configGroup.readEntry( "MediumFontSize", 10 ) ); + + QStringList fonts = configGroup.readEntry( "Fonts" , QStringList() ); + if ( fonts.isEmpty() ) + fonts << KGlobalSettings::generalFont().family() + << KGlobalSettings::fixedFont().family() + << QLatin1String(HTML_DEFAULT_VIEW_SERIF_FONT) + << QLatin1String(HTML_DEFAULT_VIEW_SANSSERIF_FONT) + << QLatin1String(HTML_DEFAULT_VIEW_CURSIVE_FONT) + << QLatin1String(HTML_DEFAULT_VIEW_FANTASY_FONT) + << QString(); + + m_standardFontCombo->setCurrentFont( fonts[ 0 ] ); + m_fixedFontCombo->setCurrentFont( fonts[ 1 ] ); + m_serifFontCombo->setCurrentFont( fonts[ 2 ] ); + m_sansSerifFontCombo->setCurrentFont( fonts[ 3 ] ); + m_italicFontCombo->setCurrentFont( fonts[ 4 ] ); + m_fantasyFontCombo->setCurrentFont( fonts[ 5 ] ); + + QString encoding = configGroup.readEntry( "DefaultEncoding" ); + if (encoding.isEmpty()) m_defaultEncoding->setCurrentIndex( 0 ); + else m_defaultEncoding->setCurrentItem( encoding ); + m_fontSizeAdjustement->setValue( fonts[ 6 ].toInt() ); + } +} + +void FontDialog::save() +{ + KSharedConfig::Ptr cfg = KGlobal::config(); + { + KConfigGroup configGroup( cfg, "General" ); + configGroup.writeEntry( "UseKonqSettings", false ); + } + { + KConfigGroup configGroup( cfg, "HTML Settings" ); + + configGroup.writeEntry( "MinimumFontSize", m_minFontSize->value() ); + configGroup.writeEntry( "MediumFontSize", m_medFontSize->value() ); + + QStringList fonts; + fonts << m_standardFontCombo->currentFont().family() + << m_fixedFontCombo->currentFont().family() + << m_serifFontCombo->currentFont().family() + << m_sansSerifFontCombo->currentFont().family() + << m_italicFontCombo->currentFont().family() + << m_fantasyFontCombo->currentFont().family() + << QString::number( m_fontSizeAdjustement->value() ); + + configGroup.writeEntry( "Fonts", fonts ); + + if ( m_defaultEncoding->currentText() == i18n( "Use Language Encoding" ) ) + configGroup.writeEntry( "DefaultEncoding", QString() ); + else + configGroup.writeEntry( "DefaultEncoding", m_defaultEncoding->currentText() ); + } + cfg->sync(); +} + +#include "fontdialog.moc" +// vim:ts=4:sw=4:noet diff --git a/khelpcenter/fontdialog.h b/khelpcenter/fontdialog.h new file mode 100644 index 00000000..a0bd4cd9 --- /dev/null +++ b/khelpcenter/fontdialog.h @@ -0,0 +1,68 @@ +/* + * This file is part of the KDE Help Center + * + * Copyright (C) 2003 Frerich Raabe + * + * 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. + */ +#ifndef KHC_FONTDIALOG_H +#define KHC_FONTDIALOG_H + +#include + +class KIntSpinBox; + +class KComboBox; +class KFontComboBox; +class KIntNumInput; +class KVBox; + +namespace KHC { + + class FontDialog : public KDialog + { + Q_OBJECT + + public: + FontDialog( QWidget *parent ); + + protected Q_SLOTS: + virtual void slotOk(); + + private: + void setupFontSizesBox(); + void setupFontTypesBox(); + void setupFontEncodingBox(); + + void load(); + void save(); + + KIntNumInput *m_minFontSize; + KIntNumInput *m_medFontSize; + KFontComboBox *m_standardFontCombo; + KFontComboBox *m_fixedFontCombo; + KFontComboBox *m_serifFontCombo; + KFontComboBox *m_sansSerifFontCombo; + KFontComboBox *m_italicFontCombo; + KFontComboBox *m_fantasyFontCombo; + KComboBox *m_defaultEncoding; + KIntSpinBox *m_fontSizeAdjustement; + KVBox *m_mainWidget; + }; + +} + +#endif // KHC_FONTDIALOG_H +// vim:ts=4:sw=4:noet diff --git a/khelpcenter/formatter.cpp b/khelpcenter/formatter.cpp new file mode 100644 index 00000000..cbf8963d --- /dev/null +++ b/khelpcenter/formatter.cpp @@ -0,0 +1,227 @@ +/* + This file is part of KHelpcenter. + + Copyright (c) 2003 Cornelius Schumacher + + 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 "formatter.h" + +#include +#include +#include +#include +#include +#include + +#include +#include + +using namespace KHC; + +Formatter::Formatter() + : mHasTemplate( false ) +{ +} + +Formatter:: ~Formatter() +{ +} + +bool Formatter::readTemplates() +{ + KConfigGroup cfg(KGlobal::config(), "Templates"); + QString mainTemplate = cfg.readEntry( "MainTemplate" ); + + if ( mainTemplate.isEmpty() ) + { + mainTemplate = KStandardDirs::locate( "appdata", "maintemplate" ); + } + + if ( mainTemplate.isEmpty() ) + { + kWarning() << "Main template file name is empty." ; + return false; + } + + QFile f( mainTemplate ); + if ( !f.open( QIODevice::ReadOnly ) ) + { + kWarning() << "Unable to open main template file '" << mainTemplate + << "'." << endl; + return false; + } + + QTextStream ts( &f ); + QString line; + enum State { IDLE, SINGLELINE, MULTILINE }; + State state = IDLE; + QString symbol; + QString endMarker; + QString value; + while( !( line = ts.readLine() ).isNull() ) { + switch ( state ) { + case IDLE: + if ( !line.isEmpty() && !line.startsWith( '#' ) ) + { + int pos = line.indexOf( "<<" ); + if ( pos >= 0 ) + { + state = MULTILINE; + symbol = line.left( pos ).trimmed(); + endMarker = line.mid( pos + 2 ).trimmed(); + } else { + state = SINGLELINE; + symbol = line.trimmed(); + } + } + break; + case SINGLELINE: + mSymbols.insert( symbol, line ); + state = IDLE; + break; + case MULTILINE: + if ( line.startsWith( endMarker ) ) + { + mSymbols.insert( symbol, value ); + value = ""; + state = IDLE; + } + else + { + value += line + '\n'; + } + break; + default: + kError() << "Formatter::readTemplates(): Illegal state: " + << static_cast(state) << endl; + break; + } + } + + f.close(); + + QStringList requiredSymbols; + requiredSymbols << "HEADER" << "FOOTER"; + + bool success = true; + QStringList::ConstIterator it2; + for( it2 = requiredSymbols.constBegin(); it2 != requiredSymbols.constEnd(); ++it2 ) + { + if ( !mSymbols.contains( *it2 ) ) + { + success = false; + kError() << "Symbol '" << *it2 << "' is missing from main template file." + << endl; + } + } + + if ( success ) mHasTemplate = true; + return success; +} + +QString Formatter::header( const QString &title ) +{ + QString s; + if ( mHasTemplate ) + { + s = mSymbols[ "HEADER" ]; + s.replace( "--TITLE:--", title ); + } else { + s = QLatin1String("") + title + QLatin1String("\n\n"); + } + return s; +} + +QString Formatter::footer() +{ + if ( mHasTemplate ) + { + return mSymbols[ "FOOTER" ]; + } else { + return QLatin1String(""); + } +} + +QString Formatter::separator() +{ + return "
"; +} + +QString Formatter::docTitle( const QString &title ) +{ + return QLatin1String("

") + title + QLatin1String("

"); +} + +QString Formatter::sectionHeader( const QString §ion ) +{ + return QLatin1String("

") + section + QLatin1String("

"); +} + +QString Formatter::processResult( const QString &data ) +{ + QString result; + + enum { Header, BodyTag, Body, Footer }; + + int state = Header; + + for( int i = 0; i < data.length(); ++i ) + { + QChar c = data[i]; + switch ( state ) + { + case Header: + if ( c == QLatin1Char('<') && data.mid( i, 5 ).toLower() == QLatin1String("' ) state = Body; + break; + case Body: + if ( c == QLatin1Char('<') && data.mid( i, 7 ).toLower() == QLatin1String("") ) + { + state = Footer; + } else { + result.append( c ); + } + break; + case Footer: + break; + default: + result.append( c ); + break; + } + } + + if ( state == Header ) return data; + else return result; +} + +QString Formatter::paragraph( const QString &str ) +{ + return QLatin1String("

") + str + QLatin1String("

"); +} + +QString Formatter::title( const QString &title ) +{ + return QLatin1String("

") + title + QLatin1String("

"); +} + +// vim:ts=2:sw=2:et diff --git a/khelpcenter/formatter.h b/khelpcenter/formatter.h new file mode 100644 index 00000000..3c13fc6f --- /dev/null +++ b/khelpcenter/formatter.h @@ -0,0 +1,56 @@ + +/* + This file is part of KHelpcenter. + + Copyright (c) 2003 Cornelius Schumacher + + 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. +*/ + +#ifndef KHC_FORMATTER_H +#define KHC_FORMATTER_H + +#include + +namespace KHC { + + class Formatter + { + public: + Formatter(); + virtual ~Formatter(); + + bool readTemplates(); + + virtual QString header( const QString &title ); + virtual QString footer(); + virtual QString separator(); + virtual QString docTitle( const QString & ); + virtual QString sectionHeader( const QString & ); + virtual QString paragraph( const QString & ); + virtual QString title( const QString & ); + + virtual QString processResult( const QString & ); + + private: + bool mHasTemplate; + QMap mSymbols; + }; + +} + +#endif //KHC_FORMATTER_H + +// vim:ts=2:sw=2:et diff --git a/khelpcenter/glossary.cpp b/khelpcenter/glossary.cpp new file mode 100644 index 00000000..0a52e8a0 --- /dev/null +++ b/khelpcenter/glossary.cpp @@ -0,0 +1,355 @@ + +/* + * This file is part of the KDE Help Center + * + * Copyright (C) 2002 Frerich Raabe (raabe@kde.org) + * + * 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 "glossary.h" +#include "view.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include + +using namespace KHC; + +class SectionItem : public QTreeWidgetItem +{ + public: + SectionItem( QTreeWidgetItem *parent, const QString &text ) + : QTreeWidgetItem( parent ) + { + setText(0,text); + setIcon(0,SmallIcon( "help-contents" )); + } +}; + +class EntryItem : public QTreeWidgetItem +{ + public: + EntryItem( SectionItem *parent, const QString &term, const QString &id ) + : QTreeWidgetItem( parent ), m_id( id ) + { + setText(0,term); + } + + QString id() const { return m_id; } + + private: + QString m_id; +}; + +bool Glossary::m_alreadyWarned = false; + +Glossary::Glossary( QWidget *parent ) : QTreeWidget( parent ) +{ + m_initialized = false; + setFrameStyle( QFrame::NoFrame ); + + connect( this, SIGNAL( itemActivated(QTreeWidgetItem *, int) ), + this, SLOT( treeItemSelected( QTreeWidgetItem * ) ) ); + + setHeaderHidden(true); + setAllColumnsShowFocus( true ); + setRootIsDecorated( true ); + + m_byTopicItem = new QTreeWidgetItem( this ); + m_byTopicItem->setText( 0, i18n( "By Topic" ) ); + m_byTopicItem->setIcon( 0, SmallIcon( "help-contents" ) ); + + m_alphabItem = new QTreeWidgetItem( this ); + m_alphabItem->setText( 0, i18n( "Alphabetically" ) ); + m_alphabItem->setIcon( 0, SmallIcon( "character-set" ) ); + + m_cacheFile = KStandardDirs::locateLocal( "cache", "help/glossary.xml" ); + + m_sourceFile = View::langLookup( QLatin1String( "khelpcenter/glossary/index.docbook" ) ); + m_config = KGlobal::config(); + +} + +void Glossary::showEvent(QShowEvent *event) +{ + if ( !m_initialized ) + { + if ( cacheStatus() == NeedRebuild ) + rebuildGlossaryCache(); + else + buildGlossaryTree(); + m_initialized = true; + } + QTreeWidget::showEvent(event); +} + +Glossary::~Glossary() +{ + qDeleteAll( m_glossEntries ); +} + +const GlossaryEntry &Glossary::entry( const QString &id ) const +{ + return *m_glossEntries[ id ]; +} + +Glossary::CacheStatus Glossary::cacheStatus() const +{ + if ( !QFile::exists( m_cacheFile ) || + m_config->group("Glossary").readPathEntry( "CachedGlossary", QString() ) != m_sourceFile || + m_config->group("Glossary").readEntry( "CachedGlossaryTimestamp" ).toInt() != glossaryCTime() ) + return NeedRebuild; + + return CacheOk; +} + +int Glossary::glossaryCTime() const +{ + struct stat stat_buf; + stat( QFile::encodeName( m_sourceFile ).data(), &stat_buf ); + + return stat_buf.st_ctime; +} + +void Glossary::rebuildGlossaryCache() +{ + KXmlGuiWindow *mainWindow = dynamic_cast( kapp->activeWindow() ); + if (mainWindow) + mainWindow->statusBar()->showMessage( i18n( "Rebuilding glossary cache..." ) ); + + KProcess *meinproc = new KProcess; + connect( meinproc, SIGNAL( finished(int,QProcess::ExitStatus) ), + this, SLOT( meinprocFinished(int,QProcess::ExitStatus) ) ); + + *meinproc << KStandardDirs::locate( "exe", QLatin1String( "meinproc4" ) ); + *meinproc << QLatin1String( "--output" ) << m_cacheFile; + *meinproc << QLatin1String( "--stylesheet" ) + << KStandardDirs::locate( "data", QLatin1String( "khelpcenter/glossary.xslt" ) ); + *meinproc << m_sourceFile; + + meinproc->setOutputChannelMode(KProcess::OnlyStderrChannel); + meinproc->start(); + if (!meinproc->waitForStarted()) + { + kError() << "could not start process" << meinproc->program(); + if (mainWindow && !m_alreadyWarned) + { + ; // add warning message box with don't display again option + // http://api.kde.org/4.0-api/kdelibs-apidocs/kdeui/html/classKDialog.html + m_alreadyWarned = true; + } + delete meinproc; + } +} + +void Glossary::meinprocFinished( int exitCode, QProcess::ExitStatus exitStatus ) +{ + KProcess *meinproc = static_cast(sender()); + KXmlGuiWindow *mainWindow = dynamic_cast( kapp->activeWindow() ); + + if (exitStatus != QProcess::NormalExit || exitCode != 0) + { + kError() << "running" << meinproc->program() << "failed with exitCode" << exitCode; + kError() << "stderr output:" << meinproc->readAllStandardError(); + if (mainWindow && !m_alreadyWarned) + { + ; // add warning message box with don't display again option + // http://api.kde.org/4.0-api/kdelibs-apidocs/kdeui/html/classKDialog.html + m_alreadyWarned = true; + } + delete meinproc; + return; + } + delete meinproc; + + if ( !QFile::exists( m_cacheFile ) ) + return; + + m_config->group("Glossary").writePathEntry( "CachedGlossary", m_sourceFile ); + m_config->group("Glossary").writeEntry( "CachedGlossaryTimestamp", glossaryCTime() ); + m_config->sync(); + + m_status = CacheOk; + + if (mainWindow) + mainWindow->statusBar()->showMessage( i18n( "Rebuilding cache... done." ), 2000 ); + + buildGlossaryTree(); +} + +void Glossary::buildGlossaryTree() +{ + QFile cacheFile(m_cacheFile); + if ( !cacheFile.open( QIODevice::ReadOnly ) ) + return; + + QDomDocument doc; + if ( !doc.setContent( &cacheFile ) ) + return; + + QDomNodeList sectionNodes = doc.documentElement().elementsByTagName( QLatin1String( "section" ) ); + for ( int i = 0; i < sectionNodes.count(); i++ ) + { + QDomElement sectionElement = sectionNodes.item( i ).toElement(); + QString title = sectionElement.attribute( QLatin1String( "title" ) ); + SectionItem *topicSection = new SectionItem( m_byTopicItem, title ); + + QDomNodeList entryNodes = sectionElement.elementsByTagName( QLatin1String( "entry" ) ); + for ( int j = 0; j < entryNodes.count(); j++ ) + { + QDomElement entryElement = entryNodes.item( j ).toElement(); + + QString entryId = entryElement.attribute( QLatin1String( "id" ) ); + if ( entryId.isNull() ) + continue; + + QDomElement termElement = childElement( entryElement, QLatin1String( "term" ) ); + QString term = termElement.text().simplified(); + + EntryItem *entry = new EntryItem(topicSection, term, entryId ); + m_idDict.insert( entryId, entry ); + + SectionItem *alphabSection = 0L; + + QTreeWidgetItemIterator it(m_alphabItem); + while(*it) + { + if ( (*it)->text( 0 ) == QString( term[ 0 ].toUpper() ) ) + { + alphabSection = static_cast( (*it) ); + break; + } + ++it; + } + + if ( !alphabSection ) + alphabSection = new SectionItem( m_alphabItem, QString( term[ 0 ].toUpper() ) ); + + new EntryItem( alphabSection, term, entryId ); + + QDomElement definitionElement = childElement( entryElement, QLatin1String( "definition" ) ); + QString definition = definitionElement.text().simplified(); + + GlossaryEntryXRef::List seeAlso; + + QDomElement referencesElement = childElement( entryElement, QLatin1String( "references" ) ); + QDomNodeList referenceNodes = referencesElement.elementsByTagName( QLatin1String( "reference" ) ); + if ( referenceNodes.count() > 0 ) + for ( int k = 0; k < referenceNodes.count(); k++ ) + { + QDomElement referenceElement = referenceNodes.item( k ).toElement(); + + QString term = referenceElement.attribute( QLatin1String( "term" ) ); + QString id = referenceElement.attribute( QLatin1String( "id" ) ); + + seeAlso += GlossaryEntryXRef( term, id ); + } + + m_glossEntries.insert( entryId, new GlossaryEntry( term, definition, seeAlso ) ); + } + } + sortItems(0, Qt::AscendingOrder); +} + +void Glossary::treeItemSelected( QTreeWidgetItem *item ) +{ + if ( !item ) + return; + + if ( EntryItem *i = dynamic_cast( item ) ) + emit entrySelected( entry( i->id() ) ); + + item->setExpanded( !item->isExpanded() ); +} + +QDomElement Glossary::childElement( const QDomElement &element, const QString &name ) +{ + QDomElement e; + for ( e = element.firstChild().toElement(); !e.isNull(); e = e.nextSibling().toElement() ) + if ( e.tagName() == name ) + break; + return e; +} + +QString Glossary::entryToHtml( const GlossaryEntry &entry ) +{ + QFile htmlFile( KStandardDirs::locate("data", "khelpcenter/glossary.html.in" ) ); + if (!htmlFile.open(QIODevice::ReadOnly)) + return QString( "

%1

%2" ) + .arg( i18n( "Error" ) ) + .arg( i18n( "Unable to show selected glossary entry: unable to open " + "file 'glossary.html.in'!" ) ); + + QString seeAlso; + if (!entry.seeAlso().isEmpty()) + { + seeAlso = i18n("See also: "); + GlossaryEntryXRef::List seeAlsos = entry.seeAlso(); + GlossaryEntryXRef::List::ConstIterator it = seeAlsos.constBegin(); + GlossaryEntryXRef::List::ConstIterator end = seeAlsos.constEnd(); + for (; it != end; ++it) + { + seeAlso += QLatin1String("") + (*it).term(); + seeAlso += QLatin1String(", "); + } + seeAlso = seeAlso.left(seeAlso.length() - 2); + } + + QTextStream htmlStream(&htmlFile); + return htmlStream.readAll() + .arg( i18n( "KDE Glossary" ) ) + .arg( entry.term() ) + .arg( entry.definition() ) + .arg( seeAlso ); +} + +void Glossary::slotSelectGlossEntry( const QString &id ) +{ + if ( !m_idDict.contains( id ) ) + return; + + EntryItem *newItem = m_idDict.value( id ); + EntryItem *curItem = dynamic_cast( currentItem() ); + if ( curItem != 0 ) + { + if ( curItem->id() == id ) + return; + curItem->parent()->setExpanded( false ); + } + + setCurrentItem( newItem ); +} + +#include "glossary.moc" +// vim:ts=4:sw=4:et diff --git a/khelpcenter/glossary.h b/khelpcenter/glossary.h new file mode 100644 index 00000000..0d7b614c --- /dev/null +++ b/khelpcenter/glossary.h @@ -0,0 +1,145 @@ +/* + * glossary.h - part of the KDE Help Center + * + * Copyright (C) 2002 Frerich Raabe (raabe@kde.org) + * + * 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. + */ +#ifndef KHC_GLOSSARY_H +#define KHC_GLOSSARY_H + +#include +#include +#include +#include +#include +#include + +class EntryItem; + +namespace KHC { + + class GlossaryEntryXRef + { + friend QDataStream &operator>>( QDataStream &, GlossaryEntryXRef & ); + public: + typedef QList List; + + GlossaryEntryXRef() {} + GlossaryEntryXRef( const QString &term, const QString &id ) : + m_term( term ), + m_id( id ) + { + } + + QString term() const { return m_term; } + QString id() const { return m_id; } + + private: + QString m_term; + QString m_id; + }; + + inline QDataStream &operator<<( QDataStream &stream, const GlossaryEntryXRef &e ) + { + return stream << e.term() << e.id(); + } + + inline QDataStream &operator>>( QDataStream &stream, GlossaryEntryXRef &e ) + { + return stream >> e.m_term >> e.m_id; + } + + class GlossaryEntry + { + friend QDataStream &operator>>( QDataStream &, GlossaryEntry & ); + public: + GlossaryEntry() {} + GlossaryEntry( const QString &term, const QString &definition, + const GlossaryEntryXRef::List &seeAlso ) : + m_term( term ), + m_definition( definition ), + m_seeAlso( seeAlso ) + { } + + QString term() const { return m_term; } + QString definition() const { return m_definition; } + GlossaryEntryXRef::List seeAlso() const { return m_seeAlso; } + + private: + QString m_term; + QString m_definition; + GlossaryEntryXRef::List m_seeAlso; + }; + + inline QDataStream &operator<<( QDataStream &stream, const GlossaryEntry &e ) + { + return stream << e.term() << e.definition() << e.seeAlso(); + } + + inline QDataStream &operator>>( QDataStream &stream, GlossaryEntry &e ) + { + return stream >> e.m_term >> e.m_definition >> e.m_seeAlso; + } + + class Glossary : public QTreeWidget + { + Q_OBJECT + public: + Glossary( QWidget *parent ); + virtual ~Glossary(); + + const GlossaryEntry &entry( const QString &id ) const; + + static QString entryToHtml( const GlossaryEntry &entry ); + + public Q_SLOTS: + void slotSelectGlossEntry( const QString &id ); + + Q_SIGNALS: + void entrySelected( const GlossaryEntry &entry ); + + private Q_SLOTS: + void meinprocFinished(int exitCode, QProcess::ExitStatus exitStatus); + void treeItemSelected( QTreeWidgetItem *item ); + + protected: + virtual void showEvent(QShowEvent *event); + + private: + enum CacheStatus { NeedRebuild, CacheOk }; + + CacheStatus cacheStatus() const; + int glossaryCTime() const; + void rebuildGlossaryCache(); + void buildGlossaryTree(); + QDomElement childElement( const QDomElement &e, const QString &name ); + + KSharedConfigPtr m_config; + QTreeWidgetItem *m_byTopicItem; + QTreeWidgetItem *m_alphabItem; + QString m_sourceFile; + QString m_cacheFile; + CacheStatus m_status; + QHash m_glossEntries; + QHash m_idDict; + bool m_initialized; + static bool m_alreadyWarned; + }; + +} + +#endif // KHC_GLOSSARY_H +// vim:ts=2:sw=2:et diff --git a/khelpcenter/glossary.html.in b/khelpcenter/glossary.html.in new file mode 100644 index 00000000..b03bf2a6 --- /dev/null +++ b/khelpcenter/glossary.html.in @@ -0,0 +1,47 @@ + + + + %1: %2 + + + + +
+
+ +
+
+ +
+
+ %2 +
+
+
+ %3 +
+
+ %4 +
+
+
+ +
+
+ +
+
+ + + diff --git a/khelpcenter/glossary.xslt b/khelpcenter/glossary.xslt new file mode 100644 index 00000000..4be123a8 --- /dev/null +++ b/khelpcenter/glossary.xslt @@ -0,0 +1,34 @@ + + + + + + + + + + +
+ + +
+
+ + + + + + + + + + + + + + + + + +
diff --git a/khelpcenter/history.cpp b/khelpcenter/history.cpp new file mode 100644 index 00000000..59b1c9d9 --- /dev/null +++ b/khelpcenter/history.cpp @@ -0,0 +1,389 @@ +/* + * This file is part of the KDE Help Center + * + * Copyright (C) 2002 Frerich Raabe + * + * 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 "history.h" +#include "view.h" + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +using namespace KHC; + +// TODO: Needs complete redo! +// TODO: oh yeah + +History *History::m_instance = 0; + +History &History::self() +{ + if ( !m_instance ) + m_instance = new History; + return *m_instance; +} + +History::History() : QObject(), + m_goBuffer( 0 ) +{ + m_entries_current = m_entries.end(); +} + +History::~History() +{ + qDeleteAll(m_entries); +} + +void History::setupActions( KActionCollection *coll ) +{ + QPair backForward = KStandardGuiItem::backAndForward(); + + m_backAction = new KToolBarPopupAction( KIcon( backForward.first.iconName() ), backForward.first.text(), this ); + coll->addAction( "back", m_backAction ); + m_backAction->setShortcut(KStandardShortcut::back()); + + connect( m_backAction, SIGNAL( triggered() ), this, SLOT( back() ) ); + + connect( m_backAction->menu(), SIGNAL( triggered( QAction* ) ), + SLOT( backActivated( QAction* ) ) ); + + connect( m_backAction->menu(), SIGNAL( aboutToShow() ), + SLOT( fillBackMenu() ) ); + + m_backAction->setEnabled( false ); + + m_forwardAction = new KToolBarPopupAction( KIcon( backForward.second.iconName() ), backForward.second.text(), this ); + coll->addAction( QLatin1String("forward"), m_forwardAction ); + m_forwardAction->setShortcut(KStandardShortcut::forward()); + + connect( m_forwardAction, SIGNAL( triggered() ), this, SLOT( forward() ) ); + + connect( m_forwardAction->menu(), SIGNAL( triggered( QAction* ) ), + SLOT( forwardActivated( QAction* ) ) ); + + connect( m_forwardAction->menu(), SIGNAL( aboutToShow() ), + SLOT( fillForwardMenu() ) ); + + m_forwardAction->setEnabled( false ); +} + +void History::installMenuBarHook( KXmlGuiWindow *mainWindow ) +{ + QMenu *goMenu = dynamic_cast( + mainWindow->guiFactory()->container( QLatin1String("go_web"), mainWindow ) ); + if ( goMenu ) + { + connect( goMenu, SIGNAL( aboutToShow() ), SLOT( fillGoMenu() ) ); + + connect( goMenu, SIGNAL( triggered( QAction* ) ), + SLOT( goMenuActivated( QAction* ) ) ); + + m_goMenuIndex = goMenu->actions().count(); + } +} + +void History::createEntry() +{ + kDebug() << "History::createEntry()"; + + // First, remove any forward history + if (m_entries_current!=m_entries.end()) + { + + m_entries.erase(m_entries.begin(),m_entries_current); + + // If current entry is empty reuse it. + if ( !(*m_entries_current)->view ) { + return; + } + } + // Append a new entry + m_entries_current = m_entries.insert(m_entries_current, new Entry ); // made current +} + +void History::updateCurrentEntry( View *view ) +{ + if ( m_entries.isEmpty() ) + return; + + KUrl url = view->url(); + + Entry *current = *m_entries_current; + + QDataStream stream( ¤t->buffer, QIODevice::WriteOnly ); + view->browserExtension()->saveState( stream ); + + current->view = view; + + if ( url.isEmpty() ) { + kDebug() << "History::updateCurrentEntry(): internal url"; + url = view->internalUrl(); + } + + kDebug() << "History::updateCurrentEntry(): " << view->title() + << " (URL: " << url.url() << ")" << endl; + + current->url = url; + current->title = view->title(); + + current->search = view->state() == View::Search; +} + +void History::updateActions() +{ + m_backAction->setEnabled( canGoBack() ); + m_forwardAction->setEnabled( canGoForward() ); +} + +void History::back() +{ + kDebug( 1400 ) << "History::back()"; + goHistoryActivated( -1 ); +} + +void History::backActivated( QAction *action ) +{ + int id = action->data().toInt(); + kDebug( 1400 ) << "History::backActivated(): id = " << id; + goHistoryActivated( -( id + 1 ) ); +} + +void History::forward() +{ + kDebug( 1400 ) << "History::forward()"; + goHistoryActivated( 1 ); +} + +void History::forwardActivated( QAction *action ) +{ + int id = action->data().toInt(); + kDebug( 1400 ) << "History::forwardActivated(): id = " << id; + goHistoryActivated( id + 1 ); +} + +void History::goHistoryActivated( int steps ) +{ + kDebug( 1400 ) << "History::goHistoryActivated(): m_goBuffer = " << m_goBuffer; + if ( m_goBuffer ) + return; + m_goBuffer = steps; + QTimer::singleShot( 0, this, SLOT( goHistoryDelayed() ) ); +} + +void History::goHistoryDelayed() +{ + kDebug( 1400 ) << "History::goHistoryDelayed(): m_goBuffer = " << m_goBuffer; + if ( !m_goBuffer ) + return; + int steps = m_goBuffer; + m_goBuffer = 0; + goHistory( steps ); +} + +void History::goHistory( int steps ) +{ + kDebug() << "History::goHistory(): " << steps; + + // If current entry is empty remove it. + Entry *current = *m_entries_current; + if ( current && !current->view ) m_entries_current = m_entries.erase(m_entries_current); + + EntryList::iterator newPos = m_entries_current - steps; + + current = *newPos; + if ( !current ) { + kError() << "No History entry at position " << newPos - m_entries.begin() << endl; + return; + } + + if ( !current->view ) { + kWarning() << "Empty history entry." ; + return; + } + + m_entries_current = newPos; + + if ( current->search ) { + kDebug() << "History::goHistory(): search"; + current->view->lastSearch(); + return; + } + + if ( current->url.protocol() == QLatin1String("khelpcenter") ) { + kDebug() << "History::goHistory(): internal"; + emit goInternalUrl( current->url ); + return; + } + + kDebug() << "History::goHistory(): restore state"; + + emit goUrl( current->url ); + + Entry h( *current ); + h.buffer.detach(); + + QDataStream stream( h.buffer ); + + h.view->closeUrl(); + updateCurrentEntry( h.view ); + h.view->browserExtension()->restoreState( stream ); + + + updateActions(); +} + +void History::fillBackMenu() +{ + QMenu *menu = m_backAction->menu(); + menu->clear(); + fillHistoryPopup( menu, true, false, false ); +} + +void History::fillForwardMenu() +{ + QMenu *menu = m_forwardAction->menu(); + menu->clear(); + fillHistoryPopup( menu, false, true, false ); +} + +void History::fillGoMenu() +{ + KXmlGuiWindow *mainWindow = static_cast( kapp->activeWindow() ); + QMenu *goMenu = dynamic_cast( mainWindow->guiFactory()->container( QLatin1String( "go" ), mainWindow ) ); + if ( !goMenu || m_goMenuIndex == -1 ) + return; + + for ( int i = goMenu->actions().count() - 1 ; i >= m_goMenuIndex; i-- ) + goMenu->removeAction( goMenu->actions()[i] ); + + // TODO perhaps smarter algorithm (rename existing items, create new ones only if not enough) ? + + // Ok, we want to show 10 items in all, among which the current url... + + if ( m_entries.count() <= 9 ) + { + // First case: limited history in both directions -> show it all + m_goMenuHistoryStartPos = m_entries.count() - 1; // Start right from the end + } else + // Second case: big history, in one or both directions + { + // Assume both directions first (in this case we place the current URL in the middle) + m_goMenuHistoryStartPos = (m_entries_current - m_entries.begin()) + 4; + + // Forward not big enough ? + if ( m_goMenuHistoryStartPos > (int) m_entries.count() - 4 ) + m_goMenuHistoryStartPos = m_entries.count() - 1; + } + Q_ASSERT( m_goMenuHistoryStartPos >= 0 && (int) m_goMenuHistoryStartPos < m_entries.count() ); + m_goMenuHistoryCurrentPos = m_entries_current - m_entries.begin(); // for slotActivated + fillHistoryPopup( goMenu, false, false, true, m_goMenuHistoryStartPos ); +} + +void History::goMenuActivated( QAction* action ) +{ + KXmlGuiWindow *mainWindow = static_cast( kapp->activeWindow() ); + QMenu *goMenu = dynamic_cast( mainWindow->guiFactory()->container( QLatin1String( "go" ), mainWindow ) ); + if ( !goMenu ) + return; + + // 1 for first item in the list, etc. + int index = goMenu->actions().indexOf(action) - m_goMenuIndex + 1; + if ( index > 0 ) + { + kDebug(1400) << "Item clicked has index " << index; + // -1 for one step back, 0 for don't move, +1 for one step forward, etc. + int steps = ( m_goMenuHistoryStartPos+1 ) - index - m_goMenuHistoryCurrentPos; // make a drawing to understand this :-) + kDebug(1400) << "Emit activated with steps = " << steps; + goHistory( steps ); + } +} + +void History::fillHistoryPopup( QMenu *popup, bool onlyBack, bool onlyForward, bool checkCurrentItem, uint startPos ) +{ + Q_ASSERT ( popup ); // kill me if this 0... :/ + + Entry * current = *m_entries_current; + QList::iterator it = m_entries.begin(); + if (onlyBack || onlyForward) + { + it = m_entries_current; // Jump to current item + // And move off it + if ( !onlyForward ) { + if ( it != m_entries.end() ) ++it; + } else { + if ( it != m_entries.begin() ) --it; + } + } else if ( startPos ) + it += startPos; // Jump to specified start pos + + uint i = 0; + while ( it != m_entries.end() ) + { + QString text = (*it)->title; + text = KStringHandler::csqueeze(text, 50); //CT: squeeze + text.replace( '&', "&&" ); + QAction *action = popup->addAction( text ); + action->setData( i ); + if ( checkCurrentItem && *it == current ) + { + action->setChecked( true ); // no pixmap if checked + } + if ( ++i > 10 ) + break; + if ( !onlyForward ) { + ++it; + } else { + if ( it == m_entries.begin() ) { + it = m_entries.end(); + } else { + --it; + } + } + } +} + +bool History::canGoBack() const +{ + return m_entries.size()>1 && EntryList::const_iterator(m_entries_current) != (m_entries.begin()+(m_entries.size()-1)); +} + +bool History::canGoForward() const +{ + return EntryList::const_iterator(m_entries_current) != m_entries.constBegin() && m_entries.size() > 1; +} + +void History::dumpHistory() const { + for(EntryList::const_iterator it = m_entries.constBegin() ; it!=m_entries.constEnd() ; ++it) { + kDebug() << (*it)->title << (*it)->url << (it==EntryList::const_iterator(m_entries_current) ? "current" : "" ) ; + } + +} + +#include "history.moc" +// vim:ts=2:sw=2:et diff --git a/khelpcenter/history.h b/khelpcenter/history.h new file mode 100644 index 00000000..e9e6af27 --- /dev/null +++ b/khelpcenter/history.h @@ -0,0 +1,118 @@ +/* + * This file is part of the KDE Help Center + * + * Copyright (C) 2002 Frerich Raabe + * + * 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. + */ +#ifndef KHC_HISTORY_H +#define KHC_HISTORY_H + +#include + +#include + +#include +#include + +class KActionCollection; +class KXmlGuiWindow; +class KToolBarPopupAction; +class QMenu; + +namespace KHC { + +class View; + +class History : public QObject +{ + Q_OBJECT + public: + friend class foo; // to make gcc shut up + struct Entry + { + Entry() : view( 0 ), search( false ) {} + + View *view; + KUrl url; + QString title; + QByteArray buffer; + bool search; + }; + + static History &self(); + + void setupActions( KActionCollection *coll ); + void updateActions(); + + void installMenuBarHook( KXmlGuiWindow *mainWindow ); + + void createEntry(); + void updateCurrentEntry( KHC::View *view ); + + Q_SIGNALS: + void goInternalUrl( const KUrl & ); + void goUrl( const KUrl & ); + + private Q_SLOTS: + void backActivated( QAction *action ); + void fillBackMenu(); + void forwardActivated( QAction *action ); + void fillForwardMenu(); + void goMenuActivated( QAction* action ); + void fillGoMenu(); + void back(); + void forward(); + void goHistoryActivated( int steps ); + void goHistory( int steps ); + void goHistoryDelayed(); + + private: + History(); + History( const History &rhs ); + History &operator=( const History &rhs ); + ~History(); + + typedef QList EntryList; + + bool canGoBack() const; + bool canGoForward() const; + void fillHistoryPopup( QMenu *, bool, bool, bool, uint = 0 ); + + /** + * dumps the history with a kDebug and mark wihch one is the current one + * This is a debugging function. + */ + void dumpHistory() const; + + static History *m_instance; + + EntryList m_entries; + EntryList::Iterator m_entries_current; + + + int m_goBuffer; + int m_goMenuIndex; + int m_goMenuHistoryStartPos; + int m_goMenuHistoryCurrentPos; + public: + KToolBarPopupAction *m_backAction; + KToolBarPopupAction *m_forwardAction; +}; + +} + +#endif // KHC_HISTORY_H +// vim:ts=2:sw=2:et diff --git a/khelpcenter/htmlsearch.cpp b/khelpcenter/htmlsearch.cpp new file mode 100644 index 00000000..200885aa --- /dev/null +++ b/khelpcenter/htmlsearch.cpp @@ -0,0 +1,62 @@ +#include "htmlsearch.h" + +#include +#include +#include + +#include "docentry.h" + +#include "htmlsearch.moc" + +using namespace KHC; + +HTMLSearch::HTMLSearch() +{ + mConfig = new KConfig("khelpcenterrc"); +} + +HTMLSearch::~HTMLSearch() +{ + delete mConfig; +} + +void HTMLSearch::setupDocEntry( KHC::DocEntry *entry ) +{ +// kDebug() << "HTMLSearch::setupDocEntry(): " << entry->name(); + + if ( entry->searchMethod().toLower() != QLatin1String("htdig") ) return; + + if ( entry->search().isEmpty() ) + entry->setSearch( defaultSearch( entry ) ); + if ( entry->indexer().isEmpty() ) + entry->setIndexer( defaultIndexer( entry ) ); + if ( entry->indexTestFile().isEmpty() ) + entry->setIndexTestFile( defaultIndexTestFile( entry ) ); + +// entry->dump(); +} + +QString HTMLSearch::defaultSearch( KHC::DocEntry *entry ) +{ + QString htsearch = QLatin1String("cgi:"); + htsearch += mConfig->group("htdig").readPathEntry( "htsearch", QString() ); + htsearch += "?words=%k&method=and&format=-desc&config="; + htsearch += entry->identifier(); + + return htsearch; +} + +QString HTMLSearch::defaultIndexer( KHC::DocEntry * ) +{ + QString indexer = mConfig->group("htdig").readPathEntry( "indexer", QString() ); + indexer += " --indexdir=%i %f"; + + return indexer; +} + +QString HTMLSearch::defaultIndexTestFile( KHC::DocEntry *entry ) +{ + return entry->identifier() + QLatin1String(".exists"); +} + +// vim:ts=2:sw=2:et diff --git a/khelpcenter/htmlsearch.h b/khelpcenter/htmlsearch.h new file mode 100644 index 00000000..04b1022c --- /dev/null +++ b/khelpcenter/htmlsearch.h @@ -0,0 +1,51 @@ +/* This file is part of the KDE project + Copyright 2002 Cornelius Schumacher + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public + License version 2 or at your option version 3 as published + by the Free Software Foundation. + + 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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef KHC_HTMLSEARCH_H +#define KHC_HTMLSEARCH_H + +#include + +class KConfig; + +namespace KHC { + +class DocEntry; + +class HTMLSearch : public QObject +{ + Q_OBJECT + public: + HTMLSearch(); + ~HTMLSearch(); + + void setupDocEntry( KHC::DocEntry * ); + + QString defaultSearch( KHC::DocEntry * ); + QString defaultIndexer( KHC::DocEntry * ); + QString defaultIndexTestFile( KHC::DocEntry * ); + + private: + KConfig *mConfig; +}; + +} + +#endif //KHC_HTMLSEARCH_H +// vim:ts=2:sw=2:et diff --git a/khelpcenter/htmlsearch/CMakeLists.txt b/khelpcenter/htmlsearch/CMakeLists.txt new file mode 100644 index 00000000..af3585c5 --- /dev/null +++ b/khelpcenter/htmlsearch/CMakeLists.txt @@ -0,0 +1,50 @@ + + +########### next target ############### + +set(htmlsearch_LIB_SRCS htmlsearch.cpp progressdialog.cpp) + + +kde4_add_library(htmlsearch SHARED ${htmlsearch_LIB_SRCS}) + +target_link_libraries(htmlsearch ${KDE4_KIO_LIBS}) + +set_target_properties(htmlsearch PROPERTIES VERSION ${GENERIC_LIB_VERSION} SOVERSION ${GENERIC_LIB_SOVERSION}) +install(TARGETS htmlsearch ${INSTALL_TARGETS_DEFAULT_ARGS}) + + +########### next target ############### + +set(kcm_htmlsearch_LIB_SRCS kcmhtmlsearch.cpp klangcombo.cpp ktagcombobox.cpp) + + +kde4_add_library(kcm_htmlsearch SHARED ${kcm_htmlsearch_LIB_SRCS}) + +target_link_libraries(kcm_htmlsearch ${KDE4_KIO_LIBS}) + +set_target_properties(kcm_htmlsearch PROPERTIES VERSION ${GENERIC_LIB_VERSION} SOVERSION ${GENERIC_LIB_SOVERSION}) +install(TARGETS kcm_htmlsearch ${INSTALL_TARGETS_DEFAULT_ARGS}) + + +########### next target ############### + +set(khtmlindex_SRCS index.cpp ) + + +kde4_add_executable(khtmlindex ${khtmlindex_SRCS}) + +target_link_libraries(khtmlindex ${KDE4_KDEUI_LIBS} htmlsearch ) + +install(PROGRAMS khtmlindex ${INSTALL_TARGETS_DEFAULT_ARGS}) + + +########### install files ############### + +install( FILES htmlsearch.desktop DESTINATION ${SERVICES_INSTALL_DIR} ) +install( FILES long.html short.html wrapper.html nomatch.html syntax.html DESTINATION ${DATA_INSTALL_DIR}/khelpcenter/en ) +install( FILES star.png star_blank.png DESTINATION ${DATA_INSTALL_DIR}/khelpcenter/pics ) +install( FILES unchecked.xpm checked.xpm DESTINATION ${DATA_INSTALL_DIR}/khelpcenter/pics ) + +install( PROGRAMS meinproc_wrapper DESTINATION ${DATA_INSTALL_DIR}/khelpcenter/ ) + +kde4_install_icons( ${DATA_INSTALL_DIR}/khelpcenter/ ) diff --git a/khelpcenter/htmlsearch/Messages.sh b/khelpcenter/htmlsearch/Messages.sh new file mode 100644 index 00000000..0cfbb98e --- /dev/null +++ b/khelpcenter/htmlsearch/Messages.sh @@ -0,0 +1,4 @@ +#! /usr/bin/env bash +### TODO: why do we need 2 POT files for one directory? +$XGETTEXT index.cpp htmlsearch.cpp progressdialog.cpp rc.cpp -o $podir/htmlsearch.pot +$XGETTEXT kcmhtmlsearch.cpp klangcombo.cpp ktagcombobox.cpp rc.cpp -o $podir/kcmhtmlsearch.pot diff --git a/khelpcenter/htmlsearch/checked.xpm b/khelpcenter/htmlsearch/checked.xpm new file mode 100644 index 00000000..1ed19024 --- /dev/null +++ b/khelpcenter/htmlsearch/checked.xpm @@ -0,0 +1,23 @@ +/* XPM */ +static char*unchecked[]={ +"16 16 4 1", +"# c #000000", +"+ c #ffffff", +"D c #000000", +". c None", +"................", +"............++++", +"..++++++++++DDD+", +"..+########DDD+.", +"..+#++++++DDD+..", +"+DDD+...+DDD#+..", +"++DDD+++DDD+#+..", +"..+DDDDDDD++#+..", +"..+#DDDDD+.+#+..", +"..+#++DD+..+#+..", +"..+#+++++..+#+..", +"..+#++++++++#+..", +"..+##########+..", +"..++++++++++++..", +"................", +"................"}; diff --git a/khelpcenter/htmlsearch/htmlsearch.cpp b/khelpcenter/htmlsearch/htmlsearch.cpp new file mode 100644 index 00000000..38e72160 --- /dev/null +++ b/khelpcenter/htmlsearch/htmlsearch.cpp @@ -0,0 +1,478 @@ +#include +#include +#include + +#include +#include +#include +#include +#include + + +#include "progressdialog.h" +#include +#include "htmlsearch.moc" + + +HTMLSearch::HTMLSearch() + : QObject(), _proc(0) +{ +} + + +QString HTMLSearch::dataPath(const QString& _lang) +{ + return kapp->dirs()->saveLocation("data", QString("khelpcenter/%1").arg(_lang)); +} + + +void HTMLSearch::scanDir(const QString& dir) +{ + assert( dir.at( dir.length() - 1 ) == '/' ); + + QStringList::ConstIterator it; + + if ( KStandardDirs::exists( dir + "index.docbook" ) ) { + _files.append(dir + "index.docbook"); + progress->setFilesScanned(++_filesScanned); + } else { + QDir d(dir, "*.html", QDir::Name|QDir::IgnoreCase, QDir::Files | QDir::Readable); + QStringList const &list = d.entryList(); + QString adir = d.canonicalPath () + '/'; + QString file; + for (it=list.begin(); it != list.end(); ++it) + { + file = adir + *it; + if ( !_files.contains( file ) ) { + _files.append(file); + progress->setFilesScanned(++_filesScanned); + } + } + } + + QDir d2(dir, QString(), QDir::Name|QDir::IgnoreCase, QDir::Dirs); + QStringList const &dlist = d2.entryList(); + for (it=dlist.begin(); it != dlist.end(); ++it) + if (*it != "." && *it != "..") + { + scanDir(dir + *it + '/'); + kapp->processEvents(); + } +} + + +bool HTMLSearch::saveFilesList(const QString& _lang) +{ + QStringList dirs; + + // throw away old files list + _files.clear(); + + // open config file + KConfig config("khelpcenterrc"); + KConfigGroup scopeGroup( &config, "Scope" ); + + // add KDE help dirs + if (scopeGroup.readEntry("KDE", true)) + dirs = kapp->dirs()->findDirs("html", _lang + '/'); + kDebug() << "got " << dirs.count() << " dirs\n"; + + // TODO: Man and Info!! + + // add local urls + QStringList add = scopeGroup.readEntry("Paths", QStringList() ); + QStringList::const_iterator it; + for (it = add.begin(); it != add.end(); ++it) { + if ( ( *it ).at( ( *it ).length() - 1 ) != '/' ) + ( *it ) += '/'; + dirs.append(*it); + } + + _filesScanned = 0; + + for (it = dirs.begin(); it != dirs.end(); ++it) + scanDir(*it); + + return true; +} + + +bool HTMLSearch::createConfig(const QString& _lang) +{ + QString fname = dataPath(_lang) + "/htdig.conf"; + + // locate the common dir + QString wrapper = locate("data", QString("khelpcenter/%1/wrapper.html").arg(_lang)); + if (wrapper.isEmpty()) + wrapper = locate("data", QString("khelpcenter/en/wrapper.html")); + if (wrapper.isEmpty()) + return false; + wrapper = wrapper.left(wrapper.length() - 12); + + // locate the image dir + QString images = locate("data", "khelpcenter/pics/star.png"); + if (images.isEmpty()) + return false; + images = images.left(images.length() - 8); + + // This is an example replacement for the default bad_words file + // distributed with ht://Dig. It was compiled by Marjolein Katsma + // . + QString bad_words = i18nc( "List of words to exclude from index", + "above:about:according:across:actually:\n" + "adj:after:afterwards:again:against:all:\n" + "almost:alone:along:already:also:although:\n" + "always:among:amongst:and:another:any:\n" + "anyhow:anyone:anything:anywhere:are:aren:\n" + "arent:around:became:because:become:\n" + "becomes:becoming:been:before:beforehand:\n" + "begin:beginning:behind:being:below:beside:\n" + "besides:between:beyond:billion:both:but:\n" + "can:cant:cannot:caption:could:couldnt:\n" + "did:didnt:does:doesnt:dont:down:during:\n" //krazy:exclude=spelling + "each:eight:eighty:either:else:elsewhere:\n" + "end:ending:enough:etc:even:ever:every:\n" + "everyone:everything:everywhere:except:few:\n" + "fifty:first:five:for:former:formerly:forty:\n" + "found:four:from:further:had:has:hasnt:have:\n" //krazy:exclude=spelling + "havent:hence:her:here:hereafter:hereby:\n" + "herein:heres:hereupon:hers:herself:hes:him:\n" + "himself:his:how:however:hundred:\n" + "inc:indeed:instead:into:isnt:its:\n" + "itself:last:later:latter:latterly:least:\n" + "less:let:like:likely:ltd:made:make:makes:\n" + "many:may:maybe:meantime:meanwhile:might:\n" + "million:miss:more:moreover:most:mostly:\n" + "mrs:much:must:myself:namely:neither:\n" + "never:nevertheless:next:nine:ninety:\n" + "nobody:none:nonetheless:noone:nor:not:\n" //krazy:exclude=spelling + "nothing:now:nowhere:off:often:once:\n" + "one:only:onto:others:otherwise:our:ours:\n" + "ourselves:out:over:overall:own:page:per:\n" + "perhaps:rather:recent:recently:same:\n" + "seem:seemed:seeming:seems:seven:seventy:\n" + "several:she:shes:should:shouldnt:since:six:\n" //krazy:exclude=spelling + "sixty:some:somehow:someone:something:\n" + "sometime:sometimes:somewhere:still:stop:\n" + "such:taking:ten:than:that:the:their:them:\n" + "themselves:then:thence:there:thereafter:\n" + "thereby:therefore:therein:thereupon:these:\n" + "they:thirty:this:those:though:thousand:\n" + "three:through:throughout:thru:thus:tips:\n" + "together:too:toward:towards:trillion:\n" + "twenty:two:under:unless:unlike:unlikely:\n" + "until:update:updated:updates:upon:\n" + "used:using:very:via:want:wanted:wants:\n" + "was:wasnt:way:ways:wed:well:were:\n" + "werent:what:whats:whatever:when:whence:\n" + "whenever:where:whereafter:whereas:whereby:\n" + "wherein:whereupon:wherever:wheres:whether:\n" + "which:while:whither:who:whoever:whole:\n" + "whom:whomever:whose:why:will:with:within:\n" + "without:wont:work:worked:works:working:\n" + "would:wouldnt:yes:yet:you:youd:youll:your:\n" + "youre:yours:yourself:yourselves:youve" ); + + QFile f; + f.setName( dataPath(_lang) + "/bad_words" ); + if (f.open(QIODevice::WriteOnly)) + { + QTextStream ts( &f ); + QStringList words = bad_words.split( QRegExp ( "[\n:]" ), QString::SkipEmptyParts ); + for ( QStringList::ConstIterator it = words.begin(); + it != words.end(); ++it ) + ts << *it << endl; + f.close(); + } + + f.setName(fname); + if (f.open(QIODevice::WriteOnly)) + { + kDebug() << "Writing config for " << _lang << " to " << fname; + + QTextStream ts(&f); + + ts << "database_dir:\t\t" << dataPath(_lang) << endl; + ts << "start_url:\t\t`" << dataPath(_lang) << "/files`" << endl; + ts << "local_urls:\t\tfile:/=/" << endl; + ts << "local_urls_only:\ttrue" << endl; + ts << "maximum_pages:\t\t1" << endl; + ts << "image_url_prefix:\t" << images << endl; + ts << "star_image:\t\t" << images << "star.png" << endl; + ts << "star_blank:\t\t" << images << "star_blank.png" << endl; + ts << "compression_level:\t6" << endl; + ts << "max_hop_count:\t\t0" << endl; + + ts << "search_results_wrapper:\t" << wrapper << "wrapper.html" << endl; + ts << "nothing_found_file:\t" << wrapper << "nomatch.html" << endl; + ts << "syntax_error_file:\t" << wrapper << "syntax.html" << endl; + ts << "bad_word_list:\t\t" << dataPath(_lang) << "/bad_words" << endl; + ts << "external_parsers:\t" << "text/xml\t" << locate( "data", "khelpcenter/meinproc_wrapper" ) << endl; + f.close(); + return true; + } + + return false; +} + + +#define CHUNK_SIZE 15 + +bool HTMLSearch::generateIndex( const QString & _lang, QWidget *parent) +{ + if (_lang == "C") + _lang = "en"; + + if (!createConfig(_lang)) + return false; + + // create progress dialog + progress = new ProgressDialog(parent); + progress->show(); + kapp->processEvents(); + + // create files list ---------------------------------------------- + if (!saveFilesList(_lang)) + return false; + + progress->setState(1); + + // run htdig ------------------------------------------------------ + KConfig config("khelpcenterrc", true); + KConfigGroup group(&config, "htdig"); + QString exe = group.readPathEntry("htdig", KGlobal::dirs()->findExe("htdig")); + + if (exe.isEmpty()) + { + return false; + } + bool initial = true; + bool done = false; + int count = 0; + + _filesToDig = _files.count(); + progress->setFilesToDig(_filesToDig); + _filesDigged = 0; + + QDir d; d.mkdir(dataPath(_lang)); + + while (!done) + { + // kill old process + delete _proc; + + // prepare new process + _proc = new K3Process(); + *_proc << exe << "-v" << "-c" << dataPath(_lang)+"/htdig.conf"; + if (initial) + { + *_proc << "-i"; + initial = false; + } + + kDebug() << "Running htdig"; + + connect(_proc, SIGNAL(receivedStdout(K3Process *,char*,int)), + this, SLOT(htdigStdout(K3Process *,char*,int))); + + connect(_proc, SIGNAL(processExited(K3Process *)), + this, SLOT(htdigExited(K3Process *))); + + _htdigRunning = true; + + // write out file + QFile f(dataPath(_lang)+"/files"); + if (f.open(QIODevice::WriteOnly)) + { + QTextStream ts(&f); + + for (int i=0; istart(K3Process::NotifyOnExit, K3Process::Stdout ); + + kapp->enter_loop(); + + if (!_proc->normalExit() || _proc->exitStatus() != 0) + { + delete _proc; + delete progress; + return false; + } + + // _filesDigged += CHUNK_SIZE; + progress->setFilesDigged(_filesDigged); + kapp->processEvents(); + } + + progress->setState(2); + + // run htmerge ----------------------------------------------------- + exe = group.readPathEntry("htmerge", kapp->dirs()->findExe("htmerge")); + if (exe.isEmpty()) + { + return false; + } + delete _proc; + _proc = new K3Process(); + *_proc << exe << "-c" << dataPath(_lang)+"/htdig.conf"; + + kDebug() << "Running htmerge"; + + connect(_proc, SIGNAL(processExited(K3Process *)), + this, SLOT(htmergeExited(K3Process *))); + + _htmergeRunning = true; + + _proc->start(K3Process::NotifyOnExit, K3Process::Stdout); + + kapp->enter_loop(); + + if (!_proc->normalExit() || _proc->exitStatus() != 0) + { + delete _proc; + delete progress; + return false; + } + + delete _proc; + + progress->setState(3); + kapp->processEvents(); + + delete progress; + + return true; +} + + + +void HTMLSearch::htdigStdout(K3Process *, char *buffer, int len) +{ + QString line = QString(buffer).left(len); + + int cnt=0, index=-1; + while ( (index = line.find("file://", index+1)) > 0) + cnt++; + _filesDigged += cnt; + + cnt=0; + index=-1; + while ( (index = line.find("not changed", index+1)) > 0) + cnt++; + _filesDigged -= cnt; + + progress->setFilesDigged(_filesDigged); +} + + +void HTMLSearch::htdigExited(K3Process *p) +{ + kDebug() << "htdig terminated " << p->exitStatus(); + _htdigRunning = false; + kapp->exit_loop(); +} + + +void HTMLSearch::htmergeExited(K3Process *) +{ + kDebug() << "htmerge terminated"; + _htmergeRunning = false; + kapp->exit_loop(); +} + + +void HTMLSearch::htsearchStdout(K3Process *, char *buffer, int len) +{ + _searchResult += QString::fromLocal8Bit(buffer,len); +} + + +void HTMLSearch::htsearchExited(K3Process *) +{ + kDebug() << "htsearch terminated"; + _htsearchRunning = false; + kapp->exit_loop(); +} + + +QString HTMLSearch::search( const QString & _lang, const QString & words, const QString & method, int matches, + const QString & format, const QString & sort) +{ + if (_lang == "C") + _lang = "en"; + + createConfig(_lang); + + QString result = dataPath(_lang)+"/result.html"; + + // run htsearch ---------------------------------------------------- + KConfig *config = new KConfig("khelpcenterrc", true); + KConfigGroup group(config, "htdig"); + QString exe = group.readPathEntry("htsearch", kapp->dirs()->findExe("htsearch")); + if (exe.isEmpty()) + { + delete config; + return QString(); + } + _proc = new K3Process(); + *_proc << exe << "-c" << dataPath(_lang)+"/htdig.conf" << + QString("words=%1;method=%2;matchesperpage=%3;format=%4;sort=%5").arg(words).arg(method).arg(matches).arg(format).arg(sort); + + kDebug() << "Running htsearch"; + + connect(_proc, SIGNAL(receivedStdout(K3Process *,char*,int)), + this, SLOT(htsearchStdout(K3Process *,char*,int))); + connect(_proc, SIGNAL(processExited(K3Process *)), + this, SLOT(htsearchExited(K3Process *))); + + _htsearchRunning = true; + _searchResult = ""; + + _proc->start(K3Process::NotifyOnExit, K3Process::Stdout); + + kapp->enter_loop(); + + if (!_proc->normalExit() || _proc->exitStatus() != 0) + { + kDebug() << "Error running htsearch... returning now"; + delete _proc; + delete config; + return QString(); + } + + delete _proc; + + // modify the search result + _searchResult = _searchResult.replace("http://localhost/", "file:/"); + _searchResult = _searchResult.remove("Content-type: text/html"); + + // dump the search result + QFile f(result); + if (f.open(QIODevice::WriteOnly)) + { + QTextStream ts(&f); + + ts << _searchResult << endl; + + f.close(); + delete config; + return result; + } + delete config; + return QString(); +} diff --git a/khelpcenter/htmlsearch/htmlsearch.desktop b/khelpcenter/htmlsearch/htmlsearch.desktop new file mode 100644 index 00000000..f23fe4a0 --- /dev/null +++ b/khelpcenter/htmlsearch/htmlsearch.desktop @@ -0,0 +1,256 @@ +[Desktop Entry] +Exec=kcmshell4 htmlsearch +Icon=help_index +Type=Service +X-KDE-ServiceTypes=KCModule +X-DocPath=kcontrol/help-index.html + +X-KDE-Library=kcm_htmlsearch +X-KDE-FactoryName=htmlsearch +X-KDE-ParentApp=kcontrol + +Name=Index +Name[af]=Indeks +Name[ar]=الفهرس +Name[ast]=Índiz +Name[be]=Індэкс +Name[be@latin]=Źmiest +Name[bg]=Индекс +Name[bn]=সূচি +Name[bn_IN]=ইন্ডেক্স +Name[br]=Meneger +Name[bs]=Indeks +Name[ca]=Índex +Name[ca@valencia]=Índex +Name[cs]=Rejstřík +Name[csb]=Indeks +Name[cy]=Mynegai +Name[da]=Indeks +Name[de]=Stichwortverzeichnis +Name[el]=Ευρετήριο +Name[en_GB]=Index +Name[eo]=Indekso +Name[es]=Índice +Name[et]=Indeks +Name[eu]=Indizea +Name[fa]=فهرست +Name[fi]=Hakemisto +Name[fr]=Index +Name[fy]=Yndeks +Name[ga]=Innéacs +Name[gl]=Índice +Name[gu]=અનુક્રમણિકા +Name[he]=אינדקס +Name[hi]=निर्देशिका +Name[hne]=निर्देसिका +Name[hr]=Indeks +Name[hsb]=Indeks +Name[hu]=Keresési index +Name[ia]=Indice +Name[id]=Indeks +Name[is]=Yfirlit +Name[it]=Indice +Name[ja]=インデックス +Name[ka]=ინდექსი +Name[kk]=Индекс +Name[km]=លិបិក្រម +Name[kn]=ಅನುಕ್ರಮ (ಇಂಡೆಕ್ಸ್) +Name[ko]=찾아보기 +Name[ku]=Pêrist +Name[lt]=Rodyklė +Name[lv]=Indekss +Name[mai]=सूची +Name[mk]=Индекс +Name[ml]=സൂചിക +Name[mr]=सूची +Name[ms]=Indeks +Name[nb]=Indeks +Name[nds]=Index +Name[ne]=अनुक्रमणिका +Name[nl]=Index +Name[nn]=Indeks +Name[oc]=Indèx +Name[or]=ଅନୁକ୍ରମଣିକା +Name[pa]=ਇੰਡੈਕਸ +Name[pl]=Indeks +Name[pt]=Índice +Name[pt_BR]=Índice +Name[ro]=Index +Name[ru]=Индекс +Name[se]=Indeaksa +Name[si]=පටුන +Name[sk]=Index +Name[sl]=Kazalo +Name[sr]=Индекс +Name[sr@ijekavian]=Индекс +Name[sr@ijekavianlatin]=Indeks +Name[sr@latin]=Indeks +Name[sv]=Index +Name[ta]=பொருளடக்கம் +Name[te]=సూచిక +Name[tg]=Индекс +Name[th]=ดัชนี +Name[tr]=Dizin +Name[ug]=مۇندەرىجە +Name[uk]=Індекс +Name[uz]=Indeks +Name[uz@cyrillic]=Индекс +Name[vi]=chỉ mục +Name[wa]=Indecse +Name[xh]=Isalathiso +Name[x-test]=xxIndexxx +Name[zh_CN]=索引 +Name[zh_TW]=索引 + +Comment=Index generation +Comment[af]=Indeks genereering +Comment[ar]=توليد الفهرس +Comment[ast]=Xeneración del índiz +Comment[be]=Стварэнне індэксу +Comment[be@latin]=Stvareńnie źmiestu +Comment[bg]=Създаване на индекс +Comment[bn]=সূচি উত্‍পাদন +Comment[bn_IN]=ইন্ডেক্স নির্মাণ প্রণালী +Comment[br]=Genel ar meneger +Comment[bs]=Stvaranje indeksa +Comment[ca]=Generació de l'índex +Comment[ca@valencia]=Generació de l'índex +Comment[cs]=Vytvoření rejstříku +Comment[csb]=Generowanié indeksu +Comment[cy]=Cynhyrchu mynegai +Comment[da]=Indeksgenerering +Comment[de]=Erstellung des Stichwortverzeichnisses +Comment[el]=Δημιουργία περιεχομένων +Comment[en_GB]=Index generation +Comment[eo]=Kreado de indekso +Comment[es]=Generación del índice +Comment[et]=Indeksi loomine +Comment[eu]=Indizea sortzea +Comment[fa]=تولید فهرست +Comment[fi]=Hakemiston luonti +Comment[fr]=Génération d'index +Comment[fy]=Yndeksgeneraasje +Comment[ga]=Giniúint innéacs +Comment[gl]=Xeración do índice +Comment[gu]=અનુક્રમણિકા બનાવટ +Comment[he]=יצירת אינדקס +Comment[hi]=सूची बनाएँ +Comment[hne]=सूची बनाव +Comment[hr]=Generiranje indeksa +Comment[hsb]=Stworjenje indeksa +Comment[hu]=Index létrehozása +Comment[ia]=Generation de indice +Comment[id]=Pembuatan indeks +Comment[is]=Yfirlitsgerð +Comment[it]=Generazione dell'indice +Comment[ja]=インデックスを生成 +Comment[ka]=ინდექსის შექმნა +Comment[kk]=Индексті құру +Comment[km]=ការ​បង្កើត​លិបិក្រម +Comment[kn]=ಅನುಕ್ರಮ (ಇಂಡೆಕ್ಸ್) ಉತ್ಪತ್ತಿ +Comment[ko]=찾아보기 생성 +Comment[ku]=Afirandina pêristê +Comment[lt]=Rodyklės generavimas +Comment[lv]=Indeksa ģenerēšana +Comment[mai]=सूची बनाबू +Comment[mk]=Генерирање на индекс +Comment[ml]=സൂചികാനിര്‍മ്മാണം +Comment[mr]=सूची बनवा +Comment[ms]=Penjanaan indeks +Comment[nb]=Lag innholdsregister +Comment[nds]=Index maken +Comment[ne]=अनुक्रमणिका सिर्जना +Comment[nl]=Indexgeneratie +Comment[nn]=Indekslaging +Comment[or]=ଅନୁକ୍ରମଣିକା ସୃଷ୍ଟି +Comment[pa]=ਇੰਡੈਕਸ ਬਣਾਓ +Comment[pl]=Generowanie indeksu +Comment[pt]=Geração de índices +Comment[pt_BR]=Geração de índice +Comment[ro]=Generează indexul +Comment[ru]=Создание индекса +Comment[se]=Indeaksaráhkadeapmi +Comment[si]=පටුන ජනණය +Comment[sk]=Generovanie indexu +Comment[sl]=Ustvarjanje kazala +Comment[sr]=Стварање индекса +Comment[sr@ijekavian]=Стварање индекса +Comment[sr@ijekavianlatin]=Stvaranje indeksa +Comment[sr@latin]=Stvaranje indeksa +Comment[sv]=Indexskapare +Comment[ta]=பொருளடக்க இயக்கம் +Comment[te]=సూచిక ను తయారుచెయుట +Comment[tg]=Эҷоди индекс +Comment[th]=สร้างดัชนี +Comment[tr]=Dizin oluşturma +Comment[ug]=ئىندېكس ھاسىل قىلىش +Comment[uk]=Створення індексу +Comment[uz]=Indeksni yaratish +Comment[uz@cyrillic]=Индексни яратиш +Comment[vi]=Tạo ra chỉ mục +Comment[wa]=Fijhaedje d' indecse +Comment[xh]=Ulwenziwo Lwesalathiso +Comment[x-test]=xxIndex generationxx +Comment[zh_CN]=索引生成 +Comment[zh_TW]=產生索引 + +X-KDE-Keywords=Help,HTML,Search,Index,htdig,htsearch,htmerge,Scope,Language +X-KDE-Keywords[ar]=مساعدة,HTML,بحث,فهرس,htdig,htsearch,htmerge,نطاق,لغة +X-KDE-Keywords[bg]=Help,HTML,Search,Index,htdig,htsearch,htmerge,Scope,Language,Помощ,Търсене,Индекс,Език +X-KDE-Keywords[bn]=Help,HTML,Search,Index,htdig,htsearch,htmerge,Scope,Language +X-KDE-Keywords[bs]=Help,HTML,Search,Index,htdig,htsearch,htmerge,Scope,Language,pomoć,pretraga,indeks +X-KDE-Keywords[ca]=Ajuda,HTML,Cerca,Índex,htdig,htsearch,htmerge,Àmbit,Idioma +X-KDE-Keywords[ca@valencia]=Ajuda,HTML,Cerca,Índex,htdig,htsearch,htmerge,Àmbit,Idioma +X-KDE-Keywords[cs]=Nápověda,HTML,Hledání,htdig,htsearch,htmerge,Rozsah,Jazyk +X-KDE-Keywords[da]=Hjælp,HTML,Søgning,Indeks,htdig,htsearch,htmerge,Scope,sprog +X-KDE-Keywords[de]=Hilfe,HTML,Suche,Index,Stichwortverzeichnis,htdig,Sprachen +X-KDE-Keywords[el]=Βοήθεια,HTML,αναζήτηση,ευρετήριο,htdig,htsearch,htmerge,εμβέλεια,γλώσσα +X-KDE-Keywords[en_GB]=Help,HTML,Search,Index,htdig,htsearch,htmerge,Scope,Language +X-KDE-Keywords[eo]=Helpo,HTML,Serĉi,Indekso,htdig,htsearch,htmerge,Amplekso,Lingvo +X-KDE-Keywords[es]=Ayuda,HTML,Buscar,Indice,htdig,htsearch,htmerge,Ámbito,Idioma +X-KDE-Keywords[et]=abi,HTML,otsing,indeks,htdig,htsearch,htmerge,keel +X-KDE-Keywords[eu]=Laguntza,HTML,Bilaketa,Indizea,htdig,htsearch,htmerge,Esparrua,Hizkuntza +X-KDE-Keywords[fa]=Help,HTML,Search,Index,htdig,htsearch,htmerge,Scope,Language +X-KDE-Keywords[fi]=Help,HTML,Search,Index,htdig,htsearch,htmerge,Scope,Language,Ohjeet,HTML,Haku,Indeksi,Hakemisto,Laajuus,Kieli +X-KDE-Keywords[fr]=Aide, HTML, recherche, index, htdig, htsearch, htmerge, étendue, langage +X-KDE-Keywords[ga]=Cabhair,HTML,Cuardach,Innéacs,htdig,htsearch,htmerge,Scóip,Teanga +X-KDE-Keywords[gl]=Axuda, buscar, índice, html, htdig, htsearch, htmerge, lingua, ámbito +X-KDE-Keywords[gu]=મદદ,HTML,શોધ,અનુક્રમ,htdig,htsearch,htmerge,અવકાશ,ભાષા +X-KDE-Keywords[hi]=मदद, HTML, खोज, सूचकांक, htdig, htsearch, htmerge, स्कोप, भाषा +X-KDE-Keywords[hu]=Súgó,HTML,Keresés,Index,htdig,htsearch,htmerge,Tartomány,Nyelv +X-KDE-Keywords[ia]=Adjuta,HTML,Cerca,Indice,htdig,htsearch,htmerge,Scopo,Linguage +X-KDE-Keywords[id]=Bantuan,HTML,Cari,Indeks,htding,htsearch,htmerge,Cakupan,Bahasa +X-KDE-Keywords[is]=Hjálp,HTML,Leit,Yfirlit,htdig,htsearch,htmerge,Svið,Tungumál +X-KDE-Keywords[it]=aiuto,HTML,ricerca,indice,htdig,htsearch,htmerge,contesto,lingua +X-KDE-Keywords[ja]=Help,HTML,Search,Index,htdig,htsearch,htmerge,Scope,Language +X-KDE-Keywords[kk]=Help,HTML,Search,Index,htdig,htsearch,htmerge,Scope,Language +X-KDE-Keywords[km]=Help,HTML,Search,Index,htdig,htsearch,htmerge,Scope,Language +X-KDE-Keywords[ko]=Help,HTML,Search,Index,htdig,htsearch,htmerge,Scope,Language,도움말,검색,인덱스,언어 +X-KDE-Keywords[lv]=Palīdzība,HTML,meklēšana,indekss,htdig,htsearch,htmerge,Scope,valoda +X-KDE-Keywords[mr]=मदत, HTML, शोध, अनुक्रमणिका, htdig,htsearch,htmerge, सीमा, भाषा +X-KDE-Keywords[nb]=Hjelp,HTML,Søk,Index,htdig,htsearch,htmerge,omfang,språk +X-KDE-Keywords[nds]=Hülp.HTML,Söök,Index,htsearch,htmerge,Rebeet,Spraak +X-KDE-Keywords[nl]=Help,HTML,zoeken,index,htdig,htsearch,htmerge,scope,taal +X-KDE-Keywords[nn]=Hjelp,HTML,Søk,indeksering,htdig,htsearch,htmerge,omfang,Scope,Språk +X-KDE-Keywords[pa]=ਮੱਦਦ,HTML,ਖੋਜ,ਲੱਭੋ,ਇੰਡੈਕਸ,htdig,htsearch,htmerge,ਸਕੋਪ,ਹੱਦ,ਭਾਸ਼ਾ +X-KDE-Keywords[pl]=Pomoc,HTML,Znajdowanie,Wyszukiwanie,Indeks,htdig,htsearch,htmerge,Zakres,Język +X-KDE-Keywords[pt]=Ajuda,HTML,Pesquisa,Índice,htdig,htsearch,htmerge,Âmbito,Linguagem +X-KDE-Keywords[pt_BR]=Ajuda,HTML,Pesquisa,Índice,htdig,htsearch,htmerge,Âmbito,Linguagem +X-KDE-Keywords[ro]=ajutor,HTML,căutare,caută,cuprins,htdig,htsearch,htmerge,limbă +X-KDE-Keywords[ru]=Help,HTML,Search,Index,htdig,htsearch,htmerge,Scope,Language,помощь,справка,поиск,индекс,язык +X-KDE-Keywords[sk]=Pomoc,HTML,Hľadať,Index,htdig,htsearch,htmerge,Scope,Jazyk +X-KDE-Keywords[sl]=pomoč,html,iskanje,kazalo,htdig,htsearch,htmerge,obseg,jezik +X-KDE-Keywords[sr]=Help,HTML,Search,Index,htdig,htsearch,htmerge,Scope,Language,помоћ,ХТМЛ,претрага,тражење,индекс,језик +X-KDE-Keywords[sr@ijekavian]=Help,HTML,Search,Index,htdig,htsearch,htmerge,Scope,Language,помоћ,ХТМЛ,претрага,тражење,индекс,језик +X-KDE-Keywords[sr@ijekavianlatin]=Help,HTML,Search,Index,htdig,htsearch,htmerge,Scope,Language,pomoć,HTML,pretraga,traženje,indeks,jezik +X-KDE-Keywords[sr@latin]=Help,HTML,Search,Index,htdig,htsearch,htmerge,Scope,Language,pomoć,HTML,pretraga,traženje,indeks,jezik +X-KDE-Keywords[sv]=Hjälp,HTML,Sök,Index,htdig,htsearch,htmerge,Omfattning,Språk +X-KDE-Keywords[tg]=Кумак,HTML,Ҷустуҷӯ,Индекс,htdig,htsearch,htmerge,Намудсоз,Забон +X-KDE-Keywords[tr]=Yardım,HTML,Arama,Dizin,htdig,htsearch,htmerge,Kapsam,Dil +X-KDE-Keywords[ug]=ياردەم، HTML، ئىزدەش، ئىندېكس، htdig، htsearch، htmerge، دائىرە، تىل +X-KDE-Keywords[uk]=Help;HTML;Search;Index;htdig;htsearch;htmerge;Scope;Language;довідка;допомога;пошук;індекс;покажчик;область;мова +X-KDE-Keywords[vi]=Trợ giúp,HTML,Tìm kiếm,chỉ mục,htdig,htsearch,htmerge,Phạm vi,Ngôn ngữ,Help,HTML,Search,Index,htdig,htsearch,htmerge,Scope,Language +X-KDE-Keywords[wa]=Aidance,HTML,Cweri,Trover,Cachî,Cachî après,indecse,htdig,htsearch,htmerge,scope,fortchete,lingaedje +X-KDE-Keywords[x-test]=xxHelp,HTML,Search,Index,htdig,htsearch,htmerge,Scope,Languagexx +X-KDE-Keywords[zh_CN]=Help,HTML,Search,Index,htdig,htsearch,htmerge,Scope,Language,帮助,搜索,索引,语言 +X-KDE-Keywords[zh_TW]=Help,HTML,Search,Index,htdig,htsearch,htmerge,Scope,Language diff --git a/khelpcenter/htmlsearch/htmlsearch.h b/khelpcenter/htmlsearch/htmlsearch.h new file mode 100644 index 00000000..f93cb2b0 --- /dev/null +++ b/khelpcenter/htmlsearch/htmlsearch.h @@ -0,0 +1,62 @@ +#ifndef __HTMLSEARCH_H__ +#define __HTMLSEARCH_H__ + + + + + +class QWidget; + + +class K3Process; + + +class ProgressDialog; + + +class HTMLSearch : public QObject +{ + Q_OBJECT + +public: + + HTMLSearch(); + + bool generateIndex(const QString & lang, QWidget *parent=0); + + QString search(const QString & lang, const QString & words, const QString & method="and", int matches=10, + const QString & format="builtin-long", const QString & sort="score"); + + +protected Q_SLOTS: + + void htdigStdout(K3Process *proc, char *buffer, int buflen); + void htdigExited(K3Process *proc); + void htmergeExited(K3Process *proc); + void htsearchStdout(K3Process *proc, char *buffer, int buflen); + void htsearchExited(K3Process *proc); + + +protected: + + QString dataPath(const QString& lang); + + bool saveFilesList(const QString& lang); + void scanDir(const QString& dir); + + bool createConfig(const QString& lang); + + +private: + + QStringList _files; + K3Process *_proc; + int _filesToDig, _filesDigged, _filesScanned; + volatile bool _htdigRunning, _htmergeRunning, _htsearchRunning; + QString _searchResult; + ProgressDialog *progress; + +}; + + +#endif diff --git a/khelpcenter/htmlsearch/index.cpp b/khelpcenter/htmlsearch/index.cpp new file mode 100644 index 00000000..1532afe6 --- /dev/null +++ b/khelpcenter/htmlsearch/index.cpp @@ -0,0 +1,28 @@ + +#include +#include +#include +#include +#include + +#include "htmlsearch.h" + + +int main(int argc, char *argv[]) +{ + KAboutData aboutData( "khtmlindex", "htmlsearch", ki18n("KHtmlIndex"), + "", + ki18n("KDE Index generator for help files.")); + + KCmdLineArgs::init(argc, argv, &aboutData); + + KCmdLineOptions options; + options.add("lang ", ki18n("The language to index"), "en"); + KCmdLineArgs::addCmdLineOptions( options ); + + KApplication app; + HTMLSearch search; + + KCmdLineArgs *args = KCmdLineArgs::parsedArgs(); + search.generateIndex(args->getOption("lang")); +} diff --git a/khelpcenter/htmlsearch/kcmhtmlsearch.cpp b/khelpcenter/htmlsearch/kcmhtmlsearch.cpp new file mode 100644 index 00000000..9b6aa190 --- /dev/null +++ b/khelpcenter/htmlsearch/kcmhtmlsearch.cpp @@ -0,0 +1,377 @@ +/** + * kcmhtmlsearch.cpp + * + * Copyright (c) 2000 Matthias Hölzer-Klüpfel + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include "klangcombo.h" +#include +#include +#include +#include + +#include "kcmhtmlsearch.moc" + +K_PLUGIN_FACTORY(KHTMLSearchConfigFactory, registerPlugin();) +K_EXPORT_PLUGIN(KHTMLSearchConfigFactory("kcmhtmlsearch")) + +KHTMLSearchConfig::KHTMLSearchConfig(QWidget *parent, const QVariantList &) + : KCModule(KHTMLSearchConfigFactory::componentData(), parent), indexProc(0) +{ + QVBoxLayout *vbox = new QVBoxLayout(this); + vbox->setSpacing(5); + + + QGroupBox *gb = new QGroupBox(i18n("ht://dig"), this); + vbox->addWidget(gb); + + QGridLayout *grid = new QGridLayout(gb); + grid->setSpacing(6); + grid->setMargin(6); + + grid->addRowSpacing(0, gb->fontMetrics().lineSpacing()); + + QLabel *l = new QLabel(i18n("The fulltext search feature makes use of the " + "ht://dig HTML search engine. " + "You can get ht://dig at the"), gb); + l->setAlignment(QLabel::WordBreak); + l->setMinimumSize(l->sizeHint()); + grid->addWidget(l, 1, 0, 1, 2 ); + QWhatsThis::add( gb, i18n( "Information about where to get the ht://dig package." ) ); + + KUrlLabel *url = new KUrlLabel(gb); + url->setURL("http://www.htdig.org"); + url->setText(i18n("ht://dig home page")); + url->setAlignment(QLabel::AlignHCenter); + grid->addWidget(url, 2, 0, 1, 2 ); + connect(url, SIGNAL(leftClickedUrl(const QString&)), + this, SLOT(urlClicked(const QString&))); + + gb = new QGroupBox(i18n("Program Locations"), this); + + vbox->addWidget(gb); + grid = new QGridLayout(gb); + grid->setSpacing(6); + grid->setMargin(6); + grid->addRowSpacing(0, gb->fontMetrics().lineSpacing()); + + htdigBin = new KUrlRequester(gb); + l = new QLabel(i18n("ht&dig"),gb); + l->setBuddy(htdigBin); + grid->addWidget(l, 1,0); + grid->addWidget(htdigBin, 1,1); + connect(htdigBin->lineEdit(), SIGNAL(textChanged(const QString&)), this, SLOT(configChanged())); + QString wtstr = i18n( "Enter the path to your htdig program here, e.g. /usr/local/bin/htdig" ); + QWhatsThis::add( htdigBin, wtstr ); + QWhatsThis::add( l, wtstr ); + + htsearchBin = new KUrlRequester(gb); + l = new QLabel(i18n("ht&search"),gb); + l->setBuddy(htsearchBin); + grid->addWidget(l, 2,0); + grid->addWidget(htsearchBin, 2,1); + connect(htsearchBin->lineEdit(), SIGNAL(textChanged(const QString&)), this, SLOT(configChanged())); + wtstr = i18n( "Enter the path to your htsearch program here, e.g. /usr/local/bin/htsearch" ); + QWhatsThis::add( htsearchBin, wtstr ); + QWhatsThis::add( l, wtstr ); + + htmergeBin = new KUrlRequester(gb); + l = new QLabel(i18n("ht&merge"),gb); + l->setBuddy(htmergeBin); + grid->addWidget(l, 3,0); + grid->addWidget(htmergeBin, 3,1); + connect(htmergeBin->lineEdit(), SIGNAL(textChanged(const QString&)), this, SLOT(configChanged())); + wtstr = i18n( "Enter the path to your htmerge program here, e.g. /usr/local/bin/htmerge" ); + QWhatsThis::add( htmergeBin, wtstr ); + QWhatsThis::add( l, wtstr ); + + QHBoxLayout *hbox = new QHBoxLayout(vbox); + + gb = new QGroupBox(i18n("Scope"), this); + hbox->addWidget(gb); + QWhatsThis::add( gb, i18n( "Here you can select which parts of the documentation should be included in the fulltext search index. Available options are the KDE Help pages, the installed man pages, and the installed info pages. You can select any number of these." ) ); + + QVBoxLayout *vvbox = new QVBoxLayout(gb); + vvbox->setSpacing(2); + vvbox->setMargin(6); + vvbox->addSpacing(gb->fontMetrics().lineSpacing()); + + indexKDE = new QCheckBox(i18n("&KDE help"), gb); + vvbox->addWidget(indexKDE); + connect(indexKDE, SIGNAL(clicked()), this, SLOT(configChanged())); + + indexMan = new QCheckBox(i18n("&Man pages"), gb); + vvbox->addWidget(indexMan); + indexMan->setEnabled(false), + connect(indexMan, SIGNAL(clicked()), this, SLOT(configChanged())); + + indexInfo = new QCheckBox(i18n("&Info pages"), gb); + vvbox->addWidget(indexInfo); + indexInfo->setEnabled(false); + connect(indexInfo, SIGNAL(clicked()), this, SLOT(configChanged())); + + gb = new QGroupBox(i18n("Additional Search Paths"), this); + hbox->addWidget(gb); + QWhatsThis::add( gb, i18n( "Here you can add additional paths to search for documentation. To add a path, click on the Add... button and select the folder from where additional documentation should be searched. You can remove folders by clicking on the Delete button." ) ); + + grid = new QGridLayout(gb); + grid->setSpacing(2); + grid->setMargin(6); + grid->addRowSpacing(0, gb->fontMetrics().lineSpacing()); + + addButton = new QPushButton(i18n("Add..."), gb); + grid->addWidget(addButton, 1,0); + + delButton = new QPushButton(i18n("Delete"), gb); + grid->addWidget(delButton, 2,0); + + searchPaths = new KListWidget(gb); + grid->addWidget(searchPaths, 1, 1,3, 1); + grid->setRowStretch(2,2); + + gb = new QGroupBox(i18n("Language Settings"), this); + vbox->addWidget(gb); + QWhatsThis::add(gb, i18n("Here you can select the language you want to create the index for.")); + language = new KLanguageCombo(gb); + l = new QLabel(i18n("&Language"),gb); + l->setBuddy(language); + vvbox = new QVBoxLayout(gb); + vvbox->setSpacing(2); + vvbox->setMargin(6); + vvbox->addSpacing(gb->fontMetrics().lineSpacing()); + hbox = new QHBoxLayout(vvbox); + hbox->setSpacing(6); + hbox->addWidget(l); + hbox->addWidget(language,1); + hbox->addStretch(1); + + loadLanguages(); + + vbox->addStretch(1); + + runButton = new QPushButton(i18n("Generate Index..."), this); + QWhatsThis::add( runButton, i18n( "Click this button to generate the index for the fulltext search." ) ); + runButton->setFixedSize(runButton->sizeHint()); + vbox->addWidget(runButton, AlignRight); + connect(runButton, SIGNAL(clicked()), this, SLOT(generateIndex())); + + connect(addButton, SIGNAL(clicked()), this, SLOT(addClicked())); + connect(delButton, SIGNAL(clicked()), this, SLOT(delClicked())); + connect(searchPaths, SIGNAL(highlighted(const QString &)), + this, SLOT(pathSelected(const QString &))); + + checkButtons(); + + load(); +} + + +void KHTMLSearchConfig::loadLanguages() +{ + // clear the list + language->clear(); + + // add all languages to the list + QStringList langs = KGlobal::dirs()->findAllResources("locale", + QLatin1String("*/entry.desktop")); + langs.sort(); + + for (QStringList::ConstIterator it = langs.begin(); it != langs.end(); ++it) + { + KSimpleConfig entry(*it); + entry.setGroup(QLatin1String("KCM Locale")); + QString name = entry.readEntry(QLatin1String("Name"), i18n("without name")); + + QString path = *it; + int index = path.lastIndexOf('/'); + path = path.left(index); + index = path.lastIndexOf('/'); + path = path.mid(index+1); + language->insertLanguage(path, name); + } +} + + +QString KHTMLSearchConfig::quickHelp() const +{ + return i18n( "

Help Index

This configuration module lets you configure the ht://dig engine which can be used for fulltext search in the KDE documentation as well as other system documentation like man and info pages." ); +} + + +void KHTMLSearchConfig::pathSelected(const QString &) +{ + checkButtons(); +} + + +void KHTMLSearchConfig::checkButtons() +{ + + delButton->setEnabled(searchPaths->currentItem() >= 0); +} + + +void KHTMLSearchConfig::addClicked() +{ + QString dir = KFileDialog::getExistingDirectory(); + + if (!dir.isEmpty()) + { + for (uint i=0; icount(); ++i) + if (searchPaths->text(i) == dir) + return; + searchPaths->insertItem(dir); + configChanged(); + } +} + + +void KHTMLSearchConfig::delClicked() +{ + searchPaths->removeItem(searchPaths->currentItem()); + checkButtons(); + configChanged(); +} + + +KHTMLSearchConfig::~KHTMLSearchConfig() +{ +} + + +void KHTMLSearchConfig::configChanged() +{ + emit changed(true); +} + + +void KHTMLSearchConfig::load() +{ + KConfig *config = new KConfig("khelpcenterrc", true); + + config->setGroup("htdig"); + htdigBin->lineEdit()->setText(config->readPathEntry("htdig", kapp->dirs()->findExe("htdig"))); + htsearchBin->lineEdit()->setText(config->readPathEntry("htsearch", kapp->dirs()->findExe("htsearch"))); + htmergeBin->lineEdit()->setText(config->readPathEntry("htmerge", kapp->dirs()->findExe("htmerge"))); + + config->setGroup("Scope"); + indexKDE->setChecked(config->readEntry("KDE", true)); + indexMan->setChecked(config->readEntry("Man", false)); + indexInfo->setChecked(config->readEntry("Info", false)); + + QStringList l = config->readPathEntry("Paths", QStringList()); + searchPaths->clear(); + QStringList::const_iterator it; + for (it=l.begin(); it != l.end(); ++it) + searchPaths->insertItem(*it); + + config->setGroup("Locale"); + QString lang = config->readEntry("Search Language", KGlobal::locale()->language()); + language->setCurrentItem(lang); + delete config; + + emit changed(false); +} + + +void KHTMLSearchConfig::save() +{ + KConfig *config= new KConfig("khelpcenterrc", false); + + config->setGroup("htdig"); + config->writePathEntry("htdig", htdigBin->lineEdit()->text()); + config->writePathEntry("htsearch", htsearchBin->lineEdit()->text()); + config->writePathEntry("htmerge", htmergeBin->lineEdit()->text()); + + config->setGroup("Scope"); + config->writeEntry("KDE", indexKDE->isChecked()); + config->writeEntry("Man", indexMan->isChecked()); + config->writeEntry("Info", indexInfo->isChecked()); + + QStringList l; + for (uint i=0; icount(); ++i) + l.append(searchPaths->text(i)); + config->writePathEntry("Paths", l); + + config->setGroup("Locale"); + config->writeEntry("Search Language", language->currentTag()); + + config->sync(); + delete config; + + emit changed(false); +} + + +void KHTMLSearchConfig::defaults() +{ + htdigBin->lineEdit()->setText(kapp->dirs()->findExe("htdig")); + htsearchBin->lineEdit()->setText(kapp->dirs()->findExe("htsearch")); + htmergeBin->lineEdit()->setText(kapp->dirs()->findExe("htmerge")); + + indexKDE->setChecked(true); + indexMan->setChecked(false); + indexInfo->setChecked(false); + + searchPaths->clear(); + + language->setCurrentItem(KGlobal::locale()->language()); + + emit changed(true); +} + + +void KHTMLSearchConfig::urlClicked(const QString &url) +{ + KToolInvocation::invokeBrowser(url); +} + + +void KHTMLSearchConfig::generateIndex() +{ + save(); + + QString exe = kapp->dirs()->findExe("khtmlindex"); + if (exe.isEmpty()) + return; + + delete indexProc; + + indexProc = new K3Process; + *indexProc << exe << "--lang" << language->currentTag(); + + connect(indexProc, SIGNAL(processExited(K3Process *)), + this, SLOT(indexTerminated(K3Process *))); + + runButton->setEnabled(false); + + indexProc->start(); +} + + +void KHTMLSearchConfig::indexTerminated(K3Process *) +{ + runButton->setEnabled(true); +} diff --git a/khelpcenter/htmlsearch/kcmhtmlsearch.h b/khelpcenter/htmlsearch/kcmhtmlsearch.h new file mode 100644 index 00000000..40583909 --- /dev/null +++ b/khelpcenter/htmlsearch/kcmhtmlsearch.h @@ -0,0 +1,84 @@ +/** + * kcmhtmlsearch.h + * + * Copyright (c) 2000 Matthias Hölzer-Klüpfel + * + * 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. + */ + +#ifndef __kcmhtmlsearch_h__ +#define __kcmhtmlsearch_h__ + + +#define KDE3_SUPPORT +#include +#undef KDE3_SUPPORT +#include + + +class QCheckBox; +class QPushButton; +class KListWidget; +class K3Process; +class KLanguageCombo; +class KUrlRequester; +class QStringList; + +class KHTMLSearchConfig : public KCModule +{ + Q_OBJECT + +public: + + KHTMLSearchConfig(QWidget *parent, const QVariantList &args); + virtual ~KHTMLSearchConfig(); + + void load(); + void save(); + void defaults(); + + QString quickHelp() const; + + int buttons(); + + +protected Q_SLOTS: + + void configChanged(); + void addClicked(); + void delClicked(); + void pathSelected(const QString &); + void urlClicked(const QString&); + void generateIndex(); + + void indexTerminated(K3Process *proc); + + +private: + + void checkButtons(); + void loadLanguages(); + + KUrlRequester *htdigBin, *htsearchBin, *htmergeBin; + QCheckBox *indexKDE, *indexMan, *indexInfo; + QPushButton *addButton, *delButton, *runButton; + KListWidget *searchPaths; + KLanguageCombo *language; + + K3Process *indexProc; + +}; + +#endif diff --git a/khelpcenter/htmlsearch/klangcombo.cpp b/khelpcenter/htmlsearch/klangcombo.cpp new file mode 100644 index 00000000..6309e0d9 --- /dev/null +++ b/khelpcenter/htmlsearch/klangcombo.cpp @@ -0,0 +1,52 @@ +/* + * klangcombo.cpp - Adds some methods for inserting languages. + * + * Copyright (c) 1999-2000 Hans Petter Bieker + * + * Requires the Qt widget libraries, available at no cost at + * http://www.troll.no/ + * + * 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 "klangcombo.h" + +#include + +KLanguageCombo::~KLanguageCombo () +{ +} + +KLanguageCombo::KLanguageCombo (QWidget * parent, const char *name) + : KTagComboBox(parent, name) +{ +} + +void KLanguageCombo::insertLanguage(const QString& path, const QString& name, const QString& sub, const QString &submenu, int index) +{ + QString output = name + QLatin1String(" (") + path + QString::fromLatin1(")"); + QPixmap flag(locate("locale", sub + path + QLatin1String("/flag.png"))); + insertItem(QIcon(flag), output, path, submenu, index); +} + +void KLanguageCombo::changeLanguage(const QString& name, int i) +{ + if (i < 0 || i >= count()) return; + QString output = name + QLatin1String(" (") + tag(i) + QString::fromLatin1(")"); + changeItem(output, i); +} + +#include "klangcombo.moc" + diff --git a/khelpcenter/htmlsearch/klangcombo.h b/khelpcenter/htmlsearch/klangcombo.h new file mode 100644 index 00000000..85359612 --- /dev/null +++ b/khelpcenter/htmlsearch/klangcombo.h @@ -0,0 +1,47 @@ +/* + * klangcombo.h - Adds some methods for inserting languages. + * + * Copyright (c) 1999-2000 Hans Petter Bieker + * + * Requires the Qt widget libraries, available at no cost at + * http://www.troll.no/ + * + * 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. + */ + + +#ifndef __KLANGCOMBO_H__ +#define __KLANGCOMBO_H__ + +#include "ktagcombobox.h" + +/* + * Extends KTagCombo to support adding and changing languages. + * + * It has also support for sub menus. + */ +class KLanguageCombo : public KTagComboBox +{ + Q_OBJECT + +public: + explicit KLanguageCombo(QWidget *parent=0, const char *name=0); + ~KLanguageCombo(); + + void insertLanguage(const QString& path, const QString& name, const QString& sub = QString(), const QString &submenu = QString(), int index = -1); + void changeLanguage(const QString& name, int i); +}; + +#endif diff --git a/khelpcenter/htmlsearch/ktagcombobox.cpp b/khelpcenter/htmlsearch/ktagcombobox.cpp new file mode 100644 index 00000000..535715fd --- /dev/null +++ b/khelpcenter/htmlsearch/ktagcombobox.cpp @@ -0,0 +1,250 @@ +/* + * ktagcombobox.cpp - A combobox with support for submenues, icons and tags + * + * Copyright (c) 1999-2000 Hans Petter Bieker + * + * Requires the Qt widget libraries, available at no cost at + * http://www.troll.no/ + * + * 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. + */ + +#define INCLUDE_MENUITEM_DEF 1 +#include "ktagcombobox.h" + +#include + +#include + +KTagComboBox::~KTagComboBox () +{ + delete popup; +} + +KTagComboBox::KTagComboBox (QWidget * parent, const char *name) + : QComboBox(parent, name), + popup(0), + old_popup(0) +{ + clear(); +} + +void KTagComboBox::popupMenu() +{ + popup->popup( mapToGlobal( QPoint(0,0) ), current ); +} + +void KTagComboBox::keyPressEvent( QKeyEvent *e ) +{ + int c; + + if ( ( e->key() == Key_F4 && e->state() == 0 ) || + ( e->key() == Key_Down && (e->state() & AltButton) ) || + ( e->key() == Key_Space ) ) { + if ( count() ) { + popup->setActiveItem( current ); + popupMenu(); + } + return; + } else { + e->ignore(); + return; + } + + c = currentItem(); + emit highlighted( c ); + emit activated( c ); +} + +void KTagComboBox::mousePressEvent( QMouseEvent * ) +{ + popupMenu(); +} + +void KTagComboBox::internalActivate( int index ) +{ + if (current == index) return; + current = index; + emit activated( index ); + repaint(); +} + +void KTagComboBox::internalHighlight( int index ) +{ + emit highlighted( index ); +} + +void KTagComboBox::clear() +{ + tags.clear(); + + delete old_popup; + old_popup = popup; + popup = new QPopupMenu(this); + connect( popup, SIGNAL(activated(int)), + SLOT(internalActivate(int)) ); + connect( popup, SIGNAL(highlighted(int)), + SLOT(internalHighlight(int)) ); +} + +int KTagComboBox::count() const +{ + return tags.count(); +} + +static inline void checkInsertPos(QPopupMenu *popup, const QString & str, int &index) +{ + if (index == -2) index = popup->count(); + if (index != -1) return; + + int a = 0; + int b = popup->count(); + while (a <= b) { + int w = (a + b) / 2; + + int id = popup->idAt(w); + int j = str.compare(popup->text(id)); + + if (j > 0) + a = w + 1; + else + b = w - 1; + } + + index = a; // it doesn't really matter ... a == b here. +} + +static inline QPopupMenu *checkInsertIndex(QPopupMenu *popup, const QStringList& tags, const QString &submenu) +{ + int pos = tags.findIndex(submenu); + + QPopupMenu *pi = 0; + if (pos != -1) + { + QMenuItem *p = popup->findItem(pos); + pi = p?p->popup():0; + } + if (!pi) pi = popup; + + return pi; +} + +void KTagComboBox::insertItem(const QIcon& icon, const QString &text, const QString &tag, const QString &submenu, int index ) +{ + QPopupMenu *pi = checkInsertIndex(popup, tags, submenu); + checkInsertPos(pi, text, index); + pi->insertItem(icon, text, count(), index); + tags.append(tag); +} + +void KTagComboBox::insertItem(const QString &text, const QString &tag, const QString &submenu, int index ) +{ + QPopupMenu *pi = checkInsertIndex(popup, tags, submenu); + checkInsertPos(pi, text, index); + pi->insertItem(text, count(), index); + tags.append(tag); +} + +void KTagComboBox::insertSeparator(const QString &submenu, int index) +{ + QPopupMenu *pi = checkInsertIndex(popup, tags, submenu); + pi->insertSeparator(index); + tags.append(QString()); +} + +void KTagComboBox::insertSubmenu(const QString &text, const QString &tag, const QString &submenu, int index) +{ + QPopupMenu *pi = checkInsertIndex(popup, tags, submenu); + QPopupMenu *p = new QPopupMenu(pi); + checkInsertPos(pi, text, index); + pi->insertItem(text, p, count(), index); + tags.append(tag); + connect( p, SIGNAL(activated(int)), + SLOT(internalActivate(int)) ); + connect( p, SIGNAL(highlighted(int)), + SLOT(internalHighlight(int)) ); +} + +void KTagComboBox::paintEvent( QPaintEvent * ev) +{ + QComboBox::paintEvent(ev); + + QPainter p (this); + + // Text + QRect clip(2, 2, width() - 4, height() - 4); +#if 0 + if ( hasFocus() && style().guiStyle() != MotifStyle ) + p.setPen( colorGroup().highlightedText() ); +#endif + p.drawText(clip, AlignCenter | SingleLine, popup->text( current )); + + // Icon + QIcon *icon = popup->iconSet( this->current ); + if (icon) { + QPixmap pm = icon->pixmap(); + p.drawPixmap( 4, (height()-pm.height())/2, pm ); + } +} + +bool KTagComboBox::containsTag( const QString &str ) const +{ + return tags.contains(str) > 0; +} + +QString KTagComboBox::currentTag() const +{ + return tags.at(currentItem()); +} + +QString KTagComboBox::tag(int i) const +{ + if (i < 0 || i >= count()) + { + kDebug() << "KTagComboBox::tag(), unknown tag " << i; + return QString(); + } + return *tags.at(i); +} + +int KTagComboBox::currentItem() const +{ + return current; +} + +void KTagComboBox::setCurrentItem(int i) +{ + if (i < 0 || i >= count()) return; + current = i; + repaint(); +} + +void KTagComboBox::setCurrentItem(const QString &code) +{ + int i = tags.findIndex(code); + if (code.isNull()) + i = 0; + if (i != -1) + setCurrentItem(i); +} + +void KTagComboBox::setFont( const QFont &font ) +{ + QComboBox::setFont( font ); + popup->setFont( font ); +} + +#include "ktagcombobox.moc" + diff --git a/khelpcenter/htmlsearch/ktagcombobox.h b/khelpcenter/htmlsearch/ktagcombobox.h new file mode 100644 index 00000000..ccf9712f --- /dev/null +++ b/khelpcenter/htmlsearch/ktagcombobox.h @@ -0,0 +1,92 @@ +/* + * ktagcombobox.h - A combobox with support for submenues, icons and tags + * + * Copyright (c) 1999-2000 Hans Petter Bieker + * + * Requires the Qt widget libraries, available at no cost at + * http://www.troll.no/ + * + * 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. + */ + + +#ifndef __KTAGCOMBOBOX_H__ +#define __KTAGCOMBOBOX_H__ + +#include + +class QPopupMenu; + +/* + * This class should be just like qcombobox, but it should be possible + * to have have a QIcon for each entry, and each entry should have a tag. + * + * It has also support for sub menus. + */ +class KTagComboBox : public QComboBox +{ + Q_OBJECT + +public: + explicit KTagComboBox(QWidget *parent=0, const char *name=0); + ~KTagComboBox(); + + void insertItem(const QIcon& icon, const QString &text, const QString &tag, const QString &submenu = QString(), int index=-1 ); + void insertItem(const QString &text, const QString &tag, const QString &submenu = QString(), int index=-1 ); + void insertSeparator(const QString &submenu = QString(), int index=-1 ); + void insertSubmenu(const QString &text, const QString &tag, const QString &submenu = QString(), int index=-1); + + int count() const; + void clear(); + + /* + * Tag of the selected item + */ + QString currentTag() const; + QString tag ( int i ) const; + bool containsTag (const QString &str ) const; + + /* + * Set the current item + */ + int currentItem() const; + void setCurrentItem(int i); + void setCurrentItem(const QString &code); + + // widget stuff + virtual void setFont( const QFont & ); + +Q_SIGNALS: + void activated( int index ); + void highlighted( int index ); + +private Q_SLOTS: + void internalActivate( int ); + void internalHighlight( int ); + +protected: + void paintEvent( QPaintEvent * ); + void mousePressEvent( QMouseEvent * ); + void keyPressEvent( QKeyEvent *e ); + void popupMenu(); + +private: + // work space for the new class + QStringList tags; + QPopupMenu *popup, *old_popup; + int current; +}; + +#endif diff --git a/khelpcenter/htmlsearch/long.html b/khelpcenter/htmlsearch/long.html new file mode 100644 index 00000000..1d0fa4ce --- /dev/null +++ b/khelpcenter/htmlsearch/long.html @@ -0,0 +1,6 @@ +
$&(TITLE)$(STARSLEFT) +
$(EXCERPT)
+$&(URL) +$(MODIFIED), $(SIZE) bytes +
+ diff --git a/khelpcenter/htmlsearch/meinproc_wrapper b/khelpcenter/htmlsearch/meinproc_wrapper new file mode 100644 index 00000000..239cf746 --- /dev/null +++ b/khelpcenter/htmlsearch/meinproc_wrapper @@ -0,0 +1,4 @@ +#! /bin/sh + +file=`echo $3 | sed -e "s#http://localhost/#/#; s#file:/*#/#"` +meinproc --htdig $file diff --git a/khelpcenter/htmlsearch/nomatch.html b/khelpcenter/htmlsearch/nomatch.html new file mode 100644 index 00000000..30592703 --- /dev/null +++ b/khelpcenter/htmlsearch/nomatch.html @@ -0,0 +1,21 @@ +No match for '$&(LOGICAL_WORDS)' + +

+Search results

+
+

No matches were found for '$&(LOGICAL_WORDS)'

+

+Check the spelling of the search word(s) you used. +If the spelling is correct and you only used one word, +try using one or more similar search words with "Any." +

+If the spelling is correct and you used more than one +word with "Any," try using one or more similar search +words with "Any."

+If the spelling is correct and you used more than one +word with "All," try using one or more of the same words +with "Any."

+
+ +ht://Dig $(VERSION) + diff --git a/khelpcenter/htmlsearch/progressdialog.cpp b/khelpcenter/htmlsearch/progressdialog.cpp new file mode 100644 index 00000000..2cc89c0b --- /dev/null +++ b/khelpcenter/htmlsearch/progressdialog.cpp @@ -0,0 +1,81 @@ +#include +#include +#include + +#include +#include + + +#include "progressdialog.moc" + + +ProgressDialog::ProgressDialog(QWidget *parent, const char *name) + : KDialog( parent ) +{ + setCaption( i18n("Generating Index") ); + setButtons( Cancel ); + setDefaultButton( Cancel ); + setObjectName( name ); + setModal( false ); + + QGridLayout *grid = new QGridLayout(plainPage()); + grid->setSpacing(spacingHint()); + + QLabel *l = new QLabel(i18n("Scanning for files"), plainPage()); + grid->addWidget(l, 0, 1, 1,2); + + filesScanned = new QLabel(plainPage()); + grid->addWidget(filesScanned, 1,2); + setFilesScanned(0); + + check1 = new QLabel(plainPage()); + grid->addWidget(check1, 0,0); + + l = new QLabel(i18n("Extracting search terms"), plainPage()); + grid->addWidget(l, 2, 1, 1,2); + + bar = new QProgressBar(plainPage()); + grid->addWidget(bar, 3,2); + + check2 = new QLabel(plainPage()); + grid->addWidget(check2, 2,0); + + l = new QLabel(i18n("Generating index..."), plainPage()); + grid->addWidget(l, 4, 1, 1,2); + + check3 = new QLabel(plainPage()); + grid->addWidget(check3, 4,0); + + setState(0); + + setMinimumWidth(300); +} + + +void ProgressDialog::setFilesScanned(int n) +{ + filesScanned->setText(i18n("Files processed: %1", n)); +} + + +void ProgressDialog::setFilesToDig(int n) +{ + bar->setRange(0, n); +} + + +void ProgressDialog::setFilesDigged(int n) +{ + bar->setValue(n); +} + + +void ProgressDialog::setState(int n) +{ + QPixmap unchecked = QPixmap(locate("data", "khelpcenter/pics/unchecked.xpm")); + QPixmap checked = QPixmap(locate("data", "khelpcenter/pics/checked.xpm")); + + check1->setPixmap( n > 0 ? checked : unchecked); + check2->setPixmap( n > 1 ? checked : unchecked); + check3->setPixmap( n > 2 ? checked : unchecked); +} diff --git a/khelpcenter/htmlsearch/progressdialog.h b/khelpcenter/htmlsearch/progressdialog.h new file mode 100644 index 00000000..2b718572 --- /dev/null +++ b/khelpcenter/htmlsearch/progressdialog.h @@ -0,0 +1,32 @@ +#ifndef __PROGRESS_DIALOG_H__ +#define __PROGRESS_DIALOG_H__ + +#include + +class QLabel; +class QProgressBar; + +class ProgressDialog : public KDialog +{ + + Q_OBJECT + +public: + + explicit ProgressDialog(QWidget *parent=0, const char *name=0); + + void setFilesScanned(int s); + void setFilesToDig(int d); + void setFilesDigged(int d); + + void setState(int n); + +private: + + QLabel *filesScanned, *check1, *check2, *check3; + QProgressBar *bar; + +}; + + +#endif diff --git a/khelpcenter/htmlsearch/short.html b/khelpcenter/htmlsearch/short.html new file mode 100644 index 00000000..e3e5e447 --- /dev/null +++ b/khelpcenter/htmlsearch/short.html @@ -0,0 +1 @@ +$(STARSRIGHT) $&(TITLE)
diff --git a/khelpcenter/htmlsearch/star.png b/khelpcenter/htmlsearch/star.png new file mode 100644 index 00000000..1bddebcb Binary files /dev/null and b/khelpcenter/htmlsearch/star.png differ diff --git a/khelpcenter/htmlsearch/star_blank.png b/khelpcenter/htmlsearch/star_blank.png new file mode 100644 index 00000000..ede2fd36 Binary files /dev/null and b/khelpcenter/htmlsearch/star_blank.png differ diff --git a/khelpcenter/htmlsearch/syntax.html b/khelpcenter/htmlsearch/syntax.html new file mode 100644 index 00000000..e724fd90 --- /dev/null +++ b/khelpcenter/htmlsearch/syntax.html @@ -0,0 +1,19 @@ +Error in Boolean search for '$&(WORDS)' + +

+Error in Boolean search for '$&(LOGICAL_WORDS)'

+
+Boolean expressions need to be 'correct' in order for the search +system to use them. +The expression you entered has errors in it.

+Examples of correct expressions are: cat and dog, cat +not dog, cat or (dog not nose).
Note that +the operator not has the meaning of 'without'. +

+$(SYNTAXERROR) +
+
+ +ht://Dig $(VERSION) + + diff --git a/khelpcenter/htmlsearch/unchecked.xpm b/khelpcenter/htmlsearch/unchecked.xpm new file mode 100644 index 00000000..e447281a --- /dev/null +++ b/khelpcenter/htmlsearch/unchecked.xpm @@ -0,0 +1,22 @@ +/* XPM */ +static char*unchecked[]={ +"16 16 3 1", +"# c #000000", +"+ c #ffffff", +". c None", +"................", +"................", +"..++++++++++++..", +"..+##########+..", +"..+#++++++++#+..", +"..+#+......+#+..", +"..+#+......+#+..", +"..+#+......+#+..", +"..+#+......+#+..", +"..+#+......+#+..", +"..+#+......+#+..", +"..+#++++++++#+..", +"..+##########+..", +"..++++++++++++..", +"................", +"................"}; diff --git a/khelpcenter/htmlsearch/wrapper.html b/khelpcenter/htmlsearch/wrapper.html new file mode 100644 index 00000000..251266de --- /dev/null +++ b/khelpcenter/htmlsearch/wrapper.html @@ -0,0 +1,16 @@ +Search results for '$&(WORDS)' + +

+Search results for '$&(LOGICAL_WORDS)'

+
+ +More *'s indicate a better match. + +
+$(HTSEARCH_RESULTS) +$(PAGEHEADER) +$(PREVPAGE) $(PAGELIST) $(NEXTPAGE) +
+ +ht://Dig $(VERSION) + diff --git a/khelpcenter/htmlsearchconfig.cpp b/khelpcenter/htmlsearchconfig.cpp new file mode 100644 index 00000000..36780b9b --- /dev/null +++ b/khelpcenter/htmlsearchconfig.cpp @@ -0,0 +1,159 @@ +/** + * kcmhtmlsearch.cpp + * + * Copyright (c) 2000 Matthias Hölzer-Klüpfel + * + * 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 "htmlsearchconfig.h" + +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace KHC { + +HtmlSearchConfig::HtmlSearchConfig(QWidget *parent, const char *name) + : QWidget(parent) +{ + setObjectName( name ); + + QVBoxLayout *vbox = new QVBoxLayout(this); + vbox->setMargin( 5 ); + + + QGroupBox *gb = new QGroupBox(i18n("ht://dig"), this); + vbox->addWidget(gb); + + QGridLayout *grid = new QGridLayout(gb); + grid->setMargin( 6 ); + grid->setSpacing( 6 ); + + grid->addItem( new QSpacerItem( 0, gb->fontMetrics().lineSpacing() ), 0, 0 ); + + QLabel *l = new QLabel(i18n("The fulltext search feature makes use of the " + "ht://dig HTML search engine."), gb); + l->setMinimumSize(l->sizeHint()); + grid->addWidget(l, 1, 1, 0, 1); + gb->setWhatsThis( i18n( "Information about where to get the ht://dig package." ) ); + + KUrlLabel *url = new KUrlLabel(gb); + url->setUrl(QLatin1String("http://www.htdig.org")); + url->setText(i18n("You can get ht://dig at the ht://dig home page")); + url->setAlignment(Qt::AlignHCenter); + grid->addWidget(url, 2,2, 0, 1); + connect(url, SIGNAL(leftClickedUrl(const QString&)), + this, SLOT(urlClicked(const QString&))); + + gb = new QGroupBox(i18n("Program Locations"), this); + + vbox->addWidget(gb); + grid = new QGridLayout(gb); + grid->setMargin( 6 ); + grid->setSpacing( 6 ); + grid->addItem( new QSpacerItem( 0, gb->fontMetrics().lineSpacing() ), 0, 0 ); + + mHtsearchUrl = new KUrlRequester(gb); + l = new QLabel(i18n("htsearch:"), gb); + l->setBuddy( mHtsearchUrl ); + grid->addWidget(l, 1,0); + grid->addWidget(mHtsearchUrl, 1,1); + connect( mHtsearchUrl->lineEdit(), SIGNAL( textChanged( const QString & ) ), + SIGNAL( changed() ) ); + QString wtstr = i18n( "Enter the URL of the htsearch CGI program." ); + mHtsearchUrl->setWhatsThis( wtstr ); + l->setWhatsThis( wtstr ); + + mIndexerBin = new KUrlRequester(gb); + l = new QLabel(i18n("Indexer:"), gb); + l->setBuddy( mIndexerBin ); + grid->addWidget(l, 2,0); + grid->addWidget(mIndexerBin, 2,1); + connect( mIndexerBin->lineEdit(), SIGNAL( textChanged( const QString & ) ), + SIGNAL( changed() ) ); + wtstr = i18n( "Enter the path to your htdig indexer program here." ); + mIndexerBin->setWhatsThis( wtstr ); + l->setWhatsThis( wtstr ); + + mDbDir = new KUrlRequester(gb); + mDbDir->setMode( KFile::Directory | KFile::LocalOnly ); + l = new QLabel(i18n("htdig database:"), gb); + l->setBuddy( mDbDir ); + grid->addWidget(l, 3,0); + grid->addWidget(mDbDir, 3,1); + connect( mDbDir->lineEdit(), SIGNAL( textChanged( const QString & ) ), + SIGNAL( changed() ) ); + wtstr = i18n( "Enter the path to the htdig database folder." ); + mDbDir->setWhatsThis( wtstr ); + l->setWhatsThis( wtstr ); +} + +HtmlSearchConfig::~HtmlSearchConfig() +{ + kDebug() << "~HtmlSearchConfig()"; +} + +void HtmlSearchConfig::makeReadOnly() +{ + mHtsearchUrl->setEnabled( false ); + mIndexerBin->setEnabled( false ); + mDbDir->setEnabled( false ); +} + +void HtmlSearchConfig::load( KConfig *config ) +{ + mHtsearchUrl->lineEdit()->setText(config->group("htdig").readPathEntry("htsearch", KGlobal::mainComponent().dirs()->findExe("htsearch"))); + mIndexerBin->lineEdit()->setText(config->group("htdig").readPathEntry("indexer", QString())); + mDbDir->lineEdit()->setText(config->group("htdig").readPathEntry("dbdir", "/opt/www/htdig/db/" ) ); +} + +void HtmlSearchConfig::save( KConfig *config ) +{ + config->group("htdig").writePathEntry("htsearch", mHtsearchUrl->lineEdit()->text()); + config->group("htdig").writePathEntry("indexer", mIndexerBin->lineEdit()->text()); + config->group("htdig").writePathEntry("dbdir", mDbDir->lineEdit()->text()); +} + +void HtmlSearchConfig::defaults() +{ + mHtsearchUrl->lineEdit()->setText(KGlobal::mainComponent().dirs()->findExe("htsearch")); + mIndexerBin->lineEdit()->setText(""); + mDbDir->lineEdit()->setText(QLatin1String("/opt/www/htdig/db/") ); +} + +void HtmlSearchConfig::urlClicked(const QString &url) +{ + KToolInvocation::invokeBrowser(url); +} + +} // End namespace KHC +// vim:ts=2:sw=2:et + +#include "htmlsearchconfig.moc" + diff --git a/khelpcenter/htmlsearchconfig.h b/khelpcenter/htmlsearchconfig.h new file mode 100644 index 00000000..a93567d0 --- /dev/null +++ b/khelpcenter/htmlsearchconfig.h @@ -0,0 +1,58 @@ +/** + * This file is part of KHelpCenter + * + * Copyright (c) 2000 Matthias Hölzer-Klüpfel + * + * 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. + */ + +#ifndef KHC_HTMLSEARCHCONFIG_H +#define KHC_HTMLSEARCHCONFIG_H + +#include + +class KUrlRequester; +class KConfig; + +namespace KHC { + +class HtmlSearchConfig : public QWidget +{ + Q_OBJECT + public: + explicit HtmlSearchConfig(QWidget *parent = 0L, const char *name = 0L); + virtual ~HtmlSearchConfig(); + + void load( KConfig * ); + void save( KConfig * ); + void defaults(); + void makeReadOnly(); + + Q_SIGNALS: + void changed(); + + protected Q_SLOTS: + void urlClicked(const QString&); + + private: + KUrlRequester *mHtsearchUrl; + KUrlRequester *mIndexerBin; + KUrlRequester *mDbDir; +}; + +} + +#endif //KHC_HTMLSEARCHCONFIG_H +// vim:ts=2:sw=2:et diff --git a/khelpcenter/index.html.in b/khelpcenter/index.html.in new file mode 100644 index 00000000..ec8ea453 --- /dev/null +++ b/khelpcenter/index.html.in @@ -0,0 +1,42 @@ + + + + %1 + + + + +
+
+ +
+
+ +
+
+ %2 +
+
+ %3 +
+
+ +
+
+ +
+
+ + + diff --git a/khelpcenter/infotree.cpp b/khelpcenter/infotree.cpp new file mode 100644 index 00000000..ec2136ca --- /dev/null +++ b/khelpcenter/infotree.cpp @@ -0,0 +1,194 @@ +/* + * This file is part of the KDE Help Center + * + * Copyright (C) 2002 Frerich Raabe (raabe@kde.org) + * + * 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 "infotree.h" + +#include "navigatoritem.h" +#include "docentry.h" + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include // for getenv() + +using namespace KHC; + +class InfoCategoryItem : public NavigatorItem +{ + public: + InfoCategoryItem( NavigatorItem *parent, const QString &text ); + + virtual void setExpanded( bool open ); +}; + +class InfoNodeItem : public NavigatorItem +{ + public: + InfoNodeItem( InfoCategoryItem *parent, const QString &text ); +}; + +InfoCategoryItem::InfoCategoryItem( NavigatorItem *parent, const QString &text ) + : NavigatorItem( new DocEntry( text ), parent ) +{ + setAutoDeleteDocEntry( true ); + setExpanded( false ); +// kDebug(1400) << "Got category: " << text; +} + +void InfoCategoryItem::setExpanded( bool open ) +{ + NavigatorItem::setExpanded( open ); + + if ( open && childCount() > 0 ) setIcon( 0, SmallIcon( "help-contents" ) ); +// TODO: was contents2 -> needs to be changed to help-contents-alternate or similar + else setIcon( 0, SmallIcon( "help-contents" ) ); +} + +InfoNodeItem::InfoNodeItem( InfoCategoryItem *parent, const QString &text ) + : NavigatorItem( new DocEntry( text ), parent ) +{ + setAutoDeleteDocEntry( true ); +// kDebug( 1400 ) << "Created info node item: " << text; +} + +InfoTree::InfoTree( QObject *parent ) + : TreeBuilder( parent ), + m_parentItem( 0 ) +{ +} + +void InfoTree::build( NavigatorItem *parent ) +{ + kDebug( 1400 ) << "Populating info tree."; + + m_parentItem = parent; + + DocEntry *entry = new DocEntry( i18n( "Alphabetically" ) ); + m_alphabItem = new NavigatorItem( entry, parent ); + m_alphabItem->setAutoDeleteDocEntry( true ); + entry = new DocEntry( i18n( "By Category" ) ); + m_categoryItem = new NavigatorItem( entry, parent ); + m_categoryItem->setAutoDeleteDocEntry( true ); + + KConfigGroup cfg(KGlobal::config(), "Info pages"); + QStringList infoDirFiles = cfg.readEntry( "Search paths" , QStringList() ); + // Default paths taken fron kdebase/kioslave/info/kde-info2html.conf + if ( infoDirFiles.isEmpty() ) { + infoDirFiles << "/usr/share/info"; + infoDirFiles << "/usr/info"; + infoDirFiles << "/usr/lib/info"; + infoDirFiles << "/usr/local/info"; + infoDirFiles << "/usr/local/lib/info"; + infoDirFiles << "/usr/X11R6/info"; + infoDirFiles << "/usr/X11R6/lib/info"; + infoDirFiles << "/usr/X11R6/lib/xemacs/info"; + } + + QString infoPath = ::getenv( "INFOPATH" ); + if ( !infoPath.isEmpty() ) + infoDirFiles += infoPath.split( ':'); + + QStringList::ConstIterator it = infoDirFiles.constBegin(); + QStringList::ConstIterator end = infoDirFiles.constEnd(); + for ( ; it != end; ++it ) { + QString infoDirFileName = *it + "/dir"; + if ( QFile::exists( infoDirFileName ) ) + parseInfoDirFile( infoDirFileName ); + } + + m_alphabItem->sortChildren( 0, Qt::AscendingOrder /* ascending */ ); +} + +void InfoTree::parseInfoDirFile( const QString &infoDirFileName ) +{ + kDebug( 1400 ) << "Parsing info dir file " << infoDirFileName; + + QFile infoDirFile( infoDirFileName ); + if ( !infoDirFile.open( QIODevice::ReadOnly ) ) + return; + + QTextStream stream( &infoDirFile ); + // Skip introduction blurb. + while ( !stream.atEnd() && !stream.readLine().startsWith( QLatin1String("* Menu:") ) ) { + ; + } + + while ( !stream.atEnd() ) { + QString s = stream.readLine(); + if ( s.trimmed().isEmpty() ) + continue; + + InfoCategoryItem *catItem = new InfoCategoryItem( m_categoryItem, s ); + while ( !stream.atEnd() && !s.trimmed().isEmpty() ) { + s = stream.readLine(); + if ( s[ 0 ] == '*' ) { + const int colon = s.indexOf( ":" ); + const int openBrace = s.indexOf( "(", colon ); + const int closeBrace = s.indexOf( ")", openBrace ); + const int dot = s.indexOf( ".", closeBrace ); + + QString appName = s.mid( 2, colon - 2 ); + QString url = "info:/" + s.mid( openBrace + 1, closeBrace - openBrace - 1 ); + if ( dot - closeBrace > 1 ) + url += QLatin1Char('/') + s.mid( closeBrace + 1, dot - closeBrace - 1 ); + else + url += QLatin1String("/Top"); + + InfoNodeItem *item = new InfoNodeItem( catItem, appName ); + item->entry()->setUrl( url ); + + InfoCategoryItem *alphabSection = 0; + + QTreeWidgetItemIterator it( m_alphabItem ); + while ( (*it) ) + { + if ( (*it)->text( 0 ) == QString( appName[ 0 ].toUpper() ) ) + { + alphabSection = static_cast( (*it) ); + break; + } + ++it; + } + + if ( alphabSection == 0 ) + alphabSection = new InfoCategoryItem( m_alphabItem, QString( appName[ 0 ].toUpper() ) ); + + item = new InfoNodeItem( alphabSection, appName ); + item->entry()->setUrl( url ); + } + } + } + infoDirFile.close(); +} + +#include "infotree.moc" +// vim:ts=2:sw=2:et diff --git a/khelpcenter/infotree.h b/khelpcenter/infotree.h new file mode 100644 index 00000000..cd704656 --- /dev/null +++ b/khelpcenter/infotree.h @@ -0,0 +1,46 @@ +/* + * infotree.h - part of the KDE Help Center + * + * Copyright (C) 2002 Frerich Raabe (raabe@kde.org) + * + * 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. + */ +#ifndef KHC_INFOTREE_H +#define KHC_INFOTREE_H + +#include "treebuilder.h" + +namespace KHC +{ + class NavigatorItem; + class InfoTree : public TreeBuilder + { + Q_OBJECT + public: + InfoTree( QObject *parent ); + + virtual void build( NavigatorItem *parentItem ); + + private: + void parseInfoDirFile( const QString &fileName ); + + NavigatorItem *m_parentItem; + NavigatorItem *m_alphabItem; + NavigatorItem *m_categoryItem; + }; +} + +#endif // KHC_INFOTREE_H +// vim:ts=2:sw=2:et diff --git a/khelpcenter/kcmhelpcenter.cpp b/khelpcenter/kcmhelpcenter.cpp new file mode 100644 index 00000000..9f91d0b5 --- /dev/null +++ b/khelpcenter/kcmhelpcenter.cpp @@ -0,0 +1,693 @@ +/* + This file is part of KHelpcenter. + + Copyright (C) 2002 Cornelius Schumacher + + 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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "kcmhelpcenter.h" + +#include "htmlsearchconfig.h" +#include "docmetainfo.h" +#include "prefs.h" +#include "searchhandler.h" +#include "searchengine.h" + +#include "kcmhelpcenteradaptor.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +using namespace KHC; + +IndexDirDialog::IndexDirDialog( QWidget *parent ) + : KDialog( parent ) +{ + setModal( true ); + setCaption( i18n("Change Index Folder") ); + setButtons( Ok | Cancel ); + + QFrame *topFrame = new QFrame( this ); + setMainWidget( topFrame ); + + QBoxLayout *urlLayout = new QHBoxLayout( topFrame ); + + QLabel *label = new QLabel( i18n("Index folder:"), topFrame ); + urlLayout->addWidget( label ); + + mIndexUrlRequester = new KUrlRequester( topFrame ); + mIndexUrlRequester->setMode( KFile::Directory | KFile::ExistingOnly | + KFile::LocalOnly ); + urlLayout->addWidget( mIndexUrlRequester ); + + mIndexUrlRequester->setUrl( Prefs::indexDirectory() ); + connect(mIndexUrlRequester->lineEdit(),SIGNAL(textChanged ( const QString & )), this, SLOT(slotUrlChanged( const QString &))); + slotUrlChanged( mIndexUrlRequester->lineEdit()->text() ); + + connect( this, SIGNAL( okClicked() ), SLOT( slotOk() ) ); +} + +void IndexDirDialog::slotUrlChanged( const QString &_url ) +{ + enableButtonOk( !_url.isEmpty() ); +} + + +void IndexDirDialog::slotOk() +{ + Prefs::setIndexDirectory( mIndexUrlRequester->url().url() ); + accept(); +} + + +IndexProgressDialog::IndexProgressDialog( QWidget *parent ) + : KDialog( parent ), + mFinished( true ) +{ + setCaption( i18n("Build Search Indices") ); + + QVBoxLayout *topLayout = new QVBoxLayout( mainWidget() ); + topLayout->setMargin( marginHint() ); + topLayout->setSpacing( spacingHint() ); + + mLabel = new QLabel( mainWidget() ); + mLabel->setAlignment( Qt::AlignHCenter ); + topLayout->addWidget( mLabel ); + + mProgressBar = new QProgressBar( mainWidget() ); + topLayout->addWidget( mProgressBar ); + + mLogLabel = new QLabel( i18n("Index creation log:"), mainWidget() ); + topLayout->addWidget( mLogLabel ); + + mLogView = new QTextEdit( mainWidget() ); + mLogView->setReadOnly( true ); + mLogView->setWordWrapMode( QTextOption::NoWrap ); + mLogView->setMinimumHeight( 200 ); + topLayout->addWidget( mLogView ); + + setButtons( User1 | Close ); + connect( this, SIGNAL( closeClicked() ), SLOT( slotEnd() ) ); + connect( this, SIGNAL( user1Clicked() ), SLOT( toggleDetails() ) ); + + hideDetails(); + + setFinished( false ); +} + +IndexProgressDialog::~IndexProgressDialog() +{ + if ( !mLogView->isHidden() ) { + KConfigGroup cfg(KGlobal::config(), "indexprogressdialog"); + cfg.writeEntry( "size", size() ); + } +} + +void IndexProgressDialog::setTotalSteps( int steps ) +{ + mProgressBar->setRange( 0, steps ); + mProgressBar->setValue( 0 ); + setFinished( false ); + mLogView->clear(); +} + +void IndexProgressDialog::advanceProgress() +{ + mProgressBar->setValue( mProgressBar->value() + 1 ); +} + +void IndexProgressDialog::setLabelText( const QString &text ) +{ + mLabel->setText( text ); +} + +void IndexProgressDialog::setMinimumLabelWidth( int width ) +{ + mLabel->setMinimumWidth( width ); +} + +void IndexProgressDialog::setFinished( bool finished ) +{ + if ( finished == mFinished ) return; + + mFinished = finished; + + if ( mFinished ) { + setButtonText( Close, i18nc("Label for button to close search index progress dialog after successful completion", "Close") ); + mLabel->setText( i18n("Index creation finished.") ); + mProgressBar->setValue( mProgressBar->maximum() ); + } else { + setButtonText( Close, i18nc("Label for stopping search index generation before completion", "Stop") ); + } +} + +void IndexProgressDialog::appendLog( const QString &text ) +{ + mLogView->append( text ); +} + +void IndexProgressDialog::slotEnd() +{ + if ( mFinished ) { + emit closed(); + accept(); + } else { + emit cancelled(); + reject(); + } +} + +void IndexProgressDialog::toggleDetails() +{ + KConfigGroup cfg(KGlobal::config(), "indexprogressdialog"); + if ( mLogView->isHidden() ) { + mLogLabel->show(); + mLogView->show(); + setButtonText( User1, i18n("Details <<") ); + QSize size = cfg.readEntry( "size", QSize() ); + if ( !size.isEmpty() ) resize( size ); + } else { + cfg.writeEntry( "size", size() ); + hideDetails(); + } +} + +void IndexProgressDialog::hideDetails() +{ + mLogLabel->hide(); + mLogView->hide(); + setButtonText( User1, i18n("Details >>") ); + + // causes bug 166343 + //layout()->activate(); + adjustSize(); +} + + +KCMHelpCenter::KCMHelpCenter( KHC::SearchEngine *engine, QWidget *parent, + const char *name) + : KDialog( parent ), + mEngine( engine ), mProgressDialog( 0 ), mCmdFile( 0 ), + mProcess( 0 ), mIsClosing( false ), mRunAsRoot( false ) +{ + new KcmhelpcenterAdaptor(this); + QDBusConnection::sessionBus().registerObject(QLatin1String("/kcmhelpcenter"), this); + setObjectName( name ); + setCaption( i18n("Build Search Index") ); + setButtons( Ok | Cancel ); + + QWidget *widget = new QWidget( this ); + setMainWidget( widget ); + + setupMainWidget( widget ); + + setButtonGuiItem( KDialog::Ok, KGuiItem(i18n("Build Index")) ); + + mConfig = KGlobal::config(); + + DocMetaInfo::self()->scanMetaInfo(); + + load(); + const QString dbusInterface = "org.kde.khelpcenter.kcmhelpcenter"; + QDBusConnection dbus = QDBusConnection::sessionBus(); + bool success = dbus.connect(QString(), "/kcmhelpcenter", dbusInterface, "buildIndexProgress", this, SLOT(slotIndexProgress())); + if ( !success ) + kError() << "connect D-Bus signal failed" << endl; + success = dbus.connect(QString(), "/kcmhelpcenter", dbusInterface, "buildIndexError", this, SLOT(slotIndexError(const QString&))); + if ( !success ) + kError() << "connect D-Bus signal failed" << endl; + KConfigGroup id( mConfig, "IndexDialog" ); + restoreDialogSize( id ); +} + +KCMHelpCenter::~KCMHelpCenter() +{ + KConfigGroup cg( KGlobal::config(), "IndexDialog" ); + KDialog::saveDialogSize( cg ); +} + +void KCMHelpCenter::setupMainWidget( QWidget *parent ) +{ + QVBoxLayout *topLayout = new QVBoxLayout( parent ); + topLayout->setSpacing( KDialog::spacingHint() ); + + QString helpText = + i18n("To be able to search a document, a search\n" + "index needs to exist. The status column of the list below shows whether an index\n" + "for a document exists.\n") + + i18n("To create an index, check the box in the list and press the\n" + "\"Build Index\" button.\n"); + + QLabel *label = new QLabel( helpText, parent ); + topLayout->addWidget( label ); + + mListView = new QTreeWidget( parent ); + //mListView->setFullWidth( true ); + mListView->setColumnCount(2); + mListView->setHeaderLabels( QStringList() << i18n("Search Scope") << i18n("Status") ); + topLayout->addWidget( mListView ); + // not just itemClicked, so that Key_Space also triggers it (#123954) + connect( mListView, SIGNAL(itemChanged(QTreeWidgetItem*,int)), + SLOT(checkSelection()) ); + + QBoxLayout *urlLayout = new QHBoxLayout(); + topLayout->addLayout( urlLayout ); + + QLabel *urlLabel = new QLabel( i18n("Index folder:"), parent ); + urlLayout->addWidget( urlLabel ); + + mIndexDirLabel = new QLabel( parent ); + urlLayout->addWidget( mIndexDirLabel, 1 ); + + QPushButton *button = new QPushButton( i18n("Change..."), parent ); + connect( button, SIGNAL( clicked() ), SLOT( showIndexDirDialog() ) ); + urlLayout->addWidget( button ); + + QBoxLayout *buttonLayout = new QHBoxLayout(); + topLayout->addLayout( buttonLayout ); + + buttonLayout->addStretch( 1 ); + + connect( this, SIGNAL( okClicked() ), SLOT( slotOk() ) ); +} + +void KCMHelpCenter::defaults() +{ +} + +bool KCMHelpCenter::save() +{ + kDebug(1401) << "KCMHelpCenter::save()"; + + if ( !QFile::exists( Prefs::indexDirectory() ) ) { + KMessageBox::sorry( this, + i18n("The folder %1 does not exist; unable to create index.", + Prefs::indexDirectory() ) ); + return false; + } else { + return buildIndex(); + } + + return true; +} + +void KCMHelpCenter::load() +{ + mIndexDirLabel->setText( Prefs::indexDirectory() ); + + mListView->clear(); + + const DocEntry::List &entries = DocMetaInfo::self()->docEntries(); + DocEntry::List::ConstIterator it; + for( it = entries.begin(); it != entries.end(); ++it ) { +// kDebug(1401) << "Entry: " << (*it)->name() << " Indexer: '" +// << (*it)->indexer() << "'" << endl; + if ( mEngine->needsIndex( *it ) ) { + ScopeItem *item = new ScopeItem( mListView, *it ); + item->setOn( (*it)->searchEnabled() ); + } + } + + mListView->header()->setResizeMode( QHeaderView::ResizeToContents ); + + updateStatus(); +} + +void KCMHelpCenter::updateStatus() +{ + QTreeWidgetItemIterator it( mListView ); + while ( (*it) != 0 ) { + ScopeItem *item = static_cast( (*it) ); + QString status; + if ( item->entry()->indexExists( Prefs::indexDirectory() ) ) { + status = i18nc("Describes the status of a documentation index that is present", "OK"); + item->setOn( false ); + } else { + status = i18nc("Describes the status of a documentation index that is missing", "Missing"); + } + item->setText( 1, status ); + + ++it; + } + + checkSelection(); +} + +bool KCMHelpCenter::buildIndex() +{ + kDebug(1401) << "Build Index"; + + kDebug() << "IndexPath: '" << Prefs::indexDirectory() << "'"; + + if ( mProcess ) { + kError() << "Error: Index Process still running." << endl; + return false; + } + + mIndexQueue.clear(); + + QFontMetrics fm( font() ); + int maxWidth = 0; + + mCmdFile = new KTemporaryFile; + if ( !mCmdFile->open() ) { + kError() << "Error opening command file." << endl; + deleteCmdFile(); + return false; + } + + QTextStream ts ( mCmdFile ); + kDebug() << "Writing to file '" << mCmdFile->fileName() << "'"; + + bool hasError = false; + + QTreeWidgetItemIterator it( mListView ); + while ( (*it) != 0 ) { + ScopeItem *item = static_cast( (*it) ); + if ( item->isOn() ) { + DocEntry *entry = item->entry(); + + QString docText = i18nc(" Generic prefix label for error messages when creating documentation index, first arg is the document's identifier, second is the document's name", "Document '%1' (%2):\n", + entry->identifier() , + entry->name() ); + if ( entry->documentType().isEmpty() ) { + KMessageBox::sorry( this, docText + + i18n("No document type.") ); + hasError = true; + } else { + QString error; + SearchHandler *handler = mEngine->handler( entry->documentType() ); + if ( !handler ) { + KMessageBox::sorry( this, docText + + i18n("No search handler available for document type '%1'.", + entry->documentType() ) ); + hasError = true; + } else if ( !handler->checkPaths( &error ) ) { + KMessageBox::sorry( this, docText + error ); + hasError = true; + } else { + QString indexer = handler->indexCommand( entry->identifier() ); + if ( indexer.isEmpty() ) { + KMessageBox::sorry( this, docText + + i18n("No indexing command specified for document type '%1'.", + entry->documentType() ) ); + hasError = true; + } else { + indexer.replace( QLatin1String("%i" ), entry->identifier() ); + indexer.replace( QLatin1String( "%d" ), Prefs::indexDirectory() ); + indexer.replace( QLatin1String( "%p" ), entry->url() ); + kDebug() << "INDEXER: " << indexer; + ts << indexer << endl; + + int width = fm.width( entry->name() ); + if ( width > maxWidth ) maxWidth = width; + + mIndexQueue.append( entry ); + } + } + } + } + ++it; + } + + ts.flush(); + + if ( mIndexQueue.isEmpty() ) { + deleteCmdFile(); + return !hasError; + } + + mCurrentEntry = mIndexQueue.constBegin(); + QString name = (*mCurrentEntry)->name(); + + if ( !mProgressDialog ) { + mProgressDialog = new IndexProgressDialog( parentWidget() ); + connect( mProgressDialog, SIGNAL( cancelled() ), + SLOT( cancelBuildIndex() ) ); + connect( mProgressDialog, SIGNAL( closed() ), + SLOT( slotProgressClosed() ) ); + } + mProgressDialog->setLabelText( name ); + mProgressDialog->setTotalSteps( mIndexQueue.count() ); + mProgressDialog->setMinimumLabelWidth( maxWidth ); + mProgressDialog->show(); + + startIndexProcess(); + + return true; +} + +void KCMHelpCenter::startIndexProcess() +{ + kDebug() << "KCMHelpCenter::startIndexProcess()"; + + mProcess = new KProcess; +#ifndef Q_WS_WIN + if ( mRunAsRoot ) { + QString kdesu = KStandardDirs::findExe("kdesu"); + if(kdesu.isEmpty()) { + kError() << "Failed to run index process as root - could not find kdesu"; + } else { + *mProcess << kdesu; + if(parentWidget()) { + *mProcess << "--attach" << QString::number(parentWidget()->window()->winId()); + kDebug() << "Run as root, attaching kdesu to winid " << QString::number(parentWidget()->window()->winId()); + } + *mProcess << "--"; + } + } +#endif + + *mProcess << KStandardDirs::findExe("khc_indexbuilder"); + *mProcess << mCmdFile->fileName(); + *mProcess << Prefs::indexDirectory(); + + mProcess->setOutputChannelMode(KProcess::SeparateChannels); + connect( mProcess, SIGNAL( readyReadStandardError() ), + SLOT( slotReceivedStderr() ) ); + connect( mProcess, SIGNAL( readyReadStandardOutput() ), + SLOT( slotReceivedStdout() ) ); + connect( mProcess, SIGNAL( finished(int, QProcess::ExitStatus) ), + SLOT( slotIndexFinished(int, QProcess::ExitStatus) ) ); + + mProcess->start(); + if (!mProcess->waitForStarted()) { + kError() << "KCMHelpcenter::startIndexProcess(): Failed to start process."; + deleteProcess(); + deleteCmdFile(); + } +} + +void KCMHelpCenter::cancelBuildIndex() +{ + kDebug() << "cancelBuildIndex()"; + + deleteProcess(); + deleteCmdFile(); + mIndexQueue.clear(); + + if ( mIsClosing ) { + mIsClosing = false; + } +} + +void KCMHelpCenter::slotIndexFinished(int exitCode, QProcess::ExitStatus exitStatus) +{ + kDebug() << "KCMHelpCenter::slotIndexFinished()"; + + if ( exitStatus == QProcess::NormalExit && exitCode == 2 ) { + if ( mRunAsRoot ) { + kError() << "Insufficient permissions." << endl; + } else { + kDebug() << "Insufficient permissions. Trying again as root."; + mRunAsRoot = true; + deleteProcess(); + startIndexProcess(); + return; + } + } else if ( exitStatus != QProcess::NormalExit || exitCode != 0 ) { + kDebug() << "KProcess reported an error."; + KMessageBox::error( this, i18n("Failed to build index.") ); + } else { + mConfig->group( "Search" ).writeEntry( "IndexExists", true ); + emit searchIndexUpdated(); + } + + deleteProcess(); + deleteCmdFile(); + + if ( mProgressDialog ) { + mProgressDialog->setFinished( true ); + } + + mStdOut.clear(); + mStdErr.clear(); + + if ( mIsClosing ) { + if ( !mProgressDialog || !mProgressDialog->isVisible() ) { + mIsClosing = false; + accept(); + } + } +} + +void KCMHelpCenter::deleteProcess() +{ + delete mProcess; + mProcess = 0; +} + +void KCMHelpCenter::deleteCmdFile() +{ + delete mCmdFile; + mCmdFile = 0; +} + +void KCMHelpCenter::slotIndexProgress() +{ + if( !mProcess ) + return; + + kDebug() << "KCMHelpCenter::slotIndexProgress()"; + + updateStatus(); + + advanceProgress(); +} + +void KCMHelpCenter::slotIndexError( const QString &str ) +{ + if( !mProcess ) + return; + + kDebug() << "KCMHelpCenter::slotIndexError()"; + + KMessageBox::sorry( this, i18n("Error executing indexing build command:\n%1", + str ) ); + + if ( mProgressDialog ) { + mProgressDialog->appendLog( "" + str + "" ); + } + + advanceProgress(); +} + +void KCMHelpCenter::advanceProgress() +{ + if ( mProgressDialog && mProgressDialog->isVisible() ) { + mProgressDialog->advanceProgress(); + mCurrentEntry++; + if ( mCurrentEntry != mIndexQueue.constEnd() ) { + QString name = (*mCurrentEntry)->name(); + mProgressDialog->setLabelText( name ); + } + } +} + +void KCMHelpCenter::slotReceivedStdout() +{ + QByteArray text= mProcess->readAllStandardOutput(); + int pos = text.lastIndexOf( '\n' ); + if ( pos < 0 ) { + mStdOut.append( text ); + } else { + if ( mProgressDialog ) { + mProgressDialog->appendLog( mStdOut + text.left( pos ) ); + mStdOut = text.mid( pos + 1 ); + } + } +} + +void KCMHelpCenter::slotReceivedStderr( ) +{ + QByteArray text = mProcess->readAllStandardError(); + int pos = text.lastIndexOf( '\n' ); + if ( pos < 0 ) { + mStdErr.append( text ); + } else { + if ( mProgressDialog ) { + mProgressDialog->appendLog( QLatin1String("") + mStdErr + text.left( pos ) + + QLatin1String("")); + mStdErr = text.mid( pos + 1 ); + } + } +} + +void KCMHelpCenter::slotOk() +{ + if ( buildIndex() ) { + if ( !mProcess ) accept(); + else mIsClosing = true; + } +} + +void KCMHelpCenter::slotProgressClosed() +{ + kDebug() << "KCMHelpCenter::slotProgressClosed()"; + + if ( mIsClosing ) accept(); +} + +void KCMHelpCenter::showIndexDirDialog() +{ + IndexDirDialog dlg( this ); + if ( dlg.exec() == QDialog::Accepted ) { + load(); + } +} + +void KCMHelpCenter::checkSelection() +{ + int count = 0; + + QTreeWidgetItemIterator it( mListView ); + while ( (*it) != 0 ) { + ScopeItem *item = static_cast( (*it) ); + if ( item->isOn() ) { + ++count; + } + ++it; + } + + enableButtonOk( count != 0 ); +} + +#include "kcmhelpcenter.moc" + +// vim:ts=2:sw=2:et diff --git a/khelpcenter/kcmhelpcenter.desktop b/khelpcenter/kcmhelpcenter.desktop new file mode 100644 index 00000000..3de4c05a --- /dev/null +++ b/khelpcenter/kcmhelpcenter.desktop @@ -0,0 +1,253 @@ +[Desktop Entry] +Type=Application +Exec=kcmshell4 kcmhelpcenter +Icon=help + +X-KDE-SubstituteUID=true +X-KDE-Library=helpcenter +X-KDE-RootOnly=true +X-KDE-HasReadOnlyMode=true +X-KDE-ParentApp=kcontrol + +Name=Help Index +Name[af]=Hulp Indeks +Name[ar]=فهرس المساعدة +Name[ast]=Índiz d'ayuda +Name[be]=Індэкс дапамогі +Name[be@latin]=Źmiest dapamohi +Name[bg]=Помощна информация +Name[bn]=সাহায্য সূচি +Name[bn_IN]=সহায়িকার ইন্ডেক্স +Name[br]=Meneger ar skoazell +Name[bs]=Indeks pomoći +Name[ca]=Índex d'ajuda +Name[ca@valencia]=Índex d'ajuda +Name[cs]=Rejstřík nápovědy +Name[csb]=Indeks pòmòcë +Name[cy]=Mynegai Cymorth +Name[da]=Hjælpeindeks +Name[de]=Hilfeindex +Name[el]=Ευρετήριο βοήθειας +Name[en_GB]=Help Index +Name[eo]=Helpa indekso +Name[es]=Índice de ayuda +Name[et]=Abifailide indeks +Name[eu]=Laguntza-indizea +Name[fa]=فهرست کمک +Name[fi]=Opasteen hakemisto +Name[fr]=Index d'aide +Name[fy]=Help-yndeks +Name[ga]=Innéacs na Cabhrach +Name[gl]=Índice da axuda +Name[gu]=મદદ અનુક્રમણિકા +Name[he]=אינדקס עזרה +Name[hi]=मदद सूची +Name[hne]=मदद सूची +Name[hr]=Indeks pomoći +Name[hsb]=Indeks za pomoc +Name[hu]=Dokumentációkeresési index +Name[ia]=Indice de adjuta +Name[id]=Indeks Bantuan +Name[is]=Hjálparyfirlit +Name[it]=Indice della guida +Name[ja]=ヘルプインデックス +Name[ka]=დახმარების ინდექსი +Name[kk]=Анықтама индексі +Name[km]=លិបិក្រម​ជំនួយ +Name[kn]=ಸಹಾಯ ಅನುಕ್ರಮ (ಇಂಡೆಕ್ಸ್) +Name[ko]=도움말 찾아보기 +Name[ku]=Pêrista Alîkariyê +Name[lt]=Pagalbos rodyklė +Name[lv]=Palīdzības indekss +Name[mai]=मद्दति सूची +Name[mk]=Индекс за помош +Name[ml]=സഹായത്തിനുളള സൂചിക +Name[mr]=मदत सूची +Name[ms]=Indeks Bantuan +Name[nb]=Hjelpindeks +Name[nds]=Hülpindex +Name[ne]=मद्दत अनुक्रमणिका +Name[nl]=Documentatie-index +Name[nn]=Hjelpindeks +Name[or]=ସହାୟତା ଅନୁକ୍ରମଣିକା +Name[pa]=ਮੱਦਦ ਇੰਡੈਕਸ +Name[pl]=Indeks pomocy +Name[pt]=Índice da Ajuda +Name[pt_BR]=Índice da ajuda +Name[ro]=Index ajutor +Name[ru]=Индекс справки +Name[se]=Veahkkeindeaksa +Name[si]=උදව් පටුන +Name[sk]=Index pomocníka +Name[sl]=Seznam pomoči +Name[sr]=Индекс помоћи +Name[sr@ijekavian]=Индекс помоћи +Name[sr@ijekavianlatin]=Indeks pomoći +Name[sr@latin]=Indeks pomoći +Name[sv]=Hjälpindex +Name[ta]=உதவி பொருளடக்கம் +Name[te]=సహాయ సూచిక +Name[tg]=Индекси роҳнамо +Name[th]=ดัชนีเอกสารช่วยเหลือ +Name[tr]=Yardım İçeriği +Name[ug]=ياردەم ئىندېكسى +Name[uk]=Індекс довідки +Name[uz]=Yordam indeksi +Name[uz@cyrillic]=Ёрдам индекси +Name[vi]=Chỉ mục Trợ giúp +Name[wa]=Indecse di l' aidance +Name[xh]=Uncedo Lwesalathisi +Name[x-test]=xxHelp Indexxx +Name[zh_CN]=帮助索引 +Name[zh_TW]=說明索引 + +Comment=Help center search index configuration and generation +Comment[af]=Hulp sentrum soektog indeks opstelling en genereering +Comment[ar]=توليد وضبط فهرس بحث مركز المساعدة +Comment[ast]=Configuración y xeneración del índiz de gueta del centru d'ayuda +Comment[be]=Настаўленне і стварэнне індэксу для пошуку ў дакументацыі +Comment[be@latin]=Naładžvańnie j stvareńnie źmiestu dla pošuku ŭ centry dapamohi +Comment[bg]=Създаване на индекс за ускоряване на търсенето в помощната информация +Comment[bn]=সহায়িকাসন্ধানসূচি কনফিগারেশন এবং সৃষ্টি +Comment[bn_IN]=সহায়িকা অনুসন্ধানের ইন্ডেক্স কনফিগারেশন ও নির্মাণ প্রণালী +Comment[bs]=Postava i stvaranje indeksa za pretragu Centra za pomoć +Comment[ca]=Configuració i generació de l'índex de cerca per al Centre d'ajuda +Comment[ca@valencia]=Configuració i generació de l'índex de cerca per al Centre d'ajuda +Comment[cs]=Generování a konfigurace rejstříku nápovědy +Comment[csb]=Kònfigùracëje ë generowanié indeksu pòmòcë +Comment[cy]=Ffurfweddu a chynhyrchu mynegai chwilio y Ganolfan Cymorth +Comment[da]=Hjælpecenterets indstilling og generering af søgeindeks +Comment[de]=Stichwortverzeichnis für das Hilfezentrum einrichten und erstellen +Comment[el]=Διαμόρφωση και δημιουργία του ευρετηρίου αναζήτησης του Κέντρου βοήθειας +Comment[en_GB]=Help centre search index configuration and generation +Comment[es]=Configuración y generación del índice de búsqueda del centro de ayuda +Comment[et]=Abifailide otsingu indeksi loomine ja seadistamine +Comment[eu]=Laguntza-zentroaren bilaketa-indizea konfiguratzea eta sortzea +Comment[fa]=تولید و پیکربندی فهرست جستجوی مرکز کمک +Comment[fi]=Opastekeskuksen hakuindeksin asetukset ja tuottaminen +Comment[fr]=Configuration et génération de l'index de recherche du centre d'aide +Comment[fy]=Sykjeyndeks fan it helpsintrum ynstellen en generearen +Comment[ga]=Cumraíocht agus giniúint an innéacs cuardaigh don lárionad cabhrach +Comment[gl]=Configuración e xeración do índice de busca do centro de axuda +Comment[gu]=મદદ કેન્દ્ર શોધ અનુક્રમણિકા રૂપરેખાંકન અને બનાવટ +Comment[he]=שינוי הגדרות ויצירת אינדקס החיפוש של מרכז העזרה +Comment[hi]=मदद केंद्र खोज तालिका कॉन्फ़िगरेशन तथा ज़ेनरेशन +Comment[hne]=मदद केंद्र खोज टेबल कान्फिगरेसन अउ जेनरेसन +Comment[hr]=Konfiguriranje i generiranje indeksa za pretraživanje pomoći +Comment[hsb]=Připrawjenje a stworjenje pytanskeho indeksa za pomhanišćo +Comment[hu]=A dokumentáció keresési indexének beállításai +Comment[ia]=Configuration e generation del indice de cerca pro le centro de adjuta +Comment[id]=Konfigurasi dan pembuatan indeks pencarian pusat bantuan +Comment[is]=Uppsettning og sköpun af leitaryfirliti fyrir hjálparmiðstöðina +Comment[it]=Configurazione e generazione dell'indice di ricerca della guida +Comment[ja]=ヘルプセンターの検索インデックスの設定と生成 +Comment[ka]=KDE-ს დახმარების სისტემაში ინდექსების კონფიგურაცია +Comment[kk]=Анықтамадан табу индексін баптау +Comment[km]=ការ​កំណត់​រចនាសម្ព័ន្ធ និង​ការ​បង្កើត​លិបិក្រម​ស្វែងរក សម្រាប់​មជ្ឈមណ្ឌល​ជំនួយ +Comment[kn]=ಸಹಾಯ ಕೇಂದ್ರ ಶೋಧನಾ ಅನುಕ್ರಮ (ಇಂಡೆಕ್ಸ್) ಸಂರಚನೆ ಮತ್ತು ಉತ್ಪತ್ತಿ +Comment[ko]=도움말 찾아보기 설정 및 생성 +Comment[ku]=Hilberîn û veavakirina îndeksa lêgerînê a navenda alîkariyê +Comment[lt]=Pagalbos centro indekso konfigūravimas ir generavimas +Comment[lv]=Palīdzības centra meklēšanas indeksa konfigurācija un ģenerācija +Comment[mai]=मद्दति केंद्र खोज तालिका कान्फिगरेशन आओर जेनरेशन +Comment[mk]=Конфигурирање и генерирање на индексот на Центарот за Помош +Comment[ml]=സഹായകേന്ദ്രത്തിലെ തെരയാനുള്ള സൂചികയുടെ ക്രമീകരണവും ഉത്പാദനവും +Comment[mr]=मदत केंद्र शोध तालिका संयोजना व जेनरेशन +Comment[nb]=Tilpass søkeindeksen og legg den til i hjelpesenteret +Comment[nds]=Söökindex för't Hülpzentrum inrichten un maken laten +Comment[ne]=मद्दत केन्द्र खोजी अनुक्रमणिका कन्फिगरेसन र सिर्जना +Comment[nl]=Zoekindex van het documentatiecentrum instellen en genereren +Comment[nn]=Oppsett og generering av søkjeindeks for hjelpesenteret +Comment[or]=ସହାୟତା କେନ୍ଦ୍ର ଅନୁକ୍ରମଣିକା ସଂରଚନା ଏବଂ ସୃଷ୍ଟି +Comment[pa]=ਮੱਦਦ ਸੈਂਟਰ ਖੋਜ ਇੰਡੈਕਸ ਸੰਰਚਨਾ ਅਤੇ ਨਿਰਮਾਣ +Comment[pl]=Ustawienia i tworzenie spisu treści pomocy +Comment[pt]=Configuração e geração do índice de pesquisa do centro de ajuda +Comment[pt_BR]=Configuração e geração do índice de busca do centro de ajuda +Comment[ro]=Generează și configurează indexul de căutare pentru Centrul de Ajutor +Comment[ru]=Настройка индекса справочной системы KDE +Comment[se]=Veahkkeguovddáža ohcanindeavssa heiveheapmi ja ráhkadeapmi +Comment[si]=උදව් මධ්‍යස්ථාන සූචිය සැකසීම හා ජනනය +Comment[sk]=Nastavenie a generovanie indexu pre pomocníka +Comment[sl]=Nastavitve in ustvarjanje iskalnega kazala za Središče za pomoč +Comment[sr]=Постава и стварање индекса за претрагу Центра за помоћ +Comment[sr@ijekavian]=Постава и стварање индекса за претрагу Центра за помоћ +Comment[sr@ijekavianlatin]=Postava i stvaranje indeksa za pretragu Centra za pomoć +Comment[sr@latin]=Postava i stvaranje indeksa za pretragu Centra za pomoć +Comment[sv]=Skapa och ställ in sökindex för Hjälpcentralen +Comment[ta]=உதவி மையத்தை தேடும் பொருளடக்கம் வடிவமைத்தல் மற்றும் உருவாக்கல் +Comment[te]=సహాయ కేంద్ర అన్వెషణ సూచి అమరిక మరయూ తయారుచెయుట +Comment[tg]=Маркази роҳнамои ҷустуҷӯи индекси танзимот ва эҷодкорӣ +Comment[th]=การปรับแต่งและสร้างดัชนีสำหรับค้นหาของศูนย์ช่วยเหลือ +Comment[tr]=Yardım merkezi dizininin yapılandırılması ve oluşturulması +Comment[ug]=ياردەم مەركىزىنىڭ ئىزدەش ئىندېكس سەپلىمىسى ۋە ھاسىل قىلىش +Comment[uk]=Створення та налаштування індексу пошуку Центру довідки +Comment[uz]=Yordam markazining qidiruv indeksini yaratish va moslash +Comment[uz@cyrillic]=Ёрдам марказининг қидирув индексини яратиш ва мослаш +Comment[vi]=Cấu hình và tạo ra chỉ mục tìm kiếm của trung tâm trợ giúp +Comment[wa]=Fijhaedje eyet apontiaedje di l' indecse di cweraedje do cinte d' aidance +Comment[xh]=Uqwalaselo lophendlo loncedo osembindi nolwenziwo +Comment[x-test]=xxHelp center search index configuration and generationxx +Comment[zh_CN]=帮助中心搜索索引配置和生成 +Comment[zh_TW]=求助中心搜尋索引的組態與產生 + +X-KDE-Keywords=khelpcenter,help,index,search +X-KDE-Keywords[ar]=مركز مساعدة كدي,مساعدة,فهرس,بحث +X-KDE-Keywords[bg]=khelpcenter,help,index,search,помощ,индекс,търсене +X-KDE-Keywords[bn]=khelpcenter,help,index,search +X-KDE-Keywords[bs]=khelpcenter,help,index,search,pomoć,pretraga,indeks +X-KDE-Keywords[ca]=khelpcenter,ajuda,índex,cerca +X-KDE-Keywords[ca@valencia]=khelpcenter,ajuda,índex,cerca +X-KDE-Keywords[cs]=khelpcenter,help,index,hledat +X-KDE-Keywords[da]=khelpcenter,hjælp,indeks,søg +X-KDE-Keywords[de]=Hilfezentrum,Index,Stichwortverzeichnis,Suche +X-KDE-Keywords[el]=khelpcenter,βοήθεια,ευρετήριο,αναζήτηση +X-KDE-Keywords[en_GB]=khelpcenter,help,index,search +X-KDE-Keywords[eo]=khelpcenter,helpo,indekso,serĉo +X-KDE-Keywords[es]=khelpcenter,ayuda,índice,buscar +X-KDE-Keywords[et]=khelpcenter,abi,indeks,otsing,KDE abikeskus,abikeskus +X-KDE-Keywords[eu]=khelpcenter,laguntza,indizea,bilaketa +X-KDE-Keywords[fa]=khelpcenter,help,index,search +X-KDE-Keywords[fi]=khelpcenter,ohje,opaste,indeksi,hakemisto,haku +X-KDE-Keywords[fr]=khelpcenter, aide, index, recherche +X-KDE-Keywords[ga]=khelpcenter,cabhair,innéacs,cuardach +X-KDE-Keywords[gl]=khelpcenter,axuda,índice,buscar +X-KDE-Keywords[gu]=khelpcenter,મદદ,અનુક્રમ,શોધ +X-KDE-Keywords[hi]=khelpcenter, मदद, सूचकांक, खोज +X-KDE-Keywords[hu]=khelpcenter,súgó,index,keresés +X-KDE-Keywords[ia]=khelpcenter,adjuta,indice,cerca +X-KDE-Keywords[id]=khelpcenter,bantuan,indeks,cari +X-KDE-Keywords[is]=khelpcenter,hjálp,yfirlit,leit +X-KDE-Keywords[it]=khelpcenter,aiuto,indice,ricerca +X-KDE-Keywords[ja]=khelpcenter,help,index,search +X-KDE-Keywords[kk]=khelpcenter,help,index,search +X-KDE-Keywords[km]=khelpcenter,help,index,search +X-KDE-Keywords[ko]=khelpcenter,help,index,search,도움말,인덱스,검색 +X-KDE-Keywords[lv]=khelpcenter,palīdzība,indekss,meklēšana +X-KDE-Keywords[mr]=khelpcenter, मदत, अनुक्रमणिका, शोध +X-KDE-Keywords[nb]=khelpcenter,hjelp,index,søk +X-KDE-Keywords[nds]=khelpcenter,Hülp,Index,Söök +X-KDE-Keywords[nl]=khelpcenter,help,index,zoeken +X-KDE-Keywords[nn]=khelpcenter,hjelp,indeks,stikkord,søk +X-KDE-Keywords[pa]=khelpcenter,ਮੱਦਦ,ਸਹਾਇਤਾ,ਇੰਡੈਕਸ,ਖੋਜ +X-KDE-Keywords[pl]=centrum pomocy,pomoc,indeks,znajdywanie,wyszukiwanie +X-KDE-Keywords[pt]=khelpcenter,ajuda,índice,pesquisa +X-KDE-Keywords[pt_BR]=khelpcenter,ajuda,índice,pesquisa +X-KDE-Keywords[ro]=khelpcenter,centru,ajutor,cuprins,căutare +X-KDE-Keywords[ru]=khelpcenter,help,index,search,помощь,справка,индекс,поиск +X-KDE-Keywords[sk]=khelpcenter,help,index,hľadanie +X-KDE-Keywords[sl]=khelpcenter,pomoč,kazalo,iskanje +X-KDE-Keywords[sr]=khelpcenter,help,index,search,К‑центар-помоћи,помоћ,индекс,претрага,тражење +X-KDE-Keywords[sr@ijekavian]=khelpcenter,help,index,search,К‑центар-помоћи,помоћ,индекс,претрага,тражење +X-KDE-Keywords[sr@ijekavianlatin]=khelpcenter,help,index,search,K‑centar-pomoći,pomoć,indeks,pretraga,traženje +X-KDE-Keywords[sr@latin]=khelpcenter,help,index,search,K‑centar-pomoći,pomoć,indeks,pretraga,traženje +X-KDE-Keywords[sv]=Hjälpcentralen,hjälp,index,sök +X-KDE-Keywords[tg]=khelpcenter,кумак,индекс,ҷустуҷӯ +X-KDE-Keywords[tr]=khelpcenter,yardım,dizin,arama +X-KDE-Keywords[ug]=khelpcenter، ياردەم، ئىندېكس، ئىزدەش +X-KDE-Keywords[uk]=khelpcenter;help;index;search;довідка;центр;покажчик;індекс;пошук;допомога +X-KDE-Keywords[vi]=trung tâm trợ giúp KDE,trợ giúp,chỉ mục,tìm kiếm,khelpcenter,help,index,search +X-KDE-Keywords[wa]=khelpcenter,kcinte d' aidance,indecse,cweri,cweraedje,trover,cachî,cachî après +X-KDE-Keywords[x-test]=xxkhelpcenter,help,index,searchxx +X-KDE-Keywords[zh_CN]=khelpcenter,help,index,search,帮助搜索,索引 +X-KDE-Keywords[zh_TW]=khelpcenter,help,index,search +Categories=Qt;KDE;X-KDE-settings-system; diff --git a/khelpcenter/kcmhelpcenter.h b/khelpcenter/kcmhelpcenter.h new file mode 100644 index 00000000..ccbeb8f5 --- /dev/null +++ b/khelpcenter/kcmhelpcenter.h @@ -0,0 +1,168 @@ +/* + This file is part of KHelpcenter. + + Copyright (C) 2002 Cornelius Schumacher + + 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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ +#ifndef KHC_KCMHELPCENTER_H +#define KHC_KCMHELPCENTER_H + +#include +#include +#include + +#include "scopeitem.h" + +class QPushButton; +class QProgressBar; +class QTextEdit; +class QLabel; + +class KAboutData; +class KTemporaryFile; +class KUrlRequester; +class QTreeWidget; + +namespace KHC { +class HtmlSearchConfig; +class DocEntry; +class SearchEngine; +} + +class IndexDirDialog : public KDialog +{ + Q_OBJECT + public: + IndexDirDialog( QWidget *parent ); + + protected Q_SLOTS: + void slotOk(); + void slotUrlChanged( const QString &_url); + private: + KUrlRequester *mIndexUrlRequester; +}; + +class IndexProgressDialog : public KDialog +{ + Q_OBJECT + public: + IndexProgressDialog( QWidget *parent ); + ~IndexProgressDialog(); + + void setTotalSteps( int ); + void advanceProgress(); + void setLabelText( const QString & ); + void setMinimumLabelWidth( int width ); + void setFinished( bool ); + + void appendLog( const QString &text ); + + Q_SIGNALS: + void closed(); + void cancelled(); + + protected: + void hideDetails(); + + protected Q_SLOTS: + void slotEnd(); + void toggleDetails(); + + private: + QLabel *mLabel; + QProgressBar *mProgressBar; + QLabel *mLogLabel; + QTextEdit *mLogView; + + bool mFinished; +}; + +class KCMHelpCenter : public KDialog +{ + Q_OBJECT + public: + explicit KCMHelpCenter( KHC::SearchEngine *, QWidget *parent = 0, + const char *name = 0 ); + ~KCMHelpCenter(); + + void load(); + bool save(); + void defaults(); + + public Q_SLOTS: + + Q_SIGNALS: + void searchIndexUpdated(); + public Q_SLOTS: + void slotIndexError( const QString & ); + void slotIndexProgress(); + protected Q_SLOTS: + bool buildIndex(); + void cancelBuildIndex(); + void slotIndexFinished( int exitCode, QProcess::ExitStatus exitStatus ); + void slotReceivedStdout(); + void slotReceivedStderr(); + void slotProgressClosed(); + + void slotOk(); + + void showIndexDirDialog(); + + void checkSelection(); + + protected: + void setupMainWidget( QWidget *parent ); + void updateStatus(); + void startIndexProcess(); + + void deleteProcess(); + void deleteCmdFile(); + + void advanceProgress(); + + private: + KHC::SearchEngine *mEngine; + + QTreeWidget *mListView; + QLabel *mIndexDirLabel; + QPushButton *mBuildButton; + IndexProgressDialog *mProgressDialog; + + QList mIndexQueue; + QList::ConstIterator mCurrentEntry; + + KSharedConfigPtr mConfig; + + KAboutData *mAboutData; + + KHC::HtmlSearchConfig *mHtmlSearchTab; + QWidget *mScopeTab; + + KTemporaryFile *mCmdFile; + + KProcess *mProcess; + + bool mIsClosing; + + QByteArray mStdOut; + QByteArray mStdErr; + + bool mRunAsRoot; +}; + +#endif //KHC_KCMHELPCENTER_H +// vim:ts=2:sw=2:et diff --git a/khelpcenter/khc_indexbuilder.cpp b/khelpcenter/khc_indexbuilder.cpp new file mode 100644 index 00000000..04a55006 --- /dev/null +++ b/khelpcenter/khc_indexbuilder.cpp @@ -0,0 +1,203 @@ +/* + This file is part of the KDE Help Center + + Copyright (c) 2003 Cornelius Schumacher + + 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 "khc_indexbuilder.h" + +#include "version.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +using namespace KHC; + +IndexBuilder::IndexBuilder(const QString& cmdFile) +{ + m_cmdFile = cmdFile; + kDebug(1402) << "IndexBuilder()"; +} + +void IndexBuilder::buildIndices() +{ + QFile f( m_cmdFile ); + if ( !f.open( QIODevice::ReadOnly ) ) { + kError() << "Unable to open file '" << m_cmdFile << "'" << endl; + exit( 1 ); + } + kDebug(1402) << "Opened file '" << m_cmdFile << "'"; + QTextStream ts( &f ); + QString line = ts.readLine(); + while ( !line.isNull() ) { + kDebug(1402) << "LINE: " << line; + mCmdQueue.append( line ); + line = ts.readLine(); + } + + processCmdQueue(); +} + +void IndexBuilder::processCmdQueue() +{ + kDebug(1402) << "IndexBuilder::processCmdQueue()"; + + QStringList::Iterator it = mCmdQueue.begin(); + + if ( it == mCmdQueue.end() ) { + quit(); + return; + } + + QString cmd = *it; + + kDebug(1402) << "PROCESS: " << cmd; + + KProcess *proc = new KProcess; + + *proc << KShell::splitArgs(cmd); + + connect( proc, SIGNAL( finished( int, QProcess::ExitStatus) ), + SLOT( slotProcessExited( int, QProcess::ExitStatus) ) ); + + mCmdQueue.erase( it ); + + proc->start(); + + if ( !proc->waitForStarted() ) { + sendErrorSignal( i18n("Unable to start command '%1'.", cmd ) ); + processCmdQueue(); + delete proc; + } +} + +void IndexBuilder::slotProcessExited( int exitCode, QProcess::ExitStatus exitStatus ) +{ + KProcess *proc = static_cast(sender()); + + if ( exitStatus != QProcess::NormalExit ) { + kError(1402) << "Process failed" << endl; + kError(1402) << "stdout output:" << proc->readAllStandardOutput(); + kError(1402) << "stderr output:" << proc->readAllStandardError(); + } + else if (exitCode != 0 ) { + kError(1402) << "running" << proc->program() << "failed with exitCode" << exitCode; + kError(1402) << "stdout output:" << proc->readAllStandardOutput(); + kError(1402) << "stderr output:" << proc->readAllStandardError(); + } + delete proc; + + sendProgressSignal(); + + processCmdQueue(); +} + +void IndexBuilder::sendErrorSignal( const QString &error ) +{ + kDebug(1402) << "IndexBuilder::sendErrorSignal()"; + QDBusMessage message = + QDBusMessage::createSignal("/kcmhelpcenter", "org.kde.kcmhelpcenter", "buildIndexError"); + message <quit(); +} + + +int main( int argc, char **argv ) +{ + KAboutData aboutData( "khc_indexbuilder", 0, + ki18n("KHelpCenter Index Builder"), + HELPCENTER_VERSION, + ki18n("The KDE Help Center"), + KAboutData::License_GPL, + ki18n("(c) 2003, The KHelpCenter developers") ); + + aboutData.addAuthor( ki18n("Cornelius Schumacher"), KLocalizedString(), "schumacher@kde.org" ); + + KCmdLineArgs::init( argc, argv, &aboutData ); + + KCmdLineOptions options; + options.add("+cmdfile", ki18n("Document to be indexed")); + options.add("+indexdir", ki18n("Index directory")); + KCmdLineArgs::addCmdLineOptions( options ); + + // Note: no KComponentData seems necessary + QCoreApplication app( KCmdLineArgs::qtArgc(), KCmdLineArgs::qtArgv() ); + + KCmdLineArgs *args = KCmdLineArgs::parsedArgs(); + + if ( args->count() != 2 ) { + kDebug(1402) << "Wrong number of arguments."; + return 1; + } + + QString cmdFile = args->arg( 0 ); + QString indexDir = args->arg( 1 ); + + kDebug(1402) << "cmdFile: " << cmdFile; + kDebug(1402) << "indexDir: " << indexDir; + + QFile file( indexDir + "/testaccess" ); + if ( !file.open( QIODevice::WriteOnly ) || !file.putChar( ' ' ) ) { + kDebug(1402) << "access denied"; + return 2; + } else { + kDebug(1402) << "can access"; + file.remove(); + } + + IndexBuilder builder(cmdFile); + + QTimer::singleShot(0, &builder, SLOT(buildIndices())); + + return app.exec(); +} + +#include "khc_indexbuilder.moc" + +// vim:ts=2:sw=2:et diff --git a/khelpcenter/khc_indexbuilder.h b/khelpcenter/khc_indexbuilder.h new file mode 100644 index 00000000..0b6de7fb --- /dev/null +++ b/khelpcenter/khc_indexbuilder.h @@ -0,0 +1,59 @@ +/* + * This file is part of the KDE Help Center + * + * Copyright (C) 2003 Cornelius Schumacher + * + * 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. + */ +#ifndef KHC_INDEXBUILDER_H +#define KHC_INDEXBUILDER_H + +#include +#include + +#include +#include + +namespace KHC { + +class IndexBuilder : public QObject +{ + Q_OBJECT + public: + IndexBuilder(const QString& cmdFile); + + void sendProgressSignal(); + void sendErrorSignal( const QString &error ); + void quit(); + + + void processCmdQueue(); + + protected Q_SLOTS: + void buildIndices(); + void slotProcessExited( int, QProcess::ExitStatus ); + + private: + QString m_cmdFile; + QTimer mTimer; + QStringList mCmdQueue; +}; + +} + +#endif //KHC_INDEXBUILDER_H + +// vim:ts=2:sw=2:et diff --git a/khelpcenter/khelpcenter.desktop b/khelpcenter/khelpcenter.desktop new file mode 100644 index 00000000..2c88e525 --- /dev/null +++ b/khelpcenter/khelpcenter.desktop @@ -0,0 +1,190 @@ +[Desktop Entry] +Name=KHelpCenter +Name[af]=Khulpsentrum +Name[ar]=مركز مساعدة كدي +Name[ast]=KHelpcenter +Name[be]=Цэнтр дапамогі KDE +Name[be@latin]=KHelpCenter +Name[bg]=Помощен център +Name[bn]=KHelpCenter +Name[bn_IN]=KHelpCenter +Name[br]=KHelpCenter +Name[bs]=K‑centar-pomoći +Name[ca]=KHelpCenter +Name[ca@valencia]=KHelpCenter +Name[cs]=Centrum nápovědy +Name[csb]=Centróm Pòmòcë +Name[cy]=KCanolfanCymorth +Name[da]=KHjælpecenter +Name[de]=KDE-Hilfezentrum +Name[el]=KHelpCenter +Name[en_GB]=KHelpCentre +Name[eo]=KHelpCenter +Name[es]=KHelpcenter +Name[et]=KDE abikeskus +Name[eu]=KHelpCenter +Name[fa]=KHelpCenter +Name[fi]=KHelpCenter +Name[fr]=Centre d'aide de KDE +Name[fy]=KHelpCenter +Name[ga]=KHelpCenter +Name[gl]=Centro de axuda de KDE +Name[gu]=KHelpCenter +Name[he]=KHelpCenter +Name[hi]=के-हेल्प-सेंटर +Name[hne]=के-हेल्प-सेंटर +Name[hr]=KHelpCenter +Name[hsb]=KHelpCenter (pomhanišćo) +Name[hu]=KHelpCenter +Name[ia]=KHelpCenter +Name[id]=KHelpCenter +Name[is]=Hjálparkerfi KDE +Name[it]=KHelpCenter +Name[ja]=K ヘルプセンター +Name[ka]=KHelpCenter +Name[kk]=KHelpCenter +Name[km]=KHelpCenter +Name[kn]=ಕೆಹೆಲ್ಪ್ ಸೆಂಟರ್ +Name[ko]=KHelpCenter +Name[ku]=KHelpCenter +Name[lt]=KHelpCenter +Name[lv]=KHelpCenter +Name[mai]=के-हेल्प-सेंटर +Name[mk]=KHelpCenter +Name[ml]=സഹായകേന്ദ്രം +Name[mr]=के-हेल्प-सेंटर +Name[ms]=KHelpCenter +Name[nb]=KHelpCenter +Name[nds]=KDE-Hülpzentrum +Name[ne]=केडीई मद्दत केन्द्र +Name[nl]=KHelpCenter +Name[nn]=KHelpCenter +Name[oc]=KHelpCenter +Name[or]=Kସହାୟତା କେନ୍ଦ୍ର +Name[pa]=ਕੇ-ਮੱਦਦਸੈਂਟਰ +Name[pl]=Centrum Pomocy +Name[pt]=KHelpCenter +Name[pt_BR]=KHelpCenter +Name[ro]=Centrul de ajutor KDE +Name[ru]=Центр справки +Name[se]=KHelpCenter +Name[si]=KHelpCenter +Name[sk]=KHelpCenter +Name[sl]=KHelpCenter +Name[sr]=К‑центар-помоћи +Name[sr@ijekavian]=К‑центар-помоћи +Name[sr@ijekavianlatin]=K‑centar-pomoći +Name[sr@latin]=K‑centar-pomoći +Name[sv]=Hjälpcentralen +Name[ta]=Kஉதவிமையம் +Name[te]=కెసహాయ కేంద్రం +Name[tg]=Маркази роҳнамои KDE +Name[th]=ศูนย์ช่วยเหลือ-K +Name[tr]=KHelpCenter +Name[ug]=KHelpCenter +Name[uk]=KHelpCenter +Name[uz]=Yordam markazi +Name[uz@cyrillic]=Ёрдам маркази +Name[vi]=Trung tâm Trợ giúp KDE +Name[wa]=KCinte d' aidance +Name[xh]=KHelpCenter +Name[x-test]=xxKHelpCenterxx +Name[zh_CN]=KHelpcenter +Name[zh_TW]=KHelpCenter +Comment=The KDE Help Center +Comment[af]=Die Kde Hulp Sentrum +Comment[ar]=مركز كدي للمساعدة +Comment[ast]=El centru d'ayuda de KDE +Comment[be]=Цэнтр дапамогі KDE +Comment[be@latin]=Centar dapamohi KDE +Comment[bg]=Център за помощна информация +Comment[bn]=কে.ডি.ই. সাহায্য কেন্দ্র +Comment[bn_IN]=KDE সহায়তা কেন্দ্র +Comment[br]=Kreizenn sikour KDE +Comment[bs]=KDE‑ov centar za pomoć +Comment[ca]=El centre d'ajuda KDE +Comment[ca@valencia]=El centre d'ajuda KDE +Comment[cs]=Centrum nápovědy prostředí KDE +Comment[csb]=Centróm Pòmòcë KDE +Comment[cy]=Canolfan Cymorth KDE +Comment[da]=KDE's hjælpecenter +Comment[de]=Das KDE-Hilfezentrum +Comment[el]=Το κέντρο βοήθειας του KDE +Comment[en_GB]=The KDE Help Centre +Comment[eo]=La helpocentro de KDE +Comment[es]=Centro de ayuda de KDE +Comment[et]=KDE abikeskus +Comment[eu]=KDEren laguntza-zentroa +Comment[fa]=مرکز کمک کی‌دی‌ای +Comment[fi]=KDE:n ohjeet +Comment[fr]=Le centre d'aide de KDE +Comment[fy]=It KDE-dokumintaasjesintrum +Comment[ga]=Lárionad Cabhrach KDE +Comment[gl]=O centro de axuda de KDE +Comment[gu]=KDE મદદ કેન્દ્ર +Comment[he]=מרכז העזרה של KDE +Comment[hi]=केडीई मदद केंद्र +Comment[hne]=केडीई मदद केंद्र +Comment[hr]=KDE pomoć +Comment[hsb]=KDE pomhanišćo +Comment[hu]=KDE Súgó +Comment[ia]=Le centro de adjuta de KDE +Comment[id]=Pusat Bantuan KDE +Comment[is]=Hjálparkerfi KDE +Comment[it]=Guida di KDE +Comment[ja]=KDE ヘルプセンター +Comment[ka]=KDE-ს დახმარების ცენტრი +Comment[kk]=KDE анықтама орталығы +Comment[km]=មជ្ឈមណ្ឌល​ជំនួយ​របស់ KDE +Comment[kn]=ಕೆಡಿಇ ಯ ಸಹಾಯ ಕೇಂದ್ರ +Comment[ko]=KDE 도움말 센터 +Comment[ku]=Navenda Alîkariya KDE'yê +Comment[lt]=KDE pagalbos centras +Comment[lv]=KDE palīdzības centrs +Comment[mai]=केडीई मद्दति केंद्र +Comment[mk]=KDE Центарот за Помош +Comment[ml]=കെഡിഇ സഹായകേന്ദ്രം +Comment[mr]=केडीई मदत केंद्र +Comment[ms]=Pusat Bantuan KDE +Comment[nb]=KDE Hjelpesenter +Comment[nds]=Dat KDE-Hülpzentrum +Comment[ne]=केडीई मद्दत केन्द्र +Comment[nl]=Het KDE-documentatiecentrum +Comment[nn]=KDE-hjelpesenteret +Comment[or]=KDE ସହାୟତା କେନ୍ଦ୍ର +Comment[pa]=ਕੇਡੀਈ ਮੱਦਦ ਸੈਂਟਰ +Comment[pl]=Centrum Pomocy KDE +Comment[pt]=O Centro de Ajuda do KDE +Comment[pt_BR]=O centro de ajuda do KDE +Comment[ro]=Centrul de ajutor al KDE +Comment[ru]=Центр справки KDE +Comment[se]=KDE veahkkeguovddáš +Comment[si]=KDE උදව් මධ්‍යස්ථානය +Comment[sk]=Centrum pomoci KDE +Comment[sl]=Središče za pomoč v KDE +Comment[sr]=КДЕ‑ов центар за помоћ +Comment[sr@ijekavian]=КДЕ‑ов центар за помоћ +Comment[sr@ijekavianlatin]=KDE‑ov centar za pomoć +Comment[sr@latin]=KDE‑ov centar za pomoć +Comment[sv]=KDE:s hjälpcentral +Comment[ta]=KDE உதவி மையம் +Comment[te]=కెడిఈ సహాయ కేంద్రం +Comment[tg]=Маркази роҳнамои KDE +Comment[th]=ศูนย์ช่วยเหลือของ KDE +Comment[tr]=KDE Yardım Merkezi +Comment[ug]=ك د ئې(KDE) ياردەم مەركىزى +Comment[uk]=Центр довідки KDE +Comment[uz]=KDE yordam markazi +Comment[uz@cyrillic]=KDE ёрдам маркази +Comment[vi]=Trung tâm Trợ giúp KDE +Comment[wa]=Li cinte d' aidance di KDE +Comment[xh]=Umbindi woncedo lwe KDE +Comment[x-test]=xxThe KDE Help Centerxx +Comment[zh_CN]=KDE 帮助中心 +Comment[zh_TW]=KDE 求助中心 +Icon=help-browser +X-DocPath=khelpcenter/index.html +Type=Service +Terminal=false +Exec=khelpcenter %u +X-KDE-StartupNotify=true diff --git a/khelpcenter/khelpcenter.kcfg b/khelpcenter/khelpcenter.kcfg new file mode 100644 index 00000000..0ece51e1 --- /dev/null +++ b/khelpcenter/khelpcenter.kcfg @@ -0,0 +1,36 @@ + + + kstandarddirs.h + + + + + + Path to directory containing search indices. + KGlobal::dirs()->saveLocation("data", "khelpcenter/index/") + + + + 0 + + + 0 + + + + + + + + + + + + Content + + + + diff --git a/khelpcenter/khelpcenterui.rc b/khelpcenter/khelpcenterui.rc new file mode 100644 index 00000000..36ffe46e --- /dev/null +++ b/khelpcenter/khelpcenterui.rc @@ -0,0 +1,45 @@ + + + + + &Edit + + + + + + + + &View + + + + + &Go + + + + + + + + + + + + + Main Toolbar + + + + + + + + + + + diff --git a/khelpcenter/mainwindow.cpp b/khelpcenter/mainwindow.cpp new file mode 100644 index 00000000..c8d6d7ac --- /dev/null +++ b/khelpcenter/mainwindow.cpp @@ -0,0 +1,508 @@ + /* + * This file is part of the KDE Help Center + * + * Copyright (C) 1999 Matthias Elter (me@kde.org) + * 2001 Stephan Kulow (coolo@kde.org) + * + * 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 "mainwindow.h" + +#include "history.h" +#include "view.h" +#include "searchengine.h" +#include "fontdialog.h" +#include "prefs.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +using namespace KHC; + +class LogDialog : public KDialog +{ + public: + LogDialog( QWidget *parent = 0 ) + : KDialog( parent ) + { + setCaption( i18n("Search Error Log") ); + setButtons( Ok ); + + QFrame *topFrame = new QFrame( this ); + setMainWidget( topFrame ); + + QBoxLayout *topLayout = new QVBoxLayout( topFrame ); + + mTextView = new QTextEdit( topFrame ); + mTextView->setReadOnly ( true ); + mTextView->setWordWrapMode( QTextOption::NoWrap ); + topLayout->addWidget( mTextView ); + + KConfigGroup cg = KGlobal::config()->group( "logdialog" ); + restoreDialogSize( cg ); + } + + ~LogDialog() + { + KConfigGroup cg = KGlobal::config()->group( "logdialog" ); + KDialog::saveDialogSize( cg ); + } + + void setLog( const QString &log ) + { + mTextView->setText( log ); + } + + private: + QTextEdit *mTextView; +}; + + +MainWindow::MainWindow() + : KXmlGuiWindow(0), + mLogDialog( 0 ) +{ + setObjectName( QLatin1String( "MainWindow" ) ); + + QDBusConnection::sessionBus().registerObject("/KHelpCenter", this, QDBusConnection::ExportScriptableSlots); + mSplitter = new QSplitter( this ); + + mDoc = new View( mSplitter, this, KHTMLPart::DefaultGUI, actionCollection() ); + connect( mDoc, SIGNAL( setWindowCaption( const QString & ) ), + SLOT( setCaption( const QString & ) ) ); + connect( mDoc, SIGNAL( setStatusBarText( const QString & ) ), + SLOT( statusBarMessage( const QString & ) ) ); + connect( mDoc, SIGNAL( onURL( const QString & ) ), + SLOT( statusBarMessage( const QString & ) ) ); + connect( mDoc, SIGNAL( started( KIO::Job * ) ), + SLOT( slotStarted( KIO::Job * ) ) ); + connect( mDoc, SIGNAL( completed() ), + SLOT( documentCompleted() ) ); + connect( mDoc, SIGNAL( searchResultCacheAvailable() ), + SLOT( enableLastSearchAction() ) ); + + connect( mDoc, SIGNAL( selectionChanged() ), + SLOT( enableCopyTextAction() ) ); + + statusBar()->insertItem(i18n("Preparing Index"), 0, 1); + statusBar()->setItemAlignment(0, Qt::AlignLeft | Qt::AlignVCenter); + + connect( mDoc->browserExtension(), + SIGNAL( openUrlRequest( const KUrl &, + const KParts::OpenUrlArguments &, const KParts::BrowserArguments & ) ), + SLOT( slotOpenURLRequest( const KUrl &, + const KParts::OpenUrlArguments &, const KParts::BrowserArguments & ) ) ); + + mNavigator = new Navigator( mDoc, mSplitter, "nav" ); + connect( mNavigator, SIGNAL( itemSelected( const QString & ) ), + SLOT( viewUrl( const QString & ) ) ); + connect( mNavigator, SIGNAL( glossSelected( const GlossaryEntry & ) ), + SLOT( slotGlossSelected( const GlossaryEntry & ) ) ); + + mSplitter->insertWidget(0, mNavigator); + mSplitter->setStretchFactor(mSplitter->indexOf(mNavigator), 0); + setCentralWidget( mSplitter ); + QList sizes; + sizes << 220 << 580; + mSplitter->setSizes(sizes); + + KSharedConfig::Ptr cfg = KGlobal::config(); + { + KConfigGroup configGroup( cfg, "General" ); + if ( configGroup.readEntry( "UseKonqSettings", true) ) { + KConfig konqCfg( "konquerorrc" ); + const_cast( mDoc->settings() )->init( &konqCfg ); + } + const int fontScaleFactor = configGroup.readEntry( "Font zoom factor", 100 ); + mDoc->setFontScaleFactor( fontScaleFactor ); + } + + setupActions(); + + foreach (QAction *act, mDoc->actionCollection()->actions()) + actionCollection()->addAction(act->objectName(), act); + + setupGUI(QSize(800, 600), ToolBar | Keys | StatusBar | Create); + setAutoSaveSettings(); + + History::self().installMenuBarHook( this ); + + connect( &History::self(), SIGNAL( goInternalUrl( const KUrl & ) ), + mNavigator, SLOT( openInternalUrl( const KUrl & ) ) ); + connect( &History::self(), SIGNAL( goUrl( const KUrl & ) ), + mNavigator, SLOT( selectItem( const KUrl & ) ) ); + + statusBarMessage(i18n("Ready")); + enableCopyTextAction(); + + readConfig(); +} + +MainWindow::~MainWindow() +{ + writeConfig(); +} + +void MainWindow::enableCopyTextAction() +{ + mCopyText->setEnabled( mDoc->hasSelection() ); +} + +void MainWindow::saveProperties( KConfigGroup &config ) +{ + kDebug(); + config.writePathEntry( "URL" , mDoc->baseURL().url() ); +} + +void MainWindow::readProperties( const KConfigGroup &config ) +{ + kDebug(); + mDoc->slotReload( KUrl( config.readPathEntry( "URL", QString() ) ) ); +} + +void MainWindow::readConfig() +{ + KConfigGroup config(KGlobal::config(), "MainWindowState"); + QList sizes = config.readEntry( "Splitter", QList() ); + if ( sizes.count() == 2 ) { + mSplitter->setSizes( sizes ); + } + + mNavigator->readConfig(); +} + +void MainWindow::writeConfig() +{ + KConfigGroup config(KGlobal::config(), "MainWindowState"); + config.writeEntry( "Splitter", mSplitter->sizes() ); + + mNavigator->writeConfig(); + + Prefs::self()->writeConfig(); +} + +void MainWindow::setupActions() +{ + actionCollection()->addAction( KStandardAction::Quit, this, SLOT( close() ) ); + actionCollection()->addAction( KStandardAction::Print, this, SLOT( print() ) ); + + KAction *prevPage = actionCollection()->addAction( "prevPage" ); + prevPage->setText( i18n( "Previous Page" ) ); + prevPage->setShortcut( Qt::CTRL+Qt::Key_PageUp ); + prevPage->setWhatsThis( i18n( "Moves to the previous page of the document" ) ); + connect( prevPage, SIGNAL( triggered() ), mDoc, SLOT( prevPage() ) ); + + KAction *nextPage = actionCollection()->addAction( "nextPage" ); + nextPage->setText( i18n( "Next Page" ) ); + nextPage->setShortcut( Qt::CTRL + Qt::Key_PageDown ); + nextPage->setWhatsThis( i18n( "Moves to the next page of the document" ) ); + connect( nextPage, SIGNAL( triggered() ), mDoc, SLOT( nextPage() ) ); + + QAction *home = KStandardAction::home( this, SLOT( slotShowHome() ), this ); + actionCollection()->addAction( home->objectName(), home ); + home->setText(i18n("Table of &Contents")); + home->setToolTip(i18n("Table of contents")); + home->setWhatsThis(i18n("Go back to the table of contents")); + + mCopyText = KStandardAction::copy( this, SLOT(slotCopySelectedText()), this ); + actionCollection()->addAction( "copy_text", mCopyText ); + + mLastSearchAction = actionCollection()->addAction( QLatin1String("lastsearch") ); + mLastSearchAction->setText( i18n("&Last Search Result") ); + mLastSearchAction->setEnabled( false ); + connect( mLastSearchAction, SIGNAL( triggered() ), this, SLOT( slotLastSearch() ) ); +/* + QAction *action = actionCollection()->addAction( QLatin1String("build_index") ); + action->setText( i18n("Build Search Index...") ); + connect( action, SIGNAL( triggered() ), mNavigator, SLOT( showIndexDialog() ) ); + + KConfigGroup debugGroup( KGlobal::config(), "Debug" ); + if ( debugGroup.readEntry( "SearchErrorLog", false) ) { + action = actionCollection()->addAction(QLatin1String("show_search_stderr")); + action->setText( i18n("Show Search Error Log") ); + connect( action, SIGNAL( triggered() ), this, SLOT( showSearchStderr() ) ); + } +*/ + History::self().setupActions( actionCollection() ); + + QAction *action = actionCollection()->addAction(QLatin1String("configure_fonts" )); + action->setText( i18n( "Configure Fonts..." ) ); + connect( action, SIGNAL( triggered() ), this, SLOT( slotConfigureFonts() ) ); + + action = actionCollection()->addAction(QLatin1String("incFontSizes")); + action->setText( i18n( "Increase Font Sizes" ) ); + action->setIcon( KIcon( QLatin1String("zoom-in") ) ); + connect( action, SIGNAL( triggered() ), this, SLOT( slotIncFontSizes() ) ); + + action = actionCollection()->addAction(QLatin1String("decFontSizes")); + action->setText( i18n( "Decrease Font Sizes" ) ); + action->setIcon( KIcon( QLatin1String("zoom-out") ) ); + connect( action, SIGNAL( triggered() ), this, SLOT( slotDecFontSizes() ) ); +} + +void MainWindow::slotCopySelectedText() +{ + mDoc->copySelectedText(); +} + +void MainWindow::print() +{ + mDoc->view()->print(); +} + +void MainWindow::slotStarted(KIO::Job *job) +{ + if (job) + connect(job, SIGNAL(infoMessage( KJob *, const QString &, const QString &)), + SLOT(slotInfoMessage(KJob *, const QString &))); + + History::self().updateActions(); +} + +void MainWindow::goInternalUrl( const KUrl &url ) +{ + mDoc->closeUrl(); + slotOpenURLRequest( url ); +} + +void MainWindow::slotOpenURLRequest( const KUrl &url, + const KParts::OpenUrlArguments &args, + const KParts::BrowserArguments &browserArgs ) +{ + kDebug( 1400 ) << url.url(); + + mNavigator->selectItem( url ); + viewUrl( url, args, browserArgs ); +} + +void MainWindow::viewUrl( const QString &url ) +{ + viewUrl( KUrl( url ) ); +} + +void MainWindow::viewUrl( const KUrl &url, const KParts::OpenUrlArguments &args, const KParts::BrowserArguments &browserArgs ) +{ + stop(); + + QString proto = url.protocol().toLower(); + + if ( proto == "khelpcenter" ) { + History::self().createEntry(); + mNavigator->openInternalUrl( url ); + return; + } + + bool own = false; + + if ( proto == QLatin1String("help") + || proto == QLatin1String("glossentry") + || proto == QLatin1String("about") + || proto == QLatin1String("man") + || proto == QLatin1String("info") + || proto == QLatin1String("cgi") + || proto == QLatin1String("ghelp")) + own = true; + else if ( url.isLocalFile() ) { + KMimeType::Ptr mime = KMimeType::findByPath( url.toLocalFile() ); + if ( mime->is("text/html") ) + own = true; + } + + if ( !own ) { + new KRun( url,this ); + return; + } + + History::self().createEntry(); + + mDoc->setArguments( args ); + mDoc->browserExtension()->setBrowserArguments( browserArgs ); + + if ( proto == QLatin1String("glossentry") ) { + QString decodedEntryId = QUrl::fromPercentEncoding( url.encodedPathAndQuery().toAscii() ); + slotGlossSelected( mNavigator->glossEntry( decodedEntryId ) ); + mNavigator->slotSelectGlossEntry( decodedEntryId ); + } else { + mDoc->openUrl( url ); + } +} + +void MainWindow::documentCompleted() +{ + kDebug(); + + History::self().updateCurrentEntry( mDoc ); + History::self().updateActions(); +} + +void MainWindow::slotInfoMessage(KJob *, const QString &m) +{ + statusBarMessage(m); +} + +void MainWindow::statusBarMessage(const QString &m) +{ + statusBar()->changeItem(m, 0); +} + +void MainWindow::openUrl( const QString &url ) +{ + openUrl( KUrl( url ) ); +} + +void MainWindow::openUrl( const QString &url, const QByteArray& startup_id ) +{ + KStartupInfo::setNewStartupId( this, startup_id ); + openUrl( KUrl( url ) ); +} + +void MainWindow::openUrl( const KUrl &url ) +{ + if ( url.isEmpty() ) slotShowHome(); + else { + mNavigator->selectItem( url ); + viewUrl( url ); + } +} + +void MainWindow::slotGlossSelected(const GlossaryEntry &entry) +{ + kDebug(); + + stop(); + History::self().createEntry(); + mDoc->begin( KUrl( "help:/khelpcenter/glossary" ) ); + mDoc->write( Glossary::entryToHtml( entry ) ); + mDoc->end(); +} + +void MainWindow::stop() +{ + kDebug(); + + mDoc->closeUrl(); + History::self().updateCurrentEntry( mDoc ); +} + +void MainWindow::showHome() +{ + slotShowHome(); +} + +void MainWindow::slotShowHome() +{ + viewUrl( mNavigator->homeURL() ); + mNavigator->clearSelection(); +} + +void MainWindow::lastSearch() +{ + slotLastSearch(); +} + +void MainWindow::slotLastSearch() +{ + mDoc->lastSearch(); +} + +void MainWindow::enableLastSearchAction() +{ + mLastSearchAction->setEnabled( true ); +} + +void MainWindow::showSearchStderr() +{ + QString log = mNavigator->searchEngine()->errorLog(); + + if ( !mLogDialog ) { + mLogDialog = new LogDialog( this ); + } + + mLogDialog->setLog( log ); + mLogDialog->show(); + mLogDialog->raise(); +} + +void MainWindow::slotIncFontSizes() +{ + mDoc->slotIncFontSizes(); + updateFontScaleActions(); +} + +void MainWindow::slotDecFontSizes() +{ + mDoc->slotDecFontSizes(); + updateFontScaleActions(); +} + +void MainWindow::updateFontScaleActions() +{ + actionCollection()->action( QLatin1String("incFontSizes") )->setEnabled( mDoc->fontScaleFactor() + mDoc->fontScaleStepping() <= 300 ); + actionCollection()->action( QLatin1String("decFontSizes") )->setEnabled( mDoc->fontScaleFactor() - mDoc->fontScaleStepping() >= 20 ); + + KConfigGroup configGroup( KGlobal::config(), QLatin1String("General") ); + configGroup.writeEntry( QLatin1String("Font zoom factor"), mDoc->fontScaleFactor() ); + configGroup.sync(); +} + +void MainWindow::slotConfigureFonts() +{ + FontDialog dlg( this ); + if ( dlg.exec() == QDialog::Accepted ) + { + if (mDoc->baseURL().isEmpty()) + { + const_cast( mDoc->settings() )->init( KGlobal::config().data() ); + slotShowHome(); + } + else mDoc->slotReload(); + } +} + +#include "mainwindow.moc" + +// vim:ts=2:sw=2:et diff --git a/khelpcenter/mainwindow.h b/khelpcenter/mainwindow.h new file mode 100644 index 00000000..fcf1ec00 --- /dev/null +++ b/khelpcenter/mainwindow.h @@ -0,0 +1,107 @@ + +#ifndef KHC_MAINWINDOW_H +#define KHC_MAINWINDOW_H + +#include +#include + +#include +#include + +#include "navigator.h" +#include "glossary.h" + +class QSplitter; + +class LogDialog; + +namespace KHC { + +class View; + +class MainWindow : public KXmlGuiWindow +{ + Q_OBJECT + Q_CLASSINFO("D-Bus Interface", "org.kde.khelpcenter.khelpcenter") + public: + MainWindow(); + ~MainWindow(); + + public Q_SLOTS: + Q_SCRIPTABLE void openUrl( const QString &url ); + Q_SCRIPTABLE void openUrl( const QString &url, const QByteArray& startup_id ); + Q_SCRIPTABLE void showHome(); + Q_SCRIPTABLE void lastSearch(); + + public Q_SLOTS: + void print(); + void statusBarMessage(const QString &m); + void slotShowHome(); + void slotLastSearch(); + void showSearchStderr(); + /** + Show document corresponding to given URL in viewer part. + */ + void viewUrl( const QString & ); + + /** + Open document corresponding to given URL, i.e. show it in the viewer part + and select the corresponding entry in the navigator widget. + */ + void openUrl( const KUrl &url ); + + protected: + void setupActions(); + /** + Show document corresponding to given URL in viewer part. + */ + void viewUrl( const KUrl &url, + const KParts::OpenUrlArguments &args = KParts::OpenUrlArguments(), + const KParts::BrowserArguments &browserArgs = KParts::BrowserArguments() ); + + virtual void saveProperties( KConfigGroup &config ); + virtual void readProperties( const KConfigGroup &config ); + + void readConfig(); + void writeConfig(); + + protected Q_SLOTS: + void enableLastSearchAction(); + void enableCopyTextAction(); + + private: + void stop(); + + private Q_SLOTS: + void slotGlossSelected(const GlossaryEntry &entry); + void slotStarted(KIO::Job *job); + void slotInfoMessage(KJob *, const QString &); + void goInternalUrl( const KUrl & ); + /** + This function is called when the user clicks on a link in the viewer part. + */ + void slotOpenURLRequest( const KUrl &url, + const KParts::OpenUrlArguments &args = KParts::OpenUrlArguments(), + const KParts::BrowserArguments &browserArgs = KParts::BrowserArguments()); + void documentCompleted(); + void slotIncFontSizes(); + void slotDecFontSizes(); + void slotConfigureFonts(); + void slotCopySelectedText(); + +private: + void updateFontScaleActions(); + + QSplitter *mSplitter; + View *mDoc; + Navigator *mNavigator; + + QAction *mLastSearchAction; + QAction *mCopyText; + LogDialog *mLogDialog; +}; + +} + +#endif //KHC_MAINWINDOW_H +// vim:ts=2:sw=2:et diff --git a/khelpcenter/navigator.cpp b/khelpcenter/navigator.cpp new file mode 100644 index 00000000..84be06bb --- /dev/null +++ b/khelpcenter/navigator.cpp @@ -0,0 +1,679 @@ +/* + * This file is part of the KDE Help Center + * + * Copyright (C) 1999 Matthias Elter (me@kde.org) + * + * 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 "navigator.h" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "navigatoritem.h" +#include "navigatorappitem.h" +#include "searchwidget.h" +#include "searchengine.h" +#include "docmetainfo.h" +#include "docentrytraverser.h" +#include "glossary.h" +#include "toc.h" +#include "view.h" +#include "infotree.h" +#include "mainwindow.h" +#include "plugintraverser.h" +#include "scrollkeepertreebuilder.h" +#include "kcmhelpcenter.h" +#include "formatter.h" +#include "history.h" +#include "prefs.h" + +using namespace KHC; + +Navigator::Navigator( View *view, QWidget *parent, const char *name ) + : QWidget( parent ), mIndexDialog( 0 ), + mView( view ), mSelected( false ) +{ + setObjectName( name ); + + KConfigGroup config(KGlobal::config(), "General"); + mShowMissingDocs = config.readEntry("ShowMissingDocs", false); + + mSearchEngine = new SearchEngine( view ); + connect( mSearchEngine, SIGNAL( searchFinished() ), + SLOT( slotSearchFinished() ) ); + + DocMetaInfo::self()->scanMetaInfo(); + + QBoxLayout *topLayout = new QVBoxLayout( this ); + + mSearchFrame = new QFrame( this ); + topLayout->addWidget( mSearchFrame ); + + QBoxLayout *searchLayout = new QHBoxLayout( mSearchFrame ); + searchLayout->setSpacing( KDialog::spacingHint() ); + searchLayout->setMargin( 6 ); + + mSearchEdit = new KLineEdit( mSearchFrame ); + mSearchEdit->setClearButtonShown(true); + searchLayout->addWidget( mSearchEdit ); + connect( mSearchEdit, SIGNAL( returnPressed() ), SLOT( slotSearch() ) ); + connect( mSearchEdit, SIGNAL( textChanged( const QString & ) ), + SLOT( checkSearchButton() ) ); + + mSearchButton = new QPushButton( i18n("&Search"), mSearchFrame ); + searchLayout->addWidget( mSearchButton ); + connect( mSearchButton, SIGNAL( clicked() ), SLOT( slotSearch() ) ); + + mTabWidget = new QTabWidget( this ); + topLayout->addWidget( mTabWidget ); + + setupContentsTab(); + setupGlossaryTab(); + setupSearchTab(); + + insertPlugins(); + hideSearch(); +/* + if ( !mSearchEngine->initSearchHandlers() ) { + hideSearch(); + } else { + mSearchWidget->updateScopeList(); + mSearchWidget->readConfig( KGlobal::config().data() ); + } + */ + connect( mTabWidget, SIGNAL( currentChanged( QWidget * ) ), + SLOT( slotTabChanged( QWidget * ) ) ); +} + +Navigator::~Navigator() +{ + delete mSearchEngine; +} + +SearchEngine *Navigator::searchEngine() const +{ + return mSearchEngine; +} + +Formatter *Navigator::formatter() const +{ + return mView->formatter(); +} + +bool Navigator::showMissingDocs() const +{ + return mShowMissingDocs; +} + +void Navigator::setupContentsTab() +{ + mContentsTree = new QTreeWidget( mTabWidget ); + mContentsTree->setFrameStyle( QFrame::NoFrame ); + mContentsTree->setAllColumnsShowFocus(true); + mContentsTree->setRootIsDecorated(false); + mContentsTree->headerItem()->setHidden(true); + + connect(mContentsTree, SIGNAL(itemActivated(QTreeWidgetItem*,int)), + SLOT(slotItemSelected(QTreeWidgetItem*))); + + mTabWidget->addTab(mContentsTree, i18n("&Contents")); +} + +void Navigator::setupSearchTab() +{ + + mSearchWidget = new SearchWidget( mSearchEngine, mTabWidget ); + connect( mSearchWidget, SIGNAL( searchResult( const QString & ) ), + SLOT( slotShowSearchResult( const QString & ) ) ); + connect( mSearchWidget, SIGNAL( scopeCountChanged( int ) ), + SLOT( checkSearchButton() ) ); + connect( mSearchWidget, SIGNAL( showIndexDialog() ), + SLOT( showIndexDialog() ) ); + + mTabWidget->addTab( mSearchWidget, i18n("Search Options")); + +} + +void Navigator::setupGlossaryTab() +{ + mGlossaryTree = new Glossary( mTabWidget ); + connect( mGlossaryTree, SIGNAL( entrySelected( const GlossaryEntry & ) ), + this, SIGNAL( glossSelected( const GlossaryEntry & ) ) ); + mTabWidget->addTab( mGlossaryTree, i18n( "G&lossary" ) ); +} + +void Navigator::insertPlugins() +{ + PluginTraverser t( this, mContentsTree ); + DocMetaInfo::self()->traverseEntries( &t ); +} + +void Navigator::insertParentAppDocs( const QString &name, NavigatorItem *topItem ) +{ + kDebug(1400) << "Requested plugin documents for ID " << name; + + KServiceGroup::Ptr grp = KServiceGroup::childGroup( name ); + if ( !grp ) + return; + + KServiceGroup::List entries = grp->entries(); + KServiceGroup::List::ConstIterator it = entries.constBegin(); + KServiceGroup::List::ConstIterator end = entries.constEnd(); + for ( ; it != end; ++it ) { + QString desktopFile = ( *it )->entryPath(); + if ( QDir::isRelativePath( desktopFile ) ) + desktopFile = KStandardDirs::locate( "apps", desktopFile ); + createItemFromDesktopFile( topItem, desktopFile ); + } +} + +void Navigator::insertKCMDocs( const QString &name, NavigatorItem *topItem, const QString &type ) +{ + kDebug(1400) << "Requested KCM documents for ID" << name; + QString systemsettingskontrolconstraint = "[X-KDE-System-Settings-Parent-Category] != ''"; + QString konquerorcontrolconstraint = "[X-KDE-PluginKeyword] == 'khtml_general'\ + or [X-KDE-PluginKeyword] == 'performance'\ + or [X-KDE-PluginKeyword] == 'bookmarks'"; + QString filemanagercontrolconstraint = "[X-KDE-PluginKeyword] == 'behavior'\ + or [X-KDE-PluginKeyword] == 'dolphinviewmodes'\ + or [X-KDE-PluginKeyword] == 'dolphinnavigation'\ + or [X-KDE-PluginKeyword] == 'dolphinservices'\ + or [X-KDE-PluginKeyword] == 'dolphingeneral'\ + or [X-KDE-PluginKeyword] == 'trash'"; + QString browsercontrolconstraint = "[X-KDE-PluginKeyword] == 'khtml_behavior'\ + or [X-KDE-PluginKeyword] == 'proxy'\ + or [X-KDE-PluginKeyword] == 'khtml_appearance'\ + or [X-KDE-PluginKeyword] == 'khtml_filter'\ + or [X-KDE-PluginKeyword] == 'cache'\ + or [X-KDE-PluginKeyword] == 'cookie'\ + or [X-KDE-PluginKeyword] == 'useragent'\ + or [X-KDE-PluginKeyword] == 'khtml_java_js'\ + or [X-KDE-PluginKeyword] == 'khtml_plugins'"; +/* missing in browsercontrolconstraint +History no X-KDE-PluginKeyword in kcmhistory.desktop +*/ + QString othercontrolconstraint = "[X-KDE-PluginKeyword] == 'cgi'"; + + KService::List list; + + if ( type == QString("kcontrol") ) { + list = KServiceTypeTrader::self()->query( "KCModule", systemsettingskontrolconstraint ); + } else if ( type == QString("konquerorcontrol") ) { + list = KServiceTypeTrader::self()->query( "KCModule", konquerorcontrolconstraint ); + } else if ( type == QString("browsercontrol") ) { + list = KServiceTypeTrader::self()->query( "KCModule", browsercontrolconstraint ); + } else if ( type == QString("filemanagercontrol") ) { + list = KServiceTypeTrader::self()->query( "KCModule", filemanagercontrolconstraint ); + } else if ( type == QString("othercontrol") ) { + list = KServiceTypeTrader::self()->query( "KCModule", othercontrolconstraint ); + } else if ( type == QString("kinfocenter") ) { + list = KServiceTypeTrader::self()->query( "KCModule", "[X-KDE-ParentApp] == 'kinfocenter'" ); + } + + for ( KService::List::const_iterator it = list.constBegin(); it != list.constEnd(); ++it ) + { + KService::Ptr s = (*it); + KCModuleInfo m = KCModuleInfo(s); + QString desktopFile = KStandardDirs::locate( "services", m.fileName() ); + createItemFromDesktopFile( topItem, desktopFile ); + } + topItem->sortChildren( 0, Qt::AscendingOrder /* ascending */ ); +} + +void Navigator::insertIOSlaveDocs( const QString &name, NavigatorItem *topItem ) +{ + kDebug(1400) << "Requested IOSlave documents for ID" << name; + + QStringList list = KProtocolInfo::protocols(); + list.sort(); + + NavigatorItem *prevItem = 0; + for ( QStringList::ConstIterator it = list.constBegin(); it != list.constEnd(); ++it ) + { + QString docPath = KProtocolInfo::docPath(*it); + if ( !docPath.isNull() ) + { + // First parameter is ignored if second is an absolute path + KUrl url(KUrl("help:/"), docPath); + QString icon = KProtocolInfo::icon(*it); + if ( icon.isEmpty() ) icon = "text-plain"; + DocEntry *entry = new DocEntry( *it, url.url(), icon ); + NavigatorItem *item = new NavigatorItem( entry, topItem, prevItem ); + prevItem = item; + item->setAutoDeleteDocEntry( true ); + } + } +} + +void Navigator::createItemFromDesktopFile( NavigatorItem *topItem, + const QString &file ) +{ + KDesktopFile desktopFile( file ); + QString docPath = desktopFile.readDocPath(); + if ( !docPath.isNull() ) { + // First parameter is ignored if second is an absolute path + KUrl url(KUrl("help:/"), docPath); + QString icon = desktopFile.readIcon(); + if ( icon.isEmpty() ) icon = "text-plain"; + DocEntry *entry = new DocEntry( desktopFile.readName(), url.url(), icon ); + NavigatorItem *item = new NavigatorItem( entry, topItem ); + item->setAutoDeleteDocEntry( true ); + } +} + +void Navigator::insertInfoDocs( NavigatorItem *topItem ) +{ + InfoTree *infoTree = new InfoTree( this ); + infoTree->build( topItem ); +} + +NavigatorItem *Navigator::insertScrollKeeperDocs( NavigatorItem *topItem, + NavigatorItem *after ) +{ + ScrollKeeperTreeBuilder *builder = new ScrollKeeperTreeBuilder( this ); + return builder->build( topItem, after ); +} + +void Navigator::selectItem( const KUrl &url ) +{ + kDebug() << "Navigator::selectItem(): " << url.url(); + + if ( url.url() == "khelpcenter:home" ) { + clearSelection(); + return; + } + + // help:/foo&anchor=bar gets redirected to help:/foo#bar + // Make sure that we match both the original URL as well as + // its counterpart. + KUrl alternativeURL = url; + if (url.hasRef()) + { + alternativeURL.setQuery("anchor="+url.ref()); + alternativeURL.setRef(QString()); + } + + // If the navigator already has the given URL selected, do nothing. + NavigatorItem *item; + item = static_cast( mContentsTree->currentItem() ); + if ( item && mSelected ) { + KUrl currentURL ( item->entry()->url() ); + if ( (currentURL == url) || (currentURL == alternativeURL) ) { + kDebug() << "URL already shown."; + return; + } + } + + // First, populate the NavigatorAppItems if we don't want the home page + if ( url != homeURL() ) { + QTreeWidgetItemIterator it1( mContentsTree ); + while( (*it1) ) + { + NavigatorAppItem *appItem = dynamic_cast( (*it1) ); + if ( appItem ) appItem->populate( true ); + ++it1; + } + } + + QTreeWidgetItemIterator it( mContentsTree ); + while ( (*it) ) { + NavigatorItem *item = static_cast( (*it) ); + KUrl itemUrl( item->entry()->url() ); + if ( (itemUrl == url) || (itemUrl == alternativeURL) ) { + mContentsTree->setCurrentItem( item ); + // If the current item was not selected and remained unchanged it + // needs to be explicitly selected + mContentsTree->setCurrentItem(item); + item->setExpanded( true ); + break; + } + ++it; + } + if ( !(*it) ) { + clearSelection(); + } else { + mSelected = true; + } +} + +void Navigator::clearSelection() +{ + mContentsTree->clearSelection(); + mSelected = false; +} + +void Navigator::slotItemSelected( QTreeWidgetItem *currentItem ) +{ + if ( !currentItem ) return; + + mSelected = true; + + NavigatorItem *item = static_cast( currentItem ); + + kDebug(1400) << item->entry()->name() << endl; + + item->setExpanded( !item->isExpanded() ); + + KUrl url ( item->entry()->url() ); + + + + if ( url.protocol() == "khelpcenter" ) { + mView->closeUrl(); + History::self().updateCurrentEntry( mView ); + History::self().createEntry(); + showOverview( item, url ); + } else { + + emit itemSelected( url.url() ); + } + + mLastUrl = url; +} + +void Navigator::openInternalUrl( const KUrl &url ) +{ + if ( url.url() == "khelpcenter:home" ) { + clearSelection(); + showOverview( 0, url ); + return; + } + + selectItem( url ); + if ( !mSelected ) return; + + NavigatorItem *item = + static_cast( mContentsTree->currentItem() ); + + if ( item ) showOverview( item, url ); +} + +void Navigator::showOverview( NavigatorItem *item, const KUrl &url ) +{ + mView->beginInternal( url ); + + QString fileName = KStandardDirs::locate( "data", "khelpcenter/index.html.in" ); + if ( fileName.isEmpty() ) + return; + + QFile file( fileName ); + + if ( !file.open( QIODevice::ReadOnly ) ) + return; + + QTextStream stream( &file ); + QString res = stream.readAll(); + + QString title,name,content; + uint childCount; + + if ( item ) { + title = item->entry()->name(); + name = item->entry()->name(); + + QString info = item->entry()->info(); + if ( !info.isEmpty() ) content = QLatin1String("

") + info + QLatin1String("

\n"); + + childCount = item->childCount(); + } else { + title = i18n("Start Page"); + name = i18n("KDE Help Center"); + + childCount = mContentsTree->topLevelItemCount(); + } + + if ( childCount > 0 ) { + QTreeWidgetItem *child; + if ( item ) child = item; + else child = mContentsTree->invisibleRootItem(); + + mDirLevel = 0; + + content += createChildrenList( child ); + } + else + content += QLatin1String("

"); + + res = res.arg(title).arg(name).arg(content); + + mView->write( res ); + + mView->end(); +} + +QString Navigator::createChildrenList( QTreeWidgetItem *child ) +{ + ++mDirLevel; + + QString t; + + t += QLatin1String("\n"); + + --mDirLevel; + + return t; +} + +void Navigator::slotSearch() +{ + + kDebug(1400) << "Navigator::slotSearch()"; + + if ( !checkSearchIndex() ) return; + + if ( mSearchEngine->isRunning() ) return; + + QString words = mSearchEdit->text(); + QString method = mSearchWidget->method(); + int pages = mSearchWidget->pages(); + QString scope = mSearchWidget->scope(); + + kDebug(1400) << "Navigator::slotSearch() words: " << words; + kDebug(1400) << "Navigator::slotSearch() scope: " << scope; + + if ( words.isEmpty() || scope.isEmpty() ) return; + + // disable search Button during searches + mSearchButton->setEnabled(false); + QApplication::setOverrideCursor(Qt::WaitCursor); + + if ( !mSearchEngine->search( words, method, pages, scope ) ) { + slotSearchFinished(); + KMessageBox::sorry( this, i18n("Unable to run search program.") ); + } + +} + +void Navigator::slotShowSearchResult( const QString &url ) +{ + QString u = url; + u.replace( "%k", mSearchEdit->text() ); + + emit itemSelected( u ); +} + +void Navigator::slotSearchFinished() +{ + mSearchButton->setEnabled(true); + QApplication::restoreOverrideCursor(); + + kDebug( 1400 ) << "Search finished."; +} + +void Navigator::checkSearchButton() +{ + mSearchButton->setEnabled( !mSearchEdit->text().isEmpty() && + mSearchWidget->scopeCount() > 0 ); + mTabWidget->setCurrentIndex( mTabWidget->indexOf( mSearchWidget ) ); +} + + +void Navigator::hideSearch() +{ + mSearchFrame->hide(); + mTabWidget->removeTab( mTabWidget->indexOf( mSearchWidget ) ); +} + +bool Navigator::checkSearchIndex() +{ + KConfigGroup cfg(KGlobal::config(), "Search" ); + if ( cfg.readEntry( "IndexExists", false) ) return true; + + if ( mIndexDialog && !mIndexDialog->isHidden() ) return true; + + QString text = i18n( "A search index does not yet exist. Do you want " + "to create the index now?" ); + + int result = KMessageBox::questionYesNo( this, text, QString(), + KGuiItem(i18n("Create")), + KGuiItem(i18n("Do Not Create")), + QLatin1String("indexcreation") ); + if ( result == KMessageBox::Yes ) { + showIndexDialog(); + return false; + } + + return true; +} + +void Navigator::slotTabChanged( QWidget *wid ) +{ + if ( wid == mSearchWidget ) checkSearchIndex(); +} + +void Navigator::slotSelectGlossEntry( const QString &id ) +{ + mGlossaryTree->slotSelectGlossEntry( id ); +} + +KUrl Navigator::homeURL() +{ + if ( !mHomeUrl.isEmpty() ) return mHomeUrl; + + KSharedConfig::Ptr cfg = KGlobal::config(); + // We have to reparse the configuration here in order to get a + // language-specific StartUrl, e.g. "StartUrl[de]". + cfg->reparseConfiguration(); + mHomeUrl = cfg->group("General").readPathEntry( "StartUrl", QLatin1String("khelpcenter:home") ); + return mHomeUrl; +} + +void Navigator::showIndexDialog() +{ + if ( !mIndexDialog ) { + mIndexDialog = new KCMHelpCenter( mSearchEngine, this ); + connect( mIndexDialog, SIGNAL( searchIndexUpdated() ), mSearchWidget, + SLOT( updateScopeList() ) ); + } + mIndexDialog->show(); + mIndexDialog->raise(); +} + +void Navigator::readConfig() +{ + if ( Prefs::currentTab() == Prefs::Search ) { + mTabWidget->setCurrentIndex( mTabWidget->indexOf( mSearchWidget ) ); + } else if ( Prefs::currentTab() == Prefs::Glossary ) { + mTabWidget->setCurrentIndex( mTabWidget->indexOf( mGlossaryTree ) ); + } else { + mTabWidget->setCurrentIndex( mTabWidget->indexOf( mContentsTree ) ); + } +} + +void Navigator::writeConfig() +{ + if ( mTabWidget->currentWidget() == mSearchWidget ) { + Prefs::setCurrentTab( Prefs::Search ); + } else if ( mTabWidget->currentWidget() == mGlossaryTree ) { + Prefs::setCurrentTab( Prefs::Glossary ); + } else { + Prefs::setCurrentTab( Prefs::Content ); + } +} + +void Navigator::clearSearch() +{ + mSearchEdit->setText( QString() ); +} + +#include "navigator.moc" + +// vim:ts=2:sw=2:et diff --git a/khelpcenter/navigator.h b/khelpcenter/navigator.h new file mode 100644 index 00000000..d72c7814 --- /dev/null +++ b/khelpcenter/navigator.h @@ -0,0 +1,144 @@ +/* + * This file is part of the KDE Help Center + * + * Copyright (C) 1999 Matthias Elter (me@kde.org) + * + * 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. + */ + +#ifndef KHC_NAVIGATOR_H +#define KHC_NAVIGATOR_H + +#include "glossary.h" + +#include + +#include +#include +#include +#include +#include +#include + +class QPushButton; +class KLineEdit; +class KCMHelpCenter; + +namespace KHC { + +class NavigatorItem; +class Navigator; +class View; +class SearchEngine; +class SearchWidget; +class Formatter; + +class Navigator : public QWidget +{ + Q_OBJECT + public: + explicit Navigator(View *, QWidget *parent=0, const char *name=0); + virtual ~Navigator(); + + KUrl homeURL(); + + SearchEngine *searchEngine() const; + Formatter *formatter() const; + + const GlossaryEntry &glossEntry(const QString &term) const { return mGlossaryTree->entry( term ); } + + void insertParentAppDocs( const QString &name, NavigatorItem *parent ); + NavigatorItem *insertScrollKeeperDocs( NavigatorItem *parentItem, + NavigatorItem *after ); + void insertInfoDocs( NavigatorItem *parentItem ); + void insertKCMDocs(const QString &, NavigatorItem*parent, const QString &); + void insertIOSlaveDocs(const QString &, NavigatorItem*parent); + + void createItemFromDesktopFile( NavigatorItem *item, const QString &name ); + + bool showMissingDocs() const; + + void clearSelection(); + + void showOverview( NavigatorItem *item, const KUrl &url ); + + void readConfig(); + void writeConfig(); + + public Q_SLOTS: + void openInternalUrl( const KUrl &url ); + void slotItemSelected(QTreeWidgetItem* index); + void slotSearch(); + void slotShowSearchResult( const QString & ); + void slotSelectGlossEntry( const QString &id ); + void selectItem( const KUrl &url ); + void showIndexDialog(); + + Q_SIGNALS: + void itemSelected(const QString& itemURL); + void glossSelected(const GlossaryEntry &entry); + + protected Q_SLOTS: + void slotSearchFinished(); + void slotTabChanged( QWidget * ); + void checkSearchButton(); + + bool checkSearchIndex(); + + void clearSearch(); + + protected: + QString createChildrenList( QTreeWidgetItem *child ); + + private: + void setupContentsTab(); + void setupIndexTab(); + void setupSearchTab(); + void setupGlossaryTab(); + + void insertPlugins(); + void hideSearch(); + + QTreeWidget *mContentsTree; + Glossary *mGlossaryTree; + + SearchWidget *mSearchWidget; + KCMHelpCenter *mIndexDialog; + + QTabWidget *mTabWidget; + + QFrame *mSearchFrame; + KLineEdit *mSearchEdit; + QPushButton *mSearchButton; + + bool mShowMissingDocs; + + SearchEngine *mSearchEngine; + + View *mView; + + KUrl mHomeUrl; + + bool mSelected; + + KUrl mLastUrl; + + int mDirLevel; +}; + +} + +#endif //KHC_NAVIGATOR_H +// vim:ts=2:sw=2:et diff --git a/khelpcenter/navigatorappitem.cpp b/khelpcenter/navigatorappitem.cpp new file mode 100644 index 00000000..d5b0f6f7 --- /dev/null +++ b/khelpcenter/navigatorappitem.cpp @@ -0,0 +1,149 @@ +/* + * This file is part of the KDE Help Center + * + * Copyright (C) 2001 Waldo Bastian + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License version 2 or at your option version 3 as published + * by the Free Software Foundation. + * + * 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 "navigatorappitem.h" +#include "docentry.h" + +#include +#include +#include + +using namespace KHC; + +NavigatorAppItem::NavigatorAppItem( DocEntry *entry, QTreeWidget *parent, + const QString &relPath ) + : NavigatorItem( entry, parent ), + mRelpath( relPath ), + mPopulated( false ) +{ + populate(); +} + +NavigatorAppItem::NavigatorAppItem( DocEntry *entry, QTreeWidgetItem *parent, + const QString &relPath ) + : NavigatorItem( entry, parent ), + mRelpath( relPath ), + mPopulated( false ) +{ + populate(); +} + +NavigatorAppItem::NavigatorAppItem( DocEntry *entry, QTreeWidget *parent, + QTreeWidgetItem *after ) + : NavigatorItem( entry, parent, after ), + mPopulated( false ) +{ + populate(); +} + +NavigatorAppItem::NavigatorAppItem( DocEntry *entry, QTreeWidgetItem *parent, + QTreeWidgetItem *after ) + : NavigatorItem( entry, parent, after ), + mPopulated( false ) +{ + populate(); +} + +void NavigatorAppItem::setRelpath( const QString &relpath ) +{ + mRelpath = relpath; +} + +void NavigatorAppItem::setExpanded(bool open) +{ + kDebug() << "NavigatorAppItem::setOpen()"; + + if ( open && (childCount() == 0) && !mPopulated ) + { + kDebug() << "NavigatorAppItem::setOpen(" << this << ", " + << mRelpath << ")" << endl; + populate(); + } + QTreeWidgetItem::setExpanded(open); +} + +void NavigatorAppItem::populate( bool recursive ) +{ + if ( mPopulated ) return; + + KServiceGroup::Ptr root = KServiceGroup::group(mRelpath); + if ( !root ) { + kWarning() << "No Service groups\n"; + return; + } + KServiceGroup::List list = root->entries(); + + + for ( KServiceGroup::List::ConstIterator it = list.constBegin(); + it != list.constEnd(); ++it ) + { + const KSycocaEntry::Ptr e = *it; + NavigatorItem *item; + QString url; + + switch ( e->sycocaType() ) { + case KST_KService: + { + const KService::Ptr s = KService::Ptr::staticCast(e); + url = documentationURL( s.data() ); + if ( !url.isEmpty() ) { + DocEntry *entry = new DocEntry( s->name(), url, s->icon() ); + item = new NavigatorItem( entry, this ); + item->setAutoDeleteDocEntry( true ); + } + break; + } + case KST_KServiceGroup: + { + KServiceGroup::Ptr g = KServiceGroup::Ptr::staticCast(e); + if ( ( g->childCount() == 0 ) || g->name().startsWith( '.' ) ) + continue; + DocEntry *entry = new DocEntry( g->caption(), "", g->icon() ); + NavigatorAppItem *appItem; + appItem = new NavigatorAppItem( entry, this, g->relPath() ); + appItem->setAutoDeleteDocEntry( true ); + if ( recursive ) appItem->populate( recursive ); + break; + } + default: + break; + } + } + sortChildren( 0, Qt::AscendingOrder /* ascending */ ); + mPopulated = true; +} + +QString NavigatorAppItem::documentationURL( const KService *s ) +{ + QString docPath = s->property( QLatin1String("DocPath") ).toString(); + if ( docPath.isEmpty() ) { + docPath = s->property( QLatin1String("X-DocPath") ).toString(); + if ( docPath.isEmpty() ) { + return QString(); + } + } + + if ( docPath.startsWith( QLatin1String("file:")) || docPath.startsWith( QLatin1String("http:") ) ) + return docPath; + + return QLatin1String( "help:/" ) + docPath; +} + +// vim:ts=2:sw=2:et diff --git a/khelpcenter/navigatorappitem.h b/khelpcenter/navigatorappitem.h new file mode 100644 index 00000000..2622286b --- /dev/null +++ b/khelpcenter/navigatorappitem.h @@ -0,0 +1,59 @@ +/* + * navigatorappitem.h - part of the KDE Help Center + * + * Copyright (C) 2001 Waldo Bastian + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License version 2 or at your option version 3 as published + * by the Free Software Foundation. + * + * 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. + */ + +#ifndef KHC_NAVIGATORAPPITEM_H +#define KHC_NAVIGATORAPPITEM_H + +#include "navigatoritem.h" + +class KService; + +namespace KHC { + +class NavigatorAppItem : public NavigatorItem +{ + public: + NavigatorAppItem( DocEntry *entry, QTreeWidget *parent, + const QString &relPath ); + NavigatorAppItem( DocEntry *entry, QTreeWidgetItem *parent, + const QString &relPath ); + + NavigatorAppItem( DocEntry *entry, QTreeWidget *parent, + QTreeWidgetItem *after ); + NavigatorAppItem( DocEntry *entry, QTreeWidgetItem *parent, + QTreeWidgetItem *after ); + + void setRelpath( const QString & ); + + virtual void setExpanded(bool); + void populate( bool recursive = false ); + + protected: + QString documentationURL( const KService *s ); + + private: + QString mRelpath; + bool mPopulated; +}; + +} + +#endif //KHC_NAVIGATORAPPITEM_H +// vim:ts=2:sw=2:et diff --git a/khelpcenter/navigatoritem.cpp b/khelpcenter/navigatoritem.cpp new file mode 100644 index 00000000..efd83ed0 --- /dev/null +++ b/khelpcenter/navigatoritem.cpp @@ -0,0 +1,121 @@ +/* + * This file is part of the KDE Help Center + * + * Copyright (C) 1999 Matthias Elter (me@kde.org) + * + * 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 "navigatoritem.h" + +#include "toc.h" +#include "docentry.h" +#include "view.h" + +#include +#include + +#include + +using namespace KHC; + +NavigatorItem::NavigatorItem( DocEntry *entry, QTreeWidget *parent, + QTreeWidgetItem *after ) + : QTreeWidgetItem( parent, after ) +{ + init( entry ); +} + +NavigatorItem::NavigatorItem( DocEntry *entry, QTreeWidgetItem *parent, + QTreeWidgetItem *after ) + : QTreeWidgetItem( parent, after ) +{ + init( entry ); +} + +NavigatorItem::NavigatorItem( DocEntry *entry, QTreeWidget *parent ) + : QTreeWidgetItem( parent ) +{ + init( entry ); +} + +NavigatorItem::NavigatorItem( DocEntry *entry, QTreeWidgetItem *parent ) + : QTreeWidgetItem( parent ) +{ + init( entry ); +} + +NavigatorItem::~NavigatorItem() +{ + delete mToc; + + if ( mAutoDeleteDocEntry ) delete mEntry; +} + +void NavigatorItem::init( DocEntry *entry ) +{ + mEntry = entry; + mAutoDeleteDocEntry = false; + mToc = 0; + + updateItem(); +} + +DocEntry *NavigatorItem::entry() const +{ + return mEntry; +} + +void NavigatorItem::setAutoDeleteDocEntry( bool enabled ) +{ + mAutoDeleteDocEntry = enabled; +} + +void NavigatorItem::updateItem() +{ + setText( 0, entry()->name() ); + setIcon( 0, SmallIcon( entry()->icon() ) ); +} + +void NavigatorItem::scheduleTOCBuild() +{ + KUrl url ( entry()->url() ); + if ( !mToc && url.protocol() == "help") { + mToc = new TOC( this ); + + kDebug( 1400 ) << "Trying to build TOC for " << entry()->name() << endl; + mToc->setApplication( url.directory() ); + QString doc = View::langLookup( url.path() ); + // Enforce the original .docbook version, in case langLookup returns a + // cached version + if ( !doc.isNull() ) { + int pos = doc.indexOf( ".html" ); + if ( pos >= 0 ) { + doc.replace( pos, 5, ".docbook" ); + } + kDebug( 1400 ) << "doc = " << doc; + + mToc->build( doc ); + } + } +} + +void NavigatorItem::setExpanded( bool open ) +{ + scheduleTOCBuild(); + QTreeWidgetItem::setExpanded( open ); +} + +// vim:ts=2:sw=2:et diff --git a/khelpcenter/navigatoritem.h b/khelpcenter/navigatoritem.h new file mode 100644 index 00000000..d8b58fba --- /dev/null +++ b/khelpcenter/navigatoritem.h @@ -0,0 +1,68 @@ +/* + * navigatoritem.h - part of the KDE Help Center + * + * Copyright (C) 1999 Matthias Elter (me@kde.org) + * + * 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. + */ +#ifndef KHC_NAVIGATORITEM_H +#define KHC_NAVIGATORITEM_H + +#include +#include + +namespace KHC { + +class TOC; +class DocEntry; + +class NavigatorItem : public QTreeWidgetItem +{ + public: + NavigatorItem( DocEntry *entry, QTreeWidget *parent ); + NavigatorItem( DocEntry *entry, QTreeWidgetItem *parent ); + + NavigatorItem( DocEntry *entry, QTreeWidget *parent, + QTreeWidgetItem *after ); + NavigatorItem( DocEntry *entry, QTreeWidgetItem *parent, + QTreeWidgetItem *after ); + + ~NavigatorItem(); + + DocEntry *entry() const; + + void setAutoDeleteDocEntry( bool ); + + void updateItem(); + + TOC *toc() const { return mToc; } + + void setExpanded( bool open ); + + private: + void init( DocEntry * ); + void scheduleTOCBuild(); + + TOC *mToc; + + DocEntry *mEntry; + bool mAutoDeleteDocEntry; +}; + +} + +#endif // KHC_NAVIGATORITEM_H + +// vim:ts=2:sw=2:et diff --git a/khelpcenter/org.kde.khelpcenter.kcmhelpcenter.xml b/khelpcenter/org.kde.khelpcenter.kcmhelpcenter.xml new file mode 100644 index 00000000..14318bcb --- /dev/null +++ b/khelpcenter/org.kde.khelpcenter.kcmhelpcenter.xml @@ -0,0 +1,14 @@ + + + + + + + + + + + + + diff --git a/khelpcenter/plugins/Applications/.directory b/khelpcenter/plugins/Applications/.directory new file mode 100644 index 00000000..2f48c5bd --- /dev/null +++ b/khelpcenter/plugins/Applications/.directory @@ -0,0 +1,95 @@ +[Desktop Entry] + +Name=Application Manuals +Name[af]=Toepassing Handleidings +Name[ar]=دليل التطبيقات +Name[ast]=Manuales de l'aplicación +Name[be]=Даведкі аплетаў +Name[be@latin]=Padručniki pa aplikacyjach +Name[bg]=Ръководства на аплети +Name[bn]=অ্যাপলিকেশন ম্যানুয়াল +Name[bn_IN]=অ্যাপ্লিকেশনের সহায়িকা +Name[bs]=Uputstva za programe +Name[ca]=Manuals de les aplicacions +Name[ca@valencia]=Manuals de les aplicacions +Name[cs]=Příručky aplikací +Name[csb]=Pòdrãczniczi aplikacëjów +Name[da]=Programmanualer +Name[de]=Programmhandbücher +Name[el]=Εγχειρίδια εφαρμογών +Name[en_GB]=Application Manuals +Name[eo]=Manlibroj de aplikaĵoj +Name[es]=Manuales de las aplicaciones +Name[et]=Rakenduste käsiraamatud +Name[eu]=Aplikazio-eskuliburuak +Name[fa]=راهنماهای کاربرد +Name[fi]=Sovellusten oppaat +Name[fr]=Manuels des applications +Name[fy]=Applikaasje hânlieding +Name[ga]=Lámhleabhair Fheidhmchláir +Name[gl]=Manuais dos programas +Name[gu]=કાર્યક્રમ માર્ગદર્શિકાઓ +Name[he]=ספרי הדרכה של תוכניות +Name[hi]=अनुप्रयोग निर्देशिका +Name[hne]=अनुपरयोग निर्देसिका +Name[hr]=Priručnici aplikacije +Name[hsb]=Přiručki za aplikacije +Name[hu]=Alkalmazások kézikönyvei +Name[ia]=Manuales de application +Name[id]=Manual Aplikasi +Name[is]=Handbækur forrita +Name[it]=Manuali delle applicazioni +Name[ja]=アプリケーションマニュアル +Name[kk]=Қолданбаның нұсқаулары +Name[km]=សៀវភៅ​ដៃ​កម្មវិធី​ +Name[kn]=ಅನ್ವಯಗಳ ಕೈಪಿಡಿಗಳು +Name[ko]=프로그램 사용 설명서 +Name[ku]=Rêberên Sepanan +Name[lt]=Programų vadovai +Name[lv]=Programmu rokasgrāmatas +Name[mai]=अनुप्रयोग निर्देशिका +Name[mk]=Прирачници за апликации +Name[ml]=പ്രയോഗ സഹായകഗ്രന്ഥങ്ങള്‍ +Name[mr]=अनुप्रयोग पुस्तिका +Name[nb]=Håndbøker for programmer +Name[nds]=Programmhandböker +Name[ne]=अनुप्रयोग म्यानुअल +Name[nl]=Programmahandboeken +Name[nn]=Programbruksrettleiingar +Name[or]=ପ୍ରୟୋଗ ସହାୟକ ପୁସ୍ତକ +Name[pa]=ਐਪਲੀਕੇਸ਼ਨ ਮੈਨੂਅਲ +Name[pl]=Podręczniki programów +Name[pt]=Manuais das Aplicações +Name[pt_BR]=Manuais dos aplicativos +Name[ro]=Manualele aplicațiilor +Name[ru]=Руководства приложений +Name[se]=Prográmmagiehtagirjjit +Name[si]=යෙදුම් අත්පොත් +Name[sk]=Aplikačné manuály +Name[sl]=Priročniki za programe +Name[sr]=Упутства за програме +Name[sr@ijekavian]=Упутства за програме +Name[sr@ijekavianlatin]=Uputstva za programe +Name[sr@latin]=Uputstva za programe +Name[sv]=Programhandböcker +Name[ta]=பயன்பாட்டு கையேடுகள் +Name[te]=అనువర్తనముల మాన్యువల్‍స్‌ +Name[tg]=Дастуруламалҳои барнома +Name[th]=คู่มือของโปรแกรมต่าง ๆ +Name[tr]=Uygulama Kılavuzları +Name[ug]=پروگرامما قوللانمىسى +Name[uk]=Підручники з програм +Name[uz]=Dasturlar uchun qoʻllanmalar +Name[uz@cyrillic]=Дастурлар учун қўлланмалар +Name[vi]=Sổ tay ứng dụng +Name[wa]=Manuels des programes +Name[x-test]=xxApplication Manualsxx +Name[zh_CN]=应用程序手册 +Name[zh_TW]=應用程式手冊 + +X-DOC-Weight=200 + +X-KDE-KHelpcenter-Special=apps + +X-DOC-DocumentType=application/docbook+xml +X-DOC-Identifier=kde_application_manuals diff --git a/khelpcenter/plugins/Applications/CMakeLists.txt b/khelpcenter/plugins/Applications/CMakeLists.txt new file mode 100644 index 00000000..f9c45743 --- /dev/null +++ b/khelpcenter/plugins/Applications/CMakeLists.txt @@ -0,0 +1 @@ +install( FILES .directory DESTINATION ${DATA_INSTALL_DIR}/khelpcenter/plugins/Applications ) diff --git a/khelpcenter/plugins/CMakeLists.txt b/khelpcenter/plugins/CMakeLists.txt new file mode 100644 index 00000000..b9b3169f --- /dev/null +++ b/khelpcenter/plugins/CMakeLists.txt @@ -0,0 +1,20 @@ + +add_subdirectory( Applications ) +if (NOT WIN32) +add_subdirectory( Manpages ) +add_subdirectory( Scrollkeeper ) +endif (NOT WIN32) + + +########### install files ############### + +install( FILES fundamentals.desktop plasma.desktop + onlinehelp.desktop + info.desktop kicmodules.desktop + kcontrolmodules.desktop + konquerorcontrolmodules.desktop + browsercontrolmodules.desktop + filemanagercontrolmodules.desktop + othercontrolmodules.desktop + kioslaves.desktop DESTINATION ${DATA_INSTALL_DIR}/khelpcenter/plugins ) + diff --git a/khelpcenter/plugins/Manpages/.directory b/khelpcenter/plugins/Manpages/.directory new file mode 100644 index 00000000..a69c2283 --- /dev/null +++ b/khelpcenter/plugins/Manpages/.directory @@ -0,0 +1,92 @@ +[Desktop Entry] +Name=UNIX manual pages +Name[af]=UNIX manual pages +Name[ar]=صفحات كتيّب يونِكس +Name[ast]=Páxines de manual d'Unix +Name[be@latin]=Padručnyja staronki UNIX („man”) +Name[bg]=Ръководство за UNIX +Name[bn]=ইউনিক্স ম্যানুয়াল পেজ +Name[bn_IN]=UNIX ম্যানুয়াল পেজ +Name[bs]=Uputne stranice naredbi +Name[ca]=Pàgines de manual del UNIX +Name[ca@valencia]=Pàgines de manual del UNIX +Name[cs]=Manuálové stránky pro UNIX +Name[csb]=Pòdrãczniczi dlô UNIXA +Name[da]=UNIX manualsider +Name[de]=UNIX-Hilfeseiten +Name[el]=Σελίδες εγχειριδίου UNIX +Name[en_GB]=UNIX manual pages +Name[eo]=Paĝoj de manlibro de UNIX +Name[es]=Páginas de manual de Unix +Name[et]=UNIX-i manuaalileheküljed +Name[eu]=UNIX eskuliburu-orriak +Name[fa]=صفحات راهنمای یونیکس +Name[fi]=UNIX man-sivut +Name[fr]=Pages de manuel UNIX +Name[fy]=UNIX hânlieding siden +Name[ga]=Leathanaigh lámhleabhair UNIX +Name[gl]=Páxinas de manual de UNIX +Name[gu]=UNIX માર્ગદર્શિકા પાનાંઓ +Name[he]=דפי הוראות של יוניקס +Name[hi]=यूनिक्स निर्देशिका पृष्ठ +Name[hne]=यूनिक्स निर्देसिका पेज +Name[hr]=UNIX stranice s uputama +Name[hsb]=UNIX manual pages +Name[hu]=UNIX man oldalak +Name[ia]=Paginas de manual UNIX +Name[id]=Halaman manual UNIX +Name[is]=UNIX handbókin +Name[it]=Pagine «man» di UNIX +Name[ja]=UNIX マニュアルページ +Name[kk]=UNIX man беттері +Name[km]=ទំព័រ​សៀវភៅ​ដៃ​របស់​យូនីក +Name[kn]=UNIX ಕೈಪಿಡಿ ಪುಟಗಳು (ಮ್ಯಾನುಯಲ್ ಪೇಜಸ್) +Name[ko]=UNIX 매뉴얼 페이지 +Name[ku]=Rûpelên rêberiyê yên UNIX +Name[lt]=UNIX man (programų vadovų) puslapiai +Name[lv]=UNIX rokasgrāmatas +Name[mai]=यूनिक्स निर्देशिका पृष्ठ +Name[mk]=Страници со UNIX-прирачници +Name[ml]=യുണിക്സിലെ മാനുവല്‍ താളുകള്‍ +Name[mr]=UNIX पुस्तिका पान +Name[nb]=UNIX man-sider +Name[nds]=UNIX man-Sieden +Name[ne]=युनिक्स म्यानुअल पृष्ठ +Name[nl]=UNIX-handboeken +Name[nn]=Unix-manualsider +Name[or]=UNIX ସହାୟକ ପୁସ୍ତକ ପୃଷ୍ଠାଗୁଡ଼ିକ +Name[pa]=UNIX ਮੈਨੂਅਲ ਪੇਜ਼ +Name[pl]=Strony podręcznika UNIX-a +Name[pt]=Páginas de manual do UNIX +Name[pt_BR]=Páginas de manual do UNIX +Name[ro]=Pagini de manual UNIX +Name[ru]=Страницы руководств UNIX +Name[se]=Unix-giehtagirjesiiddut +Name[si]=UNIX අත්පොත් පිටු +Name[sk]=Unixové manuálové stránky +Name[sl]=Strani priročnika za UNIX +Name[sr]=Упутне странице наредби +Name[sr@ijekavian]=Упутне странице наредби +Name[sr@ijekavianlatin]=Uputne stranice naredbi +Name[sr@latin]=Uputne stranice naredbi +Name[sv]=Unix manualsidor +Name[ta]=UNIX உதவிப் பக்கங்கள் +Name[te]=UNIX మాన్యువల్ పుటలు +Name[tg]=Дастуруламалҳои UNIX +Name[th]=หน้าคู่มือ UNIX +Name[tr]=UNIX kılavuz sayfaları +Name[ug]=Unix قوللانما بەتلىرى +Name[uk]=Сторінки довідки UNIX +Name[vi]=Trang hướng dẫn UNIX +Name[wa]=Pådjes di man Unix +Name[x-test]=xxUNIX manual pagesxx +Name[zh_CN]=UNIX 手册页 +Name[zh_TW]=UNIX 手冊 + +X-DocPath=man:/ + +Icon=application-x-troff-man + +X-DOC-Weight=500 +X-DOC-DocumentType=text/man +X-DOC-Identifier=manpages diff --git a/khelpcenter/plugins/Manpages/CMakeLists.txt b/khelpcenter/plugins/Manpages/CMakeLists.txt new file mode 100644 index 00000000..e6a7590d --- /dev/null +++ b/khelpcenter/plugins/Manpages/CMakeLists.txt @@ -0,0 +1,3 @@ + +install( FILES .directory man1.desktop man2.desktop man3.desktop man4.desktop man5.desktop man6.desktop man7.desktop man8.desktop DESTINATION ${DATA_INSTALL_DIR}/khelpcenter/plugins/Manpages ) + diff --git a/khelpcenter/plugins/Manpages/man1.desktop b/khelpcenter/plugins/Manpages/man1.desktop new file mode 100644 index 00000000..1ef4799c --- /dev/null +++ b/khelpcenter/plugins/Manpages/man1.desktop @@ -0,0 +1,94 @@ +[Desktop Entry] +Name=(1) User Commands +Name[af]=(1) Gebruikerbevele +Name[ar]=(1) أوامر المستخدم +Name[ast]=(1) Órdenes d'usuariu +Name[be]=(1) Каманды карыстальніка +Name[be@latin]=(1) Zahady karystańnika +Name[bg]=(1) Потребителски команди +Name[bn]=(1) User Commands +Name[bn_IN]=(১) ব্যবহারকারীদের জন্য উপলব্ধ কমান্ড +Name[br]=(1) Urzhiadoù arveriad +Name[bs]=(1) Korisničke naredbe +Name[ca]=(1) Ordres d'usuari +Name[ca@valencia]=(1) Ordes d'usuari +Name[cs]=(1) Uživatelské příkazy +Name[csb]=(1) Pòlét brëkòwnika +Name[cy]=(1) Gorchmynion Defnyddiwr +Name[da]=(1) Brugerkommandoer +Name[de]=(1) Benutzerbefehle +Name[el]=(1) Εντολές χρήστη +Name[en_GB]=(1) User Commands +Name[eo]=(1) Uzantkomandoj +Name[es]=(1) Órdenes de usuario +Name[et]=(1) Kasutaja käsud +Name[eu]=(1) Erabiltzaile-aginduak +Name[fa]=(۱) فرمانهای کاربر +Name[fi]=(1) Käyttäjän komennot +Name[fr]=(1) Commandes utilisateur +Name[fy]=(1) Brûkerskommando's +Name[ga]=(1) Orduithe Úsáideora +Name[gl]=(1) Ordes do usuario +Name[gu]=(૧) વપરાશકર્તા આદેશો +Name[he]=פקודות משתמש (1) +Name[hi]=(1) उपयोक्ता कमांड +Name[hne]=(1) कमइया कमांड +Name[hr]=(1) Korisničke naredbe +Name[hsb]=(1) Přikazy za wužiwarja +Name[hu]=(1) Felhasználói parancsok +Name[ia]=(1) Commandos de usator +Name[id]=(1) Perintah Pengguna +Name[is]=(1) Notandaskipanir +Name[it]=(1) Comandi dell'utente +Name[ja]=(1) ユーザコマンド +Name[ka]=(1) მომხმარებლის ბრძანებები +Name[kk]=(1) Пайдаланушы командалар +Name[km]=(១) ពាក្យ​បញ្ជា​របស់​អ្នក​ប្រើ +Name[kn]=(೧) ಬಳಕೆದಾರ ಆದೇಶಗಳು +Name[ko]=(1) 사용자 명령 +Name[ku]=(1) Fermanên Bikarhêneran +Name[lt]=(1) Naudotojo komandos +Name[lv]=(1) Lietotāja komandas +Name[mai]=(1) प्रयोक्ता कमांड +Name[mk]=(1) Кориснички команди +Name[ml]=(1) ഉപയോക്താവിനുള്ള ആജ്ഞകള്‍ +Name[mr]=(1) वापरकर्ता आदेश +Name[ms]=(1) Arahan Pengguna +Name[nb]=(1) Brukerkommandoer +Name[nds]=(1) Brukerbefehlen +Name[ne]=(१) प्रयोगकर्ता आदेश +Name[nl]=(1) Gebruikercommando's +Name[nn]=(1) Brukarkommandoar +Name[oc]=(1) Comandas personalizadas +Name[or]=(1) ଚାଳକ ନିର୍ଦ୍ଦେଶଗୁଡ଼ିକ +Name[pa]=(1) ਯੂਜ਼ਰ ਕਮਾਡਾਂ +Name[pl]=(1) Polecenia użytkownika +Name[pt]=(1) Comandos do Utilizador +Name[pt_BR]=(1) Comandos do usuário +Name[ro]=(1) Comenzi utilizator +Name[ru]=(1) Пользовательские команды +Name[se]=(1) Geavaheaddjigohččumat +Name[si]=(1) පරිශීලක විධානය +Name[sk]=(1) Užívateľské príkazy +Name[sl]=(1) Uporabniški ukazi +Name[sr]=(1) Корисничке наредбе +Name[sr@ijekavian]=(1) Корисничке наредбе +Name[sr@ijekavianlatin]=(1) Korisničke naredbe +Name[sr@latin]=(1) Korisničke naredbe +Name[sv]=(1) Användarkommandon +Name[ta]=(1) பயன்படுத்துபவர் கட்டளைகள் +Name[te]=(1) యూజర్ ఆదేశాలు +Name[tg]=(1) Фармонҳои корбар +Name[th]=(1) คำสั่งต่าง ๆ ของผู้ใช้ +Name[tr]=(1) Kullanıcı Komutları +Name[ug]=(1) ئىشلەتكۈچى بۇيرۇقلىرى +Name[uk]=(1) Команди користувача +Name[uz]=(1) Foydalanuvchi uchun buyruqlar +Name[uz@cyrillic]=(1) Фойдаланувчи учун буйруқлар +Name[vi]=(1) Lệnh của người dùng +Name[wa]=(1) Comandes uzeu +Name[x-test]=xx(1) User Commandsxx +Name[zh_CN]=(1) 用户命令 +Name[zh_TW]=(1) 使用者命令 + +X-DocPath=man:/(1) diff --git a/khelpcenter/plugins/Manpages/man2.desktop b/khelpcenter/plugins/Manpages/man2.desktop new file mode 100644 index 00000000..85538e2b --- /dev/null +++ b/khelpcenter/plugins/Manpages/man2.desktop @@ -0,0 +1,94 @@ +[Desktop Entry] +Name=(2) System Calls +Name[af]=(2) Stelselroepe +Name[ar]=(2) استدعاءات النظام +Name[ast]=(2) Llamaes del sistema +Name[be]=(2) Сістэмныя выклікі +Name[be@latin]=(2) Systemnyja vykliki +Name[bg]=(2) Системни сигнали +Name[bn]=(2) সিস্টেম কল +Name[bn_IN]=(২) সিস্টেম কল +Name[br]=(3) Galvioù reizhiad +Name[bs]=(2) Sistemski pozivi +Name[ca]=(2) Crides del sistema +Name[ca@valencia]=(2) Crides del sistema +Name[cs]=(2) Systémová volání +Name[csb]=(2) Systemòwé fùnkcëje +Name[cy]=(2) Galwadau Cysawd +Name[da]=(2) Systemkald +Name[de]=(2) Systemaufrufe +Name[el]=(2) Κλήσεις συστήματος +Name[en_GB]=(2) System Calls +Name[eo]=(2) Sistemaj vokoj +Name[es]=(2) Llamadas del sistema +Name[et]=(2) Süsteemsed väljakutsed +Name[eu]=(2) Sistema-deiak +Name[fa]=(۲) فراخوانیهای سیستم +Name[fi]=(2) Järjestelmäkutsut +Name[fr]=(2) Appels système +Name[fy]=(2) Systeemoanroppen +Name[ga]=(2) Glaonna ar an chóras +Name[gl]=(2) Chamadas do sistema +Name[gu]=(૨) સિસ્ટમ કૉલ્સ +Name[he]=קריאות מערכת (2) +Name[hi]=(2) सिस्टम काल्स +Name[hne]=(2) सिसटम काल्स +Name[hr]=(2) Sistemski pozivi +Name[hsb]=(2) Systemowe přikazy +Name[hu]=(2) Rendszerhívások +Name[ia]=(2) Appellos de Systema (System Calls) +Name[id]=(2) Panggilan Sistem +Name[is]=(2) Kerfisköll +Name[it]=(2) Chiamate di sistema +Name[ja]=(2) システムコール +Name[ka]=(2) სისტემური გამოძახებები +Name[kk]=(2) Жүйелік шақырулар +Name[km]=(២) ការ​ហៅ​ប្រព័ន្ធ +Name[kn]=(೨) ವ್ಯವಸ್ಥಾ ಕರೆಗಳು +Name[ko]=(2) 시스템 콜 +Name[ku]=(2) Bangên Pergalê +Name[lt]=(2) Sisteminiai iškvietimai +Name[lv]=(2) Sistēmas izsaukumi +Name[mai]=(2) सिस्टम काल्स +Name[mk]=(2) Системски повици +Name[ml]=(2) സിസ്റ്റം കോളുകള്‍ +Name[mr]=(2) सिस्टम कॉल्स +Name[ms]=(2) Panggilan Sistem +Name[nb]=(2) Systemkall +Name[nds]=(2) Systeemoprööp +Name[ne]=(२) प्रणाली कल +Name[nl]=(2) Systeemaanroepen +Name[nn]=(2) Systemkall +Name[oc]=(2) Apèls sistèma +Name[or]=(2) ତନ୍ତ୍ର ଡ଼ାକରା +Name[pa]=(2) ਸਿਸਟਮ ਕਾਲਾਂ +Name[pl]=(2) Wywołania systemowe +Name[pt]=(2) Chamadas do Sistema +Name[pt_BR]=(2) Chamadas de sistema +Name[ro]=(2) Apeluri de sistem +Name[ru]=(2) Системные вызовы +Name[se]=(2) Vuogádatgohččumat +Name[si]=(2) පද්ධතිය ඇමතුම් +Name[sk]=(2) Systémové volania +Name[sl]=(2) Sistemski klici +Name[sr]=(2) Системски позиви +Name[sr@ijekavian]=(2) Системски позиви +Name[sr@ijekavianlatin]=(2) Sistemski pozivi +Name[sr@latin]=(2) Sistemski pozivi +Name[sv]=(2) Systemanrop +Name[ta]=(2) கணினி அழைப்புகள் +Name[te]=(2) వ్యవస్థ కాల్స్ +Name[tg]=(2) Зангҳои система +Name[th]=(2) คำสั่งต่าง ๆ ของระบบ +Name[tr]=(2) Sistem Çağrıları +Name[ug]=(2) سىستېما چاقىرىشلىرى +Name[uk]=(2) Системні виклики +Name[uz]=(2) Tizim chaqiruvlari +Name[uz@cyrillic]=(2) Тизим чақирувлари +Name[vi]=(2) Lệnh gọi hệ thống +Name[wa]=(2) Houcaedjes sistinme +Name[x-test]=xx(2) System Callsxx +Name[zh_CN]=(2) 系统调用 +Name[zh_TW]=(2) 系統呼叫 + +X-DocPath=man:/(2) diff --git a/khelpcenter/plugins/Manpages/man3.desktop b/khelpcenter/plugins/Manpages/man3.desktop new file mode 100644 index 00000000..bcf2e035 --- /dev/null +++ b/khelpcenter/plugins/Manpages/man3.desktop @@ -0,0 +1,92 @@ +[Desktop Entry] +Name=(3) Subroutines +Name[af]=(3) Subroetines +Name[ar]=(3) الوظائف الفرعية +Name[ast]=(3) Subrutines +Name[be]=(3) Падпраграмы +Name[be@latin]=(3) Padpracedury +Name[bg]=(3) Подпрограми +Name[bn]=(3) সাবরুটিন +Name[bn_IN]=(৩) সাব-রুটিন +Name[br]=(3) Isroudennadoù +Name[bs]=(3) Potprogrami +Name[ca]=(3) Subrutines +Name[ca@valencia]=(3) Subrutines +Name[cs]=(3) Funkce +Name[csb]=(3) Pòdprogramë +Name[cy]=(3) Is-reolweithiau +Name[da]=(3) Subrutiner +Name[de]=(3) Funktionsaufrufe +Name[el]=(3) Υπορουτίνες +Name[en_GB]=(3) Subroutines +Name[eo]=(3) Proceduroj +Name[es]=(3) Subrutinas +Name[et]=(3) Alamfunktsioonid +Name[eu]=(3) Azpirrutinak +Name[fa]=(۳) زیرروالها +Name[fi]=(3) Aliohjelmat +Name[fr]=(3) Sous-programmes +Name[fy]=(3) Subroutines +Name[ga]=(3) Foghnáthaimh +Name[gl]=(3) Subrutinas +Name[gu]=(૩) સબરૂટિનો +Name[he]=תת־שגרות (3) +Name[hi]=(3) सबरूटीन्स +Name[hne]=(3) सबरूटीन्स +Name[hr]=(3) Pod-rutine +Name[hsb]=(3) Subrutiny +Name[hu]=(3) Eljárások +Name[ia]=(3) Subroutines +Name[id]=(3) Subrutin +Name[is]=(3) Stefjur +Name[it]=(3) Procedure +Name[ja]=(3) サブルーチン +Name[ka]=(3) პროცედურები +Name[kk]=(3) Процедуралар +Name[km]=(៣) ទម្រង់ការ​រង +Name[kn]=(೩) ಆಂಶಿಕಕ್ರಮವಿಧಿ (ಸಬ್ರೊಟೀನ್) +Name[ko]=(3) 서브루틴 +Name[ku]=(3) Rûtînên Binî +Name[lt]=(3) Paprogramės +Name[lv]=(3) Subrutīnas +Name[mai]=(3) सबरूटीन्स +Name[mk]=(3) Потпрограми +Name[ml]=(3) സബ്റൂട്ടീനുകള്‍ +Name[mr]=(3) सबरूटीन्स +Name[ms]=(3) Subrutin +Name[nb]=(3) Delrutiner +Name[nds]=(3) Funkschonen +Name[ne]=(३) सहायक कार्यतालिका +Name[nl]=(3) Subroutines +Name[nn]=(3) Subrutinar +Name[or]=(3) Subroutines +Name[pa]=(3) ਸਬ-ਰੂਟੀਨ +Name[pl]=(3) Podprogramy +Name[pt]=(3) Sub-rotinas +Name[pt_BR]=(3) Sub-rotinas +Name[ro]=(3) Subrutine +Name[ru]=(3) Процедуры +Name[se]=(3) Vuollerutiinnat +Name[si]=(3) උප රූටිනය +Name[sk]=(3) Podprogramy +Name[sl]=(3) Podprogrami +Name[sr]=(3) Потпрограми +Name[sr@ijekavian]=(3) Потпрограми +Name[sr@ijekavianlatin]=(3) Potprogrami +Name[sr@latin]=(3) Potprogrami +Name[sv]=(3) Subrutiner +Name[ta]=(3)மற்ற நடைமுறைகள் +Name[te]=(3) సబ్ రొటిన్లు +Name[tg]=(3) Зербарномаҳо +Name[th]=(3) รูทีนย่อยต่าง ๆ +Name[tr]=(3) Alt Yordamlar +Name[ug]=(3) تارماق جەريان +Name[uk]=(3) Підпрограми +Name[vi]=(3) Chương trình con +Name[wa]=(3) Fonccions di programaedje +Name[xh]=(3) Ulwenzeko rhoqo olusezantsi +Name[x-test]=xx(3) Subroutinesxx +Name[zh_CN]=(3) 子程序 +Name[zh_TW]=(3) 子程式 + +X-DocPath=man:/(3) diff --git a/khelpcenter/plugins/Manpages/man4.desktop b/khelpcenter/plugins/Manpages/man4.desktop new file mode 100644 index 00000000..c53487b7 --- /dev/null +++ b/khelpcenter/plugins/Manpages/man4.desktop @@ -0,0 +1,95 @@ +[Desktop Entry] +Name=(4) Devices +Name[af]=(4) Toestelle +Name[ar]=(4) الأجهزة +Name[ast]=(4) Preseos +Name[be]=(4) Прылады +Name[be@latin]=(4) Pryłady +Name[bg]=(4) Устройства +Name[bn]=(4) ডিভাইস +Name[bn_IN]=(৪) ডিভাইস +Name[br]=(4) Trobarzhelloù +Name[bs]=(4) Uređaji +Name[ca]=(4) Dispositius +Name[ca@valencia]=(4) Dispositius +Name[cs]=(4) Zařízení +Name[csb]=(4) Ùrządzenia +Name[cy]=(4) Dyfeisiau +Name[da]=(4) Enheder +Name[de]=(4) Geräte +Name[el]=(4) Συσκευές +Name[en_GB]=(4) Devices +Name[eo]=(4) Aparatoj +Name[es]=(4) Dispositivos +Name[et]=(4) Seadmed +Name[eu]=(4) Gailuak +Name[fa]=(۴) دستگاهها +Name[fi]=(4) Laitteet +Name[fr]=(4) Périphériques +Name[fy]=(4) Apparaten +Name[ga]=(4) Gléasra +Name[gl]=(4) Dispositivos +Name[gu]=(૪) ઉપકરણો +Name[he]=התקנים (4) +Name[hi]=(4) औज़ार +Name[hne]=(4) उपकरन +Name[hr]=(4) Uređaji +Name[hsb]=(4) Graty +Name[hu]=(4) Eszközök +Name[ia]=(4) Dispositivos +Name[id]=(4) Divais +Name[is]=(4) Tæki +Name[it]=(4) Dispositivi +Name[ja]=(4) デバイス +Name[ka]=(4) მოწყობილობები +Name[kk]=(4) Құрылғылар +Name[km]=(៤) ឧបករណ៍ +Name[kn]=(೪) ಸಾಧನಗಳು +Name[ko]=(4) 장치 +Name[ku]=(4) Cîhaz +Name[lt]=(4) Įrenginiai +Name[lv]=(4) Ierīces +Name[mai]=(4) अओजार +Name[mk]=(4) Уреди +Name[ml]=(4) ഉപകരണങ്ങള്‍ +Name[mr]=(4) साधन +Name[ms]=(4) Peranti +Name[nb]=(4) Enheter +Name[nds]=(4) Reedschappen +Name[ne]=(४) यन्त्र +Name[nl]=(4) Apparaten +Name[nn]=(4) Einingar +Name[oc]=(4) Periferics +Name[or]=(4) ଉପକରଣଗୁଡ଼ିକ +Name[pa]=(4) ਜੰਤਰ +Name[pl]=(4) Urządzenia +Name[pt]=(4) Dispositivos +Name[pt_BR]=(4) Dispositivos +Name[ro]=(4) Dispozitive +Name[ru]=(4) Устройства +Name[se]=(4) Ovttadagat +Name[si]=(4) මෙවලම් +Name[sk]=(4) Zariadenia +Name[sl]=(4) Naprave +Name[sr]=(4) Уређаји +Name[sr@ijekavian]=(4) Уређаји +Name[sr@ijekavianlatin]=(4) Uređaji +Name[sr@latin]=(4) Uređaji +Name[sv]=(4) Enheter +Name[ta]=(4) சாதனங்கள் +Name[te]=(4) పరికరాలు +Name[tg]=(4) Дастгоҳҳо +Name[th]=(4) อุปกรณ์ต่าง ๆ +Name[tr]=(4) Aygıtlar +Name[ug]=(4) ئۈسكۈنە +Name[uk]=(4) Пристрої +Name[uz]=(4) Uskunalar +Name[uz@cyrillic]=(4) Ускуналар +Name[vi]=(4) Thiết bị +Name[wa]=(4) Éndjins +Name[xh]=(4) Amacebo +Name[x-test]=xx(4) Devicesxx +Name[zh_CN]=(4) 设备 +Name[zh_TW]=(4) 裝置 + +X-DocPath=man:/(4) diff --git a/khelpcenter/plugins/Manpages/man5.desktop b/khelpcenter/plugins/Manpages/man5.desktop new file mode 100644 index 00000000..b9bac793 --- /dev/null +++ b/khelpcenter/plugins/Manpages/man5.desktop @@ -0,0 +1,95 @@ +[Desktop Entry] +Name=(5) File Formats +Name[af]=(5) Lêerformate +Name[ar]=(5) صيغ الملفات +Name[ast]=(5) Formatos de ficheros +Name[be]=(5) Фарматы файлаў +Name[be@latin]=(5) Farmaty fajłaŭ +Name[bg]=(5) Файлови формати +Name[bn]=(5) ফাইল ফরম্যাট +Name[bn_IN]=(৫) ফাইলের বিন্যাস +Name[br]=(5) Furmadoù ar restroù +Name[bs]=(5) Formati datoteka +Name[ca]=(5) Formats de fitxers +Name[ca@valencia]=(5) Formats de fitxers +Name[cs]=(5) Datové formáty +Name[csb]=(5) Fòrmatë lopków +Name[cy]=(5) Fformatau Ffeil +Name[da]=(5) Filformater +Name[de]=(5) Dateiformate +Name[el]=(5) Μορφές αρχείων +Name[en_GB]=(5) File Formats +Name[eo]=(5) Dosieraranĝoj +Name[es]=(5) Formatos de archivos +Name[et]=(5) Failivormingud +Name[eu]=(5) Fitxategi-formatuak +Name[fa]=(۵) قالبهای پرونده +Name[fi]=(5) Tiedostomuodot +Name[fr]=(5) Formats de fichiers +Name[fy]=(5) Triemopmaak +Name[ga]=(5) Formáidí Comhaid +Name[gl]=(5) Formatos de ficheiro +Name[gu]=(૫) ફાઇલ બંધારણો +Name[he]=תבניות קבצים (5) +Name[hi]=(5) फ़ाइल फार्मेट्स +Name[hne]=(5) फाइल फार्मेट्स +Name[hr]=(5) Oblici datoteka +Name[hsb]=(5) Datajowe formaty +Name[hu]=(5) Fájlformátumok +Name[ia]=(5) Formatos de File +Name[id]=(5) Format Berkas +Name[is]=(5) Skráasnið +Name[it]=(5) Formati di file +Name[ja]=(5) ファイルフォーマット +Name[ka]=(5) ფაილთა ფორმატები +Name[kk]=(5) Файл пішімдері +Name[km]=(៥) ទ្រង់ទ្រាយ​ឯកសារ +Name[kn]=(೫)ಕಡತ ಕ್ರಮವ್ಯವಸ್ಥೆ (ಫಾರ್ಮಾಟ್) +Name[ko]=(5) 파일 형식 +Name[ku]=(5) Formatên Pelan +Name[lt]=(5) Failų formatai +Name[lv]=(5) Failu formāti +Name[mai]=(5) फाइल फार्मेट्स +Name[mk]=(5) Формати на датотеки +Name[ml]=(5) ഫയല്‍ ഫോര്‍മാറ്റുകള്‍ +Name[mr]=(5) फाईल फार्मेट्स +Name[ms]=(5) Format Fail +Name[nb]=(5) Filformat +Name[nds]=(5) Dateiformaten +Name[ne]=(५) फाइल ढाँचा +Name[nl]=(5) Bestandsformaten +Name[nn]=(5) Filformat +Name[oc]=(5) Formats de fichièrs +Name[or]=(5) ଫାଇଲ ଶୈଳୀଗୁଡ଼ିକ +Name[pa]=(5) ਫਾਇਲ ਫਾਰਮੈਟ +Name[pl]=(5) Formaty plików +Name[pt]=(5) Formatos de Ficheiros +Name[pt_BR]=(5) Formatos de arquivo +Name[ro]=(5) Formate de fișiere +Name[ru]=(5) Форматы файлов +Name[se]=(5) Fiilaformáhtat +Name[si]=(5) ගොනු සංයුති +Name[sk]=(5) Formáty súborov +Name[sl]=(5) Vrste datotek +Name[sr]=(5) Формати фајлова +Name[sr@ijekavian]=(5) Формати фајлова +Name[sr@ijekavianlatin]=(5) Formati fajlova +Name[sr@latin]=(5) Formati fajlova +Name[sv]=(5) Filformat +Name[ta]=(5) கோப்பு வடிவமைப்புகள் +Name[te]=(5) దస్త్ర ఫార్మెట్లు +Name[tg]=(5) Намудҳои файл +Name[th]=(5) รูปแบบแฟ้มต่าง ๆ +Name[tr]=(5) Dosya Biçimleri +Name[ug]=(5) ھۆججەت پىچىملىرى +Name[uk]=(5) Формати файлів +Name[uz]=(5) Fayl formatlari +Name[uz@cyrillic]=(5) Файл форматлари +Name[vi]=(5) Định dạng Tập tin +Name[wa]=(5) Sôres di fitchîs +Name[xh]=(5) Ifomati Yeefayile +Name[x-test]=xx(5) File Formatsxx +Name[zh_CN]=(5) 文件格式 +Name[zh_TW]=(5) 檔案格式 + +X-DocPath=man:/(5) diff --git a/khelpcenter/plugins/Manpages/man6.desktop b/khelpcenter/plugins/Manpages/man6.desktop new file mode 100644 index 00000000..e29efdcb --- /dev/null +++ b/khelpcenter/plugins/Manpages/man6.desktop @@ -0,0 +1,95 @@ +[Desktop Entry] +Name=(6) Games +Name[af]=(6) Speletjies +Name[ar]=(6) الألعاب +Name[ast]=(6) Xuegos +Name[be]=(6) Гульні +Name[be@latin]=(6) Hulni +Name[bg]=(6) Игри +Name[bn]=(6) খেলা +Name[bn_IN]=(৬) খেলা +Name[br]=(6) C'hoarioù +Name[bs]=(6) Igre +Name[ca]=(6) Jocs +Name[ca@valencia]=(6) Jocs +Name[cs]=(6) Hry +Name[csb]=(6) Grë +Name[cy]=(6) Gemau +Name[da]=(6) Spil +Name[de]=(6) Spiele +Name[el]=(6) Παιχνίδια +Name[en_GB]=(6) Games +Name[eo]=(6) Ludoj +Name[es]=(6) Juegos +Name[et]=(6) Mängud +Name[eu]=(6) Jokoak +Name[fa]=(۶) بازیها +Name[fi]=(6) Pelit +Name[fr]=(6) Jeux +Name[fy]=(6) Spultsjes +Name[ga]=(6) Cluichí +Name[gl]=(6) Xogos +Name[gu]=(૬) રમતો +Name[he]=משחקים (6) +Name[hi]=(6) खेल +Name[hne]=(6) खेल +Name[hr]=(6) Igre +Name[hsb]=(6) Hry +Name[hu]=(6) Játékok +Name[ia]=(6) Jocos +Name[id]=(6) Permainan +Name[is]=(6) Leikir +Name[it]=(6) Giochi +Name[ja]=(6) ゲーム +Name[ka]=(6) თამაშები +Name[kk]=(6) Ойындар +Name[km]=(៦) ល្បែង +Name[kn]=(೬)ಆಟಗಳು +Name[ko]=(6) 게임 +Name[ku]=(6) Lîstik +Name[lt]=(6) Žaidimai +Name[lv]=(6) Spēles +Name[mai]=(6) खेल +Name[mk]=(6) Игри +Name[ml]=(6) കളികള്‍ +Name[mr]=(6) खेळ +Name[ms]=(6) Permainan +Name[nb]=(6) Spill +Name[nds]=(6) Spelen +Name[ne]=(६) खेल +Name[nl]=(6) Spelletjes +Name[nn]=(6) Spel +Name[oc]=(6) Jòcs +Name[or]=(6) ଖେଳଗୁଡ଼ିକ +Name[pa]=(6) ਖੇਡਾਂ +Name[pl]=(6) Gry +Name[pt]=(6) Jogos +Name[pt_BR]=(6) Jogos +Name[ro]=(6) Jocuri +Name[ru]=(6) Игры +Name[se]=(6) Spealut +Name[si]=(6) ක්‍රීඩා +Name[sk]=(6) Hry +Name[sl]=(6) Igre +Name[sr]=(6) Игре +Name[sr@ijekavian]=(6) Игре +Name[sr@ijekavianlatin]=(6) Igre +Name[sr@latin]=(6) Igre +Name[sv]=(6) Spel +Name[ta]=(6) விளையாட்டுகள் +Name[te]=(6) ఆటలు +Name[tg]=(6) Бозиҳо +Name[th]=(6) เกมต่าง ๆ +Name[tr]=(6) Oyunlar +Name[ug]=(6) ئويۇنلار +Name[uk]=(6) Ігри +Name[uz]=(6) Oʻyinlar +Name[uz@cyrillic]=(6) Ўйинлар +Name[vi]=(6) Trò chơi +Name[wa]=(6) Djeus +Name[xh]=(6) Imidlalo +Name[x-test]=xx(6) Gamesxx +Name[zh_CN]=(6) 游戏 +Name[zh_TW]=(6) 遊戲 + +X-DocPath=man:/(6) diff --git a/khelpcenter/plugins/Manpages/man7.desktop b/khelpcenter/plugins/Manpages/man7.desktop new file mode 100644 index 00000000..b5476714 --- /dev/null +++ b/khelpcenter/plugins/Manpages/man7.desktop @@ -0,0 +1,95 @@ +[Desktop Entry] +Name=(7) Miscellaneous +Name[af]=(7) Allerlei +Name[ar]=(7) متنوع +Name[ast]=(7) Dellos +Name[be]=(7) Рознае +Name[be@latin]=(7) Roznaje +Name[bg]=(7) Разни +Name[bn]=(7) বিবিধ +Name[bn_IN]=(৭) বিবিধ +Name[br]=(7) A bep seurt +Name[bs]=(7) Razno +Name[ca]=(7) Miscel·lània +Name[ca@valencia]=(7) Miscel·lània +Name[cs]=(7) Různé +Name[csb]=(7) Wszelejaczé +Name[cy]=(7) Amrwyiol +Name[da]=(7) Diverse +Name[de]=(7) Verschiedenes +Name[el]=(7) Διάφορα +Name[en_GB]=(7) Miscellaneous +Name[eo]=(7) Diversaĵoj +Name[es]=(7) Varios +Name[et]=(7) Muud +Name[eu]=(7) Beste zenbait +Name[fa]=(۷) متفرقه +Name[fi]=(7) Sekalaista +Name[fr]=(7) Divers +Name[fy]=(7) Ferskate +Name[ga]=(7) Rudaí éagsúla +Name[gl]=(7) Diversas +Name[gu]=(૭) અન્ય +Name[he]=שונות (7) +Name[hi]=(7) विविध +Name[hne]=(7) विविध +Name[hr]=(7) Razno +Name[hsb]=(7) Wšelake +Name[hu]=(7) Egyéb +Name[ia]=(7) Miscellanea +Name[id]=(7) Lain-lain +Name[is]=(7) Ýmislegt +Name[it]=(7) Varie +Name[ja]=(7) その他 +Name[ka]=(7) სხვადასხვა +Name[kk]=(7) Әр түрлі +Name[km]=(៧) ផ្សេងៗ +Name[kn]=(೭) ಇತರೆ +Name[ko]=(7) 기타 +Name[ku]=(7) Cur be cur +Name[lt]=(7) Įvairūs dalykai +Name[lv]=(7) Dažādi +Name[mai]=(7) विविध +Name[mk]=(7) Разно +Name[ml]=(7) പലവക +Name[mr]=(7) किरकोळ +Name[ms]=(7) Pelbagai +Name[nb]=(7) Diverse +Name[nds]=(7) Annerswat +Name[ne]=(७) विविध +Name[nl]=(7) Diversen +Name[nn]=(7) Ymse +Name[oc]=(7) Divèrs +Name[or]=(7) ମିଶ୍ରିତ +Name[pa]=(7) ਫੁਟਕਲ +Name[pl]=(7) Różne +Name[pt]=(7) Diversos +Name[pt_BR]=(7) Diversos +Name[ro]=(7) Diverse +Name[ru]=(7) Разное +Name[se]=(7) Feará mii +Name[si]=(7) විවිධ +Name[sk]=(7) Rôzne +Name[sl]=(7) Razno +Name[sr]=(7) Разно +Name[sr@ijekavian]=(7) Разно +Name[sr@ijekavianlatin]=(7) Razno +Name[sr@latin]=(7) Razno +Name[sv]=(7) Diverse +Name[ta]=(7) மற்ற +Name[te]=(7) ఇతర +Name[tg]=(7) Барномаҳои гуногун +Name[th]=(7) เบ็ดเตล็ด +Name[tr]=(7) Çeşitli +Name[ug]=(7) باشقىلار +Name[uk]=(7) Різне +Name[uz]=(7) Har xil +Name[uz@cyrillic]=(7) Ҳар хил +Name[vi]=(7) Khác +Name[wa]=(7) Totès sôres +Name[xh]=(7) Ezixubeneyo +Name[x-test]=xx(7) Miscellaneousxx +Name[zh_CN]=(7) 杂项 +Name[zh_TW]=(7) 雜項 + +X-DocPath=man:/(7) diff --git a/khelpcenter/plugins/Manpages/man8.desktop b/khelpcenter/plugins/Manpages/man8.desktop new file mode 100644 index 00000000..ce089855 --- /dev/null +++ b/khelpcenter/plugins/Manpages/man8.desktop @@ -0,0 +1,94 @@ +[Desktop Entry] +Name=(8) Sys. Administration +Name[af]=(8) Sys. Administrasie +Name[ar]=(8) إدارة النظام +Name[ast]=(8) Alministración del sistema +Name[be]=(8) Сістэмнае адміністраванне +Name[be@latin]=(8) Systemnaje administravańnie +Name[bg]=(8) Администрация +Name[bn]=(8) সিস্টেম অ্যাডমিনস্ট্রেশন +Name[bn_IN]=(৮) সিস্টেম অ্যাডমিনিস্ট্রেশন +Name[br]=(8) Melestradur ar reizhiad +Name[bs]=(8) Administracija sistema +Name[ca]=(8) Administració del sistema +Name[ca@valencia]=(8) Administració del sistema +Name[cs]=(8) Správa systému +Name[csb]=(8) Sprôwianié systemą +Name[cy]=(8) Gweinyddiaeth Cysawd +Name[da]=(8) Systemadministration +Name[de]=(8) Systemverwaltung +Name[el]=(8) Διαχείριση συστήματος +Name[en_GB]=(8) Sys. Administration +Name[eo]=(8) Sistemadministrado +Name[es]=(8) Administración del sistema +Name[et]=(8) Süsteemi haldamine +Name[eu]=(8) Sist.-administrazioa +Name[fa]=(۸) سرپرستی سیستم +Name[fi]=(8) Järjestelmänhallinta +Name[fr]=(8) Administration système +Name[fy]=(8) Systeembehear +Name[ga]=(8) Riarachán an Chórais +Name[gl]=(8) Administración do sistema +Name[gu]=(૮) સિસ્ટમ સંચાલન +Name[he]=ניהול המערכת (8) +Name[hi]=(8) तंत्र प्रशासन +Name[hne]=(8) तंत्र प्रसासन +Name[hr]=(8) Administracija sustava +Name[hsb]=(8) Zarjadowanje systema +Name[hu]=(8) Rendszeradminisztráció +Name[ia]=(8) Sys. Administration +Name[id]=(8) Administrasi Sistem +Name[is]=(8) Kerfisstjórnun +Name[it]=(8) Amministrazione di sistema +Name[ja]=(8) システム管理 +Name[ka]=(8) სისტემური ადმინისტრირება +Name[kk]=(8) Жүйе әкімшілігі +Name[km]=(៨) ការ​គ្រប់គ្រង​ប្រព័ន្ធ +Name[kn]=(೮) ಗಣಕವ್ಯವಸ್ಥೆಯ ನಿರ್ವಹಣೆ +Name[ko]=(8) 시스템 관리 +Name[ku]=(8) Gerînendetiya Pergale +Name[lt]=(8) Sist. administravimas +Name[lv]=(8) Sistēmas administrācija +Name[mai]=(8) तंत्र प्रशासन +Name[mk]=(8) Системска администрација +Name[ml]=(8) സിസ്റ്റത്തിന്റെ ഭരണം +Name[mr]=(8) प्रणाली प्रशासन +Name[ms]=(8) Pentadbiran Sistem +Name[nb]=(8) Systemadministrasjon +Name[nds]=(8) Systeempleeg +Name[ne]=(८) प्रणाली प्रशासन +Name[nl]=(8) Systeembeheer +Name[nn]=(8) Systemadministrasjon +Name[or]=(8) ତନ୍ତ୍ର ପ୍ରଶାସକ +Name[pa]=(8) ਸਿਸਟਮ ਪਰਸ਼ਾਸ਼ਨ +Name[pl]=(8) Administracja systemu +Name[pt]=(8) Administração do Sistema +Name[pt_BR]=(8) Administração do sistema +Name[ro]=(8) Administrare de sistem +Name[ru]=(8) Системное администрирование +Name[se]=(8) Vuogádathálddašeapmi +Name[si]=(8) පද්ධති පරිපාලනය +Name[sk]=(8) Administrácia systému +Name[sl]=(8) Sistemsko skrbništvo +Name[sr]=(8) Администрација система +Name[sr@ijekavian]=(8) Администрација система +Name[sr@ijekavianlatin]=(8) Administracija sistema +Name[sr@latin]=(8) Administracija sistema +Name[sv]=(8) Systemadministration +Name[ta]=(8) கணினி-நிர்வாகம் +Name[te]=(8) వ్యవస్థ నిర్వహణ +Name[tg]=(8) Мудирияти система +Name[th]=(8) ผู้ดูแลระบบ +Name[tr]=(8) Sistem Yönetimi +Name[ug]=(8) سىستېما باشقۇرۇش +Name[uk]=(8) Сист. адміністрування +Name[uz]=(8) Tizimni boshqarish +Name[uz@cyrillic]=(8) Тизимни бошқариш +Name[vi]=(8) Quản trị Hệ thống +Name[wa]=(8) Manaedjmint do sistinme +Name[xh]=(8) Sys. Administration +Name[x-test]=xx(8) Sys. Administrationxx +Name[zh_CN]=(8) 系统管理 +Name[zh_TW]=(8) 系統管理 + +X-DocPath=man:/(8) diff --git a/khelpcenter/plugins/Manpages/man9.desktop b/khelpcenter/plugins/Manpages/man9.desktop new file mode 100644 index 00000000..27e14173 --- /dev/null +++ b/khelpcenter/plugins/Manpages/man9.desktop @@ -0,0 +1,94 @@ +[Desktop Entry] +Name=(9) Kernel +Name[af]=(9) Kern +Name[ar]=(9) النواة +Name[ast]=(9) Nucleu +Name[be]=(9) Ядро +Name[be@latin]=(9) Jadro +Name[bg]=(9) Ядро +Name[bn]=(9) কার্নেল +Name[bn_IN]=(৯) কার্নেল (Kernel) +Name[br]=(9) Kalon +Name[bs]=(9) Kernel +Name[ca]=(9) Nucli +Name[ca@valencia]=(9) Nucli +Name[cs]=(9) Jádro +Name[csb]=(9) Jądro systemë +Name[cy]=(9) Cnewyllen +Name[da]=(9) Kerne +Name[de]=(9) Kernel +Name[el]=(9) Πυρήνας +Name[en_GB]=(9) Kernel +Name[eo]=(9) Kerno +Name[es]=(9) Núcleo +Name[et]=(9) Kernel +Name[eu]=(9) Nukleoa +Name[fa]=(۹) هسته +Name[fi]=(9) Ydin +Name[fr]=(9) Noyau (Kernel) +Name[fy]=(9) Kernel +Name[ga]=(9) Eithne +Name[gl]=(9) Núcleo +Name[gu]=(૯) કર્નલ +Name[he]=גרעין (9) +Name[hi]=(9) कर्नेल +Name[hne]=(9) कर्नेल +Name[hr]=(9) Kernel +Name[hsb]=(9) Kernel +Name[hu]=(9) Kernel +Name[ia]=(9) Kernel +Name[id]=(9) Kernel +Name[is]=(9) Kjarni +Name[it]=(9) Kernel +Name[ja]=(9) カーネル +Name[ka]=(9) ბირთვი +Name[kk]=(9) Өзегі +Name[km]=(៩) ខឺណែល +Name[kn]=(೯) ತಿರುಳು (ಕೆರ್ನಲ್) +Name[ko]=(9) 커널 +Name[ku]=(9) Kernel (Kakîl) +Name[lt]=(9) Branduolys +Name[lv]=(9) Kodols +Name[mai]=(9) कर्नेल +Name[mk]=(9) Кернел +Name[ml]=(9) കെര്‍ണല്‍ +Name[mr]=(9) कर्नल +Name[ms]=(9) Kernel +Name[nb]=(9) Kjerne +Name[nds]=(9) Kernel (Karn vun't Bedriefsysteem) +Name[ne]=(९) कर्नेल +Name[nl]=(9) Kernel +Name[nn]=(9) Kjerne +Name[or]=(9) କର୍ଣ୍ଣଲ +Name[pa]=(9) ਕਰਨਲ +Name[pl]=(9) Jądro systemu +Name[pt]=(9) 'Kernel' +Name[pt_BR]=(9) Kernel +Name[ro]=(9) Nucleu +Name[ru]=(9) Ядро +Name[se]=(9) Čoahkku +Name[si]=(9) කර්ණලය +Name[sk]=(9) Kernel +Name[sl]=(9) Jedro +Name[sr]=(9) Кернел +Name[sr@ijekavian]=(9) Кернел +Name[sr@ijekavianlatin]=(9) Kernel +Name[sr@latin]=(9) Kernel +Name[sv]=(9) Kärna +Name[ta]=(9) கெர்னல் +Name[te]=(9) కెర్నెల్ +Name[tg]=(9) Мағзи система +Name[th]=(9) เคอร์เนล +Name[tr]=(9) Çekirdek +Name[ug]=(9) يادروسى +Name[uk]=(9) Ядро +Name[uz]=(9) Kernel +Name[uz@cyrillic]=(9) Кернел +Name[vi]=(9) Hạt nhân +Name[wa]=(9) Fonccions do nawea linux +Name[xh]=(9) Kernel +Name[x-test]=xx(9) Kernelxx +Name[zh_CN]=(9) 内核 +Name[zh_TW]=(9) 核心 + +X-DocPath=man:/(9) diff --git a/khelpcenter/plugins/Manpages/mann.desktop b/khelpcenter/plugins/Manpages/mann.desktop new file mode 100644 index 00000000..c930eea6 --- /dev/null +++ b/khelpcenter/plugins/Manpages/mann.desktop @@ -0,0 +1,94 @@ +[Desktop Entry] +Name=(n) New +Name[af]=(n) Nuwe +Name[ar]=(n) جديد +Name[ast]=(n) Nuevu +Name[be]=(n) Новыя +Name[be@latin]=(n) Novaje +Name[bg]=(n) Нови +Name[bn]=(n) নতুন +Name[bn_IN]=(n) নতুন +Name[br]=(n) Nevez +Name[bs]=(n) Novo +Name[ca]=(n) Nou +Name[ca@valencia]=(n) Nou +Name[cs]=(n) Nové +Name[csb]=(n) Nowé +Name[cy]=(n) Newydd +Name[da]=(n) Ny +Name[de]=(n) Neu +Name[el]=(n) Νέο +Name[en_GB]=(n) New +Name[eo]=(n) Nova +Name[es]=(n) Nuevo +Name[et]=(n) Uus +Name[eu]=(n) Berria +Name[fa]=(n) جدید +Name[fi]=(n) Uudet +Name[fr]=(n) Nouveautés +Name[fy]=(n) Nij +Name[ga]=(n) Nua +Name[gl]=(n) Novo +Name[gu]=(n) નવું +Name[he]=חדש (n) +Name[hi]=(n) नया +Name[hne]=(n) नवा +Name[hr]=(n) Novo +Name[hsb]=(n) Nowe +Name[hu]=(n) Új +Name[ia]=(n) Nove +Name[id]=(n) Baru +Name[is]=(n) Nýtt +Name[it]=(n) Nuovi +Name[ja]=(n) 新規 +Name[ka]=(n) ახალი +Name[kk]=(n) Жаңа +Name[km]=(n) ថ្មី +Name[kn]=(n)ಹೊಸ +Name[ko]=(n) 새로운 항목 +Name[ku]=(n) Nû +Name[lt]=(n) Nauji dalykai +Name[lv]=(n) Jauns +Name[mai]=(n) नवीन +Name[mk]=(n) Нови +Name[ml]=(n) പുതിയ +Name[mr]=(n) नवीन +Name[ms]=(n) Baru +Name[nb]=(n) Ny +Name[nds]=(n) Nieg +Name[ne]=(n) नयाँ +Name[nl]=(n) Nieuw +Name[nn]=(n) Ny +Name[or]=(n) ନୂତନ +Name[pa]=(n) ਨਵਾਂ +Name[pl]=(n) nowe +Name[pt]=(n) Novos +Name[pt_BR]=(n) Novos +Name[ro]=(n) Nou +Name[ru]=(n) Новые +Name[se]=(n) Ođđa +Name[si]=(n) නව +Name[sk]=(n) Nové +Name[sl]=(n) Novo +Name[sr]=(n) Ново +Name[sr@ijekavian]=(n) Ново +Name[sr@ijekavianlatin]=(n) Novo +Name[sr@latin]=(n) Novo +Name[sv]=(n) Ny +Name[ta]=(n) புதிய +Name[te]=(n) కొత్త +Name[tg]=(н) Нав +Name[th]=(n) หมวดใหม่ +Name[tr]=(n) Yeni +Name[ug]=(n) يېڭى +Name[uk]=(n) Нові +Name[uz]=(n) Yangi +Name[uz@cyrillic]=(n) Янги +Name[vi]=(n) Mới +Name[wa]=(n) Noveas +Name[xh]=(n) Entsha +Name[x-test]=xx(n) Newxx +Name[zh_CN]=(n) 新建 +Name[zh_TW]=(n) 新 + +X-DocPath=man:/(n) diff --git a/khelpcenter/plugins/Scrollkeeper/.directory b/khelpcenter/plugins/Scrollkeeper/.directory new file mode 100644 index 00000000..b0cba935 --- /dev/null +++ b/khelpcenter/plugins/Scrollkeeper/.directory @@ -0,0 +1,88 @@ +[Desktop Entry] +Name=Scrollkeeper +Name[af]=Scrollkeeper +Name[ar]=حافظ التمرير +Name[ast]=Scrollkeeper +Name[be]=Scrollkeeper +Name[be@latin]=Scrollkeeper +Name[bg]=Scrollkeeper +Name[bn]=স্ক্রোলকীপার +Name[bn_IN]=স্ক্রোল-কিপার +Name[bs]=Čuvar svitaka +Name[ca]=Scrollkeeper +Name[ca@valencia]=Scrollkeeper +Name[cs]=Scrollkeeper +Name[csb]=Scrollkeeper +Name[da]=Scrollkeeper +Name[de]=Scrollkeeper +Name[el]=Scrollkeeper +Name[en_GB]=Scrollkeeper +Name[es]=Scrollkeeper +Name[et]=Scrollkeeper +Name[eu]=Scrollkeeper +Name[fa]=Scrollkeeper +Name[fi]=Scrollkeeper +Name[fr]=Scrollkeeper +Name[fy]=Skowhâlder +Name[ga]=Scrollkeeper +Name[gl]=Scrollkeeper +Name[gu]=સ્ક્રોલકિપર +Name[he]=Scrollkeeper +Name[hi]=स्क्रॉलकीपर +Name[hne]=स्क्रालकीपर +Name[hr]=Scrollkeeper +Name[hsb]=Scrollkeeper +Name[hu]=Scrollkeeper +Name[ia]=Scrollkeeper (mantenitor de rolo) +Name[id]=Scrollkeeper +Name[is]=Scrollkeeper +Name[it]=Scrollkeeper +Name[ja]=Scrollkeeper +Name[kk]=Scrollkeeper +Name[km]=ឧបករណ៍​រក្សា​រមូរ​ +Name[kn]=ಸುರುಳು ಪಾಲಕ (ಸ್ಕ್ರಾಲ್ ಕೀಪರ್) +Name[ko]=읽을 거리 +Name[ku]=Scrollkeeper +Name[lt]=Scrollkeeper +Name[lv]=Scrollkeeper +Name[mai]=स्क्रालकीपर +Name[mk]=Scrollkeeper +Name[ml]=സ്ക്രോള്‍കീപ്പര്‍ +Name[mr]=स्क्रोलकीपर +Name[nb]=Scrollkeeper +Name[nds]=Scrollkeeper +Name[ne]=स्क्रोलकिपर +Name[nl]=Scrollkeeper +Name[nn]=Scrollkeeper +Name[or]=Scrollkeeper +Name[pa]=ਸਕਰੋਲਕੀਪਰ +Name[pl]=Scrollkeeper +Name[pt]=Scrollkeeper +Name[pt_BR]=Scrollkeeper +Name[ro]=Scrollkeeper +Name[ru]=Scrollkeeper +Name[se]=Scrollkeeper +Name[si]=Scrollkeeper +Name[sk]=Scrollkeeper +Name[sl]=Scrollkeeper +Name[sr]=Чувар свитака +Name[sr@ijekavian]=Чувар свитака +Name[sr@ijekavianlatin]=Čuvar svitaka +Name[sr@latin]=Čuvar svitaka +Name[sv]=Scrollkeeper +Name[ta]=மாற்றுவைப்பு +Name[te]=స్క్రాల్‌కీపర్ +Name[tg]=Дорандаи паймоиш +Name[th]=Scrollkeeper +Name[tr]=Scrollkeeper +Name[ug]=Scrollkeeper +Name[uk]=Scrollkeeper +Name[uz]=Scrollkeeper +Name[uz@cyrillic]=Scrollkeeper +Name[vi]=Scrollkeeper +Name[wa]=Scrollkeeper +Name[x-test]=xxScrollkeeperxx +Name[zh_CN]=Scrollkeeper +Name[zh_TW]=捲軸固定 +Icon=help-contents +X-DOC-Weight=550 diff --git a/khelpcenter/plugins/Scrollkeeper/CMakeLists.txt b/khelpcenter/plugins/Scrollkeeper/CMakeLists.txt new file mode 100644 index 00000000..8026ac97 --- /dev/null +++ b/khelpcenter/plugins/Scrollkeeper/CMakeLists.txt @@ -0,0 +1,2 @@ +install( FILES .directory scrollkeeper.desktop DESTINATION ${DATA_INSTALL_DIR}/khelpcenter/plugins/Scrollkeeper ) + diff --git a/khelpcenter/plugins/Scrollkeeper/scrollkeeper.desktop b/khelpcenter/plugins/Scrollkeeper/scrollkeeper.desktop new file mode 100644 index 00000000..990c4703 --- /dev/null +++ b/khelpcenter/plugins/Scrollkeeper/scrollkeeper.desktop @@ -0,0 +1,2 @@ +[Desktop Entry] +X-KDE-KHelpcenter-Special=scrollkeeper diff --git a/khelpcenter/plugins/browsercontrolmodules.desktop b/khelpcenter/plugins/browsercontrolmodules.desktop new file mode 100644 index 00000000..0a39306e --- /dev/null +++ b/khelpcenter/plugins/browsercontrolmodules.desktop @@ -0,0 +1,48 @@ +[Desktop Entry] +Name=Browser Settings Modules +Name[ar]=مستعرض دليل الإعدادات +Name[ca]=Mòduls de configuració del navegador +Name[ca@valencia]=Mòduls de configuració del navegador +Name[cs]=Moduly nastavení prohlížeče +Name[da]=Moduler til browserindstillinger +Name[de]=Browser-Einstellungsmodule +Name[el]=Αρθρώματα ρυθμίσεων του περιηγητή +Name[en_GB]=Browser Settings Modules +Name[es]=Módulos de preferencias del navegador +Name[et]=Brauseriseadistuste moodulid +Name[eu]=Arakatzaile-ezarpenen moduluak +Name[fa]=مرور پیمانه‌های تنظیمات +Name[fi]=Selaimen asetusosiot +Name[fr]=Modules des paramètres du navigateur +Name[gl]=Módulos de configuración do navegador +Name[hu]=Böngésző beállítási modulok +Name[ia]=Modulos pro navigar inter preferentias +Name[id]=Modul Pengaturan Peramban +Name[is]=Stillingaeiningar vafra +Name[ko]=브라우저 설정 모듈 +Name[nb]=Moduler for nettleser-innstillinger +Name[nds]=Nettkieker-Instellenmodulen +Name[nl]=Modules voor instellingen van de browser +Name[pa]=ਬਰਾਊਜ਼ਰ ਸੈਟਿੰਗ ਮੋਡੀਊਲ +Name[pl]=Moduły ustawień przeglądarki +Name[pt]=Módulos de Configuração do Navegador +Name[pt_BR]=Módulos de configuração do Navegador +Name[ru]=Модули настроек браузера +Name[sk]=Moduly nastavení prehliadača +Name[sl]=Moduli nastavitev brskalnika +Name[sr]=Модули поставки прегледача +Name[sr@ijekavian]=Модули поставки прегледача +Name[sr@ijekavianlatin]=Moduli postavki pregledača +Name[sr@latin]=Moduli postavki pregledača +Name[sv]=Inställningsmoduler för webbläsare +Name[tr]=Tarayıcı Ayar Modülleri +Name[uk]=Модулі параметрів перегляду інтернету +Name[x-test]=xxBrowser Settings Modulesxx +Name[zh_CN]=浏览器设置模块 +Name[zh_TW]=瀏覽器設定模組 + +Icon=preferences-system + +X-DOC-Weight=370 + +X-KDE-KHelpcenter-Special=browsercontrol diff --git a/khelpcenter/plugins/filemanagercontrolmodules.desktop b/khelpcenter/plugins/filemanagercontrolmodules.desktop new file mode 100644 index 00000000..ea804506 --- /dev/null +++ b/khelpcenter/plugins/filemanagercontrolmodules.desktop @@ -0,0 +1,48 @@ +[Desktop Entry] +Name=Filemanager Settings Modules +Name[ar]=نماذج إعدادات مدير الملفات +Name[ca]=Mòduls de configuració del gestor de fitxers +Name[ca@valencia]=Mòduls de configuració del gestor de fitxers +Name[cs]=Moduly nastavení správce souborů +Name[da]=Moduler til filhåndteringindstillinger +Name[de]=Dateiverwaltungs-Einstellungsmodule +Name[el]=Αρθρώματα ρυθμίσεων του διαχειριστή αρχείων +Name[en_GB]=Filemanager Settings Modules +Name[es]=Módulos de preferencias del gestor de archivos +Name[et]=Failihalduri seadistuste moodulid +Name[eu]=Fitxategi-kudeatzaile-ezarpenen moduluak +Name[fa]=پیمانه‌های تنظیمات مدیر پرونده +Name[fi]=Tiedostonhallinnan asetusosiot +Name[fr]=Modules des paramètres du gestionnaire de fichiers +Name[gl]=Módulos de configuración do xestor de ficheiros +Name[hu]=Fájlkezelő beállítási modulok +Name[ia]=Modulos de Preferentias de gerente de file +Name[id]=Modul Pengaturan Manajer Berkas +Name[is]=Stillingaeiningar skráastjóra +Name[ko]=파일 관리자 설정 모듈 +Name[nb]=Moduler for filbehandler-innstillinger +Name[nds]=Dateipleger-Instellenmodulen +Name[nl]=Modules voor instellingen van de bestandsbeheerder +Name[pa]=ਫਾਇਲ-ਮੈਨੇਜਰ ਸੈਟਿੰਗ ਮੋਡੀਊਲ +Name[pl]=Moduły ustawień przeglądarki plików +Name[pt]=Módulos de Configuração do Gestor de Ficheiros +Name[pt_BR]=Módulos de configuração do Gerenciador de Arquivos +Name[ru]=Модули настроек диспетчера файлов +Name[sk]=Moduly nastavení správcu súborov +Name[sl]=Moduli nastavitev upravljalnika datotek +Name[sr]=Модули поставки менаџера фајлова +Name[sr@ijekavian]=Модули поставки менаџера фајлова +Name[sr@ijekavianlatin]=Moduli postavki menadžera fajlova +Name[sr@latin]=Moduli postavki menadžera fajlova +Name[sv]=Inställningsmoduler för filhanterare +Name[tr]=Dosya Yönetici Ayar Modülleri +Name[uk]=Модулі параметрів керування файлами +Name[x-test]=xxFilemanager Settings Modulesxx +Name[zh_CN]=文件管理器设置模块 +Name[zh_TW]=檔案管理員設定模組 + +Icon=preferences-system + +X-DOC-Weight=350 + +X-KDE-KHelpcenter-Special=filemanagercontrol diff --git a/khelpcenter/plugins/fundamentals.desktop b/khelpcenter/plugins/fundamentals.desktop new file mode 100644 index 00000000..cf9526c5 --- /dev/null +++ b/khelpcenter/plugins/fundamentals.desktop @@ -0,0 +1,61 @@ +[Desktop Entry] +X-DocPath=help:/fundamentals/index.html +Icon=system-help +Name=KDE Fundamentals +Name[ar]=أساسيات كدي +Name[bg]=Основи на KDE +Name[bn]=কে.ডি.ই. ফান্ডামেন্টালস +Name[bs]=KDE osnove +Name[ca]=Fonaments del KDE +Name[ca@valencia]=Fonaments del KDE +Name[cs]=Základy KDE +Name[da]=KDE Fundamentals +Name[de]=KDE-Grundlagen +Name[el]=Βασικές αρχές του KDE +Name[en_GB]=KDE Fundamentals +Name[eo]=Bazoj de KDE +Name[es]=Fundamentos de KDE +Name[et]=KDE põhialused +Name[eu]=KDEren oinarriak +Name[fa]=اصول کی‌دی‌ای +Name[fi]=KDE:n perusasiat +Name[fr]=Fondamentaux de KDE +Name[ga]=Uraiceacht KDE +Name[gl]=Esenciais de KDE +Name[gu]=KDE મૂળભૂતો +Name[he]=יסודות של KDE +Name[hi]=केडीई मूल +Name[hu]=KDE Fundamentals +Name[ia]=Fundamentales de KDE +Name[id]=Fundamental KDE +Name[is]=Grunnatriði KDE +Name[it]=Fondamentali di KDE +Name[kk]=KDE негіздері +Name[km]=មូលដ្ឋាន KDE +Name[ko]=KDE 기반 +Name[lt]=KDE pagrindai +Name[mr]=केडीई मूलतत्त्व +Name[nb]=Grunnleggende KDE +Name[nds]=KDE-Grundlagen +Name[nl]=KDE-fundamentals +Name[nn]=Grunnleggjande KDE +Name[pa]=KDE ਮੂਲ +Name[pl]=Fundamenty KDE +Name[pt]=Fundamentos do KDE +Name[pt_BR]=Fundamentos do KDE +Name[ro]=Noțiuni de bază KDE +Name[ru]=Основы KDE +Name[sk]=KDE princípy +Name[sl]=Osnove KDE-ja +Name[sr]=Основе КДЕ‑а +Name[sr@ijekavian]=Основе КДЕ‑а +Name[sr@ijekavianlatin]=Osnove KDE‑a +Name[sr@latin]=Osnove KDE‑a +Name[sv]=KDE:s grunder +Name[tr]=Temel KDE Bilgileri +Name[ug]=ك د ئې(KDE) ئاساسلىرى +Name[uk]=Основи KDE +Name[wa]=Soûmints di KDE +Name[x-test]=xxKDE Fundamentalsxx +Name[zh_CN]=KDE 基础 +Name[zh_TW]=KDE 基礎 diff --git a/khelpcenter/plugins/info.desktop b/khelpcenter/plugins/info.desktop new file mode 100644 index 00000000..2bb89212 --- /dev/null +++ b/khelpcenter/plugins/info.desktop @@ -0,0 +1,98 @@ +[Desktop Entry] +Name=Browse Info Pages +Name[af]=Blaai deur inligting bladsye (Info pages) +Name[ar]=تصفح صفحات المعلومات +Name[ast]=Restolar pente páxines d'info +Name[be]=Праглядзець старонкі info +Name[be@latin]=Hartańnie infarmacyjnych staronak („info”) +Name[bg]=Преглед на страниците с информация +Name[bn]=ইনফো পেজ ব্রাউজ করুন +Name[bn_IN]=Info পেজ পরিদর্শন করুন +Name[br]=Furchal ar pajennoù titouroù +Name[bs]=Pregledanje info stranica +Name[ca]=Navega per les pàgines Info +Name[ca@valencia]=Navega per les pàgines Info +Name[cs]=Prohlížeč info stránek +Name[csb]=Przezéranié wëdowiédnëch starnów +Name[cy]=Pori Tudalennau Info +Name[da]=Gennemse infosider +Name[de]=Infoseiten durchsehen +Name[el]=Περιήγηση στις σελίδες info +Name[en_GB]=Browse Info Pages +Name[eo]=Foliumi informopaĝojn +Name[es]=Examinar páginas info +Name[et]=Infolehekülgede lehitsemine +Name[eu]=Arakatu informazio-orriak +Name[fa]=مرور صفحات اطلاعات +Name[fi]=Selaa info-sivuja +Name[fr]=Naviguer dans les pages d'informations +Name[fy]=ynfo-siden trochblêdzje +Name[ga]=Brabhsáil Leathanaigh Eolais +Name[gl]=Navegar polas páxinas info +Name[gu]=માહિતી પાનાંઓ જુઓ +Name[he]=עיון בדפי מידע +Name[hi]=इन्फो पृष्ठ ब्राउज़ करें +Name[hne]=इन्फो पेज ब्राउज करव +Name[hr]=Pretraživanje info stranica +Name[hsb]=Informaciske strony přelistować +Name[hu]=Info oldalak +Name[ia]=Naviga in le paginas de info +Name[id]=Ramban Halaman Info +Name[is]=Flakka um upplýsingasíður +Name[it]=Sfoglia le pagine «info» +Name[ja]=Info ページの参照 +Name[ka]=ცნობარის დათვალიერება +Name[kk]=Info парақтары +Name[km]=រុករក​ទំព័រ​ព័ត៌មាន +Name[kn]=ಮಾಹಿತಿ ಪುಟಗಳನ್ನು ವೀಕ್ಷಿಸು +Name[ko]=Info 페이지 탐색 +Name[ku]=Rûpelên Agahiyan Veke +Name[lt]=Naršyti info puslapius +Name[lv]=Pārlūkot info lapas +Name[mai]=इन्फो पृष्ठ ब्राउज करू +Name[mk]=Прелистај ги info страниците +Name[ml]=ഇന്‍ഫൊ പേജുകള്‍ പരതുക +Name[mr]=इन्फो पान ब्राउज करा +Name[ms]=Layar Halaman Maklumat +Name[nb]=Les info-sider +Name[nds]=Info-Sieden dörkieken +Name[ne]=सूचना पृष्ठ ब्राउज गर्नुहोस् +Name[nl]=Info-pagina's doorbladeren +Name[nn]=Les info-sider +Name[or]=ବ୍ରାଉଜ ସୂଚନା ପୃଷ୍ଠାଗୁଡ଼ିକ +Name[pa]=ਜਾਣਕਾਰੀ ਸਫੇ ਝਲਕ +Name[pl]=Przeglądanie stron informacyjnych +Name[pt]=Navegar nas Páginas do Info +Name[pt_BR]=Páginas de navegação no Info +Name[ro]=Pagini info +Name[ru]=Страницы Info +Name[se]=Loga info-siidduid +Name[si]=තොරතුරු පිටුව ගවේශනය +Name[sk]=Prehliadanie info stránok +Name[sl]=Brskanje po straneh info +Name[sr]=Прегледање инфо страница +Name[sr@ijekavian]=Прегледање инфо страница +Name[sr@ijekavianlatin]=Pregledanje info stranica +Name[sr@latin]=Pregledanje info stranica +Name[sv]=Bläddra i info-sidor +Name[ta]=தகவல் பக்கங்களில் உலாவவும் +Name[te]=info పుటలను అన్వేషించు +Name[tg]=Намоиши саҳифаҳои маълумот +Name[th]=เรียกดูหน้าข้อมูล (info) +Name[tr]=Bilgi Sayfalarını Tara +Name[ug]=ئۇچۇر بېتىنى كۆرۈش +Name[uk]=Перегляд сторінок info +Name[uz]=Info varaqlarni koʻrish +Name[uz@cyrillic]=Info варақларни кўриш +Name[vi]=Duyệt Trang Thông tin +Name[wa]=Foyter les pådjes info +Name[x-test]=xxBrowse Info Pagesxx +Name[zh_CN]=浏览信息页面 +Name[zh_TW]=瀏覽資訊頁 +Icon=help-contents + +X-KDE-KHelpcenter-Special=info + +X-DocPath=info:/dir + +X-DOC-Weight=700 diff --git a/khelpcenter/plugins/kcontrolmodules.desktop b/khelpcenter/plugins/kcontrolmodules.desktop new file mode 100644 index 00000000..aaed0a63 --- /dev/null +++ b/khelpcenter/plugins/kcontrolmodules.desktop @@ -0,0 +1,48 @@ +[Desktop Entry] +Name=System Settings Modules +Name[ar]=نماذج إعدادات النظام +Name[ca]=Mòduls de configuració del sistema +Name[ca@valencia]=Mòduls de configuració del sistema +Name[cs]=Moduly nastavení systému +Name[da]=Moduler til Systemindstillinger +Name[de]=Systemeinstellungen-Module +Name[el]=Αρθρώματα ρυθμίσεων του συστήματος +Name[en_GB]=System Settings Modules +Name[es]=Módulos de preferencias del sistema +Name[et]=Süsteemi seadistuste moodulid +Name[eu]=Sistema-ezarpenen moduluak +Name[fa]=پیمانه‌های تنظیمات سیستم +Name[fi]=Järjestelmäasetusosiot +Name[fr]=Modules des paramètres du système +Name[gl]=Módulos de configuración do sistema +Name[hu]=Rendszerbeállítások modulok +Name[ia]=Modulosde Preferentias de Systema +Name[id]=Modul Pengaturan Sistem +Name[is]=Stillingaeiningar kerfis +Name[ko]=시스템 설정 모듈 +Name[nb]=Moduler for systeminnstillinger +Name[nds]=Systeem-Instellenmodulen +Name[nl]=Modules voor systeeminstellingen +Name[pa]=ਸਿਸਟਮ ਸੈਟਿੰਗ ਮੋਡੀਊਲ +Name[pl]=Moduły ustawień systemu +Name[pt]=Módulos de Configuração do Sistema +Name[pt_BR]=Módulos das Configurações do Sistema +Name[ru]=Модули «Параметров системы» +Name[sk]=Moduly nastavení systému +Name[sl]=Moduli sistemskih nastavitev +Name[sr]=Модули системских поставки +Name[sr@ijekavian]=Модули системских поставки +Name[sr@ijekavianlatin]=Moduli sistemskih postavki +Name[sr@latin]=Moduli sistemskih postavki +Name[sv]=Inställningsmoduler för system +Name[tr]=Sistem Ayar Modülleri +Name[uk]=Модулі системних параметрів +Name[x-test]=xxSystem Settings Modulesxx +Name[zh_CN]=系统设置模块 +Name[zh_TW]=系統設定模組 + +Icon=preferences-system + +X-DOC-Weight=300 + +X-KDE-KHelpcenter-Special=kcontrol diff --git a/khelpcenter/plugins/kicmodules.desktop b/khelpcenter/plugins/kicmodules.desktop new file mode 100644 index 00000000..218871cd --- /dev/null +++ b/khelpcenter/plugins/kicmodules.desktop @@ -0,0 +1,98 @@ +[Desktop Entry] +Name=KInfoCenter Modules +Name[af]=K-Inligtingsentrum Modules +Name[ar]=نماذج مركز معلومات كدي +Name[ast]=Módulos del KInfoCenter +Name[be]=Модулі інфармацыйнага цэнтра +Name[be@latin]=Moduli KInfoCenter +Name[bg]=Информационен център +Name[bn]=KInfoCenter মডিউল +Name[bn_IN]=KInfoCenter মডিউল +Name[br]=Molladoù KInfoCenter +Name[bs]=Moduli K‑infocentra +Name[ca]=Mòduls del KInfoCenter +Name[ca@valencia]=Mòduls del KInfoCenter +Name[cs]=Moduly Informačního centra +Name[csb]=Wëdowiédné mòdułë centróm kòntrolë +Name[cy]=Modiwlau KInfoCenter +Name[da]=KInfoCenter-moduler +Name[de]=Infozentrum-Module +Name[el]=Αρθρώματα KInfoCenter +Name[en_GB]=KInfoCentre Modules +Name[eo]=Moduloj de KInfoCenter +Name[es]=Módulos de KInfoCenter +Name[et]=Infokeskuse moodulid +Name[eu]=KInfoCenter moduluak +Name[fa]=پیمانه‌های KInfoCenter +Name[fi]=KInfoCenter-moduulit +Name[fr]=Modules du centre d'informations +Name[fy]=Ynformaasjesintrummodules +Name[ga]=Modúil KInfoCenter +Name[gl]=Módulos de KInfoCenter +Name[gu]=KInfoCenter મોડ્યુલો +Name[he]=מודולי מרכז המידע +Name[hi]=के-जानकारी-सेंटर मॉड्यूल्स +Name[hne]=के-इनफो-सेंटर माड्यूल्स +Name[hr]=KInfoCenter moduli +Name[hsb]=Module za KInfoCenter +Name[hu]=KInfoCenter-modulok +Name[ia]=Modulos de KInfoCenter +Name[id]=Modul KInfoCenter +Name[is]=Upplýsingaborðseiningar +Name[it]=Moduli del centro d'informazione +Name[ja]=KInfoCenter モジュール +Name[ka]=საინფორმაციო ცენტრის მოდულები +Name[kk]=KInfoCenter модульдері +Name[km]=ម៉ូឌុល KInfoCenter +Name[kn]=ಕೆಇನ್ಫೋಸೆಂಟರ್ ಘಟಕಗಳು +Name[ko]=KInfoCenter 모듈 +Name[ku]=Modulên Navenda KInfo +Name[lt]=KInfoCenter moduliai +Name[lv]=KInfoCenter moduļi +Name[mai]=के-सूचना-सेंटर मोड्यूल्स +Name[mk]=KInfoCenter модули +Name[ml]=കെഇന്‍ഫൊ കേന്ദ്രം മൊഡ്യൂളുകള്‍ +Name[mr]=केमाहितीकेंद्र विभाग +Name[ms]=Modul KInfoCenter +Name[nb]=Infosentermoduler +Name[nds]=Modulen för dat KDE-Infozentrum +Name[ne]=केडीई सूचना केन्द्र मोड्युल +Name[nl]=Informatiecentrummodules +Name[nn]=Infosentermodular +Name[or]=KInfoCenter ଏକକାଂଶଗୁଡ଼ିକ +Name[pa]=ਕੇਜਾਣਕਾਰੀ-ਸੈਂਟਰ ਮੋਡੀਊਲ +Name[pl]=Moduły informacyjne Centrum sterowania +Name[pt]=Módulos do KInfoCenter +Name[pt_BR]=Módulos do centro de informações +Name[ro]=Module Centru de Informații +Name[ru]=Модули «Информации о системе» +Name[se]=Diehtoguovddášmoduvllat +Name[si]=KInfoCenter මොඩියුල +Name[sk]=Moduly pre Informačné centrum +Name[sl]=Moduli Informacijskega središča +Name[sr]=Модули К‑инфоцентра +Name[sr@ijekavian]=Модули К‑инфоцентра +Name[sr@ijekavianlatin]=Moduli K‑infocentra +Name[sr@latin]=Moduli K‑infocentra +Name[sv]=Moduler i Informationscentralen +Name[ta]=கேதகவல் மைய பகுதிகள் +Name[te]=కెసమాచార కేంద్రం మాడ్యూళ్లు +Name[tg]=Модулҳои маркази иттилоотӣ +Name[th]=มอดูลของศูนย์ข้อมูล +Name[tr]=KInfoCenter Modülleri +Name[ug]=KInfoCenter بۆلەكلىرى +Name[uk]=Модулі KInfoCenter +Name[uz]=KInfoCenter modullari +Name[uz@cyrillic]=KInfoCenter модуллари +Name[vi]=Mô-đun Trung tâm Thông tin của KDE +Name[wa]=Modules do cinte d' infôrmåcions di KDE +Name[xh]=Izicatshulwa ze KInfoCenter +Name[x-test]=xxKInfoCenter Modulesxx +Name[zh_CN]=KInfoCenter 模块 +Name[zh_TW]=KInfoCenter 模組 + +Icon=help-contents + +X-DOC-Weight=400 + +X-KDE-KHelpcenter-Special=kinfocenter diff --git a/khelpcenter/plugins/kioslaves.desktop b/khelpcenter/plugins/kioslaves.desktop new file mode 100644 index 00000000..e5456300 --- /dev/null +++ b/khelpcenter/plugins/kioslaves.desktop @@ -0,0 +1,97 @@ +[Desktop Entry] +Name=Kioslaves +Name[af]=Kioslaves +Name[ar]=Kioslaves +Name[ast]=Kioslaves +Name[be]=Kioslaves +Name[be@latin]=Słužby „kioslave” +Name[bg]=Система за вход-изход +Name[bn]=Kioslaves +Name[bn_IN]=Kioslaves +Name[br]=Kioslaves +Name[bs]=U/I zahvati +Name[ca]=Kioslaves +Name[ca@valencia]=Kioslaves +Name[cs]=Pomocné protokoly KDE +Name[csb]=wtëkôczë wéńdzeniô/wińdzeniô +Name[cy]=Kioslaves +Name[da]=Kioslaver +Name[de]=Ein-/Ausgabemodule +Name[el]=Kioslaves +Name[en_GB]=Kioslaves +Name[eo]=Kioslaves +Name[es]=Kioslaves +Name[et]=KIO-moodulid +Name[eu]=Kioslaves +Name[fa]=Kioslaves +Name[fi]=KIO-palvelut +Name[fr]=Modules d'entrées / sorties +Name[fy]=Kioslaves +Name[ga]=Sclábhaithe KIO +Name[gl]=Kioslaves +Name[gu]=Kioslaves +Name[he]=פרוטוקולים +Name[hi]=केआईओ-स्लेव्स +Name[hne]=केआईओ-स्लेव्स +Name[hr]=Kioslaves +Name[hsb]=Kioslaves +Name[hu]=KDE-protokollok +Name[ia]=Kioslaves +Name[id]=Kioslaves +Name[is]=Kioslaves +Name[it]=Kioslave +Name[ja]=Kioslave +Name[ka]=Kioslaves +Name[kk]=Kioslaves +Name[km]=Kioslaves +Name[kn]=ಕಐಓಸ್ಲೇವ್ಸ್ +Name[ko]=KIO 슬레이브 +Name[ku]=Kioslaves +Name[lt]=Kioprotokolai +Name[lv]=KIO vergi +Name[mai]=केआईओ-स्लेव्स +Name[mk]=Kioslaves +Name[ml]=കിയോസ്ലേവുകള്‍ +Name[mr]=Kioslaves +Name[ms]=Kioslaves +Name[nb]=Kioslaver +Name[nds]=In-/Utgaavmodulen +Name[ne]=किओस्लाभ +Name[nl]=Kioslaves +Name[nn]=Kioslavar +Name[oc]=Kioslaves +Name[or]=Kioslaves +Name[pa]=Kioslaves +Name[pl]=Wtyczki wejścia/wyjścia +Name[pt]=Kioslaves +Name[pt_BR]=Kioslaves +Name[ro]=Dispozitive KIO +Name[ru]=Поддержка протоколов +Name[se]=KIO-šlávat +Name[si]=Kioslaves +Name[sk]=Kioslaves +Name[sl]=Kioslaves +Name[sr]=У/И захвати +Name[sr@ijekavian]=У/И захвати +Name[sr@ijekavianlatin]=U/I zahvati +Name[sr@latin]=U/I zahvati +Name[sv]=I/O-slavar +Name[ta]=Kioslaves +Name[te]=కెఐఒ బానిసలు +Name[tg]=Kioslaves +Name[th]=Kioslaves +Name[tr]=Kioslaves +Name[ug]=Kioslaves +Name[uk]=Підлеглі В/В +Name[uz]=Kioslaves +Name[uz@cyrillic]=Kioslaves +Name[vi]=Kioslaves +Name[wa]=Vårlets d' I/R (kioslaves) +Name[x-test]=xxKioslavesxx +Name[zh_CN]=Kioslaves +Name[zh_TW]=Kioslaves +Icon=help-contents + +X-DOC-Weight=500 + +X-KDE-KHelpcenter-Special=kioslave diff --git a/khelpcenter/plugins/konquerorcontrolmodules.desktop b/khelpcenter/plugins/konquerorcontrolmodules.desktop new file mode 100644 index 00000000..94dc8312 --- /dev/null +++ b/khelpcenter/plugins/konquerorcontrolmodules.desktop @@ -0,0 +1,49 @@ +[Desktop Entry] +Name=Konqueror Settings Modules +Name[ar]=نماذج إعدادات كونكيورر +Name[ca]=Mòduls de configuració del Konqueror +Name[ca@valencia]=Mòduls de configuració del Konqueror +Name[cs]=Moduly nastavení Konqueroru +Name[da]=Moduler til Konqueror-indstillinger +Name[de]=Konqueror-Einstellungsmodule +Name[el]=Αρθρώματα ρυθμίσεων του Konqueror +Name[en_GB]=Konqueror Settings Modules +Name[es]=Módulos de preferencias de Konqueror +Name[et]=Konquerori seadistuste moodulid +Name[eu]=Konqueror-ezarpenen moduluak +Name[fa]=پیمانه‌های تنظیمات کانکرر +Name[fi]=Konquerorin asetusosiot +Name[fr]=Modules des paramètres de Konqueror +Name[gl]=Módulos de configuración do Konqueror +Name[hu]=Konqueror beállítási modulok +Name[ia]=Modulos de preferentias de Konqueror +Name[id]=Modul Pengaturan Konqueror +Name[is]=Stillingaeiningar Konqueror +Name[ja]=Konqueror 設定モジュール +Name[ko]=Konqueror 설정 모듈 +Name[nb]=Modulen for Konqueror-innstillinger +Name[nds]=Konqueror-Instellenmodulen +Name[nl]=Modules voor instellingen van Konqueror +Name[pa]=ਕੋਨਕਿਊਰੋਰ ਸੈਟਿੰਗ ਮੋਡੀਊਲ +Name[pl]=Moduły ustawień Konquerora +Name[pt]=Módulos de Configuração do Konqueror +Name[pt_BR]=Módulos de configuração do Konqueror +Name[ru]=Модули настроек Konqueror +Name[sk]=Moduly nastavení Konquerora +Name[sl]=Moduli nastavitev Konquerorja +Name[sr]=Модули К‑освајачевих поставки +Name[sr@ijekavian]=Модули К‑освајачевих поставки +Name[sr@ijekavianlatin]=Moduli K‑osvajačevih postavki +Name[sr@latin]=Moduli K‑osvajačevih postavki +Name[sv]=Inställningsmoduler för Konqueror +Name[tr]=Konqueror Ayar Modülleri +Name[uk]=Модулі параметрів Konqueror +Name[x-test]=xxKonqueror Settings Modulesxx +Name[zh_CN]=Konqueror 设置模块 +Name[zh_TW]=Konqueror 設定模組 + +Icon=preferences-system + +X-DOC-Weight=330 + +X-KDE-KHelpcenter-Special=konquerorcontrol diff --git a/khelpcenter/plugins/onlinehelp.desktop b/khelpcenter/plugins/onlinehelp.desktop new file mode 100644 index 00000000..f4c42c12 --- /dev/null +++ b/khelpcenter/plugins/onlinehelp.desktop @@ -0,0 +1,72 @@ +[Desktop Entry] +Name=Online Help +Name[ar]=مساعدة عبر الإنترنت +Name[ast]=Ayuda en llinia +Name[bg]=Помощ в мрежата +Name[bn]=অনলাইন সহায়তা +Name[bs]=Pomoć na vezi +Name[ca]=Ajuda en línia +Name[ca@valencia]=Ajuda en línia +Name[cs]=Nápověda online +Name[da]=Online hjælp +Name[de]=Online-Hilfe +Name[el]=Βοήθεια στο διαδίκτυο +Name[en_GB]=Online Help +Name[eo]=Reta helpo +Name[es]=Ayuda en línea +Name[et]=Abi +Name[eu]=Lineako laguntza +Name[fa]=کمک برخط +Name[fi]=Online-ohje +Name[fr]=Aide en ligne +Name[ga]=Cabhair Ar Líne +Name[gl]=Axuda con conexión +Name[gu]=ઓનલાઈન મદદ +Name[he]=עזרה מקוונת +Name[hi]=ऑनलाइन सहायक +Name[hr]=Online Pomoć +Name[hu]=Online súgó +Name[ia]=Adjuta in linea +Name[id]=Bantuan Daring +Name[is]=Hjálp á netinu +Name[it]=Aiuto in rete +Name[ja]=オンラインヘルプ +Name[kk]=Интернет анықтамасы +Name[km]=ជំនួយ​លើ​បណ្ដាញ +Name[kn]=ಜಾಲಲಭ್ಯ ನೆರವು +Name[ko]=온라인 도움말 +Name[lt]=Pagalba internete +Name[lv]=Tiešsaistes palīdzība +Name[mai]=आनलाइन मदति +Name[mr]=ऑनलाइन मदत +Name[nb]=Hjelp på nettverket +Name[nds]=Online-Hülp +Name[nl]=Online-hulp +Name[nn]=Hjelp på nettet +Name[pa]=ਆਨਲਾਈਨ ਮੱਦਦ +Name[pl]=Pomoc w sieci +Name[pt]=Ajuda 'Online' +Name[pt_BR]=Ajuda on-line +Name[ro]=Ajutor online +Name[ru]=Справка в Интернете +Name[si]=සබැඳි උදව් +Name[sk]=Online pomocník +Name[sl]=Pomoč na spletu +Name[sr]=Помоћ на вези +Name[sr@ijekavian]=Помоћ на вези +Name[sr@ijekavianlatin]=Pomoć na vezi +Name[sr@latin]=Pomoć na vezi +Name[sv]=Direkthjälp +Name[tg]=Кӯмаки онлайн +Name[th]=ความช่วยเหลือออนไลน์ +Name[tr]=Çevrimiçi Yardım +Name[ug]=توردىكى ياردەم +Name[uk]=Довідка у інтернеті +Name[vi]=Trợ giúp trực tuyến +Name[wa]=Aidance so fyis +Name[x-test]=xxOnline Helpxx +Name[zh_CN]=在线帮助 +Name[zh_TW]=線上說明 +Icon=help-contents +X-DocPath=help:/onlinehelp/index.html +X-DOC-Weight=100 diff --git a/khelpcenter/plugins/othercontrolmodules.desktop b/khelpcenter/plugins/othercontrolmodules.desktop new file mode 100644 index 00000000..958c86dc --- /dev/null +++ b/khelpcenter/plugins/othercontrolmodules.desktop @@ -0,0 +1,48 @@ +[Desktop Entry] +Name=Other Settings Modules +Name[ar]=نماذج إعدادا أخرى +Name[ca]=Altres mòduls de configuració +Name[ca@valencia]=Altres mòduls de configuració +Name[cs]=Moduly nastavení ostatního +Name[da]=Andre indstillingsmoduler +Name[de]=Andere Einstellungsmodule +Name[el]=Λοιπά αρθρώματα ρυθμίσεων +Name[en_GB]=Other Settings Modules +Name[es]=Módulos de otras preferencias +Name[et]=Muude seadistuste moodulid +Name[eu]=Beste ezarpen batzuen moduluak +Name[fa]=پیمانه‌های تنظیمات دیگر +Name[fi]=Muut asetusosiot +Name[fr]=Autres modules de paramètres +Name[gl]=Outros módulos de configuración +Name[hu]=Egyéb beállítási modulok +Name[ia]=altere modulos de preferentias +Name[id]=Modul Pengaturan Lainnya +Name[is]=Aðrar stillingaeiningar +Name[ko]=기타 설정 모듈 +Name[nb]=Moduler for andre innstillinger +Name[nds]=Anner Instellenmodulen +Name[nl]=Overige modules voor instellingen +Name[pa]=ਹੋਰ ਸੈਟਿੰਗ ਮੋਡੀਊਲ +Name[pl]=Moduły innych ustawień +Name[pt]=Outros Módulos de Configuração +Name[pt_BR]=Outros módulos de configuração +Name[ru]=Модули других настроек +Name[sk]=Iné moduly nastavení +Name[sl]=Moduli ostalih nastavitev +Name[sr]=Остали модули поставки +Name[sr@ijekavian]=Остали модули поставки +Name[sr@ijekavianlatin]=Ostali moduli postavki +Name[sr@latin]=Ostali moduli postavki +Name[sv]=Övriga inställningsmoduler +Name[tr]=Diğer Ayar Modülleri +Name[uk]=Модулі інших параметрів +Name[x-test]=xxOther Settings Modulesxx +Name[zh_CN]=其它设置模块 +Name[zh_TW]=其他設定檢視 + +Icon=preferences-system + +X-DOC-Weight=390 + +X-KDE-KHelpcenter-Special=othercontrol diff --git a/khelpcenter/plugins/plasma.desktop b/khelpcenter/plugins/plasma.desktop new file mode 100644 index 00000000..a9cc502d --- /dev/null +++ b/khelpcenter/plugins/plasma.desktop @@ -0,0 +1,85 @@ +[Desktop Entry] +X-DocPath=help:/plasma-desktop/index.html +Icon=plasma +Name=Plasma Manual +Name[ar]=كتيّب بلازما +Name[ast]=Manual de Plasma +Name[be@latin]=Padručnik pa systemie „Plasma” +Name[bg]=Ръководство за Plasma +Name[bn]=প্লাসমা ম্যানুয়াল +Name[bn_IN]=Plasma সহায়িকা +Name[bs]=Uputstvo za Plazmu +Name[ca]=Manual del Plasma +Name[ca@valencia]=Manual del Plasma +Name[cs]=Manuál k plasmě +Name[csb]=Ùczbòwnik plazmë +Name[da]=Plasma-manual +Name[de]=Handbuch zu Plasma +Name[el]=Εγχειρίδιο του Plasma +Name[en_GB]=Plasma Manual +Name[eo]=Manlibro de Plasmo +Name[es]=Manual de Plasma +Name[et]=Plasma käsiraamat +Name[eu]=Plasma eskuliburua +Name[fa]=راهنمای پلاسما +Name[fi]=Plasma-opas +Name[fr]=Manuel de Plasma +Name[fy]=Plasma hânlieding +Name[ga]=Lámhleabhar Plasma +Name[gl]=Manual de Plasma +Name[gu]=પ્લાઝમા માર્ગદર્શિકા +Name[he]=המדריך של Plasma +Name[hi]=प्लाज़्मा मैनुअल +Name[hne]=प्लाज्मा मेनुअल +Name[hr]=Upute za uporabu Plasme +Name[hsb]=Přiručka za Plasma +Name[hu]=Plasma kézikönyv +Name[ia]=Manual de Plasma +Name[id]=Manual Plasma +Name[is]=Plasma handbók +Name[it]=Manuale di Plasma +Name[ja]=Plasma マニュアル +Name[kk]=Plasma нұсқауы +Name[km]=សៀវភៅ​ដៃ​ប្លាស្មា +Name[kn]=ಪ್ಲಾಸ್ಮಾ ಕೈಪಿಡಿ +Name[ko]=Plasma 설명서 +Name[ku]=Rêberê Plasma +Name[lt]=Plasma Naudotojo vadovas +Name[lv]=Plasma rokasgrāmata +Name[mai]=प्लाज़्मा मैनुअल +Name[mk]=Упатство за Плазма +Name[ml]=പ്ലാസ്മയുടെ സഹായക്കുറിപ്പു് +Name[mr]=प्लाज्मा पुस्तिका +Name[nb]=Plasma-håndbok +Name[nds]=Plasma-Handbook +Name[nl]=Plasma-handleiding +Name[nn]=Plasma-handbok +Name[or]=ପ୍ଲାଜମା ସହାୟକ ପୁସ୍ତକ +Name[pa]=ਪਲਾਜ਼ਮਾ ਮੇਨੂਅਲ +Name[pl]=Podręcznik Plazmy +Name[pt]=Manual do Plasma +Name[pt_BR]=Manual do Plasma +Name[ro]=Manualul Plasma +Name[ru]=Руководство пользователя Plasma +Name[se]=Plasmagiehtagirji +Name[si]=Plasma අත් පොත +Name[sk]=Manuál k Plasme +Name[sl]=Priročnik za Plasmo +Name[sr]=Упутство за Плазму +Name[sr@ijekavian]=Упутство за Плазму +Name[sr@ijekavianlatin]=Uputstvo za Plasmu +Name[sr@latin]=Uputstvo za Plasmu +Name[sv]=Handbok Plasma +Name[ta]=பிளாஸ்மா கையேடு +Name[te]=ప్లాజ్మా మేన్యువల్ +Name[tg]=Дастуруламали Plasma +Name[th]=คู่มือของพลาสมา +Name[tr]=Plasma El Kitabı +Name[ug]=Plasma قوللانمىسى +Name[uk]=Підручник з Плазми +Name[vi]=Sổ tay Plasma +Name[wa]=Esplikêyes di Plasma +Name[x-test]=xxPlasma Manualxx +Name[zh_CN]=Plasma 手册 +Name[zh_TW]=Plasma 手冊 +Icon=plasma diff --git a/khelpcenter/plugins/quickstart.desktop b/khelpcenter/plugins/quickstart.desktop new file mode 100644 index 00000000..e5e11ef0 --- /dev/null +++ b/khelpcenter/plugins/quickstart.desktop @@ -0,0 +1,96 @@ +# KDE Config File +[Desktop Entry] +Name=Quickstart Guide +Name[af]=Woerts-warts Gids +Name[ar]=مرشد البدء السريع +Name[ast]=Guía rápida +Name[be]=Падручнік для пачаткоўца +Name[be@latin]=Karotki padručnik +Name[bg]=Ръководство за начинаещите +Name[bn]=কুইকস্টার্ট গাইড +Name[bn_IN]=দ্রুত প্রস্তুতির সহায়িকা +Name[br]=Sturier Kregiñ fonnus +Name[bs]=Vodič za početnike +Name[ca]=Guia ràpida +Name[ca@valencia]=Guia ràpida +Name[cs]=Úvodní seznámení +Name[csb]=Sztartowi prowôdnik +Name[cy]=Canllaw cychwyn cyflym +Name[da]=Kvikstart-guide +Name[de]=Kurzeinführung +Name[el]=Οδηγός γρήγορου ξεκινήματος +Name[en_GB]=Quickstart Guide +Name[eo]=Konciza gvidlibro +Name[es]=Guía rápida +Name[et]=Kiire sissejuhatus +Name[eu]=Gida bizkorra +Name[fa]=راهنمای آغاز سریع +Name[fi]=Pikaopas +Name[fr]=Guide de démarrage rapide +Name[fy]=Fluchstartgids +Name[ga]=Lámhleabhar Mearthosaigh +Name[gl]=Guía de inicio rápido +Name[gu]=ઝડપીશરૂઆત માર્ગદર્શન +Name[he]=מדריך התחלה מהירה +Name[hi]=शीघ्रप्रारंभ मार्गदर्शक +Name[hne]=सीघ्रसुरू मार्गदर्सक +Name[hr]=Brzi uvod +Name[hsb]=Spěšny zawod +Name[hu]=Rövid bevezetés +Name[ia]=Guida initial rapide +Name[id]=Panduan Memulai Secara Cepat +Name[is]=Skyndileiðbeiningar +Name[it]=Guida rapida +Name[ja]=クイックスタート +Name[ka]=სახელმძღვანელო დამწყებთათვის +Name[kk]=Бастаушы бағыттамасы +Name[km]=មគ្គុទ្ទេសក៍​ចាប់ផ្ដើម​រហ័ស +Name[kn]=ಶೀಘ್ರ ಪ್ರಾರಂಭ ಮಾರ್ಗದರ್ಶಿ +Name[ko]=빠른 시작 설명서 +Name[ku]=Rêbernameya Destpêkirina Lezgîn +Name[lt]=Greitos pradžios gidas +Name[lv]=Ātras sākšanas ceļvedis +Name[mai]=शीघ्रप्रारंभ मार्गदर्शक +Name[mk]=Водич за брзо снаоѓање +Name[ml]=കൈപ്പുസ്തകം +Name[mr]=Quickstart पुस्तिका +Name[ms]=Panduan Mula Pantas +Name[nb]=Hurtigstart-guide +Name[nds]=Fixstart-Föhrer +Name[ne]=द्रुत सुरुआत मार्गदर्शन +Name[nl]=Snelstartgids +Name[nn]=Snøggstartgaid +Name[or]=Quickstart ପଥ ପ୍ରଦର୍ଶକ +Name[pa]=ਤੁਰੰਤ ਸਟਾਰਟ ਗਾਈਡ +Name[pl]=Przewodnik startowy +Name[pt]=Guia de Iniciação +Name[pt_BR]=Guia de início rápido +Name[ro]=Ghid rapid +Name[ru]=Руководство для начинающих в KDE +Name[se]=Oanehis KDE-introdukšuvdna +Name[si]=ක්‍ෂණික ඇරඹුම් සහාය +Name[sk]=Návod na rýchle použitie +Name[sl]=Vodnik za hitri začetek +Name[sr]=Водич за почетнике +Name[sr@ijekavian]=Водич за почетнике +Name[sr@ijekavianlatin]=Vodič za početnike +Name[sr@latin]=Vodič za početnike +Name[sv]=Snabbstartsguide +Name[ta]=விரைவுதுவக்க வழிகாட்டி. +Name[te]=త్వరితప్రారంభక మార్గదర్శి +Name[tg]=Дастуруламали оғози кор +Name[th]=คำแนะนำด่วน +Name[tr]=Hızlı Başlama Rehberi +Name[ug]=تېز باشلاش يېتەكچىسى +Name[uk]=Настанови з перших кроків +Name[uz]=KDE boʻyicha yoʻlkoʻrsatgich +Name[uz@cyrillic]=KDE бўйича йўлкўрсатгич +Name[vi]=Hướng dẫn bắt đầu nhanh +Name[wa]=Guide d' enondaedje abeye +Name[xh]=Isikhombisi Sesiqalo esikhawulezayo +Name[x-test]=xxQuickstart Guidexx +Name[zh_CN]=速成指南 +Name[zh_TW]=快速入門指南 +Icon=text-plain +X-DocPath=help:/khelpcenter/quickstart/index.html +X-DOC-Weight=-3000 diff --git a/khelpcenter/plugins/userguide.desktop b/khelpcenter/plugins/userguide.desktop new file mode 100644 index 00000000..a5e5e976 --- /dev/null +++ b/khelpcenter/plugins/userguide.desktop @@ -0,0 +1,95 @@ +[Desktop Entry] +X-DocPath=help:/khelpcenter/userguide/index.html +Name=KDE Users' Manual +Name[af]=KDE gebruikershandleiding +Name[ar]=كتيّب كدي للمستخدمين +Name[ast]=Manual d'usuariu de KDE +Name[be]=Падручнік карыстальніка KDE +Name[be@latin]=Padručnik dla karystańnika KDE +Name[bg]=Ръководство за употреба +Name[bn]=কে.ডি.ই. ব্যবহারকারীদের জন্য ম্যানুয়াল +Name[bn_IN]=KDE ব্যবহারকারীদের জন্য সহায়িকা +Name[br]=Levr-dorn arveriaded KDE +Name[bs]=Korisnički priručnik KDE‑a +Name[ca]=Manual d'usuari KDE +Name[ca@valencia]=Manual d'usuari KDE +Name[cs]=Příručka uživatele KDE +Name[csb]=Pòdrãcznik brëkòwnika KDE +Name[cy]=Llawlyfr Defnyddwyr KDE +Name[da]=KDE-brugervejledning +Name[de]=KDE-Benutzerhandbuch +Name[el]=Εγχειρίδιο χρήστη του KDE +Name[en_GB]=KDE Users' Manual +Name[eo]=Manlibro por uzantoj de KDE +Name[es]=Manual del usuario de KDE +Name[et]=KDE kasutaja käsiraamat +Name[eu]=KDEren erabiltzailearen eskuliburua +Name[fa]=راهنمای کاربران KDE +Name[fi]=KDE:n käyttöopaste +Name[fr]=Manuel utilisateur de KDE +Name[fy]=KDE's hânlieding +Name[ga]=Lámhleabhar KDE d'úsáideoirí +Name[gl]=Manual do usuario de KDE +Name[gu]=KDE વપરાશકર્તાની માર્ગદર્શિકા +Name[he]=המדריך למשתמש ב־KDE +Name[hi]=केडीई उपयोक्ता निर्देशिका +Name[hne]=केडीई कमइया निर्देसिका +Name[hr]=KDE korisnički priručnik +Name[hsb]=Přiručka za wužiwarja KDE +Name[hu]=KDE-felhasználók kézikönyve +Name[ia]=Manual pro le Usator de KDE +Name[id]=Manual Pengguna KDE +Name[is]=KDE notandahandbækur +Name[it]=Manuale degli utenti di KDE +Name[ja]=KDE ユーザマニュアル +Name[ka]=KDE-ს მომხმარებლის სახელმძღვანელო +Name[kk]=KDE пайдаланушының оқулығы +Name[km]=សៀវភៅ​របស់​អ្នក​ប្រើ KDE +Name[kn]=ಕೆಡಿಇ ಬಳಕೆದಾರರ ಕೆಪಿಡಿ +Name[ko]=KDE 사용자 설명서 +Name[ku]=Bikarhênerên KDE Bi Destan +Name[lt]=KDE Naudotojo vadovas +Name[lv]=KDE lietotāja rokasgrāmata +Name[mai]=केडीई प्रयोक्ता निर्देशिका +Name[mk]=KDE кориснички прирачник +Name[ml]=കെഡിഇ ഉപയോക്തൃസഹായകഗ്രന്ഥം +Name[mr]=केडीई वापरकर्ता निर्देशिका +Name[ms]=Manual Pengguna KDE +Name[nb]=Brukerhandbok for KDE +Name[nds]=KDE-Brukerhandbook +Name[ne]=केडीई प्रयोगकर्ता म्यानुअल +Name[nl]=KDE's handleiding +Name[nn]=Brukarhandbok for KDE +Name[or]=KDE ଚାଳକ ସହାୟକ ପୁସ୍ତକ +Name[pa]=KDE ਯੂਜ਼ਰ ਡੌਕੂਮੈਂਟ +Name[pl]=Podręcznik użytkownika KDE +Name[pt]=Manual do Utilizador do KDE +Name[pt_BR]=Manual do usuário do KDE +Name[ro]=Manualul utilizatorului KDE +Name[ru]=Руководство пользователя KDE +Name[se]=KDE giehtagirji +Name[si]=KDE පරිශීලක අත්පොත +Name[sk]=Užívateľský manuál KDE +Name[sl]=Uporabniški priročnik KDE +Name[sr]=Кориснички приручник КДЕ‑а +Name[sr@ijekavian]=Кориснички приручник КДЕ‑а +Name[sr@ijekavianlatin]=Korisnički priručnik KDE‑a +Name[sr@latin]=Korisnički priručnik KDE‑a +Name[sv]=KDE:s användarhandbok +Name[ta]=KDE பயனர்களின் கையேடு +Name[te]=కెడిఈ యూజర్ మెన్యువల్ +Name[tg]=Дастуруламалҳои корбари KDE +Name[th]=คู่มือผู้ใช้งาน KDE +Name[tr]=KDE Kullanıcı Kılavuzu +Name[ug]=KDE ئىشلەتكۈچىلەر قوللانمىسى +Name[uk]=Інструкція користувача KDE +Name[uz]=KDE uchun qoʻllanma +Name[uz@cyrillic]=KDE учун қўлланма +Name[vi]=Sổ tay người dùng KDE +Name[wa]=Manuel di l' uzeu di KDE +Name[x-test]=xxKDE Users' Manualxx +Name[zh_CN]=KDE 用户手册 +Name[zh_TW]=KDE 使用者手冊 + +X-DOC-Weight=-2000 + diff --git a/khelpcenter/plugintraverser.cpp b/khelpcenter/plugintraverser.cpp new file mode 100644 index 00000000..23a7a401 --- /dev/null +++ b/khelpcenter/plugintraverser.cpp @@ -0,0 +1,119 @@ +/* + * This file is part of the KDE Help Center + * + * Copyright (C) 1999 Matthias Elter (me@kde.org) + * + * 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 "plugintraverser.h" +#include "docmetainfo.h" +#include "navigator.h" +#include "navigatorappitem.h" +#include "navigatoritem.h" + +#include +#include +#include +#include +#include +#include + +using namespace KHC; + +PluginTraverser::PluginTraverser( Navigator *navigator, QTreeWidget *parent ) + : DocEntryTraverser(), + mListView( parent ), + mParentItem( 0 ), + mCurrentItem( 0 ), + mNavigator( navigator ) +{ +} + +PluginTraverser::PluginTraverser( Navigator *navigator, NavigatorItem *parent ) + : DocEntryTraverser(), + mListView( 0 ), + mParentItem( parent ), + mCurrentItem( 0 ), + mNavigator( navigator ) +{ +} + +void PluginTraverser::process( DocEntry *entry ) +{ + if ( !mListView && !mParentItem ) { + kDebug( 1400 ) << "ERROR! Neither mListView nor mParentItem is set."; + return; + } + + if ( !entry->docExists() && !mNavigator->showMissingDocs() ) + return; + + if ( entry->khelpcenterSpecial() == QLatin1String("apps") ) { + NavigatorAppItem *appItem; + entry->setIcon( "kde" ); + if ( mListView ) + appItem = new NavigatorAppItem( entry, mListView, mCurrentItem ); + else + appItem = new NavigatorAppItem( entry, mParentItem, mCurrentItem ); + KConfigGroup cfg(KGlobal::config(), "General"); + appItem->setRelpath( cfg.readPathEntry( "AppsRoot", QString() ) ); + mCurrentItem = appItem; + } else if ( entry->khelpcenterSpecial() == QLatin1String("scrollkeeper" )) { + if ( mParentItem ) { + mCurrentItem = mNavigator->insertScrollKeeperDocs( mParentItem, mCurrentItem ); + } + return; + } else { + if ( mListView ) + mCurrentItem = new NavigatorItem( entry, mListView, mCurrentItem ); + else + mCurrentItem = new NavigatorItem( entry, mParentItem, mCurrentItem ); + + if ( entry->khelpcenterSpecial() == QLatin1String("konqueror") ) { + mNavigator->insertParentAppDocs( entry->khelpcenterSpecial(), mCurrentItem ); + } else if ( entry->khelpcenterSpecial() == QLatin1String("kcontrol") ) { + mNavigator->insertKCMDocs( entry->khelpcenterSpecial(), mCurrentItem, QString("kcontrol") ); + } else if ( entry->khelpcenterSpecial() == QLatin1String("konquerorcontrol") ) { + mNavigator->insertKCMDocs( entry->khelpcenterSpecial(), mCurrentItem, QString("konquerorcontrol") ); + } else if ( entry->khelpcenterSpecial() == QLatin1String("filemanagercontrol") ) { + mNavigator->insertKCMDocs( entry->khelpcenterSpecial(), mCurrentItem, QString("filemanagercontrol") ); + } else if ( entry->khelpcenterSpecial() == QLatin1String("browsercontrol") ) { + mNavigator->insertKCMDocs( entry->khelpcenterSpecial(), mCurrentItem, QString("browsercontrol") ); + } else if ( entry->khelpcenterSpecial() == QLatin1String("othercontrol") ) { + mNavigator->insertKCMDocs( entry->khelpcenterSpecial(), mCurrentItem, QString("othercontrol") ); + } else if ( entry->khelpcenterSpecial() == QLatin1String("kinfocenter") ) { + mNavigator->insertKCMDocs( entry->khelpcenterSpecial(), mCurrentItem, QString("kinfocenter") ); + } else if ( entry->khelpcenterSpecial() == QLatin1String("kioslave") ) { + mNavigator->insertIOSlaveDocs( entry->khelpcenterSpecial(), mCurrentItem ); + } else if ( entry->khelpcenterSpecial() == QLatin1String("info") ) { + mNavigator->insertInfoDocs( mCurrentItem ); + } else { + return; + } +// TODO: was contents2 -> needs to be changed to help-contents-alternate or similar + mCurrentItem->setIcon( 0, SmallIcon( QLatin1String("help-contents") ) ); + } +} + +DocEntryTraverser *PluginTraverser::createChild( DocEntry * /*entry*/ ) +{ + if ( mCurrentItem ) { + return new PluginTraverser( mNavigator, mCurrentItem ); + } + kDebug( 1400 ) << "ERROR! mCurrentItem is not set."; + return 0; +} + +// vim:ts=2:sw=2:et diff --git a/khelpcenter/plugintraverser.h b/khelpcenter/plugintraverser.h new file mode 100644 index 00000000..6a76f516 --- /dev/null +++ b/khelpcenter/plugintraverser.h @@ -0,0 +1,54 @@ +/* + * This file is part of the KDE Help Center + * + * Copyright (C) 1999 Matthias Elter (me@kde.org) + * + * 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. + */ +#ifndef KHC_PLUGINTRAVERSER_H +#define KHC_PLUGINTRAVERSER_H + +#include "docentrytraverser.h" + +#include + +class QTreeWidget; + +namespace KHC { + + class Navigator; + class NavigatorItem; + + class PluginTraverser : public DocEntryTraverser + { + public: + PluginTraverser( Navigator *navigator, QTreeWidget *parent ); + PluginTraverser( Navigator *navigator, NavigatorItem *parent ); + + virtual void process( DocEntry *entry ); + + virtual DocEntryTraverser *createChild( DocEntry *entry ); + + private: + QTreeWidget *mListView; + NavigatorItem *mParentItem; + NavigatorItem *mCurrentItem; + + Navigator *mNavigator; + }; +} + +#endif // KHC_PLUGINTRAVERSER_H +// vim:ts=2:sw=2:et diff --git a/khelpcenter/prefs.kcfgc b/khelpcenter/prefs.kcfgc new file mode 100644 index 00000000..ae03d9c4 --- /dev/null +++ b/khelpcenter/prefs.kcfgc @@ -0,0 +1,6 @@ +# Code generation options for kconfig_compiler +File=khelpcenter.kcfg +ClassName=Prefs +Singleton=true +Mutators=true +GlobalEnums=true diff --git a/khelpcenter/scopeitem.h b/khelpcenter/scopeitem.h new file mode 100644 index 00000000..dacf06e1 --- /dev/null +++ b/khelpcenter/scopeitem.h @@ -0,0 +1,73 @@ +/* This file is part of the KDE project + Copyright 2002 Cornelius Schumacher + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public + License version 2 or at your option version 3 as published + by the Free Software Foundation. + + 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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef KHC_SCOPEITEM_H +#define KHC_SCOPEITEM_H + +#include + +#include "docmetainfo.h" + +namespace KHC { + +class ScopeItem : public QTreeWidgetItem +{ + public: + ScopeItem( QTreeWidget *parent, DocEntry *entry ) + : QTreeWidgetItem( parent, QStringList() << entry->name(), rttiId() ), + mEntry( entry ), mObserver( 0 ) { init(); } + + ScopeItem( QTreeWidgetItem *parent, DocEntry *entry ) + : QTreeWidgetItem( parent, QStringList() << entry->name(), rttiId() ), + mEntry( entry ), mObserver( 0 ) { init(); } + + DocEntry *entry()const { return mEntry; } + + static int rttiId() { return 734678; } + + class Observer + { + public: + virtual ~Observer() {} + virtual void scopeItemChanged( ScopeItem * ) = 0; + }; + + void setObserver( Observer *o ) { mObserver = o; } + + void setOn( bool on ) { setCheckState( 0, on ? Qt::Checked : Qt::Unchecked ); } + bool isOn() const { return checkState( 0 ) == Qt::Checked; } + + protected: + void stateChange ( bool ) + { + if ( mObserver ) mObserver->scopeItemChanged( this ); + } + + private: + void init() { setCheckState(0, Qt::Checked); } + + DocEntry *mEntry; + + Observer *mObserver; +}; + +} + +#endif //KHC_SCOPEITEM_H +// vim:ts=2:sw=2:et diff --git a/khelpcenter/scrollkeepertreebuilder.cpp b/khelpcenter/scrollkeepertreebuilder.cpp new file mode 100644 index 00000000..ba0d935e --- /dev/null +++ b/khelpcenter/scrollkeepertreebuilder.cpp @@ -0,0 +1,197 @@ +/* + * This file is part of the KDE Help Center + * + * Copyright (C) 1999 Matthias Elter (me@kde.org) + * + * 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 "scrollkeepertreebuilder.h" + +#include "navigatoritem.h" +#include "docentry.h" + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +using namespace KHC; + +ScrollKeeperTreeBuilder::ScrollKeeperTreeBuilder( QObject *parent, const char *name ) + : QObject( parent ) +{ + setObjectName( name ); + + loadConfig(); +} + +void ScrollKeeperTreeBuilder::loadConfig() +{ + KConfigGroup configGroup( KGlobal::config(), "ScrollKeeper" ); + mShowEmptyDirs = configGroup.readEntry( "ShowEmptyDirs", false); +} + +NavigatorItem *ScrollKeeperTreeBuilder::build( NavigatorItem *parent, + NavigatorItem *after ) +{ + QString lang = KGlobal::locale()->language(); + + kDebug(1400) << "ScrollKeeper language: " << lang; + + KProcess proc; + proc << "scrollkeeper-get-content-list"; + proc << lang; + + proc.setOutputChannelMode(KProcess::OnlyStdoutChannel); + proc.start(); + if ( !proc.waitForFinished() ) { + kDebug(1400) << "Could not execute scrollkeeper-get-content-list"; + return 0; + } + mContentsList = proc.readAllStandardOutput().trimmed(); + + if (!QFile::exists(mContentsList)) { + kDebug(1400) << "Scrollkeeper contents file '" << mContentsList + << "' does not exist." << endl; + return 0; + } + + QDomDocument doc("ScrollKeeperContentsList"); + QFile f(mContentsList); + if ( !f.open( QIODevice::ReadOnly ) ) + return 0; + if ( !doc.setContent( &f ) ) { + f.close(); + return 0; + } + f.close(); + + // Create top-level item + mItems.append(parent); + + QDomElement docElem = doc.documentElement(); + + NavigatorItem *result = 0; + + QDomNode n = docElem.firstChild(); + while( !n.isNull() ) { + QDomElement e = n.toElement(); + if( !e.isNull() ) { + if (e.tagName() == "sect") { + NavigatorItem *createdItem; + insertSection( parent, after, e, createdItem ); + if ( createdItem ) result = createdItem; + } + } + n = n.nextSibling(); + } + + return result; +} + +int ScrollKeeperTreeBuilder::insertSection( NavigatorItem *parent, + NavigatorItem *after, + const QDomNode §Node, + NavigatorItem *§Item ) +{ +// TODO: was contents2 -> needs to be changed to help-contents-alternate or similar + DocEntry *entry = new DocEntry( "", "", "help-contents" ); + sectItem = new NavigatorItem( entry, parent, after ); + sectItem->setAutoDeleteDocEntry( true ); + mItems.append( sectItem ); + + int numDocs = 0; // Number of docs created in this section + + QDomNode n = sectNode.firstChild(); + while( !n.isNull() ) { + QDomElement e = n.toElement(); + if( !e.isNull() ) { + if ( e.tagName() == "title" ) { + entry->setName( e.text() ); + sectItem->updateItem(); + } else if (e.tagName() == "sect") { + NavigatorItem *created; + numDocs += insertSection( sectItem, 0, e, created ); + } else if (e.tagName() == "doc") { + insertDoc(sectItem,e); + ++numDocs; + } + } + n = n.nextSibling(); + } + + // Remove empty sections + if (!mShowEmptyDirs && numDocs == 0) { + delete sectItem; + sectItem = 0; + } + + return numDocs; +} + +void ScrollKeeperTreeBuilder::insertDoc( NavigatorItem *parent, + const QDomNode &docNode ) +{ + DocEntry *entry = new DocEntry( "", "", "text-plain" ); + NavigatorItem *docItem = new NavigatorItem( entry, parent ); + docItem->setAutoDeleteDocEntry( true ); + mItems.append( docItem ); + + QString url; + + QDomNode n = docNode.firstChild(); + while( !n.isNull() ) { + QDomElement e = n.toElement(); + if( !e.isNull() ) { + if ( e.tagName() == "doctitle" ) { + entry->setName( e.text() ); + docItem->updateItem(); + } else if ( e.tagName() == "docsource" ) { + url.append( e.text() ); + } else if ( e.tagName() == "docformat" ) { + QString mimeType = e.text(); + if ( mimeType == "text/html") { + // Let the HTML part figure out how to get the doc + } else if ( mimeType == "application/xml" + || mimeType == "text/xml" /*deprecated name*/ ) { + if ( url.left( 5 ) == "file:" ) url = url.mid( 5 ); + url.prepend( "ghelp:" ); +#if 0 + url.replace( QRegExp( ".xml$" ), ".html" ); +#endif + } else if ( mimeType == "text/sgml" ) { + // GNOME docs use this type. We don't have a real viewer for this. + url.prepend( "file:" ); + } else if ( mimeType.left(5) == "text/" ) { + url.prepend( "file:" ); + } + } + } + n = n.nextSibling(); + } + + entry->setUrl( url ); +} + +#include "scrollkeepertreebuilder.moc" +// vim:sw=2:ts=2:et diff --git a/khelpcenter/scrollkeepertreebuilder.h b/khelpcenter/scrollkeepertreebuilder.h new file mode 100644 index 00000000..7218dd7b --- /dev/null +++ b/khelpcenter/scrollkeepertreebuilder.h @@ -0,0 +1,53 @@ +/* + * This file is part of the KDE Help Center + * + * Copyright (C) 1999 Matthias Elter (me@kde.org) + * + * 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. + */ +#ifndef KHC_SCROLLKEEPERTREEBUILDER_H +#define KHC_SCROLLKEEPERTREEBUILDER_H + +#include + +#include "navigatoritem.h" + +class QDomNode; + +namespace KHC { + +class ScrollKeeperTreeBuilder : public QObject +{ + Q_OBJECT + public: + explicit ScrollKeeperTreeBuilder( QObject *parent, const char *name = 0 ); + + NavigatorItem *build( NavigatorItem *parent, NavigatorItem *after ); + + private: + void loadConfig(); + int insertSection( NavigatorItem *parent, NavigatorItem *after, + const QDomNode §Node, NavigatorItem *&created ); + void insertDoc( NavigatorItem *parent, const QDomNode &docNode ); + + bool mShowEmptyDirs; + QString mContentsList; + QList mItems; +}; + +} + +#endif // KHC_SCROLLKEEPERTREEBUILDER_H +// vim:ts=2:sw=2:et diff --git a/khelpcenter/searchengine.cpp b/khelpcenter/searchengine.cpp new file mode 100644 index 00000000..bfc4b9e5 --- /dev/null +++ b/khelpcenter/searchengine.cpp @@ -0,0 +1,473 @@ + +#include "searchengine.h" + +#include "stdlib.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "docmetainfo.h" +#include "formatter.h" +#include "view.h" +#include "searchhandler.h" +#include "prefs.h" + +namespace KHC +{ + +SearchTraverser::SearchTraverser( SearchEngine *engine, int level ) : + mMaxLevel( 999 ), mEngine( engine), mLevel( level ) +{ +#if 0 + kDebug() << "SearchTraverser(): " << mLevel + << " 0x" << QString::number( int( this ), 16 ) << endl; +#endif +} + +SearchTraverser::~SearchTraverser() +{ +#if 0 + kDebug() << "~SearchTraverser(): " << mLevel + << " 0x" << QString::number( int( this ), 16 ) << endl; +#endif + + QString section; + if ( parentEntry() ) { + section = parentEntry()->name(); + } else { + section = ("Unknown Section"); + } + + if ( !mResult.isEmpty() ) { + mEngine->view()->writeSearchResult( + mEngine->formatter()->sectionHeader( section ) ); + mEngine->view()->writeSearchResult( mResult ); + } +} + +void SearchTraverser::process( DocEntry * ) +{ + kDebug() << "SearchTraverser::process()"; +} + +void SearchTraverser::startProcess( DocEntry *entry ) +{ +// kDebug() << "SearchTraverser::startProcess(): " << entry->name() << " " +// << "SEARCH: '" << entry->search() << "'" << endl; + + if ( !mEngine->canSearch( entry ) || !entry->searchEnabled() ) { + mNotifyee->endProcess( entry, this ); + return; + } + +// kDebug() << "SearchTraverser::startProcess(): " << entry->identifier() +// << endl; + + SearchHandler *handler = mEngine->handler( entry->documentType() ); + + if ( !handler ) { + QString txt; + if ( entry->documentType().isEmpty() ) { + txt = i18n("Error: No document type specified."); + } else { + txt = i18n("Error: No search handler for document type '%1'.", + entry->documentType() ); + } + showSearchError( handler, entry, txt ); + return; + } + + connectHandler( handler ); + + handler->search( entry, mEngine->words(), mEngine->maxResults(), + mEngine->operation() ); + +// kDebug() << "SearchTraverser::startProcess() done: " << entry->name(); +} + +void SearchTraverser::connectHandler( SearchHandler *handler ) +{ + QMap::Iterator it; + it = mConnectCount.find( handler ); + int count = 0; + if ( it != mConnectCount.end() ) count = *it; + if ( count == 0 ) { + connect( handler, SIGNAL( searchError( SearchHandler *, DocEntry *, const QString & ) ), + SLOT( showSearchError( SearchHandler *, DocEntry *, const QString & ) ) ); + connect( handler, SIGNAL( searchFinished( SearchHandler *, DocEntry *, const QString & ) ), + SLOT( showSearchResult( SearchHandler *, DocEntry *, const QString & ) ) ); + } + mConnectCount[ handler ] = ++count; +} + +void SearchTraverser::disconnectHandler( SearchHandler *handler ) +{ + QMap::Iterator it; + it = mConnectCount.find( handler ); + if ( it == mConnectCount.end() ) { + kError() << "SearchTraverser::disconnectHandler() handler not connected." + << endl; + } else { + int count = *it; + --count; + if ( count == 0 ) { + disconnect( handler, SIGNAL( searchError( SearchHandler *, DocEntry *, const QString & ) ), + this, SLOT( showSearchError( SearchHandler *, DocEntry *, const QString & ) ) ); + disconnect( handler, SIGNAL( searchFinished( SearchHandler *, DocEntry *, const QString & ) ), + this, SLOT( showSearchResult( SearchHandler *, DocEntry *, const QString & ) ) ); + } + mConnectCount[ handler ] = count; + } +} + +DocEntryTraverser *SearchTraverser::createChild( DocEntry *parentEntry ) +{ +// kDebug() << "SearchTraverser::createChild() level " << mLevel; + + if ( mLevel >= mMaxLevel ) { + ++mLevel; + return this; + } else { + DocEntryTraverser *t = new SearchTraverser( mEngine, mLevel + 1 ); + t->setParentEntry( parentEntry ); + return t; + } +} + +DocEntryTraverser *SearchTraverser::parentTraverser() +{ +// kDebug() << "SearchTraverser::parentTraverser(): level: " << mLevel; + + if ( mLevel > mMaxLevel ) { + return this; + } else { + return mParent; + } +} + +void SearchTraverser::deleteTraverser() +{ +// kDebug() << "SearchTraverser::deleteTraverser()"; + + if ( mLevel > mMaxLevel ) { + --mLevel; + } else { + delete this; + } +} + +void SearchTraverser::showSearchError( SearchHandler *handler, DocEntry *entry, const QString &error ) +{ +// kDebug() << "SearchTraverser::showSearchError(): " << entry->name() +// << endl; + + mResult += mEngine->formatter()->docTitle( entry->name() ); + mResult += mEngine->formatter()->paragraph( error ); + + mEngine->logError( entry, error ); + + disconnectHandler( handler ); + + mNotifyee->endProcess( entry, this ); +} + +void SearchTraverser::showSearchResult( SearchHandler *handler, DocEntry *entry, const QString &result ) +{ +// kDebug() << "SearchTraverser::showSearchResult(): " << entry->name() +// << endl; + + mResult += mEngine->formatter()->docTitle( entry->name() ); + mResult += mEngine->formatter()->processResult( result ); + + disconnectHandler( handler ); + + mNotifyee->endProcess( entry, this ); +} + +void SearchTraverser::finishTraversal() +{ +// kDebug() << "SearchTraverser::finishTraversal()"; + + mEngine->view()->writeSearchResult( mEngine->formatter()->footer() ); + mEngine->view()->endSearchResult(); + + mEngine->finishSearch(); +} + + +SearchEngine::SearchEngine( View *destination ) + : QObject(), + mProc( 0 ), mSearchRunning( false ), mView( destination ), + mRootTraverser( 0 ) +{ + mLang = KGlobal::locale()->language().left( 2 ); +} + +SearchEngine::~SearchEngine() +{ + delete mRootTraverser; +} + +bool SearchEngine::initSearchHandlers() +{ + const QStringList resources = KGlobal::dirs()->findAllResources( + "appdata", "searchhandlers/*.desktop" ); + QStringList::ConstIterator it; + for( it = resources.constBegin(); it != resources.constEnd(); ++it ) { + QString filename = *it; + kDebug() << "SearchEngine::initSearchHandlers(): " << filename; + SearchHandler *handler = SearchHandler::initFromFile( filename ); + if ( !handler ) { + QString txt = i18n("Unable to initialize SearchHandler from file '%1'.", + filename ); + kWarning() << txt ; +// KMessageBox::sorry( mView->widget(), txt ); + } else { + QStringList documentTypes = handler->documentTypes(); + QStringList::ConstIterator it; + for( it = documentTypes.constBegin(); it != documentTypes.constEnd(); ++it ) { + mHandlers.insert( *it, handler ); + } + } + } + + if ( mHandlers.isEmpty() ) { + QString txt = i18n("No valid search handler found."); + kWarning() << txt ; +// KMessageBox::sorry( mView->widget(), txt ); + return false; + } + + return true; +} + +void SearchEngine::searchExited(int exitCode, QProcess::ExitStatus exitStatus) +{ + Q_UNUSED(exitCode); + Q_UNUSED(exitStatus); + kDebug() << "Search terminated"; + mSearchRunning = false; +} + +bool SearchEngine::search( const QString & words, const QString & method, int matches, + const QString & scope ) +{ + if ( mSearchRunning ) return false; + + // These should be removed + mWords = words; + mMethod = method; + mMatches = matches; + mScope = scope; + + // Saner variables to store search parameters: + mWordList = words.split(' '); + mMaxResults = matches; + if ( method == "or" ) mOperation = Or; + else mOperation = And; + + KConfigGroup cfg(KGlobal::config(), "Search"); + QString commonSearchProgram = cfg.readPathEntry( "CommonProgram", QString() ); + bool useCommon = cfg.readEntry( "UseCommonProgram", false); + + if ( commonSearchProgram.isEmpty() || !useCommon ) { + if ( !mView ) { + return false; + } + + QString txt = i18n("Search Results for '%1':", Qt::escape(words) ); + + mStderr = "" + txt + "\n"; + + mView->beginSearchResult(); + mView->writeSearchResult( formatter()->header( i18n("Search Results") ) ); + mView->writeSearchResult( formatter()->title( txt ) ); + + if ( mRootTraverser ) { + kDebug() << "SearchEngine::search(): mRootTraverser not null."; + return false; + } + mRootTraverser = new SearchTraverser( this, 0 ); + DocMetaInfo::self()->startTraverseEntries( mRootTraverser ); + + return true; + } else { + QString lang = KGlobal::locale()->language().left(2); + + if ( lang.toLower() == "c" || lang.toLower() == "posix" ) + lang = "en"; + + // if the string contains '&' replace with a '+' and set search method to and + if (mWords.indexOf("&") != -1) { + mWords.replace('&', ' '); + mMethod = "and"; + } + + // replace whitespace with a '+' + mWords = mWords.trimmed(); + mWords = mWords.simplified(); + mWords.replace(QRegExp("\\s"), "+"); + + commonSearchProgram = substituteSearchQuery( commonSearchProgram ); + + kDebug() << "Common Search: " << commonSearchProgram; + + mProc = new KProcess(); + *mProc << KShell::splitArgs(commonSearchProgram); + + connect( mProc, SIGNAL( finished(int, QProcess::ExitStatus) ), + this, SLOT( searchExited(int, QProcess::ExitStatus) ) ); + + mSearchRunning = true; + mSearchResult = ""; + mStderr = "" + commonSearchProgram + "\n\n"; + + mProc->start(); + if (!mProc->waitForStarted()) { + kError() << "could not start search program '" << commonSearchProgram + << "'" << endl; + delete mProc; + return false; + } + + while (mSearchRunning && mProc->state() == QProcess::Running) + kapp->processEvents(); + + // no need to use signals/slots + mStderr += mProc->readAllStandardError(); + mSearchResult += mProc->readAllStandardOutput(); + + if ( mProc->exitStatus() == KProcess::CrashExit || mProc->exitCode() != 0 ) { + kError() << "Unable to run search program '" << commonSearchProgram + << "'" << endl; + delete mProc; + + return false; + } + + delete mProc; + + // modify the search result + mSearchResult = mSearchResult.replace("http://localhost/", "file:/"); + mSearchResult = mSearchResult.mid( mSearchResult.indexOf( '<' ) ); + + mView->beginSearchResult(); + mView->writeSearchResult( mSearchResult ); + mView->endSearchResult(); + + emit searchFinished(); + } + + return true; +} + +QString SearchEngine::substituteSearchQuery( const QString &query ) +{ + QString result = query; + result.replace( QLatin1String("%k"), mWords ); + result.replace( QLatin1String("%n"), QString::number( mMatches ) ); + result.replace( QLatin1String("%m"), mMethod ); + result.replace( QLatin1String("%l"), mLang ); + result.replace( QLatin1String("%s"), mScope ); + + return result; +} + +QString SearchEngine::substituteSearchQuery( const QString &query, + const QString &identifier, const QStringList &words, int maxResults, + Operation operation, const QString &lang, const QString& binary ) +{ + QString result = query; + result.replace( QLatin1String("%i"), identifier ); + result.replace( QLatin1String("%w"), words.join( "+" ) ); + result.replace( QLatin1String("%m"), QString::number( maxResults ) ); + QString o = QLatin1String(operation == Or ? "or" : "and"); + result.replace( QLatin1String("%o"), o ); + result.replace( QLatin1String("%d"), Prefs::indexDirectory() ); + result.replace( QLatin1String("%l"), lang ); + result.replace( QLatin1String("%b"), binary ); + + return result; +} + +Formatter *SearchEngine::formatter() const +{ + return mView->formatter(); +} + +View *SearchEngine::view() const +{ + return mView; +} + +void SearchEngine::finishSearch() +{ + delete mRootTraverser; + mRootTraverser = 0; + + emit searchFinished(); +} + +QString SearchEngine::errorLog() const +{ + return mStderr; +} + +void SearchEngine::logError( DocEntry *entry, const QString &msg ) +{ + mStderr += entry->identifier() + QLatin1String(": ") + msg; +} + +bool SearchEngine::isRunning() const +{ + return mSearchRunning; +} + +SearchHandler *SearchEngine::handler( const QString &documentType ) const +{ + return mHandlers.value( documentType, 0 ); +} + +QStringList SearchEngine::words() const +{ + return mWordList; +} + +int SearchEngine::maxResults() const +{ + return mMaxResults; +} + +SearchEngine::Operation SearchEngine::operation() const +{ + return mOperation; +} + +bool SearchEngine::canSearch( DocEntry *entry ) +{ + return entry->docExists() && !entry->documentType().isEmpty() && + handler( entry->documentType() ); +} + +bool SearchEngine::needsIndex( DocEntry *entry ) +{ + if ( !canSearch( entry ) ) return false; + + SearchHandler *h = handler( entry->documentType() ); + if ( !h || h->indexCommand( entry->identifier() ).isEmpty() ) return false; + + return true; +} + +} + +#include "searchengine.moc" + +// vim:ts=2:sw=2:et diff --git a/khelpcenter/searchengine.h b/khelpcenter/searchengine.h new file mode 100644 index 00000000..c1b265fa --- /dev/null +++ b/khelpcenter/searchengine.h @@ -0,0 +1,143 @@ + +#ifndef KHC_SEARCHENGINE_H +#define KHC_SEARCHENGINE_H + +#include + +#include +#include + +#include "docentrytraverser.h" + +namespace KHC { + +class Formatter; +class SearchEngine; +class View; +class SearchHandler; + +class SearchTraverser : public QObject, public DocEntryTraverser +{ + Q_OBJECT + public: + SearchTraverser( SearchEngine *engine, int level ); + ~SearchTraverser(); + + void process( DocEntry * ); + + void startProcess( DocEntry * ); + + DocEntryTraverser *createChild( DocEntry * ); + + DocEntryTraverser *parentTraverser(); + + void deleteTraverser(); + + void finishTraversal(); + + protected: + void connectHandler( SearchHandler *handler ); + void disconnectHandler( SearchHandler *handler ); + + protected Q_SLOTS: + void showSearchResult( SearchHandler *, DocEntry *, const QString &result ); + void showSearchError( SearchHandler *, DocEntry *, const QString &error ); + + private: + const int mMaxLevel; + + SearchEngine *mEngine; + int mLevel; + + DocEntry *mEntry; + QString mJobData; + + QString mResult; + + QMap mConnectCount; +}; + + +class SearchEngine : public QObject +{ + Q_OBJECT + public: + enum Operation { And, Or }; + + SearchEngine( View * ); + ~SearchEngine(); + + bool initSearchHandlers(); + + bool search( const QString & words, const QString & method = "and", int matches = 5, + const QString & scope = "" ); + + Formatter *formatter() const; + View *view() const; + + QString substituteSearchQuery( const QString &query ); + + static QString substituteSearchQuery( const QString &query, + const QString &identifier, const QStringList &words, int maxResults, + Operation operation, const QString &lang, const QString& binary ); + + void finishSearch(); + + /** + Append error message to error log. + */ + void logError( DocEntry *entry, const QString &msg ); + + /** + Return error log. + */ + QString errorLog() const; + + bool isRunning() const; + + SearchHandler *handler( const QString &documentType ) const; + + QStringList words() const; + int maxResults() const; + Operation operation() const; + + bool canSearch( DocEntry * ); + bool needsIndex( DocEntry * ); + + Q_SIGNALS: + void searchFinished(); + + protected Q_SLOTS: + void searchExited(int, QProcess::ExitStatus); + + protected: + void processSearchQueue(); + + private: + KProcess *mProc; + bool mSearchRunning; + QString mSearchResult; + + QString mStderr; + + View *mView; + + QString mWords; + int mMatches; + QString mMethod; + QString mLang; + QString mScope; + + QStringList mWordList; + int mMaxResults; + Operation mOperation; + + DocEntryTraverser *mRootTraverser; + + QMap mHandlers; +}; + +} + +#endif //KHC_SEARCHENGINE_H +// vim:ts=2:sw=2:et diff --git a/khelpcenter/searchhandler.cpp b/khelpcenter/searchhandler.cpp new file mode 100644 index 00000000..59ae8b92 --- /dev/null +++ b/khelpcenter/searchhandler.cpp @@ -0,0 +1,245 @@ + +/* + This file is part of KHelpCenter. + + Copyright (c) 2005 Cornelius Schumacher + + 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 "searchhandler.h" + +#include "searchengine.h" +#include "prefs.h" +#include "docentry.h" + +#include +#include +#include +#include +#include +#include +#include + +#include + +using namespace KHC; + +SearchJob::SearchJob(DocEntry *entry) : mEntry( entry ), mProcess( 0 ), mKioJob( 0 ) +{ +} + +bool SearchJob::startLocal(const QString &cmdString) +{ + mProcess = new KProcess; + *mProcess << KShell::splitArgs(cmdString); + + connect( mProcess, SIGNAL( finished(int, QProcess::ExitStatus) ), + this, SLOT( searchExited(int, QProcess::ExitStatus) ) ); + + mProcess->setOutputChannelMode(KProcess::SeparateChannels); + mProcess->start(); + if (!mProcess->waitForStarted()) { + QString txt = i18n("Error executing search command '%1'.", cmdString ); + emit searchError( this, mEntry, txt ); + return false; + } + return true; +} + +bool SearchJob::startRemote(const QString &urlString) +{ + KIO::TransferJob *job = KIO::get( KUrl( urlString ) ); + connect( job, SIGNAL( result( KJob * ) ), + this, SLOT( slotJobResult( KJob * ) ) ); + connect( job, SIGNAL( data( KIO::Job *, const QByteArray & ) ), + this, SLOT( slotJobData( KIO::Job *, const QByteArray & ) ) ); + + mKioJob = job; + return true; +} + +SearchJob::~SearchJob() +{ + delete mProcess; + delete mKioJob; +} + +void SearchJob::searchExited( int exitCode, QProcess::ExitStatus exitStatus ) +{ + if ( exitStatus == QProcess::NormalExit && exitCode == 0 ) { + mResult = mProcess->readAllStandardOutput(); + emit searchFinished( this, mEntry, mResult ); + } else { + mError = mProcess->readAllStandardError(); + QString error = QLatin1String("") + mCmd + QLatin1String("\n") + mError; + emit searchError( this, mEntry, error ); + } +} + +void SearchJob::slotJobResult( KJob *job ) +{ + QString result; + //DocEntry *entry = 0; + + if ( job->error() ) { + emit searchError( this, mEntry, i18n("Error: %1", job->errorString() ) ); + } else { + emit searchFinished( this, mEntry, mResult ); + } +} + +void SearchJob::slotJobData( KIO::Job *job, const QByteArray &data ) +{ + Q_UNUSED(job); + mResult += data.data(); +} + + +SearchHandler::SearchHandler( const KConfigGroup &cg ) +{ + mLang = KGlobal::locale()->language().left( 2 ); + mDocumentTypes = cg.readEntry( "DocumentTypes" , QStringList() ); +} + +SearchHandler::~SearchHandler() +{ +} + +SearchHandler *SearchHandler::initFromFile( const QString &filename ) +{ + KDesktopFile file( filename ); + KConfigGroup dg = file.desktopGroup(); + + SearchHandler *handler = 0; + + const QString type = dg.readEntry( "Type" ); + if ( false ) { + } else { + handler = new ExternalProcessSearchHandler( dg ); + } + + return handler; +} + +QStringList SearchHandler::documentTypes() const +{ + return mDocumentTypes; +} + + +ExternalProcessSearchHandler::ExternalProcessSearchHandler( const KConfigGroup &cg ) + : SearchHandler( cg ) +{ + mSearchCommand = cg.readEntry( "SearchCommand" ); + mSearchUrl = cg.readEntry( "SearchUrl" ); + mIndexCommand = cg.readEntry( "IndexCommand" ); + mTryExec = cg.readEntry( "TryExec" ); + mSearchBinary = cg.readEntry( "SearchBinary" ); + const QStringList searchBinaryPaths = cg.readEntry( "SearchBinaryPaths", QStringList() ); + mSearchBinary = KStandardDirs::findExe(mSearchBinary, searchBinaryPaths.join(":")); +} + +QString ExternalProcessSearchHandler::indexCommand( const QString &identifier ) +{ + QString cmd = mIndexCommand; + cmd.replace( "%i", identifier ); + cmd.replace( "%d", Prefs::indexDirectory() ); + cmd.replace( "%l", mLang ); + return cmd; +} + +bool ExternalProcessSearchHandler::checkPaths(QString* error) const +{ + if ( !mSearchCommand.isEmpty() && !checkBinary( mSearchCommand ) ) { + *error = i18n("'%1' not found, check your installation", mSearchCommand); + return false; + } + + if ( !mIndexCommand.isEmpty() && !checkBinary( mIndexCommand ) ) { + *error = i18n("'%1' not found, check your installation", mIndexCommand); + return false; + } + + if ( !mTryExec.isEmpty() && !checkBinary( mTryExec ) ) { + *error = i18n("'%1' not found, install the package containing it", mTryExec); + return false; + } + + return true; +} + +bool ExternalProcessSearchHandler::checkBinary( const QString &cmd ) const +{ + QString binary; + + int pos = cmd.indexOf( ' ' ); + if ( pos < 0 ) binary = cmd; + else binary = cmd.left( pos ); + + return !KStandardDirs::findExe( binary ).isEmpty(); +} + +void ExternalProcessSearchHandler::search( DocEntry *entry, const QStringList &words, + int maxResults, + SearchEngine::Operation operation ) +{ + kDebug() << entry->identifier(); + + if ( !mSearchCommand.isEmpty() ) { + QString cmdString = SearchEngine::substituteSearchQuery( mSearchCommand, + entry->identifier(), words, maxResults, operation, mLang, mSearchBinary ); + + kDebug() << "CMD:" << cmdString; + + SearchJob *searchJob = new SearchJob(entry); + connect(searchJob, SIGNAL(searchFinished( SearchJob *, DocEntry *, const QString & )), + this, SLOT(slotSearchFinished( SearchJob *, DocEntry *, const QString & ))); + connect(searchJob, SIGNAL(searchError( SearchJob *, DocEntry *, const QString & )), + this, SLOT(slotSearchError( SearchJob *, DocEntry *, const QString & ))); + searchJob->startLocal(cmdString); + + } else if ( !mSearchUrl.isEmpty() ) { + QString urlString = SearchEngine::substituteSearchQuery( mSearchUrl, + entry->identifier(), words, maxResults, operation, mLang, mSearchBinary ); + + kDebug() << "URL:" << urlString; + + SearchJob *searchJob = new SearchJob(entry); + connect(searchJob, SIGNAL(searchFinished( SearchJob *, DocEntry *, const QString & )), + this, SLOT(slotSearchFinished( SearchJob *, DocEntry *, const QString & ))); + connect(searchJob, SIGNAL(searchError( SearchJob *, DocEntry *, const QString & )), + this, SLOT(slotSearchError( SearchJob *, DocEntry *, const QString & ))); + searchJob->startRemote(urlString); + + } else { + QString txt = i18n("No search command or URL specified."); + emit searchFinished( this, entry, txt ); + } +} + +void ExternalProcessSearchHandler::slotSearchFinished( SearchJob *job, DocEntry *entry, const QString &result ) +{ + emit searchFinished( this, entry, result); + job->deleteLater(); +} + +void ExternalProcessSearchHandler::slotSearchError( SearchJob *job, DocEntry *entry, const QString &error ) +{ + emit searchError(this, entry, error); + job->deleteLater(); +} + +#include "searchhandler.moc" diff --git a/khelpcenter/searchhandler.h b/khelpcenter/searchhandler.h new file mode 100644 index 00000000..351b7174 --- /dev/null +++ b/khelpcenter/searchhandler.h @@ -0,0 +1,125 @@ + +/* + This file is part of KHelpCenter. + + Copyright (c) 2005 Cornelius Schumacher + + 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. +*/ + +#ifndef KHC_SEARCHHANDLER_H +#define KHC_SEARCHHANDLER_H + +#include "searchengine.h" + +#include + +#include + +class KConfigGroup; +namespace KIO { + class Job; +} + +namespace KHC { + + class SearchJob : public QObject { + Q_OBJECT + public: + SearchJob(DocEntry *entry); + ~SearchJob(); + + bool startLocal(const QString &cmdString); + bool startRemote(const QString &url); + + Q_SIGNALS: + void searchFinished( SearchJob *, DocEntry *, const QString & ); + void searchError( SearchJob *, DocEntry *, const QString & ); + + protected Q_SLOTS: + void searchExited( int exitCode, QProcess::ExitStatus ); + void slotJobResult( KJob *job ); + void slotJobData( KIO::Job *, const QByteArray &data ); + + protected: + DocEntry *mEntry; + KProcess *mProcess; + KIO::Job *mKioJob; + QString mCmd; + QString mResult; + QString mError; + }; + + class SearchHandler : public QObject + { + Q_OBJECT + public: + static SearchHandler *initFromFile( const QString &filename ); + + virtual ~SearchHandler(); + + virtual void search( DocEntry *, const QStringList &words, + int maxResults = 10, + SearchEngine::Operation operation = SearchEngine::And ) = 0; + + virtual QString indexCommand( const QString &identifier ) = 0; + + QStringList documentTypes() const; + + virtual bool checkPaths(QString* error) const = 0; + + Q_SIGNALS: + void searchFinished( SearchHandler *, DocEntry *, const QString & ); + void searchError( SearchHandler *, DocEntry *, const QString & ); + + protected: + SearchHandler( const KConfigGroup &cg ); + + QString mLang; + QStringList mDocumentTypes; + }; + + class ExternalProcessSearchHandler : public SearchHandler + { + Q_OBJECT + public: + ExternalProcessSearchHandler( const KConfigGroup &cg ); + + void search( DocEntry *, const QStringList &words, + int maxResults = 10, + SearchEngine::Operation operation = SearchEngine::And ); + + QString indexCommand( const QString &identifier ); + + bool checkPaths(QString* error) const; + + private: + bool checkBinary( const QString &cmd ) const; + + private slots: + void slotSearchFinished( SearchJob *, DocEntry *, const QString & ); + void slotSearchError( SearchJob *, DocEntry *, const QString & ); + + private: + QString mSearchCommand; + QString mSearchUrl; + QString mSearchBinary; + QString mIndexCommand; + QString mTryExec; + }; + +} + +#endif //KHC_SEARCHHANDLER_H diff --git a/khelpcenter/searchhandlers/CMakeLists.txt b/khelpcenter/searchhandlers/CMakeLists.txt new file mode 100644 index 00000000..fc8e537a --- /dev/null +++ b/khelpcenter/searchhandlers/CMakeLists.txt @@ -0,0 +1,23 @@ +if (NOT WIN32) +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/khc_docbookdig.pl.cmake ${CMAKE_CURRENT_BINARY_DIR}/khc_docbookdig.pl @ONLY) +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/khc_htdig.pl.cmake ${CMAKE_CURRENT_BINARY_DIR}/khc_htdig.pl @ONLY ) + +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/docbook.desktop.cmake +${CMAKE_CURRENT_BINARY_DIR}/docbook.desktop ) + +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/man.desktop.cmake +${CMAKE_CURRENT_BINARY_DIR}/man.desktop ) + +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/htdig.desktop.cmake +${CMAKE_CURRENT_BINARY_DIR}/htdig.desktop ) + +macro_additional_clean_files( ${CMAKE_CURRENT_BINARY_DIR}/khc_htdig.pl {CMAKE_CURRENT_BINARY_DIR}/khc_docbookdig.pl @ONLY) + +########### install files ############### + +install( FILES htdig_long.html DESTINATION ${DATA_INSTALL_DIR}/khelpcenter/searchhandlers/htdig ) +install( FILES ${CMAKE_CURRENT_BINARY_DIR}/htdig.desktop ${CMAKE_CURRENT_BINARY_DIR}/man.desktop ${CMAKE_CURRENT_BINARY_DIR}/docbook.desktop DESTINATION ${DATA_INSTALL_DIR}/khelpcenter/searchhandlers ) + +install(PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/khc_htdig.pl khc_htsearch.pl khc_mansearch.pl ${CMAKE_CURRENT_BINARY_DIR}/khc_docbookdig.pl DESTINATION ${LIBEXEC_INSTALL_DIR}) + +endif (NOT WIN32) diff --git a/khelpcenter/searchhandlers/README.searchhandlers b/khelpcenter/searchhandlers/README.searchhandlers new file mode 100644 index 00000000..cbbfbbbd --- /dev/null +++ b/khelpcenter/searchhandlers/README.searchhandlers @@ -0,0 +1,61 @@ +KHelpcenter Search Handlers +=========================== + +Searching documents in KHelpcenter is handled by document-type-specific search +handlers. Each searchable document provides provides a document type in its meta +data and if a corresponding handler is found, it can be searched. + +Search handlers are described by a desktop file which is put in the khelpcenter +app directory in a "searchhandlers" directory. The desktop file contains the +information about which document types the handler covers, how to do a search +query and how to create a search index. + +A search handler has to provide a command line tool based interface. There has +to be a command to do a query and, if previous creation of an index is required, +a command to create a search index. The search commands returns its results as +HTML on stdout. + + +Search Query +------------ + +KHelpcenter reads the command to execute for submitting a search query from the +search handler's desktop file ("SearchCommand"). The search command can contain +some symbols which are replaced by KHelpcenter with the data for the concrete +search request: + +%i Identifier of document (usually the name of the document's desktop file) +%w Words to be searched for +%o Operation for combining multiple search words. Allowed values: "and" and + "or". +%m Maximum number of results +%d Directory containing search indices + +Search Query Result +------------------- + +The result has to be returned as HTML page. The content of the tag will +be extracted and inserted in the search results page. If there is no body tag, +the complete result text will be inserted. + + +Building a Search Index +----------------------- + +KHelpcenter reads the command to build a search index from the search handler's +desktop file ("IndexCommand"). The indexing command can contain some symbols +which are replaced by KHelpcenter with the data for the concrete index creation +call: + +%i Identifier of document (usually the name of the document's desktop file) +%d Directory containing search indices +%p Path to document to be indexed + +Index Creation Result +--------------------- + +As result of the indexing command an index is created in the directory specified +by KHelpcenter. The format and structure of the index is handler-specific. When +index creation is finished the indexing command has to create a special file +with the name ".exists", where has to have the value +passed by the %i symbol. This file indicates the existance of the index. diff --git a/khelpcenter/searchhandlers/docbook.desktop.cmake b/khelpcenter/searchhandlers/docbook.desktop.cmake new file mode 100644 index 00000000..a5e29cdc --- /dev/null +++ b/khelpcenter/searchhandlers/docbook.desktop.cmake @@ -0,0 +1,8 @@ +[Desktop Entry] +DocumentTypes=application/docbook+xml + +SearchBinary=htsearch +SearchBinaryPaths=/srv/www/cgi-bin,/usr/lib/cgi-bin,/opt/www/htdig/bin +SearchCommand=${LIBEXEC_INSTALL_DIR}/khc_htsearch.pl --binary=%b --docbook --indexdir=%d --config=%i --words=%w --method=%o --maxnum=%m --lang=en +IndexCommand=${LIBEXEC_INSTALL_DIR}/khc_docbookdig.pl --indexdir=%d --docpath=%p --identifier=%i +TryExec=/usr/bin/htdig diff --git a/khelpcenter/searchhandlers/htdig.desktop.cmake b/khelpcenter/searchhandlers/htdig.desktop.cmake new file mode 100644 index 00000000..f961306e --- /dev/null +++ b/khelpcenter/searchhandlers/htdig.desktop.cmake @@ -0,0 +1,8 @@ +[Desktop Entry] +DocumentTypes=text/html + +SearchBinary=htsearch +SearchBinaryPaths=/srv/www/cgi-bin,/usr/lib/cgi-bin,/opt/www/htdig/bin +SearchCommand=${LIBEXEC_INSTALL_DIR}/khc_htsearch.pl --binary=%b --indexdir=%d --config=%i --words=%w --method=%o --maxnum=%m --lang=%l +IndexCommand=${LIBEXEC_INSTALL_DIR}/khc_htdig.pl --indexdir=%d --docpath=%p --identifier=%i --lang=%l +TryExec=/usr/bin/htdig diff --git a/khelpcenter/searchhandlers/htdig_long.html b/khelpcenter/searchhandlers/htdig_long.html new file mode 100644 index 00000000..a2e6e218 --- /dev/null +++ b/khelpcenter/searchhandlers/htdig_long.html @@ -0,0 +1,2 @@ +$(STARSRIGHT) $&(TITLE) ($(MODIFIED))
+$(EXCERPT)
diff --git a/khelpcenter/searchhandlers/khc_docbookdig.pl.cmake b/khelpcenter/searchhandlers/khc_docbookdig.pl.cmake new file mode 100755 index 00000000..3b424c4d --- /dev/null +++ b/khelpcenter/searchhandlers/khc_docbookdig.pl.cmake @@ -0,0 +1,222 @@ +#!/usr/bin/perl +# +# Wrapper script for creating search indices for htdig. +# +# This file is part of KHelpcenter. +# +# Copyright (C) 2002 SuSE Linux AG, Nuernberg +# +# Author: Cornelius Schumacher +# +# 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 + +use strict; + +use Getopt::Long; + +my $htdigdata = "/srv/www/htdig/common/"; +my $htdigbin = "/usr/bin"; +my $kdeprefix = "@CMAKE_INSTALL_PREFIX@"; +chomp $kdeprefix; + +my $dbg = 1; + +my ($indexdir, $docpath, $identifier, $lang, $help ); + +GetOptions ( + 'indexdir=s' => \$indexdir, + 'docpath=s' => \$docpath, + 'identifier=s' => \$identifier, + 'lang=s' => \$lang, + 'help' => \$help, +); + +if ( $help ) { + usage(); +} + +if ( !$indexdir || !$docpath || !$identifier ) { + print STDERR "Missing arguments.\n"; + usage(); +} + +&dbg( "INDEXDIR: $indexdir" ); + +if ( !$lang ) { $lang = "en"; } + +my $tmpdir = "$indexdir/$identifier.tmp"; +if ( ! -e $tmpdir ) { + mkdir $tmpdir; +} + +print "Creating index for '$identifier'\n"; + +my $htdigconf = $indexdir; +my $htdigdb = $indexdir; + +my $conffile = "$htdigconf/$identifier.conf"; + +my $commondir = "$htdigdata/$lang"; +if ( !$lang || !-e $commondir ) { + $commondir = "$htdigdata/en"; +} +if ( !-e $commondir ) { $commondir = $htdigdata; } + +my $locale; +if ( $lang eq "de" ) { $locale = "de_DE"; } +else { $locale = $lang; } + +my $startfile = "$tmpdir/index.html"; + +if ( !open( START, ">$startfile" ) ) { + print STDERR "Unable to open '$startfile' for writing.\n"; + exit 1; +} + +$ENV{ PATH } = '/bin:/usr/bin'; +$ENV{ CDPATH } = ''; +$ENV{ ENV } = ''; + +my $findpath = "@HTML_INSTALL_DIR@/$lang/"; +my $findcmd = "find $findpath -name index.docbook"; + +print STDERR "FINDCMD: $findcmd\n"; + +if ( !open FIND, "$findcmd|" ) { + print STDERR "Unable to find docs.\n"; + exit 1; +} +while ( ) { + chomp; + my $path = $_; + $path =~ /$findpath(.*)\/index.docbook$/; + my $app = $1; + print START "$path\n"; +} +close START; + +my $mimetypefile = "$tmpdir/htdig_mime"; +if ( !open( MIME, ">$mimetypefile" ) ) { + print STDERR "Unable to open '$mimetypefile' for writing.\n"; + exit 1; +} +print MIME << "EOT"; +text/html html +text/docbook docbook +EOT +close MIME; + +my $parserfile = "$tmpdir/docbookparser"; +if ( !open( PARSER, ">$parserfile" ) ) { + print STDERR "Unable to open '$parserfile' for writing.\n"; + exit 1; +} +print PARSER << "EOT"; +#! /bin/bash + +file=\$1 +shift +mime=\$1 +shift + +if test "\$#" -gt 0; then + orig=\${1/file:\\//} + shift +fi + +case "\$orig" in + help:/*) + orig=\${orig/help:\\//} + orig=\${orig/\/index.docbook/} + cd @HTML_INSTALL_DIR@/en/\$orig + file=index.docbook + ;; + *) + file=\$orig + cd `dirname \$orig` + ;; +esac + +echo "t apptitle" +#$kdeprefix/bin/meinproc --htdig "\$file" +$kdeprefix/bin/meinproc4 --htdig "\$file" +EOT +close PARSER; +chmod 0755, $parserfile; + +if ( !open( CONF, ">$conffile" ) ) { + print STDERR "Unable to open '$conffile' for writing.\n"; + exit 1; +} +print CONF << "EOT"; +# htdig configuration for doc '$identifier' +# +# This file has been automatically created by KHelpcenter +common_dir: $commondir +locale: $locale +database_dir: $htdigdb +database_base: \${database_dir}/$identifier +local_urls: help://=@HTML_INSTALL_DIR@/en/ file://=/ +local_urls_only: true +limit_urls_to: file:// help:/ +ignore_noindex: true +max_hop_count: 4 +robotstxt_name: kdedig +compression_level: 6 +template_map: Long long @DATA_INSTALL_DIR@/khelpcenter/searchhandlers/htdig/htdig_long.html +search_algorithm: exact:1 prefix:0.8 +maximum_pages: 1 +matches_per_page: 10 +start_url: file://$tmpdir/index.html +external_parsers: text/docbook $parserfile +valid_extensions: .docbook .html +mime_types: $mimetypefile +EOT +close CONF; + +my $ret = system( "$htdigbin/htdig", "-v", "-s", "-i", "-c", $conffile ); +if ( $ret != 0 ) { + print STDERR "htdig failed\n"; +} else { + $ret = system( "$htdigbin/htmerge", "-c", $conffile ); + if ( $ret != 0 ) { print STDERR "htmerge failed\n"; } +} + +if ( $ret == 0 ) { + my $existsfile = "$indexdir/$identifier.exists"; + + if ( !open( EXISTS, ">$existsfile" ) ) { + print STDERR "Unable to open '$existsfile' for writing.\n"; + exit 1; + } + print EXISTS "$identifier\n"; + close EXISTS; + + print "Finished successfully.\n"; +} + +exit $ret; + +sub dbg($) +{ + $dbg && print STDERR shift, "\n"; +} + +sub usage() +{ + print "Usage: khc_docbookdig.pl --indexdir --docpath "; + print "--identifier \n"; + exit 1; +} diff --git a/khelpcenter/searchhandlers/khc_htdig.pl.cmake b/khelpcenter/searchhandlers/khc_htdig.pl.cmake new file mode 100755 index 00000000..511adc83 --- /dev/null +++ b/khelpcenter/searchhandlers/khc_htdig.pl.cmake @@ -0,0 +1,148 @@ +#!/usr/bin/perl +# +# Wrapper script for creating search indices for htdig. +# +# This file is part of the SuSE help system. +# +# Copyright (C) 2002 SuSE Linux AG, Nuernberg +# +# Author: Cornelius Schumacher +# +# 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 + +use strict; + +use Getopt::Long; + +my $htdigdata = "/srv/www/htdig/common/"; +my $htdigbin = "/usr/bin"; +my $kdeprefix = "@CMAKE_INSTALL_PREFIX@"; +chomp $kdeprefix; + +my $dbg = 1; + +my ($indexdir, $docpath, $identifier, $lang, $help ); + +GetOptions ( + 'indexdir=s' => \$indexdir, + 'docpath=s' => \$docpath, + 'identifier=s' => \$identifier, + 'lang=s' => \$lang, + 'help' => \$help, +); + +if ( $help ) { + usage(); +} + +if ( !$indexdir || !$docpath || !$identifier ) { + print STDERR "Missing arguments.\n"; + usage(); +} + +if ( !$lang ) { $lang = "en"; } + +&dbg( "INDEXDIR: $indexdir" ); + +print "Creating index for '$identifier'\n"; + +my $htdigconf = $indexdir; +my $htdigdb = $indexdir; + +my $conffile = "$htdigconf/$identifier.conf"; + +if ( !open( CONF, ">$conffile" ) ) { + print STDERR "Unable to open '$conffile' for writing.\n"; + exit 1; +} + +my $commondir = "$htdigdata/$lang"; +if ( !$lang || !-e $commondir ) { + $commondir = "$htdigdata/en"; +} +if ( !-e $commondir ) { $commondir = $htdigdata; } + +my $locale; +if ( $lang eq "de" ) { $locale = "de_DE"; } +else { $locale = $lang; } + +print CONF << "EOT"; +# htdig configuration for doc '$identifier' +# +# This file has been automatically created by KHelpcenter + +common_dir: $commondir +locale: $locale +database_dir: $htdigdb +local_urls: http://localhost= +local_urls_only: true +limit_urls_to: http://localhost +ignore_noindex: true +max_hop_count: 4 +robotstxt_name: kdedig +compression_level: 6 +template_map: Long long $kdeprefix/share/apps/khelpcenter/searchhandlers/htdig/htdig_long.html \\ + Short short $htdigdata/short.html +search_algorithm: exact:1 prefix:0.8 +maximum_pages: 1 +matches_per_page: 10 +database_base: \${database_dir}/$identifier +start_url: http://localhost/$docpath +# for pdf-files +max_doc_size: 5000000 +external_parsers: application/pdf /usr/share/doc/packages/htdig/contrib/parse_doc.pl application/postscript /usr/share/doc/packages/htdig/contrib/parse_doc.pl +#external_parsers: text/docbook /build/htdig/parser +EOT + +close CONF; + +$ENV{ PATH } = ''; +$ENV{ CDPATH } = ''; +$ENV{ ENV } = ''; + +my $ret = system( "$htdigbin/htdig", "-s", "-i", "-c", $conffile ); +if ( $ret != 0 ) { + print STDERR "htdig failed\n"; +} else { + $ret = system( "$htdigbin/htmerge", "-c", $conffile ); + if ( $ret != 0 ) { print STDERR "htmerge failed\n"; } +} + +if ( $ret == 0 ) { + my $existsfile = "$indexdir/$identifier.exists"; + + if ( !open( EXISTS, ">$existsfile" ) ) { + print STDERR "Unable to open '$existsfile' for writing.\n"; + exit 1; + } + print EXISTS "$identifier\n"; + close EXISTS; + + print "Finished successfully.\n"; +} + +exit $ret; + +sub dbg($) +{ + $dbg && print STDERR shift, "\n"; +} + +sub usage() +{ + print "Usage: khc_htdig.pl --indexdir --docpath "; + print "--identifier \n"; + exit 1; +} diff --git a/khelpcenter/searchhandlers/khc_htsearch.pl b/khelpcenter/searchhandlers/khc_htsearch.pl new file mode 100755 index 00000000..5dc3f5f7 --- /dev/null +++ b/khelpcenter/searchhandlers/khc_htsearch.pl @@ -0,0 +1,117 @@ +#!/usr/bin/perl + +use strict; + +use Encode; +use Getopt::Long; + +use open IO => ':utf8'; +use open ':std'; + +my $htsearchpath="/srv/www/cgi-bin/htsearch"; +my $config; +my $format; +my $method; +my $words; +my $lang; +my $docbook; +my $indexdir; +my $maxnum; + +GetOptions ( + 'binary=s' => \$htsearchpath, + 'config=s' => \$config, + 'format=s' => \$format, + 'method=s' => \$method, + 'words=s' => \$words, + 'lang=s' => \$lang, + 'docbook' => \$docbook, + 'indexdir=s' => \$indexdir, + 'maxnum=s' => \$maxnum +); + +if ( !$indexdir ) { + print STDERR "No index dir given.\n"; + exit 1; +} + +if ( !$lang ) { $lang = "en"; } + +my $charset = langCharset( $lang ); + +$words = encode( $charset, $words ); + +if ( !open( HTSEARCH, "-|", "$htsearchpath", "-c", "$indexdir/$config.conf", + "format=$format&method=$method&words=$words&matchesperpage=$maxnum&exclude=[index.html]" ) ) +{ + print "Can't execute htsearch at '$htsearchpath'.\n"; + exit 1; +} + +my ($body,$liststart,$ref,$link,$error,$errorOut); + +while( ) { + if ( !$body ) { + print; + if ( /^/ ) { + print; + print "
    \n"; + $liststart = 1; + } + if ( /^(.*)<\/a>/ ) { + $ref = $1; + $link = $2; + + print STDERR "REF: $ref LINK: $link\n"; + + $ref =~ s/file:\/\/localhost//; + + $ref =~ s/http:\/\/localhost\//file:\//; + + if ( $docbook ) { + $ref =~ /help:\/\/(.*)\/index.docbook/; + my $app = $1; + $ref = "help:$app"; + + $link =~ s/apptitle/$app/; + } + + print "
  • $link
  • \n"; + } + if ( /^

    ht:\/\/Dig error/ ) { + $error = 1; + print "Htdig error:\n"; + } + if ( $error && /^
    / ) {
    +    $errorOut = 1;
    +  }
    +  if ( $errorOut ) {
    +    print;
    +    if ( /^<\/pre>/ ) { $errorOut = 0; }
    +  }
    +}
    +
    +close HTSEARCH;
    +
    +if ( $liststart ) { print "

\n"; } + +print "\n"; + +if ( $? != 0 ) { exit $?; } + +1; + +# Return charset used for given language +sub langCharset( $ ) +{ + my $lang = shift; + if ( $lang eq "cz" || $lang eq "hu" ) { + return "latin2"; + } elsif ( $lang eq "kr" ) { + return "utf8"; + } else { + return "latin1"; + } +} diff --git a/khelpcenter/searchhandlers/khc_mansearch.pl b/khelpcenter/searchhandlers/khc_mansearch.pl new file mode 100755 index 00000000..a68fde75 --- /dev/null +++ b/khelpcenter/searchhandlers/khc_mansearch.pl @@ -0,0 +1,84 @@ +#!/usr/bin/perl +# +# Script for searching man pages. The result is generated as HTML. +# +# This file is part of KHelpcenter. +# +# Copyright (C) 2002 SuSE Linux AG, Nuernberg +# +# Author: Cornelius Schumacher +# +# 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 + +use strict; + +use Getopt::Long; + +my ( $words, $maxcount, $lang, $help ); + +GetOptions ( + 'maxcount=s' => \$maxcount, + 'words=s' => \$words, + 'lang=s' => \$lang, + 'help' => \$help +); + +if ( $help ) { + print STDERR "Usage: khc_mansearch.pl --maxcount=n --words= " . + "--lang=\n"; + exit 1; +} + +if ( !$words ) { + print STDERR "No search words given.\n"; + exit; +} + +# Perform search +if ( !open( MAN, "-|", "apropos", $words ) ) { + print "Can't open apropos.\n"; + exit 1; +} +my @results; +while( ) { +# print "RAW:$_"; + chop; + /^([^\s]+)\s+\((.*)\)\s+-\s+(.*)$/; + my $page = $1; + my $section = $2; + my $description = $3; + + if ( $page ) { push @results, [ $page, $section, $description ]; } +} +close MAN; + +my $nummatches = @results; + +if ( $nummatches > 0 ) { + print "
    \n"; + + my $count = 0; + for my $result ( @results ) { + my ( $page, $section, $description ) = @$result; + my $url = "man:" . $page; + print "
  • "; + print "$page - $description
  • \n"; + if ( ++$count == $maxcount ) { last; } + } + + print "
\n"; +} + +1; diff --git a/khelpcenter/searchhandlers/man.desktop.cmake b/khelpcenter/searchhandlers/man.desktop.cmake new file mode 100644 index 00000000..f31bf4ea --- /dev/null +++ b/khelpcenter/searchhandlers/man.desktop.cmake @@ -0,0 +1,4 @@ +[Desktop Entry] +DocumentTypes=text/man + +SearchCommand=${LIBEXEC_INSTALL_DIR}/khc_mansearch.pl --words=%w --maxcount=%m diff --git a/khelpcenter/searchwidget.cpp b/khelpcenter/searchwidget.cpp new file mode 100644 index 00000000..da6ee59b --- /dev/null +++ b/khelpcenter/searchwidget.cpp @@ -0,0 +1,407 @@ + +/* + * searchwidget.cpp - part of the KDE Help Center + * + * Copyright (C) 1999 Matthias Elter (me@kde.org) + * (C) 2000 Matthias Hoelzer-Kluepfel (hoelzer@kde.org) + * + * 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 "searchwidget.h" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "scopeitem.h" +#include "docentrytraverser.h" +#include "kcmhelpcenter.h" +#include "prefs.h" +#include "searchengine.h" + +namespace KHC { + +SearchWidget::SearchWidget( SearchEngine *engine, QWidget *parent ) + : QWidget( parent ), mEngine( engine ), + mScopeCount( 0 ) +{ + QDBusConnection::sessionBus().registerObject("/SearchWidget", this, QDBusConnection::ExportScriptableSlots); + + QBoxLayout *topLayout = new QVBoxLayout( this ); + topLayout->setMargin( 2 ); + topLayout->setSpacing( 2 ); + + QBoxLayout *hLayout = new QHBoxLayout(); + topLayout->addLayout( hLayout ); + + mMethodCombo = new QComboBox( this ); + mMethodCombo->addItem( i18n("and") ); + mMethodCombo->addItem( i18n("or") ); + + QLabel *l = new QLabel( i18n("&Method:"), this ); + l->setBuddy( mMethodCombo ); + + hLayout->addWidget( l ); + hLayout->addWidget( mMethodCombo ); + + hLayout = new QHBoxLayout(); + topLayout->addLayout( hLayout ); + + mPagesCombo = new QComboBox( this ); + mPagesCombo->addItem( QLatin1String("5") ); + mPagesCombo->addItem( QLatin1String("10") ); + mPagesCombo->addItem( QLatin1String("25") ); + mPagesCombo->addItem( QLatin1String("50") ); + mPagesCombo->addItem( QLatin1String("1000") ); + + l = new QLabel( i18n("Max. &results:"), this ); + l->setBuddy( mPagesCombo ); + + hLayout->addWidget( l ); + hLayout->addWidget( mPagesCombo ); + + hLayout = new QHBoxLayout(); + topLayout->addLayout( hLayout ); + + mScopeCombo = new QComboBox( this ); + for (int i=0; i < ScopeNum; ++i ) { + mScopeCombo->addItem( scopeSelectionLabel( i ) ); + } + connect( mScopeCombo, SIGNAL( activated( int ) ), + SLOT( scopeSelectionChanged( int ) ) ); + + l = new QLabel( i18n("&Scope selection:"), this ); + l->setBuddy( mScopeCombo ); + + hLayout->addWidget( l ); + hLayout->addWidget( mScopeCombo ); + + mScopeListView = new QTreeWidget( this ); + mScopeListView->setColumnCount( 1 ); + mScopeListView->setHeaderLabels( QStringList() << i18n("Scope") ); + topLayout->addWidget( mScopeListView, 1 ); + + QPushButton *indexButton = new QPushButton( i18n("Build Search &Index..."), + this ); + connect( indexButton, SIGNAL( clicked() ), SIGNAL( showIndexDialog() ) ); + topLayout->addWidget( indexButton ); + +// FIXME: Use SearchHandler on double-clicked document +#if 0 + connect( mScopeListView, SIGNAL(itemDoubleClicked(QTreeWidgetItem*,int) ), + SLOT(scopeDoubleClicked(QTreeWidgetItem*)) ); +#endif + connect( mScopeListView, SIGNAL(itemClicked(QTreeWidgetItem*,int)), + SLOT(scopeClicked(QTreeWidgetItem*)) ); +} + + +SearchWidget::~SearchWidget() +{ + writeConfig( KGlobal::config().data() ); +} + + +void SearchWidget::readConfig( KConfig *cfg ) +{ + KConfigGroup searchGroup(cfg, "Search"); + int scopeSelection = searchGroup.readEntry( "ScopeSelection", (int)ScopeDefault ); + mScopeCombo->setCurrentIndex( scopeSelection ); + if ( scopeSelection != ScopeDefault ) scopeSelectionChanged( scopeSelection ); + + mMethodCombo->setCurrentIndex( Prefs::method() ); + mPagesCombo->setCurrentIndex( Prefs::maxCount() ); + + if ( scopeSelection == ScopeCustom ) { + KConfigGroup searchScopeGroup(cfg, "Custom Search Scope" ); + QTreeWidgetItemIterator it( mScopeListView ); + while( *it ) { + if ( (*it)->type() == ScopeItem::rttiId() ) { + ScopeItem *item = static_cast(*it); + item->setOn( searchScopeGroup.readEntry( + item->entry()->identifier(), + item->isOn() ) ); + } + ++it; + } + } + + checkScope(); +} + +void SearchWidget::writeConfig( KConfig *cfg ) +{ + KConfigGroup cg (cfg, "Search"); + + cg.writeEntry( "ScopeSelection", mScopeCombo->currentIndex() ); + Prefs::setMethod( mMethodCombo->currentIndex() ); + Prefs::setMaxCount( mPagesCombo->currentIndex() ); + + if ( mScopeCombo->currentIndex() == ScopeCustom ) { + KConfigGroup cg2 (cfg, "Custom Search Scope"); + QTreeWidgetItemIterator it( mScopeListView ); + while( (*it) ) { + if ( (*it)->type() == ScopeItem::rttiId() ) { + ScopeItem *item = static_cast( (*it) ); + cg2.writeEntry( item->entry()->identifier(), item->isOn() ); + } + ++it; + } + } +} + +void SearchWidget::slotSwitchBoxes() +{ + QTreeWidgetItemIterator it( mScopeListView ); + while( (*it) ) { + if ( (*it)->type() == ScopeItem::rttiId() ) { + ScopeItem *item = static_cast( (*it) ); + item->setOn( !item->isOn() ); + } + ++it; + } + + checkScope(); +} + +void SearchWidget::scopeSelectionChanged( int id ) +{ + QTreeWidgetItemIterator it( mScopeListView ); + while( (*it) ) { + if ( (*it)->type() == ScopeItem::rttiId() ) { + ScopeItem *item = static_cast( (*it) ); + bool state = item->isOn(); + switch( id ) { + case ScopeDefault: + state = item->entry()->searchEnabledDefault(); + break; + case ScopeAll: + state = true; + break; + case ScopeNone: + state = false; + break; + default: + break; + } + if ( state != item->isOn() ) { + item->setOn( state ); + } + } + ++it; + } + + checkScope(); +} + +QString SearchWidget::method() +{ + QString m = "and"; + if ( mMethodCombo->currentIndex() == 1) + m = "or"; + + return m; +} + +int SearchWidget::pages() +{ + int p = mPagesCombo->currentText().toInt(); + + return p; +} + +QString SearchWidget::scope() +{ + QString scope; + + QTreeWidgetItemIterator it( mScopeListView ); + while( (*it) ) { + if ( (*it)->type() == ScopeItem::rttiId() ) { + ScopeItem *item = static_cast( (*it) ); + if ( item->isOn() ) { + if ( !scope.isEmpty() ) scope += '&'; + scope += QLatin1String("scope=") + item->entry()->identifier(); + } + } + ++it; + } + + return scope; +} + +class ScopeTraverser : public DocEntryTraverser +{ + public: + ScopeTraverser( SearchWidget *widget, int level ) : + mWidget( widget ), mLevel( level ), mParentItem( 0 ) {} + + ~ScopeTraverser() + { + if( mParentItem && !mParentItem->childCount() ) delete mParentItem; + } + + void process( DocEntry *entry ) + { + if ( mWidget->engine()->canSearch( entry ) && + ( !mWidget->engine()->needsIndex( entry ) || + entry->indexExists( Prefs::indexDirectory() ) ) ) { + ScopeItem *item = 0; + if ( mParentItem ) { + item = new ScopeItem( mParentItem, entry ); + } else { + item = new ScopeItem( mWidget->listView(), entry ); + } + item->setOn( entry->searchEnabled() ); + } + } + + DocEntryTraverser *createChild( DocEntry *entry ) + { + if ( mLevel >= mNestingLevel ) { + ++mLevel; + return this; + } else { + ScopeTraverser *t = new ScopeTraverser( mWidget, mLevel + 1 ); + QTreeWidgetItem *item = 0; + if ( mParentItem ) { + item = new QTreeWidgetItem( mParentItem, QStringList() << entry->name() ); + } else { + item = new QTreeWidgetItem( mWidget->listView(), QStringList() << entry->name() ); + } + item->setExpanded( true ); + t->mParentItem = item; + return t; + } + } + + DocEntryTraverser *parentTraverser() + { + if ( mLevel > mNestingLevel ) return this; + else return mParent; + } + + void deleteTraverser() + { + if ( mLevel > mNestingLevel ) --mLevel; + else delete this; + } + + private: + SearchWidget *mWidget; + int mLevel; + QTreeWidgetItem *mParentItem; + + static int mNestingLevel; +}; + +int ScopeTraverser::mNestingLevel = 2; + +void SearchWidget::searchIndexUpdated() +{ + KGlobal::config()->reparseConfiguration(); + updateScopeList(); + update(); +} + +void SearchWidget::updateScopeList() +{ + mScopeListView->clear(); + + ScopeTraverser t( this, 0 ); + DocMetaInfo::self()->traverseEntries( &t ); + + checkScope(); +} + +void SearchWidget::scopeDoubleClicked( QTreeWidgetItem* item ) +{ + if ( !item || item->type() != ScopeItem::rttiId() ) return; + ScopeItem *scopeItem = static_cast( item ); + + QString searchUrl = scopeItem->entry()->search(); + + kDebug() << "DoubleClick: " << searchUrl; + + emit searchResult( searchUrl ); +} + +void SearchWidget::scopeClicked( QTreeWidgetItem* ) +{ + checkScope(); + + mScopeCombo->setCurrentIndex( ScopeCustom ); +} + +QString SearchWidget::scopeSelectionLabel( int id ) const +{ + switch( id ) { + case ScopeCustom: + return i18nc("Label for searching documentation using custom (user defined) scope", "Custom"); + case ScopeDefault: + return i18nc("Label for searching documentation using default search scope", "Default"); + case ScopeAll: + return i18nc("Label for searching documentation in all subsections", "All"); + case ScopeNone: + return i18nc("Label for scope that deselects all search subsections", "None"); + default: + return i18nc("Label for Unknown search scope, that should never appear", "unknown"); + } +} + +void SearchWidget::checkScope() +{ + mScopeCount = 0; + + QTreeWidgetItemIterator it( mScopeListView ); + while( (*it) ) { + if ( (*it)->type() == ScopeItem::rttiId() ) { + ScopeItem *item = static_cast( (*it) ); + if ( item->isOn() ) { + ++mScopeCount; + } + item->entry()->enableSearch( item->isOn() ); + } + ++it; + } + + emit scopeCountChanged( mScopeCount ); +} + +int SearchWidget::scopeCount() const +{ + return mScopeCount; +} + +} + +#include "searchwidget.moc" + +// vim:ts=2:sw=2:et diff --git a/khelpcenter/searchwidget.h b/khelpcenter/searchwidget.h new file mode 100644 index 00000000..fb676083 --- /dev/null +++ b/khelpcenter/searchwidget.h @@ -0,0 +1,103 @@ +/* + * searchwidget.h - part of the KDE Help Center + * + * Copyright (C) 1999 Matthias Elter (me@kde.org) + * + * 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. + */ + +#ifndef KHC_SEARCHWIDGET_H +#define KHC_SEARCHWIDGET_H + +#include +#include + +#include "docmetainfo.h" + +class QTreeWidgetItem; +class QTreeWidget; +class QTreeWidgetItem; +class QComboBox; + +class KConfig; + + +namespace KHC { + +class SearchEngine; + +class SearchWidget : public QWidget +{ + Q_OBJECT + Q_CLASSINFO("D-Bus Interface", "org.kde.khelpcenter.searchwidget") + +public Q_SLOTS: + Q_SCRIPTABLE Q_NOREPLY void searchIndexUpdated(); // called from kcmhelpcenter + + public: + explicit SearchWidget ( SearchEngine *, QWidget *parent = 0 ); + ~SearchWidget(); + + QString method(); + int pages(); + QString scope(); + + QTreeWidget *listView() { return mScopeListView; } + + enum { ScopeDefault, ScopeAll, ScopeNone, ScopeCustom, ScopeNum }; + + QString scopeSelectionLabel( int ) const; + + void readConfig( KConfig * ); + void writeConfig( KConfig * ); + + int scopeCount() const; + + SearchEngine *engine() const { return mEngine; } + + Q_SIGNALS: + void searchResult( const QString &url ); + void scopeCountChanged( int ); + void showIndexDialog(); + + public Q_SLOTS: + void slotSwitchBoxes(); + void scopeSelectionChanged( int ); + void updateScopeList(); + + protected: + void checkScope(); + + protected Q_SLOTS: + void scopeDoubleClicked( QTreeWidgetItem* ); + void scopeClicked( QTreeWidgetItem* ); + + private: + void loadLanguages(); + + SearchEngine *mEngine; + + QComboBox *mMethodCombo; + QComboBox *mPagesCombo; + QComboBox *mScopeCombo; + QTreeWidget *mScopeListView; + + int mScopeCount; +}; + +} + +#endif //KHC_SEARCHWIDGET_H +// vim:ts=2:sw=2:et diff --git a/khelpcenter/table-of-contents.xslt b/khelpcenter/table-of-contents.xslt new file mode 100644 index 00000000..47b7fbb7 --- /dev/null +++ b/khelpcenter/table-of-contents.xslt @@ -0,0 +1,26 @@ + + + + + + + + + + + +<xsl:value-of select="title"/> + + + + + + +
+<xsl:value-of select="title"/> + +
+
+ +
diff --git a/khelpcenter/tests/CMakeLists.txt b/khelpcenter/tests/CMakeLists.txt new file mode 100644 index 00000000..cd44627c --- /dev/null +++ b/khelpcenter/tests/CMakeLists.txt @@ -0,0 +1,49 @@ +set( EXECUTABLE_OUTPUT_PATH ${CMAKE_CURRENT_BINARY_DIR} ) + +include_directories( ${CMAKE_CURRENT_SOURCE_DIR}/.. ) + +########### next target ############### + +set(khelpcenter_KDEINIT_SRCS + navigator.cpp + navigatoritem.cpp + navigatorappitem.cpp + view.cpp + searchwidget.cpp + searchengine.cpp + docmetainfo.cpp + docentrytraverser.cpp + formatter.cpp + glossary.cpp + toc.cpp + mainwindow.cpp + docentry.cpp + htmlsearch.cpp + history.cpp + application.cpp + treebuilder.cpp + infotree.cpp + kcmhelpcenter.cpp + htmlsearchconfig.cpp + fontdialog.cpp + plugintraverser.cpp + scrollkeepertreebuilder.cpp + searchhandler.cpp ) + +########### next target ############### + +kde4_add_kcfg_files(khelpcenter_SRCS ../prefs.kcfgc ) + +set(testmetainfo_SRCS + testmetainfo.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/../docmetainfo.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/../docentry.cpp + ${khelpcenter_SRCS} + ${CMAKE_CURRENT_SOURCE_DIR}/../docentrytraverser.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/../htmlsearch.cpp ) + + +kde4_add_executable(testmetainfo TEST ${testmetainfo_SRCS}) + +target_link_libraries(testmetainfo ${KDE4_KDEUI_LIBS} ) + diff --git a/khelpcenter/tests/testmetainfo.cpp b/khelpcenter/tests/testmetainfo.cpp new file mode 100644 index 00000000..d535fd10 --- /dev/null +++ b/khelpcenter/tests/testmetainfo.cpp @@ -0,0 +1,115 @@ +#include + +#include +#include +#include +#include + +#include "docmetainfo.h" +#include "docentrytraverser.h" + +using namespace KHC; + +class MyTraverser : public DocEntryTraverser +{ + public: + MyTraverser( const QString &indent = "" ) : mIndent( indent ) {} + + void process( DocEntry *entry ) + { + kDebug() << mIndent << entry->name() << " - WEIGHT: " << entry->weight() + << endl; +#if 0 + if ( entry->parent() ) kDebug() << mIndent << " PARENT: " + << entry->parent()->name() << endl; + if ( entry->nextSibling() ) kDebug() << mIndent << " NEXT: " + << entry->nextSibling()->name() << endl; +#endif + } + + DocEntryTraverser *createChild( DocEntry * ) + { + return new MyTraverser( mIndent + " " ); + } + + private: + QString mIndent; +}; + +class LinearTraverser : public DocEntryTraverser +{ + public: + void process( DocEntry *entry ) + { + kDebug() << "PROCESS: " << entry->name(); + } + + DocEntryTraverser *createChild( DocEntry * ) + { + return this; + } + + DocEntryTraverser *parentTraverser() + { + return this; + } + + void deleteTraverser() {} +}; + +class AsyncTraverser : public DocEntryTraverser +{ + public: + AsyncTraverser( const QString &indent = "" ) : mIndent( indent ) + { +// kDebug() << "AsyncTraverser()"; + } + + ~AsyncTraverser() + { +// kDebug() << "~AsyncTraverser()"; + } + + void process( DocEntry *entry ) + { + kDebug() << mIndent << entry->name(); + } + + DocEntryTraverser *createChild( DocEntry * ) + { +// kDebug() << "AsyncTraverser::childTraverser()"; + return new AsyncTraverser( mIndent + " " ); + } + + private: + QString mIndent; +}; + +int main(int argc,char **argv) +{ + KAboutData aboutData("testmetainfo", 0,ki18n("TestDocMetaInfo"),"0.1"); + // KComponentData componentData(&aboutData); doesn't seem to be necessary + QCoreApplication app(argc,argv); + + kDebug() << "Scanning Meta Info"; + + DocMetaInfo::self()->scanMetaInfo( ); + + kDebug() << "My TRAVERSE start"; + MyTraverser t; + DocMetaInfo::self()->startTraverseEntries( &t ); + kDebug() << "My TRAVERSE end"; + + kDebug() << "Linear TRAVERSE start"; + LinearTraverser l; + DocMetaInfo::self()->startTraverseEntries( &l ); + kDebug() << "Linear TRAVERSE end"; + + kDebug() << "Async TRAVERSE start"; + AsyncTraverser a; + DocMetaInfo::self()->startTraverseEntries( &a ); + kDebug() << "Async TRAVERSE end"; + + return 0; +} +// vim:ts=2:sw=2:et diff --git a/khelpcenter/toc.cpp b/khelpcenter/toc.cpp new file mode 100644 index 00000000..315eb522 --- /dev/null +++ b/khelpcenter/toc.cpp @@ -0,0 +1,313 @@ +/* + * This file is part of the KDE Help Center + * + * Copyright (C) 2002 Frerich Raabe (raabe@kde.org) + * + * 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 "toc.h" + +#include "docentry.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +using namespace KHC; + +class TOCItem : public NavigatorItem +{ + public: + TOCItem( TOC *parent, QTreeWidgetItem *parentItem, QTreeWidgetItem *after, const QString &text ); + + const TOC *toc() const { return m_toc; } + + private: + TOC *m_toc; +}; + +class TOCChapterItem : public TOCItem +{ + public: + TOCChapterItem( TOC *toc, NavigatorItem *parent, QTreeWidgetItem *after, const QString &title, + const QString &name ); + + virtual QString url(); + + private: + QString m_name; +}; + +class TOCSectionItem : public TOCItem +{ + public: + TOCSectionItem( TOC *toc, TOCChapterItem *parent, QTreeWidgetItem *after, const QString &title, + const QString &name ); + + virtual QString url(); + + private: + QString m_name; +}; + +bool TOC::m_alreadyWarned = false; + +TOC::TOC( NavigatorItem *parentItem ) +{ + m_parentItem = parentItem; +} + +void TOC::build( const QString &file ) +{ + QFileInfo fileInfo( file ); + QString fileName = fileInfo.absoluteFilePath(); + const QStringList resourceDirs = KGlobal::dirs()->resourceDirs( "html" ); + QStringList::ConstIterator it = resourceDirs.begin(); + QStringList::ConstIterator end = resourceDirs.end(); + for ( ; it != end; ++it ) { + if ( fileName.startsWith( *it ) ) { + fileName.remove( 0, ( *it ).length() ); + break; + } + } + + QString cacheFile = fileName.replace( '/', "__" ); +#ifdef Q_WS_WIN + cacheFile = cacheFile.replace( ':', "_" ); +#endif + m_cacheFile = KStandardDirs::locateLocal( "cache", "help/" + cacheFile ); + m_sourceFile = file; + + if ( cacheStatus() == NeedRebuild ) + buildCache(); + else + fillTree(); +} + +TOC::CacheStatus TOC::cacheStatus() const +{ + if ( !QFile::exists( m_cacheFile ) || + sourceFileCTime() != cachedCTime() ) + return NeedRebuild; + + return CacheOk; +} + +int TOC::sourceFileCTime() const +{ + struct stat stat_buf; + stat( QFile::encodeName( m_sourceFile ).data(), &stat_buf ); + + return stat_buf.st_ctime; +} + +int TOC::cachedCTime() const +{ + QFile f( m_cacheFile ); + if ( !f.open( QIODevice::ReadOnly ) ) + return 0; + + QDomDocument doc; + if ( !doc.setContent( &f ) ) + return 0; + + QDomComment timestamp = doc.documentElement().lastChild().toComment(); + + return timestamp.data().trimmed().toInt(); +} + +void TOC::buildCache() +{ + KXmlGuiWindow *mainWindow = dynamic_cast( kapp->activeWindow() ); + + KProcess *meinproc = new KProcess; + connect( meinproc, SIGNAL( finished( int, QProcess::ExitStatus) ), + this, SLOT( meinprocExited( int, QProcess::ExitStatus) ) ); + + *meinproc << KStandardDirs::locate("exe", "meinproc4"); + *meinproc << "--stylesheet" << KStandardDirs::locate( "data", "khelpcenter/table-of-contents.xslt" ); + *meinproc << "--output" << m_cacheFile; + *meinproc << m_sourceFile; + + meinproc->setOutputChannelMode(KProcess::OnlyStderrChannel); + meinproc->start(); + if (!meinproc->waitForStarted()) { + kError() << "could not start process" << meinproc->program(); + if (mainWindow && !m_alreadyWarned) { + ; // add warning message box with don't display again option + // http://api.kde.org/4.0-api/kdelibs-apidocs/kdeui/html/classKDialog.html + m_alreadyWarned = true; + } + delete meinproc; + } +} + +void TOC::meinprocExited( int exitCode, QProcess::ExitStatus exitStatus) +{ + KProcess *meinproc = static_cast(sender()); + KXmlGuiWindow *mainWindow = dynamic_cast( kapp->activeWindow() ); + + if ( exitStatus == QProcess::CrashExit || exitCode != 0 ) { + kError() << "running" << meinproc->program() << "failed with exitCode" << exitCode; + kError() << "stderr output:" << meinproc->readAllStandardError(); + if (mainWindow && !m_alreadyWarned) { + ; // add warning message box with don't display again option + // http://api.kde.org/4.0-api/kdelibs-apidocs/kdeui/html/classKDialog.html + m_alreadyWarned = true; + } + delete meinproc; + return; + } + + delete meinproc; + + // add a timestamp to the meinproc4 created xml file + QFile f( m_cacheFile ); + if ( !f.open( QIODevice::ReadWrite ) ) + return; + + QDomDocument doc; + if ( !doc.setContent( &f ) ) + return; + + QDomComment timestamp = doc.createComment( QString::number( sourceFileCTime() ) ); + doc.documentElement().appendChild( timestamp ); + + // write back updated xml content + f.seek( 0 ); + QTextStream stream( &f ); + stream.setCodec( "UTF-8" ); +#ifdef Q_WS_WIN + /* + the problem that on german systems umlauts are displayed as '?' for unknown (Qt'r related ?) reasons + is caused by wrong encoding type conversations and has been fixed in kdelibs/kdoctools + To have propper encoding tags in the xml file, QXmlDocument::save() is used. + */ + doc.save(stream, 1, QDomNode::EncodingFromTextStream); + +#else + stream << doc.toString(); +#endif + f.close(); + fillTree(); +} + +void TOC::fillTree() +{ + QFile f( m_cacheFile ); + if ( !f.open( QIODevice::ReadOnly ) ) + return; + + QDomDocument doc; + if ( !doc.setContent( &f ) ) + return; + + TOCChapterItem *chapItem = 0; + QDomNodeList chapters = doc.documentElement().elementsByTagName( "chapter" ); + for ( int chapterCount = 0; chapterCount < chapters.count(); chapterCount++ ) { + QDomElement chapElem = chapters.item( chapterCount ).toElement(); + QDomElement chapTitleElem = childElement( chapElem, QLatin1String( "title" ) ); + QString chapTitle = chapTitleElem.text().simplified(); + QDomElement chapRefElem = childElement( chapElem, QLatin1String( "anchor" ) ); + QString chapRef = chapRefElem.text().trimmed(); + + chapItem = new TOCChapterItem( this, m_parentItem, chapItem, chapTitle, chapRef ); + + TOCSectionItem *sectItem = 0; + QDomNodeList sections = chapElem.elementsByTagName( "section" ); + for ( int sectCount = 0; sectCount < sections.count(); sectCount++ ) { + QDomElement sectElem = sections.item( sectCount ).toElement(); + QDomElement sectTitleElem = childElement( sectElem, QLatin1String( "title" ) ); + QString sectTitle = sectTitleElem.text().simplified(); + QDomElement sectRefElem = childElement( sectElem, QLatin1String( "anchor" ) ); + QString sectRef = sectRefElem.text().trimmed(); + + sectItem = new TOCSectionItem( this, chapItem, sectItem, sectTitle, sectRef ); + } + } +} + +QDomElement TOC::childElement( const QDomElement &element, const QString &name ) +{ + QDomElement e; + for ( e = element.firstChild().toElement(); !e.isNull(); e = e.nextSibling().toElement() ) + if ( e.tagName() == name ) + break; + return e; +} + +void TOC::slotItemSelected( QTreeWidgetItem *item ) +{ + TOCItem *tocItem; + if ( ( tocItem = dynamic_cast( item ) ) ) + emit itemSelected( tocItem->entry()->url() ); + + item->setExpanded( !item->isExpanded() ); +} + +TOCItem::TOCItem( TOC *toc, QTreeWidgetItem *parentItem, QTreeWidgetItem *after, const QString &text ) + : NavigatorItem( new DocEntry( text ), parentItem, after ) +{ + setAutoDeleteDocEntry( true ); + m_toc = toc; +} + +TOCChapterItem::TOCChapterItem( TOC *toc, NavigatorItem *parent, QTreeWidgetItem *after, + const QString &title, const QString &name ) + : TOCItem( toc, parent, after, title ), + m_name( name ) +{ + setExpanded( false ); + entry()->setUrl(url()); +} + +QString TOCChapterItem::url() +{ + return QLatin1String("help:") + toc()->application() + QLatin1Char('/') + m_name + + QLatin1String(".html"); +} + +TOCSectionItem::TOCSectionItem( TOC *toc, TOCChapterItem *parent, QTreeWidgetItem *after, + const QString &title, const QString &name ) + : TOCItem( toc, parent, after, title ), + m_name( name ) +{ + setIcon( 0, SmallIcon( "text-plain" ) ); + entry()->setUrl(url()); +} + +QString TOCSectionItem::url() +{ + if ( static_cast( parent()->child(0) ) == this ) + return static_cast( parent() )->url() + '#' + m_name; + + return "help:" + toc()->application() + '/' + m_name + ".html"; +} + +#include "toc.moc" +// vim:ts=2:sw=2:et diff --git a/khelpcenter/toc.h b/khelpcenter/toc.h new file mode 100644 index 00000000..ede0a75d --- /dev/null +++ b/khelpcenter/toc.h @@ -0,0 +1,78 @@ + +/* + * toc.h - part of the KDE Help Center + * + * Copyright (C) 2002 Frerich Raabe (raabe@kde.org) + * + * 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. + */ + +#ifndef KHC_TOC_H +#define KHC_TOC_H + +#include "navigatoritem.h" + +#include + +#include +#include + +#include + +#include + +namespace KHC { + +class TOC : public QObject +{ + Q_OBJECT + public: + TOC( NavigatorItem *parentItem ); + + QString application() const { return m_application; } + void setApplication( const QString &application ) { m_application = application; } + + public Q_SLOTS: + void build( const QString &file ); + + Q_SIGNALS: + void itemSelected( const QString &url ); + + private Q_SLOTS: + void slotItemSelected( QTreeWidgetItem *item ); + void meinprocExited( int exitCode, QProcess::ExitStatus exitStatus); + + private: + enum CacheStatus { NeedRebuild, CacheOk }; + + CacheStatus cacheStatus() const; + int sourceFileCTime() const; + int cachedCTime() const; + QDomElement childElement( const QDomElement &e, const QString &name ); + void buildCache(); + void fillTree(); + + QString m_application; + QString m_cacheFile; + QString m_sourceFile; + + NavigatorItem *m_parentItem; + static bool m_alreadyWarned; +}; + +} + +#endif // KHC_TOC_H +// vim:ts=2:sw=2:et diff --git a/khelpcenter/treebuilder.cpp b/khelpcenter/treebuilder.cpp new file mode 100644 index 00000000..959d8e45 --- /dev/null +++ b/khelpcenter/treebuilder.cpp @@ -0,0 +1,35 @@ +/* + * This file is part of the KDE Help Center + * + * Copyright (C) 2002 Frerich Raabe + * + * 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 "treebuilder.h" + +using namespace KHC; + +TreeBuilder::TreeBuilder( QObject *parent ) + : QObject( parent ) +{ +} + +void TreeBuilder::selectURL( const QString & ) +{ +} + +#include "treebuilder.moc" + +// vim:ts=2:sw=2:et diff --git a/khelpcenter/treebuilder.h b/khelpcenter/treebuilder.h new file mode 100644 index 00000000..8ada49f9 --- /dev/null +++ b/khelpcenter/treebuilder.h @@ -0,0 +1,51 @@ + +/* + * This file is part of the KDE Help Center + * + * Copyright (C) 2002 Frerich Raabe + * + * 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. + */ + +#ifndef KHC_TREEBUILDER_H +#define KHC_TREEBUILDER_H + +#include "QtCore/QObject" + +#include + +namespace KHC +{ + +class NavigatorItem; +class TreeBuilder : public QObject +{ + Q_OBJECT + public: + TreeBuilder( QObject *parent ); + + virtual void build( NavigatorItem *item ) = 0; + + public Q_SLOTS: + virtual void selectURL( const QString &url ); + + Q_SIGNALS: + void urlSelected( const KUrl &url ); +}; + +} + +#endif // TREEBUILDER_H +// vim:ts=2:sw=2:et diff --git a/khelpcenter/version.h b/khelpcenter/version.h new file mode 100644 index 00000000..1535474f --- /dev/null +++ b/khelpcenter/version.h @@ -0,0 +1,8 @@ + +#ifndef KHC_VERSION_H +#define KHC_VERSION_H + +#define HELPCENTER_VERSION KDE_VERSION_STRING + +#endif // KHC_VERSION_H +// vim:ts=2:sw=2:et diff --git a/khelpcenter/view.cpp b/khelpcenter/view.cpp new file mode 100644 index 00000000..fc83e0f1 --- /dev/null +++ b/khelpcenter/view.cpp @@ -0,0 +1,319 @@ + +#include "view.h" + +#include "formatter.h" +#include "history.h" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +using namespace KHC; + +View::View( QWidget *parentWidget, QObject *parent, KHTMLPart::GUIProfile prof, KActionCollection *col ) + : KHTMLPart( parentWidget, parent, prof ), mState( Docu ), mActionCollection(col) +{ + setJScriptEnabled(false); + setJavaEnabled(false); + setPluginsEnabled(false); + + mFormatter = new Formatter; + if ( !mFormatter->readTemplates() ) { + kDebug() << "Unable to read Formatter templates."; + } + + m_fontScaleStepping = 10; + + connect( this, SIGNAL( setWindowCaption( const QString & ) ), + this, SLOT( setTitle( const QString & ) ) ); + connect( this, SIGNAL( popupMenu( const QString &, const QPoint& ) ), + this, SLOT( showMenu( const QString &, const QPoint& ) ) ); + + QString css = langLookup("common/kde-default.css"); + if (!css.isEmpty()) + { + QFile css_file(css); + if (css_file.open(QIODevice::ReadOnly)) + { + QTextStream s(&css_file); + QString stylesheet = s.readAll(); + preloadStyleSheet("help:/common/kde-default.css", stylesheet); + } + } + + view()->installEventFilter( this ); +} + +View::~View() +{ + delete mFormatter; +} + +void View::copySelectedText() +{ + kapp->clipboard()->setText( selectedText() ); +} + +bool View::openUrl( const KUrl &url ) +{ + mState = Docu; + return KHTMLPart::openUrl( url ); +} + +void View::saveState( QDataStream &stream ) +{ + stream << mState; + if ( mState == Docu ) + KHTMLPart::saveState( stream ); +} + +void View::restoreState( QDataStream &stream ) +{ + stream >> mState; + if ( mState == Docu ) + KHTMLPart::restoreState( stream ); +} + +QString View::langLookup( const QString &fname ) +{ + QStringList search; + + // assemble the local search paths + const QStringList localDoc = KGlobal::dirs()->resourceDirs("html"); + + // look up the different languages + for (int id=localDoc.count()-1; id >= 0; --id) + { + QStringList langs = KGlobal::locale()->languageList(); + langs.replaceInStrings("en_US", "en"); + langs.append("en"); + QStringList::ConstIterator lang; + for (lang = langs.constBegin(); lang != langs.constEnd(); ++lang) + search.append(QString("%1%2/%3").arg(localDoc[id]).arg(*lang).arg(fname)); + } + + // try to locate the file + QStringList::Iterator it; + for (it = search.begin(); it != search.end(); ++it) + { + QFileInfo info(*it); + if (info.exists() && info.isFile() && info.isReadable()) + return *it; + + QString file = (*it).left((*it).lastIndexOf('/')) + "/index.docbook"; + info.setFile(file); + if (info.exists() && info.isFile() && info.isReadable()) + return *it; + } + + return QString(); +} + +void View::setTitle( const QString &title ) +{ + mTitle = title; +} + +void View::beginSearchResult() +{ + mState = Search; + + begin(); + mSearchResult = ""; +} + +void View::writeSearchResult( const QString &str ) +{ + write( str ); + mSearchResult += str; +} + +void View::endSearchResult() +{ + end(); + if ( !mSearchResult.isEmpty() ) emit searchResultCacheAvailable(); +} + +void View::beginInternal( const KUrl &url ) +{ + mInternalUrl = url; + begin(); +} + +KUrl View::internalUrl() const +{ + return mInternalUrl; +} + +void View::lastSearch() +{ + if ( mSearchResult.isEmpty() ) return; + + mState = Search; + + begin(); + write( mSearchResult ); + end(); +} + +void View::slotIncFontSizes() +{ + setFontScaleFactor( fontScaleFactor() + m_fontScaleStepping ); +} + +void View::slotDecFontSizes() +{ + setFontScaleFactor( fontScaleFactor() - m_fontScaleStepping ); +} + +void View::showMenu( const QString& url, const QPoint& pos) +{ + KMenu pop(view()); + + if (url.isEmpty()) + { + QAction *action; + action = mActionCollection->action("go_home"); + if (action) pop.addAction( action ); + + pop.addSeparator(); + + action = mActionCollection->action("prevPage"); + if (action) pop.addAction( action ); + action = mActionCollection->action("nextPage"); + if (action) pop.addAction( action); + + pop.addSeparator(); + + pop.addAction( History::self().m_backAction ); + pop.addAction( History::self().m_forwardAction ); + } + else + { + QAction *action = pop.addAction(i18n("Copy Link Address")); + connect( action, SIGNAL( triggered() ), this, SLOT( slotCopyLink() ) ); + + mCopyURL = completeURL(url).url(); + } + + pop.exec(pos); +} + +void View::slotCopyLink() +{ + QApplication::clipboard()->setText(mCopyURL); +} + +static DOM::HTMLLinkElement findLink(const DOM::NodeList& links, const char *rel) +{ + for (unsigned i = 0; i <= links.length(); i++) { + DOM::HTMLLinkElement link(links.item(i)); + if (link.isNull()) + continue; + + if (link.rel() == rel) + return link; + } + return DOM::HTMLLinkElement(); +} + +bool View::prevPage(bool checkOnly) +{ + const DOM::NodeList links = document().getElementsByTagName("link"); + + KUrl prevURL = urlFromLinkNode( findLink(links, "prev") ); + + if (!prevURL.isValid()) + return false; + + if (!checkOnly) + emit browserExtension()->openUrlRequest(prevURL); + return true; +} + +bool View::nextPage(bool checkOnly) +{ + const DOM::NodeList links = document().getElementsByTagName("link"); + + KUrl nextURL = urlFromLinkNode( findLink(links, "next") ); + + if (!nextURL.isValid()) + return false; + + if (!checkOnly) + emit browserExtension()->openUrlRequest(nextURL); + return true; +} + +bool View::eventFilter( QObject *o, QEvent *e ) +{ + if ( e->type() != QEvent::KeyPress || + htmlDocument().links().length() == 0 ) + return KHTMLPart::eventFilter( o, e ); + + QKeyEvent *ke = static_cast( e ); + if ( ke->modifiers() & Qt::ShiftModifier && ke->key() == Qt::Key_Space ) { + // If we're on the first page, it does not make sense to go back. + if ( baseURL().path().endsWith( QLatin1String("/index.html") ) ) + return KHTMLPart::eventFilter( o, e ); + + const QScrollBar * const scrollBar = view()->verticalScrollBar(); + if ( scrollBar->value() == scrollBar->minimum() ) { + if (prevPage()) + return true; + } + } else if ( ke->key() == Qt::Key_Space ) { + const QScrollBar * const scrollBar = view()->verticalScrollBar(); + if ( scrollBar->value() == scrollBar->maximum() ) { + if (nextPage()) + return true; + } + } + return KHTMLPart::eventFilter( o, e ); +} + +KUrl View::urlFromLinkNode( const DOM::HTMLLinkElement &link ) const +{ + if ( link.isNull() ) + return KUrl(); + + DOM::DOMString domHref = link.href(); + if (domHref.isNull()) + return KUrl(); + + return KUrl(baseURL(), domHref.string()); +} + +void View::slotReload( const KUrl &url ) +{ + const_cast( settings() )->init( KGlobal::config().data() ); + KParts::OpenUrlArguments args = arguments(); + args.setReload( true ); + setArguments( args ); + if ( url.isEmpty() ) + openUrl( baseURL() ); + else + openUrl( url ); +} + +#include "view.moc" +// vim:ts=2:sw=2:et diff --git a/khelpcenter/view.h b/khelpcenter/view.h new file mode 100644 index 00000000..0d86adb2 --- /dev/null +++ b/khelpcenter/view.h @@ -0,0 +1,96 @@ + +#ifndef KHC_VIEW_H +#define KHC_VIEW_H + +#include + +#include "glossary.h" +#include "navigator.h" + +#include + +class KActionCollection; + +namespace DOM { + class Node; + class HTMLLinkElement; +} + +namespace KHC { + +class Formatter; + +class View : public KHTMLPart +{ + Q_OBJECT + public: + View( QWidget *parentWidget, QObject *parent, KHTMLPart::GUIProfile prof, + KActionCollection *col ); + + ~View(); + + virtual bool openUrl( const KUrl &url ); + + virtual void saveState( QDataStream &stream ); + virtual void restoreState( QDataStream &stream ); + + enum State { Docu, About, Search }; + + int state() const { return mState; } + QString title() const { return mTitle; } + + static QString langLookup( const QString &fname ); + + void beginSearchResult(); + void writeSearchResult( const QString & ); + void endSearchResult(); + + void beginInternal( const KUrl & ); + KUrl internalUrl() const; + + int fontScaleStepping() const { return m_fontScaleStepping; } + + Formatter *formatter() const { return mFormatter; } + + void copySelectedText(); + + public Q_SLOTS: + void lastSearch(); + void slotIncFontSizes(); + void slotDecFontSizes(); + void slotReload( const KUrl &url = KUrl() ); + void slotCopyLink(); + bool nextPage(bool checkOnly = false); + bool prevPage(bool checkOnly = false); + + Q_SIGNALS: + void searchResultCacheAvailable(); + + protected: + bool eventFilter( QObject *o, QEvent *e ); + + private Q_SLOTS: + void setTitle( const QString &title ); + void showMenu( const QString& url, const QPoint& pos); + + private: + KUrl urlFromLinkNode( const DOM::HTMLLinkElement &link ) const; + + int mState; + QString mTitle; + + QString mSearchResult; + KUrl mInternalUrl; + + int m_fontScaleStepping; + + Formatter *mFormatter; + KActionCollection *mActionCollection; + QString mCopyURL; +}; + +} + +#endif //KHC_VIEW_H + +// vim:ts=2:sw=2:et diff --git a/kiconfinder/CMakeLists.txt b/kiconfinder/CMakeLists.txt new file mode 100644 index 00000000..73aa4338 --- /dev/null +++ b/kiconfinder/CMakeLists.txt @@ -0,0 +1,5 @@ +kde4_add_executable(kiconfinder NOGUI kiconfinder.cpp) + +target_link_libraries(kiconfinder ${KDE4_KDEUI_LIBS}) + +install(TARGETS kiconfinder ${INSTALL_TARGETS_DEFAULT_ARGS} ) diff --git a/kiconfinder/Messages.sh b/kiconfinder/Messages.sh new file mode 100755 index 00000000..63efd3fd --- /dev/null +++ b/kiconfinder/Messages.sh @@ -0,0 +1,2 @@ +#! /usr/bin/env bash +$XGETTEXT *.cpp -o $podir/kiconfinder.pot diff --git a/kiconfinder/kiconfinder.cpp b/kiconfinder/kiconfinder.cpp new file mode 100644 index 00000000..34ca1beb --- /dev/null +++ b/kiconfinder/kiconfinder.cpp @@ -0,0 +1,55 @@ +/* This file is part of the KDE project + Copyright (C) 2008 David Faure + + 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, at the discretion of KDE e.V. ( which shall + act as a proxy as in section 14 of the GPLv3 ), 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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include +#include +#include +#include +#include +#include + +int main(int argc, char *argv[]) +{ + KCmdLineArgs::init( argc, argv, "kiconfinder", 0, ki18n("Icon Finder"), KDE_VERSION_STRING , ki18n("Finds an icon based on its name")); + + + KCmdLineOptions options; + + options.add("+iconname", ki18n("The icon name to look for")); + + KCmdLineArgs::addCmdLineOptions( options ); + + KComponentData instance("kiconfinder"); + + KCmdLineArgs *args = KCmdLineArgs::parsedArgs(); + if( args->count() < 1 ) { + printf( "No icon name specified\n" ); + return 1; + } + const QString iconName = args->arg( 0 ); + const QString icon = KIconLoader::global()->iconPath(iconName, KIconLoader::Desktop /*TODO configurable*/, true); + if ( !icon.isEmpty() ) { + printf("%s\n", icon.toLatin1().constData()); + } else { + return 1; // error + } + + return 0; +} diff --git a/kimgio/CMakeLists.txt b/kimgio/CMakeLists.txt new file mode 100644 index 00000000..62ee1173 --- /dev/null +++ b/kimgio/CMakeLists.txt @@ -0,0 +1,22 @@ +project(runtime_kimgio) + +find_package(KDE4 REQUIRED) +include(KDE4Defaults) + +################################## +# WebP image IO support + +find_library(FOUND_WEBP webp) +if ( FOUND_WEBP ) + set(kimg_webp_LIB_SRCS webp.cpp) + kde4_add_plugin(kimg_webp ${kimg_webp_LIB_SRCS}) + target_link_libraries(kimg_webp ${KDE4_KDECORE_LIBS} ${QT_QTGUI_LIBRARY} webp) + + install(TARGETS kimg_webp DESTINATION ${PLUGIN_INSTALL_DIR}/plugins/imageformats/) + install(FILES webp.desktop DESTINATION ${SERVICES_INSTALL_DIR}/qimageioplugins/) + + find_package(SharedMimeInfo REQUIRED) + install(FILES webp.xml DESTINATION ${XDG_MIME_INSTALL_DIR}) + update_xdg_mimetypes(${XDG_MIME_INSTALL_DIR}) +endif() + diff --git a/kimgio/webp.cpp b/kimgio/webp.cpp new file mode 100644 index 00000000..d51c1eac --- /dev/null +++ b/kimgio/webp.cpp @@ -0,0 +1,246 @@ +/* +QImageIO Routines to read/write WebP images. + +Copyright (c) 2012,2013 Martin Koller + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 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 6 of version 3 of the license. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library. If not, see . +*/ + +#include + +#include "webp.h" +#include +#include + +#include +#include + +//--------------------------------------------------------------------- + +WebPHandler::WebPHandler() + : quality(75) +{ +} + +//--------------------------------------------------------------------- + +bool WebPHandler::canRead() const +{ + if (canRead(device())) { + setFormat("webp"); + return true; + } + return false; +} + +//--------------------------------------------------------------------- + +bool WebPHandler::read(QImage *retImage) +{ + QByteArray data = device()->readAll(); + + WebPBitstreamFeatures features; + VP8StatusCode ret = WebPGetFeatures(reinterpret_cast(data.constData()), data.size(), &features); + if ( ret != VP8_STATUS_OK ) { + return false; + } + + if ( features.has_alpha ) { + *retImage = QImage(features.width, features.height, QImage::Format_ARGB32); + } else { + *retImage = QImage(features.width, features.height, QImage::Format_RGB32); + } + + if ( retImage->isNull() ) { // out of memory + return false; + } + +#if Q_BYTE_ORDER == Q_BIG_ENDIAN + if ( WebPDecodeARGBInto(reinterpret_cast(data.constData()), + data.size(), reinterpret_cast(retImage->bits()), + retImage->byteCount(), retImage->bytesPerLine()) == 0 ) { + return false; + } +#else + if ( WebPDecodeBGRAInto(reinterpret_cast(data.constData()), + data.size(), reinterpret_cast(retImage->bits()), + retImage->byteCount(), retImage->bytesPerLine()) == 0 ) { + return false; + } +#endif + + return true; +} + +//--------------------------------------------------------------------- + +bool WebPHandler::write(const QImage &image) +{ + // limitation in WebP + if ( (image.height() > 16383) || (image.height() == 0) || + (image.width() > 16383) || (image.width() == 0) ) + return false; + + uint8_t *imageData = new uint8_t[image.width() * image.height() * (3 + image.hasAlphaChannel())]; + + size_t idx = 0; + for (int y = 0; y < image.height(); y++) { + const QRgb *scanline = reinterpret_cast(image.constScanLine(y)); + for (int x = 0; x < image.width(); x++) { + imageData[idx++] = qRed(scanline[x]); + imageData[idx++] = qGreen(scanline[x]); + imageData[idx++] = qBlue(scanline[x]); + + if ( image.hasAlphaChannel() ) { + imageData[idx++] = qAlpha(scanline[x]); + } + } + } + + uint8_t *output = 0; + size_t size; + if ( image.hasAlphaChannel() ) { + size = WebPEncodeRGBA(imageData, image.width(), image.height(), image.width() * 4, quality, &output); + } else { + size = WebPEncodeRGB(imageData, image.width(), image.height(), image.width() * 4, quality, &output); + } + delete [] imageData; + + if ( size == 0 ) { + free(output); + return false; + } + + device()->write(reinterpret_cast(output), size); + free(output); + + return true; +} + +//--------------------------------------------------------------------- + +QByteArray WebPHandler::format() const +{ + return "webp"; +} + +//--------------------------------------------------------------------- + +bool WebPHandler::supportsOption(ImageOption option) const +{ + return (option == Quality) || (option == Size); +} + +//--------------------------------------------------------------------- + +QVariant WebPHandler::option(ImageOption option) const +{ + switch ( option ) + { + case Quality: + return quality; + + case Size: { + QByteArray data = device()->peek(26); + + int width = 0, height = 0; + + if ( WebPGetInfo(reinterpret_cast(data.constData()), + data.size(), &width, &height) == 0 ) + return QSize(); // header error + + return QSize(width, height); + } + + default: return QVariant(); + } +} + +//--------------------------------------------------------------------- + +void WebPHandler::setOption(ImageOption option, const QVariant &value) +{ + if (option == Quality) + quality = qBound(0, value.toInt(), 100); +} + +//--------------------------------------------------------------------- + +bool WebPHandler::canRead(QIODevice *device) +{ + if (!device) { + qWarning("WebPHandler::canRead() called with no device"); + return false; + } + + // WebP file header: 4 bytes "RIFF", 4 bytes length, 4 bytes "WEBP" + QByteArray header = device->peek(12); + + return (header.size() == 12) && header.startsWith("RIFF") && header.endsWith("WEBP"); +} + +//--------------------------------------------------------------------- +//--------------------------------------------------------------------- + +class WebPPlugin : public QImageIOPlugin +{ +public: + QStringList keys() const; + Capabilities capabilities(QIODevice *device, const QByteArray &format) const; + QImageIOHandler *create(QIODevice *device, const QByteArray &format = QByteArray()) const; +}; + +//--------------------------------------------------------------------- + +QStringList WebPPlugin::keys() const +{ + return QStringList() << "webp"; +} + +//--------------------------------------------------------------------- + +QImageIOPlugin::Capabilities WebPPlugin::capabilities(QIODevice *device, const QByteArray &format) const +{ + if (format == "webp") + return Capabilities(CanRead | CanWrite); + if (!format.isEmpty()) + return 0; + if (!device->isOpen()) + return 0; + + Capabilities cap; + if (device->isReadable() && WebPHandler::canRead(device)) + cap |= CanRead; + if (device->isWritable()) + cap |= CanWrite; + return cap; +} + +//--------------------------------------------------------------------- + +QImageIOHandler *WebPPlugin::create(QIODevice *device, const QByteArray &format) const +{ + QImageIOHandler *handler = new WebPHandler; + handler->setDevice(device); + handler->setFormat(format); + return handler; +} + +//--------------------------------------------------------------------- + +Q_EXPORT_STATIC_PLUGIN(WebPPlugin) +Q_EXPORT_PLUGIN2(webp, WebPPlugin) diff --git a/kimgio/webp.desktop b/kimgio/webp.desktop new file mode 100644 index 00000000..3526be5f --- /dev/null +++ b/kimgio/webp.desktop @@ -0,0 +1,7 @@ +[Desktop Entry] +Type=Service +X-KDE-ServiceTypes=QImageIOPlugins +X-KDE-ImageFormat=webp +X-KDE-MimeType=image/x-webp +X-KDE-Read=true +X-KDE-Write=true diff --git a/kimgio/webp.h b/kimgio/webp.h new file mode 100644 index 00000000..a58d1f16 --- /dev/null +++ b/kimgio/webp.h @@ -0,0 +1,49 @@ +/* +QImageIO Routines to read/write WebP images. + +Copyright (c) 2012,2013 Martin Koller + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 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 6 of version 3 of the license. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library. If not, see . +*/ + +#ifndef WEBP_H +#define WEBP_H + +#include + +class WebPHandler : public QImageIOHandler +{ +public: + WebPHandler(); + + virtual bool canRead() const; + virtual bool read(QImage *image); + virtual bool write(const QImage &image); + + virtual QByteArray format() const; + + virtual bool supportsOption(ImageOption option) const; + virtual QVariant option(ImageOption option) const; + virtual void setOption(ImageOption option, const QVariant &value); + + static bool canRead(QIODevice *device); + +private: + int quality; +}; + +#endif diff --git a/kimgio/webp.xml b/kimgio/webp.xml new file mode 100644 index 00000000..4246f760 --- /dev/null +++ b/kimgio/webp.xml @@ -0,0 +1,7 @@ + + + + WebP image + + + diff --git a/kioclient/CMakeLists.txt b/kioclient/CMakeLists.txt new file mode 100644 index 00000000..16d7b430 --- /dev/null +++ b/kioclient/CMakeLists.txt @@ -0,0 +1,30 @@ +set(kioclient_SRCS kioclient.cpp ) +kde4_add_executable(kioclient NOGUI ${kioclient_SRCS}) +macro_add_compile_flags(kioclient -DKIOCLIENT_AS_KIOCLIENT) +target_link_libraries(kioclient ${KDE4_KIO_LIBS}) +install(TARGETS kioclient ${INSTALL_TARGETS_DEFAULT_ARGS}) + +################ + +set(kde-open_SRCS kioclient.cpp ) +kde4_add_executable(kde-open NOGUI ${kde-open_SRCS}) +macro_add_compile_flags(kde-open -DKIOCLIENT_AS_KDEOPEN) +target_link_libraries(kde-open ${KDE4_KIO_LIBS}) +install(TARGETS kde-open ${INSTALL_TARGETS_DEFAULT_ARGS}) + +################ + +set(kde-cp_SRCS kioclient.cpp ) +kde4_add_executable(kde-cp NOGUI ${kde-cp_SRCS}) +macro_add_compile_flags(kde-cp -DKIOCLIENT_AS_KDECP) +target_link_libraries(kde-cp ${KDE4_KIO_LIBS}) +install(TARGETS kde-cp ${INSTALL_TARGETS_DEFAULT_ARGS}) + +################ + +set(kde-mv_SRCS kioclient.cpp ) +kde4_add_executable(kde-mv NOGUI ${kde-mv_SRCS}) +macro_add_compile_flags(kde-mv -DKIOCLIENT_AS_KDEMV) +target_link_libraries(kde-mv ${KDE4_KIO_LIBS}) +install(TARGETS kde-mv ${INSTALL_TARGETS_DEFAULT_ARGS}) + diff --git a/kioclient/Messages.sh b/kioclient/Messages.sh new file mode 100755 index 00000000..407cf6d8 --- /dev/null +++ b/kioclient/Messages.sh @@ -0,0 +1,2 @@ +#! /usr/bin/env bash +$XGETTEXT *.cpp -o $podir/kioclient.pot diff --git a/kioclient/kioclient.cpp b/kioclient/kioclient.cpp new file mode 100644 index 00000000..536b3dfc --- /dev/null +++ b/kioclient/kioclient.cpp @@ -0,0 +1,430 @@ +/* This file is part of the KDE project + Copyright (C) 1999-2006 David Faure + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "kioclient.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static const char appName[] = "kioclient"; +static const char programName[] = I18N_NOOP("KIO Client"); +static const char description[] = I18N_NOOP("Command-line tool for network-transparent operations"); +static const char version[] = "2.0"; + +bool ClientApp::m_ok = true; +static bool s_interactive = true; +static KIO::JobFlags s_jobFlags = KIO::DefaultFlags; + +#ifdef KIOCLIENT_AS_KIOCLIENT +static void usage() +{ + KCmdLineArgs::enable_i18n(); + puts(i18n("\nSyntax:\n").toLocal8Bit()); + puts(i18n(" kioclient openProperties 'url'\n" + " # Opens a properties menu\n\n").toLocal8Bit()); + puts(i18n(" kioclient exec 'url' ['mimetype']\n" + " # Tries to open the document pointed to by 'url', in the application\n" + " # associated with it in KDE. You may omit 'mimetype'.\n" + " # In this case the mimetype is determined\n" + " # automatically. Of course URL may be the URL of a\n" + " # document, or it may be a *.desktop file.\n" + " # 'url' can be an executable, too.\n").toLocal8Bit()); + puts(i18n(" kioclient move 'src' 'dest'\n" + " # Moves the URL 'src' to 'dest'.\n" + " # 'src' may be a list of URLs.\n").toLocal8Bit()); + puts(i18n(" # 'dest' may be \"trash:/\" to move the files\n" + " # to the trash.\n").toLocal8Bit()); + puts(i18n(" # the short version kioclient mv\n" + " # is also available.\n\n").toLocal8Bit()); + puts(i18n(" kioclient download ['src']\n" + " # Copies the URL 'src' to a user-specified location'.\n" + " # 'src' may be a list of URLs, if not present then\n" + " # a URL will be requested.\n\n").toLocal8Bit()); + puts(i18n(" kioclient copy 'src' 'dest'\n" + " # Copies the URL 'src' to 'dest'.\n" + " # 'src' may be a list of URLs.\n").toLocal8Bit()); + puts(i18n(" # the short version kioclient cp\n" + " # is also available.\n\n").toLocal8Bit()); + puts(i18n(" kioclient cat 'url'\n" + " # Writes out the contents of 'url' to stdout\n\n").toLocal8Bit()); + puts(i18n(" kioclient ls 'url'\n" + " # Lists the contents of the directory 'url' to stdout\n\n").toLocal8Bit()); + puts(i18n(" kioclient remove 'url'\n" + " # Removes the URL\n" + " # 'url' may be a list of URLs.\n").toLocal8Bit()); + puts(i18n(" # the short version kioclient rm\n" + " # is also available.\n\n").toLocal8Bit()); + + puts(i18n("*** Examples:\n" + " kioclient exec file:/root/Desktop/cdrom.desktop \"Mount default\"\n" + " // Mounts the CDROM\n\n").toLocal8Bit()); + puts(i18n(" kioclient exec file:/home/weis/data/test.html\n" + " // Opens the file with default binding\n\n").toLocal8Bit()); + puts(i18n(" kioclient exec file:/home/weis/data/test.html Netscape\n" + " // Opens the file with netscape\n\n").toLocal8Bit()); + puts(i18n(" kioclient exec ftp://localhost/\n" + " // Opens new window with URL\n\n").toLocal8Bit()); + puts(i18n(" kioclient exec file:/root/Desktop/emacs.desktop\n" + " // Starts emacs\n\n").toLocal8Bit()); + puts(i18n(" kioclient exec file:/root/Desktop/cdrom.desktop\n" + " // Opens the CDROM's mount directory\n\n").toLocal8Bit()); + puts(i18n(" kioclient exec .\n" + " // Opens the current directory. Very convenient.\n\n").toLocal8Bit()); +} +#endif + +int main( int argc, char **argv ) +{ + KCmdLineArgs::init(argc, argv, appName, 0, ki18n(programName), version, ki18n(description), KCmdLineArgs::CmdLineArgNone); + + + KCmdLineOptions options; + options.add("noninteractive", ki18n("Non-interactive use: no message boxes")); + #if !defined(KIOCLIENT_AS_KDEOPEN) + options.add("overwrite", ki18n("Overwrite destination if it exists (for copy and move)")); + #endif + #if defined(KIOCLIENT_AS_KDEOPEN) + options.add("+url", ki18n("file or URL")); + #elif defined(KIOCLIENT_AS_KDECP) + options.add("+src", ki18n("Source URL or URLs")); + options.add("+dest", ki18n("Destination URL")); + #elif defined(KIOCLIENT_AS_KDEMV) + options.add("+src", ki18n("Source URL or URLs")); + options.add("+dest", ki18n("Destination URL")); + #elif defined(KIOCLIENT_AS_KIOCLIENT) + options.add("commands", ki18n("Show available commands")); + options.add("+command", ki18n("Command (see --commands)")); + options.add("+[URL(s)]", ki18n("Arguments for command")); + #endif + + KCmdLineArgs::addCmdLineOptions( options ); + KCmdLineArgs::addTempFileOption(); + +#ifdef KIOCLIENT_AS_KIOCLIENT + KCmdLineArgs *args = KCmdLineArgs::parsedArgs(); + + if ( argc == 1 || args->isSet("commands") ) + { + usage(); + return 0; + } +#endif + + return ClientApp::doIt() ? 0 /*no error*/ : 1 /*error*/; +} + +bool krun_has_error = false; + +void ClientApp::delayedQuit() +{ + // Quit in 2 seconds. This leaves time for KRun to pop up + // "app not found" in KProcessRunner, if that was the case. + QTimer::singleShot( 2000, this, SLOT(deref()) ); + // don't access the KRun instance later, it will be deleted after calling slots + if( static_cast< const KRun* >( sender())->hasError()) + krun_has_error = true; +} + +static void checkArgumentCount(int count, int min, int max) +{ + if (count < min) + { + fputs( i18nc("@info:shell", "%1: Syntax error, not enough arguments\n", appName).toLocal8Bit(), stderr ); + ::exit(1); + } + if (max && (count > max)) + { + fputs( i18nc("@info:shell", "%1: Syntax error, too many arguments\n", appName).toLocal8Bit(), stderr ); + ::exit(1); + } +} + +bool ClientApp::kde_open(const KUrl& url, const QString& mimeType, bool allowExec) +{ + if ( mimeType.isEmpty() ) { + kDebug() << url; + KRun * run = new KRun( url, 0 ); + run->setRunExecutables(allowExec); + QObject::connect( run, SIGNAL( finished() ), this, SLOT( delayedQuit() )); + QObject::connect( run, SIGNAL( error() ), this, SLOT( delayedQuit() )); + this->exec(); + return !krun_has_error; + } else { + KUrl::List urls; + urls.append( url ); + const KService::List offers = KMimeTypeTrader::self()->query( + mimeType, QLatin1String( "Application" ) ); + if (offers.isEmpty()) return 1; + KService::Ptr serv = offers.first(); + return KRun::run( *serv, urls, 0 ); + } +} + +bool ClientApp::doCopy( int firstArg ) +{ + KCmdLineArgs *args = KCmdLineArgs::parsedArgs(); + int argc = args->count(); + KUrl::List srcLst; + for ( int i = firstArg; i <= argc - 2; i++ ) + srcLst.append( args->url(i) ); + KIO::Job * job = KIO::copy( srcLst, args->url(argc - 1), s_jobFlags ); + if ( !s_interactive ) + job->setUiDelegate( 0 ); + connect( job, SIGNAL( result( KJob * ) ), this, SLOT( slotResult( KJob * ) ) ); + this->exec(); + return m_ok; +} + +void ClientApp::slotEntries(KIO::Job* job, const KIO::UDSEntryList& list) +{ + KUrl url = static_cast( job )->url(); + KIO::UDSEntryList::ConstIterator it=list.begin(); + for (; it != list.end(); ++it) { + // For each file... + QString name = (*it).stringValue( KIO::UDSEntry::UDS_NAME ); + std::cout << qPrintable(name) << std::endl; + } +} + +bool ClientApp::doList( int firstArg ) +{ + KCmdLineArgs *args = KCmdLineArgs::parsedArgs(); + KUrl dir = args->url(firstArg); + KIO::Job * job = KIO::listDir(dir, KIO::HideProgressInfo); + if ( !s_interactive ) + job->setUiDelegate(0); + connect(job, SIGNAL(entries(KIO::Job*,KIO::UDSEntryList)), + SLOT(slotEntries(KIO::Job*,KIO::UDSEntryList))); + connect(job, SIGNAL(result(KJob *)), this, SLOT(slotResult(KJob *))); + this->exec(); + return m_ok; +} + +bool ClientApp::doMove( int firstArg ) +{ + KCmdLineArgs *args = KCmdLineArgs::parsedArgs(); + int argc = args->count(); + KUrl::List srcLst; + for ( int i = firstArg; i <= argc - 2; i++ ) + srcLst.append( args->url(i) ); + + KIO::Job * job = KIO::move( srcLst, args->url(argc - 1), s_jobFlags ); + if ( !s_interactive ) + job->setUiDelegate( 0 ); + connect( job, SIGNAL( result( KJob * ) ), this, SLOT( slotResult( KJob * ) ) ); + this->exec(); + return m_ok; +} + +bool ClientApp::doRemove( int firstArg ) +{ + KCmdLineArgs *args = KCmdLineArgs::parsedArgs(); + int argc = args->count(); + KUrl::List srcLst; + for ( int i = firstArg; i < argc; i++ ) + srcLst.append( args->url(i) ); + KIO::Job * job = KIO::del( srcLst, s_jobFlags ); + if ( !s_interactive ) + job->setUiDelegate( 0 ); + connect( job, SIGNAL( result( KJob * ) ), this, SLOT( slotResult( KJob * ) ) ); + this->exec(); + return m_ok; +} + +bool ClientApp::doIt() +{ + KCmdLineArgs *args = KCmdLineArgs::parsedArgs(); + const int argc = args->count(); + checkArgumentCount(argc, 1, 0); + + if ( !args->isSet( "ninteractive" ) ) { + s_interactive = false; + s_jobFlags = KIO::HideProgressInfo; + } +#if !defined(KIOCLIENT_AS_KDEOPEN) + if (args->isSet("overwrite")) { + s_jobFlags |= KIO::Overwrite; + } +#endif + + kDebug() << "Creating ClientApp"; + int fake_argc = 0; + char** fake_argv = 0; + ClientApp app( fake_argc, fake_argv ); + KComponentData componentData("kioclient"); // needed by KIO's internal use of KConfig + app.setApplicationName(componentData.componentName()); + KGlobal::ref(); + KGlobal::setAllowQuit(true); + + // KIO needs dbus (for uiserver communication) + extern void qDBusBindToApplication(); + qDBusBindToApplication(); + if (!QDBusConnection::sessionBus().isConnected()) + kFatal(101) << "Session bus not found" ; + +#ifdef KIOCLIENT_AS_KDEOPEN + return app.kde_open(args->url(0), QByteArray(), false); +#elif defined(KIOCLIENT_AS_KDECP) + checkArgumentCount(argc, 2, 0); + return app.doCopy(0); +#elif defined(KIOCLIENT_AS_KDEMV) + checkArgumentCount(argc, 2, 0); + return app.doMove(0); +#else + // Normal kioclient mode + const QByteArray command = args->arg(0).toLocal8Bit(); + if ( command == "openProperties" ) + { + checkArgumentCount(argc, 2, 2); // openProperties + KPropertiesDialog * p = new KPropertiesDialog( args->url(1), 0 /*no parent*/ ); + QObject::connect( p, SIGNAL( destroyed() ), &app, SLOT( quit() )); + QObject::connect( p, SIGNAL( canceled() ), &app, SLOT( slotDialogCanceled() )); + p->show(); + app.exec(); + return m_ok; + } + else if ( command == "cat" ) + { + checkArgumentCount(argc, 2, 2); // cat + KIO::TransferJob* job = KIO::get(args->url(1), KIO::NoReload, s_jobFlags); + if ( !s_interactive ) + job->setUiDelegate( 0 ); + connect(job, SIGNAL(data(KIO::Job*,QByteArray) ), &app, SLOT(slotPrintData(KIO::Job*,QByteArray))); + connect( job, SIGNAL( result( KJob * ) ), &app, SLOT( slotResult( KJob * ) ) ); + app.exec(); + return m_ok; + } + else if ( command == "exec" ) + { + checkArgumentCount(argc, 2, 3); + return app.kde_open( args->url( 1 ), + argc == 3 ? args->arg( 2 ) : QString(), + true ); + } + else if ( command == "download" ) + { + checkArgumentCount(argc, 0, 0); + KUrl::List srcLst; + if (argc == 1) { + while(true) { + KUrl src = KUrlRequesterDialog::getUrl(); + if (!src.isEmpty()) { + if (!src.isValid()) { + KMessageBox::error(0, i18n("Unable to download from an invalid URL.")); + continue; + } + srcLst.append(src); + } + break; + } + } else { + for ( int i = 1; i <= argc - 1; i++ ) + srcLst.append( args->url(i) ); + } + if (srcLst.count() == 0) + return m_ok; + QString dst = + KFileDialog::getSaveFileName( (argc<2) ? QString() : (args->url(1).fileName()) ); + if (dst.isEmpty()) // canceled + return m_ok; // AK - really okay? + KUrl dsturl; + dsturl.setPath( dst ); + KIO::Job * job = KIO::copy( srcLst, dsturl, s_jobFlags ); + if ( !s_interactive ) + job->setUiDelegate( 0 ); + connect( job, SIGNAL( result( KJob * ) ), &app, SLOT( slotResult( KJob * ) ) ); + app.exec(); + return m_ok; + } + else if ( command == "copy" || command == "cp" ) + { + checkArgumentCount(argc, 3, 0); // cp + return app.doCopy( 1 ); + } + else if ( command == "move" || command == "mv" ) + { + checkArgumentCount(argc, 3, 0); // mv + return app.doMove( 1 ); + } + else if ( command == "list" || command == "ls" ) + { + checkArgumentCount(argc, 2, 2); // ls + return app.doList( 1 ); + } + else if ( command == "remove" || command == "rm" ) + { + checkArgumentCount(argc, 2, 0); // rm + return app.doRemove( 1 ); + } + else + { + fputs( i18nc("@info:shell", "%1: Syntax error, unknown command '%2'\n", appName, QString::fromLocal8Bit(command)).toLocal8Bit().data(), stderr ); + return false; + } + return true; +#endif +} + +void ClientApp::slotResult( KJob * job ) +{ + if (job->error() && s_interactive) + static_cast(job)->ui()->showErrorMessage(); + m_ok = !job->error(); + quit(); +} + +void ClientApp::slotDialogCanceled() +{ + m_ok = false; + quit(); +} + +void ClientApp::deref() +{ + KGlobal::deref(); +} + +void ClientApp::slotPrintData(KIO::Job*, const QByteArray &data) +{ + if (!data.isEmpty()) + std::cout.write(data.constData(), data.size()); +} + +ClientApp::ClientApp(int &argc, char **argv ) + : QApplication( argc, argv, s_interactive /*-> bool GUIenabled*/ ) +{ +} + +#include "kioclient.moc" diff --git a/kioclient/kioclient.h b/kioclient/kioclient.h new file mode 100644 index 00000000..0044d328 --- /dev/null +++ b/kioclient/kioclient.h @@ -0,0 +1,55 @@ +/* This file is part of the KDE project + Copyright (C) 1999-2006 David Faure + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef __kioclient_h +#define __kioclient_h + +#include +#include +class KUrl; +class KJob; +namespace KIO { class Job; } + +class ClientApp : public QApplication +{ + Q_OBJECT +public: + ClientApp(int &argc, char **argv ); + + /** Parse command-line arguments and "do it" */ + static bool doIt(); + +private Q_SLOTS: + void slotPrintData(KIO::Job *job, const QByteArray &data); + void slotEntries(KIO::Job* job, const KIO::UDSEntryList& ); + void slotResult( KJob * ); + void delayedQuit(); + void slotDialogCanceled(); + void deref(); + +private: + bool kde_open( const KUrl& url, const QString& mimeType, bool allowExec ); + bool doCopy( int firstArg ); + bool doMove( int firstArg ); + bool doList( int firstArg ); + bool doRemove( int firstArg ); + + static bool m_ok; +}; + +#endif diff --git a/kioexec/CMakeLists.txt b/kioexec/CMakeLists.txt new file mode 100644 index 00000000..b4eefe8c --- /dev/null +++ b/kioexec/CMakeLists.txt @@ -0,0 +1,9 @@ +set(kioexec_SRCS main.cpp ) + + +kde4_add_executable(kioexec NOGUI ${kioexec_SRCS}) + +target_link_libraries(kioexec ${KDE4_KIO_LIBS}) + +install(TARGETS kioexec DESTINATION ${LIBEXEC_INSTALL_DIR} ) + diff --git a/kioexec/Messages.sh b/kioexec/Messages.sh new file mode 100644 index 00000000..e12fe20c --- /dev/null +++ b/kioexec/Messages.sh @@ -0,0 +1,2 @@ +#! /usr/bin/env bash +$XGETTEXT *.cpp -o $podir/kioexec.pot diff --git a/kioexec/README b/kioexec/README new file mode 100644 index 00000000..78e0b3da --- /dev/null +++ b/kioexec/README @@ -0,0 +1,26 @@ +kioexec is launched when the user wants to open a remote file with +an application that only supports local files. + +For this it does the following: +- downloads a remote file to a temp location +- starts a 'local' application with that temp file as argument +- wait fors application to be exited +- if the modification time of the file is different from the original one, +(because the file was modified) then it offers re-uploading the modified version. +This is how you offer network transparency to apps that don't have it. + +BUT: with KUniqueApplication, this breaks, because the app returns at once, +so we have no way to know when the user finished editing the file... + +Conclusion: if the application has network transparency built-in, it should +put "%u" in its desktop file - and kioexec isn't used -. If it doesn't, either +it's a KApplication and kiiooexec does its job, or it's a KUniqueApplication +and... kioexec can't see modifications to the file. Be warned. + +From Waldo: "The program doesn't return _at once_. It returns +after "newInstance()" returns. So if you open the file there it will still work. +(Or rename it)" + +David Faure +20-May-2000 + diff --git a/kioexec/main.cpp b/kioexec/main.cpp new file mode 100644 index 00000000..06cd8f31 --- /dev/null +++ b/kioexec/main.cpp @@ -0,0 +1,283 @@ +/* This file is part of the KDE project + Copyright (C) 1998, 1999 Torben Weis + Copyright (C) 2000-2005 David Faure + Copyright (C) 2001 Waldo Bastian + + 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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "main.h" + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static const char description[] = + I18N_NOOP("KIO Exec - Opens remote files, watches modifications, asks for upload"); + + +KIOExec::KIOExec() + : mExited(false) +{ + KCmdLineArgs *args = KCmdLineArgs::parsedArgs(); + if (args->count() < 1) + KCmdLineArgs::usageError(i18n("'command' expected.\n")); + + tempfiles = args->isSet("tempfiles"); + if ( args->isSet( "suggestedfilename" ) ) + suggestedFileName = args->getOption( "suggestedfilename" ); + expectedCounter = 0; + jobCounter = 0; + command = args->arg(0); + kDebug() << "command=" << command; + + for ( int i = 1; i < args->count(); i++ ) + { + KUrl url = args->url(i); + url = KIO::NetAccess::mostLocalUrl( url, 0 ); + + //kDebug() << "url=" << url.url() << " filename=" << url.fileName(); + // A local file, not an URL ? + // => It is not encoded and not shell escaped, too. + if ( url.isLocalFile() ) + { + FileInfo file; + file.path = url.toLocalFile(); + file.url = url; + fileList.append(file); + } + // It is an URL + else + { + if ( !url.isValid() ) + KMessageBox::error( 0L, i18n( "The URL %1\nis malformed" , url.url() ) ); + else if ( tempfiles ) + KMessageBox::error( 0L, i18n( "Remote URL %1\nnot allowed with --tempfiles switch" , url.url() ) ); + else + // We must fetch the file + { + QString fileName = KIO::encodeFileName( url.fileName() ); + if ( !suggestedFileName.isEmpty() ) + fileName = suggestedFileName; + // Build the destination filename, in ~/.kde/cache-*/krun/ + // Unlike KDE-1.1, we put the filename at the end so that the extension is kept + // (Some programs rely on it) + QString tmp = KGlobal::dirs()->saveLocation( "cache", "krun/" ) + + QString("%1_%2_%3").arg(getpid()).arg(jobCounter++).arg(fileName); + FileInfo file; + file.path = tmp; + file.url = url; + fileList.append(file); + + expectedCounter++; + KUrl dest; + dest.setPath( tmp ); + kDebug() << "Copying " << url.prettyUrl() << " to " << dest; + KIO::Job *job = KIO::file_copy( url, dest ); + jobList.append( job ); + + connect( job, SIGNAL( result( KJob * ) ), SLOT( slotResult( KJob * ) ) ); + } + } + } + args->clear(); + + if ( tempfiles ) + { + slotRunApp(); + return; + } + + counter = 0; + if ( counter == expectedCounter ) + slotResult( 0L ); +} + +void KIOExec::slotResult( KJob * job ) +{ + if (job && job->error()) + { + // That error dialog would be queued, i.e. not immediate... + //job->showErrorDialog(); + if ( (job->error() != KIO::ERR_USER_CANCELED) ) + KMessageBox::error( 0L, job->errorString() ); + + QString path = static_cast(job)->destUrl().path(); + + QList::Iterator it = fileList.begin(); + for(;it != fileList.end(); ++it) + { + if ((*it).path == path) + break; + } + + if ( it != fileList.end() ) + fileList.erase( it ); + else + kDebug() << path << " not found in list"; + } + + counter++; + + if ( counter < expectedCounter ) + return; + + kDebug() << "All files downloaded, will call slotRunApp shortly"; + // We know we can run the app now - but let's finish the job properly first. + QTimer::singleShot( 0, this, SLOT( slotRunApp() ) ); + + jobList.clear(); +} + +void KIOExec::slotRunApp() +{ + if ( fileList.isEmpty() ) { + kDebug() << "No files downloaded -> exiting"; + mExited = true; + QApplication::exit(1); + return; + } + + KService service("dummy", command, QString()); + + KUrl::List list; + // Store modification times + QList::Iterator it = fileList.begin(); + for ( ; it != fileList.end() ; ++it ) + { + KDE_struct_stat buff; + (*it).time = KDE_stat( QFile::encodeName((*it).path), &buff ) ? 0 : buff.st_mtime; + KUrl url; + url.setPath((*it).path); + list << url; + } + + QStringList params = KRun::processDesktopExec(service, list); + + kDebug() << "EXEC " << KShell::joinArgs( params ); + +#ifdef Q_WS_X11 + // propagate the startup identification to the started process + KStartupInfoId id; + id.initId( kapp->startupId()); + id.setupStartupEnv(); +#endif + + QString exe( params.takeFirst() ); + const int exit_code = QProcess::execute( exe, params ); + +#ifdef Q_WS_X11 + KStartupInfo::resetStartupEnv(); +#endif + + kDebug() << "EXEC done"; + + // Test whether one of the files changed + it = fileList.begin(); + for( ;it != fileList.end(); ++it ) + { + KDE_struct_stat buff; + QString src = (*it).path; + KUrl dest = (*it).url; + if ( (KDE::stat( src, &buff ) == 0) && + ((*it).time != buff.st_mtime) ) + { + if ( tempfiles ) + { + if ( KMessageBox::questionYesNo( 0L, + i18n( "The supposedly temporary file\n%1\nhas been modified.\nDo you still want to delete it?" , dest.pathOrUrl()), + i18n( "File Changed" ), KStandardGuiItem::del(), KGuiItem(i18n("Do Not Delete")) ) != KMessageBox::Yes ) + continue; // don't delete the temp file + } + else if ( ! dest.isLocalFile() ) // no upload when it's already a local file + { + if ( KMessageBox::questionYesNo( 0L, + i18n( "The file\n%1\nhas been modified.\nDo you want to upload the changes?" , dest.prettyUrl()), + i18n( "File Changed" ), KGuiItem(i18n("Upload")), KGuiItem(i18n("Do Not Upload")) ) == KMessageBox::Yes ) + { + kDebug() << "src='" << src << "' dest='" << dest << "'"; + // Do it the synchronous way. + if ( !KIO::NetAccess::upload( src, dest, 0 ) ) + { + KMessageBox::error( 0L, KIO::NetAccess::lastErrorString() ); + continue; // don't delete the temp file + } + } + } + } + + if ((!dest.isLocalFile() || tempfiles) && exit_code == 0) { + // Wait for a reasonable time so that even if the application forks on startup (like OOo or amarok) + // it will have time to start up and read the file before it gets deleted. #130709. + kDebug() << "sleeping..."; + sleep(180); // 3 mn + kDebug() << "about to delete " << src; + unlink( QFile::encodeName(src) ); + } + } + + mExited = true; + QApplication::exit(exit_code); +} + +int main( int argc, char **argv ) +{ + KAboutData aboutData( "kioexec", "kioexec", ki18n("KIOExec"), + KDE_VERSION_STRING, ki18n(description), KAboutData::License_GPL, + ki18n("(c) 1998-2000,2003 The KFM/Konqueror Developers")); + aboutData.addAuthor(ki18n("David Faure"),KLocalizedString(), "faure@kde.org"); + aboutData.addAuthor(ki18n("Stephan Kulow"),KLocalizedString(), "coolo@kde.org"); + aboutData.addAuthor(ki18n("Bernhard Rosenkraenzer"),KLocalizedString(), "bero@arklinux.org"); + aboutData.addAuthor(ki18n("Waldo Bastian"),KLocalizedString(), "bastian@kde.org"); + aboutData.addAuthor(ki18n("Oswald Buddenhagen"),KLocalizedString(), "ossi@kde.org"); + aboutData.setProgramIconName("kde"); + KCmdLineArgs::init( argc, argv, &aboutData ); + + KCmdLineOptions options; + options.add("tempfiles", ki18n("Treat URLs as local files and delete them afterwards")); + options.add("suggestedfilename ", ki18n("Suggested file name for the downloaded file")); + options.add("+command", ki18n("Command to execute")); + options.add("+[URLs]", ki18n("URL(s) or local file(s) used for 'command'")); + KCmdLineArgs::addCmdLineOptions( options ); + + KApplication app; + app.setQuitOnLastWindowClosed(false); + + KIOExec exec; + + // Don't go into the event loop if we already want to exit (#172197) + if (exec.exited()) + return 0; + + return app.exec(); +} + +#include "main.moc" diff --git a/kioexec/main.h b/kioexec/main.h new file mode 100644 index 00000000..d214189b --- /dev/null +++ b/kioexec/main.h @@ -0,0 +1,66 @@ +/* This file is part of the KDE project + Copyright (C) 1998, 1999 Torben Weis + Copyright (C) 2000-2005 David Faure + Copyright (C) 2001 Waldo Bastian + + 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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + + +#ifndef KIOEXEC_MAIN_H +#define KIOEXEC_MAIN_H + +#include +#include +#include +#include + +#include + +namespace KIO { class Job; } + +class KJob; + +class KIOExec : public QObject +{ + Q_OBJECT +public: + KIOExec(); + + bool exited() const { return mExited; } + +public Q_SLOTS: + void slotResult( KJob * ); + void slotRunApp(); + +protected: + bool mExited; + bool tempfiles; + QString suggestedFileName; + int counter; + int expectedCounter; + QString command; + struct FileInfo { + QString path; + KUrl url; + int time; + }; + QList fileList; + int jobCounter; + QList jobList; +}; + +#endif diff --git a/kioslave/CMakeLists.txt b/kioslave/CMakeLists.txt new file mode 100644 index 00000000..b150290c --- /dev/null +++ b/kioslave/CMakeLists.txt @@ -0,0 +1,65 @@ + +if(NOT WIN32) +# we need a version of samba which has already smbc_set_context(), Alex +set(SAMBA_REQUIRE_SMBC_SET_CONTEXT TRUE) +set(SAMBA_REQUIRE_SMBC_OPTION_SET TRUE) +macro_optional_find_package(Samba) +set_package_properties(Samba PROPERTIES DESCRIPTION "the SMB client library, a version with smbc_set_context() and smbc_option_set()" + URL "http://www.samba.org" + TYPE OPTIONAL + PURPOSE "Needed to build the SMB kioslave" + ) +endif(NOT WIN32) + +macro_optional_find_package(LibSSH 0.6.0) +set_package_properties(LibSSH PROPERTIES DESCRIPTION "the SSH library with SFTP support" + URL "http://www.libssh.org/" + TYPE OPTIONAL + PURPOSE "Needed to build the SFTP kioslave" + ) + +add_subdirectory( about ) +add_subdirectory( bookmarks ) +if(NOT WINCE) +add_subdirectory( cgi ) +endif(NOT WINCE) +add_subdirectory( filter ) +if(NOT WINCE) +add_subdirectory( info ) +endif(NOT WINCE) +add_subdirectory( archive ) +add_subdirectory( settings ) +add_subdirectory( applications ) +if(NOT WINCE) +add_subdirectory( trash ) +endif(NOT WINCE) +if(NOT WIN32) +add_subdirectory( network ) +endif(NOT WIN32) +add_subdirectory( remote ) +add_subdirectory( desktop ) +add_subdirectory( recentdocuments ) +add_subdirectory( fish ) +if(NOT WINCE) +add_subdirectory( thumbnail ) +endif(NOT WINCE) +add_subdirectory( docfilter ) +if (LIBSSH_FOUND) + add_subdirectory(sftp) +endif (LIBSSH_FOUND) + +if(NOT WIN32) + add_subdirectory( floppy ) + add_subdirectory( finger ) + add_subdirectory( man ) + check_include_files(rpc/rpc.h HAVE_RPC_RPC_H) + add_feature_info("NFS kioslave" HAVE_RPC_RPC_H "The RPC library is needed to build the NFS kioslave") + if(HAVE_RPC_RPC_H) + add_subdirectory( nfs ) + endif(HAVE_RPC_RPC_H) +endif(NOT WIN32) + +if(SAMBA_FOUND OR WIN32 AND NOT WINCE) + add_subdirectory(smb) +endif(SAMBA_FOUND OR WIN32 AND NOT WINCE) + diff --git a/kioslave/DEBUG.howto b/kioslave/DEBUG.howto new file mode 100644 index 00000000..c50be17f --- /dev/null +++ b/kioslave/DEBUG.howto @@ -0,0 +1,4 @@ +Please refer to the TechBase article, +http://techbase.kde.org/Development/Tutorials/Debugging/Debugging_IOSlaves + +Happy debugging. diff --git a/kioslave/DESIGN b/kioslave/DESIGN new file mode 100644 index 00000000..92a03b21 --- /dev/null +++ b/kioslave/DESIGN @@ -0,0 +1,43 @@ +What is a kioslave you ask yourself? + +A kioslave is a program designed to be intimately familiar with a certian +protocol, so that a standardized interface can be used to get at data from +any number of places. A few examples are the http and ftp kioslaves, +which using nearly identical methods will retrieve data from an http or +ftp server respectively. + +Well, that's nice. How do they work? + +To understand it, you'll need two ice cubes, a pair of handcuffs, and a +ferret. Some Crisco (or other shortening) is optional. Well, that aside, +this document focuses on the business end of the whole kio library. The +ioslave. See the documentation of the SlaveBase class for the methods +you need to reimplement, and see +http://developer.kde.org/documentation/design/kde/ioslaves/ for more docu +online. + +That's nice, but how can I use it? + +Any time you'd like to use non blocking IO over a high level protocol +(such as HTTP or FTP) a kioslave is for you. + +That's nice, but how do I use it? + +Basically, you create "jobs" by calling a public KIO::blah method +(the correct prototypes, etc, are in kio/job.h). Once this is done, you +connect to the result() signal, and wait for the result. There are +other signals emitted by jobs, see kio/jobclasses.h. Once again, +see the online documentation for more. + + +If you are interested in working on an ioslave, +the following slaves are severely lacking in functionality: + + SMTP + SMB + +------------- + +Original document by Rich. +Updated for KDE 2 by David. + diff --git a/kioslave/about/CMakeLists.txt b/kioslave/about/CMakeLists.txt new file mode 100644 index 00000000..4f8d91f7 --- /dev/null +++ b/kioslave/about/CMakeLists.txt @@ -0,0 +1,20 @@ + + + + +########### next target ############### + +set(kio_about_PART_SRCS kio_about.cpp ) + + +kde4_add_plugin(kio_about ${kio_about_PART_SRCS}) + + +target_link_libraries(kio_about ${KDE4_KIO_LIBS} ) + +install(TARGETS kio_about DESTINATION ${PLUGIN_INSTALL_DIR} ) + + +########### install files ############### + +install( FILES about.protocol DESTINATION ${SERVICES_INSTALL_DIR} ) diff --git a/kioslave/about/Messages.sh b/kioslave/about/Messages.sh new file mode 100644 index 00000000..747558b4 --- /dev/null +++ b/kioslave/about/Messages.sh @@ -0,0 +1,2 @@ +#! /usr/bin/env bash +$XGETTEXT *.cpp *.h -o $podir/kio_about.pot diff --git a/kioslave/about/about.protocol b/kioslave/about/about.protocol new file mode 100644 index 00000000..7bf028cf --- /dev/null +++ b/kioslave/about/about.protocol @@ -0,0 +1,9 @@ +[Protocol] +exec=kio_about +protocol=about +input=none +output=filesystem +reading=true +defaultMimetype=text/html +Icon=help-about +Class=:local diff --git a/kioslave/about/kio_about.cpp b/kioslave/about/kio_about.cpp new file mode 100644 index 00000000..d7396d86 --- /dev/null +++ b/kioslave/about/kio_about.cpp @@ -0,0 +1,75 @@ +/* This file is part of the KDE libraries + + Copyright (c) 2002 John Firebaugh + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "kio_about.h" + +#include + +using namespace KIO; + +AboutProtocol::AboutProtocol(const QByteArray &pool_socket, const QByteArray &app_socket) + : SlaveBase("about", pool_socket, app_socket) +{ +} + +AboutProtocol::~AboutProtocol() +{ +} + +void AboutProtocol::get( const KUrl& ) +{ + QByteArray output; + + QTextStream os( &output, QIODevice::WriteOnly ); + os.setCodec( "ISO-8859-1" ); // In fact ASCII + + os << "about:blank"; + os.flush(); + + mimeType("text/html"); + data( output ); + finished(); +} + +void AboutProtocol::mimetype( const KUrl& ) +{ + mimeType("text/html"); + finished(); +} + +extern "C" +{ + int KDE_EXPORT kdemain( int argc, char **argv ) { + + KComponentData componentData("kio_about"); + + if (argc != 4) + { + fprintf(stderr, "Usage: kio_about protocol domain-socket1 domain-socket2\n"); + exit(-1); + } + + AboutProtocol slave(argv[2], argv[3]); + slave.dispatchLoop(); + + return 0; + } +} + diff --git a/kioslave/about/kio_about.h b/kioslave/about/kio_about.h new file mode 100644 index 00000000..620d6aa6 --- /dev/null +++ b/kioslave/about/kio_about.h @@ -0,0 +1,39 @@ +/* This file is part of the KDE libraries + + Copyright (c) 2002 John Firebaugh + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ +#ifndef __kio_about_h__ +#define __kio_about_h__ + +#include + +#include +#include + + +class AboutProtocol : public KIO::SlaveBase +{ +public: + AboutProtocol(const QByteArray &pool_socket, const QByteArray &app_socket); + virtual ~AboutProtocol(); + + virtual void get(const KUrl& url); + virtual void mimetype(const KUrl& url); +}; + +#endif diff --git a/kioslave/applications/CMakeLists.txt b/kioslave/applications/CMakeLists.txt new file mode 100644 index 00000000..453be34a --- /dev/null +++ b/kioslave/applications/CMakeLists.txt @@ -0,0 +1,12 @@ +########### kio_applications ############### + +kde4_add_plugin(kio_applications kio_applications.cpp) + +target_link_libraries(kio_applications ${KDE4_KIO_LIBS} ) + +install(TARGETS kio_applications DESTINATION ${PLUGIN_INSTALL_DIR} ) + + +########### install files ############### + +install( FILES programs.protocol applications.protocol DESTINATION ${SERVICES_INSTALL_DIR} ) diff --git a/kioslave/applications/Messages.sh b/kioslave/applications/Messages.sh new file mode 100644 index 00000000..8543f2e8 --- /dev/null +++ b/kioslave/applications/Messages.sh @@ -0,0 +1,2 @@ +#! /usr/bin/env bash +$XGETTEXT `find . -name "*.cc" -o -name "*.cpp" -o -name "*.h"` -o $podir/kio_applications.pot diff --git a/kioslave/applications/applications.protocol b/kioslave/applications/applications.protocol new file mode 100644 index 00000000..ea0aa259 --- /dev/null +++ b/kioslave/applications/applications.protocol @@ -0,0 +1,15 @@ +[Protocol] +exec=kio_applications +protocol=applications +input=none +output=filesystem +listing=Name,Type,Size,Date,Access,Owner,Group,Link, +reading=true +writing=false +makedir=false +deleting=false +linking=false +moving=false +Icon=start-here-kde +maxInstances=2 +Class=:local diff --git a/kioslave/applications/kio_applications.cpp b/kioslave/applications/kio_applications.cpp new file mode 100644 index 00000000..02958bb9 --- /dev/null +++ b/kioslave/applications/kio_applications.cpp @@ -0,0 +1,193 @@ +/* This file is part of the KDE project + Copyright (C) 2003 Joseph Wenninger + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +class ApplicationsProtocol : public KIO::SlaveBase +{ +public: + enum RunMode { ProgramsMode, ApplicationsMode }; + ApplicationsProtocol(const QByteArray &protocol, const QByteArray &pool, const QByteArray &app); + virtual ~ApplicationsProtocol(); + virtual void get( const KUrl& url ); + virtual void stat(const KUrl& url); + virtual void listDir(const KUrl& url); + +private: + RunMode m_runMode; +}; + +extern "C" { + KDE_EXPORT int kdemain( int, char **argv ) + { + KComponentData componentData( "kio_applications" ); + ApplicationsProtocol slave(argv[1], argv[2], argv[3]); + slave.dispatchLoop(); + return 0; + } +} + + +static void createFileEntry(KIO::UDSEntry& entry, const KService::Ptr& service, const KUrl& parentUrl) +{ + entry.clear(); + entry.insert(KIO::UDSEntry::UDS_NAME, KIO::encodeFileName(service->name())); + entry.insert(KIO::UDSEntry::UDS_FILE_TYPE, S_IFREG); + const QString fileUrl = parentUrl.url(KUrl::AddTrailingSlash) + service->desktopEntryName(); + entry.insert(KIO::UDSEntry::UDS_URL, fileUrl); + entry.insert(KIO::UDSEntry::UDS_ACCESS, 0500); + entry.insert(KIO::UDSEntry::UDS_MIME_TYPE, "application/x-desktop"); + entry.insert(KIO::UDSEntry::UDS_SIZE, 0); + entry.insert(KIO::UDSEntry::UDS_LOCAL_PATH, KStandardDirs::locate("apps", service->entryPath())); + entry.insert(KIO::UDSEntry::UDS_MODIFICATION_TIME, time(0)); + entry.insert(KIO::UDSEntry::UDS_ICON_NAME, service->icon()); +} + +static void createDirEntry(KIO::UDSEntry& entry, const QString& name, const QString& url, const QString& mime,const QString& iconName) +{ + entry.clear(); + entry.insert( KIO::UDSEntry::UDS_NAME, name ); + entry.insert( KIO::UDSEntry::UDS_FILE_TYPE, S_IFDIR ); + entry.insert( KIO::UDSEntry::UDS_ACCESS, 0500 ); + entry.insert( KIO::UDSEntry::UDS_MIME_TYPE, mime ); + if (!url.isEmpty()) + entry.insert( KIO::UDSEntry::UDS_URL, url ); + entry.insert( KIO::UDSEntry::UDS_ICON_NAME, iconName ); +} + +ApplicationsProtocol::ApplicationsProtocol( const QByteArray &protocol, const QByteArray &pool, const QByteArray &app) + : SlaveBase( protocol, pool, app ) +{ + // Adjusts which part of the K Menu to virtualize. + if ( protocol == "programs" ) + m_runMode = ProgramsMode; + else // if (protocol == "applications") + m_runMode = ApplicationsMode; +} + +ApplicationsProtocol::~ApplicationsProtocol() +{ +} + +void ApplicationsProtocol::get( const KUrl & url ) +{ + KService::Ptr service = KService::serviceByDesktopName(url.fileName()); + if (service && service->isValid()) { + KUrl redirUrl(KStandardDirs::locate("apps", service->entryPath())); + redirection(redirUrl); + finished(); + } else { + error( KIO::ERR_IS_DIRECTORY, url.prettyUrl() ); + } +} + + +void ApplicationsProtocol::stat(const KUrl& url) +{ + KIO::UDSEntry entry; + + QString servicePath( url.path( KUrl::AddTrailingSlash ) ); + servicePath.remove(0, 1); // remove starting '/' + + KServiceGroup::Ptr grp = KServiceGroup::group(servicePath); + + if (grp && grp->isValid()) { + createDirEntry(entry, ((m_runMode==ApplicationsMode) ? i18n("Applications") : i18n("Programs")), + url.url(), "inode/directory",grp->icon() ); + } else { + KService::Ptr service = KService::serviceByDesktopName( url.fileName() ); + if (service && service->isValid()) { + createFileEntry(entry, service, url ); + } else { + error(KIO::ERR_SLAVE_DEFINED,i18n("Unknown application folder")); + return; + } + } + + statEntry(entry); + finished(); +} + + +void ApplicationsProtocol::listDir(const KUrl& url) +{ + QString groupPath = url.path( KUrl::AddTrailingSlash ); + groupPath.remove(0, 1); // remove starting '/' + + KServiceGroup::Ptr grp = KServiceGroup::group(groupPath); + + if (!grp || !grp->isValid()) { + error(KIO::ERR_DOES_NOT_EXIST, groupPath); + return; + } + + unsigned int count = 0; + KIO::UDSEntry entry; + + foreach (const KSycocaEntry::Ptr &e, grp->entries(true, true)) { + if (e->isType(KST_KServiceGroup)) { + KServiceGroup::Ptr g(KServiceGroup::Ptr::staticCast(e)); + QString groupCaption = g->caption(); + + kDebug() << "ADDING SERVICE GROUP WITH PATH " << g->relPath(); + + // Avoid adding empty groups. + KServiceGroup::Ptr subMenuRoot = KServiceGroup::group(g->relPath()); + if (subMenuRoot->childCount() == 0) + continue; + + // Ignore dotfiles. + if ((g->name().at(0) == '.')) + continue; + + QString relPath = g->relPath(); + KUrl dirUrl = url; // preserve protocol, whether that's programs:/ or applications:/ + dirUrl.setPath('/' + relPath); + dirUrl.adjustPath(KUrl::RemoveTrailingSlash); + kDebug() << "ApplicationsProtocol: adding entry" << dirUrl; + createDirEntry(entry, groupCaption, dirUrl.url(), "inode/directory", g->icon()); + + } else { + KService::Ptr service(KService::Ptr::staticCast(e)); + + kDebug() << "the entry name is" << service->desktopEntryName() + << "with path" << service->entryPath(); + + if (!service->isApplication()) // how could this happen? + continue; + createFileEntry(entry, service, url); + } + + listEntry(entry, false); + count++; + } + + totalSize(count); + listEntry(entry, true); + finished(); +} + diff --git a/kioslave/applications/programs.protocol b/kioslave/applications/programs.protocol new file mode 100644 index 00000000..7890a96b --- /dev/null +++ b/kioslave/applications/programs.protocol @@ -0,0 +1,15 @@ +[Protocol] +exec=kio_applications +protocol=programs +input=none +output=filesystem +listing=Name,Type,Size,Date,Access,Owner,Group,Link, +reading=true +writing=false +makedir=false +deleting=false +linking=false +moving=false +Icon=start-here-kde +maxInstances=2 +Class=:local diff --git a/kioslave/archive/CMakeLists.txt b/kioslave/archive/CMakeLists.txt new file mode 100644 index 00000000..e7744ea7 --- /dev/null +++ b/kioslave/archive/CMakeLists.txt @@ -0,0 +1,14 @@ +add_subdirectory(tests) + +########### kio_archive ############### + +set(kio_archive_SRCS kio_archive.cpp ) + +kde4_add_plugin(kio_archive ${kio_archive_SRCS}) + +target_link_libraries(kio_archive ${KDE4_KIO_LIBS} ) + +install(TARGETS kio_archive DESTINATION ${PLUGIN_INSTALL_DIR} ) +install( FILES tar.protocol ar.protocol zip.protocol DESTINATION ${SERVICES_INSTALL_DIR} ) + + diff --git a/kioslave/archive/Messages.sh b/kioslave/archive/Messages.sh new file mode 100644 index 00000000..f5a1e519 --- /dev/null +++ b/kioslave/archive/Messages.sh @@ -0,0 +1,2 @@ +#! /usr/bin/env bash +$XGETTEXT *.cpp -o $podir/kio_archive.pot diff --git a/kioslave/archive/ar.protocol b/kioslave/archive/ar.protocol new file mode 100644 index 00000000..7a848e50 --- /dev/null +++ b/kioslave/archive/ar.protocol @@ -0,0 +1,11 @@ +[Protocol] +exec=kio_archive +protocol=ar +archiveMimetype=application/x-archive +input=filesystem +output=filesystem +listing=Name,Type,Size,Date,Access,Owner,Group,Link +reading=true +source=true +Icon=package-x-generic +Class=:local diff --git a/kioslave/archive/kio_archive.cpp b/kioslave/archive/kio_archive.cpp new file mode 100644 index 00000000..5fc1c70d --- /dev/null +++ b/kioslave/archive/kio_archive.cpp @@ -0,0 +1,617 @@ +/* This file is part of the KDE libraries + Copyright (C) 2000 David Faure + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "kio_archive.h" + +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +using namespace KIO; + +extern "C" { int KDE_EXPORT kdemain(int argc, char **argv); } + +int kdemain( int argc, char **argv ) +{ + KComponentData componentData( "kio_archive" ); + + kDebug(7109) << "Starting" << getpid(); + + if (argc != 4) + { + fprintf(stderr, "Usage: kio_archive protocol domain-socket1 domain-socket2\n"); + exit(-1); + } + + ArchiveProtocol slave(argv[2], argv[3]); + slave.dispatchLoop(); + + kDebug(7109) << "Done"; + return 0; +} + +ArchiveProtocol::ArchiveProtocol( const QByteArray &pool, const QByteArray &app ) : SlaveBase( "tar", pool, app ) +{ + kDebug( 7109 ) << "ArchiveProtocol::ArchiveProtocol"; + m_archiveFile = 0L; +} + +ArchiveProtocol::~ArchiveProtocol() +{ + delete m_archiveFile; +} + +bool ArchiveProtocol::checkNewFile( const KUrl & url, QString & path, KIO::Error& errorNum ) +{ +#ifndef Q_WS_WIN + QString fullPath = url.path(); +#else + QString fullPath = url.path().remove(0, 1); +#endif + kDebug(7109) << "ArchiveProtocol::checkNewFile" << fullPath; + + + // Are we already looking at that file ? + if ( m_archiveFile && m_archiveName == fullPath.left(m_archiveName.length()) ) + { + // Has it changed ? + KDE_struct_stat statbuf; + if ( KDE_stat( QFile::encodeName( m_archiveName ), &statbuf ) == 0 ) + { + if ( m_mtime == statbuf.st_mtime ) + { + path = fullPath.mid( m_archiveName.length() ); + kDebug(7109) << "ArchiveProtocol::checkNewFile returning" << path; + return true; + } + } + } + kDebug(7109) << "Need to open a new file"; + + // Close previous file + if ( m_archiveFile ) + { + m_archiveFile->close(); + delete m_archiveFile; + m_archiveFile = 0L; + } + + // Find where the tar file is in the full path + int pos = 0; + QString archiveFile; + path.clear(); + + int len = fullPath.length(); + if ( len != 0 && fullPath[ len - 1 ] != '/' ) + fullPath += '/'; + + kDebug(7109) << "the full path is" << fullPath; + KDE_struct_stat statbuf; + statbuf.st_mode = 0; // be sure to clear the directory bit + while ( (pos=fullPath.indexOf( '/', pos+1 )) != -1 ) + { + QString tryPath = fullPath.left( pos ); + kDebug(7109) << fullPath << "trying" << tryPath; + if ( KDE_stat( QFile::encodeName(tryPath), &statbuf ) == -1 ) + { + // We are not in the file system anymore, either we have already enough data or we will never get any useful data anymore + break; + } + if ( !S_ISDIR(statbuf.st_mode) ) + { + archiveFile = tryPath; + m_mtime = statbuf.st_mtime; +#ifdef Q_WS_WIN // st_uid and st_gid provides no information + m_user.clear(); + m_group.clear(); +#else + KUser user(statbuf.st_uid); + m_user = user.loginName(); + KUserGroup group(statbuf.st_gid); + m_group = group.name(); +#endif + path = fullPath.mid( pos + 1 ); + kDebug(7109).nospace() << "fullPath=" << fullPath << " path=" << path; + len = path.length(); + if ( len > 1 ) + { + if ( path[ len - 1 ] == '/' ) + path.truncate( len - 1 ); + } + else + path = QString::fromLatin1("/"); + kDebug(7109).nospace() << "Found. archiveFile=" << archiveFile << " path=" << path; + break; + } + } + if ( archiveFile.isEmpty() ) + { + kDebug(7109) << "ArchiveProtocol::checkNewFile: not found"; + if ( S_ISDIR(statbuf.st_mode) ) // Was the last stat about a directory? + { + // Too bad, it is a directory, not an archive. + kDebug(7109) << "Path is a directory, not an archive."; + errorNum = KIO::ERR_IS_DIRECTORY; + } + else + errorNum = KIO::ERR_DOES_NOT_EXIST; + return false; + } + + // Open new file + if ( url.protocol() == "tar" ) { + kDebug(7109) << "Opening KTar on" << archiveFile; + m_archiveFile = new KTar( archiveFile ); + } else if ( url.protocol() == "ar" ) { + kDebug(7109) << "Opening KAr on " << archiveFile; + m_archiveFile = new KAr( archiveFile ); + } else if ( url.protocol() == "zip" ) { + kDebug(7109) << "Opening KZip on " << archiveFile; + m_archiveFile = new KZip( archiveFile ); + } else { + kWarning(7109) << "Protocol" << url.protocol() << "not supported by this IOSlave" ; + errorNum = KIO::ERR_UNSUPPORTED_PROTOCOL; + return false; + } + + if ( !m_archiveFile->open( QIODevice::ReadOnly ) ) + { + kDebug(7109) << "Opening" << archiveFile << "failed."; + delete m_archiveFile; + m_archiveFile = 0L; + errorNum = KIO::ERR_CANNOT_OPEN_FOR_READING; + return false; + } + + m_archiveName = archiveFile; + return true; +} + + +void ArchiveProtocol::createRootUDSEntry( KIO::UDSEntry & entry ) +{ + entry.clear(); + entry.insert( KIO::UDSEntry::UDS_NAME, "." ); + entry.insert( KIO::UDSEntry::UDS_FILE_TYPE, S_IFDIR ); + entry.insert( KIO::UDSEntry::UDS_MODIFICATION_TIME, m_mtime ); + //entry.insert( KIO::UDSEntry::UDS_ACCESS, 07777 ); // fake 'x' permissions, this is a pseudo-directory + entry.insert( KIO::UDSEntry::UDS_USER, m_user); + entry.insert( KIO::UDSEntry::UDS_GROUP, m_group); +} + +void ArchiveProtocol::createUDSEntry( const KArchiveEntry * archiveEntry, UDSEntry & entry ) +{ + entry.clear(); + entry.insert( KIO::UDSEntry::UDS_NAME, archiveEntry->name() ); + entry.insert( KIO::UDSEntry::UDS_FILE_TYPE, archiveEntry->permissions() & S_IFMT ); // keep file type only + entry.insert( KIO::UDSEntry::UDS_SIZE, archiveEntry->isFile() ? ((KArchiveFile *)archiveEntry)->size() : 0L ); + entry.insert( KIO::UDSEntry::UDS_MODIFICATION_TIME, archiveEntry->date()); + entry.insert( KIO::UDSEntry::UDS_ACCESS, archiveEntry->permissions() & 07777 ); // keep permissions only + entry.insert( KIO::UDSEntry::UDS_USER, archiveEntry->user()); + entry.insert( KIO::UDSEntry::UDS_GROUP, archiveEntry->group()); + entry.insert( KIO::UDSEntry::UDS_LINK_DEST, archiveEntry->symLinkTarget()); +} + +void ArchiveProtocol::listDir( const KUrl & url ) +{ + kDebug( 7109 ) << "ArchiveProtocol::listDir" << url.url(); + + QString path; + KIO::Error errorNum; + if ( !checkNewFile( url, path, errorNum ) ) + { + if ( errorNum == KIO::ERR_CANNOT_OPEN_FOR_READING ) + { + // If we cannot open, it might be a problem with the archive header (e.g. unsupported format) + // Therefore give a more specific error message + error( KIO::ERR_SLAVE_DEFINED, + i18n( "Could not open the file, probably due to an unsupported file format.\n%1", + url.prettyUrl() ) ); + return; + } + else if ( errorNum != ERR_IS_DIRECTORY ) + { + // We have any other error + error( errorNum, url.prettyUrl() ); + return; + } + // It's a real dir -> redirect + KUrl redir; + redir.setPath( url.path() ); + kDebug( 7109 ) << "Ok, redirection to" << redir.url(); + redirection( redir ); + finished(); + // And let go of the tar file - for people who want to unmount a cdrom after that + delete m_archiveFile; + m_archiveFile = 0L; + return; + } + + if ( path.isEmpty() ) + { + KUrl redir( url.protocol() + QString::fromLatin1( ":/") ); + kDebug( 7109 ) << "url.path()=" << url.path(); + redir.setPath( url.path() + QString::fromLatin1("/") ); + kDebug( 7109 ) << "ArchiveProtocol::listDir: redirection" << redir.url(); + redirection( redir ); + finished(); + return; + } + + kDebug( 7109 ) << "checkNewFile done"; + const KArchiveDirectory* root = m_archiveFile->directory(); + const KArchiveDirectory* dir; + if (!path.isEmpty() && path != "/") + { + kDebug(7109) << "Looking for entry" << path; + const KArchiveEntry* e = root->entry( path ); + if ( !e ) + { + error( KIO::ERR_DOES_NOT_EXIST, url.prettyUrl() ); + return; + } + if ( ! e->isDirectory() ) + { + error( KIO::ERR_IS_FILE, url.prettyUrl() ); + return; + } + dir = (KArchiveDirectory*)e; + } else { + dir = root; + } + + const QStringList l = dir->entries(); + totalSize( l.count() ); + + UDSEntry entry; + if (!l.contains(".")) { + createRootUDSEntry(entry); + listEntry(entry, false); + } + + QStringList::const_iterator it = l.begin(); + for( ; it != l.end(); ++it ) + { + kDebug(7109) << (*it); + const KArchiveEntry* archiveEntry = dir->entry( (*it) ); + + createUDSEntry( archiveEntry, entry ); + + listEntry( entry, false ); + } + + listEntry( entry, true ); // ready + + finished(); + + kDebug( 7109 ) << "ArchiveProtocol::listDir done"; +} + +void ArchiveProtocol::stat( const KUrl & url ) +{ + QString path; + UDSEntry entry; + KIO::Error errorNum; + if ( !checkNewFile( url, path, errorNum ) ) + { + // We may be looking at a real directory - this happens + // when pressing up after being in the root of an archive + if ( errorNum == KIO::ERR_CANNOT_OPEN_FOR_READING ) + { + // If we cannot open, it might be a problem with the archive header (e.g. unsupported format) + // Therefore give a more specific error message + error( KIO::ERR_SLAVE_DEFINED, + i18n( "Could not open the file, probably due to an unsupported file format.\n%1", + url.prettyUrl() ) ); + return; + } + else if ( errorNum != ERR_IS_DIRECTORY ) + { + // We have any other error + error( errorNum, url.prettyUrl() ); + return; + } + // Real directory. Return just enough information for KRun to work + entry.insert( KIO::UDSEntry::UDS_NAME, url.fileName()); + kDebug( 7109 ).nospace() << "ArchiveProtocol::stat returning name=" << url.fileName(); + + KDE_struct_stat buff; +#ifdef Q_WS_WIN + QString fullPath = url.path().remove(0, 1); +#else + QString fullPath = url.path(); +#endif + + if ( KDE_stat( QFile::encodeName( fullPath ), &buff ) == -1 ) + { + // Should not happen, as the file was already stated by checkNewFile + error( KIO::ERR_COULD_NOT_STAT, url.prettyUrl() ); + return; + } + + entry.insert( KIO::UDSEntry::UDS_FILE_TYPE, buff.st_mode & S_IFMT); + + statEntry( entry ); + + finished(); + + // And let go of the tar file - for people who want to unmount a cdrom after that + delete m_archiveFile; + m_archiveFile = 0L; + return; + } + + const KArchiveDirectory* root = m_archiveFile->directory(); + const KArchiveEntry* archiveEntry; + if ( path.isEmpty() ) + { + path = QString::fromLatin1( "/" ); + archiveEntry = root; + } else { + archiveEntry = root->entry( path ); + } + if ( !archiveEntry ) + { + error( KIO::ERR_DOES_NOT_EXIST, url.prettyUrl() ); + return; + } + + createUDSEntry( archiveEntry, entry ); + statEntry( entry ); + + finished(); +} + +void ArchiveProtocol::get( const KUrl & url ) +{ + kDebug( 7109 ) << "ArchiveProtocol::get" << url.url(); + + QString path; + KIO::Error errorNum; + if ( !checkNewFile( url, path, errorNum ) ) + { + if ( errorNum == KIO::ERR_CANNOT_OPEN_FOR_READING ) + { + // If we cannot open, it might be a problem with the archive header (e.g. unsupported format) + // Therefore give a more specific error message + error( KIO::ERR_SLAVE_DEFINED, + i18n( "Could not open the file, probably due to an unsupported file format.\n%1", + url.prettyUrl() ) ); + return; + } + else + { + // We have any other error + error( errorNum, url.prettyUrl() ); + return; + } + } + + const KArchiveDirectory* root = m_archiveFile->directory(); + const KArchiveEntry* archiveEntry = root->entry( path ); + + if ( !archiveEntry ) + { + error( KIO::ERR_DOES_NOT_EXIST, url.prettyUrl() ); + return; + } + if ( archiveEntry->isDirectory() ) + { + error( KIO::ERR_IS_DIRECTORY, url.prettyUrl() ); + return; + } + const KArchiveFile* archiveFileEntry = static_cast(archiveEntry); + if ( !archiveEntry->symLinkTarget().isEmpty() ) + { + kDebug(7109) << "Redirection to" << archiveEntry->symLinkTarget(); + KUrl realURL( url, archiveEntry->symLinkTarget() ); + kDebug(7109).nospace() << "realURL=" << realURL.url(); + redirection( realURL ); + finished(); + return; + } + + //kDebug(7109) << "Preparing to get the archive data"; + + /* + * The easy way would be to get the data by calling archiveFileEntry->data() + * However this has drawbacks: + * - the complete file must be read into the memory + * - errors are skipped, resulting in an empty file + */ + + QIODevice* io = archiveFileEntry->createDevice(); + + if (!io) + { + error( KIO::ERR_SLAVE_DEFINED, + i18n( "The archive file could not be opened, perhaps because the format is unsupported.\n%1" , + url.prettyUrl() ) ); + return; + } + + if ( !io->open( QIODevice::ReadOnly ) ) + { + error( KIO::ERR_CANNOT_OPEN_FOR_READING, url.prettyUrl() ); + delete io; + return; + } + + totalSize( archiveFileEntry->size() ); + + // Size of a QIODevice read. It must be large enough so that the mime type check will not fail + const qint64 maxSize = 0x100000; // 1MB + + qint64 bufferSize = qMin( maxSize, archiveFileEntry->size() ); + QByteArray buffer; + buffer.resize( bufferSize ); + if ( buffer.isEmpty() && bufferSize > 0 ) + { + // Something went wrong + error( KIO::ERR_OUT_OF_MEMORY, url.prettyUrl() ); + delete io; + return; + } + + bool firstRead = true; + + // How much file do we still have to process? + qint64 fileSize = archiveFileEntry->size(); + KIO::filesize_t processed = 0; + + while ( !io->atEnd() && fileSize > 0 ) + { + if ( !firstRead ) + { + bufferSize = qMin( maxSize, fileSize ); + buffer.resize( bufferSize ); + } + const qint64 read = io->read( buffer.data(), buffer.size() ); // Avoid to use bufferSize here, in case something went wrong. + if ( read != bufferSize ) + { + kWarning(7109) << "Read" << read << "bytes but expected" << bufferSize ; + error( KIO::ERR_COULD_NOT_READ, url.prettyUrl() ); + delete io; + return; + } + if ( firstRead ) + { + // We use the magic one the first data read + // (As magic detection is about fixed positions, we can be sure that it is enough data.) + KMimeType::Ptr mime = KMimeType::findByNameAndContent( path, buffer ); + kDebug(7109) << "Emitting mimetype" << mime->name(); + mimeType( mime->name() ); + firstRead = false; + } + data( buffer ); + processed += read; + processedSize( processed ); + fileSize -= bufferSize; + } + io->close(); + delete io; + + data( QByteArray() ); + + finished(); +} + +/* + In case someone wonders how the old filter stuff looked like : :) +void TARProtocol::slotData(void *_p, int _len) +{ + switch (m_cmd) { + case CMD_PUT: + assert(m_pFilter); + m_pFilter->send(_p, _len); + break; + default: + abort(); + break; + } +} + +void TARProtocol::slotDataEnd() +{ + switch (m_cmd) { + case CMD_PUT: + assert(m_pFilter && m_pJob); + m_pFilter->finish(); + m_pJob->dataEnd(); + m_cmd = CMD_NONE; + break; + default: + abort(); + break; + } +} + +void TARProtocol::jobData(void *_p, int _len) +{ + switch (m_cmd) { + case CMD_GET: + assert(m_pFilter); + m_pFilter->send(_p, _len); + break; + case CMD_COPY: + assert(m_pFilter); + m_pFilter->send(_p, _len); + break; + default: + abort(); + } +} + +void TARProtocol::jobDataEnd() +{ + switch (m_cmd) { + case CMD_GET: + assert(m_pFilter); + m_pFilter->finish(); + dataEnd(); + break; + case CMD_COPY: + assert(m_pFilter); + m_pFilter->finish(); + m_pJob->dataEnd(); + break; + default: + abort(); + } +} + +void TARProtocol::filterData(void *_p, int _len) +{ +debug("void TARProtocol::filterData"); + switch (m_cmd) { + case CMD_GET: + data(_p, _len); + break; + case CMD_PUT: + assert (m_pJob); + m_pJob->data(_p, _len); + break; + case CMD_COPY: + assert(m_pJob); + m_pJob->data(_p, _len); + break; + default: + abort(); + } +} +*/ + +// kate: space-indent on; indent-width 4; replace-tabs on; diff --git a/kioslave/archive/kio_archive.h b/kioslave/archive/kio_archive.h new file mode 100644 index 00000000..ae6e9062 --- /dev/null +++ b/kioslave/archive/kio_archive.h @@ -0,0 +1,60 @@ +/* This file is part of the KDE libraries + Copyright (C) 2000 David Faure + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef KIO_ARCHIVE_H +#define KIO_ARCHIVE_H + +#include + +#include +#include + +class KArchive; +class KArchiveEntry; + +class ArchiveProtocol : public KIO::SlaveBase +{ +public: + ArchiveProtocol( const QByteArray &pool, const QByteArray &app ); + virtual ~ArchiveProtocol(); + + virtual void listDir( const KUrl & url ); + virtual void stat( const KUrl & url ); + virtual void get( const KUrl & url ); + +private: + void createRootUDSEntry( KIO::UDSEntry & entry ); + void createUDSEntry( const KArchiveEntry * tarEntry, KIO::UDSEntry & entry ); + + /** + * \brief find, check and open the archive file + * \param url The URL of the archive + * \param path Path where the archive really is (returned value) + * \param errNum KIO error number (undefined if the function returns true) + * \return true if file was found, false if there was an error + */ + bool checkNewFile( const KUrl & url, QString & path, KIO::Error& errorNum ); + + KArchive * m_archiveFile; + QString m_archiveName; + QString m_user, m_group; + time_t m_mtime; +}; + +#endif // KIO_ARCHIVE_H diff --git a/kioslave/archive/tar.protocol b/kioslave/archive/tar.protocol new file mode 100644 index 00000000..9442d4de --- /dev/null +++ b/kioslave/archive/tar.protocol @@ -0,0 +1,12 @@ +[Protocol] +exec=kio_archive +protocol=tar +archiveMimetype=application/x-tar,application/x-compressed-tar,application/x-bzip-compressed-tar,application/x-webarchive,application/x-lzma-compressed-tar,application/x-xz-compressed-tar +input=filesystem +output=filesystem +listing=Name,Type,Size,Date,Access,Owner,Group,Link +reading=true +source=true +X-DocPath=kioslave/tar/index.html +Icon=package-x-generic +Class=:local diff --git a/kioslave/archive/tests/CMakeLists.txt b/kioslave/archive/tests/CMakeLists.txt new file mode 100644 index 00000000..c3f36873 --- /dev/null +++ b/kioslave/archive/tests/CMakeLists.txt @@ -0,0 +1,3 @@ +set( EXECUTABLE_OUTPUT_PATH ${CMAKE_CURRENT_BINARY_DIR} ) +kde4_add_unit_test(testkioarchive testkioarchive.cpp) +target_link_libraries(testkioarchive ${KDE4_KIO_LIBS} ${QT_QTTEST_LIBRARY}) diff --git a/kioslave/archive/tests/testkioarchive.cpp b/kioslave/archive/tests/testkioarchive.cpp new file mode 100644 index 00000000..79b76f4a --- /dev/null +++ b/kioslave/archive/tests/testkioarchive.cpp @@ -0,0 +1,169 @@ +/* This file is part of the KDE project + Copyright (C) 2007 David Faure + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "testkioarchive.h" +#include +#include +#include +#include +#include +#include +#include + +QTEST_KDEMAIN(TestKioArchive, NoGUI) +static const char s_tarFileName[] = "karchivetest.tar"; + +static void writeTestFilesToArchive( KArchive* archive ) +{ + bool ok; + ok = archive->writeFile( "empty", "weis", "users", "", 0 ); + QVERIFY( ok ); + ok = archive->writeFile( "test1", "weis", "users", "Hallo", 5 ); + QVERIFY( ok ); + ok = archive->writeFile( "mydir/subfile", "dfaure", "users", "Bonjour", 7 ); + QVERIFY( ok ); + ok = archive->writeSymLink( "mydir/symlink", "subfile", "dfaure", "users" ); + QVERIFY( ok ); +} + +void TestKioArchive::initTestCase() +{ + // Make sure we start clean + cleanupTestCase(); + + // Taken from KArchiveTest::testCreateTar + KTar tar( s_tarFileName ); + bool ok = tar.open( QIODevice::WriteOnly ); + QVERIFY( ok ); + writeTestFilesToArchive( &tar ); + ok = tar.close(); + QVERIFY( ok ); + QFileInfo fileInfo( QFile::encodeName( s_tarFileName ) ); + QVERIFY( fileInfo.exists() ); +} + +void TestKioArchive::testListTar() +{ + m_listResult.clear(); + KIO::ListJob* job = KIO::listDir(tarUrl(), KIO::HideProgressInfo); + connect( job, SIGNAL( entries( KIO::Job*, const KIO::UDSEntryList& ) ), + SLOT( slotEntries( KIO::Job*, const KIO::UDSEntryList& ) ) ); + bool ok = KIO::NetAccess::synchronousRun( job, 0 ); + QVERIFY( ok ); + kDebug() << "listDir done - entry count=" << m_listResult.count(); + QVERIFY( m_listResult.count() > 1 ); + + kDebug() << m_listResult; + QCOMPARE(m_listResult.count( "." ), 1); // found it, and only once + QCOMPARE(m_listResult.count("empty"), 1); + QCOMPARE(m_listResult.count("test1"), 1); + QCOMPARE(m_listResult.count("mydir"), 1); + QCOMPARE(m_listResult.count("mydir/subfile"), 0); // not a recursive listing + QCOMPARE(m_listResult.count("mydir/symlink"), 0); +} + +void TestKioArchive::testListRecursive() +{ + m_listResult.clear(); + KIO::ListJob* job = KIO::listRecursive(tarUrl(), KIO::HideProgressInfo); + connect( job, SIGNAL( entries( KIO::Job*, const KIO::UDSEntryList& ) ), + SLOT( slotEntries( KIO::Job*, const KIO::UDSEntryList& ) ) ); + bool ok = KIO::NetAccess::synchronousRun( job, 0 ); + QVERIFY( ok ); + kDebug() << "listDir done - entry count=" << m_listResult.count(); + QVERIFY( m_listResult.count() > 1 ); + + kDebug() << m_listResult; + QCOMPARE(m_listResult.count( "." ), 1); // found it, and only once + QCOMPARE(m_listResult.count("empty"), 1); + QCOMPARE(m_listResult.count("test1"), 1); + QCOMPARE(m_listResult.count("mydir"), 1); + QCOMPARE(m_listResult.count("mydir/subfile"), 1); + QCOMPARE(m_listResult.count("mydir/symlink"), 1); +} + +KUrl TestKioArchive::tarUrl() const +{ + KUrl url; + url.setProtocol("tar"); + url.setPath(QDir::currentPath()); + url.addPath(s_tarFileName); + return url; +} + +void TestKioArchive::slotEntries( KIO::Job*, const KIO::UDSEntryList& lst ) +{ + for( KIO::UDSEntryList::ConstIterator it = lst.begin(); it != lst.end(); ++it ) { + const KIO::UDSEntry& entry (*it); + QString displayName = entry.stringValue( KIO::UDSEntry::UDS_NAME ); + m_listResult << displayName; + } +} + +QString TestKioArchive::tmpDir() const +{ + // Note that this goes into ~/.kde-unit-test (see qtest_kde.h) + // Use saveLocation if locateLocal doesn't work + return KStandardDirs::locateLocal("tmp", "test_kio_archive/"); +} + +void TestKioArchive::cleanupTestCase() +{ + KIO::NetAccess::synchronousRun(KIO::del(tmpDir(), KIO::HideProgressInfo), 0); +} + +void TestKioArchive::copyFromTar(const KUrl& src, const QString& destPath) +{ + KUrl dest(destPath); + // Check that src exists + KIO::StatJob* statJob = KIO::stat(src, KIO::StatJob::SourceSide, 0, KIO::HideProgressInfo); + QVERIFY(KIO::NetAccess::synchronousRun(statJob, 0)); + + KIO::Job* job = KIO::copyAs( src, dest, KIO::HideProgressInfo ); + bool ok = KIO::NetAccess::synchronousRun( job, 0 ); + QVERIFY( ok ); + QVERIFY( QFile::exists( destPath ) ); +} + +void TestKioArchive::testExtractFileFromTar() +{ + const QString destPath = tmpDir() + "fileFromTar_copied"; + KUrl u = tarUrl(); + u.addPath("mydir/subfile"); + copyFromTar(u, destPath); + QVERIFY(QFileInfo(destPath).isFile()); + QVERIFY(QFileInfo(destPath).size() == 7); +} + +void TestKioArchive::testExtractSymlinkFromTar() +{ + const QString destPath = tmpDir() + "symlinkFromTar_copied"; + KUrl u = tarUrl(); + u.addPath("mydir/symlink"); + copyFromTar(u, destPath); + QVERIFY(QFileInfo(destPath).isFile()); + QEXPECT_FAIL("", "See #5601 -- on FTP we want to download the real file, not the symlink...", Continue); + // See comment in 149903 + // Maybe this is something we can do depending on Class=:local and Class=:internet + // (we already know if a protocol is local or remote). + // So local->local should copy symlinks, while internet->local and internet->internet should + // copy the actual file, I guess? + // -> ### TODO + QVERIFY(QFileInfo(destPath).isSymLink()); +} diff --git a/kioslave/archive/tests/testkioarchive.h b/kioslave/archive/tests/testkioarchive.h new file mode 100644 index 00000000..e00baa9a --- /dev/null +++ b/kioslave/archive/tests/testkioarchive.h @@ -0,0 +1,57 @@ +/* This file is part of the KDE project + Copyright (C) 2007 David Faure + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef TESTKIOARCHIVE_H +#define TESTKIOARCHIVE_H + +#include +#include +#include + +/** + * This is a unit test for kio_archive + * See also kdelibs/kio/tests/karchivetest for lower-level KTar and KZip tests. + */ +class TestKioArchive : public QObject +{ + Q_OBJECT + +public: + TestKioArchive() {} + +private Q_SLOTS: + void initTestCase(); + void testListTar(); + void testListRecursive(); + void testExtractFileFromTar(); + void testExtractSymlinkFromTar(); + void cleanupTestCase(); + +protected Q_SLOTS: // real slots, not tests + void slotEntries( KIO::Job*, const KIO::UDSEntryList& lst ); + +private: + QString tmpDir() const; + KUrl tarUrl() const; + void copyFromTar(const KUrl& url, const QString& destPath); + + QStringList m_listResult; +}; + +#endif diff --git a/kioslave/archive/zip.protocol b/kioslave/archive/zip.protocol new file mode 100644 index 00000000..ce7c54b4 --- /dev/null +++ b/kioslave/archive/zip.protocol @@ -0,0 +1,12 @@ +[Protocol] +exec=kio_archive +protocol=zip +archiveMimetype=application/zip +input=filesystem +output=filesystem +listing=Name,Type,Size,Date,Access,Owner,Group,Link +reading=true +source=true +#DocPath=kioslave/zip/index.html +Icon=package-x-generic +Class=:local diff --git a/kioslave/bookmarks/CMakeLists.txt b/kioslave/bookmarks/CMakeLists.txt new file mode 100644 index 00000000..fbe82cba --- /dev/null +++ b/kioslave/bookmarks/CMakeLists.txt @@ -0,0 +1,14 @@ +########### next target ############### + +set(kio_bookmarks_PART_SRCS kio_bookmarks.cpp kio_bookmarks_html.cpp kio_bookmarks_pixmap.cpp) + +kde4_add_plugin(kio_bookmarks ${kio_bookmarks_PART_SRCS}) + +target_link_libraries(kio_bookmarks ${KDE4_KIO_LIBS} ${KDE4_KDEUI_LIBS} ${KDE4_KFILE_LIBS} ${KDE4_SOLID_LIBS}) + +install(TARGETS kio_bookmarks DESTINATION ${PLUGIN_INSTALL_DIR} ) + + +########### install files ############### +install( FILES kio_bookmarks.css DESTINATION ${DATA_INSTALL_DIR}/kio_bookmarks ) +install( FILES bookmarks.protocol DESTINATION ${SERVICES_INSTALL_DIR} ) diff --git a/kioslave/bookmarks/Messages.sh b/kioslave/bookmarks/Messages.sh new file mode 100755 index 00000000..045e5cfc --- /dev/null +++ b/kioslave/bookmarks/Messages.sh @@ -0,0 +1,2 @@ +#! /usr/bin/env bash +$XGETTEXT *.cpp -o $podir/kio_bookmarks.pot diff --git a/kioslave/bookmarks/bookmarks.protocol b/kioslave/bookmarks/bookmarks.protocol new file mode 100644 index 00000000..68503d8c --- /dev/null +++ b/kioslave/bookmarks/bookmarks.protocol @@ -0,0 +1,9 @@ +[Protocol] +exec=kio_bookmarks +protocol=bookmarks +input=none +output=stream +reading=true +X-DocPath=kioslave/bookmarks/index.html +Icon=bookmarks +Class=:local diff --git a/kioslave/bookmarks/kio_bookmarks.cpp b/kioslave/bookmarks/kio_bookmarks.cpp new file mode 100644 index 00000000..750495d0 --- /dev/null +++ b/kioslave/bookmarks/kio_bookmarks.cpp @@ -0,0 +1,222 @@ +/* + Copyright (C) 2008 Xavier Vello + + 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 "kio_bookmarks.h" + +#include +#include + +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace KIO; + +BookmarksProtocol::BookmarksProtocol( const QByteArray &pool, const QByteArray &app ) + : SlaveBase( "bookmarks", pool, app ) +{ + manager = KBookmarkManager::userBookmarksManager(); + cfg = new KConfig( "kiobookmarksrc" ); + config = cfg->group("General"); + cache = new KImageCache("kio_bookmarks", config.readEntry("CacheSize", 5 * 1024) * 1024); + cache->setPixmapCaching(false); + + indent = 0; + totalsize = 0; + columns = 4; +} + +BookmarksProtocol::~BookmarksProtocol() +{ + delete manager; + delete cache; + delete cfg; +} + +void BookmarksProtocol::parseTree() +{ + totalsize = 0; + + cfg->reparseConfiguration(); + columns = config.readEntry("Columns", 4); + if (columns < 1) + columns = 1; + + manager->notifyCompleteChange("kio_bookmarks"); + tree = manager->root(); + + if(tree.first().isNull()) + return; + + if(config.readEntry("FlattenTree", false)) + flattenTree(tree); + + KBookmarkGroup root; + if(config.readEntry("ShowRoot", true)) + { + root = tree.createNewFolder(i18n("Root")); + tree.moveBookmark(root, KBookmark()); + root.setIcon("konqueror"); + } + + KBookmark bm = tree.first(); + KBookmark next; + while(!bm.isNull()) + { + next = tree.next(bm); + if (bm.isSeparator()) + tree.deleteBookmark(bm); + else if (bm.isGroup()) + totalsize += sizeOfGroup(bm.toGroup()); + else + { + if(config.readEntry("ShowRoot", true)) + root.addBookmark(bm); + + tree.deleteBookmark(bm); + } + bm = next; + } + if(config.readEntry("ShowRoot", true)) + totalsize += sizeOfGroup(root); + + if(config.readEntry("ShowPlaces", true)) + totalsize += addPlaces(); +} + +int BookmarksProtocol::addPlaces() +{ + KFilePlacesModel placesModel; + KBookmarkGroup folder = tree.createNewFolder(i18n("Places")); + QList batteryList = Solid::Device::listFromType(Solid::DeviceInterface::Battery, QString()); + + if (batteryList.isEmpty()) { + folder.setIcon("computer"); + } else { + folder.setIcon("computer-laptop"); + } + + for (int row = 0; row < placesModel.rowCount(); ++row) { + QModelIndex index = placesModel.index(row, 0); + + if (!placesModel.isHidden(index)) + folder.addBookmark(placesModel.bookmarkForIndex(index)); + } + return sizeOfGroup(folder); +} + +void BookmarksProtocol::flattenTree( const KBookmarkGroup &folder ) +{ + KBookmark bm = folder.first(); + KBookmark prev = folder; + KBookmark next; + while (!bm.isNull()) + { + if (bm.isGroup()) { + flattenTree(bm.toGroup()); + } + + next = tree.next(bm); + + if (bm.isGroup() && bm.parentGroup().hasParent()) { + kDebug() << "moving " << bm.text() << " from " << bm.parentGroup().fullText() << " to " << prev.parentGroup().text() << endl; + + bm.setFullText("| " + bm.parentGroup().fullText() + " > " + bm.fullText()); + tree.moveBookmark(bm, prev); + prev = bm; + } + bm = next; + } +} + +// Should really go to KBookmarkGroup +int BookmarksProtocol::sizeOfGroup( const KBookmarkGroup &folder, bool real ) +{ + int size = 1; // counting the title line + for (KBookmark bm = folder.first(); !bm.isNull(); bm = folder.next(bm)) + { + if (bm.isGroup()) + size += sizeOfGroup(bm.toGroup()); + else + size += 1; + } + + // CSS sets a min-height for toplevel folders + if (folder.parentGroup() == tree && size < 8 && real == false) + size = 8; + + return size; +} + +void BookmarksProtocol::get( const KUrl& url ) +{ + QString path = url.path(); + QRegExp regexp("^/(background|icon)/([\\S]+)"); + + if (path.isEmpty() || path == "/") { + echoIndex(); + } else if (path == "/config") { + KToolInvocation::startServiceByDesktopName("bookmarks", ""); + echoHead("bookmarks:/"); + } else if (path == "/editbookmarks") { + KToolInvocation::kdeinitExec("keditbookmarks"); + echoHead("bookmarks:/"); + } else if (regexp.indexIn(path) >= 0) { + echoImage(regexp.cap(1), regexp.cap(2), url.queryItem("size")); + } else { + echoHead(); + echo("

" + i18n("Wrong request: %1",path) + "

"); + } + finished(); +} + +extern "C" int KDE_EXPORT kdemain(int argc, char **argv) +{ + KAboutData about("kio_bookmarks", 0, ki18n("My bookmarks"), "0.2.2"); + about.addLicense(KAboutData::License_GPL_V2); + about.addAuthor(ki18n("Xavier Vello"), ki18n("Initial developer"), "xavier.vello@gmail.com", QByteArray()); + KCmdLineArgs::init(&about); + KApplication app; + + if (argc != 4) { + kError() << "Usage: kio_bookmarks protocol domain-socket1 domain-socket2"; + exit(-1); + } + + BookmarksProtocol slave(argv[2], argv[3]); + slave.dispatchLoop(); + + return 0; +} diff --git a/kioslave/bookmarks/kio_bookmarks.css b/kioslave/bookmarks/kio_bookmarks.css new file mode 100644 index 00000000..804a2479 --- /dev/null +++ b/kioslave/bookmarks/kio_bookmarks.css @@ -0,0 +1,117 @@ +/* +Copyright (C) 2008 Xavier Vello + +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. +*/ + +body { + margin: 0 42px; + font-size: small; + font-family: "sans-serif"; + line-height: 16px; + text-align: center; + white-space: nowrap; +} + +div.column { + display: inline-block; + vertical-align: top; + width: 25%; + max-width: 300px; + min-width: 150px; + padding-top: 5px; + text-align: left; +} + +ul li { + list-style: none; + white-space: normal; + margin: 0; + padding: 0; +} + +div.column > ul { + margin: 5px 5px 10px 5px; + padding: 0 5px 5px 5px; + min-height: 150px; + background: no-repeat 90% 95%; +} + +div.column > ul > li.title { + text-align: center; + font-weight: bold; + font-size: 100%; + margin: 2px -6px 5px -6px; + border-bottom: 1px solid #AAA; +} + +li.link { + padding: 2px 5px 2px 20px; + margin-bottom: 0px; +} + +ul ul { + margin-bottom: 5px; + border-left: 1px solid #AAA; + margin-left: 8px; + padding-left: 5px; +} + +ul ul li.title { + padding: 0px 5px 2px 20px; + margin-left: -13px; + margin-bottom: 6px; + border-bottom: 1px solid #AAA; + height: 10px; +} + +li img { + float: left; + margin-left: -20px; +} + +a, a:hover a:visited { + text-decoration: none; + color: inherit; +} + +hr { + width: 66%; + margin: 7px auto 7px auto; + background-color: #AAA; + border: none; + height: 1px; +} + +p.message { + text-align: center; + margin: auto; + width: 50%; + margin-top: 2em; + padding: 2em; +} + +div.toolbar { + position: fixed; + right: 0; + top: 0; + padding: 2px 0; +} + +div.toolbar img { + display: block; + padding: 2px 5px; + margin: 0; +} diff --git a/kioslave/bookmarks/kio_bookmarks.h b/kioslave/bookmarks/kio_bookmarks.h new file mode 100644 index 00000000..d2b0f9e2 --- /dev/null +++ b/kioslave/bookmarks/kio_bookmarks.h @@ -0,0 +1,65 @@ +/* + Copyright (C) 2008 Xavier Vello + + 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. +*/ +#ifndef KIO_BOOKMARKS_H +#define KIO_BOOKMARKS_H + +#include +#include +#include +#include + +class KImageCache; + +class BookmarksProtocol : public KIO::SlaveBase +{ + public: + BookmarksProtocol( const QByteArray &pool, const QByteArray &app ); + ~BookmarksProtocol(); + + void get( const KUrl& url ); + + private: + int columns; + int indent; + int totalsize; + KImageCache* cache; + KBookmarkManager* manager; + KConfig* cfg; + KConfigGroup config; + KBookmarkGroup tree; + void parseTree(); + void flattenTree( const KBookmarkGroup &folder ); + int sizeOfGroup(const KBookmarkGroup &folder, bool real = false); + int addPlaces(); + + // Defined in kde_bookmarks_html.cpp + void echo( const QString &string ); + QString htmlColor(const QColor &col); + QString htmlColor(const QBrush &brush); + void echoIndex(); + void echoHead(const QString &redirect = QString()); + void echoStyle(); + void echoBookmark( const KBookmark &bm); + void echoSeparator(); + void echoFolder( const KBookmarkGroup &folder ); + + // Defined in kde_bookmarks_pixmap.cpp + void echoImage( const QString &type, const QString &string, const QString &sizestring = QString()); +}; + +#endif diff --git a/kioslave/bookmarks/kio_bookmarks_html.cpp b/kioslave/bookmarks/kio_bookmarks_html.cpp new file mode 100644 index 00000000..a03cf8e9 --- /dev/null +++ b/kioslave/bookmarks/kio_bookmarks_html.cpp @@ -0,0 +1,218 @@ +/* +Copyright (C) 2008 Xavier Vello + +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 "kio_bookmarks.h" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +void BookmarksProtocol::echoBookmark( const KBookmark &bm) +{ + QString descriptionAsTitle = Qt::escape(bm.description()); + if (!descriptionAsTitle.isEmpty()) + descriptionAsTitle.prepend(QLatin1String("\" title=\"")); + echo ("
  • " + Qt::escape(bm.text()) + "
  • "); +} + +void BookmarksProtocol::echoSeparator() +{ + echo ("
    "); +} + +void BookmarksProtocol::echoFolder( const KBookmarkGroup &folder ) +{ + if (sizeOfGroup(folder.toGroup(), true) > 1) + { + QString descriptionAsTitle = folder.description(); + if (!descriptionAsTitle.isEmpty()) + descriptionAsTitle.prepend(QLatin1String("\" title=\"")); + + if (folder.parentGroup() == tree) + { + if (config.readEntry("ShowBackgrounds", true)) + echo("