diff --git a/ConfigureChecks.cmake b/ConfigureChecks.cmake index b8cd421..2729adb 100644 --- a/ConfigureChecks.cmake +++ b/ConfigureChecks.cmake @@ -47,7 +47,6 @@ check_include_files(fstab.h HAVE_FSTAB_H) # kio, kd check_include_files(limits.h HAVE_LIMITS_H) # various check_include_files(mntent.h HAVE_MNTENT_H) # solid, kio, kdecore check_include_files(sysent.h HAVE_SYSENT_H) # kdecore -check_include_files("sys/types.h;sys/mman.h" HAVE_SYS_MMAN_H) # kdecore check_include_files(sys/stat.h HAVE_SYS_STAT_H) # various check_include_files(sys/ucred.h HAVE_SYS_UCRED_H) # kio check_include_files(sys/types.h HAVE_SYS_TYPES_H) # various @@ -58,7 +57,6 @@ check_include_files(sys/mntent.h HAVE_SYS_MNTENT_H) # solid, check_include_files("sys/param.h;sys/mount.h" HAVE_SYS_MOUNT_H) # kio, kdecore check_include_files(unistd.h HAVE_UNISTD_H) # various check_include_files(stdint.h HAVE_STDINT_H) # various -check_include_files("sys/types.h;netinet/in.h" HAVE_NETINET_IN_H) # kio check_include_files(paths.h HAVE_PATHS_H) # kdecore, kio check_include_files(errno.h HAVE_ERRNO_H) # kjs, errno.h is used in many places, but only guarded in kjs/ @@ -67,9 +65,6 @@ check_include_files(valgrind/memcheck.h HAVE_VALGRIND_MEMCHECK_H) # khtml check_include_files(crtdbg.h HAVE_CRTDBG_H) # kjs check_include_files(langinfo.h HAVE_LANGINFO_H) # kdecore -check_include_files(arpa/nameser_compat.h HAVE_ARPA_NAMESER_COMPAT_H) # kio -check_include_files(arpa/nameser8_compat.h HAVE_ARPA_NAMESER8_COMPAT_H) # kio - macro_bool_to_01(X11_XTest_FOUND HAVE_XTEST) # kdecore macro_bool_to_01(X11_Xcursor_FOUND HAVE_XCURSOR) # kdeui macro_bool_to_01(X11_Xfixes_FOUND HAVE_XFIXES) # kdeui @@ -99,11 +94,6 @@ if(NOT APPLE) endif(NOT APPLE) check_function_exists(mmap HAVE_MMAP) # kdecore, khtml -if(NOT WIN32) - # we don't have it on windows but need to export it to be backward compatible - # can be removed when 4.1 is out - check_function_exists(readdir_r HAVE_READDIR_R) # kio -endif(NOT WIN32) check_function_exists(sendfile HAVE_SENDFILE) # kioslave check_function_exists(srandom HAVE_SRANDOM) # config.h check_function_exists(_NSGetEnviron HAVE_NSGETENVIRON) # kinit, config.h @@ -254,7 +244,6 @@ check_prototype_exists(unsetenv stdlib.h HAVE_UNSETENV_PROTO) check_prototype_exists(usleep unistd.h HAVE_USLEEP_PROTO) check_prototype_exists(initgroups "unistd.h;sys/types.h;unistd.h;grp.h" HAVE_INITGROUPS_PROTO) check_prototype_exists(setreuid unistd.h HAVE_SETREUID_PROTO) -check_prototype_exists(seteuid unistd.h HAVE_SETEUID_PROTO) check_prototype_exists(trunc math.h HAVE_TRUNC) # check for existing datatypes diff --git a/cmake/modules/FindNepomuk.cmake b/cmake/modules/FindNepomuk.cmake index 10c995c..b822aee 100644 --- a/cmake/modules/FindNepomuk.cmake +++ b/cmake/modules/FindNepomuk.cmake @@ -79,7 +79,7 @@ include(FindPackageHandleStandardArgs) if(NOT WINCE) find_package_handle_standard_args(Nepomuk DEFAULT_MSG NEPOMUK_LIBRARIES NEPOMUK_INCLUDE_DIR NEPOMUK_ADDONTOLOGYCLASSES_FILE - Soprano_FOUND SOPRANO_PLUGIN_RAPTORPARSER_FOUND SOPRANO_PLUGIN_REDLANDBACKEND_FOUND + Soprano_FOUND SHAREDDESKTOPONTOLOGIES_FOUND ) else(NOT WINCE) diff --git a/config.h.cmake b/config.h.cmake index d5708aa..86ca906 100644 --- a/config.h.cmake +++ b/config.h.cmake @@ -50,12 +50,8 @@ #cmakedefine HAVE_FSTAB_H 1 #cmakedefine HAVE_LIMITS_H 1 #cmakedefine HAVE_MNTENT_H 1 -#cmakedefine HAVE_NETINET_IN_H 1 #cmakedefine HAVE_PATHS_H 1 -#cmakedefine HAVE_SYS_MMAN_H 1 #cmakedefine HAVE_UNISTD_H 1 -#cmakedefine HAVE_ARPA_NAMESER_COMPAT_H -#cmakedefine HAVE_ARPA_NAMESER8_COMPAT_H #cmakedefine HAVE_XTEST 1 @@ -79,7 +75,6 @@ #cmakedefine HAVE_MKSTEMP 1 #cmakedefine HAVE_MKDTEMP 1 #cmakedefine HAVE_RANDOM 1 -#cmakedefine HAVE_READDIR_R 1 #cmakedefine HAVE_SENDFILE 1 #cmakedefine HAVE_SETENV 1 #cmakedefine HAVE_SETEUID 1 diff --git a/kdecore/CMakeLists.txt b/kdecore/CMakeLists.txt index 550ec30..5525901 100644 --- a/kdecore/CMakeLists.txt +++ b/kdecore/CMakeLists.txt @@ -44,6 +44,11 @@ configure_file(auth/BackendsConfig.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/BackendsC # Configure checks for localization configure_file(localization/config-localization.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-localization.h) +# Configure checks for util +include(util/ConfigureChecks.cmake) +configure_file(util/config-util.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-util.h) + + include_directories( ${KDE4_KDECORE_INCLUDES} ) include_directories( ${ZLIB_INCLUDE_DIR} ) include_directories( ${QT_INCLUDES} ) diff --git a/kdecore/io/kmountpoint.cpp b/kdecore/io/kmountpoint.cpp index aa7a6b1..e5df5dc 100644 --- a/kdecore/io/kmountpoint.cpp +++ b/kdecore/io/kmountpoint.cpp @@ -513,14 +513,15 @@ KMountPoint::Ptr KMountPoint::List::findByDevice(const QString& device) const bool KMountPoint::probablySlow() const { - bool nfs = d->mountType == QLatin1String("nfs"); + bool nfs = d->mountType == QLatin1String("nfs"); bool autofs = d->mountType == QLatin1String("autofs") || d->mountType == QLatin1String("subfs"); + bool fuse = d->mountType.startsWith(QLatin1String("fuse.")); //bool pid = d->mountPoint.contains(":(pid"); // The "pid" thing was in kde3's KIO::probably_slow_mounted, with obscure logic // (looks like it used state from the previous line or something...) // This needs to be revised once we have a testcase or explanation about it. // But autofs works already, it shows nfs as mountType in mtab. - if (nfs || autofs) { + if (nfs || autofs || fuse) { return true; } return false; diff --git a/kdecore/sonnet/globals.cpp b/kdecore/sonnet/globals.cpp index ef57aa7..bf4f504 100644 --- a/kdecore/sonnet/globals.cpp +++ b/kdecore/sonnet/globals.cpp @@ -83,6 +83,9 @@ QString detectLanguage(const QString &sentence) return max.key(); } +// SLOW!!! +// TODO: cache this value! And then use some dbus signal to notify all apps when +// changing the default language changes. QString defaultLanguageName() { Loader *loader = Loader::openLoader(); diff --git a/kdecore/util/ConfigureChecks.cmake b/kdecore/util/ConfigureChecks.cmake new file mode 100644 index 0000000..fe9f47e --- /dev/null +++ b/kdecore/util/ConfigureChecks.cmake @@ -0,0 +1,4 @@ +include(CheckIncludeFiles) +check_include_files("sys/types.h;sys/mman.h" HAVE_SYS_MMAN_H) + + diff --git a/kdecore/util/config-util.h.cmake b/kdecore/util/config-util.h.cmake new file mode 100644 index 0000000..83ccdf7 --- /dev/null +++ b/kdecore/util/config-util.h.cmake @@ -0,0 +1,2 @@ +#cmakedefine01 HAVE_SYS_MMAN_H + diff --git a/kdecore/util/kshareddatacache_p.h b/kdecore/util/kshareddatacache_p.h index 8bf9cf6..931de4d 100644 --- a/kdecore/util/kshareddatacache_p.h +++ b/kdecore/util/kshareddatacache_p.h @@ -20,7 +20,7 @@ #ifndef KSHAREDDATACACHE_P_H #define KSHAREDDATACACHE_P_H -#include // HAVE_SYS_MMAN_H +#include // HAVE_SYS_MMAN_H #include #include @@ -82,7 +82,7 @@ int ksdcArea(); #endif // BSD/Mac OS X compat -#ifdef HAVE_SYS_MMAN_H +#if HAVE_SYS_MMAN_H #include #endif #if !defined(MAP_ANONYMOUS) && defined(MAP_ANON) diff --git a/kdeui/actions/kstandardaction.cpp b/kdeui/actions/kstandardaction.cpp index 2b20078..7de0c6f 100644 --- a/kdeui/actions/kstandardaction.cpp +++ b/kdeui/actions/kstandardaction.cpp @@ -544,8 +544,8 @@ KToggleAction *showStatusbar(const QObject *recvr, const char *slot, QObject *pa KToggleAction *ret = new KToggleAction(i18n( "Show St&atusbar" ), parent); ret->setObjectName(name(ShowStatusbar)); - ret->setWhatsThis( i18n( "Show Statusbar

" - "Shows the statusbar, which is the bar at the bottom of the window used for status information." ) ); + ret->setWhatsThis( i18n( "Show Statusbar

" + "Shows the statusbar, which is the bar at the bottom of the window used for status information.

" ) ); ret->setChecked( true ); diff --git a/kdeui/fonts/kfontchooser.cpp b/kdeui/fonts/kfontchooser.cpp index 819dc1d..d243574 100644 --- a/kdeui/fonts/kfontchooser.cpp +++ b/kdeui/fonts/kfontchooser.cpp @@ -295,7 +295,7 @@ KFontChooser::KFontChooser( QWidget *parent, } // Populate usual styles, to determine minimum list width; // will be replaced later with correct styles. - d->styleListBox->addItem(i18nc("@item font","Regular")); + d->styleListBox->addItem(I18NC_NOX("QFontDatabase", "Normal")); d->styleListBox->addItem(i18nc("@item font","Italic")); d->styleListBox->addItem(i18nc("@item font","Oblique")); d->styleListBox->addItem(i18nc("@item font","Bold")); @@ -628,12 +628,13 @@ void KFontChooser::Private::_k_family_chosen_slot(const QString& family) if (style == I18NC_NOX("QFontDatabase", "Normal")) styleMod = i18nc("@item font", "Regular"); + // i18n: Filtering message, so that translators can script the // style string according to the font family name (e.g. may need // noun-adjective congruence wrt. gender of the family name). // The message provides the dynamic context 'family', which is // the family name to which the style string corresponds. - QString fstyle = ki18nc("@item Font style", "%1").subs(styleMod).inContext("family", pureFamily).toString(); + QString fstyle = ki18nc("@item Font style", "%1").subs(style).inContext("family", pureFamily).toString(); if (!filteredStyles.contains(fstyle)) { filteredStyles.append(fstyle); qtStyles.insert(fstyle, style); @@ -644,7 +645,7 @@ void KFontChooser::Private::_k_family_chosen_slot(const QString& family) styleListBox->addItems(filteredStyles); // Try to set the current style in the listbox to that previous. - int listPos = filteredStyles.indexOf(selectedStyle.isEmpty() ? i18nc("@item font", "Regular") : selectedStyle); + int listPos = filteredStyles.indexOf(selectedStyle.isEmpty() ? I18NC_NOX("QFontDatabase", "Normal") : selectedStyle); if (listPos < 0) { // Make extra effort to have Italic selected when Oblique was chosen, // and vice versa, as that is what the user would probably want. diff --git a/kdeui/kernel/kstartupinfo.cpp b/kdeui/kernel/kstartupinfo.cpp index bdc8972..87548c2 100644 --- a/kdeui/kernel/kstartupinfo.cpp +++ b/kdeui/kernel/kstartupinfo.cpp @@ -1140,6 +1140,7 @@ bool KStartupInfoId::operator<( const KStartupInfoId& id_P ) const return id() < id_P.id(); } +// KDE5 TODO: rename to isNull ? bool KStartupInfoId::none() const { return d->id.isEmpty() || d->id == "0"; diff --git a/kdeui/widgets/klineedit.cpp b/kdeui/widgets/klineedit.cpp index 9756ef7..d96c1c4 100644 --- a/kdeui/widgets/klineedit.cpp +++ b/kdeui/widgets/klineedit.cpp @@ -336,25 +336,22 @@ void KLineEdit::updateClearButtonIcon(const QString& text) return; } - int clearButtonState = KIconLoader::DefaultState; + // set proper icon if necessary + if (d->clearButton->pixmap().isNull()) { + const int clearButtonState = KIconLoader::DefaultState; + if (layoutDirection() == Qt::LeftToRight) { + d->clearButton->setPixmap(SmallIcon("edit-clear-locationbar-rtl", 0, clearButtonState)); + } else { + d->clearButton->setPixmap(SmallIcon("edit-clear-locationbar-ltr", 0, clearButtonState)); + } + } + // trigger animation if (d->wideEnoughForClear && text.length() > 0) { d->clearButton->animateVisible(true); } else { d->clearButton->animateVisible(false); } - - if (!d->clearButton->pixmap().isNull()) { - return; - } - - if (layoutDirection() == Qt::LeftToRight) { - d->clearButton->setPixmap(SmallIcon("edit-clear-locationbar-rtl", 0, clearButtonState)); - } else { - d->clearButton->setPixmap(SmallIcon("edit-clear-locationbar-ltr", 0, clearButtonState)); - } - - d->clearButton->setVisible(text.length() > 0); } // Determine geometry of clear button. Called initially, and on resizeEvent. diff --git a/kdeui/widgets/klineedit_p.h b/kdeui/widgets/klineedit_p.h index 95016bd..f7df463 100644 --- a/kdeui/widgets/klineedit_p.h +++ b/kdeui/widgets/klineedit_p.h @@ -56,7 +56,7 @@ public: void animateVisible(bool visible) { if (visible) { - if (m_animation->direction() == QPropertyAnimation::Forward) { + if (m_animation->direction() == QPropertyAnimation::Forward && m_opacity == 255) { return; } @@ -64,7 +64,7 @@ public: m_animation->setDuration(150); show(); } else { - if (m_animation->direction() == QPropertyAnimation::Backward) { + if (m_animation->direction() == QPropertyAnimation::Backward && m_opacity == 0) { return; } diff --git a/kio/kfile/kpropertiesdialog.cpp b/kio/kfile/kpropertiesdialog.cpp index feb0c9e..223ac7c 100644 --- a/kio/kfile/kpropertiesdialog.cpp +++ b/kio/kfile/kpropertiesdialog.cpp @@ -945,29 +945,26 @@ KFilePropsPlugin::KFilePropsPlugin( KPropertiesDialog *_props ) QLabel *l; if (!mimeComment.isEmpty() && !isTrash) { l = new QLabel(i18n("Type:"), d->m_frame ); + grid->addWidget(l, curRow, 0, Qt::AlignRight | Qt::AlignTop); - grid->addWidget(l, curRow, 0, Qt::AlignRight); - - KHBox *box = new KHBox(d->m_frame); - box->setSpacing(20); // ### why 20? + KVBox *box = new KVBox(d->m_frame); + box->setSpacing(2); // without that spacing the button literally “sticks” to the label ;) l = new QLabel(mimeComment, box ); + grid->addWidget(box, curRow++, 2); QPushButton *button = new QPushButton(box); - + button->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); // Minimum still makes the button grow to the entire layout width button->setIcon( KIcon(QString::fromLatin1("configure")) ); - const int pixmapSize = button->style()->pixelMetric(QStyle::PM_SmallIconSize); - button->setFixedSize( pixmapSize+8, pixmapSize+8 ); + if ( d->mimeType == KMimeType::defaultMimeType() ) - button->setToolTip(i18n("Create new file type")); + button->setText(i18n("Create New File Type")); else - button->setToolTip(i18n("Edit file type")); + button->setText(i18n("File Type Options")); connect( button, SIGNAL(clicked()), SLOT(slotEditFileType())); if (!KAuthorized::authorizeKAction("editfiletype")) button->hide(); - - grid->addWidget(box, curRow++, 2); } if ( !magicMimeComment.isEmpty() && magicMimeComment != mimeComment ) diff --git a/kio/misc/kpac/CMakeLists.txt b/kio/misc/kpac/CMakeLists.txt index 3c21e13..81fa79a 100644 --- a/kio/misc/kpac/CMakeLists.txt +++ b/kio/misc/kpac/CMakeLists.txt @@ -12,7 +12,7 @@ if(NOT KPAC_NO_SOLID) endif(NOT KPAC_NO_SOLID) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${KDE4_ENABLE_EXCEPTIONS}") - +include(ConfigureChecks.cmake) configure_file(config-kpac.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-kpac.h) ########### next target ############### diff --git a/kio/misc/kpac/ConfigureChecks.cmake b/kio/misc/kpac/ConfigureChecks.cmake new file mode 100644 index 0000000..47994b4 --- /dev/null +++ b/kio/misc/kpac/ConfigureChecks.cmake @@ -0,0 +1,4 @@ +include(CheckIncludeFiles) +check_include_files(arpa/nameser_compat.h HAVE_ARPA_NAMESER_COMPAT_H) +check_include_files(arpa/nameser8_compat.h HAVE_ARPA_NAMESER8_COMPAT_H) +check_include_files("sys/types.h;netinet/in.h" HAVE_NETINET_IN_H) diff --git a/kio/misc/kpac/config-kpac.h.cmake b/kio/misc/kpac/config-kpac.h.cmake index 58356e6..5a53614 100644 --- a/kio/misc/kpac/config-kpac.h.cmake +++ b/kio/misc/kpac/config-kpac.h.cmake @@ -1 +1,4 @@ #cmakedefine KPAC_NO_SOLID +#cmakedefine HAVE_ARPA_NAMESER_COMPAT_H +#cmakedefine HAVE_ARPA_NAMESER8_COMPAT_H +#cmakedefine HAVE_NETINET_IN_H 1 diff --git a/kio/misc/kpac/discovery.cpp b/kio/misc/kpac/discovery.cpp index a196879..b2266f8 100644 --- a/kio/misc/kpac/discovery.cpp +++ b/kio/misc/kpac/discovery.cpp @@ -19,7 +19,7 @@ #include - +#include #include #include diff --git a/kparts/CMakeLists.txt b/kparts/CMakeLists.txt index 2eab2e8..60f17ef 100644 --- a/kparts/CMakeLists.txt +++ b/kparts/CMakeLists.txt @@ -30,9 +30,23 @@ set(kparts_LIB_SRCS textextension.cpp htmlextension.cpp fileinfoextension.cpp + + # Private classes from libkactivities + private/libkactivities/manager_p.cpp + private/libkactivities/resourceinstance.cpp + listingextension.cpp ) + +# D-Bus connection to the activity manager +qt4_add_dbus_interface( + kparts_LIB_SRCS + private/libkactivities/org.kde.ActivityManager.xml + activitymanager_interface +) + + kde4_add_library(kparts ${LIBRARY_TYPE} ${kparts_LIB_SRCS}) target_link_libraries(kparts ${KDE4_KDECORE_LIBS} kdeui kio) @@ -42,8 +56,8 @@ if(HAVE_NEPOMUK) target_link_libraries(kparts LINK_INTERFACE_LIBRARIES nepomuk nepomukutils ) endif(HAVE_NEPOMUK) -set_target_properties(kparts PROPERTIES VERSION ${GENERIC_LIB_VERSION} - SOVERSION ${GENERIC_LIB_SOVERSION} +set_target_properties(kparts PROPERTIES VERSION ${GENERIC_LIB_VERSION} + SOVERSION ${GENERIC_LIB_SOVERSION} ) diff --git a/kparts/part.cpp b/kparts/part.cpp index f74bd78..a5769f5 100644 --- a/kparts/part.cpp +++ b/kparts/part.cpp @@ -26,6 +26,9 @@ #include "partmanager.h" #include "browserextension.h" +// the activity manager feeder (kamd) +#include "private/libkactivities/resourceinstance.h" + #include #include #include @@ -380,6 +383,7 @@ public: m_duringSaveAs = false; m_bTemp = false; m_bAutoDetectedMime = false; + m_resourceInstance = 0; } ~ReadOnlyPartPrivate() @@ -389,6 +393,8 @@ public: void _k_slotJobFinished( KJob * job ); void _k_slotStatJobFinished(KJob * job); void _k_slotGotMimeType(KIO::Job *job, const QString &mime); + void _k_slotOpeningCompleted(); + void _k_slotWindowCaptionChanged(const QString & caption); bool openLocalFile(); void openRemoteFile(); @@ -421,6 +427,13 @@ public: QString m_file; OpenUrlArguments m_arguments; + + /** + * Class for talking to the activity manager (kamd) + */ + KActivities::ResourceInstance * m_resourceInstance; + QString m_resourceCaption; + }; class ReadWritePartPrivate: public ReadOnlyPartPrivate @@ -450,11 +463,23 @@ public: ReadOnlyPart::ReadOnlyPart( QObject *parent ) : Part( *new ReadOnlyPartPrivate(this), parent ) { + QObject::connect( + this, SIGNAL(completed()), + this, SLOT(_k_slotOpeningCompleted()) + ); + QObject::connect( + this, SIGNAL(setWindowCaption(QString)), + this, SLOT(_k_slotWindowCaptionChanged(QString)) + ); } ReadOnlyPart::ReadOnlyPart( ReadOnlyPartPrivate &dd, QObject *parent ) : Part( dd, parent ) { + QObject::connect( + this, SIGNAL(completed()), + this, SLOT(_k_slotOpeningCompleted()) + ); } ReadOnlyPart::~ReadOnlyPart() @@ -473,6 +498,10 @@ void ReadOnlyPart::setUrl(const KUrl &url) { Q_D(ReadOnlyPart); + if (d->m_resourceInstance) { + d->m_resourceInstance->setUri(url); + } + d->m_url = url; } @@ -658,6 +687,17 @@ bool ReadOnlyPart::closeUrl() // It always succeeds for a read-only part, // but the return value exists for reimplementations // (e.g. pressing cancel for a modified read-write part) + + // Feeding the data to the activity manager (kamd) + kDebug(1000) + << "A component named" + << KGlobal::mainComponent().componentName() + << "has closed the" + << url(); + delete d->m_resourceInstance; + d->m_resourceInstance = 0; // just in case + // Finished with the activity manager + return true; } @@ -697,9 +737,53 @@ void ReadOnlyPartPrivate::_k_slotJobFinished( KJob * job ) } } +void ReadOnlyPartPrivate::_k_slotOpeningCompleted() +{ + Q_Q(ReadOnlyPart); + + // Feeding the data to the activity manager (kamd) + kDebug(1000) + << "A component named" + << KGlobal::mainComponent().componentName() + << "is opening the" + << q->url() + << ( q->widget() ? q->widget()->topLevelWidget()->winId() : 0 ) + << "mime" + << m_arguments.mimeType() + << "title" + << m_resourceCaption; + + // deleting the previous one + delete m_resourceInstance; + + m_resourceInstance = new KActivities::ResourceInstance( + ( q->widget() ? q->widget()->topLevelWidget()->winId() : 0 ), // wid + q->url(), // resourceUri + m_arguments.mimeType(), // mimetype + m_resourceCaption, // title + KActivities::ResourceInstance::User, // accessReason + KGlobal::mainComponent().componentName(), // application + q // parent + ); + // Finished with the activity manager +} + +void ReadOnlyPartPrivate::_k_slotWindowCaptionChanged(const QString & caption) +{ + kDebug(1000) << "This is the new caption" << caption; + + m_resourceCaption = caption; + + if (m_resourceInstance) { + kDebug(1000) << "KAMD: resource caption" << caption; + m_resourceInstance->setTitle(caption); + } +} + void ReadOnlyPartPrivate::_k_slotGotMimeType(KIO::Job *job, const QString &mime) { - kDebug(1000) << mime; + kDebug(1000) << "This is the mime type we got" << mime; + Q_ASSERT(job == m_job); Q_UNUSED(job) // set the mimetype only if it was not already set (for example, by the host application) if (m_arguments.mimeType().isEmpty()) { @@ -731,6 +815,13 @@ bool ReadOnlyPart::openStream( const QString& mimeType, const KUrl& url ) return false; d->m_arguments = args; d->m_url = url; + + kDebug(1000) + << "A component named" + << KGlobal::mainComponent().componentName() + << "is opening the stream" + << url << mimeType; + return doOpenStream( mimeType ); } @@ -796,6 +887,12 @@ void ReadWritePart::setModified( bool modified ) kError(1000) << "Can't set a read-only document to 'modified' !" << endl; return; } + + if ( modified && d->m_resourceInstance ) { + kDebug(1000) << "Notifying kamd of the change"; + d->m_resourceInstance->notifyModified(); + } + d->m_bModified = modified; } diff --git a/kparts/part.h b/kparts/part.h index 56b64da..f62f2d7 100644 --- a/kparts/part.h +++ b/kparts/part.h @@ -717,6 +717,9 @@ private: Q_PRIVATE_SLOT(d_func(), void _k_slotStatJobFinished(KJob*)) Q_PRIVATE_SLOT(d_func(), void _k_slotGotMimeType(KIO::Job *job, const QString &mime)) + Q_PRIVATE_SLOT(d_func(), void _k_slotOpeningCompleted()) + Q_PRIVATE_SLOT(d_func(), void _k_slotWindowCaptionChanged(const QString & caption)) + Q_DISABLE_COPY(ReadOnlyPart) }; class ReadWritePartPrivate; diff --git a/kparts/private/libkactivities/CMakeLists.txt b/kparts/private/libkactivities/CMakeLists.txt new file mode 100644 index 0000000..e164126 --- /dev/null +++ b/kparts/private/libkactivities/CMakeLists.txt @@ -0,0 +1,152 @@ +project(kactivities) + +cmake_minimum_required(VERSION 2.8) + +FIND_PACKAGE(KDE4 REQUIRED) +INCLUDE(KDE4Defaults) +INCLUDE(MacroLibrary) +INCLUDE(MacroOptionalAddSubdirectory) +INCLUDE(FindPackageHandleStandardArgs) + +# ======================================================= +# Information to update before to release this library. + +# Library version history: +# API ABI +# 0.1.0 => 0.1.0 +# 0.1.1 => 0.1.1 +# 0.2.0 => 0.2.0 + +# Library API version +SET(KACTIVITIES_LIB_MAJOR_VERSION "6") +SET(KACTIVITIES_LIB_MINOR_VERSION "0") +SET(KACTIVITIES_LIB_PATCH_VERSION "0") + +# Suffix to add at end of version string. Usual values are: +# "-git" : alpha code unstable from git. Do not use in production +# "-beta1" : beta1 release. +# "-beta2" : beta2 release. +# "-beta3" : beta3 release. +# "-rc" : release candidate. +# "" : final relase. Can be used in production. +SET(KACTIVITIES_LIB_SUFFIX_VERSION "") + +# Library ABI version used by linker. +# For details : http://www.gnu.org/software/libtool/manual/libtool.html#Updating-version-info +SET(KACTIVITIES_LIB_SO_CUR_VERSION "6") +SET(KACTIVITIES_LIB_SO_REV_VERSION "0") +SET(KACTIVITIES_LIB_SO_AGE_VERSION "0") + +# ======================================================= +# Set env. variables accordinly. + +set(KACTIVITIES_INCLUDE_DIR + "${CMAKE_CURRENT_SOURCE_DIR}/.." + "${CMAKE_CURRENT_SOURCE_DIR}/" + CACHE STRING + "Location of libkactivities headers" FORCE) +set(KACTIVITIES_LIBS + "kactivities" + CACHE STRING + "Location of libkactivities binary" FORCE) + +SET(KACTIVITIES_LIB_VERSION_STRING "${KACTIVITIES_LIB_MAJOR_VERSION}.${KACTIVITIES_LIB_MINOR_VERSION}.${KACTIVITIES_LIB_PATCH_VERSION}${KACTIVITIES_LIB_SUFFIX_VERSION}") +SET(KACTIVITIES_LIB_VERSION_ID "0x0${KACTIVITIES_LIB_MAJOR_VERSION}0${KACTIVITIES_LIB_MINOR_VERSION}0${KACTIVITIES_LIB_PATCH_VERSION}") +SET(KACTIVITIES_LIB_SO_VERSION_STRING "${KACTIVITIES_LIB_SO_CUR_VERSION}.${KACTIVITIES_LIB_SO_REV_VERSION}.${KACTIVITIES_LIB_SO_AGE_VERSION}") + +ADD_DEFINITIONS (${QT_DEFINITIONS} ${QT_QTDBUS_DEFINITIONS} ${KDE4_DEFINITIONS}) +INCLUDE_DIRECTORIES (${QDBUS_INCLUDE_DIRS} ${CMAKE_SOURCE_DIR} ${CMAKE_BINARY_DIR} ${KDE4_INCLUDES}) + +include_directories( + ${CMAKE_SOURCE_DIR} + ${CMAKE_BINARY_DIR} + ${KDE4_INCLUDES} + ${KDE4_KIO_INCLUDES} + ) + +set( + kactivities_LIB_SRCS + + consumer.cpp + controller.cpp + info.cpp + manager_p.cpp + resourceinstance.cpp + ) + +qt4_add_dbus_interface( + kactivities_LIB_SRCS + + org.kde.ActivityManager.xml + activitymanager_interface +) + + +kde4_add_library( + kactivities SHARED + ${kactivities_LIB_SRCS} + ) + + +set_target_properties( + kactivities + PROPERTIES + VERSION ${KACTIVITIES_LIB_SO_VERSION_STRING} + SOVERSION ${KACTIVITIES_LIB_SO_CUR_VERSION} + ) + +target_link_libraries( + kactivities + ${KDE4_KDECORE_LIBS} + ) + +## install + +set( + kactivities_LIB_HEADERS + consumer.h + controller.h + info.h + resourceinstance.h + ) + +set( + kactivities_LIB_PRETTY_HEADERS + includes/KActivities/Consumer + includes/KActivities/Controller + includes/KActivities/Info + includes/KActivities/ResourceInstance + ) + +install( + FILES ${kactivities_LIB_HEADERS} + DESTINATION ${INCLUDE_INSTALL_DIR}/kactivities + COMPONENT Devel + ) + +install( + FILES ${kactivities_LIB_PRETTY_HEADERS} + DESTINATION ${INCLUDE_INSTALL_DIR}/KDE/KActivities + COMPONENT Devel + ) + +install( + TARGETS kactivities + EXPORT kdelibsLibraryTargets + ${INSTALL_TARGETS_DEFAULT_ARGS} + ) + +IF(NOT WIN32) + CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/libkactivities.pc.cmake ${CMAKE_CURRENT_BINARY_DIR}/libkactivities.pc) + INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/libkactivities.pc DESTINATION ${LIB_INSTALL_DIR}/pkgconfig ) +ENDIF(NOT WIN32) + +CONFIGURE_FILE( + KActivitiesConfig.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/KActivitiesConfig.cmake @ONLY +) + +INSTALL( + FILES ${CMAKE_CURRENT_BINARY_DIR}/KActivitiesConfig.cmake + DESTINATION ${CMAKE_INSTALL_PREFIX}/lib${LIB_SUFFIX}/cmake/KActivities +) + diff --git a/kparts/private/libkactivities/manager_p.cpp b/kparts/private/libkactivities/manager_p.cpp new file mode 100644 index 0000000..e71aec8 --- /dev/null +++ b/kparts/private/libkactivities/manager_p.cpp @@ -0,0 +1,89 @@ +/* + * Copyright (C) 2010 Ivan Cukic + * + * 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) any later version, 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 "manager_p.h" + +#include + +#include +#include + +namespace KActivities { + +Manager * Manager::s_instance = NULL; + +// #define ACTIVITY_MANAGER_DBUS_PATH "org.kde.ActivityManager" +#define ACTIVITY_MANAGER_DBUS_PATH "org.kde.kactivitymanagerd" +#define ACTIVITY_MANAGER_DBUS_OBJECT "/ActivityManager" + +Manager::Manager() + : org::kde::ActivityManager( + ACTIVITY_MANAGER_DBUS_PATH, + ACTIVITY_MANAGER_DBUS_OBJECT, + QDBusConnection::sessionBus() + ) +{ + connect(&m_watcher, SIGNAL(serviceOwnerChanged(const QString &, const QString &, const QString &)), + this, SLOT(serviceOwnerChanged(const QString &, const QString &, const QString &))); +} + +Manager * Manager::self() +{ + if (!s_instance) { + // check if the activity manager is already running + if (!isActivityServiceRunning()) { + + // not running, trying to launch it + QString error; + + int ret = KToolInvocation::startServiceByDesktopPath("kactivitymanagerd.desktop", QStringList(), &error); + if (ret > 0) { + kDebug() << "Activity: Couldn't start kactivitymanagerd: " << error << endl; + } + + if (!QDBusConnection::sessionBus().interface()->isServiceRegistered(ACTIVITY_MANAGER_DBUS_PATH)) { + kDebug() << "Activity: The kactivitymanagerd service is still not registered"; + } else { + kDebug() << "Activity: The kactivitymanagerd service has been registered"; + } + } + + // creating a new instance of the class + s_instance = new Manager(); + } + + return s_instance; +} + +bool Manager::isActivityServiceRunning() +{ + return QDBusConnection::sessionBus().interface()->isServiceRegistered(ACTIVITY_MANAGER_DBUS_PATH); +} + +void Manager::serviceOwnerChanged(const QString & serviceName, const QString & oldOwner, const QString & newOwner) +{ + Q_UNUSED(oldOwner) + + if (serviceName == ACTIVITY_MANAGER_DBUS_PATH) { + emit presenceChanged(!newOwner.isEmpty()); + } +} + +} // namespace KActivities + diff --git a/kparts/private/libkactivities/manager_p.h b/kparts/private/libkactivities/manager_p.h new file mode 100644 index 0000000..b92a94f --- /dev/null +++ b/kparts/private/libkactivities/manager_p.h @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2010 Ivan Cukic + * + * 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) any later version, 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 ACTIVITIES_MANAGER_P_ +#define ACTIVITIES_MANAGER_P_ + +#include "activitymanager_interface.h" + +#include + +namespace KActivities { + +class Manager: public org::kde::ActivityManager { + Q_OBJECT +public: + static Manager * self(); + + static bool isActivityServiceRunning(); + +public Q_SLOTS: + void serviceOwnerChanged(const QString & serviceName, const QString & oldOwner, const QString & newOwner); + +Q_SIGNALS: + void presenceChanged(bool present); + +private: + Manager(); + + QDBusServiceWatcher m_watcher; + + static Manager * s_instance; +}; + +} // namespace KActivities + +#endif // ACTIVITIES_MANAGER_P_ diff --git a/kparts/private/libkactivities/org.kde.ActivityManager.xml b/kparts/private/libkactivities/org.kde.ActivityManager.xml new file mode 100644 index 0000000..07a5b34 --- /dev/null +++ b/kparts/private/libkactivities/org.kde.ActivityManager.xml @@ -0,0 +1,118 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/kparts/private/libkactivities/resourceinstance.cpp b/kparts/private/libkactivities/resourceinstance.cpp new file mode 100644 index 0000000..6bf3925 --- /dev/null +++ b/kparts/private/libkactivities/resourceinstance.cpp @@ -0,0 +1,180 @@ +/* + * Copyright (C) 2011 Ivan Cukic + * + * 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) any later version, 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 "resourceinstance.h" +#include "manager_p.h" + +#include + +namespace KActivities { + +#ifdef Q_OS_WIN64 +__inline int toInt(WId wid) +{ + return (int)((__int64)wid); +} + +#else +__inline int toInt(WId wid) +{ + return (int)wid; +} +#endif + +class ResourceInstancePrivate { +public: + WId wid; + ResourceInstance::AccessReason reason; + QUrl uri; + QString mimetype; + QString title; + QString application; + + void closeResource(); + void openResource(); + + enum Type { + Accessed = 0, + Opened = 1, + Modified = 2, + Closed = 3, + FocusedIn = 4, + FocusedOut = 5 + }; + + static void registerResourceEvent(const QString &application, WId wid, const QUrl &uri, Type event, ResourceInstance::AccessReason reason) + { + Manager::self()->RegisterResourceEvent(application, toInt(wid), uri.toString(), uint(event), uint(reason)); + } +}; + +void ResourceInstancePrivate::closeResource() +{ + registerResourceEvent(application, wid, uri, Closed, reason); +} + +void ResourceInstancePrivate::openResource() +{ + registerResourceEvent(application, wid, uri, Opened, reason); +} + +ResourceInstance::ResourceInstance(WId wid, AccessReason reason, const QString &application, QObject *parent) + : QObject(parent), d(new ResourceInstancePrivate()) +{ + d->wid = wid; + d->reason = reason; + d->application = application.isEmpty() ? QCoreApplication::instance()->applicationName() : application; + +} + +ResourceInstance::ResourceInstance(WId wid, QUrl resourceUri, const QString &mimetype, const QString &title, AccessReason reason, const QString &application, QObject *parent) + : QObject(parent), d(new ResourceInstancePrivate()) +{ + d->wid = wid; + d->reason = reason; + d->uri = resourceUri; + d->mimetype = mimetype; + d->title = title; + d->application = application.isEmpty() ? QCoreApplication::instance()->applicationName() : application; + + d->openResource(); +} + +ResourceInstance::~ResourceInstance() +{ + d->closeResource(); + delete d; +} + +void ResourceInstance::notifyModified() +{ + d->registerResourceEvent(d->application, d->wid, d->uri, ResourceInstancePrivate::Modified, d->reason); +} + +void ResourceInstance::notifyFocusedIn() +{ + d->registerResourceEvent(d->application, d->wid, d->uri, ResourceInstancePrivate::FocusedIn, d->reason); +} + +void ResourceInstance::notifyFocusedOut() +{ + d->registerResourceEvent(d->application, d->wid, d->uri, ResourceInstancePrivate::FocusedOut, d->reason); +} + +void ResourceInstance::setUri(const QUrl &newUri) +{ + if (d->uri == newUri) + return; + + if (!d->uri.isEmpty()) { + d->closeResource(); + } + + d->uri = newUri; + + d->openResource(); +} + +void ResourceInstance::setMimetype(const QString &mimetype) +{ + d->mimetype = mimetype; + // TODO: update the service info + Manager::self()->RegisterResourceMimeType(d->uri.toString(), mimetype); +} + +void ResourceInstance::setTitle(const QString &title) +{ + d->title = title; + // TODO: update the service info + Manager::self()->RegisterResourceTitle(d->uri.toString(), title); +} + +QUrl ResourceInstance::uri() const +{ + return d->uri; +} + +QString ResourceInstance::mimetype() const +{ + return d->mimetype; +} + +QString ResourceInstance::title() const +{ + return d->title; +} + +WId ResourceInstance::winId() const +{ + return d->wid; +} + +ResourceInstance::AccessReason ResourceInstance::accessReason() const +{ + return d->reason; +} + +void ResourceInstance::notifyAccessed(const QUrl &uri, const QString &application) +{ + ResourceInstancePrivate::registerResourceEvent( + application.isEmpty() ? QCoreApplication::instance()->applicationName() : application, + 0, uri, ResourceInstancePrivate::Accessed, User); +} + +} // namespace KActivities diff --git a/kparts/private/libkactivities/resourceinstance.h b/kparts/private/libkactivities/resourceinstance.h new file mode 100644 index 0000000..d1cbab4 --- /dev/null +++ b/kparts/private/libkactivities/resourceinstance.h @@ -0,0 +1,214 @@ +/* + * Copyright (C) 2011 Ivan Cukic + * + * 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) any later version, 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 ACTIVITIES_RESOURCEINSTANCE_H_ +#define ACTIVITIES_RESOURCEINSTANCE_H_ + +#include +#include +#include + +#include + +namespace KActivities { + +class ResourceInstancePrivate; + +/** + * This class is used to notify the system that a file, web page + * or some other resource has been accessed. + * + * It provides methods to notify the system when the resource was + * opened, modified and closed, along with in what window the + * resource is shown. + * + * You should create an instance of this class for every resource + * you open. + * + * "The system" in this case can be the backend for tracking + * and automatically scoring files that are being accessed, the + * system to show the open files per window in the taskbar, + * the share-like-connect, etc. + * + * The user of this class shouldn't care about the backend + * systems - everything is done under-the-hood automatically. + * + */ +class KDE_EXPORT ResourceInstance: public QObject +{ + Q_OBJECT + + Q_PROPERTY(QUrl uri READ uri WRITE setUri) + Q_PROPERTY(QString mimetype READ mimetype WRITE setMimetype) + Q_PROPERTY(QString title READ title WRITE setTitle) + Q_PROPERTY(WId winId READ winId) + Q_PROPERTY(AccessReason accessReason READ accessReason) + +public: + /*** + * The reason for opening the resource + */ + enum AccessReason { + User = 0, ///< Due to an explicit user request + Scheduled = 1, ///< As a result of a user-scheduled action + Heuristic = 2, ///< Deduced from user's activity, or indirectly requested + System = 3, ///< Due to a system event + World = 4 ///< Due to an action performed by an external entity + }; + Q_ENUMS(AccessReason) + + /** + * Creates a new resource instance + * @param wid id of the window that will show the resource + * @param reason reason for opening the resource + * @param application application's name (the name used for the .desktop file). + * If not specified, QCoreApplication::applicationName is used + * @param parent pointer to the parent object + */ + ResourceInstance(WId wid, AccessReason reason = User, const QString &application = QString(), QObject *parent = 0); + + /** + * Creates a new resource instance and automatically + * notifies the system that it was opened. + * + * In some special cases, where the URI of the resource is + * being constantly changed (for example, in the world globe, + * street map applications) you have two options: + * - to pass an empty resourceUri while passing the mimetype + * - to update the uri from time to time (in the example of + * the world map - to send URIs for major objects - cities + * or main streets. + * and in both cases reimplementing the currentUri() method + * which will return the exact URI shown at that specific moment. + * + * @param wid window id in which the resource is shown + * @param resourceUri URI of the resource that is shown + * @param mimetype the mime type of the resource + * @param title the title of the resource + * @param reason reason for opening the resource + * @param application application's name (the name used for the .desktop file). + * If not specified, QCoreApplication::applicationName is used + * @param parent pointer to the parent object + */ + ResourceInstance(WId wid, QUrl resourceUri, const QString &mimetype = QString(), const QString &title = QString(), AccessReason reason = User, const QString &application = QString(), QObject *parent = 0); + + /** + * Destroys the ResourceInstance and notifies the system + * that the resource has been closed + */ + ~ResourceInstance(); + +public Q_SLOTS: + /** + * Call this method to notify the system that you modified + * (the contents of) the resource + */ + void notifyModified(); + + /** + * Call this method to notify the system that the resource + * has the focus in your application + * @note You only need to call this in MDI applications + */ + void notifyFocusedIn(); + + /** + * Call this method to notify the system that the resource + * lost the focus in your application + * @note You only need to call this in MDI applications + */ + void notifyFocusedOut(); + + /** + * This is a convenience method that sets the new URI. + * This is usually handled by sending the close event for + * the previous URI, and an open event for the new one. + */ + void setUri(const QUrl &newUri); + + /** + * Sets the mimetype for this resource + */ + void setMimetype(const QString &mimetype); + + /** + * Sets the title for this resource + */ + void setTitle(const QString &title); + +Q_SIGNALS: + /** + * Emitted when the system wants to show the resource + * represented by this ResourceInstance. + * + * You should listen to this signal if you have multiple + * resources shown in one window (MDI). On catching it, show + * the resource and give it focus. + */ + void requestsFocus(); + +public: + /** + * @returns the current uri + * The default implementation returns the URI that was passed + * to the constructor. + * You need to reimplement it only for the applications with + * frequently updated URIs. + */ + virtual QUrl uri() const; + + /** + * @returns mimetype of the resource + */ + QString mimetype() const; + + /** + * @returns title of the resource + */ + QString title() const; + + /** + * @returns the window id + */ + WId winId() const; + + /** + * @returns the reason for accessing the resource + */ + AccessReason accessReason() const; + + /** + * If there's no way to tell for how long an application is keeping + * the resource open, you can just call this static method - it + * will notify the system that the application has accessed the + * resource + * @param uri URI of the resource + * @param application application's name (the name used for the .desktop file). + * If not specified, QCoreApplication::applicationName is used + * + */ + static void notifyAccessed(const QUrl &uri, const QString &application = QString()); + +private: + ResourceInstancePrivate * const d; +}; + +} + +#endif // ACTIVITIES_RESOURCEINSTANCE_H_ diff --git a/nepomuk/query/queryserviceclient.cpp b/nepomuk/query/queryserviceclient.cpp index ddabff7..7d3ef0f 100644 --- a/nepomuk/query/queryserviceclient.cpp +++ b/nepomuk/query/queryserviceclient.cpp @@ -100,9 +100,12 @@ public: void _k_entriesRemoved( const QStringList& ); void _k_finishedListing(); void _k_handleQueryReply(QDBusPendingCallWatcher*); + void _k_serviceRegistered( const QString& ); + void _k_serviceUnregistered( const QString& ); org::kde::nepomuk::QueryService* queryServiceInterface; org::kde::nepomuk::Query* queryInterface; + QDBusServiceWatcher *queryServiceWatcher; QueryServiceClient* q; @@ -169,6 +172,27 @@ void Nepomuk::Query::QueryServiceClient::Private::_k_handleQueryReply(QDBusPendi } +void Nepomuk::Query::QueryServiceClient::Private::_k_serviceRegistered(const QString &service) +{ + if (service == "org.kde.nepomuk.services.nepomukqueryservice") { + delete queryServiceInterface; + queryServiceInterface = new org::kde::nepomuk::QueryService( "org.kde.nepomuk.services.nepomukqueryservice", + "/nepomukqueryservice", + dbusConnection ); + emit q->serviceAvailabilityChanged(true); + } +} + + +void Nepomuk::Query::QueryServiceClient::Private::_k_serviceUnregistered(const QString &service) +{ + if (service == "org.kde.nepomuk.services.nepomukqueryservice") { + emit q->serviceAvailabilityChanged(false); + } +} + + + Nepomuk::Query::QueryServiceClient::QueryServiceClient( QObject* parent ) : QObject( parent ), @@ -182,6 +206,12 @@ Nepomuk::Query::QueryServiceClient::QueryServiceClient( QObject* parent ) d->queryServiceInterface = new org::kde::nepomuk::QueryService( "org.kde.nepomuk.services.nepomukqueryservice", "/nepomukqueryservice", d->dbusConnection ); + d->queryServiceWatcher = new QDBusServiceWatcher(QLatin1String("org.kde.nepomuk.services.nepomukqueryservice"), + QDBusConnection::sessionBus(), + QDBusServiceWatcher::WatchForOwnerChange, + this); + connect(d->queryServiceWatcher, SIGNAL(serviceRegistered(QString)), this, SLOT(_k_serviceRegistered(QString))); + connect(d->queryServiceWatcher, SIGNAL(serviceUnregistered(QString)), this, SLOT(_k_serviceUnregistered(QString))); } diff --git a/nepomuk/query/queryserviceclient.h b/nepomuk/query/queryserviceclient.h index 234d4b0..d41bfc0 100644 --- a/nepomuk/query/queryserviceclient.h +++ b/nepomuk/query/queryserviceclient.h @@ -320,6 +320,13 @@ namespace Nepomuk { */ void error( const QString& errorMessage ); + /** + * Emitted when the availability of the query service changes + * + * \since 4.8 + */ + void serviceAvailabilityChanged( bool running ); + private: class Private; Private* const d; @@ -327,6 +334,8 @@ namespace Nepomuk { Q_PRIVATE_SLOT( d, void _k_entriesRemoved( const QStringList& ) ) Q_PRIVATE_SLOT( d, void _k_finishedListing() ) Q_PRIVATE_SLOT( d, void _k_handleQueryReply(QDBusPendingCallWatcher*) ) + Q_PRIVATE_SLOT( d, void _k_serviceRegistered( const QString& ) ) + Q_PRIVATE_SLOT( d, void _k_serviceUnregistered( const QString& ) ) }; } } diff --git a/plasma/CMakeLists.txt b/plasma/CMakeLists.txt index c179882..982c590 100644 --- a/plasma/CMakeLists.txt +++ b/plasma/CMakeLists.txt @@ -6,10 +6,15 @@ if(KDE_PLATFORM_FEATURE_BINARY_COMPATIBLE_FEATURE_REDUCTION) set(PLASMA_NO_KNEWSTUFF TRUE) set(PLASMA_NO_SOLID TRUE) set(PLASMA_NO_KIO TRUE) + set(PLASMA_NO_PACKAGEKIT TRUE) set(PLASMA_NO_KUTILS TRUE) set(PLASMA_NO_GLOBAL_SHORTCUTS TRUE) endif(KDE_PLATFORM_FEATURE_BINARY_COMPATIBLE_FEATURE_REDUCTION) +if(NOT Q_WS_X11) + set(PLASMA_NO_PACKAGEKIT TRUE) +endif(NOT Q_WS_X11) + include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${KDE4_KDECORE_INCLUDES} ${KDE4_KDEUI_INCLUDES} @@ -44,6 +49,11 @@ if(NOT PLASMA_NO_SOLID) set(PLASMA_EXTRA_LIBS ${PLASMA_EXTRA_LIBS} ${KDE4_SOLID_LIBS}) endif(NOT PLASMA_NO_SOLID) +if(NOT PLASMA_NO_PACKAGEKIT) + add_definitions(-DPLASMA_ENABLE_PACKAGEKIT_SUPPORT=1) + set(PLASMA_EXTRA_LIBS ${PLASMA_EXTRA_LIBS} ${QT_QTDBUS_LIBRARY}) +endif(NOT PLASMA_NO_PACKAGEKIT) + if (NOT PLASMA_NO_KUTILS) include_directories(${CMAKE_SOURCE_DIR}/kutils) set(PLASMA_EXTRA_LIBS ${PLASMA_EXTRA_LIBS} ${KDE4_KUTILS_LIBS}) @@ -117,6 +127,7 @@ set(plasma_LIB_SRCS private/animablegraphicswebview.cpp private/applethandle.cpp private/associatedapplicationmanager.cpp + private/componentinstaller.cpp private/datacontainer_p.cpp private/dataenginebindings.cpp private/dataengineconsumer.cpp diff --git a/plasma/dataenginemanager.cpp b/plasma/dataenginemanager.cpp index f6dabf0..49df135 100644 --- a/plasma/dataenginemanager.cpp +++ b/plasma/dataenginemanager.cpp @@ -29,6 +29,7 @@ #include "datacontainer.h" #include "pluginloader.h" +#include "private/componentinstaller_p.h" #include "private/dataengine_p.h" #include "private/datacontainer_p.h" #include "scripting/scriptengine.h" @@ -130,6 +131,9 @@ Plasma::DataEngine *DataEngineManager::loadEngine(const QString &name) DataEngine *engine = PluginLoader::pluginLoader()->loadDataEngine(name); if (!engine) { + // Try installing the engine. However, it's too late for this request. + ComponentInstaller::self()->installMissingComponent("dataengine", name); + return d->nullEngine(); } diff --git a/plasma/private/componentinstaller.cpp b/plasma/private/componentinstaller.cpp new file mode 100644 index 0000000..870667f --- /dev/null +++ b/plasma/private/componentinstaller.cpp @@ -0,0 +1,103 @@ +/* + * Copyright 2011 Kevin Kofler + * + * This program 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, 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 Library 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 "private/componentinstaller_p.h" + +#include + +#ifdef PLASMA_ENABLE_PACKAGEKIT_SUPPORT +#include +#include +#include +#include +#include +#include +#endif + +namespace Plasma +{ + +class ComponentInstallerPrivate +{ + public: +#ifdef PLASMA_ENABLE_PACKAGEKIT_SUPPORT + QSet alreadyPrompted; +#endif +}; + +class ComponentInstallerSingleton +{ + public: + ComponentInstaller self; +}; + +K_GLOBAL_STATIC(ComponentInstallerSingleton, privateComponentInstallerSelf) + +ComponentInstaller *ComponentInstaller::self() +{ + return &privateComponentInstallerSelf->self; +} + +ComponentInstaller::ComponentInstaller() + : d(new ComponentInstallerPrivate) +{ +} + +ComponentInstaller::~ComponentInstaller() +{ + delete d; +} + +void ComponentInstaller::installMissingComponent(const QString &type, + const QString &name, + QWidget *parent, bool force) +{ +#ifdef PLASMA_ENABLE_PACKAGEKIT_SUPPORT + QString searchString = type + '-' + name; + + if (!force) { + if (d->alreadyPrompted.contains(searchString)) { + return; + } + } + + d->alreadyPrompted.insert(searchString); + + QDBusInterface packageKit(QLatin1String("org.freedesktop.PackageKit"), + QLatin1String("/org/freedesktop/PackageKit"), + QLatin1String("org.freedesktop.PackageKit.Modify")); + // We don't check packageKit.isValid() because the service is activated on + // demand, so it will show up as "not valid". + WId wid = 0; + if (parent) { + wid = parent->winId(); + } + QStringList resources; + resources.append(searchString); + packageKit.asyncCall(QLatin1String("InstallResources"), (unsigned int) wid, + QLatin1String("plasma-service"), resources, QString()); +#else + Q_UNUSED(type); + Q_UNUSED(name); + Q_UNUSED(parent); + Q_UNUSED(force); +#endif +} + +} // namespace Plasma diff --git a/plasma/private/componentinstaller_p.h b/plasma/private/componentinstaller_p.h new file mode 100644 index 0000000..f85cbb6 --- /dev/null +++ b/plasma/private/componentinstaller_p.h @@ -0,0 +1,94 @@ +/* + * Copyright 2011 Kevin Kofler + * + * This program 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, 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 Library 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 PLASMA_COMPONENTINSTALLER_H +#define PLASMA_COMPONENTINSTALLER_H + +class QString; +class QWidget; + +namespace Plasma +{ + +class ComponentInstallerPrivate; + +/** + * @class ComponentInstaller plasma/private/componentinstaller_p.h + * + * @short This class provides a generic API for installation of components. + * + * @internal + * + * Plasma::ComponentInstaller allows searching for a missing data or script + * engine by name, and allowing the user to install the missing service. + * Currently, PackageKit is supported as the mechanism to install components, + * but more mechanisms could be supported in the future through the same API. + * + * @since 4.8 + */ +class ComponentInstaller +{ + public: + /** + * Singleton pattern accessor. + */ + static ComponentInstaller *self(); + + /** + * Installs a missing component asynchronously. + * + * By default, this method will cache requested components and not + * prompt again for the same engine in the same session. The force + * parameter can be used to disable this mechanism, e.g. when the user + * just installed a new widget written in a scripting language, and so + * is likely to want the script engine installed after all. + * + * In the case of on-demand installation, this will unfortunately not + * allow the call which triggered the missing component lookup to + * succeed, but we cannot afford to block all of Plasma until the + * mechanism is done installing the service. + * + * This function does nothing if PackageKit integration was disabled at + * compile time. + * + * @param type the type of the component, should be "scriptengine" or + * "dataengine" + * @param name the name of the component + * @param parent a parent widget, used to set the wid for PackageKit + * @param force whether to always prompt, even if recently prompted + */ + void installMissingComponent(const QString &type, const QString &name, + QWidget *parent = 0, bool force = false); + + private: + /** + * Default constructor. The singleton method self() is the + * preferred access mechanism. + */ + ComponentInstaller(); + ~ComponentInstaller(); + + ComponentInstallerPrivate *const d; + + friend class ComponentInstallerSingleton; +}; + +} // namespace Plasma + +#endif // multiple inclusion guard diff --git a/plasma/scripting/scriptengine.cpp b/plasma/scripting/scriptengine.cpp index fb8cd1a..21f8a9a 100644 --- a/plasma/scripting/scriptengine.cpp +++ b/plasma/scripting/scriptengine.cpp @@ -27,6 +27,7 @@ #include "applet.h" #include "dataengine.h" #include "package.h" +#include "private/componentinstaller_p.h" #include "scripting/appletscript.h" #include "scripting/dataenginescript.h" #include "scripting/runnerscript.h" @@ -196,6 +197,9 @@ ScriptEngine *loadEngine(const QString &language, ComponentType type, QObject *p << "! error reported: " << error; } + // Try installing the engine. However, it's too late for this request. + ComponentInstaller::self()->installMissingComponent("scriptengine", language); + return 0; } diff --git a/solid/solid/CMakeLists.txt b/solid/solid/CMakeLists.txt index 0aa7a43..623dd0a 100644 --- a/solid/solid/CMakeLists.txt +++ b/solid/solid/CMakeLists.txt @@ -42,6 +42,7 @@ file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/backends/hal ${CMAKE_CURRENT_BINARY_DIR}/backends/udev ${CMAKE_CURRENT_BINARY_DIR}/backends/wmi + ${CMAKE_CURRENT_BINARY_DIR}/backends/fuse ) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${KDE4_C_FLAGS}") # enable -fvisibility=hidden for C sources @@ -289,6 +290,17 @@ if(NOT WIN32 AND NOT APPLE) backends/fstab/fstabwatcher.cpp ) + message(STATUS "Building Solid Fuse backend." ) + set(solid_LIB_SRCS ${solid_LIB_SRCS} + backends/fuse/fusemanager.cpp + backends/fuse/fusedevice.cpp + backends/fuse/fusestorageaccess.cpp + backends/fuse/fusestoragedrive.cpp + backends/fuse/fusestoragevolume.cpp + backends/fuse/fusehandling.cpp + backends/fuse/fusewatcher.cpp + ) + endif(NOT WIN32 AND NOT APPLE) if(APPLE) diff --git a/solid/solid/backends/fuse/fusedevice.cpp b/solid/solid/backends/fuse/fusedevice.cpp new file mode 100644 index 0000000..20a9783 --- /dev/null +++ b/solid/solid/backends/fuse/fusedevice.cpp @@ -0,0 +1,138 @@ +/* + Copyright 2010 Mario Bensi + Copyright 2012 Ivan Cukic + + 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 "fusedevice.h" +#include "fusehandling.h" +#include "fusestorageaccess.h" +#include "fusestoragedrive.h" +#include "fusestoragevolume.h" +#include "fuseservice.h" +#include +#include + +using namespace Solid::Backends::Fuse; + +FuseDevice::FuseDevice(QString udi) : + Solid::Ifaces::Device(), + m_udi(udi) +{ + qDebug() << "UDI:" << udi; + m_device = m_udi.mid(QString::fromLatin1(FUSE_UDI_PREFIX).length(), -1); + + if (m_device.endsWith(":media")) { + m_device.chop(6); + } + + m_product = m_device; + m_vendor = "FUSE"; + + m_description = m_vendor + " on " + m_product; + qDebug() << "Info:" << m_device << m_product << m_vendor << m_description; +} + +FuseDevice::~FuseDevice() +{ +} + +QString FuseDevice::udi() const +{ + return m_udi; +} + +QString FuseDevice::parentUdi() const +{ + return udi(); + // return QString::fromLatin1(FUSE_UDI_PREFIX); +} + +QString FuseDevice::vendor() const +{ + return m_vendor; +} + +QString FuseDevice::product() const +{ + return m_product; +} + +QString FuseDevice::icon() const +{ + return QString::fromLatin1("drive-removable-media"); +} + +QStringList FuseDevice::emblems() const +{ + QStringList res; + const FuseStorageAccess accessIface(const_cast(this)); + if (accessIface.isAccessible()) { + res << "emblem-mounted"; + } else { + res << "emblem-unmounted"; + } + + return res; +} + +QString FuseDevice::description() const +{ + return m_description; +} + +bool FuseDevice::queryDeviceInterface(const Solid::DeviceInterface::Type &type) const +{ + switch (type) { + case Solid::DeviceInterface::StorageAccess: + case Solid::DeviceInterface::StorageVolume: + case Solid::DeviceInterface::StorageDrive: + return true; + + default: + return false; + } +} + +QObject* FuseDevice::createDeviceInterface(const Solid::DeviceInterface::Type &type) +{ + switch (type) { + case Solid::DeviceInterface::StorageAccess: + return new FuseStorageAccess(this); + + case Solid::DeviceInterface::StorageVolume: + return new FuseStorageVolume(this); + + case Solid::DeviceInterface::StorageDrive: + return new FuseStorageDrive(this); + + default: + return 0; + } +} + +QString FuseDevice::device() const +{ + return m_device; +} + +void FuseDevice::onMtabChanged(const QString& device) +{ + if (m_device == device) + emit mtabChanged(device); +} diff --git a/solid/solid/backends/fuse/fusedevice.h b/solid/solid/backends/fuse/fusedevice.h new file mode 100644 index 0000000..913da39 --- /dev/null +++ b/solid/solid/backends/fuse/fusedevice.h @@ -0,0 +1,81 @@ +/* + Copyright 2010 Mario Bensi + Copyright 2012 Ivan Cukic + + 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 SOLID_BACKENDS_FUSE_FUSE_DEVICE_H +#define SOLID_BACKENDS_FUSE_FUSE_DEVICE_H + +#include +#include + +namespace Solid +{ +namespace Backends +{ +namespace Fuse +{ + + class FuseDevice: public Solid::Ifaces::Device + { + Q_OBJECT + + public: + FuseDevice(QString udi); + + virtual ~FuseDevice(); + + virtual QString udi() const; + + virtual QString parentUdi() const; + + virtual QString vendor() const; + + virtual QString product() const; + + virtual QString icon() const; + + virtual QStringList emblems() const; + + virtual QString description() const; + + virtual bool queryDeviceInterface(const Solid::DeviceInterface::Type &type) const; + + virtual QObject *createDeviceInterface(const Solid::DeviceInterface::Type &type); + + QString device() const; + + Q_SIGNALS: + void mtabChanged(const QString& device); + + private Q_SLOTS: + void onMtabChanged(const QString& device); + + private: + QString m_udi; + QString m_device; + QString m_product; + QString m_vendor; + QString m_description; + }; + +} +} +} +#endif // SOLID_BACKENDS_UPNP_UPNP_DEVICE_H diff --git a/solid/solid/backends/fuse/fusehandling.cpp b/solid/solid/backends/fuse/fusehandling.cpp new file mode 100644 index 0000000..f2e57e3 --- /dev/null +++ b/solid/solid/backends/fuse/fusehandling.cpp @@ -0,0 +1,195 @@ +/* + Copyright 2006-2010 Kevin Ottens + Copyright 2010 Mario Bensi + Copyright 2012 Ivan Cukic + + 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 "fusehandling.h" + +#include +#include +#include +#include +#include + +#include + +#include +#include + +#ifdef HAVE_SYS_MNTTAB_H +#include +#endif +#ifdef HAVE_MNTENT_H +#include +#elif defined(HAVE_SYS_MNTENT_H) +#include +#endif + +// This is the *BSD branch +#ifdef HAVE_SYS_MOUNT_H +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_SYS_PARAM_H +#include +#endif +#include +#endif + +#ifndef HAVE_GETMNTINFO +# ifdef _PATH_MOUNTED +// On some Linux, MNTTAB points to /etc/fstab ! +# undef MNTTAB +# define MNTTAB _PATH_MOUNTED +# else +# ifndef MNTTAB +# ifdef MTAB_FILE +# define MNTTAB MTAB_FILE +# else +# define MNTTAB "/etc/mnttab" +# endif +# endif +# endif +#endif + +// There are (at least) four kind of APIs: +// setmntent + getmntent + struct mntent (linux...) +// getmntent + struct mnttab +// mntctl + struct vmount (AIX) +// getmntinfo + struct statfs&flags (BSD 4.4 and friends) +// getfsent + char* (BSD 4.3 and friends) + +#ifdef HAVE_SETMNTENT +#define SETMNTENT setmntent +#define ENDMNTENT endmntent +#define STRUCT_MNTENT struct mntent * +#define STRUCT_SETMNTENT FILE * +#define GETMNTENT(file, var) ((var = getmntent(file)) != 0) +#define MOUNTPOINT(var) var->mnt_dir +#define MOUNTTYPE(var) var->mnt_type +#define MOUNTOPTIONS(var) var->mnt_opts +#define FSNAME(var) var->mnt_fsname +#else +#define SETMNTENT fopen +#define ENDMNTENT fclose +#define STRUCT_MNTENT struct mnttab +#define STRUCT_SETMNTENT FILE * +#define GETMNTENT(file, var) (getmntent(file, &var) == 0) +#define MOUNTPOINT(var) var.mnt_mountp +#define MOUNTTYPE(var) var.mnt_fstype +#define MOUNTOPTIONS(var) var.mnt_mntopts +#define FSNAME(var) var.mnt_special +#endif + +#include + +SOLID_GLOBAL_STATIC(Solid::Backends::Fuse::FuseHandling, globalFuseCache) + +Solid::Backends::Fuse::FuseHandling::FuseHandling() + : m_mtabCacheValid(false) +{ } + +bool _k_isFuseFileSystem(const QString &fstype, const QString &devName) +{ + return fstype.startsWith("fuse."); +} + +QStringList Solid::Backends::Fuse::FuseHandling::deviceList() +{ + _k_updateMtabMountPointsCache(); + + QStringList devices = globalFuseCache->m_mtabCache.values(); + return devices; +} + +QStringList Solid::Backends::Fuse::FuseHandling::mountPoints(const QString &device) +{ + _k_updateMtabMountPointsCache(); + + return QStringList() << device; +} + +QProcess *Solid::Backends::Fuse::FuseHandling::callSystemCommand(const QString &commandName, + const QStringList &args, + QObject *obj, const char *slot) +{ + QStringList env = QProcess::systemEnvironment(); + env.replaceInStrings(QRegExp("^PATH=(.*)", Qt::CaseInsensitive), "PATH=/sbin:/bin:/usr/sbin/:/usr/bin"); + + QProcess *process = new QProcess(obj); + + QObject::connect(process, SIGNAL(finished(int,QProcess::ExitStatus)), + obj, slot); + + process->setEnvironment(env); + process->start(commandName, args); + + if (process->waitForStarted()) { + return process; + } else { + delete process; + return 0; + } +} + +QProcess *Solid::Backends::Fuse::FuseHandling::callSystemCommand(const QString &commandName, + const QString &device, + QObject *obj, const char *slot) +{ + return callSystemCommand(commandName, QStringList() << device, obj, slot); +} + +void Solid::Backends::Fuse::FuseHandling::_k_updateMtabMountPointsCache() +{ + if (globalFuseCache->m_mtabCacheValid) + return; + + globalFuseCache->m_mtabCache.clear(); + + STRUCT_SETMNTENT mnttab; + if ((mnttab = SETMNTENT(MNTTAB, "r")) == 0) + return; + + STRUCT_MNTENT fe; + while (GETMNTENT(mnttab, fe)) + { + QString type = QFile::decodeName(MOUNTTYPE(fe)); + if (_k_isFuseFileSystem(type, QString())) { + const QString device = QFile::decodeName(FSNAME(fe)); + const QString mountpoint = QFile::decodeName(MOUNTPOINT(fe)); + globalFuseCache->m_mtabCache << mountpoint; + } + } + ENDMNTENT(mnttab); + + globalFuseCache->m_mtabCacheValid = true; +} + +QStringList Solid::Backends::Fuse::FuseHandling::currentMountPoints(const QString &device) +{ + _k_updateMtabMountPointsCache(); + return QStringList() << device; +} + +void Solid::Backends::Fuse::FuseHandling::flushMtabCache() +{ + globalFuseCache->m_mtabCacheValid = false; +} + diff --git a/solid/solid/backends/fuse/fusehandling.h b/solid/solid/backends/fuse/fusehandling.h new file mode 100644 index 0000000..31662c8 --- /dev/null +++ b/solid/solid/backends/fuse/fusehandling.h @@ -0,0 +1,74 @@ +/* + Copyright 2006-2010 Kevin Ottens + Copyright 2010 Mario Bensi + Copyright 2012 Ivan Cukic + + 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 SOLID_BACKENDS_FUSE_FUSEHANDLING_H +#define SOLID_BACKENDS_FUSE_FUSEHANDLING_H + +#include +#include + +#include +#include + +class QProcess; +class QObject; + +namespace Solid +{ +namespace Backends +{ +namespace Fuse +{ + +class FuseHandling +{ +public: + FuseHandling(); + + static QStringList deviceList(); + static QStringList currentMountPoints(const QString &device); + static QStringList mountPoints(const QString &device); + static QProcess *callSystemCommand(const QString &commandName, + const QStringList &args, + QObject *obj, const char *slot); + static QProcess *callSystemCommand(const QString &commandName, + const QString &device, + QObject *obj, const char *slot); + static void flushMtabCache(); + static void flushFuseCache(); + +private: + static void _k_updateMtabMountPointsCache(); + static void _k_updateFuseMountPointsCache(); + + QSet m_mtabCache; + bool m_mtabCacheValid; + +}; + +} +} +} + +#endif + + diff --git a/solid/solid/backends/fuse/fusemanager.cpp b/solid/solid/backends/fuse/fusemanager.cpp new file mode 100644 index 0000000..9011bd5 --- /dev/null +++ b/solid/solid/backends/fuse/fusemanager.cpp @@ -0,0 +1,155 @@ +/* + Copyright 2010 Mario Bensi + Copyright 2012 Ivan Cukic + + 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 "fusemanager.h" +#include "fusedevice.h" +#include "fusehandling.h" +#include "../shared/rootdevice.h" +#include "fuseservice.h" +#include "fusewatcher.h" + +#include + +using namespace Solid::Backends::Fuse; +using namespace Solid::Backends::Shared; + +FuseManager::FuseManager(QObject *parent) + : Solid::Ifaces::DeviceManager(parent) +{ + m_supportedInterfaces << Solid::DeviceInterface::StorageAccess; + + m_deviceList = FuseHandling::deviceList(); + + connect(FuseWatcher::instance(), SIGNAL(mtabChanged()), this, SLOT(onMtabChanged())); +} + +QString FuseManager::udiPrefix() const +{ + return QString::fromLatin1(FUSE_UDI_PREFIX); +} + +QSet FuseManager::supportedInterfaces() const +{ + return m_supportedInterfaces; +} + +QStringList FuseManager::allDevices() +{ + QStringList result; + + result << udiPrefix(); + foreach (const QString &device, m_deviceList) { + result << udiPrefix() + device; + } + + return result; +} + +QStringList FuseManager::devicesFromQuery( const QString &parentUdi, + Solid::DeviceInterface::Type type) +{ + qDebug() << "devicesFromQuery" << parentUdi << type; + + if (type == Solid::DeviceInterface::StorageAccess + || type == Solid::DeviceInterface::StorageVolume + || type == Solid::DeviceInterface::StorageDrive) { + + if (parentUdi.isEmpty() || parentUdi == udiPrefix()) { + QStringList list = allDevices(); + list.removeFirst(); + return list; + + } else { + QStringList list; + list << parentUdi; + return list; + } + } + return QStringList(); +} + +QObject *FuseManager::createDevice(const QString &udi) +{ + qDebug() << "createDevice" << udi; + + if (udi == udiPrefix()) { + qDebug() << "returning a root device"; + RootDevice *root = new RootDevice(FUSE_UDI_PREFIX); + + root->setProduct(tr("FUSE mounts")); + root->setDescription(tr("FUSE mounts in your system")); + root->setIcon("folder-remote"); + + return root; + + } else { + // global device manager makes sure udi starts with udi prefix + '/' + QString internalName = udi.mid( udiPrefix().length(), -1 ); + qDebug() << "internalName" << internalName; + + if (!m_deviceList.contains(internalName)) + return 0; + + qDebug() << "Returning a FuseDevice for" << udi; + QObject* device = new FuseDevice(udi); + connect (this, SIGNAL(mtabChanged(QString)), device, SLOT(onMtabChanged(QString))); + return device; + + } +} + +void FuseManager::_k_updateDeviceList() +{ + QStringList deviceList = FuseHandling::deviceList(); + QSet newlist = deviceList.toSet(); + QSet oldlist = m_deviceList.toSet(); + + qDebug() << "old list" << oldlist << "new list" << newlist; + m_deviceList = deviceList; + + foreach (const QString &device, newlist) { + if ( !oldlist.contains(device) ) { + emit deviceAdded(udiPrefix() + device); + } + } + + foreach (const QString &device, oldlist) { + if ( !newlist.contains(device) ) { + emit deviceRemoved(udiPrefix() + device); + } + } +} + +void FuseManager::onMtabChanged() +{ + FuseHandling::flushMtabCache(); + + _k_updateDeviceList(); + + foreach (const QString &device, m_deviceList) { + // notify storageaccess objects via device ... + emit mtabChanged(device); + } +} + +FuseManager::~FuseManager() +{ +} diff --git a/solid/solid/backends/fuse/fusemanager.h b/solid/solid/backends/fuse/fusemanager.h new file mode 100644 index 0000000..a0b3e57 --- /dev/null +++ b/solid/solid/backends/fuse/fusemanager.h @@ -0,0 +1,68 @@ +/* + Copyright 2010 Mario Bensi + Copyright 2012 Ivan Cukic + + 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 SOLID_BACKENDS_FUSE_FUSEMANAGER_H +#define SOLID_BACKENDS_FUSE_FUSEMANAGER_H + +#include +#include +#include +#include + +namespace Solid +{ +namespace Backends +{ +namespace Fuse +{ +class AbstractDeviceFactory; + +class FuseManager : public Solid::Ifaces::DeviceManager +{ + Q_OBJECT + +public: + explicit FuseManager(QObject *parent); + virtual ~FuseManager(); + + virtual QString udiPrefix() const ; + virtual QSet supportedInterfaces() const; + virtual QStringList allDevices(); + virtual QStringList devicesFromQuery(const QString &parentUdi, Solid::DeviceInterface::Type type); + virtual QObject *createDevice(const QString &udi); + +Q_SIGNALS: + void mtabChanged(const QString& device); + +private Q_SLOTS: + void onMtabChanged(); + +private: + QSet m_supportedInterfaces; + QStringList m_deviceList; + void _k_updateDeviceList(); +}; + +} +} +} + +#endif diff --git a/solid/solid/backends/fuse/fuseservice.h b/solid/solid/backends/fuse/fuseservice.h new file mode 100644 index 0000000..22912dc --- /dev/null +++ b/solid/solid/backends/fuse/fuseservice.h @@ -0,0 +1,28 @@ +/* + Copyright 2010 Mario Bensi + Copyright 2012 Ivan Cukic + + 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 SOLID_BACKENDS_FUSE_SERVICE_H +#define SOLID_BACKENDS_FUSE_SERVICE_H + +#define FUSE_UDI_PREFIX "/org/kde/fuse" + +#endif // SOLID_BACKENDS_FUSE_H + diff --git a/solid/solid/backends/fuse/fusestorageaccess.cpp b/solid/solid/backends/fuse/fusestorageaccess.cpp new file mode 100644 index 0000000..cb68444 --- /dev/null +++ b/solid/solid/backends/fuse/fusestorageaccess.cpp @@ -0,0 +1,171 @@ +/* + Copyright 2010 Mario Bensi + Copyright 2012 Ivan Cukic + + 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 "fusewatcher.h" +#include +#include +#include +#include +#include + +#include +#include + +#define MTAB "/etc/mtab" + +using namespace Solid::Backends::Fuse; + +FuseStorageAccess::FuseStorageAccess(Solid::Backends::Fuse::FuseDevice *device) : + QObject(device), + m_fuseDevice(device) +{ + QStringList currentMountPoints = FuseHandling::currentMountPoints(device->device()); + if (currentMountPoints.isEmpty()) { + m_filePath = FuseHandling::mountPoints(device->device()).first(); + m_isAccessible = false; + } else { + m_filePath = currentMountPoints.first(); + m_isAccessible = true; + } + + connect(device, SIGNAL(mtabChanged(QString)), this, SLOT(onMtabChanged(QString))); + QTimer::singleShot(0, this, SLOT(connectDBusSignals())); + + // qDebug() << "TEST:" << + // QMetaObject::invokeMethod(this, "accessibilityChanged", Qt::QueuedConnection, + // Q_ARG(bool, true), Q_ARG(QString, device->udi())); +} + +FuseStorageAccess::~FuseStorageAccess() +{ +} + + +void FuseStorageAccess::connectDBusSignals() +{ + m_fuseDevice->registerAction("setup", this, + SLOT(slotSetupRequested()), + SLOT(slotSetupDone(int,QString))); + + m_fuseDevice->registerAction("teardown", this, + SLOT(slotTeardownRequested()), + SLOT(slotTeardownDone(int,QString))); +} + +const Solid::Backends::Fuse::FuseDevice *FuseStorageAccess::fuseDevice() const +{ + return m_fuseDevice; +} + +bool FuseStorageAccess::isAccessible() const +{ + return m_isAccessible; +} + +QString FuseStorageAccess::filePath() const +{ + return m_filePath; +} + +bool FuseStorageAccess::isIgnored() const +{ + return false; +} + +bool FuseStorageAccess::setup() +{ + if (filePath().isEmpty()) { + return false; + } + m_fuseDevice->broadcastActionRequested("setup"); + m_process = FuseHandling::callSystemCommand("mount", filePath(), + this, SLOT(slotSetupFinished(int,QProcess::ExitStatus))); + + return m_process!=0; +} + +void FuseStorageAccess::slotSetupRequested() +{ + emit setupRequested(m_fuseDevice->udi()); +} + +bool FuseStorageAccess::teardown() +{ + if (filePath().isEmpty()) { + return false; + } + m_fuseDevice->broadcastActionRequested("teardown"); + m_process = FuseHandling::callSystemCommand("umount", filePath(), + this, SLOT(slotTeardownFinished(int,QProcess::ExitStatus))); + + return m_process!=0; +} + +void FuseStorageAccess::slotTeardownRequested() +{ + emit teardownRequested(m_fuseDevice->udi()); +} + +void FuseStorageAccess::slotSetupFinished(int exitCode, QProcess::ExitStatus /*exitStatus*/) +{ + if (exitCode==0) { + m_fuseDevice->broadcastActionDone("setup", Solid::NoError, QString()); + } else { + m_fuseDevice->broadcastActionDone("setup", Solid::UnauthorizedOperation, m_process->readAllStandardError()); + } + delete m_process; +} + +void FuseStorageAccess::slotSetupDone(int error, const QString &errorString) +{ + emit setupDone(static_cast(error), errorString, m_fuseDevice->udi()); +} + +void FuseStorageAccess::slotTeardownFinished(int exitCode, QProcess::ExitStatus /*exitStatus*/) +{ + if (exitCode==0) { + m_fuseDevice->broadcastActionDone("teardown", Solid::NoError, QString()); + } else { + m_fuseDevice->broadcastActionDone("teardown", Solid::UnauthorizedOperation, m_process->readAllStandardError()); + } + delete m_process; +} + +void FuseStorageAccess::slotTeardownDone(int error, const QString &errorString) +{ + emit teardownDone(static_cast(error), errorString, m_fuseDevice->udi()); +} + +void FuseStorageAccess::onMtabChanged(const QString& device) +{ + QStringList currentMountPoints = FuseHandling::currentMountPoints(device); + if (currentMountPoints.isEmpty()) { + // device umounted + m_filePath = FuseHandling::mountPoints(device).first(); + m_isAccessible = false; + emit accessibilityChanged(false, QString(FUSE_UDI_PREFIX) + device); + } else { + // device added + m_filePath = currentMountPoints.first(); + m_isAccessible = true; + emit accessibilityChanged(true, QString(FUSE_UDI_PREFIX) + device); + } +} diff --git a/solid/solid/backends/fuse/fusestorageaccess.h b/solid/solid/backends/fuse/fusestorageaccess.h new file mode 100644 index 0000000..bd5fee3 --- /dev/null +++ b/solid/solid/backends/fuse/fusestorageaccess.h @@ -0,0 +1,94 @@ +/* + Copyright 2010 Mario Bensi + Copyright 2012 Ivan Cukic + + 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 SOLID_BACKENDS_FUSE_STORAGEACCESS_H +#define SOLID_BACKENDS_FUSE_STORAGEACCESS_H + +#include + +#include +#include + +namespace Solid +{ +namespace Backends +{ +namespace Fuse +{ + class FuseDevice; + class FuseStorageAccess : public QObject, public Solid::Ifaces::StorageAccess + { + Q_OBJECT + Q_INTERFACES(Solid::Ifaces::StorageAccess) + Q_INTERFACES(Solid::Ifaces::DeviceInterface) + + public: + explicit FuseStorageAccess(Solid::Backends::Fuse::FuseDevice *device); + + virtual ~FuseStorageAccess(); + + virtual bool isAccessible() const; + + virtual QString filePath() const; + + virtual bool isIgnored() const; + + virtual bool setup(); + + virtual bool teardown(); + + public: + const Solid::Backends::Fuse::FuseDevice* fuseDevice() const; + + Q_SIGNALS: + void accessibilityChanged(bool accessible, const QString &udi); + + void setupDone(Solid::ErrorType error, QVariant data, const QString &udi); + + void teardownDone(Solid::ErrorType error, QVariant data, const QString &udi); + + void setupRequested(const QString &udi); + + void teardownRequested(const QString &udi); + + private Q_SLOTS: + void slotSetupFinished(int exitCode, QProcess::ExitStatus exitStatus); + void slotTeardownFinished(int exitCode, QProcess::ExitStatus exitStatus); + void onMtabChanged(const QString& device); + void connectDBusSignals(); + + void slotSetupRequested(); + void slotSetupDone(int error, const QString &errorString); + void slotTeardownRequested(); + void slotTeardownDone(int error, const QString &errorString); + + private: + Solid::Backends::Fuse::FuseDevice *m_fuseDevice; + QProcess *m_process; + QString m_filePath; + bool m_isAccessible; + }; + +} +} +} + +#endif // SOLID_BACKENDS_FUSE_DEVICE_INTERFACE_H diff --git a/solid/solid/backends/fuse/fusestoragedrive.cpp b/solid/solid/backends/fuse/fusestoragedrive.cpp new file mode 100644 index 0000000..4910349 --- /dev/null +++ b/solid/solid/backends/fuse/fusestoragedrive.cpp @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2012 Ivan Cukic + * + * 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) any later version, 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 "fusestoragedrive.h" +#include + +namespace Solid +{ +namespace Backends +{ +namespace Fuse +{ + +FuseStorageDrive::FuseStorageDrive(FuseDevice *device) + : QObject(device) +{ + qDebug() << "FuseStorageDrive constructor" << device->device(); +} + +FuseStorageDrive::~FuseStorageDrive() +{ +} + +bool FuseStorageDrive::isHotpluggable() const +{ + qDebug() << "isHotpluggable true"; + return true; +} + +bool FuseStorageDrive::isRemovable() const +{ + qDebug() << "isRemovable true"; + return true; +} + +qulonglong FuseStorageDrive::size() const +{ + // TODO: make this real + return 1024; +} + +Solid::StorageDrive::Bus FuseStorageDrive::bus() const +{ + return Solid::StorageDrive::Platform; +} + +Solid::StorageDrive::DriveType FuseStorageDrive::driveType() const +{ + return Solid::StorageDrive::HardDisk; +} + +} +} +} diff --git a/solid/solid/backends/fuse/fusestoragedrive.h b/solid/solid/backends/fuse/fusestoragedrive.h new file mode 100644 index 0000000..2047ca5 --- /dev/null +++ b/solid/solid/backends/fuse/fusestoragedrive.h @@ -0,0 +1,64 @@ +/* + Copyright 2010 Michael Zanetti + Copyright 2010 Lukas Tinkl + Copyright 2012 Ivan Cukic + + 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 FUSESTORAGEDRIVE_H +#define FUSESTORAGEDRIVE_H + +#include + +#include "fusedevice.h" + +namespace Solid +{ +namespace Backends +{ +namespace Fuse +{ + +class FuseStorageDrive: public QObject, virtual public Solid::Ifaces::StorageDrive +{ + Q_OBJECT + Q_INTERFACES(Solid::Ifaces::StorageDrive) + Q_INTERFACES(Solid::Ifaces::DeviceInterface) + +public: + FuseStorageDrive(FuseDevice *device); + virtual ~FuseStorageDrive(); + + virtual qulonglong size() const; + virtual bool isHotpluggable() const; + virtual bool isRemovable() const; + virtual Solid::StorageDrive::DriveType driveType() const; + virtual Solid::StorageDrive::Bus bus() const; + + virtual QString device() const { return QString::fromLatin1("/dev/fuse"); } + virtual int deviceMajor() const { return 0; }; + virtual int deviceMinor() const { return 0; }; + + +}; + +} +} +} + +#endif // FUSESTORAGEDRIVE_H diff --git a/solid/solid/backends/fuse/fusestoragevolume.cpp b/solid/solid/backends/fuse/fusestoragevolume.cpp new file mode 100644 index 0000000..d7a1216 --- /dev/null +++ b/solid/solid/backends/fuse/fusestoragevolume.cpp @@ -0,0 +1,104 @@ +/* + * Copyright (C) 2012 Ivan Cukic + * + * 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) any later version, 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 "fusestoragevolume.h" +#include "fusedevice.h" + +#include +#include +#include + +namespace Solid +{ +namespace Backends +{ +namespace Fuse +{ + +FuseStorageVolume::FuseStorageVolume(FuseDevice * device) + : QObject(), m_device(device) +{ +} + +FuseStorageVolume::~FuseStorageVolume() +{ +} + +bool FuseStorageVolume::isIgnored() const +{ + return false; +} + +QString FuseStorageVolume::encryptedContainerUdi() const +{ + return QString(); +} + +QString FuseStorageVolume::fsType() const +{ + return QString::fromLatin1("fuse"); +} + +QString FuseStorageVolume::label() const +{ + return QString(); +} + +QString FuseStorageVolume::uuid() const +{ + if (!m_device) { + qDebug() << "DEVICE IS NULL!?"; + return QString(); + } + // We are using the mount path to generate the UUID + // it would be better if we could get the source URI, but + // fuse doesn't save that in mtab + // + // UUID will be version 3 - MD5 based instead of SHA1 (v 5) + + QByteArray hash = QCryptographicHash::hash( + m_device->udi().toUtf8(), + QCryptographicHash::Md5); + + // "90015098-3cd2-4fb0-d696-3f7d28e17f72" + // "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" + // {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx} + // 8 12 16 + + QString result(hash.toHex().insert(20, '-').insert(16, '-').insert(12, '-').insert(8, '-')); + + qDebug() << "UUID is " << result; + + return result; +} + +qulonglong FuseStorageVolume::size() const +{ + return 1024; +} + +Solid::StorageVolume::UsageType FuseStorageVolume::usage() const +{ + return Solid::StorageVolume::FileSystem; +} + + +} +} +} diff --git a/solid/solid/backends/fuse/fusestoragevolume.h b/solid/solid/backends/fuse/fusestoragevolume.h new file mode 100644 index 0000000..7a79a7d --- /dev/null +++ b/solid/solid/backends/fuse/fusestoragevolume.h @@ -0,0 +1,67 @@ +/* + Copyright 2010 Michael Zanetti + Copyright 2012 Ivan Cukic + + 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 FUSESTORAGEVOLUME_H +#define FUSESTORAGEVOLUME_H + +#include + + +namespace Solid +{ +namespace Backends +{ +namespace Fuse +{ + +class FuseDevice; + +class FuseStorageVolume: public QObject, public Solid::Ifaces::StorageVolume +{ + Q_OBJECT + Q_INTERFACES(Solid::Ifaces::StorageVolume) + Q_INTERFACES(Solid::Ifaces::DeviceInterface) + +public: + FuseStorageVolume(FuseDevice *device); + virtual ~FuseStorageVolume(); + + virtual QString encryptedContainerUdi() const; + virtual qulonglong size() const; + virtual QString uuid() const; + virtual QString label() const; + virtual QString fsType() const; + virtual Solid::StorageVolume::UsageType usage() const; + virtual bool isIgnored() const; + + virtual QString device() const { return QString::fromLatin1("/dev/fuse"); } + virtual int deviceMajor() const { return 0; }; + virtual int deviceMinor() const { return 0; }; + +private: + FuseDevice * m_device; +}; + +} +} +} + +#endif // FUSESTORAGEVOLUME_H diff --git a/solid/solid/backends/fuse/fusewatcher.cpp b/solid/solid/backends/fuse/fusewatcher.cpp new file mode 100644 index 0000000..902a41e --- /dev/null +++ b/solid/solid/backends/fuse/fusewatcher.cpp @@ -0,0 +1,112 @@ +/* + Copyright 2010 Mario Bensi + Copyright 2012 Ivan Cukic + + 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 "fusewatcher.h" +#include "soliddefs_p.h" + +#include +#include +#include +#include +#include + +using namespace Solid::Backends::Fuse; + +SOLID_GLOBAL_STATIC(FuseWatcher, globalFuseWatcher) + +#define MTAB "/etc/mtab" +#ifdef Q_OS_SOLARIS +#define FSTAB "/etc/vfstab" +#else +#define FSTAB "/etc/fstab" +#endif + +FuseWatcher::FuseWatcher() + : m_isRoutineInstalled(false) + , m_fileSystemWatcher(new QFileSystemWatcher(this)) +{ + if (qApp) { + connect(qApp, SIGNAL(aboutToQuit()), this, SLOT(orphanFileSystemWatcher())); + } + + m_mtabFile = new QFile(MTAB, this); + if (m_mtabFile && m_mtabFile->symLinkTarget().startsWith("/proc/") + && m_mtabFile->open(QIODevice::ReadOnly) ) { + + m_mtabSocketNotifier = new QSocketNotifier(m_mtabFile->handle(), + QSocketNotifier::Exception, this); + connect(m_mtabSocketNotifier, + SIGNAL(activated(int)), this, SIGNAL(mtabChanged()) ); + } else { + m_fileSystemWatcher->addPath(MTAB); + } + + m_fileSystemWatcher->addPath(FSTAB); + connect(m_fileSystemWatcher, SIGNAL(fileChanged(QString)), this, SLOT(onFileChanged(QString))); +} + +FuseWatcher::~FuseWatcher() +{ + // The QFileSystemWatcher doesn't work correctly in a singleton + // The solution so far was to destroy the QFileSystemWatcher when the application quits + // But we have some crash with this solution. + // For the moment to workaround the problem, we detach the QFileSystemWatcher from the parent + // effectively leaking it on purpose. + +#if 0 + //qRemovePostRoutine(globalFuseWatcher.destroy); +#else + m_fileSystemWatcher->setParent(0); +#endif +} + +void FuseWatcher::orphanFileSystemWatcher() +{ + m_fileSystemWatcher->setParent(0); +} + +FuseWatcher *FuseWatcher::instance() +{ +#if 0 + FuseWatcher *fstabWatcher = globalFuseWatcher; + + if (fstabWatcher && !fstabWatcher->m_isRoutineInstalled) { + qAddPostRoutine(globalFuseWatcher.destroy); + fstabWatcher->m_isRoutineInstalled = true; + } + return fstabWatcher; +#else + return globalFuseWatcher; +#endif +} + + +void FuseWatcher::onFileChanged(const QString &path) +{ + if (path == MTAB) { + emit mtabChanged(); + if (!m_fileSystemWatcher->files().contains(MTAB)) { + m_fileSystemWatcher->addPath(MTAB); + } + } +} + + diff --git a/solid/solid/backends/fuse/fusewatcher.h b/solid/solid/backends/fuse/fusewatcher.h new file mode 100644 index 0000000..7aa742f --- /dev/null +++ b/solid/solid/backends/fuse/fusewatcher.h @@ -0,0 +1,63 @@ +/* + Copyright 2010 Mario Bensi + Copyright 2012 Ivan Cukic + + 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 SOLID_BACKENDS_FUSE_WATCHER_H +#define SOLID_BACKENDS_FUSE_WATCHER_H + +#include + +class QFileSystemWatcher; +class QFile; +class QSocketNotifier; + +namespace Solid +{ +namespace Backends +{ +namespace Fuse +{ + + class FuseWatcher : public QObject { + Q_OBJECT + public: + FuseWatcher(); + virtual ~FuseWatcher(); + + static FuseWatcher *instance(); + + Q_SIGNALS: + void mtabChanged(); + + private Q_SLOTS: + void onFileChanged(const QString &path); + void orphanFileSystemWatcher(); + + private: + bool m_isRoutineInstalled; + QFileSystemWatcher *m_fileSystemWatcher; + QSocketNotifier *m_mtabSocketNotifier; + QFile *m_mtabFile; + }; +} +} +} +#endif // SOLID_BACKENDS_FUSE_WATCHER_H + diff --git a/solid/solid/managerbase.cpp b/solid/solid/managerbase.cpp index fb5a67c..ee189df 100644 --- a/solid/solid/managerbase.cpp +++ b/solid/solid/managerbase.cpp @@ -33,6 +33,7 @@ #include "backends/hal/halmanager.h" #include "backends/udisks/udisksmanager.h" #include "backends/upower/upowermanager.h" +#include "backends/fuse/fusemanager.h" #if defined (HUPNP_FOUND) #include "backends/upnp/upnpdevicemanager.h" @@ -87,6 +88,8 @@ void Solid::ManagerBasePrivate::loadBackends() << new Solid::Backends::UPower::UPowerManager(0) << new Solid::Backends::Fstab::FstabManager(0); } + + m_backends << new Solid::Backends::Fuse::FuseManager(0); # endif # if defined (HUPNP_FOUND)