Development/Tutorials/KAuth/KAuth Actions: Difference between revisions

From KDE TechBase
No edit summary
m (Replaced content with "This tutorial was moved to [https://develop.kde.org/docs/kauth/using_kauth/ develop.kde.org/docs/kauth/using_kauth/]")
Tag: Replaced
(3 intermediate revisions by 2 users not shown)
Line 1: Line 1:
 
This tutorial was moved to [https://develop.kde.org/docs/kauth/using_kauth/ develop.kde.org/docs/kauth/using_kauth/]
 
{{TutorialBrowser|
 
series=KAuth Tutorial|
 
name=Using KAuth actions in your application|
 
pre=[[Development/Tutorials/KAuth/KAuth_Basics|KAuth Basics]]|
 
next=[[Development/Tutorials/KAuth/Helper_HowTo|Creating a KAuth helper to perform a privileged action]]|
 
reading=[http://api.kde.org/4.x-api/kdelibs-apidocs/kdecore/html/classKAuth_1_1Action.html KAuth::Action Class Reference]
}}
 
== Using actions in your applications ==
Now that you've learned the basic KAuth concepts and how to register a set of actions into the system, it's time to see how to actually use KAuth actions inside your application. This tutorial will cover the caller side: how to implement an helper associated to an action will be covered in the next tutorial.
 
=== A simple case: creating and executing an action that has no helper associated ===
Creating an action in your code is rather simple:
<syntaxhighlight lang="cpp">
KAuth::Action action(QLatin1String("org.kde.auth.example.read"));
</syntaxhighlight>
 
As you can see, Actions are usually created on the stack and just when needed. To create an action, you just have to specify its own identifier.
 
If your action has no helper associated with it (so you just want to check if the user is authorized before going on), the next step is just doing the following:
 
<syntaxhighlight lang="cpp">
KAuth::ExecuteJob *job = action.execute();
bool execSuccess = job->exec();
if (!execSuccess) {
    QMessageBox::information(this, "Error", QString("KAuth returned an error code: %1 %2").arg(job->error()).arg(job->errorString()));
} else {
    // Do your stuff here...
}
</syntaxhighlight>
 
''Action::execute()'' starts up all the phases from authorization to execution and returns an ActionReply. In our case, if the reply failed is because the authorization was unsuccessful: in any case, the KJob carries additional information about the error occurred.
 
=== Creating and executing an action that has an helper attached to it ===
The basics are pretty much the same. This is how the snippet changes:
 
<syntaxhighlight lang="cpp">
KAuth::Action action(QLatin1String("org.kde.auth.example.read"));
action.setHelperID("org.kde.auth.example");
QVariantMap args;
args["filename"] = filename;
action.setArguments(args);
KAuth::ExecuteJob *job = action.execute();
bool execSuccess = job->exec();
if (!execSuccess) {
    QMessageBox::information(this, "Error", QString("KAuth returned an error code: %1 %2").arg(job->error()).arg(job->errorString()));
} else {
    QString contents = job->data()["contents"].toString();
}
</syntaxhighlight>
 
There are more parameters this time. First of all, the helper has to be explicitely declared throughout ''Action::setHelperID''. This is also done to prevent calling an helper accidentally. We are also able to pass some parameters to the helper, through ''Action::setArguments''. In the very same way, the helper, upon success, is able to give back to the application a QVariantMap, accessible through ''ActionReply::data()''.
 
In this case, ''Action::execute()'' also launches the execution phase of the helper, given that the authorization was successful.
 
There are more advanced usages for helper actions, such as progress reporting and data retrieval during execution, but these will be covered in the next tutorial.
 
=== Executing actions asynchronously ===
In the previous examples all the actions have been executed synchronously. However, when you have an action attached to an helper which is likely to be taking a long time, a synchronous approach is not very well fitting. KAuth is able to handle action execution asynchronously in the same way as KJob can using start(). To monitor the action's progress there's some signals [https://api.kde.org/frameworks/kauth/html/classKAuth_1_1ExecuteJob.html#a4188a035ebdef1c5a2acc66c527fb366 newData] or [https://api.kde.org/frameworks/kcoreaddons/html/classKJob.html#a91803b47fc242540d60e0502e3175a56 KJob::percent]. Let's see how a long action could be handled:
 
<syntaxhighlight lang="cpp">
void MainWindow::on_longAction_triggered()
{
    KAuth::Action longAction(QLatin1String("org.kde.auth.example.longaction"));
    KAuth::ExecuteJob *job = longAction.execute();
    connect(job, SIGNAL(percent(KJob*, unsigned long)), this, SLOT(helperPercent(KJob*, unsigned long)));
    connect(job, SIGNAL(newData(const QVariantMap &)), this, SLOT(helperData(const QVariantMap &)));
    connect(job, SIGNAL(result(KJob*)), this, SLOT(finished(KJob*)));
    job->start();
 
    //...
}
 
void MainWindow::helperPercent(KJob*, unsigned long step)
{
    qDebug() << step;
}
 
void MainWindow::helperData(const QVariantMap & data)
{
    //...
}
 
void MainWindow::finished(KJob* job)
{
    qDebug() << "helper finished " << job->error();
}
</syntaxhighlight>
 
As you can see, we're using the watcher to monitor the progress and the result.
 
There is currently (Frameworks 5.31, early 2017) no way to stop the action.
 
== Handling Results ==
 
Check for errors when running exec():
 
<syntaxhighlight lang="cpp">
    KAuth::ExecuteJob *job = action.execute();
    bool execSuccess = job->exec();
    if (!execSuccess) {
        QMessageBox::information(this, "Error", QString("KAuth returned an error code: %1 string: %2").arg(job->error()).arg(job->errorString()));
    } else {
        qDebug() << "Helper returned: " << job->data();
    }
</syntaxhighlight>
 
or for async cast the KJob back to a KAuth::ExecuteJob
<syntaxhighlight lang="cpp">
    KAuth::ExecuteJob *job = action.execute();
    connect(job, SIGNAL(result(KJob*)), this, SLOT(finished(KJob*)));
    job->start();
 
void Testy::finished(KJob* job) {
    qCDebug(IMAGEWRITER_LOG) << "finished() " << job->error();
    KAuth::ExecuteJob *authJob2 = (KAuth::ExecuteJob *)job;
    qCDebug(IMAGEWRITER_LOG) << "finished() " << authJob->data();
}
</syntaxhighlight>
 
== Integrating KAuth Actions into KDE UI elements ==
TODO: update this for Frameworks 5. Seems mostly legacy.
 
KDE provides a way to integrate KAuth action seamlessly into a user interface. UI elements such as ''KPushButton'' can be associated with an action, and will update their appearance based on the action's status. Also, KPushButton is able to perform an early authorization, if supported by the authorization system, before notifying back the application.
 
===Integrating KPushButton===
Let's see how the longAction example changes when dealing with a KPushButton:
 
<syntaxhighlight lang="cpp">
void MainWindow::setupAction()
{
    KPushButton *button = new KPushButton;
    Action *longAction = new Action("org.kde.auth.example.longaction");
    connect(longAction->watcher(), SIGNAL(progressStep(int)),
            progressBar,          SLOT(setValue(int)));
    connect(longAction->watcher(), SIGNAL(actionPerformed(ActionReply)),
            this,                SLOT(longActionPerformed(ActionReply)));
 
    longAction.setExecutesAsync(true);
 
    button->setAuthAction(longAction);
    connect(button, SIGNAL(authorized(KAuth::Action*)), this, SLOT(performAction(KAuth::Action*)));
}
 
void MainWindow::performAction(KAuth::Action *action)
{
    ActionReply earlyReply = action->execute();
    if (earlyReply.failed()) {
        this->statusBar()->showMessage("Could not execute the long action");
    }
 
    //...
}
 
void MainWindow::stopLongAction()
{
    Action("org.kde.auth.example.longaction").stop();
}
 
void MainWindow::longActionPerformed(ActionReply reply)
{
    //...
 
    if (reply.succeded())
        this->statusBar()->showMessage("Action succeded", 10000);
    else
        this->statusBar()->showMessage(QString("Could not execute the long action: %1").arg(reply.errorCode()), 10000);
}
</syntaxhighlight>
 
As you may notice, here the action is allocated on the heap through ''new''. This is because KPushButton will keep a reference to the same action throughout all his vital cycle, in a different flavour compared to what we've seen before.
 
Let's see what happens. Here we associate ''longAction'' to ''button''. Please note that we connect to ''authorized'' and not ''clicked''. ''authorized'' gets emitted only if the button was clicked and the action passed the early authorization phase. Done that, in our slot we can decide to start up explicitely the execution or do something else before that.
 
To the bottom line, associating actions to KPushButtons is a great idea if you want to start up an action dynamically, and getting good and consistent visual integration while doing it.
 
===Other GUI elements===
As of today, KAuth is also able to integrate with ''KAction'' with an almost identical workflow, that hence won't be covered here, as the API is identical.
 
==Conclusion==
As you have seen, there are lots of ways to use an action in your application, and most of the times the best solution depends on what you're trying to achieve. A good reading and advised reading is the KAuth::Action API documentation, which is quite extensive and covers everything that was shown in this tutorial

Revision as of 14:51, 15 December 2020

This tutorial was moved to develop.kde.org/docs/kauth/using_kauth/