Ejemplo n.º 1
0
void FileManager::openFile( const QString& fileName, const QString& name, const QString& title, const QString& partName, const QVariantList& partParams )
{
    if( fileName.isEmpty() )
        return;

    QString fullName = name.isEmpty() ? KUrl( fileName ).fileName() : name;
    QString fullTitle = title.isEmpty() ? fullName : title;
    if( d->parts.contains( fullName ) )
    {
        emit newPart( fullName, fullTitle );
        return;
    }

    KMimeType::Ptr mime = KMimeType::findByPath( fileName );

    KParts::ReadOnlyPart* part = 0;
    KService::List parts;

    if( !partName.isEmpty() )
    {
        KService::Ptr service = KService::serviceByDesktopName( partName );
        if( !service.isNull() )
            parts.append( service );
    }

    if( parts.count() == 0 )
    {
        parts.append( KMimeTypeTrader::self()->query( mime->name(), "KParts/ReadWritePart" ) );
        parts.append( KMimeTypeTrader::self()->query( mime->name(), "KParts/ReadOnlyPart" ) );

        if( mime->name().contains( "audio" ) && parts.count() == 0 )
            parts.append( KService::serviceByStorageId( "dragonplayer_part.desktop" ) );
    }

    if( parts.count() > 0 )
    {
        part = parts.first()->createInstance<KParts::ReadWritePart>( 0, partParams );
        if( !part )
            part = parts.first()->createInstance<KParts::ReadOnlyPart>( 0, partParams );
    }

    if( part )
    {
        // Add the part if it is found
        KUrl url( fileName );
        part->openUrl( url );
        d->parts.insert( fullName, part );
        d->partManager->addPart( part, true );
        emit newPart( fullName, fullTitle );

        return;
    }

    // There really is no part that can be used.
    // Instead, just open it in an external application.
    // KRun* runner = new KRun( KUrl( fileName ), qApp->activeWindow() );
}
Ejemplo n.º 2
0
void KMimeTypeTest::testMimeTypeTraderForAlias()
{
    if ( !KSycoca::isAvailable() )
        QSKIP( "ksycoca not available", SkipAll );

    const KService::List referenceOffers = KMimeTypeTrader::self()->query("application/xml", "KParts/ReadOnlyPart");
    QVERIFY( offerListHasService( referenceOffers, "katepart.desktop" ) );

    // Querying mimetype trader for services associated with text/xml, which is an alias for application/xml
    const KService::List offers = KMimeTypeTrader::self()->query("text/xml", "KParts/ReadOnlyPart");
    QVERIFY( offerListHasService( offers, "katepart.desktop" ) );

    QCOMPARE(offers.count(), referenceOffers.count());
}
Ejemplo n.º 3
0
void SettingsBase::initApplication()
{
    // Prepare the menu of all modules
    categories = KServiceTypeTrader::self()->query("SystemSettingsCategory");
    modules = KServiceTypeTrader::self()->query("KCModule", "[X-KDE-System-Settings-Parent-Category] != ''");
    modules += KServiceTypeTrader::self()->query("SystemSettingsExternalApp");
    rootModule = new MenuItem( true, 0 );
    initMenuList(rootModule);
    // Handle lost+found modules...
    if (lostFound) {
        for (int i = 0; i < modules.size(); ++i) {
            const KService::Ptr entry = modules.at(i);
            MenuItem * infoItem = new MenuItem(false, lostFound);
            infoItem->setService( entry );
            qDebug() << "Added " << entry->name();
        }
    }

    // Prepare the Base Data
    BaseData::instance()->setMenuItem( rootModule );
    // Load all possible views
    const KService::List pluginObjects = KServiceTypeTrader::self()->query( "SystemSettingsView" );
    const int nbPlugins = pluginObjects.count();
    for( int pluginsDone = 0; pluginsDone < nbPlugins ; ++pluginsDone ) {
        KService::Ptr activeService = pluginObjects.at( pluginsDone );
        QString error;
        BaseMode * controller = activeService->createInstance<BaseMode>(this, QVariantList(), &error);
        if( error.isEmpty() ) {
            possibleViews.insert( activeService->library(), controller );
            controller->init( activeService );
            connect(controller, SIGNAL(changeToolBarItems(BaseMode::ToolBarItems)), this, SLOT(changeToolBar(BaseMode::ToolBarItems)));
            connect(controller, SIGNAL(actionsChanged()), this, SLOT(updateViewActions()));
            connect(searchText, SIGNAL(textChanged(QString)), controller, SLOT(searchChanged(QString)));
            connect(controller, SIGNAL(viewChanged(bool)), this, SLOT(viewChange(bool)));
        } else {
Ejemplo n.º 4
0
void KMimeTypeTest::testMimeTypeTraderForDerivedMimeType()
{
    if (!KSycoca::isAvailable()) {
        QSKIP("ksycoca not available");
    }

    // Querying mimetype trader for services associated with text/x-patch, which inherits from text/plain
    KService::List offers = KMimeTypeTrader::self()->query("text/x-patch", "KParts/ReadOnlyPart");
    QVERIFY(offerListHasService(offers, "fakepatchpart.desktop"));
    QVERIFY(offerListHasService(offers, "faketextpart.desktop"));
    QVERIFY((*offers.begin())->entryPath() != "faketextpart.desktop");   // in the list, but not preferred

    offers = KMimeTypeTrader::self()->query("text/x-patch", "KPluginInfo");
    QVERIFY(offers.count() > 0);

    // We should have at least the fake text plugin that we created for this.
    // (The actual plugins from kdelibs don't mention text/plain anymore)
    QVERIFY(offerListHasService(offers, "faketextplugin.desktop"));

    offers = KMimeTypeTrader::self()->query("text/x-patch", "Application");
    QVERIFY(!offerListHasService(offers, "faketextpart.desktop"));

    // We shouldn't have non-kde apps
    Q_FOREACH (KService::Ptr service, offers) {
        kDebug() << service->name() << service->entryPath();
    }

    QVERIFY(!offerListHasService(offers, m_nonKdeApp));
}
Ejemplo n.º 5
0
TubeChannelApprover::TubeChannelApprover(const Tp::TubeChannelPtr& channel, QObject* parent):
    ChannelApprover(0),
    m_channel(channel)
{
    Q_UNUSED(parent);

    qCDebug(APPROVER) << "Incoming tube channel";
    qCDebug(APPROVER) << "\tTube Type:" << channel->channelType();

    connect(m_channel.data(), SIGNAL(invalidated(Tp::DBusProxy*,QString,QString)), SLOT(onChannelInvalidated()));

    QString serviceName;
    if (Tp::StreamTubeChannelPtr streamTube = Tp::StreamTubeChannelPtr::dynamicCast(channel)) {
        qCDebug(APPROVER) << "\tService:" << streamTube->service();
        serviceName = streamTube->service();
    } else if (Tp::DBusTubeChannelPtr dbusTube = Tp::DBusTubeChannelPtr::dynamicCast(channel)) {
        qCDebug(APPROVER) << "\tService name:" << dbusTube->serviceName();
        serviceName = dbusTube->serviceName();
    }

    KService::List services = KServiceTypeTrader::self()->query(QLatin1String("KTpApprover"));
    qCDebug(APPROVER) << "Found" << services.count() << "KTpApprover services";
    if (!services.isEmpty()) {
        Q_FOREACH(const KService::Ptr &service, services) {
            if ((service->property(QLatin1String("X-KTp-ChannelType")) != channel->channelType()) ||
                (service->property(QLatin1String("X-KTp-Service")) != serviceName)) {

                continue;
            }
            m_service = service;
        }
    }
Ejemplo n.º 6
0
ToggleViewGUIClient::ToggleViewGUIClient( KonqMainWindow *mainWindow )
: QObject( mainWindow )
{
  m_mainWindow = mainWindow;

  KService::List offers = KServiceTypeTrader::self()->query( "Browser/View" );
  KService::List::Iterator it = offers.begin();
  while ( it != offers.end() )
  {
    QVariant prop = (*it)->property( "X-KDE-BrowserView-Toggable" );
    QVariant orientation = (*it)->property( "X-KDE-BrowserView-ToggableView-Orientation" );

    if ( !prop.isValid() || !prop.toBool() ||
         !orientation.isValid() || orientation.toString().isEmpty() )
    {
      offers.erase( it );
      it = offers.begin();
    }
    else
      ++it;
  }

  m_empty = ( offers.count() == 0 );

  if ( m_empty )
    return;

  KService::List::ConstIterator cIt = offers.constBegin();
  KService::List::ConstIterator cEnd = offers.constEnd();
  for (; cIt != cEnd; ++cIt )
  {
    QString description = i18n( "Show %1" ,  (*cIt)->name() );
    QString name = (*cIt)->desktopEntryName();
    //kDebug() << "ToggleViewGUIClient: name=" << name;
    KToggleAction *action = new KToggleAction( description, this );
    mainWindow->actionCollection()->addAction( name.toLatin1(), action );

    // HACK
    if ( (*cIt)->icon() != "unknown" )
      action->setIcon( KIcon((*cIt)->icon()) );

    connect( action, SIGNAL(toggled(bool)),
             this, SLOT(slotToggleView(bool)) );

    m_actions.insert( name, action );

    QVariant orientation = (*cIt)->property( "X-KDE-BrowserView-ToggableView-Orientation" );
    bool horizontal = orientation.toString().toLower() == "horizontal";
    m_mapOrientation.insert( name, horizontal );
  }

  connect( m_mainWindow, SIGNAL(viewAdded(KonqView*)),
           this, SLOT(slotViewAdded(KonqView*)) );
  connect( m_mainWindow, SIGNAL(viewRemoved(KonqView*)),
           this, SLOT(slotViewRemoved(KonqView*)) );
}
Ejemplo n.º 7
0
PopupMenuGUIClient::PopupMenuGUIClient( const KService::List &embeddingServices,
                                        KParts::BrowserExtension::ActionGroupMap& actionGroups,
                                        QAction* showMenuBar, QAction* stopFullScreen )
    : m_actionCollection(this),
      m_embeddingServices(embeddingServices)
{
    QList<QAction *> topActions;
    if (showMenuBar) {
        topActions.append(showMenuBar);
        KAction* separator = new KAction(&m_actionCollection);
        separator->setSeparator(true);
        topActions.append(separator);
    }

    if (stopFullScreen) {
        topActions.append(stopFullScreen);
        KAction* separator = new KAction(&m_actionCollection);
        separator->setSeparator(true);
        topActions.append(separator);
    }

    if (!embeddingServices.isEmpty()) {
        QList<QAction *> previewActions;
        if (embeddingServices.count() == 1) {
            KService::Ptr service = embeddingServices.first();
            QAction* act = addEmbeddingService( 0, i18n( "Preview &in %1", service->name() ), service );
            previewActions.append(act);
        } else if (embeddingServices.count() > 1) {
            KService::List::ConstIterator it = embeddingServices.begin();
            const KService::List::ConstIterator end = embeddingServices.end();
            int idx = 0;
            for (; it != end; ++it, ++idx ) {
                QAction* act = addEmbeddingService( idx, (*it)->name(), *it );
                previewActions.append(act);
            }
        }
        actionGroups.insert("preview", previewActions);
    }
    actionGroups.insert("topactions", topActions);
}
Ejemplo n.º 8
0
bool PartController::canCreatePart(const KUrl& url)
{
    if (!url.isValid()) return false;

    QString mimeType;
    if ( url.isEmpty() )
        mimeType = QString::fromLatin1("text/plain");
    else
        mimeType = KMimeType::findByUrl( url )->name();

    KService::List offers = KMimeTypeTrader::self()->query(
                                mimeType,
                                "KParts/ReadOnlyPart" );

    return offers.count() > 0;
}
Ejemplo n.º 9
0
void KMimeTypeTest::testMimeTypeTraderForTextPlain()
{
    if ( !KSycoca::isAvailable() )
        QSKIP( "ksycoca not available", SkipAll );

    // Querying mimetype trader for services associated with text/plain
    KService::List offers = KMimeTypeTrader::self()->query("text/plain", "KParts/ReadOnlyPart");
    QVERIFY( offerListHasService( offers, "katepart.desktop" ) );
    QVERIFY( offerListHasService( offers, "faketextpart.desktop" ) );

    offers = KMimeTypeTrader::self()->query("text/plain", "KTextEditor/Plugin");
    QVERIFY( offers.count() > 0 );

    // We should have at least the fake text plugin that we created for this.
    // (The actual plugins from kdelibs don't mention text/plain anymore)
    QVERIFY( offerListHasService( offers, "faketextplugin.desktop" ) );

    // We shouldn't have non-plugins
    QVERIFY( !offerListHasService( offers, "katepart.desktop" ) );
}
Ejemplo n.º 10
0
void DesktopCorona::checkAddPanelAction(const QStringList &sycocaChanges)
{
    if (!sycocaChanges.isEmpty() && !sycocaChanges.contains("services")) {
        return;
    }

    delete m_addPanelAction;
    m_addPanelAction = 0;

    delete m_addPanelsMenu;
    m_addPanelsMenu = 0;

    KPluginInfo::List panelContainmentPlugins = Plasma::Containment::listContainmentsOfType("panel");
    const QString constraint = QString("[X-Plasma-Shell] == '%1' and 'panel' ~in [X-Plasma-ContainmentCategories]")
                                      .arg(KGlobal::mainComponent().componentName());
    KService::List templates = KServiceTypeTrader::self()->query("Plasma/LayoutTemplate", constraint);

    if (panelContainmentPlugins.count() + templates.count() == 1) {
        m_addPanelAction = new QAction(i18n("Add Panel"), this);
        m_addPanelAction->setData(Plasma::AbstractToolBox::AddTool);
        connect(m_addPanelAction, SIGNAL(triggered(bool)), this, SLOT(addPanel()));
    } else if (!panelContainmentPlugins.isEmpty()) {
Ejemplo n.º 11
0
int main( int argc, char **argv )
{
    QCoreApplication app(argc, argv);

    KLocalizedString::setApplicationDomain("ktraderclient");
    KAboutData aboutData(QLatin1String("ktraderclient"), i18n("KTraderClient"), QLatin1String(PROJECT_VERSION));
    aboutData.addAuthor(i18n("David Faure"), QString(), "*****@*****.**");

    aboutData.setShortDescription(i18n("A command-line tool for querying the KDE trader system"));
    QCommandLineParser parser;
    KAboutData::setApplicationData(aboutData);
    parser.addVersionOption();
    parser.addHelpOption();
    aboutData.setupCommandLine(&parser);

    parser.addOption(QCommandLineOption(QStringList() << QLatin1String("mimetype"), i18n("A mimetype"), QLatin1String("mimetype")));
    parser.addOption(QCommandLineOption(QStringList() << QLatin1String("servicetype"), i18n("A servicetype, like KParts/ReadOnlyPart or KMyApp/Plugin"), QLatin1String("servicetype")));
    parser.addOption(QCommandLineOption(QStringList() << QLatin1String("constraint"), i18n("A constraint expressed in the trader query language"), QLatin1String("constraint")));

    parser.addOption(QCommandLineOption(QStringList() << QLatin1String("short"), i18n("Output only paths to desktop files")));

    parser.process(app);
    aboutData.processCommandLine(&parser);

    const QString mimetype = parser.value("mimetype");
    QString servicetype = parser.value("servicetype");
    const QString constraint = parser.value("constraint");
    const bool outputProperties = !parser.isSet("short");

    if ( mimetype.isEmpty() && servicetype.isEmpty() )
        parser.showHelp();

    if ( !mimetype.isEmpty() )
        printf( "mimetype is : %s\n", qPrintable( mimetype ) );
    if ( !servicetype.isEmpty() )
        printf( "servicetype is : %s\n", qPrintable( servicetype ) );
    if ( !constraint.isEmpty() )
        printf( "constraint is : %s\n", qPrintable( constraint ) );

    KService::List offers;
    if ( !mimetype.isEmpty() ) {
        if ( servicetype.isEmpty() )
            servicetype = "Application";
        offers = KMimeTypeTrader::self()->query( mimetype, servicetype, constraint );
    }
    else
        offers = KServiceTypeTrader::self()->query( servicetype, constraint );

    printf("got %d offers.\n", offers.count());

    int i = 0;
    KService::List::ConstIterator it = offers.constBegin();
    const KService::List::ConstIterator end = offers.constEnd();
    for (; it != end; ++it, ++i )
    {
        if (outputProperties) {
            printf("---- Offer %d ----\n", i);
            QStringList props = (*it)->propertyNames();
            QStringList::ConstIterator propIt = props.constBegin();
            QStringList::ConstIterator propEnd = props.constEnd();
            for (; propIt != propEnd; ++propIt )
            {
                QVariant prop = (*it)->property( *propIt );

                if ( !prop.isValid() )
                {
                    printf("Invalid property %s\n", (*propIt).toLocal8Bit().data());
                    continue;
                }

                QString outp = *propIt;
                outp += " : '";

                switch ( prop.type() )
                {
                    case QVariant::StringList:
                        outp += prop.toStringList().join(" - ");
                        break;
                    case QVariant::Bool:
                        outp += prop.toBool() ? "TRUE" : "FALSE";
                        break;
                    default:
                        outp += prop.toString();
                        break;
                }

                if ( !outp.isEmpty() )
                    printf("%s'\n", outp.toLocal8Bit().constData());
            }
        } else {
            printf("%s\n", (*it)->entryPath().toLocal8Bit().constData());
        }
    }
    return 0;
}
Ejemplo n.º 12
0
int main(int argc, char *argv[])
{
	KCmdLineArgs::init(argc, argv, appName, "kscreensaver", ki18n("Random screen saver"), 
                KDE_VERSION_STRING, ki18n(description));


	KCmdLineOptions options;

	options.add("setup", ki18n("Setup screen saver"));

	options.add("window-id wid", ki18n("Run in the specified XWindow"));

	options.add("root", ki18n("Run in the root XWindow"));

	KCmdLineArgs::addCmdLineOptions(options);

	KApplication app;

	WId windowId = 0;

	KCmdLineArgs *args = KCmdLineArgs::parsedArgs();

	if (args->isSet("setup"))
	{
		KRandomSetup setup;
		setup.exec();
		exit(0);
	}

	if (args->isSet("window-id"))
	{
		windowId = args->getOption("window-id").toInt();
	}

#ifdef Q_WS_X11
	if (args->isSet("root"))
	{
		QX11Info info;
		windowId = RootWindow(QX11Info::display(), info.screen());
	}
#endif
	args->clear();
	const KService::List lst = KServiceTypeTrader::self()->query( "ScreenSaver");
        KService::List availableSavers;

	KConfig type("krandom.kssrc", KConfig::NoGlobals);
        const KConfigGroup configGroup = type.group("Settings");
	const bool opengl = configGroup.readEntry("OpenGL", false);
	const bool manipulatescreen = configGroup.readEntry("ManipulateScreen", false);
        // TODO replace this with TryExec=fortune in the desktop files
        const bool fortune = !KStandardDirs::findExe("fortune").isEmpty();
        foreach( const KService::Ptr& service, lst ) {
            //QString file = KStandardDirs::locate("services", service->entryPath());
            //kDebug() << "Looking at " << file;
            const QString saverType = service->property("X-KDE-Type").toString();
            foreach (const QString &type, saverType.split(QLatin1Char(';'))) {
                //kDebug() << "saverTypes is "<< type;
                if (type == QLatin1String("ManipulateScreen")) {
                    if (!manipulatescreen)
                        goto fail;
                } else if (type == QLatin1String("OpenGL")) {
                    if (!opengl)
                        goto fail;
                } else if (type == QLatin1String("Fortune")) {
                    if (!fortune)
                        goto fail;
                }
            }
            availableSavers.append(service);
          fail: ;
        }

	KRandomSequence rnd;
	const int indx = rnd.getLong(availableSavers.count());
        const KService::Ptr service = availableSavers.at(indx);
        const QList<KServiceAction> actions = service->actions();

	QString cmd;
	if (windowId)
            cmd = exeFromActionGroup(actions, "InWindow");
        if (cmd.isEmpty() && windowId == 0)
            cmd = exeFromActionGroup(actions, "Root");
        if (cmd.isEmpty())
            cmd = service->exec();

    QHash<QChar, QString> keyMap;
    keyMap.insert('w', QString::number(windowId));
    const QStringList words = KShell::splitArgs(KMacroExpander::expandMacrosShellQuote(cmd, keyMap));
    if (!words.isEmpty()) {
        QString exeFile = KStandardDirs::findExe(words.first());
        if (!exeFile.isEmpty()) {
            char **sargs = new char *[words.size() + 1];
            int i = 0;
            for (; i < words.size(); i++)
                sargs[i] = qstrdup(words[i].toLocal8Bit().constData());
            sargs[i] = 0;

            execv(exeFile.toLocal8Bit(), sargs);
        }
    }

	// If we end up here then we couldn't start a saver.
	// If we have been supplied a window id or root window then blank it.
#ifdef Q_WS_X11
	QX11Info info;
	Window win = windowId ? windowId : RootWindow(QX11Info::display(), info.screen());
	XSetWindowBackground(QX11Info::display(), win,
			BlackPixel(QX11Info::display(), info.screen()));
	XClearWindow(QX11Info::display(), win);
#endif
}
void MainWindow::ExternalPopup::slotExecuteService( QAction* action )
{
    QString name = action->objectName();
    const StringSet apps =_appToMimeTypeMap[name];

    // get the list of arguments
    KUrl::List lst;

    if ( action->data() == -1 )
    {
    return;  //user clicked the title entry. (i.e: "All Selected Items")
    } else if ( action->data() == 1 ) {
        for( DB::FileNameList::Iterator it = _list.begin(); it != _list.end(); ++it ) {
            if ( _appToMimeTypeMap[name].contains( mimeType(*it) ) )
                lst.append( KUrl((*it).absolute()) );
        }
    } else if (action->data() == 2) {
        QString origFile = _currentInfo->fileName().absolute();
        QString newFile = origFile;

        QString origRegexpString =
            Settings::SettingsData::instance()->copyFileComponent();
        QRegExp origRegexp =
            QRegExp(origRegexpString);
        QString copyFileReplacement =
            Settings::SettingsData::instance()->copyFileReplacementComponent();

        if (origRegexpString.length() > 0) {
            newFile.replace(origRegexp, copyFileReplacement);
            QFile::copy(origFile, newFile);
            lst.append( newFile );
        } else {
            qWarning("No settings were appropriate for modifying the file name (you must fill in the regexp field; Opening the original instead");
            lst.append( origFile );
        }

    } else {
        lst.append( KUrl(_currentInfo->fileName().absolute()));
    }


    // get the program to run

    // check for the special entry for self-defined
    if (name == i18n("Your Command Line")) {

        static RunDialog* dialog = new RunDialog(MainWindow::Window::theMainWindow());
        dialog->setImageList(_list);
        dialog->show();

        return;
    }

    // check for the special entry for self-defined
    if (name == i18n("Open With...")) {
        KRun::displayOpenWithDialog(lst, MainWindow::Window::theMainWindow());
        return;
    }


    KService::List offers = KMimeTypeTrader::self()->query( *(apps.begin()), QString::fromLatin1("Application"),
                                                            QString::fromLatin1("Name == '%1'").arg(name));
    Q_ASSERT( offers.count() >= 1 );
    KService::Ptr ptr = offers.first();
    KRun::run(*ptr, lst, MainWindow::Window::theMainWindow() );
}
Ejemplo n.º 14
0
SearchProvider *SearchProvider::findByKey(const QString &key)
{
    KService::List providers =
        KServiceTypeTrader::self()->query("SearchProvider", QString("'%1' in Keys").arg(key));
    return providers.count() ? new SearchProvider(providers[0]) : 0;
}
Ejemplo n.º 15
0
int main( int argc, char **argv )
{
  KCmdLineArgs::init( argc, argv, "ktraderclient", 0, ki18n("KTraderClient"), "0.0" , ki18n("A command-line tool for querying the KDE trader system"));


  KCmdLineOptions options;

  options.add("mimetype <mimetype>", ki18n("A mimetype"));

  options.add("servicetype <servicetype>", ki18n("A servicetype, like KParts/ReadOnlyPart or KMyApp/Plugin"));

  options.add("constraint <constraint>", ki18n("A constraint expressed in the trader query language"));

  KCmdLineArgs::addCmdLineOptions( options );

  KApplication app( false ); // no GUI

  KCmdLineArgs *args = KCmdLineArgs::parsedArgs();

  const QString mimetype = args->getOption( "mimetype" );
  QString servicetype = args->getOption( "servicetype" );
  const QString constraint = args->getOption( "constraint" );

  if ( mimetype.isEmpty() && servicetype.isEmpty() )
      KCmdLineArgs::usage();

  if ( !mimetype.isEmpty() )
      printf( "mimetype is : %s\n", qPrintable( mimetype ) );
  if ( !servicetype.isEmpty() )
      printf( "servicetype is : %s\n", qPrintable( servicetype ) );
  if ( !constraint.isEmpty() )
      printf( "constraint is : %s\n", qPrintable( constraint ) );

  KService::List offers;
  if ( !mimetype.isEmpty() ) {
      if ( servicetype.isEmpty() )
          servicetype = "Application";
     offers = KMimeTypeTrader::self()->query( mimetype, servicetype, constraint );
  }
  else
     offers = KServiceTypeTrader::self()->query( servicetype, constraint );

  printf("got %d offers.\n", offers.count());

  int i = 0;
  KService::List::ConstIterator it = offers.constBegin();
  const KService::List::ConstIterator end = offers.constEnd();
  for (; it != end; ++it, ++i )
  {
    printf("---- Offer %d ----\n", i);
    QStringList props = (*it)->propertyNames();
    QStringList::ConstIterator propIt = props.constBegin();
    QStringList::ConstIterator propEnd = props.constEnd();
    for (; propIt != propEnd; ++propIt )
    {
      QVariant prop = (*it)->property( *propIt );

      if ( !prop.isValid() )
      {
        printf("Invalid property %s\n", (*propIt).toLocal8Bit().data());
	continue;
      }

      QString outp = *propIt;
      outp += " : '";

      switch ( prop.type() )
      {
        case QVariant::StringList:
          outp += prop.toStringList().join(" - ");
        break;
        case QVariant::Bool:
          outp += prop.toBool() ? "TRUE" : "FALSE";
          break;
        default:
          outp += prop.toString();
        break;
      }

      if ( !outp.isEmpty() )
        printf("%s'\n", outp.toLocal8Bit().data());
    }
  }
  return 0;
}