Difference between revisions of "Development/Tutorials/KAuth/KAuth Actions"

Jump to: navigation, search
m
 
(7 intermediate revisions by 5 users not shown)
Line 1: Line 1:
{{Template:I18n/Language Navigation Bar|Development/Tutorials/KAuth/KAuth Actions}}
+
 
  
 
{{TutorialBrowser|
 
{{TutorialBrowser|
Line 19: Line 19:
 
=== A simple case: creating and executing an action that has no helper associated ===
 
=== A simple case: creating and executing an action that has no helper associated ===
 
Creating an action in your code is rather simple:
 
Creating an action in your code is rather simple:
 
+
<syntaxhighlight lang="cpp">
Action readAction = "org.kde.auth.example.read";
+
KAuth::Action readAction = "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.
 
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.
Line 26: Line 27:
 
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:
 
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:
  
<code cpp>
+
<syntaxhighlight lang="cpp">
 
KAuth::ActionReply reply = readAction.execute();
 
KAuth::ActionReply reply = readAction.execute();
 
if (reply.failed()) {
 
if (reply.failed()) {
Line 33: Line 34:
 
   // Do your stuff here...
 
   // Do your stuff here...
 
}
 
}
</code>
+
</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, ActionReply carries additional information about the error occurred.
 
''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, ActionReply carries additional information about the error occurred.
Line 40: Line 41:
 
The basics are pretty much the same. This is how the snippet changes:
 
The basics are pretty much the same. This is how the snippet changes:
  
<code cpp>
+
<syntaxhighlight lang="cpp">
 
KAuth::Action readAction = "org.kde.auth.example.read";
 
KAuth::Action readAction = "org.kde.auth.example.read";
 
readAction.setHelperID("org.kde.auth.example");
 
readAction.setHelperID("org.kde.auth.example");
Line 53: Line 54:
 
   contents = reply.data()["contents"].toString();
 
   contents = reply.data()["contents"].toString();
 
}
 
}
</code>
+
</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()''.
 
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()''.
Line 64: Line 65:
 
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 just by setting ''Action::setExecutesAsync(true)''. To monitor the action's progress there's a new object, ''ActionWatcher'', that can be used for this purpose. Let's see how a long action could be handled:
 
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 just by setting ''Action::setExecutesAsync(true)''. To monitor the action's progress there's a new object, ''ActionWatcher'', that can be used for this purpose. Let's see how a long action could be handled:
  
<code cpp>
+
<syntaxhighlight lang="cpp">
 
void MainWindow::on_longAction_triggered()
 
void MainWindow::on_longAction_triggered()
 
  {
 
  {
Line 74: Line 75:
  
 
     longAction.setExecutesAsync(true);
 
     longAction.setExecutesAsync(true);
     if (longAction.execute() != Action::Authorized) {
+
     ActionReply earlyReply = longAction.execute();
 +
    if (earlyReply.failed()) {
 
         this->statusBar()->showMessage("Could not execute the long action");
 
         this->statusBar()->showMessage("Could not execute the long action");
 
     }
 
     }
Line 90: Line 92:
 
     //...
 
     //...
  
     if (reply.succeded())
+
     if (reply.succeeded())
         this->statusBar()->showMessage("Action succeded", 10000);
+
         this->statusBar()->showMessage("Action succeeded", 10000);
 
     else
 
     else
 
         this->statusBar()->showMessage(QString("Could not execute the long action: %1").arg(reply.errorCode()), 10000);
 
         this->statusBar()->showMessage(QString("Could not execute the long action: %1").arg(reply.errorCode()), 10000);
 
  }
 
  }
</code>
+
</syntaxhighlight>
  
 
As you can see, we're using the watcher to monitor the progress and the result. Please note that even if the action is asynchronous a check on an early reply is performed: this is because with some authorization systems the authorization might take place very early, and hence before the asyncronous action returns to the event loop.
 
As you can see, we're using the watcher to monitor the progress and the result. Please note that even if the action is asynchronous a check on an early reply is performed: this is because with some authorization systems the authorization might take place very early, and hence before the asyncronous action returns to the event loop.
  
 
Also, note that asyncronous actions may be stopped with ''Action::stop()''
 
Also, note that asyncronous actions may be stopped with ''Action::stop()''
 +
 +
== Handling ActionReply ==
 +
As you have seen in the previous examples, action execution always returns an ''ActionReply''. Let's see how to handle it
 +
 +
=== Handling errors ===
 +
''ActionReply'' has two main possible statuses: ''Success'' or ''Failed''. In case of failure, the error could be associated to two different sources:
 +
 +
*KAuth's internals
 +
*An error in the execution phase (e.g.: the helper encountered an error)
 +
 +
You can easily check the error type through ''ActionReply::type'':
 +
 +
<syntaxhighlight lang="cpp">
 +
if (reply.failed())
 +
{
 +
  if (reply.type() == ActionReply::KAuthError) {
 +
        // There has been an internal KAuth error
 +
        KMessageBox::error(this, i18n("Unable to authenticate/execute the action: %1, %2", reply.errorCode(), reply.errorDescription()));
 +
  } else {
 +
        // Our helper triggered a custom error
 +
        // Act accordingly...
 +
  }
 +
}
 +
</syntaxhighlight>
 +
 +
''ActionReply::KAuthError'' is a reserved type that reports an internal error happened in KAuth. This could also mean a failure in the authorization/authentication phase: you have to check the error code (ActionReply::errorCode) for that. For an explanation of the KAuth error codes see the [http://community.kde.org/KAuth_Troubleshooting KAuth Troubleshooting] page.
 +
 +
Otherwise, it means the helper threw an error (as you will see in the next tutorial): in this case, errorCode and description are provided by the helper itself
 +
 +
=== Getting back data ===
 +
Just like ''Action'' has '''arguments''', ''ActionReply'' has '''data''', which works in a very similar flavour. Upon a successful reply, you can use ''ActionReply::data()'' to obtain a QVariantMap carrying some custom data streamed from the helper
 +
 +
=== Differences when using or not using an helper ===
 +
When not using an helper, ActionReply will just report success without any data attached to it or an ''ActionReply::KAuthError''.
  
 
== Integrating KAuth Actions into KDE UI elements ==
 
== Integrating KAuth Actions into KDE UI elements ==
 
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.
 
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.
  
===How it works===
+
===Integrating KPushButton===
 
Let's see how the longAction example changes when dealing with a KPushButton:
 
Let's see how the longAction example changes when dealing with a KPushButton:
  
<code cpp>
+
<syntaxhighlight lang="cpp">
 
void MainWindow::setupAction()
 
void MainWindow::setupAction()
 
  {
 
  {
Line 125: Line 161:
 
void MainWindow::performAction(KAuth::Action *action)
 
void MainWindow::performAction(KAuth::Action *action)
 
{
 
{
     if (action->execute() != Action::Authorized) {
+
     ActionReply earlyReply = action->execute();
 +
    if (earlyReply.failed()) {
 
         this->statusBar()->showMessage("Could not execute the long action");
 
         this->statusBar()->showMessage("Could not execute the long action");
 
     }
 
     }
Line 146: Line 183:
 
         this->statusBar()->showMessage(QString("Could not execute the long action: %1").arg(reply.errorCode()), 10000);
 
         this->statusBar()->showMessage(QString("Could not execute the long action: %1").arg(reply.errorCode()), 10000);
 
  }
 
  }
</code>
+
</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.
 
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.
Line 153: Line 190:
  
 
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.
 
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==
 
==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
 
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

Latest revision as of 16:33, 19 July 2012


Using KAuth actions in your application
Tutorial Series   KAuth Tutorial
Previous   KAuth Basics
What's Next   Creating a KAuth helper to perform a privileged action
Further Reading   KAuth::Action Class Reference

Contents

[edit] 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.

[edit] A simple case: creating and executing an action that has no helper associated

Creating an action in your code is rather simple:

KAuth::Action readAction = "org.kde.auth.example.read";

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:

KAuth::ActionReply reply = readAction.execute();
if (reply.failed()) {
   QMessageBox::information(this, "Error", QString("KAuth returned an error code: %1").arg(reply.errorCode()));
} else {
   // Do your stuff here...
}

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, ActionReply carries additional information about the error occurred.

[edit] 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:

KAuth::Action readAction = "org.kde.auth.example.read";
readAction.setHelperID("org.kde.auth.example");
QVariantMap args;
args["filename"] = filename;
readAction.setArguments(args);
 
KAuth::ActionReply reply = readAction.execute();
if (reply.failed()) {
   QMessageBox::information(this, "Error", QString("KAuth returned an error code: %1").arg(reply.errorCode()));
} else {
   contents = reply.data()["contents"].toString();
}

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.

[edit] 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 just by setting Action::setExecutesAsync(true). To monitor the action's progress there's a new object, ActionWatcher, that can be used for this purpose. Let's see how a long action could be handled:

void MainWindow::on_longAction_triggered()
 {
    Action longAction = "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);
    ActionReply earlyReply = longAction.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.succeeded())
        this->statusBar()->showMessage("Action succeeded", 10000);
     else
        this->statusBar()->showMessage(QString("Could not execute the long action: %1").arg(reply.errorCode()), 10000);
 }

As you can see, we're using the watcher to monitor the progress and the result. Please note that even if the action is asynchronous a check on an early reply is performed: this is because with some authorization systems the authorization might take place very early, and hence before the asyncronous action returns to the event loop.

Also, note that asyncronous actions may be stopped with Action::stop()

[edit] Handling ActionReply

As you have seen in the previous examples, action execution always returns an ActionReply. Let's see how to handle it

[edit] Handling errors

ActionReply has two main possible statuses: Success or Failed. In case of failure, the error could be associated to two different sources:

  • KAuth's internals
  • An error in the execution phase (e.g.: the helper encountered an error)

You can easily check the error type through ActionReply::type:

if (reply.failed())
{
  if (reply.type() == ActionReply::KAuthError) {
        // There has been an internal KAuth error
        KMessageBox::error(this, i18n("Unable to authenticate/execute the action: %1, %2", reply.errorCode(), reply.errorDescription()));
  } else {
         // Our helper triggered a custom error
         // Act accordingly...
  }
}

ActionReply::KAuthError is a reserved type that reports an internal error happened in KAuth. This could also mean a failure in the authorization/authentication phase: you have to check the error code (ActionReply::errorCode) for that. For an explanation of the KAuth error codes see the KAuth Troubleshooting page.

Otherwise, it means the helper threw an error (as you will see in the next tutorial): in this case, errorCode and description are provided by the helper itself

[edit] Getting back data

Just like Action has arguments, ActionReply has data, which works in a very similar flavour. Upon a successful reply, you can use ActionReply::data() to obtain a QVariantMap carrying some custom data streamed from the helper

[edit] Differences when using or not using an helper

When not using an helper, ActionReply will just report success without any data attached to it or an ActionReply::KAuthError.

[edit] Integrating KAuth Actions into KDE UI elements

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.

[edit] Integrating KPushButton

Let's see how the longAction example changes when dealing with a KPushButton:

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);
 }

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.

[edit] 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.

[edit] 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


This page was last modified on 19 July 2012, at 16:33. This page has been accessed 7,340 times. Content is available under Creative Commons License SA 3.0 as well as the GNU Free Documentation License 1.2.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V.Legal