\n" lomiri-action-api-1.1.3/documentation/cpp/pages/000077500000000000000000000000001455542516300215755ustar00rootroot00000000000000lomiri-action-api-1.1.3/documentation/cpp/pages/context.dox000066400000000000000000000047051455542516300240030ustar00rootroot00000000000000/*! \page page_contexts Action Contexts \section sec_overview Overview Application which has different views needs to manage it actions based on the currently active view; not all of the actions supported by the application might be relevant or applicable on all of the views. Therefore Lomiri Action API provides action contexts; a context groups actions together and by providing multiple contexts the developer is able to control the visibility of the actions. The ActionManager then exposes the actions from these different contexts. \image html context_overview.png Each application has one global context; the actions in this context are always available. The application may have one or more additional local context of which only one can be active at a time. The ActionManager merges the global context and the active local context together; the actions available at any given time is the union of the global context and the active local context. \image html multiple_contexts.png \section sec_single_context Applications with Single Context For applications that do not require multiple contexts using the API is straight forward as the ActionManager provides the global context automatically. First, create the Action: \snippet action-context/action-context.cpp create global action And add it to the ActionManager: \snippet action-context/action-context.cpp add global to manager myAction is now added to the global context. \section sec_multiple_contexts Applications with Multiple Contexts When multiple contexts are needed the developer creates suitable number of ActionContext objects, adds the actions to the contexts, adds the contexts to the manager and sets the active one. Setting the active context must be managed by the developer. The can only be one active local context at a time. Create the local actions: \snippet action-context/action-context.cpp create local actions Create the local contexts: \snippet action-context/action-context.cpp create contexts Add the local actions to the contexts: \snippet action-context/action-context.cpp add context actions Add the local contexts to the manager: \snippet action-context/action-context.cpp add local ctx to manager Manage the active context by setting the active property on any of them: \snippet action-context/action-context.cpp set context active Setting an another context active later will inactivate the previously active one. --- The complete example: \include action-context/action-context.cpp */ lomiri-action-api-1.1.3/documentation/cpp/pages/future-plans.dox000066400000000000000000000027241455542516300247430ustar00rootroot00000000000000/*! \page page_future-plans Future Development Plans \section sec_action Action \subsection sec_action-state State Property Action should be able to hold a state. State is persistent compared to the onTriggered() value. State allows us to do more complex interaction with the external platform components. \section sec_preview-action Preview Action \subsection sec_preview-action-modes Preview Modes Currently the PreviewAction does all the previews "live;" the values update continuously and the application is expected to generate the preview on constantly. This can be problematic if the application is unable to generate a preview or generating the preview is so expensive resource-wise that it's not feasible to do a live preview. In the future the PreviewAction will offer more preview modes which allows the developer to specify manual or partial previews. \subsection sec_preview-action-layout Layout for PreviewParameters Currently the PreviewAction does not offer a way to control the layout of the PreviewParameters. In the future a layout support could be added. \subsection sec_preview-action-more-parameters Additional Preview Parameters Currently the only supported preview parameter is the PreviewRangeParameter. We need more parameter types like Text, Boolean and ListSelection. \section sec_context ActionContext \subsection sec_custom-toolbar-item Custom HUD Toolbar Items Application should be able to provide their own custom toolbar items in the HUD toolbar. */ lomiri-action-api-1.1.3/documentation/cpp/pages/mainpage.dox000066400000000000000000000032501455542516300240720ustar00rootroot00000000000000/*! \mainpage Lomiri Action API \tableofcontents \section sec_introduction Introduction Lomiri Action API offers a way to easily integrate with the Lomiri components outside of the application such as the Launcher, HUD, AppMenu and MessagingMenu. Applications have internally different types of actions with different life-cycles. Some actions are application wide that are relevant and available throughout the whole life-cycle of the application. Other actions are context specific and only available when the application is in certain visual state, such as in image editing mode. See \ref page_contexts "Action Contexts" for more details. Application can define application wide actions dynamically during runtime and as offline (jumplist) actions that are available even if the application is not running. Activating an offline action will launch the application when necessary. Lomiri Action API can be used with three ways: - \ref using-cpp "using this Qt C++ API" - Using the QML module directly (see the QML documentation) - Using the UI Toolkit UI Toolkit simplifies the ActionContext management and provides ActionManager as part of the MainView. See the UI Toolkit documentation for more details. \section sec_general General Topics - \ref page_contexts "Action Contexts" - \ref page_preview-actions "Preview Actions" - \ref page_platform-integration "Platform Integration" - \ref page_offline-actions "Offline Actions" - \ref page_future-plans "Future Development Plans" \section sec_bug_reports Reporting Bugs If you find any problems with the or this documentation, please file a bug in Lomiri Action API [Launchpad page](https://bugs.launchpad.net/lomiri-action-api). */ lomiri-action-api-1.1.3/documentation/cpp/pages/offline-actions.dox000066400000000000000000000026251455542516300253760ustar00rootroot00000000000000/*! \page page_offline-actions Offline Actions Applications can define offline (jump list) actions in their .desktop files. These actions are available in the Launcher, AppMenu, HUD and MessagingMenu even if the application is not running. When an offline action is executed and the application is not running the application is started and executes the given action on startup, but for the user it does not make any difference if the application is running or not prior to the action invocation. --- This example assumes we have a mail application, MailApp. This application defines offline actions in mail-app.desktop: \include mail-app/mail-app.desktop The desktop file's Actions key lists the offline actions. Each action then has its own group entry in the .desktop file. MailApp defines two offline actions: Compose and Contacts. By leaving the Exec keys empty for the actions the platform will invoke the Lomiri Actions defined by the application. Now, the Application has to define corresponding actions in it's code: \snippet mail-app/mail-app.cpp setting the compose name \snippet mail-app/mail-app.cpp setting the contacts name And finally add the actions to the manager. \snippet mail-app/mail-app.cpp add to manager --- Here is the full example also showing the connections to the Action::triggered() signal: \include mail-app/mail-app.cpp */ lomiri-action-api-1.1.3/documentation/cpp/pages/platform-integration.dox000066400000000000000000000012661455542516300264630ustar00rootroot00000000000000/*! \page page_platform-integration Platform Integration Lomiri Action API offers a way for application to integrate with the platform components such as the Lomiri Launcher and the Lomiri HUD. The ActionManager exports the actions to D-Bus which allows external components and even 3rd party applications to interact with the actions. \image html images/platform_integration.png "Platform Integration through D-Bus." One of the key benefits of Lomiri Action API is that it allows seamless integration with the Lomiri HUD; All Lomiri Actions are available to the HUD once they have been added to the ActionManager. \image html images/hud_screenshot.jpg "The HUD showing some actions." */ lomiri-action-api-1.1.3/documentation/cpp/pages/preview-actions.dox000066400000000000000000000051151455542516300254320ustar00rootroot00000000000000/*! \page page_preview-actions Preview Actions The preview action is an action that allows the application to generate a preview of the action before the action is applied. The preview is controlled by the HUD UI. PreviewActions contain one or more parameters which form the preview parameters of the action. The PreviewAction has additional extra requirements compared to other Actions: - It can have multiple parameters whose values can be seen and changed over the bus - The parameters' ordering can be specified by client code - It adds new signals to control the preview mode: started, cancelled, resetted The ordering of the parameters is specified by the order in which the actions are defined in the parameters list. PreviewAction does not have a value of it's own. Instead the values of the parameters provide the information on which the preview is generated. \image html hud_parameters.jpg "HUD UI showing Color Balance action with four slider parameters" \section sec_control_signals Control Signals Diagram describing when the different signals are emitted: \image html preview_action_signals.png started signal informs the application that it must set up a preview view and start updating the preview based on the values of the defined preview parameters. resetted signal informs the application that it has to reset the parameter values to their original values. cancelled signal informs the application that the user cancelled the PreviewAction. At this point the application must return the the state it was in at the time the started() signal was triggered without applying any changes. triggered signal informs the application the user wants the changes to be applied. \section sec_example Example This example shows how to create a PreviewAction with a single range parameter. First a PreviewAction is created and set up: \snippet preview-action/preview-action.cpp create previewaction Then a PreviewRangeParameter: \snippet preview-action/preview-action.cpp create rangeparameter After all the parameters have been created they are added to the PreviewAction: \snippet preview-action/preview-action.cpp set previewaction parameters And finally the PreviewAction is added to the ActionManager: \snippet preview-action/preview-action.cpp add to manager Then hooking up the control signals: \snippet preview-action/preview-action.cpp connect previewaction signals And not forgetting the parameter value updates: \snippet preview-action/preview-action.cpp connect parameter signals --- The complete example: \include examples/preview-action/preview-action.cpp */ lomiri-action-api-1.1.3/documentation/cpp/pages/using-cpp.dox000066400000000000000000000006611455542516300242210ustar00rootroot00000000000000/*! \page using-cpp Using the C++ API Install the development headers: \code{.txt} sudo apt-get install liblomiri-action-qt1-dev \endcode Use pkg-config to get the necessary compilation flags: \code{.txt} $ g++ myapp.cpp `pkg-config --cflags --libs lomiri-action-qt-1` -o myapp \endcode The headers can then be included as: \code{.cpp} // includes the lomiri::action::Action class #include \endcode */ lomiri-action-api-1.1.3/documentation/images/000077500000000000000000000000001455542516300211615ustar00rootroot00000000000000lomiri-action-api-1.1.3/documentation/images/context_overview.png000066400000000000000000001432011455542516300253020ustar00rootroot00000000000000PNG  IHDR YsBIT|d pHYs B(xtEXtSoftwarewww.inkscape.org<RtEXtCopyrightCC Attribution-ShareAlike http://creativecommons.org/licenses/by-sa/3.0/^Z IDATxw|l˦76 D@TĠґ&]7S! GAH@edaM lL|C2sܳggܫ,7D"B!n'K#jNF!BH/'U!Btx]5!B!8&.wy Og$BqeL~ JDH1R !!B!j)ЅB!A@B!]!BD t!B!j)ЅB!A@B!|^zX,z=+Wdʕ,Yɓ'sUWUEUCܹY!&H#0n8F?6͛7SV-Otua„ dffrmC8eٲefѢE}5]߾}۷ou!Bqٺp0m4TU_,UFn2MKK?DQZjEHHH9~8YYYQn]7n\Dǻ~+!99?^OӦMS{JHH@Qׯ(F"""\UUu`0Yf~ yg0qD;w.::l6"##1rssIOO'(( qRRRQFR9r1ҰZԩSf͚NQQu-5䦠 !;;Ljժ_>9tAAA4m-Ϝ222\uiݶgddCXX>>>=B!K.׬YÑ#Ghڴ)}1yyyL>˗m0`>(ޮm}~!駟.۷3h {楗^Eŋbu]<#L&z=3f`<3nfΜɧ~#}\J.Y$f̘jiۗ.]`08z(sᥗ^"**xƍ3x`w'Nf1b4MɓԫWnEuRMڵy߇n7ǎctڕ[xb|M6lHΝi׮>>>޽8HHH^z[?:uHq.B+%%慆skʕٳk{U ٓdzi&6mD.]܎ԩ7|3ݺub0eRzxx8,Yr%^{-ӧOK.tM~|嗌5 ^OHH/?8SLweĉf&Oʻ`(ϲΧ9r[o]b2_y\k1L|GtnFbccٱc6l(5W^lm[`ƍ8lCFJ =9󉋋cԨQ>>oN6nȐ!CZlݺC-[PUNǦM0LtرC!,)cʜEd_T,h(8p 6b|9zhmKk&M\ۺwΫʏ?Ȅ HHH`߾}5j5\Sff͚U8N:5kxꩧ(((`t[y{aaa4oޜm۶Ǯ](((k׮}N<ɚ5khݺyl֬{e׮]XMӰZ$''vZLB||<[/5kLZضm7n$?? &мys~ш ?3>>>8222?پ}]իWs1b)3g>̆ d̘1n vɶm۸iѢZbٲeرSNa6]"]ڵk-jd69t6l{(>}s 7ks/WGB!rػ`%qt_5/2++զSN?Nnj38q"˖-cٲe6]veҤIO,=O<3gd̙sHw܁(ۼ+\mFXڶmng t<37W_}ԨQl޼kײvZ|zw?>~{eܸq=tPvI@@@j0zW^ym_dddk?3&l8g} /ﶿ~Ԯ]m۝w?LxxݻMaaaUkB!ʒyu*d`RyO89rz5a oUU?9x мyRosJRRѥ%ܾ};^^^nm{jj*w&--0ڴiSp||?(2Hw⩘r5+׬\5皕i !⟧(zEjVe]՝B![_e]mA@Q; !B*Y}oSoo|FB!l>^ !BQH.B!D "B!5B!B R !BQxtJѩQtkZO\pfnl0l t)8><ቘ|hC zwy1]8MAf6f'b.\ 'bR4f?ڶ*:FPti#B!dE=z]@EUTLESLH  DQ^T9ry"&<0aW{*2A(ڣiP+0FQxe̙FO=i5}"~uoEn wBឍՔiokܾA!n!QS{^gwzO<ӡ/I&9xplYL1AMSCa͠C!݇(j2S:5F5MXKQxBzu 'bړNpp{3`娥lQtz݇> J%ơ9옢Z]g#Ƣ\)҅B+'-N+[{@3xAO{#1O StkĽT ׀?J(ܽ V}_j^6îu!C]C`/3z+zt$tvGpd@a+ !B\)E90}@~=J%c4rAȧK?>9R}IfϩbP +:GȘ*T'>t D-<춽pZRޘ#+m{1k-0 ]J/{_*UDo ߹~LƑNBl_C+܎Y6OY\ۼ#Gԣ٬ޟèts!BK# 6-Ǟ~u7_M'/ 8#;o SN` "77t~α⚵0ST zhƞHy,nCwI8ٗcnQ|hzM0i@05h>0۩cd| K?|oZn:;IW Z8ϦbDtCC)ܵeH|>\h6+^"pg$l+ #d >B!)Eݧ:}P-|:"l߮w:F\M$9d| xͭ^z :~En#w{TΚN }W^b4tg_>@KM }Lrpd5mt޾D#:gABWUju>"Ӿm3B<o&BT%?lq sNã\{:p/ l^Qn[h"xl8`OMtW~>:@ aNǣ `{VXOt֓αsxE-'w_[IPÜ;6EgڧP>GPs3_0V0GvBQ%@5 w|2zyoM%w /\TcYB2Yj4&hf'ybKN ̰Kb?Se.2\9 !jI.jƑv=K7GQWV#xc>ȩmSNCTmmX܍I'T8ors3cRbrćsf;Wjfb;} }@L(B0Ry/{}A#ۂu e ja>zU3zvc]⢲q15l> -?aK8a&jn&w^ 1'W(ws(Fy}+@ B!C tQ# IDAT#:|z $]=߭@"'._ {6tPBF=S*N?k: ߑݧBjg5 0t@u޾|w^^F4P1/_#eԚkܸӓr9g!})ᚦ9Mk1"vݡ^S|p)Oٿ7;ơ*N&}žI}agMP FBFI蹳9kzp.id-/IN;i]?y~jA.Z(F$t!o01\(꾹nEs)M[+(cS7ܼyg+x !#vԼ,L`nޡʙ@[)+,+u^W>wc?v cf[uƾxwASO DRcn|z_E80ER3(#!^?f$wLs(f  eIsRqeR Yi˄,Ui\q@5^2mܲc!}xÙBt)Sx$߅ gh .쉬/N E}[~Ѽx ;Q5Ǚ3g^`-K3VI|!B8vӋ=Zk*?Guz*NcGQX0i$1j<≘g,kBj4#w(Di(So~B!j>5/̹oɨP{n%w\ܗEÜ:V`(K"jceɼQCDUEbcs^W>P"w'<#.ƒF-:7BQGf LJBl?+u\/`;qas.vC_ a='''tʘ"l5&j֡!)Bݷ_.VA GZ#= aVch6++QPc}#Q&.KtjI~i4+RϿ_,?'^eXj́fglD^+ǀ3s|TB!ą' wΠ3Rk\E{`M/y|S?iH; ds7+I6'.\X -ěAMP|y;_hjqZQjq!ZQZq!ݦjyu.#\a\e l^O!9Hy>|Coϖ箴\&Ձ-(4iPtz!KBP^G+* aj|mh~ϞlDN Gv:N!,*hEާfsm3L5?ʽD< PtǿPW}>q{15h>8GLs$OG@ǑN`{oZq)o>@{OWrŇvbO+15l @'8Lܲ#C1{ ZMn"oZpdը ^MRш{&'Ao _0m薛LS@4FcE ^wn^5!~a1aϭoYI֕;3v`nԜZ! ^,+E{+@:U6]S raK2>F73;Q+*@?ћ!,=o;u tz̭~Konu-O3pd='Ş̉9glmwkh||o *b,u/P=sǦ .ހMmzdl 䭞#;=!f\k`Fԝ՛BQs!Opd1l_zl:Z~vcp.xmDR|dY!x_}#Wo䭚t<3E_sCu`=qFm8Ue94ͽI`-!RcKdNGby9^sèvTɬ4WPvG9f9lPW0q>oƑNsBpFr~MؓL-`OZ4 îxQ.zEho]o;z'r~MwX~^^sB!j 0u^G8>(&/cP.^ͯCxG|:B`6%OQ F-:լ=W(hC=~v[LEI_2>NSTsPl',Hy_#( JSUAX^#H2@p8CȨH2A3lGj#gx^j&Ws;1GP͗&.]I4 ? {G,u#l]՘eIVBbWլEލ-0tB15i{v؋R|h'FmP ι)> .6׹Np57CpZtD{CASO9$ W\c o 櫺{{IA+y|ܢksfh6LQ-Y(ܹ5?StkLQ-*wwDv+J~j^K?"OPsW^hQB t!.@lRR t]y t~A| }끇q1;?!BqtN%5[t ,4,p!B!*L J0E?`y풕R{;b,95!Bqެs.&|c(.bB!eN !OkLJhfZq!LJCf.&a\G5WGncjA(f1UڡB!U,.:o? \R%k45?Gf*~LEpm*ڻG!߿g wU y5:/A1Al^t[B!5VNլ䘅(^|xwb4wMpKίv%x;(.rB! tT)SNRg#9+ d/aO}HnEۜ 'DPojۥ7DO`jPCUkQָ}ؒ\#HcK< 8Wbp$!B!jK#~M=OSxrκB4]ώ?7ԪKȘIt IPfԂRg-A޺%(&3PiAS1krQzb0RW8 q1W&wB!r]tөф=$jA.( : 0mWΕ?+шZ=55/V?}P- uq'ղ#[Wa;yEoDv}̭;m/CؓpczwPt޾{.wnv -!BiNaDTw& tcxz,o/65船E jf.*~U JhŅ#b,EH\9 !5UᎵ8rKvfx,:}]B!DMj>ja}!q|7$491pbl)CN=֛[^ 2-S9Ku9-Nn!͈АćzRgcnXDq|xK5&iO 7}weĕᒧYcηyxthg(Ș=ϒ6Pt_5]㉘?csUUt E3t>&m)sָ}[5S}Qs3lLs^ڣs^~Z#3qšX1">Pi9呷Kh6ݡƠiIHgQs3<_orءzcD 呷n ;anӅ]ŵ5nF^?1/-+M#XCʹΕ(vP]0֝K[^U4eV]pרݦjt@u}l"B33Slub2v1ZQkA lܢcyX9'6E" f$jn&y卋Wn #{Ϟ|ܟr%EYj*jnٷ̅t΅)R|!UEI^[_?57e\I՝BDV^z%%9~Z]9{Jy)e,У(ڷ[Q0ilqBY; ϥ0ԩ-10*$Sd0S6Tjs>""")Km [nо=g틠se:k~\xJO?(ݽ+By Y '74y;LÂ4BFy 7~ ZMhۖ-Q= GghmEt4N.ж{8;t#/AߢFSc>^ Ok Bxx8"""0tPx{_k^&R(TxjWDN}Snx Ucp>6u`x>^%?uĿ @u~~a1a@.R.g@'"jĬV+9"ع~L&aaa:mX-5zo3\BDȜ?^ ;wD~~ԦV*͒*&SzLt"";;R(OIIkС ggg*%"1ggK*B1ш{Jv0tPiيQ}€^%CQ"zfѣҍCii,m:X-g h%:Q=$;w"77WjSTׯlwP2VKD z=&rZ2/&WNptVIMƍRy䘉SvOb͢W׺ rss+dmJ<,, 2UzXғarR%3NT-'u?-_ QbCwT<zLӢ:Cɩ]G#חκ%*@c`ꫯ>y{+l @K(1=6RRR}IرclR:@G'za(v;~5;ւ\XZkaע䄲I*/iOYn1z%t%kvAM(,=QmEǏnܻw/F䄁J;v 2V,u@K rAuH\ {XR#;Q Ň0- jpM6Q-jCjjccc)) C VZ"1SS͊ă0$D8!?O*NY'孚ڵ 111ٳgڃ@>dxzzT)Q1S(p7aKϟAxp>Ίd"jf3YÇjJ힞:lRjn :Mvдhfr5BJ Ks mMD5viݻw`0HmZaaaR ֭ t5*f<y [V`װev."jҤ%+111ȐA@nݤ@>`8::X-Qa@ZpvYp;E;W#ـ=^8ik BDD1tPx{{T)ŀNuFPk2|=6C, <(bH2d4KުU+%":ՙ3gHKV6FcRZ"j͕+W+͒Km sR 8p t:O DDtӊ{niv큁vd`@'"jZ8t萴`6vWWW lVˠ[TRR}IرclR*-[i޼Q]a@O*wԀ_ EǏvZٻw/FP)w X1 DDŋVbcc-) CZҿhZ%""90ա<ڵK%?]{ppȇ OOO*%"L&߿_ :r/// 2DZҲeK%"'OJ7vٳR/͒w BƊc@'"T)"33Sjݺu(cDD0UvBi$C[J1`@'"ٌ)>|Vm,֑jJja@'"piݻw`0Hm,y= :ݑҤcbb! Ν;K|t2VKDDwt"#zI]{f.|}}et af.]!uӻe4HaXvWWW x`T)QǀND5f4giĉv}||0tP)7o\jt"fѣG@o>J펎 y.] 5\ DT$iΝ;+) C VZ""ƃ=Ke|.Ν;YdKpȐ!R""ƍn>X2{0ηxßhhAP+(X% k~6'K(rF,٠9%%%طo4K~1l6 C f[lY7t1ka.2^T_crht/f r2_>+N%]GrdLܟ ͆7EǏ={PRR";88R ֭GDDDujp2@Py'ApScYƺgކP5rkh(|:l״{8yYp2VgB$Ȯ6 Tג[I1yYKv$ {7A #XZ C6d:^m4o#0%)!- (p #pp4_v]>TRRsO?{(5zF~IG\GNDD0S=sUst0U#""f4(~u j BPst|O([Rˏ|7h]͡C/)l㨼ZvV?fϞg}SN<^zyvOL VU5 ,qCz%ܼrKe~ok~v~ʿpkAPB\1ּ*ǹhnI€er"##opdJ 2ssU&Uٴsu?-})U<t?WQ{mcж_(ʃ({h:%J<Kn4 ~%@xWk \ 8)r`(Yn\y\BU2%aƴ _c~h@Pk`<k6ʂuiC qʵZS֧/DDDDCޕ"QB01SbB/p<`ؽ;NX|d^D״hkO5gT' y?|bB~bDCӢDDDD2l6؉6<9&q UN-Z]ІtE(>Npybac2A)Gv`@Xj *;/-AG/ ccP8:A4!ZLP7 k QCÀN1 gr''^Eje7a Pr*!4P7 6kY.EvgQ(n]B]!]P3 NB aH7^3*r+tx%jzE@]ADDDt3ЩRJWOx j DU%t"""،._(wDw4t"""]5P6$"""(īrAԨT?-j~s=jZ"uz^Eo;OP5kUFQx4(] j+k=DDD0)bO{:Ո9- S A]J M'DÜ3⢸UX2p2޳>R+<tu_ s*[Lc7}[a3d.AsWGXӑG oSx<Yj#""Om,3a蚞ǀNf-̅~Owh4)@P'ӴhMvu2vu(di 'uCPj:U~ J6iX snYI*o3Pv J9<ж 얆d3UZp_eG- x>:T>M6݌=aJJ;}tZG~Exr/,`-@3.|;m `N|"""DzlVn]'垇!5o\9fAta<Snݶ>Ux@:^r:Ea3^,\4Wߚh(0%'"wq!0g؍o?NYQ+;ً_)7u>Qe8NbH%+ Ahh°o3lӒ9啲}u`3;hՙjQ+ E@M@ ?/& V;7!8KH(n] &my+^󈈈3T-[V'k} IDATH\y]_}(9]p G[#紐AOpP|hLI+CդyQh\d.'9l,@DDDT)t%3Іtmv o '|tZ@+ , @g*R7 Pe:Ϫ_8Q p UI돀(B?ٵaɼ 9ց+=}kKV ڠ]]v#Jrc)\Rc( D 9 th~ǏCVVحhO||. (( 6}~c_["v`nD*l^-XX@׻prd/P8:U[UTjFqr2JJJp%h4h4DdJL8.\MĬY]Oz%""N2Ke8t'^Og/”p>Veȧn8 V}U"8 92)P7 k/k=e꽹jd^FΗ@&pkklaO#&&ZU+ᜈtTюm _.Cnǔꀖ0$DprmVKo3NXE[6͊/A-+Poph z&xO{CŶmOT;o-Ą HDDDgĒbA]oy|: f,/|oLBQf [C4`p _C aH؊>b)9M??0مKOCaJCPzj3/{rnɵzR*oq=`ʔ)0+^7Чw:gJϟ6+"""7fZL4"yT -7UÐ +P!.$8æMWHǚ5kq!22Pq\{=oO+. :Q 6`vNHMN޽{1k,4k 1`G||BJJ 0g!==} MbƌjjDDDt;&QÇqvH6Xom O>ӧ-ZÇ#** QQQHJJ’%KdbرDXXJ GDh. j/]FNj kC}m(_Ϟ=ѳgO{8z(V^(?K.ҥK1c 22C JoDwKNGv]5P %4ۗ)4swѽ{w;8qϞ=_5<==1zhDFF"<<j'mtˠ[H2t;\.]ХK,\O3gl2,[ 9r$Əh4&:ˠB4W/TsI$;vĂ D,X:uB^^V\#F?86n܈RK&""jtЉB۷qIXp!t邂|w5j|||#`ݺu7|) :UM67o?swAݡj*;8q"P\\,wDDD39{iEWt"VZaܹ8r.\{={DQQ~g?>>>?~<~ K&""U/ǀND7-88/2:/bѢEӧF#0a`ܸq.qȻrV,J[fйK#+}ˠZd3]BaΜ93gRSSfDEEaXv-֮]  6 9r$\]].6eCSy 荀j%i֬f͚Yf!==] {ņ ah4s=ĨQ.wDDDz5=xNyU2 :gKe9s&fΜ ]Wƞ={yfl޼j?~#Z-MeOQ4&ӓkA'l "ZexP*!(͈3DTxzz'֭[+V`ĈP*صkf̘MbРAXx1.f4 gpq|R @CaطٮOq1.=7&w~[F=ԧ"mp\ [WVk>O-A4;RꃔʼeIҞgBh'> vCe}G"yT ,Yi25fE`qPGꓽe'"_$>z^|4^{Ə-wwwL4 6mBff&;5 9s&O>/_d"w`<~DЪD8E`NO܎G~G5IҺrGˍih"<~ 9_&C>gf(7'm4_kd6Gcφ׳t:~83Ey:wJAg/h.APz$Nn)N`70_׷FV7K7kQS#ŀND }Q_XjƌݻfBѯ_?|ᇸt%ݱːp;JwoxN]T(ڹ@u]6n:P8:Cs(!J`H0X2*yӐ ka.<.ʷ:ȧ(ZRtQaqZG(n:cWCۮ'mV Anz$d4rW,Cg@(xơz05z\DD z!K xDg%sBɱ xOW2 NHDFFh4b۶m¦Mp9rsEnݤ~[lEPŭHּ,85k= ymSP7Xk;\ŽO|?"ÙXIf4V3 l^P?@*zk*&0y(B3?b{HY6tc~w0;/Ș0t=#iJ&fV/[#3ݙ0kv:̗]!MKh1f3ؾ};qF;v ǎüyйsgDFFbh۶e5(EaػXe5-dO7+>quS(. Mp'@ ?F d7S1|ϮM~}ŇAӢ=Ix%?y 9KA{X stvkU;7 9Kxrynxb2^?T~0'`3"wBx\ E, ](tv=aT~e?p|f} q3`J>fy+V+^]i7QT+xrD 6owF@5gZsrhi4a6իWcÆ HLLDbb"^umV ;wlzGӲ}F ǻW>FpGh;<{sn^Py:8v c U~׬6v=+V_cڐ.Іt)wYH>vQ8ñs_;LIXj{/[ddd_ԩS?o&t6m`޼y8v%JBDD+ddd &&< FѪU+̝;GTw ""`@'"RC/@zz:vڅ3f.\{g=z 88/2:$wDDԈ0UBP ,, /˗M6Err2>AAA3g eQ=`:yE_W NDTM O}_5kK.?D~мys̚5 {eX'"\<[" 6ۜǀNDtA@~"%%9sТE \|| BCC3g">>6>1莢-No߬y DDH-Brr2>_~HOOŋ1h 4m3f]`Z.d,;qS&N9XЉjY={… 8r $$Xd <3bd""GЉPo?+M6ė_~cԩؾ};:1.]to?Nk#;;| ^'@tt4f% Щ2CQzV(RӱcGHLLę3goSNq}'O͛a2.ntjAA!oi,k~6'7؆.cc|g* Kf*rW#piR7Ϲ9KܫDOvꫯɓ8{,.\]"??+W<{8 o=9܊DO{*f\ _#uXd֭[c޼y8vΝ;wyw}7 c?kha@)X9JuKok״웃PkThI|w O(y+[]tghժΝ~ IIIxѫW/z7n|||0aDEEX0SOESp |" Vzh*E Ú]ySϕ.H-9W`N=\[Q,[{JVƒs%g M0 تu7hC^?Pm49jATZl^z ŋ}Aqq1~?>>>?~<~g]2$PQۨa3h:n^#*γ ςFQIiNh" {(> KvCӲǔ2:=m!\}̮FtBM;o:(chC\ٳgcٸ|2֬YիWcBTTq"22<\\\.ŒÁmpO ˚m`< P7ˮU|!aJ (V+H5 bn¡K(9Wd6lR|Jo3}*f2?+Bh9tpH#+x / ==k֬ATT݋uaݺuj6l"##1rH]6Up fB˰G|nYߔ[P8P{W:Zu- bI1<| Iu=#t_}>\DBnwK(te3GV\CnU^7s > G', MpjLt`̙9s&222vZDEE!>>7nƍhcȑl""A٬#NvYT(ča+eU2AS펫9l,l<O_OnaպE;8JO?،\}?Yn&M`عs'ӱtRfa˖-?BT5OOOL2[nEff&V\#F@R!66>,0x`,YrLDtG`@JZj˰G _G E;W:JFOaȵ]]VGQ/vm<튂uC5~5!JP{@Ӽu^{qqqU7e$s)xDZi&dffèQV3fiӦ4h>3]2QŀN* 6}cB:\k~6ҞGQ/(=w%g`7Ҍc_C$ -h*<|J/`RQ|8/X_ң9>(['aHh9|h mv 8۷ DZ('J<mn&# .Av:Np5xtҎڵ!]бn wf IDATW#gիJx<<&κ77omߕk Eξ* /KڵupU!  ((D޽L\\\Cᡇ`-[-[`߾}طofϞ޽{Kւ.^)՚?/Na)՞`@RzPyUQPհ@W_ASm}7Qq]R(-Pʖ,Qd( Cq(*APAPdnأ Ȑ)Pm~Tr-|GAwwokйűs8d̶IIs'/DEz?7 u8J):c7) i}q.[CbDt}lUStt7iaQp(SɊ΁ȴiӨU)))Y…]bf.]˗0a&LϏ;b4_uennn++$&&lf͚5۷}1p@jժdh4RD c !fRQUM Q.Hx\~FQHöm۰euI!ggg?>Z]7o^<)]4ժUcќ={VBD8$DGu^*SYO z@LQ֭˄  gРA(QpNJӦM)T.7oj>p̐!C(S 7o䧟~EҫW/֯_OZWjx gÆ oooN<éT˗/?:BhF "SժU5jgΜѣ|/_۷o/вeK|}}޽;k׮%5V /"ӧOƍriFEժU)S }:B?:Bd;)BPCرc:u#GRrebbb2K.,_+ăt:7n̔)S cΝ׏"EpEƏOZ(Q GUUc !IABdIr?9{,cƌZje. MNXt)ZGNaÆ|w\zݻwӿ+Fhh(| uߟ>={HYB<5 ![ҥ]vɜB\M .\#|.]_M:uHLLl6ꫯMǎYp!qqqZG(ԩSK.q>J,ɵkט|Lpp0Ν~~ח:`4iܸ1z^B񯤠?w:TX1O cٲegV\ʕ+qrr_d2Ѯ];˧ul UVjժ1zh=Jpp0fӧO3m4M7AAAF6m !r)skc@EclWZvUhQG~qK.l6sN֬YÚ5kpppyL&ڷoO-rʕ+SreFɉ'2'1c3fˋ@L&͚5WB$=sou![B۷/}%""e˖a6پ};!!!`0x0R@c\B TPaÆq)f3fG2sLfΜ'۷d2Ѽys-xMByfnܸi޼9o \}bhXV˗/?̙3=Uٳiݺ5^ZBhBΠ !rooozM޽u+V 88-[i&6mD>}hԨ&:ul )S>> .d`zAΝܹsm۶F^~esجĆu \719RЅ9zW^DEEb f36mb֭lݺ}Ұa̲^pac\4| .]ʜyh̟?N6m0LlckJMOAZR5 ]+xzzңGzAtt4Vl6av;ׯ 4h4ұcG-ul (QiB\o>-ZĢEpssUVL&ZjֱZvtx;i7B̒.uGn֭^`~7vŮ]߿?uh4b4)VֱE.TX1>#>#2gڽ{7BV0iwwwc?Q^O:ȱoIAgVZGBh,ٳPTe !tԉKbXXx1& 777ϠA(Q5kdܸq\pA"*\0}e۶m\~SҴiSXb:>>>k׎_# !&]TrssW^aɒ%DFFb6ԩ|8'N:ȥx7Y~=/j EQX~=o& 䥗^bƌ"V+QkC"ժu\ɉmҶm[RSSٸq#f+Wr N8a(W& Hʕ-r&tƍlܸ{ƍc2 xIAωlVu !)nݚ֭[͛1ͬXӧO3rHFI2e0L&Vul oPٲe [l\-h4ҡC *ul!$='d2jZ ^u^u/2/2?#[n%88+VpYƌØ1c(YdfYQֱE.tg.]Ϛ5k&$$m۶m۶{*RֱL z x1.f̂s˫u!`0//2m4mۆlf\pq1n8J((Rڵ-r;ӄvԉ֭[Gpp0֭cΝܹ?zeul!D6Dz^xMٺu+}PB\t:uPxq ޽{QUU"rssd2d,K4nnnٳ>ŋSn]&L p 񔑂.AѤILBXX;v_~)R+WR~}+Ƈ~ݻr4]t!O< 8%JPvmƏŋ԰BMM:xIABHwqUv͇~aaa|w4lؐEcl6ֱE.tgyeNڭ[7ǁO(Y$5j`ر;wNvgN夜.}=%^\tv!X&#j$ܯYdHAB;R3qD._޽{0`ŋL2ƍSH֭[41ܙ&tΜ9DDDvZz聧'>L2TZQFq#y7û<8NrKE,޿ fkcJvk@ĨĬA܆D|fD.DQ֭7|Chh(?& pNJf(\06m.#Z_~!""ӫW/?/(W*UbĈHTk:7FMK~7lD~ӗ-Dy]9f~z4a6"zwx遢:# X9ܞoE.q&qvɟx =_~%ǎӌ5*U˼y LJΝ;|rV!P 2i$NΟn>m\bŊqEƏOڵg۷z$)Zc^3^qo*جcW gU}]=k/7];8/SXoG`|O7ѹwϠH{ZYmn:;dVʖ-ː!C8rΝc̘1T^8.\HW_l6(צSj oې˗/ߵ˗0aգx|4piO6<_~|#rܜ2XTȤPe$>x klq8+KxG~[jF[|4c}d\k~T6fgc Rl6kN=YO [?'+k!ƑPP!C>}`}vBBB ߦYfF(P"zeM:vnZeti(lu |p0s|~8 vQ ޅqk .YSBcL߼y©LgAqŭA[]䁟K7s }o9taqȘc@Ƒ;;#baŊuV6l xwiҤ & |||-!:w?uC?ukmcfWp[1;"%A<t\83WMbC`׮]l6c !D'/5&)D\nu_ƥFSgk[B,IGwt`3;V`KV0iyW, mU5BNaÆ4lؐI&o>Yt)W\aL~ޫ ՛\!N%*W񱏙~:iWΐ|wm'aeΎ(Qj:]:Ww涘!:D6{l!'EQWc„ ߿ٌl&44)S0e|}}СFƍ뵎.x/J)9Ǐ˧"B,o_l xha^$n"6.Aǡp a-=⎢w-15)[bbr(j?lJS]bɎc!(B:uS_5GfYpӦMcڴix{{dI& O¾b-uo'SNA/ $=һBfժUZj3GfӧO3sLfΜ'F7o_n(C b.|} ?XR=BYʕ\2#Gf9y$fb֬Y˗va4y饗prr:  QCvEXX'OQFzju놏mڴaDEEiYIA_зkC!ēSpa}oεkhҤ VkңG|}}iٲ%3g֭[ZGBRг-)|U(B!4R`A{=nyl_7| K/O?aȄ_B<ˤgK%%l jG!|||xٴi̘1^z 7һwo * /?HDDƉOlvS5!"*Po̜9-[زe . iӦܸqCB'@ z6J>;n5#"˟??={dݺuDFF2{lZn``۶mۗEҨQ#&O̵k״,&RгQ wbI2B#_|YH~Wڵk;w>Ϗ 0i$^ud!IA& {֒tp+m`qBRy_gʕX,ϟOPPٳSxq֭˄ |֑l$qkwbBgys,[H-ZhŅOڵ?~</^:14Z4ȫeszjw!}e;SקǿS3oǘlZبOBswwW_W_%11uڵk9pO>zFL&J:vq{pѦqFEZ1xE:xD6EmM]/=~rΒONt*' bO:)jh|EQEY=c {{UY(LLl_!D&WWWF#/bl2^{5áC(]4UVeќ9sFȏ-aJUql 1Ć%~r1+s/QFfK'jXtҵ 1adYϷ (_[YqRe!b원uLU8fH7}ݻw;sʕ+GJ1b'O:rD-o5z񳧅$[T!o7s(^ lVbV>_<$_8'a*n| jj6#sH N$+%.b[Xocd0zXz;u ˧y(!Li߾=lذʕ+9~8ǏgС>>?cRF J,'|4PU}NO\\Y֖@q=دRb5f&o;wmZf|xɿ戚;KpTv"Ge҇$ǹb];PfǣuҮ]O_>ڇWm_&X&#a:<ڽC⏶uы'q{(B,5$B<6NG/؄ׯe{= ,ŋ?~S?  88W3:<8|=#=25WB#_k\뼄)e=\`* %(X$[|C?5.=jr}`6,ĹR}wfRjQܞ=2yπ˯B!FӴiS~]۷/ L4kIm&GsܛA|=ϋ]?퓏}{I9{5= F(N.wZE>> tz*ב\[< ©l !콦_y"r6)YdK'|x7|ל 8Bmt:5',,]vɟ=KiS܆TOżc\H: kTdia0xkk|}%PHh%>t[O%‡6-&gմGe3-9ے3sx`wVW,|_tpjz|$)(" phb݄Bo\[68z,JƅݡP Ү]$ +ֽ︊ĸGW yϖKZtny{|1+ZA SG Cɉܚ53|x- I !*qAQzk$&ajҮ#aTýIY#)8j :{v3wzj詌Y`vm8WǏ!9SO=h"jj2/?,m\c\ /RE}X}Ā˓+F!x%CzU+ֽ9Pܛv$z$6-(LĮG\0(5V+{~#?.U'ϝKFX"QRz{;ك >~$C®5 ߧi̊]kY6 up(B#o[Mۣv,HAkT$Q &v֝7B,4&B<37/_S/ǫ#ƚ3us,&s27=Hܿp*W_VZIlZƋ:=uZ$tijja[ݩtv,HAk-'dT`80. d&{B!'Cs,^])GJ_qkt$w]PE؆5&֨H ޅ3 zϘwTn/F$uJRgT|M{w73ޤi.y [D_t1F͸3[_XNjN!MQ0,F+>_,eN_=Qn&zTbW95b9a4!Bz& -!?bX 0B!x=Sz;Y6 [B̝C(eW!B![oGk5;W|b?3$n 0B!wy* 5*߹'ă=%ǝ={\W{2eł9#S;^.]8`4zݶט<1յD.]nM!t/5 ^=ҤGG$kT$gr\R||/d2fd X'>lr:j=:ʐיU\hvO{bANq\hV)U$88K=uMeˎB!r$BeuD👕rt5-S:@$3)z` : }_'ۃhdIʤE.^czPUO8a%[&)[VEU,JbB!GYSE~ -!c{Y1˄ {1AŹ֯yƙc{@K`@e?9@޽,S L3S.T-טAO z{d>5Ș_Z1B!DNy)]ԩY3;V8b)پ)V8)z)ziW@GZ3!2n\bFvgϘ?|Dm٥#B!x=N[SSŇ>? E3~C +^sE-![| ~5*k̭LQ8b)B!BbKo=0ŭ11H9DՌ"~8by;_Bdi\1]9ugZfAX|}Q_z繎?kk!l.Z!v !恳U#z !"S(4n1D6s,VVϤ\;͢B!4p@B\Wl= Pؽ{=]h(ꛊJP`2YQ|sق~p8S6/*M}򯃶yѹ͎ !kT$WiCRz8:Fw# =:.x١@Al5UkL^WJUm:#[5*RUJ>J%`=Fu~w.qiB!A !BHAB!".B!D"]!BD B!9t!B!r)B!B RЅB!A !BHAB!".B!D"]!BD B!9t!B!r)B!B RЅB!A lłUuͦLع:{|\/m3U=7cL gOP#cS{;c.[4L=c̥V+Q6Uޡ1fpO N=FcZxֻHȎ!BpZnl36:T&@UQ >.ygE ]}ܝ*cL>Z[mvSYUiSԷ50(͘1^*V_!"Ku{nl3: (jզk1 #qhС6{i2Yh!{ m*mIϱט5;EUUkLu5a ~zOjc'!B!ɜc"+,XYp?-SwlI&y[zGyѹ:B!DJػo >~MB!B RЅB!A !BHAB!".B!D"]!BD B!9t!B!rwo!RqǟnhhR$>S*XIDATQPdWVZ);خ)Qi "ZV-BT4 yw̋Z:(TDIxRf??~< 200000000BUm&2ޝ:DfRi~}ؔ|ٻ/D$U˥%ve* ;_{n,ё+p{CdiotsfvK/]S7\kcւaUm YKrpW+W~M_Ƴ/CdJJ><}'Tdk}{L?CjP.}Kru\cߝ6R|S].7KgJѴ3[Y+I{}w_8g>=0'Ds]RTp͋註C+xHHЇD-m%wm\ޕ9H|K]>h̯)ޓi  Z-kYg[Cd3I6v_Yݾy>m"Lox]˒'yja]k61mf:zYT\)`bwȭ_ʤUY{kCa2,tx:t,i-$WKAھBIuxndnt,!Xfb7IL҆$-R,",gׅKMIm,,M'2sccIe tNDZ"\~}L:KgOtY:OgtZmLBe~!W image/svg+xml Action 1 Action 2 Action 3 Application D-Bus Context Overview Action 1 Action 2 Action 3 Global Context Local Context lomiri-action-api-1.1.3/documentation/images/dots.svg000066400000000000000000002370001455542516300226550ustar00rootroot00000000000000 image/svg+xml lomiri-action-api-1.1.3/documentation/images/hud_parameters.jpg000066400000000000000000001270441455542516300246760ustar00rootroot00000000000000JFIFHHC     C   h `@@4x; M H9fB:T3(@ 9rX( "2H`!`!!`!D0 Q %h PC0PQ;ggLɡe)\8UCI U9dBuy:m:0 "sIP3_)t;4]:z5WH` w#;MގN}i2DʞO gW:ZYq8g<^n@:GЗvd{e;WII8u7WsE.΂=|=24)@xMnvy}4q= ipgyI^my:m @3kW<ȓzޏ4P;:Tz''aU]lXku=VCBM1ZeK"4ϢiM^.51饩%EK,zk(cJ<NjELrtɕ*E&-+1iB`(i4A+e KH/":(L( j("ith '+F3'I&TenI#K&\F2hBbMIz(plW*,ᔙ)4ոERO"PH$tGl8 EqDZԅ+)VQY^JKG)%H\VBYN3眎|$HHVM<9T9n.tUAtGdu9}qt&<^TSYj$Z VT*"2vͻ y+&(TR="gեf΢qx^Y24rMDSp&+oYr%eK68Wg'0U1\B%KZZ xnski5ȕj9s>O VF k4ri) EdUJҬYV gwnְ@Td: 9n7#V(I&6 3.&-٤ET]WY^yh+4&ϥ5}OI (g*Y&M$PUc*ZXYgf:B4ȩ>_[ "Udd-:L"4V+:f8ksQDR}@ W FeZf8Uv($XS^pvM;E#g[d>^N.ҡ%Eh'$ +-DutYL,%IlSkTTQ4i#EHT(X5oYa`a"R)Xd\mTՙ)Im Qpjn\m5@kˋhi:\졥vhpV\WMfePneb|%VSRĚgXHJU`Tv1f&:sVBU3,qٕ]eʓF*8k.XܴДZE*%-v^@P#ʏk0λ*=qkq֍YYU\e4U#V.I)ȕݤ!a`:\{KPVJiiaZ% 44ƥ@d3sٛhTx']cKd`f+J7K69Brd]mg]*T~Y9D S'=d3YdvZЕ4Zׁ eKRQ>}xO ~h纬kY]`5"2$IJh8JY$9ZS:PAb?3cIKXM%pM0L[0ճ [*ƳNNHTXb~iΤuIh+XksYrZ˔2Vaק Yx ZKSh&:z\1c~l%!Y03.j9)$ HTK;/[sPa;q'}1-FE֖hf)J榈vC$`fgxKGWϦZs!7ͬKQ)X Dv0;avXg9ןJ$i&SD5ءW"8+ʍ+hPԚL]<$$E@3.Pd*Jf`q7.Zf`0&m/gIE8QJ T1S(j=g2Y@ 5YRKC%BQC8zƋJFUe0,+ВDJ$d^=#+PhM,pT 1FR3XTZHAU*wʈ#j$I2t*44)`-ZAXtH=!R| 90ʐH.73jδ84$gI6;;r:q;sǤsa=w$$;p@ C42kߤv8^owTc 1 CCw(3L0 @1 C C@@3!1 A"20354B#$%&6P@}n_[r[/˗rIx(+Dž20+M)8ni-KJ_ς_bk V7isq~\҃N.Iݞ >tSq9qrJVѻ9sD'4Nh9sD'4Nh9sD'4NX9sD',Nh9sD'4Nh9sDafl6 Ì؍l6lFb6 b6l6# lFaƍl6 lflFlfr8lFlg9r6H9r63G9R8q3gC3g CPpT8&pT勡v"z$|i} ^bub/-0v'*aH]#EW,]nIgz0aq8 7Ϧ .I:_AޜݞB8k8˳TS _Y.+32 Sb#9nB*䗤pQYMff 'Sg%\U15=-R' W ^7zS!oOKNeU˱:}7;.3ӊDiO.ɽ=:[7cȽc3UCloa )ЩLZ˳ qNu6'GcUviR.MʟZ4X v#.^up01Pn_ⲹKyXmlt8}W,؜M\]yf09;*U}YWW9קJpvmb12Q3\^jG՗xuc-nV;7;7qt/ Xqvl->o޴yOKX>x;/K螗o<~ h_Dy/έ\/_\svQ-~7I^"q-Ex--;[G(״O GwDJ%5lFZ7KD @FLdnG}舷}ivI6ГKG<-߲Fu)Ζܹq =2>/Xɑ9g0e8,OjxfCNY x5r6GEŋKò<&ӻ[w_9w09:tKRU(f3JtARg9+?hjarRaxqx6dK{YD_։Xmn˽菗>mim6]E$ċ vv#X~n.X]hF]VqE2Y.~;fXl>+5dtCq+ ++YŢ#b!!؍HYQPO\ex{D~l=<\xs_硇"SՅ\FQTBJ~C,_U/lG݋OLsw<z+/֧9,­9ajn,f'oV"ZH4-oдHHDE% >2)BH] ͬ}Yb"g},\NظtO΋]Uw*R\ݸ}G[["kb&^dZyʒTJNdr?[b#모sU}U3T1ys>T*Bb*G4GV79P(ѷ*g,Nh9"G$Ne~XNDr# 'SvmV+#inȊwucC6H^nN>;,(S4F6QJ__m[lIMi<:w%(t~Gw^[%m:/r&덨|]t$- 2nNĢЇej=rvإ{IOs6_ͤU$VFa#CʶMKcEWإf|-?6Cj^RIEIE^F%},(\-}~M]^YO05py64ҥ4r:lƿ:9?d$"bwfo_D켋Q<O:5شb;2֮]J{*LM,eʭ _RNy 6 S=X_U;.Ano+M .cBͩ ݍq8sbmj&(Xiaq=2dv_pՎEت$i6"Giq! FGD#ʭѴ۴˲1T%~^}>)8QCeچՋoj-i}K,[K qz:lȸ6DaHM~PH:z?(sy}H` T%wԡB6XaI)]'Fؐ۽ ò}]xt Ԟ.s㥍BwV^win%2L8v8Z\&n7#Ĉ7֋.ޏ}9݉vqQmVuYm6MzC ordz>?^G|,TĬ5ur␴p1=gRN[YPsOrܥt*CxklUzblZ1csG"d]G!b'U 9ʎdr#\G29ʎTr>k5dIDr{_m7Nic{,X&ToF]tr#RLn:.ѹ拢܍܍RC7"n7tt]ELJdb^ؙsg ȹss73s73qrٹf9ShC{71Is73s.ˋV%n~GObͷ6z--Z+;-&UT?f:ȏEbŵx]jޟ>FSyM<<6&Yn3 $/eZ8&O1l+$6#m_k{~^e<NJר?UC>α8C†iV_  ['2k3mK{ß ww׿geKTV3OD/^5eK0jo\8/b6< ;K{~=Q?DE~:_[䨿.-f!S= ~uI{~><'*l%lU9nz)ҝ?X4`}z}gIV:<1s#={c 9aոb5cDK}n>5z5좿4_+ \ZD[_>ߍm_MӒ;\Ԕoz7܍ލR*g4GY9PU6n9`r&q7䉾&F-A֛Yh1UT9fr3d+M?L3g-B5gwZiT9FCG43li9&:9&r3g,I9foHs-m^5},->_虸LLL>ǢG Nѩ z/bB܄!>Fsyq=~O#2>Yf]Ox< => -mbcfqnbd>,Ahn>!^bߋ/vv^< GCk6k,Z6cYfZDTͯN3cfYYf,v-!EY,HrTz_$gV l 6<Qz~ 1hFm>.r/e˛ܾGz6s|~PŤuB|&|{WZD*(.8}͎>qR9NS9c9NS9NS9Nc9NS9c9S9RSݭJ_4iQ=Q3L 9ئߺ<ŵ?%R[7&[E֋݋[f[Uqa4Ks3g!EeϭϬ}e(Y@P>}e([@qK:!0 1@PQSAq"24`aBpC?٢[D?v./\+ X O)hp$䥩ZLL)%11&$v’KNi@(Yq(PAAP @&L@0 @( 4lPZM1L S m -@1% 9 aYh) jH;SxP$J $̛?-@7B0[B N*uqj~V4dT.Eρ.'>\N|Qq9>s}EρtQ61$HR>h4,0mh8|f%%(}Yѣ8j8_*fh _e4?i&5hЉK:Ț3?g ケ:_M&~T/.TDFϒdj<FpBd:"Ͷ<%2M;tRΏ縥i"G[h R!d)}o\VFt}SYt邮Oa{2>qd} Ǚ3#/wfG^<̏ya{2>qd} ǙoFGPj=6!0 @1PR4Aq`ap"$Bb?/L}ɓ&L2dɓ&L2dɓ&L2dɓ&L2dɓ&L2dɓ&O::q!ć:88::$1avW\Q0]lRUj/A)ZO>yɩ.q!Z`ۥ\6*&zM,7R}/Iv/Yq-VaaSaX5Eܠ&-z=tt4uIqzס%mM`ژa[^EttFMU:+kj88lzL0U8b`0Nߝ+,#REK43H43H43H43H43H43H?i=+VV?_Ekv̳Ĉ3Jio8-34՟ qfեD}QO=c?_Ew7m~b^]ZK>^_-"Ur\' axx,YE⫫>SOV bZݎbtRG/e] +vx2_<|Wg/e] +vx }>ͿvH1!2 Q"0Aa3@qr4BPR#bs$tCSc?8#vKQ ]ôGWb;6z=>"l/ޗQʎTrG*9QʎTrG*9QʎTrG*9QʎTrG*9QʎTrG*9QʎTruiZJҴ+IZV+IZJtbd;eqVVaTDŽ6S6GD";"O Pʼlv}V&E3Xc3Ee79%4 {qFDWN{flT_lP'OvXF+eDP'L]oc ܈Ԧ-g;MhQvF(?„ ;qĬ,l7Y3)`1&%xX`a i|WQ ~&;L# Ɯ l8l1r MFib1pO6&Bk]):E,KMsCc6'Ō+.wz{ AOwtTKLfe/m?N @/fɸjZN'ȽmvNaxNZ&e0^&Cۦyk%MYڳ_w5okac@vXV?{U38e0\'GĠ?vrvd{AGi;> -(ٗC`'p(iewZaH`F`V{f K4`a}BBԴ۞% 4KWMo.ix >im ,x}8(Pk.]7ߑ%ӲXZ .lnҚ!BN}ߏtbe28Ͼ|[q>̓tWǯgV wJߚ? z-X@ÈȂvE3o6Ŕ1KďUƎP.ńК㹰EZvCXqqAՊT/h'F,xg-)JaD\O6ڋ)~+ih%b qViβG0K3-+?䶶xjHtX1"+Ќrl?:5F`aȆL8NIvnq*%D2C48f Rl$豟{ރjq(׀7ңh$^K{Wy쪫_aUF ^շաZ5ho%Cy- Z7աCV 5hjKCy/VKCy,ա 5ho%Cy- Z7աCVZK@5hog~Wt 7+C%1DZ}gƷkT`=]'  >5 EpuПhdi b]'gU-ZՔ!۟жqnbDtKC-/@?:DC}Yfۇq㔥?0ۏk&BsCik؂HAnBtJi){}cm ,]ճ…gadƸe`8yU1"趻T-;beS6M.l2nV(FGt.2Y9[M`pOOf¶! !D1ÆsS"B5(#&+5pXWϰ) [}[uŵ9511Hk8ѭ0lPg,}wM 5]b³">̱eL՚e[ld|M3pQޏ)˫էE=xmkX|^]!eZbBl3g;a[SzU)h}Nx/ \U%^wvZlѥq6(a„aO"7fQYAe{ i'^h! ll_[AMñ٠zhw\Tk3A٢88Í'ATkE@f֘{[mO+NIHL^Mx_bx,ESrs=̯T ޳Y Y 5c>Ss6 r'Yy55ZZ>-LEE;iSާa;MK#~ܢwS7O3%C`-~Kv&m=Y4ئ@8UNY.=o~ L&+60Y Ne[LMPvS`]ܺUY{ o~uWnջ/b7a[2{F-{!=.,{hBٿĵz||z|LYzoO27Ue}nUUUܪվUUUUUUUUVef? %Wk쿷x}+$r*!H J:@Y_U`gs>-7GmmNRg`xkmNcKFyf8JËgǼjGZƊ!+":--klpqp> +UC(Dig":eDVƈ~ i Ylw CsFftD}gmK63 X;drMh95l{-'q*9!Zg1JS2Z=bLC { +3|aO jⳃq_Fj;W86xxgrjx4om7. fQ px\FY<3SN0CGȄ>[@_IL K - 95l\#܄0 'b-n I2N÷7_شpCvwDr3-kg#lBB<*Ȫ*!s~****]EEEEEEETTTTTTQR %U T*QT*PBC9AT*PkPZ5-Aj֡j֡j֡j֡j PsZ5sZ5sZ5sU UUkw5ַsZkw5ַsZjw5ַsZkw5֣kw5ַsZkw5ַsZkw5ַsZkw5Zkw5֣j<֧sZ5Zkw5֧sZ5Z5Sf,Iugi] Iy:U^FGl/OląJ"Ejcbh}+sk_ZRe`Cl/, &N9Gbw!Ea3heNU.T䨩EEEKM]EN/eeޤ,_F}%h|aFg0o*9?-_ϴٛ|Ż_ۆ0䟉Z*)/JZw37KkڶN a4F&Dpn,Oh=^oa3' 蠜bØH#)mo/[ E{EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEM }UTg!wNZ?kS-NZ9jrkS,@m߹N.{hp Qb„ B' }V{C}sѽXCsÀczyE6df ~ ۵t6 n6v9`)Ya{݅fDY;r/y E:M;Q}f&lP8~1 1pƇx%gC =@:sDH* Æ~>ˆ_Z08n$iP{m|§ST|>jgDɧ9Zkֳs9Zk3s9Zkֳk9Zkg O)!1AQaq 0@?!iTMV_E/QEc/eMq1yMd;:dQpQET&$/`E~9IОI$K<&mY s-ȷ"8v0[;Mf TAMwF|?w~UϭUwJx0Nfs.`hLC.~Kވ"f!hxwݬ('Pݖī2D/ft<6V9QhҘx-C9t y>%d^ZťfD 5 LdL] %v%'?iF]_J; >eZpD">yl*IgSX3:w{$ϞsXyf;+4X ECǵ=5ԀC\?t9vkHؒKx"PYx7ŵ(䘂:G4@lsy-taa6"?n|,W>z@"C/Iю 9gH\| 5> ŭN6N*?'!'SXL 5+)m)·Tȃbm=Pj5).t8#73K,Y2wGwzNuys~r'_U!uC~XmHJEMԜdqBgn'RYtt%$kfaQշ"V%G4wpfST'螫yk}O}RΛ,G7]Ɯuh߱k~"E崛;B(O`,ש@uF Yؼ$ƈ[7i- J}df<( nķk'ssz"P/i bm;2&! Q=!Ba O>_5з>Fޢ 9}6Vcq9:4OM*YQo-JN ߹[wȟVo]_2\yD,ZJ%Qdr!2k~PcioFe0i1п%,ycEI1|5tydS+w :dscn]$XW-ق } (2' ɟ,-IvQM Ɇؚtq=ӽ*ur%ݒ!9|sFI֒Cuy3Aq"Dp$_ظlB78Y5`oN"of"|UQqEZW7)X>DC*Wb*,a-gZ%1H:b:ZIf0]rnzgɖv?b_*$zx_;qĽ|| WFU(yg~_>K|4CI\֐NQVX&Mwt mѝo,KdT"¯glT q_O)#CUIQԓwHA &Ԥ6ْ8ضe+]K`8hע{&3EIɁ>oM]{?"= (lo#lqTmTb^Nm,lhY}p[Q砓0Sy IE^Ã}NqHjvZ֖لL !-f3{<Ѐ)߁,ɵ_&ɳZLֲd\>o6֨:hDHⱭ:NXOG@"g=J.Z1h#D |*5Œ Z_-*"A%4^Ir! Ȱs`u;PxfLԖHФ\k Iv9"`'{:ޏܙ\ f"p~sNOe=wf}%hZ`NwkH3U.Eb Ԇ,=pbp+leXDci$ӃztS< mNҌ nᳰǹfp Q+ =СإC#5fFNEjGX[)Ɯ2oQk'ͬ~Gq atD8 :8I؅㱞Hm IMuh :x+&Dz?b8c wR Yء,^BN7UFկVZR6$&g: ۺHQdYؖD bh,J򎶏FVX71y#ZGΚqUbnSJW(ZUa)3D*!f0UX̦t&$æoO۩ؓN匋 GتAO9U8kxjEQ?9E4(.C0\6$MXe'u~"vOމ:o=M.}V_h7~/CX<>}R$3~/yCo7 Zt4y:7σKi&-4E2탩ɓǠ5*MJ)%-0( $J4,7/(!dc*WCG^6E 6Ohk'Չ^MbQ>si1EM+g4׍pW,Qem#s :?"3)%Wsco%Pd&3zBY>X4R),-5Ek5^&I"8!'J[No=y!#?WD9_\ lMt6MoLs^ S%u<9VG/%Ĭ%Ooa]6s_qt^%KgW: ܝ4~':wO5/,}'?}dQrdX- Մ4'CNO%"Y}#*]x>3sJƂ ]qv[w'zz%xK _  Jù9-k; v]S}MiYDNo%aNYv+p5{0S"Ru2\% /td65:2Eݬv"[YzK&X,EMeF^F`o%4>cm{j2\)ZPOZMd`թE5~W<2_ax{@gS:VhMkZu hRu:)o΅7o$aReBTٶı"ɓn,a?ȐnAiLE~LI-׸#Hnr41gdiٚQiH82+[̪D)+[jsX:Ԇu7GHMkqMe$5<ҙQ0u Vg\$S,+y/, Bx).v" @!G \OXtLFR,"^2g :|f[ neGt@?pg(N)DdVLCn 52렝CL{ v X ңMT($WNn f()!*\[Ǎ6D}<gZBtUe+xp']vt"HWЕhN3-bl_Hq* xDT(J# Ӵqi܎bfW9y3TFY2Bl"YhoX!XVrG3Y˥\3[MI{&Ax#!05&srn')']hC'{r!֚*p"f Gpܸ:5>Óz45m &2]7NLU+X~Mre: dbb Hz DsDg'^ B:gY9J\!cdpKG)D,[x]īt'/ .Fl,1"k!'#C>FUS,lnAdO hɖ4|GC!{d),3d*iFބ1葀BC}/j8ǡ1z#wHIO OcdGI&>;L#"1drqN82AScѫacb賰cHLx3G9b'Ӑ',΋8Hvd(6)D"cCiD菉|B2M-WvؗKOB^J>+:"\ Or٨]ev@%13v'D(NZ|IGTGUdnWvy zW(O"k }K-{{!9tEN> |O?*[~ 1vI o\|tD|!OCn>EEvGx>xCS=+ X_-o}_}x>u#3YoG!ZEE `Z+P#XE (^H݉) O.LC/X'{a5b1Qg#!F6zly8=2yMLY&D`+bѪM`=ÒQSD1;ȩ}= ycTelL5v*Ceb@TInYQ;v;c]kG,SOyH]Y(b%l%=e#ݾ,g"&LFfO%t'T)D= da!։4X>{%.9cNiI (<{dmM``CEKi鸩Se\thSZ=F%i71,5 ֝ygUS0|1((qĐkҔ΂0zФ-6>>C΍A]J+љ/pe=f-24I M~ _7F_F<+#`pQ*RKZT! D[œ+!,4y,S01tb_?g,}Vu'CadCxmHB=I-yl1!!,^"1 rlwDWBdT/+)|≑p%<09*Av9h%i=:5 F(QPdӂbє  CAՋQT sJh:Uvs;3Ŗ#ѴPG$`~ƆH36-ZHϖ,FZh{ ,rV=Ñݞ4v QJ_F!2`$(p#T"% ժX̴޺2%5TX -3D?F2Ew]/ m=C" - d}Ēo2?%|5륑,#S;E"AԹ'+BfY+h蝿"]p0OG,M'g44y'UjB_!Oxr5M$x8r2#Aƿ$ 5VY<TBrh('Y M8UE|/ f7;&cN,G[$U g {iԈOx@uɂ3$WD~@EF /oquK_`W w mf CNI_Z+F^,N -1rd,^/$v@4Zh&a9Lʬ/LDbOCIJ,AwϡdO%+8g\Fw(jx`ע^ɱ3)%B': j_ jrT`C)Y|E1dTd;sɜ!F&LICؠՂ"djB"5ML= d\`lXLjm1 L۳PfCX$eȴ>mZBP{y36<`駨7Ft-yK :24Lkbt40Itw2bg ]ul Wnɓ4rk3ȓV-ãaхaLeF446( c jzp#L;LU(]C6Tɦ3\_6 h.# V6F95g*X&~2X. {B n%Wcl Cv7`Sf$\)9^kIϠؼߣllA,l䰭(\uۃeCQ(eue E(xTĦ1*u=>") 8th<؛~&,20x37NĬħ'e~[OE 8砛S D_$OQ pd1.4$M¦ xߡ^H|Y1:U9 bAFiqe'qu4'ܴ`foX}< ,a-'^M~JL5:ٯ0)ǘt o 2 0>O=D:?K9z7LR>׃,s^Ūdh“AQP޸}gO}sj} Q}*?* &$W+}>5iތF9nWG^ʸ߱6>O`_Q?BaPS+w+Y^i ='WVAjrax'U,Jz-OMW=S迷0K$%_/G~>$!p\ a;QD^-}r\VFICݱ "1ȝlBu&|%H^.2S#Mj5/_z7VvM615+]'WKb!-.T>>cڱ?g~~M~GS ?ŸOS)i+wlZ  @ @A  @ A  @ @r H!$I$I&II&i4 A @;_5,q7DBco~S≯#m6Lw?{좷d;(h2ptŕHyǫK9XC"mtOWF+1uHo b7.;kkn/rw:Ő#Jd72Z`C<`.> !@ ynme- DDi/z*y&"󻪭]OX30'WkvWJR%9i q}$̧r/cD@ĪD7a$IZYB!@rth]a)$ "~qWnEI$Bv=MP,+߅>f{{yoˇ/~%\ nPM}k8DnHMJ%vpTnz ]\nֵWWc!æ mP TָZ}ґV$Z,ؿP{aI7}RMiׇ(AQ,"I$G?$^1 85=_y¦aI)t i$qL֕ f~y}Æ(9Wb2sHkA&;m08[ cۭ4cEKjF׾N/wѴ֫B]KUf:뷟^vvD:TNNmE_\75W7Ƒ hl~)~EbqAi$<x kl xHMc$Mnt)$j#;BM01I\?;PiT)T0Ls!"J$AO%=?M@3@ Y&ˡpb}9D[m)pnxL H4S3I $,$MI"jv5 0P!Υ@<dfJ2e0I Kds@IA 4A@ \w6u"k,I4r$&-C$@A$%IE$ $H hdS$I Q 2#*H $AI$IH E$\WIH $H4HZ$$I $dI$B A I$ }$ I  A)! 10@AQaP`q?zxKoygygygygygygygygygygyguE)JTTUsJTTTTTT\R)s' ^,/ )p7 ͋+%o DŤc=A!bV>0vhc 1>Ų X[cz|,><>/Ҽ\\^LlE)aGXE7Jy^4)31 .4ڡ׫ !׌! L'"._^ ˚\N0xXY|&/p\X2.(x(Qq&'%!.V-.'2|V'CXb0_ !QN+ф1KQr||bߤs0L-)8RXb6!qX\`.%HL/d&&'b$31L(CCD!C0ZR gq؇!5tIn cc\4%: BzcQ`CAa&c_X$1!!}hDNƾж&k^ ѡi2N1""&(NB^ȑ(7eⷄ'?#h" 6ˆŢ$L\F]ܡ Ce.Q= Re"#BE ؞kABdcycTB^#4A(&7D4Bm l؅~M| CaQLXE#7I i#87M(JX(LBbjlQCEMhHnAhSC $_CtXH1&(9ž HKs CTTMؘH R4N_B2M eee(e"x)NİxMNi&58 5F#& &hxe/bn$7 "þxRb)HeDB!bTkLq! ƙ00xdZ%6FFFV Hl4bаؘ8Npn Q3DF3FAXBxEIff!DDDDB  LPtheEyd ^t| 4 ,$YF,&Qzp}0m,5_]?wD!戢 ŬLN /)EB .M#|6T66-Bk4\n^;)JRl'F,h0 Š(Mqb$6,^tZk./┅DBO/0bзRSӜ1.V/gKD.~K證p/5~( Y._ e)K&^)xqK iK e!K'Sܱr^ \ߧ9/=A>ǿJOg7_z%*tj]iw _/|o_-P7WA|Vnu\wm@1&:9h_5W7kVxS]G,H+7L'?K{%v*̲BA`Uj6JRE`|G -\?]KUe 9Hz~:/7q3ؽ9Apu9Y0Mm2{JH|Ev< l6Jp*MybJ[^X Ch=`!i;7+/k{_?hs.L?+_y̏ڇ?iߴG~ >b?_K?3?_L?//1~#W?ino^~/~ӯ4O>'wiWUGU/VuӉo/opWQS4zN3ӯI7 cgf=KO%?X`+/W_K^asX%\z> UgfS&x"X"KbaW+ Ji f($=!A{ZU9I]Tj\],i/ zƛִRmg ErDA#hPH&Q ݘ觑\˴jԺ{Ri:%TGVOK>>m#_p0sm]ԵY 0쉻C1)iFE@,2]~8?fkORH-jܹc +PDJyUvb~*m;|JxUm״ ~Ԇv\*` KT-jL@ XgQѩJ]/+=ƹq9sXģwULxYt0r^#]+KFU`m2  3$<8R nj 3Y1Tt 57m4P ]Klu0uר-C*c8<y`[ /N%"i] ֪p]ވ2eTY!k}\(XRji}c}5h`24s7PfEG/>-AZA ?Q٦ƝB@ З,'pMp͉H|Af섾 f _UP󗿀 a`+KUJwp)y #ky":"1ix0pdct{ZY`bBc+UDeРUte.v*5񖡧P9.3\64vQiJ]j3balp|Aً⥉}EN(]g|~=3(zk,S:;ܵr<64_3B%UܭGi`bow*d}V\ZyaXŅh-";]1A19*V T;vbU .i V€wa"ӣ1ɖ Y^ ZMjjEKٜ}54hK"*+esoM`(4Qce:X;t!E bGR03j UQDԪC@c H 0FVEyPat CJ P`_Jv3[m [MGz@w:%Uc~&xcT/)iWQH&'eVjEObRek_OPKƟXUzE |0Q,+kvO&uM~NοPVVOs}3cd0V/pOXtT迬t, kUz;YvrCʒ!|yaueFTP|F+ b(11O_3xʹoCs~bnהK%خ%ؽT@Vq FUo[cUf[ x̺]cC@S["򷺖[Er, t(L @ZpN > 1}9b q!cCh 5X!9 AD(;E",Xå$T qQdsӎX 8" ݜxEW^bMd Z1s_si,ƭXAqB~`_F Ym|L۫iEQ\3(SSV{09s$KbwE!,@DՙVUPQh,y "P4@YZ-A$2j0uv"Z0bD e~02QP*ܼA~hJUƃ@R UV `&CAN!f׬ѪV2׎)qL!ҙ7=GZ@YLnSEna ,+j+emjkD9$Q}㨚+Fg #F qE EֱiP{Uaw  Qt~ UQwfRc hŤ$DfpFc5MH.r(]xLMM,Fl2Āl(+(mLJܮ &u ZQs!VL@!A]l3fکJnF huZ fk43hAy-^ԦpeU5dWkRlF& C58r,}8j9f$⶙5,PV_1 3`(L*w5w%JK1iYpr݇4{3|щSfR5Nk/ Tl ' V(Zf."0U+60zŤEȣ̴pwr蚰(Wү2SXɸfM3,ZkQ xz/EfRn4(WLY7Rg!jio|@|f_Yxp=0q.Iu<:5}͞cxb)K]FԎR#e6e]"bP-~X*>6- #h pU HhJQ GQB8аw')D [hѠbe*8=swHJaS05C6Yb/ >>l6_mJV(")J`vTxol-CAE|;t@&kZ feWR˞d(NfHLj/I &Y8gq6WY)ZOU[s';nPXlV+U-`=*t(@<UjyP^ eQlJ>50i;Nvc3¹Q@OR#Ff\#GC-B%"V5,֨)AFiRo7, 8oEED)eۿ$vWy3ЀږEI@X8S1P2tŰ@i^hƕJD2zD!Z!0Zt]`]+`͟=kZE_D԰ ZW(җt¹\=FˏPƞjThFB]&a(:9H1p}!(rؕvԣ^FqP V[*7sX#jS0B,wpW5E-G7>[ܱU*eD`(@oh´{6l]ߴ~r@9Mc/+ :s Z4yW1{6Ush#>Y, p|ʄDJE瘃bH#/o}#(x?d SQ'1U\K[קmC9YhaʦPF2ZL(*=r״ P- vD0vu O`Ck) QDTavԼ Zxnb'7 B(__OQve`l D]:bأAi3IwU;}*4Ő溄-qP?6AsR-ܨVkV/rX$ jZ 45[=8{ @b(h H6ܷjI,A`,hkc U{qVH@+a@Q٘:IԆ*0#BW=`FA$J af K&~2/QLm$os曚/s ga1:Z;,UT\3(Uŧ~Н.PAZL6ᄰJ>iI]I%* ABJGb$h.i rҡdQ/v LUp9oDʣBA2iv+.x}% fCZKC(BkW)1P]uc%Lvc237WHU@ۣ+X1Ө)/'fEd1 -(Ŋ+'#ME7VRWa&:j!A# .]XC: F2ЁA0D"yc0m].Vb\u3Y$Oyb;M"+o",!pj.8e*ƢpW3Ims9 .#2[rOTeZFLh`>I{Ah ( zo%(ΓY"LS^:#vPMt@0Ф0e$]C"TtJ#pxeA{L +05`k)AЇktdSU<4!.!@ɳB =mASPlp(n*薪u;w X zBme]6 MBlYd_MJWX1 qUSl6y8*f(̂[Ph QH¢42EXWͩ *ŬSe&c`c1YUypfe Y(7ӹeynzuYS=tfUg` "[h1e--}OxQJk3kVKWm2%2sV%&Zl4}'QeB|Rfld2K-s X.^)|ы-`I?x ʝTSvf) A1a QPJlb[LrD]0¥㈑qtˠ{57o, y bJ,60E]+Ex%[BZ-[\KŦbV(raEƘ REʶ=iZ#ez.65_HC ˏIW1L ^zB#+P4 ԸwUo!w}@!jFVBU[xL sx^bخn.oklλ#\Ũ h2P (@p'A\<XmtqM#J:nKnn`D<$R!3\̞3 _Ny(V8dYC8U?7$AҀq[2hY0rƬEtL| ܱj%ys"f !9CXoltM1,7)z{_b|An{DgXk0Ә{?,ߘ*u*5ͣw4nmFn;%R-aL5pz|UžljhܰP3b!B9j\JKBwOD\{K@@94 z,pMAp[rKù3ZVۚ\DJ e^~غ50qO<͒Op]gRMd}Acj% r̶9jWsb%.qNթ8>" XYM"R^b+xT 1( . A<$2[%hx54kPX( @xe?13j8}d 1w-2=S!w9eU߯Ṟ_!;-%EsB3ZLa&ȅavqGc_IHsb}% {b_|S0yE**>yn,׻NiUlT([]bdyfXS`A=fRI&'wOL?bz@8_1MJc>`Ia^`-1 ]za-ef1Q׈IDa&Z)bQP89׼AhiXQZJ;΢AEǘse;\B գN<5p <{R 0rCRL>aB6JVIB:* Qjp09 ^s/$+X 2X{^}U?V<eTEGp@ˬLp-TBߩ\;* b+&헅M\rL'duwĦJt58ttN#Ά,Q!UU*dPO#qM؀)i8rܥ۝9SZw *[Ѻ0VPiq@Lg g8Z9eYk@NoDȭA@(Q`VB`QEu?[5FØ1ʼ{ #C"euW{ky̻ #`)mR!J[}VǨ)2+(  0 ճ-btJ EKU^g rIJ)p4`)3h1 @5ź4ָ4ea1cq6/|!C\u"V k4aoW[{g,303PSIYhPz).\KKyhZpc8rǃX^jen f~C1[w2t3bm͏$ Dzp:Rso'5ETķ^\1*Xn%\9<eܿs "1m ˮ.VNB9#UqzC B:1P'kŀ}D憵7"yQKEY!vJS{ke%7l3Whm`fp%s\32ޭ0AbzR p XM} Q *W~boYB5",*Yxȁ/ !*l)+n3( ο0JCqg83}atO5ύX.-_NKiYC^>}壯 r T? %[\WW0R_X0E̓Aj?o`zO%},k1^jŅU ǔf^2ʍ6ʛm^"mW °E噖*5 ,u]sK m"U1TY+"`3#6)5wCk2p_To7zIRsj6fbׂYXՅ$%tKG~abϤ۹B^HLcK RsE%#t JT햵c 5bU;l*Y台 "myգVUt<-R3yU%:pALY(ኜK~""4Bn%^T"p)a(>f"mCb5Wy#"js2BfWt3hR=in7U[:l jېkzL hİ\L"r`,%k)\eAkq^428sS65q9nnL_2Vkr*g.瘴݄kuAx-SbZCC~G` 8bGZZN#Q%`\ Enm D/L-c!KW vJЗut:yp 8l*؏f޲Fֲ59JEZwg9[Ĵ1,@@6ncntue87~[im0"²'-ߤhP۸oۄ!q5&)AK6YBjei49k>9AU,w7t&cb+sU.pEq2lGgrrK˼F%%3X czPa5".Q vjX"2! Ti*GbAi7&^`wzɄ5I서cQ dfLo&]lciKpEZ(5/$/Pas@Q|$Ƃb=<=5oc3ҭ'??sqo;ofLFpb8QZَGa"4(*ܨ:XV-bЎyI~QV#u$(!{091S_0J LX&aZ#1%}ZD0(kp6.A@4&,}}HSZ)<Ċ]\J:ʏ^MKD0?OyJu%Fi,O1rnr?1xB% ZW>Pښ9J81A"޸%De*6Ẃhڕ U2#Y^<5MPTsqm eTaKy1(VXov!Tsk28e-rEN=QiyyOX3yA غEr ˫="V"vRڑ]̣]UnU>JPQL PBD!fn%Ejk%0`*b.w_ˬm#Mo xpFpAn׉ԯ?BņBY)UIZlfRεy~2EQjT)sp?в{,DǨ NϔH "8 C!ͻf3Ɍ >n  $ԫ7}c(K]Ì5aPAg@^Cc4UXVq)AX.ٲ:_9(Ĵʭ*էEw;gA®a͑EsΦ!_ 9rҭl{D@g.Rz^ܡaQlez/զ&SjŻ XS/Վ[|@zm[x [\m2Իw /ciU)N?3*U2Qw:oW26ԩtkjBY)(|} Ӓ0op4\HᆍqMO/: 㘱sS [_OEAٚ8p͡1~+ _L5# V/Zy+X7"+`5nYpuz| ,|vVBۭW ,<8= Y-vZb Ɠ&t[*eaL {K3BO1,عN.FX[ߎXo@VP5h!J@$C2~!UN>'~&'fo-XoGLA]3oy`;ƶKƚC4n,k[lg?d~5gQS<) )3'mPZŲ ~x W)]TaC /Gfνl(#b6ɳE9JG(sk5Yv+;W_Y@[<-'ƥp C@&P +x+AE)aw$-qw fh#д\x(iZ`H(fEY%2xRcp6@0#sXW,W;D΃Du#E#,%zϘuWzF<- 'rvF`=L+Mg:1QQqι{A_F 0Uw<ħI|)ItgPyة] ֮*/zBi^#(2\<#DAvV AJIBw֪+AnMcF=UMpnK )K`FLE}tceԘl 5Mr~b qY_Q89W*z!{YhP?Ks[!σ1MBUY~`(: AO)u] *!-wYHclg4ar?ƗK˷(b8?ڃyG3;`^ĵDPs*]j9un-8hKgp!U\1\Y\ºZE$R!%)e_i'o<Ow+@ {t鋡GF85Mœ娖f*c^Ĭʦu] Ky5sPO0뎙q8JjW /0WMkɷL"Ʃcys+Kxlomiri-action-api-1.1.3/documentation/images/hud_screenshot.jpg000066400000000000000000001467021455542516300247120ustar00rootroot00000000000000JFIFHHC     C   h 0`  $Ec@D\oawffeu$Վ""* (̠X`$ $ (P1`!F``b T@ 1(cANt t(ggLBZb(*aЮtna^e/MӡӠ`8C 4Uy .wF&$%:vUy0V͌ i-8+=*E8`yu8Uy![85j ke$h˞pYYđFjd]:.hP*3f;"UDo2mKWi2iZGJU2(ut2M!ypSkL-*!FҨ4m[HO7ie9r-lDi-Dx$R˂ZǶC]FTy+u5Q:MVnVW*i6gnzdKiC*5 M"tXVd ԙTiPW!U6T±K6TNdD -CV]6Q8e6YnkVd"]5"\ F+F^EQI*PJDڤ\T +Q (qVdFXEĬmyJhIT%+KbZȲj4Xⲃ=Y@i %jZ8SJvMZ[@dꨐv0fe+5kRLi\j B*EnJr݄]HH4KyL&;*KBj*-/*" DQUlš䧒"-E P =mQCqf>emB\ U259CjaNڷYRΦuPZF=F= \3I*Țe2⦒!z=YwIq \gʑVW!EEUC,pfBꕥ!Zj܅RőLsm"M3+GcƬPQEIF.USc,3Ji[Ҥ@TrҳZR阍a5jR "F(KIPJ<˚i"sQ#qKS5-RRf&fDhLɔԸQhhJ5J.>ȪCPH*kYL鋇FcwϬ#"Ԋݥ*2F+ *JUpW s5nU&zh%es*kIM+*eAM++R̕MytYL,%|ئ\Ԏ-eU2(F&S#3 3VThEUzΊlIws"G,J+I/1a\*ȤJC:M(- 2nn\ΐtkˋhk+[lk rDh3;,K6i42IwbmHΣ+vfYjJpAzsl$ZFw9YrrsLQJ5[Bl؎mc+>_>R_`t^23~-CsYqDꨵ#e,:ӳc͎Yӗv7qF,κsY*eJPK+ܛ(AIYJI'.6 U82@t$t@MIZ$5#t\(S(=<`$E+JHD9jM%EI u1ɬlٝ" G[fy.vE8QrȁU*b\+9ȩ4Py{p4CZD2ʗxZ, V )KldJVcYVXƱqKIj$v+%s>8b 6"(4AFDry(49u2G)=}#=_4 @"$gA/O<*OZ]HΉ`ga\hAmqǴ *R Sij9v;#cJUzٟ>~.~~dQl}phԊ7 dT }I*~dTg|aiܝDMs3O֏̢+Ə8EYfKc$ Fd}Fq4D/bN>VQQUR rF\cȣDQ+If |%uDrlUgǟ.ha( p@` `8)8`(` b@$`1$YPs:bH45Ay% Cذdm `5dv3߯0垡Gi&duGx@2z$gEI#8:;NS:#;Ns5(C78>| (1'iQ3&It(nrfPu B0(@@01 @1 C C 3!1 "A20B#6$3%5EP`BJ24:ʝgYS*T:rNgY=G]ZBŬOѺ)~}"!>]:ZJO2JaʜJqt-[Y%0T:4&VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV `X, m` X,X, ,`X, X,`, , ,++,rܶܰr+mmm+mmܶܶܶrrzzب*--bب*-t{=zE2@NGN2CjFT tJPr7I+-#*P*Dyӥ:.2\L4,gBWKuw+A{CI\BPP D1Y P<:} .PaTuu%pGB+vQ+:IARBLpk)M֐SPin"@TA]jy\B}+KrVNrAtP0%< WiCDuy 0"1S"Pu\4%f4OȜ\5]# ANs(!+]G 0WK%,PY/PWj#LirXAۭHE}Ɲ@Se5h9pRSr!9c4NRG>tuQ0B$B'%y_P}_Piڅ05vC!G% %cFJ(.+vqZvлGLӴD"QjW Pb M>nYB 8Ѣ*xrZvg&{gpCXI E"9\Ž!JedQ*Zt3JG$804 fZ4YB=V\<;N !{ӥK\}BKV/*XBScO{N)t2 :IX˔xNR:ɕ2@p%votVHdސ+0fP]/=&gN ~p|J齠 u9@5iSGy18.d*B eL!*t!Jp:r )%!>2˥Q NfJ )A_jzC5v\LFK;HYCxAzCCIN TpQDP9Όq v7ё2_$pXP-LiiNP tQU{cGMka76Z|Pjc|`_9 D0b&ZCTp(+\(Qq\Yb1_ۥLH/L@.ebP aJ _xԓT -M2uj"G:I5%>)2<+i5f*epzCPEUʼnGOm7=CWx|ݧ_;zT_N!*ޘle,|ד>5)jpCg2bU K9xRm4Xҷk|d[UՃhZZ5w/}|g'Vm穙v.F޴Tk{}uk] &V-+v(C`(8f25W}uS=pU/Uڼmg2O ⰮXX/%64%WhL^ ѧ6V&tX##BJtyX#$ ZIPD:)vjJe-ISPO"M .0 QM}/5_q*5r x 11b܃CI*8DpP 'Pwc$MɴBTJBT]% ? i*9D1HP^"[ >lh\V,n]pxO:BO${>X(VQԟ@m ;%a>ʭ*NMOjPx?~5J4pT\/Qݺ 8FMB:?&[{BէP}6^Us[Qm+sFk@Z} {\$$֗3F=`(%u?[D6@\Ƴ(4dA:G0ڏTkT dP勑CP*r5,\V.XbV.P勑kC989r+%YԣRCOvFm@zzץ<"yky]g(M4dt&]W ZS)jQi)alz]QbSB9Oeu^xtS>>6::p(5:MԞ/w:'ѫIK3>|e׍_Z9>pcAO"-Қ9@EBN?&xj5-dӦ#+jWɌ}Fm5-.m?/{iN:([THQA4fkn_y6z۔}RwG$kqViWVVs7Lwn<<=LLҹE 5B`?Q)ӭB4~ֽ/3Lk3YVAdAf:-ƬڳblոҷJ5VmA[؍FƭƢUp-ƣQFVVMRNFѫQn[[[Tj zm /J?8݁vOrq?sx]\]vW֝.Q:S`Fz cH]SVK$&WiG=;&PtTgRD8w]oF |W|T>*ZpZ-Y!4aKTd@*ZBHRbZ!.j|P|Q-Ep^ϭ =X+;*<_,2Ru->u'Ξ?Z>*xLx'<~N:^J4iM?KҲׯG~>J**~^Bg|G}CY+[ Tw|.iy't͟y<<]mOWxVH8EZkGyy[n?o}?^!^W, KoV<%oNVW.ց'\ ~__T7IRUo~I>bN0gyQjoJdH;iEoQ]S]'u8~*%uG%zsY#>+h 6bqI:x!ӊj者RX_7Rҁ`+1毯~vz'?t|o'q_%_%_%_%_%_%O{^KKJ]||?9_%_%EX*_$R>t:Na${bV#.r'b8V$hVYN!i9x狡a$ZFV#d{!@ǘ͋E=_#(ȊelY\ (Bbbp/wB^G֒GxZtTNg,Noqo9y|3H[صz_"<1rlSpΏX&_Bh!BXdzxuz^Z<pӪ#G!p<}'9D О7?[${ B̑n$Ncz;>7;& !01@PAQ`aq?)>2dɓ&L2dɓ&L2dɓ&L2dɓ&L2dɓ&L2dɓ>p88d_4dRGG{(F(VLk$g|V[W"2! QS"0;UWBA[UT6+g"HRdbsYmWURz'fl7g"4>mDzzq|Idn}Yps㨻1ҌغHBY]=HBq~njLdY-*>LȆ=c!vlv*1ܵVEO['>M{Kd.W R ˏKb9DBgSJ!12Q "Aa0Bq#3@Pr4Rbs$5CS`t?dWn@Rwh]M:>rOЬ[!zRYtr',r',r',r',r',r',r',r',r',r',r',wK%dY,K%dY,K%dY,K%d+JViZJҴ%iZJV}.ˣܲWީ~WgިП+v~~weJ*unY~CB,$ѝ٪,JgwzyWr3?ݕ5%uԸ{j-˚qYJ55vhYT]R27~{tE]Z][ѯ޹]-$[],wҺwBH{]r_Kfu>WONwFJJUOn+%һe+ j_ ~J쳾{,ɻ? /cE+ߚRtM.(-eUҪ˧ܳ]NԺ"vs++vB5>!H2V*RtkvWpG/eEܳСREwt{unvKz7fUJ] ekNug}.eeԔxg Wt[ܷި޻V+*洉$Tly''<ӎpy5q<<ǚOO5hkGZ>8h+<?kE?R?jnlg%ǚ楄qcikOZ~ipe%U!UW%%Zbrjw-OJn rn3#nD{9+5!KQ8T}]%@RY.w&[K{:,'`KW+ۋfFS3Q~  ud^D{K#Hh3Y힐6pE)?KҾaY6X6ix~F++8D0SV-V_JFij &Z-~mł}JT~] ST rYIP)Ηu}ժ0O5Qyq<֏1}O5yk@kE>.,_<<}O5c/jey7kOZ'gy5x5x5y>cikOZ~+OԬw]AҘd]z.ѐ4;VReZPqU$UEڊ6KUw]KJ5NJo fj%f6zȂ,eaz5 mo0 ȃ{FYp6w/J%! ,6Vm8ؿ ̶FrEEyYYDqng0ĆdSITUo/.f4QL9WKqa|%|=F$%<`Dlڡk^E1R=Ɔ2C-$]΁aA}SvDlS^,!> =MWzȎ!cFYY%GEsL)`kkVB!_7C`a5KO5lecY}]Xj:TKmk-9d|si&R8ADGFL[ܪq. 5TTl1Zߢhk\(`il0THN%5{y]aDHqC,/2`8ؙX[a| {؋ &3wt~JSfR즫Яk3dUx{9_>Q}ֿ/j>|u>Q}ֿ'k}ֿ'kֿ'k}ֿ'k}ֿ'j}֣gZuZt:O/k}ֿ'k}ֿ'k}ֿ'k}ֿ'k}ֿ'k}ֿ'j֯/j>_EZ[nU3TD) %ez6&yqն-kl+͋\U،vx#᱄6qfm8[3uHP#|kk=RLp %hnsGȎ$avO#, |H%t8No^$Q*CsZ dg\٠AX9alș/GƔYIlh$-J?@k)t3T>vmNf}afgN):&ͭmآOkwڈgNM&>kg !Kq4C5փg-{ T'+}Sc&Kڞņ0ɽ6|'lZ" ņ9a˱B^qŽ"d_{դz94B~)VrY@d>.ЈIӭvWUJVWvȑ:vde1#PUTC&^`k/0洁eO x59ÚD-"9Ú9Ú9Ú9Ú9Ú9Ú9Ú^aeo59Ú9>aikOsYy5sYk/0k/0xߡJ3Rx]ܰ?׎t5+?z!Ab~L $f ٍ`Z #ggk\ph.qk‹AiNOzrU_M_>h!ZƱD2(q#4u֪\8Y C`f@+5e`pf@%ISo(0baLoV".:rM<Uf};Avg80'ڬћBvԳ Iz}z ,m"7>?m-nnιϱ0"2iI'{,穄_\Ub6nV"ȌH-&J/5oB 0l .Ny0̵!{6/'9&htV*ta:Xe3$>ҍ(<#!bdX2È/lg+h^s)4 )NrAϊ98%i39&RŌcv?N҈Ljs.dG2)fu=3339O?Db RqYZ,,`+P+P+SxC8AjVjVH8qY+1jVQjZqZqZ8Zw9݊u)wf+[nⵞ+[wVqZkwZz⵻+Sn⵻xN+[n;+SN+Q;xNⵞ+[nⵞ+[N⵻vv{CsanAŬs'a5{w;0l' c*; K[lzzd6ƅf,tHp>QPJ='8Ķ,{4VjD Lf 4q6}l` TA09ZD9Z(ޛaVۥ}\ֆΝQcC{Li=Tv! e%)5 ՠ#P;,8À]FXQel?)KhZ[dӢB^n}{[E$Wnqikh!X@ !9λꅚTKbv4?z:McEdGK0LPZ % ͖@Ȑ;ER"nSehƘb'=NcuatOZ]_S!$H=Åʋ C2iWp񹥮pf%hf qINMebAnH(p[:}M MsgWqD 8E|羅a-ip8ͪWA"̝kEl.pμog?a8k@y'8k@y'8kGZy'8kHy'8k@y'8k@y'gsCbEkX萢LNp_?h.;\ V['OEÍ:(y4S:t=5EТd8@Uu_7qn!< 糀2F;cu">G58fS7w28MFs޶ \e@= `Z!˛ة>0Jasfd_"\b8JfX-V7kkl@ikBepo3+%Q-NekfZF3A5 R=!ǩj-k2+YZQZKYZVk+ZVk_kZֵEEgV3?3zV#yLlTs]T[_'ڶwz=Wwdo9Ų;>Izdai1K|&"d18 Ga9I9B {10[^fc'.bx/l,=w7d}VTɭl1<~KXq R$18bgi8fWr4gWW7; ])\Pb# i,8/nIʽT_eQ.0~sKfPX+ {}p8!Y+- #PHSΉ GlsA9ͲmDHOpFik";LXVkl~,=Mgޠas[ 4dFc an7'[E\SqVU5wUzNN@sf,F0pϵ@`f:89jȻ\8e9iX m6]S6DDqo칮gv(f'NBUH|1L'l6X ;:9w |a{0^/w |a{0^/w |a{0^/w |a{0^/w |a{0^/ws=)!1AQaq 0@?!4ҥRKKe/贶_rKKccOr%.\Z[-._C6k3enq},& ek g 䖞S+ABxM>?Kd E!P2n%֫ĵ*2uAXO3<A*`=fD/~6+$X[u.ͿA 2o."Mo 4 GF`:'@k j`zTB!?O' B!?O' B!?O' Ba?O' B!?O' B!?O%~>eejVVSWVWRҬWVV~_Xʲ$WYY_ppU*t ȗrr00^F()8<ق<#Iy*pיVh7Z2e|taϘlFGK|QNJ8nXu  &%DN?V2=%&|]V+8?19)POG,F%ADY蜴%먠"pcbpP4KU ;({[=KsRxky]zKUBgP^*{Û̦ZY%^dtzʺ9-6[4s;8{TVeA%Q;ܿGAM }Y,/j*W+-.cYEVۇ2( "2ZyfMaF\ċc [bk/S8$©yjoѫ_5RO=g9:Js gUF21N@Ӊ.LOYUJhmKtKRp5E a(*=Nt+86sc@!zE+Z-y3^w-ye}J? +*0^{.t9h``7i6fq^<ƍ[=RDŽkJLS] 3.wOy[#]ps nn&y8el1)i-W* ς6pBs=Kr琢eԳ "JP)O%㉦o:%$Dw,go8vi~%0mWAڃ( 㛈#h ijEwpޘsES#-D& ?pNϼ,蹓s_FDkɩ\J-ahsj؋mss +@ "beY2V:_U W[/4rTedrNfԦQg~^!oP\޵.Մ{(KΠ֞#^.eM/pl~Ѻ<̫$=+s9`0s)` I]K%CİMC< ~=_3| S-S-vK{RqMYȏHyaiT&=s:L19KY_~V[塗Cu7{ B]H$3WԹc.Xav/kQ+s#G2! Lĺz\sU< ;hg@ԫA'&w 㙺ӨK:~& [=kK˄% x {Nwn0w7Ss.EFs0C_̾4WsKQ,*d)[c, m0nUe;}%X6esOUߤ,Qx_GK{/ 2Wv2=A81_|' <,O7Pyer޽?min(t`TVB@SWMO+42xSLA6yRQWؔ=<+Y A;7W0q>HEx|Kʂ]p*YX<3,(1_JNe)LJ 9&"S˘dhWpQZbSH-5\-`#4&{ s^gS~}{ƾLi2{,S .xb^:LW/1M<&>0_\-:89 x|j0K4#ֈ36pB 3/bpI~]Lu:Q6U_rlXN_2`cf׈[]Vs;q;)VYq$wDk9Kw+q͌ `X 31/N:.ҹ)H|(EzTRg,ǎ v1%%2}b޵ yL\td%&MɭkE0/pL(Df, X6` a5l&˛ۃ"j&A\♑Z-@EaCC40A ɐńP 1V+f1QQ"`=|f,:V_W40OvcT(|@Cn]h>a\SuWó/Ae+os⸸٪BœsWhE/g3LQ YcIiɍcqîۣA'%zmz7I+3_kNpvL(c2}"vADꘃ4)= Etˉ\-F&opH@i5Y \;w:0yJ8TV:Z d^513oIsXOy ĵb*{PͷU}EunQPMګyJ"m !Ff 0^cl:"&;DjERcPvPT<-z*tSoNIn&Pi`J2%+X %g@ۉ ra9lO!yfY{LC0 ^xϬ/T8jd,|;wCn]ǨKӸ@wֳ8V"{Sm] қR[jկ=Ea7)fEܷɓ8olBE^Ja-.`BUE? <^=ʲ[4Q@ ^+p fhB83V'ԗqqa_L9J ppnq3y³s*| 5*C5?'z@֥)3S%)yYU #HAoQgφ4 ͘˩W9"hZږ"X򰼉Q|cqjiA!L*Jy 2Py@qn vp_xkP{OT%.ᢽI]#GùqR0YRKV{(ݓ RD& Ix󙖼4jX*¬SG x AiY2in&<9|B˃AJb0A[})oT/,U4bUķ8`RVws"K`8!gyO0D5ܱעg̰0}]6q,` S{H4,"ׯAk| 8Z⊖0}10\X0H ,SܙB_\)&.kq)B[ͦQEO!]&U㷨tbȣ|4 8&Bދ.MV*Q8քMGf? Ժ+QlY\ǫKg8ToxP:E1]>%l~; xh&# αRJe}/k&荞LHƘ'슠\Bڽ=ҙ6rgq`2|CPkUfLԨDyfYzKu3K?[;QLfHy$9Y( wTZAHwm*,lalv< 9hT#08|3(,d*fy`)L˕VGa5 dZrya<61"D*9))WX CQ.&q$)S+.eY<o#4}Юyj~Dzwl`b2k*{Wrds:3D Nqal/B2GWKsy,F p:vlv;Skgfep`u 1s5Kf2U# Dx]a5Uf/?yڿ cRs;yEaz\f߳գ~+ۇFL湣mK"زq)R.W|ktDx.7V ;Qern [7., L]\GSrLu 2/u Cq^ܥz3UD؀|-ofL!B˿)Mtfů\|Vj 6-b6T빨fi5BB:ۤܐ&jښ' `3cj8r7˛+1w2+E3Pnjd L= Sr O551=X1<un-OWH1M]u d^q %3[:V߼S T<vu{Rur[ *&n-1u(1_VwtN!P ee02E-[0\D֮\_X`1i{Pzb vDXǾ"Klj] l\ÉY*W0f9YX0EifG,zA#ezOYR~i]gcU>ސ%ә68'%N@{ݗhӝx<#g Ҽ oRTA{8nRE}[.Tҷ/OLQ~X|Ti\۶91:U[y(٧yl4A}VEm]{Kv,7Bm谄[=pt1ʪBPx[vlƷ 2΃Q}ź}CBˋ0ϙMPP[D6Œt }vJh{]J N!unfb)*~ai#E;^%vSG$`\ʏwZ`=1Hpv'e/CmO ^cJY 牶[*TnU޾aUr ol[op4:TƘYreܸ>MS pVuU1_ f]G͞f4o 8/[47_Q$Uw8GT>&In_4{ ?zB%xSb+(zJ X k 8ruƏIiayOJc"Mj.Ω<x Oyc-ȫħq5n?هL? [SKټw(O|YD"CY2]wI ޿dt?&QsnM?w6ߔ:oth*|9R90kDDrl h#C=;bia4 [6˝b9P1eTeF@nG?F<>JYs L}eVxy?L4zkܾEϙfF#rʶ=Wr.˸=&TUhp.f QaG:b0W=s(̧3h9U<*?5B+1<&BR"^FqNl!:(iu 5.0 >YF6/={ܮBkp&_-Yo| >><˘ 38FOZ:SK ~2ڻھɪ p˧!`Z ֽ )be0Oe/ _h&#oJ׎>8ɺJVe—(P@49y ʖ0grњ"H @.52+drD4\\Nm ̠nEZQJ9%N,2yHp`j&mTyb5X:dYw(͚0IR4jZz\r s ,C" Qˈ٤o*"2+W-Mod;lY<Ϻ]8ʡ55?]E^",b8Uʷ ^ +1 t |J0͚&D#@)B]y"Ps)Iz_UlL ,4rj(^2O=`),e(x%ĻjPcWlċC1ܰ\9s>aJbXOz;ԲaFa͒j&lj寖8YgC'g,,:Q wdZdKdI53`5Ă%, b=&k1Xu15e?20Sܺ^)bqnsWbd.٧qtw6φ)o߼i1ī<̷ de6؃3ufs(Ʋ)cXC[mĤ,V _kc}LʹDAC rW'9JҋnN)q +_S[Y.E][|YfE*Eqt}1nUf0J$u 3%7eBb:U/k1`W??[M64ֽQb>4dIά4tϰY٧zg%!AqPכ"WitːާrT2 `juUdXjRܧh'\A-N[oYAQ߮6[A@{ |Q)+z- )N(< &-U^J cȽZ&iO(i%V0֥4EŞ|SQ/sBPm$/(esV^&^bK|'2W}%)Y ae;.Sv*L;GM0A<W"U&/9 k[SBa:)1'bx_L\?M/2]3=eܹĿk韧_7:?Ԯ6-sO[Gڢw|$/?K&<z g~?Q&KE^B@OS]> /zjCa_oo?~O~2])$'~ ]zDLfjGRa3 I_K dY*_f:^繣Rq}uW4rjcJh-u]%%j^ a{. 9g/ӧ7Ի2TydZ e1/A&mT[X;u}F엺 0Dr&j/zۯh&a_ <Դ*؀4e]U+ߍ1!iS6K/Ѱ+MWoYRYi%T>cb=i6Ow騔Ki/IAϬTq4(넫ͩ HS?$%) y5PouPт~C@v/#d$aZ߯2T%2z^oQew^(.in_l{,xxacǒZ$-~"0sQ`y ߤ? /?Qj4 N&ަq,(jx0lmG06/CsMUZ~[IJ8sh]˅EYKUbZs\Ɋ;Vjg0ofVKL9џg|ǷglϿyg|2g~ly>gl_ay>gg??-=|?5?  @@A  @  I@ @r$ H!$I$I&II&i4 A @{+[6.r=_AztP{mi%NiMvE7bcG4smH/ Vu.`mv$bTQ ԷoX K2+sXjKh$RRn'K.˿&MxfV1罻wSB$.AJ Oš0U&C֏X39_ɰ=xHҁ.Rv(ATb@7-v>$Q,?o~,ai.U'D0Z8нU[6颂(?݄C/>zTᏙ^CiO3N,m#lYVbYô6^ukBH QDQ|3frpՀϿh02%$,|`Gc#Еٞ|ņP ЗyDr+yr,h!lo ѱ'W/U獳xp9B:q`Ȅj/Aq|OCl}"P7p`!hTQrhXz$&d䐂]v=~ M$H$'zP"C1-h"l ٦Sg:(j؍&3'崜Ul.ȍ-",dU[U|R|iz4E4}S *IljitHɮR,uTl0d 4҉@ @ lL@@!%Iel$A$H  %dHH$ IAXEH,AH d[ H A Hd $@ dIl$@$@ I$I$ I  A$!1 AQ0aq@P`?zxKs}Ϲ>s}Ϲ>s}Ϲ>s}Ϲ>s}Ϲ>s}ϿTRbRJTTTTRR)q|= MB-r]9o&$mb~zJ:ĽMNa~aJ,A /Mu;n E)u -hG tkctPVp?~Jwѡ|Hkgd.mZ8#)&!2{p8R~:z%c.8RqLHM1 qJ_ =̢?E=|<Ӥ)JZ8\S KoN6H>gq(౼,J=H~+F1H[gh; O/WO~m/~&(R$~ xc B^QOnZ^5&.l~ ' G"ҬCOT_<_.:CC_)\! ·?HZEBz~J,ۢg<=l0 SibK D$XC~7XB\p~ ap!:0Y*'ɲU?da씟"-zΈ?*lYilgg& }%G !mLOc.a(cĊů$3 -Iӡo~! GkC~ln䈟Se~pP"L-llDkex'E-̊㆗ HH.cPN.кZPhL᧡n"3tVi#k%,_oleC?^B #D#cH4ip[br^IQkiΉFedbL?obI {)Ӥ'"`D%:> ~0 4=N8RŽWE(D|/?xnJ6YPm4Bx&/GDKcbeOx_VV"= b' ! "&QE @BgFdxlB~<¼BC~_%0xL خ;5i6^F(1;F0\BK "ҏ ؓ#(CK1Q6+qF6+$%2*4%#m16Q? Bc_=8t1,B&!&Te(EO~-hL)(.wL .cb iGV8Q2d)12V4qo6$EEְbD:4/|ZMQE CQxPj s ;1H8R)^wǸ]D!sK:6D} KFI |_.='4R6!Jˏ\/[b]3l7Y(,X!<5DW(KKxT{2Q9҄leD= e92 9F7l%6@ e/,_:I-p4 )”Xgz#)¶e.K⟌e*E)WG|.4D(Rc=f3q ~Re/])JQ)44je4R?Ƈ&?g1{]`)J_ Q υ d)ճJ}ڂiQH5!G#.TIѦ$%П(I'd-#ID17+7 6p~P{&Lkwn[q ?&{zd] $-:l$^:螡({6LؑAEFՈhW#nif侃n[bKBD4_F]boFХ=F: 5ތh LП􂚢^ Kkc4Z-> OJq1-%} h؏*$55ДB֐^&a nQNhWՇ$cm4Om")bۦ%Ta}B6 Q]͡pXn6 6 z?h/TюV6b{Ч-hR_tKacޏ;)/޴5-Tun/hn $gђ. Zi!PKcil٭% Sr= bGWKk͓ZZ.B1M(4/qbBaJXwlLJ̍hА >*j/44ea?D>t~scK \'ZHC&IlOPNCl'w &N }1%-U1ɉ+tJՍӨbǽf%zx"~!MDU1QPGJؚ/YFОy3}Qѝغ74_dhC F !OCN"6l9\F5uzBK&$FM ؔpg_eM T9ѫѦ%=w'>(S~ J/? ?{Ѥ Gӊ4UgZ4ȞDE'5&m!6ٷU'pH;'Jm#]decf(ǣPZ\"kfk|z7[EdlZkɍm MUi.lh8z[?^(i4!6fQ*m5~ G-cINT"M#>S5tNc]Lp _vCL(АXGZ'?%1 QDMhؖ!½Ѵ7%KUᡳ|VG dhKҏg= ^Mp{qXDG-Jɪd&Ttipq4*]4)'}%S$8!mctG?bb}b<.&&=7hVH%Xѽ6ض~joBC HK}c[mF؄Kn78*JA)A.Ď (D9 C X΍D$*E˱ۤlW3hm1 _cЏOz2 aiB+ELA-a 82 ┰nE.Kya# \! Ǯ $:g N/*:~ cF>l̢OD٣lMi> kMHTzKFcw/I&`4ͷ 5᮲ nXK|7h&)dbox{4Ǯ-4D$k:(#\##b4L"щL,1BbS :OX_FiqK~sQDΆ8%$ZDF U%"WEť7?[9ޑBVVE4p]6[KGO ҤXʎmz~^)nmwӼx>++8EERDF/Y!Kp:MTdLtJ@n*s E\"|?bCscE~ K7Kb/pED6W9^h8Q2h##Ѓ[d ^QzeT $&z)tfJBR.R5#/ϳ' %å1$X"-++*****LD#E!l&)P!`脉",!bbgbOJ8҉1sEx51r`Ljp.cFbCHZ.ѡ)S5Б s qe OT\(REDŽ XbAl f4xN2 4.㸥gG]? /]c|iM(wB^<81ӣ^"!R6VlS0d8ď,k x<6Lt!-5?Q$6b{/?zC|,5B(Rc6lKN,Ch)GLSC_/D #(hקH5 +42ˉhK0Ba<+2ø&Y=c!3" hټUXٿ:,?q>P͛6W%07_>7LFFn!L xLtxYgboK,ya0-8/ !AkJ[XǘS, 3O㱢D!7s |&2S3=KEx!Oƈ/ɇVox2^!VRЇc />i Q?LBa/ ~|`Пߝ(sɟ&!1AQaq?_C6>F|\x2c*u2}_l>|c>/z^/3G_c9gew>]_g0Oc ֌n{ʽ}~ B6u3wr|Ac/Y>;ψ:~_Wz3L^{Ƈ`Wc>ҦvbʑA,]2jt/ߌH``|䄧|фA=w31g_kE%Q]&YJs";ǃ5yp h^ fl/r! y.+o7W#{Y83] ޝ㜰^7^Ochxĩx޾5G@"7c g_]}[Bw2GH2yq7I:cZE):"h Xctms9_(9- @{.o_u4_''x4 Q&qm|LVbB4!ɌΊs6T9P9"Z7nS$44YY&W˳}pW~p^~?9?Yfלy?~f}Y? gv?.b7}Ϝo~˟\x8gg 'n/cw1~e{}Xy1SpΏ:7tiߌdd5W/A_^e׏xYƽc}~L{~_޵06nnvboϿtb,KƱ~Rz0d=t1DēiOX >r%:Ts1!dyr[:FU#yjY1r1:ǔPe"z0#,D^#|ds~1-b_!ZNS3f_a =qLCcY^@]x?\Qp\ yŜˆ&$!}ut9CaY0L#k|`P<YiۺitH?$6NZٓ[%$ ]ߎv?w찠|!y)3<4аm0h5Xk[ kmU>1QH=8tYXH)r\ΛǸqy‚EUOj;:C_?oiw_'x@P?9=h17D&Θ)AADߌij1TP賷! #/ ^26|6k(͘ *nnM ɕh*ҹi9#y/77r:ʺnW9s~]}q``8|؀C~rD6o/>**qZw0["zG,oCj~1E'o}S!PomQh-T}pצ#õd5OT< wu /44  v~nHA4 6”^kmrzÞ7]}rRylk;t? ٹ-<_9*ɰ.ͯRr <7fޑ!v׌#Ql2MLxr(rZ逅/bEtF`RLCQ:ÑύOJ'/rk5]wbYTIͨl3CTgL?#.YKvGe揌 SOqeM䗬 N06Z&|b~pl`;&cto YG:_"ȧ]T$O.."N׿%(=^GPtT3A4 N_ ' " t`l˄r1t=,ydX>!4#V/NkmI[sa{%p&k&7 -/3wM^Qߏ8<6?lS~Kdp+"iQ`_4?p`Nk{+c_TkL{r^~pNޖ)JMcXHp}1Ss}0j[K|b G `z1A|E~<^8vLWoAzO 93)I]1@y| xU"oEz +ẻ#=oprIb]o aMYlX^LgA $V jGp?,1FX^v}~r4>\4e&޺ [ v?O,]o&߾b|avkurX7"167)}Xm:U@RKORudW[ˠ =gګol="֞0E˭JښbOf> 4$dST% ˆkpmZQ [_2.z}uq[:q]iҢ?L@PSMu8p' i80 ]C$LM:%E_[ѐ P1t 0b6~ ^֪L ӼZ!J"`8hU99|s(yrFMY>5nU }{@i. ̻ rsit60$e~֙AuG <[a6b/?`zº鈀`7XZ}OR kXˊ b 2Axn.М _X':yb-j{5U'O$wgR/XNL&űWoxA|˔BQI"=E P~pKcPrdT0|sӈ,`@_> L\L8'mJ4G,eA6r+o!h$.]<`54<ǼM>T3 ]1!'W%ӬZCc]u`w"W0wUiRLe4SSs e!d&WT4}x0? PI]ujCsN+ṷ:Zf#P 뜻1Ы?o2]0N~;,gx@aI~{ :YpŽ y:#BA|YM+5\J/<ȋa2 7W cc'<6F"8:>([-ӱ;'ki E$Ⱦrz_Wc 72u%aQ<<<>p-ːn(eDz1rC)o"_xh ] pQ=||JjC1LgN$m}~Rof$Z9ۖ^xį[P:,da!X|6à(JkYllӽuۋ$MЇ.cJ0Z} <82$U~K&rEB׳t6C3JJE|+CLIsqΛƄ+04}X%˃])1ʆe H0 ΍,YNnw hbjP% H@vpg>-L1H/s97B6)7ٚTߧ=̦"N`*`s|ϮjwVo0<&ưh-Ϯ=b.w>#WbS[Y? r@Cӫmt }q'iPxo1i,ɤӌ$vF '."n;ȪZ(^Ƒ÷(hmQ:pMWN $;ޔ _p΃mɥS}fX_X&o+gh@`TTB>q*P[@B槐򬊢"ʃ&? s4|KC#S ú1H0 :kx[Due:`&}n.UE- PtѸܓR\/EV7?=Tg4kkcX-!/YvypbiĥT"I WbYBaPK;B- pJ)Ɣ2@D' %8hzO~dj!w$o[hl8Rp@l䧟U6_U18aņףxh[TS5pC)mχ+ьeOQk 7m~1#_A &F.. j6s= rִqyk[7 }Dא` q(EWf. Sdc}Χ5FV Q-P?F3yOD'!7);y ˿D׸u'?a[ռ6 P _TC|'),*6:*9A#O^[I c'.zr}BMӌ^X IU8*/ <YR{;ypQT# 768n M }qCk׏(aE+)+Đ.E=eS3-O@L+wf88pȨ^qA:T)7 {5`a)c V[@pqx/ x™P;|.(T}yqǫa_#wI HJ_ cRaj@7T/17VŰ+e`Cl:rk9|St×r}Te`(;~7xႁ2pS_OOi0ס׼5`nq2K| 78A\Pޟ$7ž־eP4qJQx4 ~2#uh&z]ya4.~ %86]kI\lzSU~R4-fAD;o $ӹbfB7`6"kR?])b8Xh@tJOE2Cx͜_`A6h<Xfm6a%r.Ua0DSXpZHcH!\9Sq)?,@Sؖ2 MtmI4)@4jCQSֲb]7=W(J)`QL D(ѥ4V1B9#" vw۷y W$&Fp{kҟ0묧{|1MMi6diSx!+Pe_0eb5}1D18&Ósp6l551 I_%#7jD%UC#fѦmgIu*⻛ ;K0:j Qz[o֌2XeJZ99oYx)h^TESNC犺t"\&pͯ@ %m}yIHPIJj7´+w0\VUkL-aHU,A Tnzl,4e)wn4,f~6<pДUfeM%%xáR8 :lN%%T(n:=ܡgは8ʞp .5񧌞p4(^FWq餞n;^@ &ۄBaaXD$4Є#xQ)&ݍ,IJ` ut~!-ͅ\fAmVǭbIS-Hg&=.GeîeIҏ8ВH+b6aqnno %NPwP.foU^MeI|nኩw>3))]_cZJ2ЀG! XY, 6a &2C4\a] ( dQ(#Ëhl_T {;AUXK@0"Br1Dn\ "unHygG%E5pY1#Ԣ/jtΡ#ܓ$. AU.) c9PW [ 03 r=bL{A JLL(yųlx vJ}L) --Na[ op"]L<X C0yV}rqAtfP_n5oqSpp I0&}pFq-wF 24 oÈv\(cC3MxGNb#wD)}١D8BDQǎqLbml&98xND;BeGR.% Ofc:Y\9e"x,B.b*|4^fJ!\Qxdܮ0b+1Cc _tdj -={j + 7Xd6x8m|c`PvzoX^&yw_ŹVDZ9j>0C@v`;*\цy40(,g݌bcp@4 ;!֧R'2VY6\aKCn_M Ta3NBk Lxσ:4)GKdd`q`RSC2 @|8Uf"]vс1X~GÈk5B0$ς=bSq*3Ľ}0H 3{B@#ე떰;4W0R9WmRO'Nļ7eجFRDO#аQyfLO)/xlp3Ġ5: k`u{0iy(7Mn2! A0JȱO p'OY:qܪ5{>0Xίn3xӂy.8| \S5Ddcq'O^򟦲\ 'Z}2bAXҧfUNP ىPF,L$:αy:@e,ʅ5bƠ0@y9@B%1ͨ8T @ W!}SiÊwό4pvPtKٵrsAsh|W[ *7dʉA;֬i] /')5Ջ1e2<octW]uJp\tC# Yd>gp@ `\gE. `.O JU6[`sJ5: -R_h"k@n.@&w`J1)tb'BvۮJ $[M"<6uS9K^0fE.\)@jY{x!;r g|1xNMv2KKr&oݾr*c+K2C$Ȟ_YA!}Jm\wN&@ XkDcαN? "_0r]_SI;p`J\",cbR96OkB$[s"(|^@4;MEg-*b0M]!v{**KCF lOYLw׼e ]5*± &;~ MGrnʅJxvk׬T&#WYq(n K3қ@X&03.б2Zj%*@ӗ` `zc1͆jCi7IܨY #%ڗ{ZuvW w ls4nogom4ha)ݨ ?C *щȀf< wPh + vjɈ͘àdcbX@6iw\.Sd'OǬ4Z׬i$Wt7'lbm-sI'|/buZ47sB+Mn v&3A$びzŋB 6)-U=cdosnJ3esRֵؒ1nsyMG}wd֕kWKC廏7-Oa>8/786֬j6u]+ Hׇd϶!X#O[yV"`D^?80d m[T2v9mwqVy r_ qsoqoO1N@ϜvP?f!tqq~rM^ s}vso` A76} -j(`h}kV(05NQ왱!/0n'`a}hN8f!~nɣo;0$uR1N&ƱGu:,͜L+z5Cht(3rTl Y$3ؚ78Bi@Y.Mڈp8(H]$Q;/d[,߇d~72h5>9{~1{CxL!4hX8KϷxeqTlp7 D*th6J-DRd+k%F[aE ֐jܐU) 9'XB /@+D ҩģ8a0^{@B6Fo[C1FoStOƅY lp6DEA"ۂhE&5T7/\eQ淡[8ܶk L+!<"?@F1b m "'\؄yo'ĞtQ\Ұj( m+nA8R{S*xgZi 8DlŅգQªu$ Ȃ^NJ@l8ڠxan|5F 3TFք!]11n/x\7uC%=V{(Xgtkŀ\4 'b7|)`7Qg"Cv߃X, 1 Q@)FwEیWXK;<'&#8|BG4]eְ];΁{Y*T[p@A8f+Xoo981W~)y;Ӎq+DA+es ćksbķ`aґwJO8SU׍0"h x]ư*`&rT,JaRoXd1!R[h?emo0޺bMzfju)62q^.K21:c8oiBD{eQvi#ZO͐JȵYsMs$ކ `ݾu^<!lG+ ^  ;]}Ы|" 2^m89']=﬊Jx\xbg pbXW z57.9Ad<_ :U.($xĂ0Pޱl$f2COØ[\LD؛էχkӇ4};DXN}p:mp'pݵ :)~𩟥n<'ZҎbS7,+ߎ/Xd w7!g:3n"䷌te1/nj6ust-? Uͪ@5,sk5uOa{spW/1p9Uq ;ә͸5* 2Fsf;x[w%)l,ӿ5Bxd/IX&W:K($iMF-mޱcΫ <8u8%[囂o X:ZKQ({Ƴ+&+؏T⻾d W WRDnYG T% ʢiUApp0":v=:anZ *qe^Wl6=aoLO cWaaT$(г4jA_)?MEwz+C^0sQoͭ5df%ksYCZӉ7D7~1PY݉cG10t לN&+Cmɳ"5?,\೟sT_|U&#qvag6`i:r*rK(˫[קȫqH84//(*DUcNGK>}Cuk JR<G> 2C ڶ^i}e0D5[` 4j: S816t`לy y‚ycۇs-(Yi9YQad4|VG"Myz=u;p&To!_O7@Ҙ \$ÓGaaŲY)i~~0 3ufީB˂ui|k*ow<z©8B.JC=$?7 1#O(/L5:xƌe ɽ+Hb"huB"АgmOGd':LF%{Ai 8SX>8͠ϼt=Gs9KH`k*>$%KaF͏~2Jq"`(;9[!X0zBtHw#e9W4Zm_lr{iy}0,`6u,ttpnuʃ:T@t\4C鐨 {L(,xᨲeu pLpTQ9QzŋT0QMhx(4e5D5h{>qG`G^@ֵ]0e-Tb!zW$؆Hb`E6wrrpQᕻ ]XҍA|8nY򸣂YuCWED }|Sj$X펇@sowuOnNtSzo.4LIW#~;SuM7rY$ x*|{ǥH z+]bnWϮ?lT)Bf)rQ{$c]ß~,O.]Ǭ">8 9/xѕ[?|89xlzxi]( n4&,{T'#-5F\1>\:Z0i;t׌7ܜïJ= eh\k# k[ +,8+m>\W#O:b[Vn%ce{0+5w O:Z/ v^qG{f%7hqɹlpo$oy`̳fyϞ0=y||s{2kq'  ˾.g/xv1zw<ۼ/'xlomiri-action-api-1.1.3/documentation/images/multiple_context.svg000066400000000000000000005571071455542516300253200ustar00rootroot00000000000000 image/svg+xml Action 1 Action 5 Action 6 Application D-Bus Multiple Contexts Action 1 Action 5 Action 6 Global Context Local Context << active: true >> Action 2 Action 3 Local Context << active: false >> lomiri-action-api-1.1.3/documentation/images/multiple_contexts.png000066400000000000000000001672401455542516300254630ustar00rootroot00000000000000PNG  IHDR YsBIT|d pHYs B(xtEXtSoftwarewww.inkscape.org<RtEXtCopyrightCC Attribution-ShareAlike http://creativecommons.org/licenses/by-sa/3.0/^Z IDATxwxU̖l:IؐB (F /⋾gXQA""$zzoǒ5 I`C䁝s '7wUV,"B!nNJjNF!B+Y]*z ]!BqE[daB!BE_~{N q)c; !BL~-JD*RB!!B!j)ЅB!A@B!]!BD t!B!j)ЅB!A@B!:B\v͛g RQpk<wy5pObvNf>2$1W|i>`w(K q1-[fsQPw8;OXdn_UQ{>c1m0~trPmyA#DMI۵ 'bۗKvt(ʍ_3*1W,UWF8,=xd'b=+ܳNr^+ZIGQ)(grP4W.]Sq5UEz}h(/6S1uA)qqqo̲e3%M_6 PUZbjFx4UcifRnۊ,1cSq@7y ӽr=+ܳ=+uml#O5lX2K5U)Y=WӘ/zp?PO=ҮslCc)M0ቘ>mmNc'b)snB4TP~W4mbjE lR45꩸nfi^oXLe_,THgEY'g/{VYxn4崝L8섨6EB!(%\#dg{dzPsĉޯB!2\|]wşY~'vy=zΝ;3eǦ !B#|ٳÇyζĉ%iƱcͥY 9rG}w}w4 M+9p'NLJ ҥKn6t:]O||<#00J*fZILLh4R^ҧB!DMo+V;ݎ;xYbIIIՋ>*P6mʵ^{^yU^c,]={Onn.ׯg%!#+ӤI9r$򾊭Y~֧B!DMd6nΝ;iժUz-iР'ħzw8q"7n$**_|֭[ΟN:͛iԨQ5g)B! t1c~6[neϞ=viiisvGb2 s.==lԩSB>zGڵHLLDQn]kRRR8y$L&4iBHHHe>9U$&&Iƍ1_@dlܸ.\XbOXX/qf#>>CQ~}5j^_[iǏ'99Lt:5"<<EQJɓԪU:""^ϑ#G[.7u@pp[sku<##{L@@8t6p4irӤB!j . (,,UVavE˖-͜9<{Vҷo_ڴi̙3ݮ?> .wo,7۷ӷo_;W_}~a6Yz|K:Ҷm[{9ׯ_aΝL8#Gf^z%ڷokO1c*\pL8ۋ&L@z䔈ѪU+&MDhhhs/KҰaCO8z|hh( m۶Çg}*ijs߳`ɒ%,Y2n8o־K.L<I!tzFs@z!;Ν˴i\m~7vM^\p]{RLL T+**322<3ömذaCeٲe%Fرc=qhذ!_5֭cZ.v; t:uV}vyF#Gq$$$0{lƎG}ĵ^j?Ǐ' 5+CСC>; 83f F'x j*֯_?ΪUqƌ={S2as I&[o6Bp7v5}vtBѣWB!\p @@@ 6䦛n$115`TUeĈ TaaaӧRzzz}2}tfΜɴix7yԩSX,L}:k׮]v4mԭzT rxT$ʫp8rsh$--͵ɹl62/nw.ū7g+BBBڵkmb 8wp-j*:uTdK-Zg}Ɗ+7n\!B\]8N-R*4B! ^Z*{d2zm0 ɓ$&&gZ߅cAAAm۶q 7ozoţgF-[κuΫUUYh;w}m6rCaa!/7ofɒ%<ӀsmbuA_?FqE!..Yf}vO?Ĝ9siӦ :FԩSطo[laѢE=gb~KJA#>, \47FQ l9p} (+ۀd3t2$AW,61נ= ERUf* o0O\pV]Ek*>4zv;d.O\d-M^=h,OĔ{VYg䞽Y.h4Swz*ACi(ylHVvb*hpEQx*& 87f…h,DLm@$b @i=S3f0x*4M wVvEg!ܳ= =e~J.hvjESt4[==pSq[_YUy󱿤h01kjoUu0a1c nQ^퉘6~C gU'(CuaO9pFCSo5jSqϦ9z?ᥞi=h0,<SYgg/{_fQ\dE!B\dE!B!j )ЅB!A@B!]!B2gUUB!oB!BT"B!D "B!5Heq^b͡B!ƬMɬERa?XI!B\d_=+{ժ Ri!BT)buK..Y?@B!.oy֐^ !BQH.B!D "B!5B!B R !BQxt?iQz{O\lFfxWCz"&s4E5u>cgD/)Nt~y"6w84mFA#{"e>WA#D[t}ݡYu=#չlB!Dl^+GGU1J8=Sg7tCQS`R\\G]lF ji㉘(~vBj/b޷(0BQx}ƌO=i5m="~ur&[m?Psk5ehy[ƒw B7=:9޳Umbu*ۄ ٯߨKPͻAMSEU,PH@@MQy*M{[5j(MQxBl: `'bN!sٻB 챟+Q-|ޢWI hvf%NJҫ#RB!DM-{'c7&x̓1z @oO4Cٯ_c#5` `@œg<3sdo;0\푸JWˌ鵠7U%}Ρ{ycݫ0D5Ԭ]/BY r{QXv{v:9&}N Eo bښV!]HQ3qB!:᤾$٫>uj?[{CT#=|'{~#gR TΚF7љ}ow`V3@{5]H'M֯Kz {Drg-To_"]Hcd,DNvUriЖd=ς" !UIO+j4 w£]9o>pϣo[[n[`$hso}XĻmgv4K^WrH:Z~Vs \t{AVcqd3V4{VڙBQ%@5NΆ%A%޸!,2Y96j4N8jҖzbM:Ji=vWu.l]9 !jI.j7bOOB_' CݫJ7GS׏_LРq>ȩ٬ؒzU';hP mD8otssbr şDBsՂ!tBQH.j^ƒ}R/px?QwTӻZu:sxԹK\ &o=i& /r,bb;uBb0a)ACDwY wW8B!.)E"oP}2uCƂ7ٰĭ@ '!_ ;雠(L8o$cZ;-^5]@0=GRL-/PۗaOӜx=|SQُw1ob4Q{Y?tM ><} F֗31]{)yܳQzē=p v@WQ&GPg+hEdBMQu R)/ЬE1lץ/ ǯ=fk޸Yӣ|Hγ1Ɣ\;\d, "c\gv]jҖ}I~^fn܏p>{"oڏc͚pC*o>LϞ1q:I}NxfI}(B$ IDAT>9B\99MQ F)=H tQ#yH_`,e DL]fmBׅ!rZ v=zM05mWj%>< Gn&Ɔ-15mWbLE'r vf:>ǃܓaM~L-{nׅ?7cK9/]p p3SчuQk%VQaێ=#ct3Lڣ|7%/З2'=xԥxy; Y՝eG tQ#:o4K= _^SNʥQ6>Vz8߀2>~aJWF[XurkǿfOqS}ϫ՝Dh")ЫlT$B!D "쨾nIw)B!E S\e' jزRB!G |x)_;pQOܴ)NTobs}z"&)(A= S1/T[O뉘_̛WK3)C=8쉘qqqj 8'OKFS3|Ҥ*:B!:s[أS\/󚦼gWw=3#hMuH˖DahKW.SBAUDQ@U~Ѽx LnT2ϡ)̘1{_M](X%B!jZuOm]s-j|驘v`t„ OoTmAOGn&bNP{f!w%/ FyuUA_yʊsM%!@Y_y@~OxFB9 o`u#d@d=./هf:7P^uñ17,o,ȷIJq ֜lrh"׹JoShv+Ш Y-XqD]Ci"[`Wǫ;#o^eڔwKnDb͑@?Q8 OH5ہTpgpހB!)H<56WwUO+kQLnZ#?O]pSqnׅϖ߸]Gҫ&#ĥ X \tY79~N7//4 GQ>Za>|4U9աp //1kS_B!DIToǻTݙ읖Kc=.$eq5 [ U.NӶ83׉*rY|'U3v{HY2Yi(}hݒHh"=rOjqo:fb? lVؒbK:X%Fn\[!&Ě߀) }B!()(~խ8YD~‘ hwHGt+O2{zhfyvd|&KF1pRX|s/ƞѩn}G4iݠ(433]L'@6tAyv6όf.{e_6}#)DZs(G9x>3(~7Sv.ޭo"|Ҋr߫U@O5{[ &L-:`cdCg7~QHOW@weQo;vPo;E }X`m1kS<ЩBqԴw0?s$OyZ&X wn%6-VG{l|@Q5!OW$%X)8$u?%&Puس !_E+*$y#uoq A@1bK=Ak4i}85a܌_^>!B֯Q|s"=JοdJQf~z 0. Nx SNC«>rxw.c+#8r3́ԄX̘)۫)m!dK9WkKu=#tĹ KQ}#ފoJη tS(F:^#`9c樾h6 $LWw@1`IWnnK>.\;K16h@Op^SwEE1pN>G~kb0-Tn=+ -jԚ?׹Ȇ<8![n•Dkn(8VL-:wk_tVfyQFץFў_ez@m`40)՛BQ͑3J>X׏v׻MqnّU K'U|F0VBoкX,!PuZ-u객< k`N/}.=`;-=#۸sz; 4K7Wxqs+b#ů a:ThyL1숩eGB]H%سSb͟ƬMQ !5aK=;]@p!܎Y|>䃖U] I撷 }9 WUo]N ˑ}x5l ~pK}P_iMk ާJ/>5"viǝs؝5g?*.knj?:탉94K8/!!NާEFb_&Ě+Bqa)(P8svlŹr o/z{V٫fcP+N5VA8 rKPtR:,3j]d592_T@Wմb>$YԻk {V9Y-Fs [^='?"nZI/:gHhc\ĕG DjQ|;uǷSwlIG^=Uspz$ĚW/ŬMsB!j ?h^ 1kGZN0ȷ}W{W DɓǠ CѾ?lSx5iˉūQkUv%I$ uo[LE؄OI~s4GctSPtqaoEAZ} ?q.h"|߳NOX DLYNi>CЀ]YА'HZ߄Ujt '><G^6Q3]wM\*h۳Z1_:)Vcj$IT!jITRt/G بi/;06lK?ћ#0m`z qdWΥ9[ 烤!ax]5QX<^Z| ="c05ε=35t nZFs=Sע=@с?Q}1*m(߉V><Sv8 (:Su5½an. RH80\1Y7$Z IT spfc#/6%WbR !DwI^ -+SHEаg7;F$ĚWw~B!#zz}Y{`iBy]BA9 !BQaRW1SWc~-T nXsjNM!B\&@,EΡD?fg bͦjN!B\@?O`Bo&Ǧ?ׄXsjNM!B\¤@@w#u~O5洄B!%J t0F7:4!/_<Ųetjق_}5ߓ1϶l2K?i\UB!.+ξ:..R5|0'( i fKiyTEۭH%s|u bz{wh}ͻ* !BtAtZ5qeӟottԹۦ`C݆*JRks3Ѭt Ԫj> CԱhv@XByxZ(h yQoW:h᩸gS45OS4hU_!DY[ґNCT!ct3|;u4.mT;=w2Ҧ?_9կAG@][ߖrx/'/}Eƻ1~k(.}Hy 1kS*]4r V6,S;dĮՋ4O=_Ѯqx=F&|TUt!_Lᮟ; Qn)2e&%`uY: b]pp4Dfi&"^.0LWwT0xɤd_"eEݶ o~ɩbLsc1kS앍˃yt̳M0VeB!ׁDUwƒ,{uuq8: t}X=^ g )#oפ(aV8!aj=IҒqdotyY8rשjԚWp8rzbǬMQk!b6V7VwƒrX)z5DU C\_֑ vhi&89׊ HܜϹO~9GoWqdd;yA݌𗗠|FC!BqIU\To?{_\P훰hl)hV=#GNPm$O~G^6=Cȃqtct+Z^7O5?S !BKOq9cX5cM%M߿`&K߀P\zw.>1I?㵄X1kS!BJ t}h]9 `K:J?1Խ -]XXrx&/E\%}oAx翦$ĚYr'"B!j*-'t?2nm}ȭ@iߕ:@Ygwd|:{+uT:;f>_͢-3rXj x]?Q}Xk|VvB!*--G8;hǽX_:* ǟ!a$z?Y+>,Y;kGo?h 9Ӥ{ѯ^)/JqlLgɝ /!BQU<f%{l|;:w{7GmۗWgl[)17{vZb >A'ЬR=F~_U99X-5!BQcUIm}xasbs܋UX_-=M@@sP ί[w"hxp~>N5{!Bqٸݹa2cJO8HV|GS*>FYlVg<,p2i3_E W[ߎw|69a),ג7S9,EXΑPk4$B!DrsгV~Lʏݎ):=w 'hB*9=q]@0AÞƷәxqzq `‘]eiф.0[IC ~uN>ńX1kSNwB!|ws(#c8s@Q0GF;V!!NrGnZG4}Wu}ռ=z΀N=LW_]QcK:=; S15i_ׁ޾1\06ԝ-7ՖB!4l'Л#;q9KD MMcjmëI_BFLoЊ %Ě?YsB!jc/|XT]S)o?Fκń>!~~<Ėv?Ӯ _NGT[(AoVGjNG!l8`'"g'+9Գ֓Ko`w.9jv%v'štUH "(^w&ĚWw>B!DM 4 ϓ-8Ryw7/Bs8Dwiڕ@ BEB!jG^69k`lؒW_iؒͬ\>4MhWGAJ`K:'1D4SzA $7/k|B$gx{ {լ2R}wGpF["qpsח=;O$qpsRgsX<#ې8 {7(عDY?8#ýIܜ}ġNc~"YW p, 1D4Ým[c&\:^4e z 1X4~=`DO,ǒVUсB+T DëQk %o1-ܚ[S]@QJs^Mڢz^(Ş>Bi|a 7a!ǃ8i 'oF½aIv]0ֽ 4};[z-Z:UGK/rɼ4MރF]@a{?L޶5$Ě'rߛmQF:bp8 3fFeXMB֬B!Ĺl߄x<w ww_dKSڧ}8r20?> 8g!aݴ0HK\ŵ%o?~'i&{C,u#CVFQnu;˒˻( @ tRØPj$pM7IєXQww8;84]Fﳪ/ʒ}zmνP&r_V:n9[15k_nq^< n#ƘÑAnyPtpG5)> 52z {C,Y_ٯ_߀z:z~ HH3*Bqg˷"cT}r¿sx5j\"Kmjс/gbI83+Ш(W:)k w tjNG!`lذ;oh6+2u9[rU8r2QLnl;7g$JqU/%N t A8r2'ĚŬM9P9 !?~ 6Nr+๽˗n&AR/Xcl>} eE,+xN9X0ֽb(An/~ٽ:sBqȳil8c=Fͩ[.#FO?ԩS0j(:utr*:'#jҎ_/+\X):QWfl5 {zRjt y?,q.{L&*OH^CZXWّ@!Dllݺ'rslw|ƃw^۷/ӧO'>>xONΝ/Zn[>ζ7G{4NM4q`v.4zAye4)9/Q}h6oy!S\j(cëzMu!w^֯_φ شi999sFUCyvJ۶mQlVr7U=lդ-(ع֝ GGut9,E] F۲? f)γmB 1mRCG٬aAU} "z eEo@Y'Ě}b֦BԩSlذU8quNQڴiC׮]D}0C3՘?.Z6d+;'0 IDATo am E{)^&bզj&c`0bjWSv]P0k֗mjz-?m}˽=1F7C\. !Obg{cw<)k(Eoˡ=* sBQyfWA{nקk׮t֍nڵ=#gã?g{Mo{"PT bGDQ'U,WTZ! H #Ad I &z<7swoə3?U|Qr 1lޅt7;NN=EB:Eckz V8 -k:_t[qb^k7qp7@+$ !(fƍ,q:nB||<{W^ԫWχ !JBz9f}:B/{L&ݻwfɯ{v !/ >(̧!C!o%%%yG~ٽEyZ ڵ+>Vq$c:˯ۄBXnn.+Wfw؁6qqq^ȣA!* .PЅsl޼Ysڵ8=((ݻk6ljrtY"́@tR2226H.]Ymb0ȏl!rL 3BQYÇ{7iD ݺujR!I@/ΖBrnzj-oݺkyLL ={ԖTZՇ ! 嘚=VQQH@/\1O7I@9$ .(_n7wʺn_=ᩖBiii$$$h^ 6y QWAVU2q%p'Q".K@_LwK:Nz9fKXkO:t7pwQDWhǀm$38*bO{ᇝERxP_Pz璲>B\)yyyYF [lh^|Xo$KrXj 2YCL;4ix2pg*\u9(Η'2\ߙܸou-Tx2]Qԑxx]2,BQTUe֭ڍWnktU%oڴ)b1cu22DWu 9+o`_frN1 syx9 JœD"d{e7/' lck)RwA$̥J!.Çkɾ.ArOȳ|'YY1T9o8wHE8w9 !D9֮]?kydd$={Զ?Q㼫ⲓ~S~ܠ5g*Go]m[VTG~'?KbdO1B+NUUo߮عj*rsVG.]Y-Z\ȅtQ`R&Qrݼui@C9tbȹn(eѣZ OHH ))IktiF :ul6Z!8? ?Щ/xڀmr-yp4?}"g^ݷU !*L-[ƒ%KXd {j]{AXX*Bғ.JGҬ#f 5ha=6T^> $'d!Dt:Yn6Ki&n#ݻ7jaBqi$KbSF9 d1ٿ'v=p}b-j!L(&KT$F1~{ -!|ra-oذ˥УGmnݺ>֯}] B!.ݻwkKV/_Nvvf2֑_s5zV+t!eɓ$$$h'NEyZ ڵ+>V!' B!.ZNN+Vfw絎<::G !D!]!Dn6nܨG~zND||6KޠAV+t!w^mڌF#]ty۶m1GB\ .*KRR~GjoҤl[nXVU*t!rJmʎ;PUUkW^GժU}XBT~Ѕ*vټyleڵ8jzmظqcV+Go4Ϟh0;9XqЅ*~mҥK ;vy1>V!*r;tt!RRR#?|W{Æ uݻw'((G !Deg*(8 BQ vVZ͒oݺkytt:8V+#ՑG.CTP@ wrǘoJ;NBT@?Ss͚5ktU[ҬY3V+*-) QA)F2$<ɘ9U9Y2gb-d q$&&j|ҥimzkV:tdaRL{ uP=neT:"q.I_PIzeҥKP~y||TT&@"עdTG@zyrcBT >eKǚ5k@e<IϞ=e+իWaB!. 吢X_!*_>F^ᨪ֭[VV^nҥ[h(>X!ĕ ]!Ci;$$$t:ڴi-[ԩfه ! Bql2m^ky= QB! BQk׮ᵎ<<<=zhVjժjBGЅ۵;WZEnnnXԩ6KުU+t:+d8K.E2%]!JѣZ OHH ))IkSVZisZ! wz2 ]kf/NϩTZ03_زHh 9K.0X{"ɉ|IOMD<> wprL}}pxSTLЅ_N'֭Mpncⵎnݺ>VQOw -\ Ofjߝ>,L(KB;wn\b6Mk3LtE%oӦ#v'7p݇1.w?_ˮZ;=^!ojT#gOŝ!2#=[metւfًǝ  5Ukj]vs];3^!e!t?A<Jđ9lk5/~A3`Z>7]TXЅWǏk/YSNimмys-wV+DHɉn#CBnLβYN s6f@IƏ9`b'-E!o:Q?DuDNvqaӌ`y}d,tx&,-:cV&|8[Dx)o$ ! ,_\%߳gW{jիJ|2fNX6K 8 cD5ً:u_!Xclm0nJւixc wt݄? ͩ,5quq%Ǖ|CdlL(x`'?5?\֨zc`rrv K޶U3SGT%sDŽ=?JU@z%Щ/Ƙ(* Dlkrɓ$$$h'NjoҤȻujQB\,ڒ'|;ՑO%5dsNAuxA^1ΆvO7oD=IAp>FCtAAkr7.Bu;4j[ץ +ڰ5j^.T/gH0G^T'^X^>(Oz,qDfMMx[wu$W֞wM@T\u%!''+VhvjZG^jUU*ɕzX ~ 8r_+:߂mo2d4P0wM|t:,[a9^Iz}(4Ä zS}:UMpGH~i>Z1ƪ5I~-J>FԳԋ Zݦ5,8 BrvqF-_өҭ[7mq>V_q: BNGɚ% !oO1ʷ,E?qҸD;`Q F>p:T}wYTd5 3p܅rbPc[+<;gtgTY dڭ*mY1T-X*wqW}P8#Cd,!r(Cէ[5Kɘ@uP ƋWx@EQ.Ѕ޽{%+˖-#++Kk3 tQ ^{-|<4퀥ibu OЎ&*lw¯ybaфDu7iI" PߵXڽo"M5k_CѾ6Dƞ].*T!(҆s.rssYr6KcsvA֐ݛ»/!t!evټy׮]ڵ6KެY3V+Bt!DۿdeٲeddXӾ}{-wt !Dxعs'up88tGH@B\d.]͒>|ث^zZ '$$G !*,Soy7:+V7$9`_"|;t޽Lt!DvVZ͒o۶kydd$={By}X2;pCeŊڱׯQop0qDTU-6 q$ !.j|͚5k~~~tE -Z@k!Nhhhl9r N5\5fyfhٲ%jԩSPڵk-[[.8qI5xMzz:Ǐ~ **}1rHhذ!yyy4j:u-[{B{GNNׯQFg?O~1l0RRR8}4AAA :}SOzRO|.J͝ƩQy5{s%}Is07h]zNp%;ש#T}s6~!}]d<lݺU V"//OkX,tI Z*v0!(ΓO>Iƍǀ馛ZL29s0fT€`8Gv믿[oE\\&MڌF#^t^7[TT͛7gҥ\n (/dΜ9L6[nx~mNW3?8͛7gڴiL6tF `~늜￙5kK,s|7ԯ_UUٴi3gd|͌?TC?EeՑBּ/$rEp(8W1y#0DWr˄v0^Z_O :-YYt))))Z(jJ ]t!J!.hood̘1e˖=Ð!CXf 3f`Ϟ=ZPHKKl6ӺukL& ۷oeܸq n7vN>Mttt 0h NJVVbyw6lhAƍwg֍+b9Mf͢iӦ,^֭[턆ҤIv_E-HMM[n^9tO= য়~Ytܹ̜9Ai_D']'këЩ/Y~F u%GgGXNb)ù';hF\xCcA:q<" IDAT %eĝ‰Q}p]tK.ڴilj':`O?رcѣtؑ^x~1`x k֭v#ۧO8}Gpp0SҠA&L@.]~q(M7ĢE3gsnٳ'+6l ;;oEv<@7x_~ 0|z=͚5#66VN͚5_f߾}[.o!* TrVƝBcz+Ys?'ktwz2)?}JmKq?b@wr`s3q*5y*3? |X;{bU%sd ש#cِߦW Y&k8(Y17nK`r=!j6"^?ԏ_i@_x1?'N:|"cb~؅͒׭[J+].6Ţvp>#rrr'<<? 31o<(ȑ#yHJJ",,Lۍ믿.@cAAA|dggk~188 ݎlfa2g}Fnn.iiiDEE9 ^{(K+' T~b4^!}JvҴW_Üwz2~-:cn솹^ lgɌ'/wz2jݫ7b[=Ct5>m;m7fwP!( yF/xkK.*Kyyy3.Hǎ@ަM- fZ ~Fi׏/\ڒ>?_-/5G(߿k۴K܃}J~Q(}:wzr:[uJMؽ}hr7.ƶz.z-:~o!דX܊>׸;Ưٛ:SȚ!D-[Offy}0y?: U%BADekڱ7`[;wٸROb[SPֱ`6;p`CPr^:kρL+KUe„ \{ O~~B!($m䬜>4 ݵф{T?iǝG,k)G;Bm&vv{ NK*ʖC|w5G}aÆq7Ӯ];W]w3p@m/_!B֫Z-K\DVN$ cd/N[(OP‹LPۙb<ϙ]_Tl ,C&;,0`@J-K3HJK#11z]2BQ5,y鳧JLEd/wirV\qh` Ct(eEWKS_cL-mvJ?u:%>_edV.(&!s Ҍ%.ₜ۽ czxw= @0Ub4aߔ6tAa@A/)sؖ.ԖlVA"!B\I{U["yғzt~N'ˁ1Q},B!h$rg{0:kH [؃c۹E_5OԘODގu8A10V^˂>& SӂYt:cia34V@ gLގb\%An<>" կ: 1zOFqC!bH@ #gKׯeWZv-tܿMO,v. !fiڡ0DU#dS+C:)t\˿]o.8!L2߾.C\F~˸*I@B!DNގ.C\F֜L >"]!-#cm+[^˸I@B!Ewu 嬘-dE!B! B!B#ЅB!(G$ !BQH@B!.B!D9"]!BrDA)'q2Dru B! @Gc|]B!(#+0}D Ƹ.C\F_ B+Lz1M_ BTJӁ''}hKW! B!T۪_` M~:`*^8'嘪7k][ w)j7V}V(9:{=ew?$ !B yXs'SGSћ,nE_R|{?j˘>w Ae4j7P., !BȜ!(/mT%]bn'y7Щ/-֜} K8EWo.Q:̤QJ3NfЅBQLޮ Xqh<7:SOGzɌu>C".DUfǃ.0DYxSxO$oGΙ{۠Fvt!B{s@m)>Gּ/zn&ӗ? Ց5N{96CK8{>X>c"/n4~:cjyՐSطĝ|@M@>/OT!uw$ !\s'c[5s֘\Z}Ҿ/ً$ ]$5Pcxӵ~7׬ JÝz2ONQ `5ļ9sZKq?}PjdΓR?׬cNJCB!ʵ߿Au9s/:@FY1z9y7u{^d!&:}x-,Iۏ2?NZKg>ҾTy?o J|}w)ҦG1sTljGzJ=2e[1WuB;߿A1Yrv8^Yytyӓסt~V+[5 l"?q':͊=bf%twV'zȧ[_($W`>m_!.}~iBoY+j-aC8FCG`ۢLp%Gͷcjګ3̍ۑgC{/]ۓoqp7DTN+CxU_!ʐjJ=2~}»YE>3Yvpwfjy{\ur^o q$$QtIKJ 7 peȶn>{Bdc[WJmVd=0`](|QZ158O)W,w#=BϗE%*B!DTRE~XŝLpRtAayx%KjMGHզ]7EoT훗a[=VjWЅBQ.e/kvހ~+v#y]筪^B_]u?#Hzk8ΣIo?;3,3fO dГ3Rp'y}2(_dB!݌jM )_@HEr7,“.0grd/ߡ:Q]Nj}P!wOW/4gP,Ns5knFbPr{'>1645 !Ded%XKjI@%WX{ Ҏ^w9&{4n߾kkٵкmH> Qk a!H܉v?8 Uk0߿ jn6qgrݢ_ˮD!%!‡$ r%žu%z-¬_.o_!Ukg#+#籿1DyTQz`y:16ӇW!/ NGvZ?8Ip:[ @0j\w </y¸;x<?G)/ M2&BEfEԼ\rE1YxS+cAg%I}LyYa^⦮DEPOđd' ]~D lb߼#Caip ߊ>4Db^]p۳TaC_]tOnn.=X]NHƍF=MHHK!eKfEl\%APl?}xnsV_NM]AuwXoYnLu:}Z5SLؿ #X\r`K,\[ _QհoY'FChe--4:q]P(f1>{Ft`[W'\I&2eeĈLKHϞ=i&өkY&cǎ%--'BK'3XxB D>yY+3A 9"[-k {TD1~ѣl+B2ch%wF Σ|]UMؔ)SHOO?2nݚٳg}v^{5f͚ŤI:u*Æ #66,\‡_N.CIza_qUDE!,{7oޜ~;v0x`|uaĈ9r U+B.UI&ڵ!Cr:u*c:t% ! B\u6lȷ~˞={x<|ԫWCD!&]Tzꫯػw/CEQ 4h}Ǿ}rB Ѕծ]>3|pz=ӦMq 2={D!"]@59p=M2h vB a :{W'~']ZjL2D|If33f̠y~lݺ% !TU%4$ !ɓILLdԨQ?Ӻukn66oBr͒~rR͠˃*O^$۷}](C[KTRw}1c;G1g̙M7K/Dv|]BQ(;$WG}] DFF[o2qDLoo_K/Dǎ}]BQI@{ q)V_PHxx8:Gfɼ{,\ ҳgO^z%v2B Kzf ᾮB\BCCyW5j>&M"!!uK/D=|]qg?S=LQZes=t 1j7Ezĕ!7 !.Ipp0cǎüDDDb zIΝYxKBTĝlK:W'/r;mG|жFsxpcNr7s0g5+CLsAz-Xf ]w:t`.QQeCS/\9K"Ϧb۫#_s[7uD>>UߜMģYH6ۚyK\vЅejrA}]Ti۶-suB ȕ|ۊ٘AMpg]6'뭠.*E</|Iuwע3AYd-Y'Ҥ=|Q$[{ Bks¶7wc_N{hꗏa, IDATvÕtwV*xiұYs@/G>bo zڗO zg?/m.%y[CD<'tIi#6JRU+Ŀ¯Hymwx Eʥ[_"⳦Rppp̙3l۶*UСCfƌƾDBLEN_QcR[R17?nhL!3Q2} {Un%IzI'K{ZpcwNj޲?F{l{V!ؽ;%|r#U>? ^S`<֟? TjrJ!"hڴ)'Oחիñfԩļ$BL! KTƼ+tH? f?I0\bV*=}' UL1ӴVSrA$\?KJCB9CJt*}ynX4y?w]rYti|ͨx%|-"FejT:690Lk5}dyaI1BLaÆ4lؐ={Çqrrbڴi :A5kVc !Ju0T烎9lk"lg֠C|͍,Eޛ+on\;}ζ2}[i֍kGeۮ?\ABdZСC߿:u3VVVL0# !%YZtR1@Bdzkf߾}>|O2~xpqq! O>*Q!WL tQbm!r7Q;?ѰF9]|[6*I/ѻ~^<@<'/S:/ʕ+z*ݺuCӱxb)BϞ=uB|@%rï Qi[xD?u!tIiMȬ0.In;H",_ׯӳgOT*K.Xbt֍7n(Q!WD t/!?Yƴf=mtI$\=ENB7ndƍJJ)'gjHipd*w_4G t~Z֠66}i8Km_F?ttIC?Ըh[{oqbOs/m Yj$o 11PC[H |q)aR%Eg@mĝ#hLkaȓ'ӧOgԨQL>yuVnJ&MpqqjժJP*A/$*+^j$m"&U~DN?Ӷ'߿ ڰJJjl$y qXug߽s-32%'ɑg`V=Yj$2u:>y7i|4KX"#Gdi{"̙SȘ1cȚ5+;vZj4lؐcǎ)Q!D&&W{EV}QDZwi5N[W>&v;o&RedԸlJrA(dӥ`̹s^;F__y?~,R\,ieϞάY={6vb׮]ԫWWWW^A !8r]62PfŰhy)ðxETF&ğ=HJ#yS}ɟy4o:<{^Ʀ=*TŅ͛{B|ztF*->41~_qn zyk;&VoARm㊵1X6G,[lT* .$665kPpa6lHÆ 񫓛#ܹsYh899QP!Es1x`˒%K2e Νe˖)SZn-B|!bulv2]LDVb 066N^LY̸|<]tAղ`)B޽s玂ū ߿?,\+++i۶-Kf͚5c P!~lēn޾i'k׮^?y(V(+VڵkN7EG(X}ƍ,Y[[[\Bǎ)Y$+WD*S!'&C\Ȅ 9s[.\KɓY|9˗/gʕtggg+ wё]zj<<<~:]v͍cҹsg%[dQa4 ]tSN]'rz쉻;G{(UZM6mp6l|ܻwckk˜9sHHHP:xABX`nbzjJ.MvfB6FInޮЏi'STlْsαe*WÇK-tym@B(ޞSNcVǏ6lL6؏TPd|1k,ܹ?17nB 888p# !D'c?C:~cnntL\Μ92e #F`̙̝;;wsNpuuFJBLE ωFCN#N".9Q, Znݺԭ[ƾ}puue̙ 2!C-[6cgώÇg֬Y̞=]vk.ի+1JJOk_)?#*:T:Fܼ0@WʕOq~ѣGqssϏ &ŠA:t(ٳgW:x.[lL0aÆ1{lf͚޽{ٻw/?ԭ[W xBs {>P#%*M<&$*j֬ɮ]8q7&** Ь] IDATprr"$$D游ȤIȑ#^zԪU ???# 4=>iwHK#Q^\{]ʑ,]ُ'\vplOdNR !2UcN:=111L:+++Npp =z4xzz+W.=իWgΝJG(5>]b1S NIRh HcMt=ڨt9@$\9n qBdJ+Wf˖-?www6mČ37o}aȑ˗O9SSSFXp!8q&MPre\]]i֬1EKykFbTfSh‰ھۗPY`ެ6޻%c`S }QVHOoݬ^J廒KQgĬn ULwo_"52 iV+ŴzٻīϦy$*CRcܼ(E~Ͳ &r":#F#)_QT?it!DV|y6l h۶-/2p@ iLZqt2&ijѻV?;gd{Uiy:_h,r`Tr6Hy򀔰71*Aʓ{7YP DDؔg?,6<%'>u]d8]rWXbXk׮ѣGt:+V=ztDÍ7Xd \r;RdIV\ X1kWUg1G오Y6yi6"5?jD|6$^}{ԦYAJۦy~U^]U蒓oj| jCcrh?7)Qm.^&PIWѥLTpa.]ʍ7ݻ7*˗Sxqtו(^#׮]~hѢ\~]Rxq-[FJlrCmjN=iRBxR*FƟُ^ f ;c֨T,?4'>o{~$?MrP`ڶS{PÆĩM%Ľ|BI {yX0*lU-M0T'._)EzښE@~cժU,Y:p#ѵkW\N%ёEM{b e$'r—RaQ;W` {|x<R5%~B~Fĝ# %]"7/$9_ϰXE.}r3NAS "|?# _6K'09mx<~k[JVo,lX[wz~kFb޲1\m&$ON#ھ%n$<"I6YfhѾP x%!wODj}W <==Yp!T*7o *TP:xNcƍs (QիFFF 'ܢw2sfۓ9JDuôz#rP:g 7<-WEHy|8&&&lڴ+booӧ(^RhժΝcTT0h lll5kJB/H.2ӕSH̚"2ܹs3m4qrřm۶ҸqcN8tDJOfTR 5ӧO'66VB\R||m\i'HwwjZctFd*9r`L֬Yz4hЀ#G(QI&'Np)c*5U۲}M:v|1@&l3 WN:⋑5kV{.'O&G:tSfMvڥtDڵko>>̏?HDDǏPBEsN^vE._\v>}nݺt=]=>Dm_ fliep$!2D,Yprr"00iӦ;wn;FÆ Z*;vP:xEZ4jԈ(&NG&44T Z-?~<=[q388c>}޽Aj)=ygFtt4 ibbb L{Oڜ>ѣGt2x?KO;7D_};v̙3ԩSoooY߭[7{$ر#7n|MÇ0`7"]'ڨpݻKJXbt&!>%ccc~'n߾͜9s(PgΜyTP 6Hoٺu+gϞy1}t6lAAAJGٲe ;vˋ5jЮ];Yd7oΝ;ѣ۾};6l`o<}Dc׮]QHիǁ8pzzziɗ/EM~ULLL(Qf"2sLO΍7077iӦ͛ϯVZ 6Fp},,,psscȑd˖?ɓ'sUƎgɒ%/cii3/_e˖̜9PfM:tƍiѢ+V 22C~5"]{TL)N$b8p nb,X .кukʖ-!W>3*T`ӦM?֭[666 <*1ҥ +Wٙ˗ӴiS I&͌3^:*s={ooovލ!!!FN044DV֭˞={سgg/_-[6]k]lY:vH̜%K7nL۶mߙ%55'Obaa׎-Y$...ic[lQԪUYf`N:EFHLuRED>ğƳq i&h"tڵtҬ^V&7-[uOIJJbΜ9ҿݻtLgʕ '''/_ӧ&033c1rHmƢrbbbygN,Y>*Ϗ?Ç;;;8qZt҅bŊ<7j:m HJJ"!!@^:ŋT>رcٿ?K >>͛73bqrr~'hO ݒC["6!w%gE__޽{s .]J…z*:udɒXB LRXf /_sΤ0| .L>}s3Zj1oΝ;h=z4nnn/;v,̘1mҳgONxymKKK̙… [.j?%[bXv--[DڸfpEV@5ยg+Y6"7wSn30Z} EKMMeڵL81m޽|D}6'O~#99FCǎqvvNCAoOΟ(ݻ\~JE)]tr TP333?~̥K077bŊRȟ??o+WFOTT/^$** /Njj*GjժM&%%q(Z(EŋjJ.ұș3'%JH4 ::BBBȕ+ʕ$~)NݺaZ]W(bCmYԖ]|<]b]dR2EWVoݻ]/?8BZM6\p7R|y߿πeΜ9/-"WP!,X[0`^ҥKӮ]7!R#أaG.U g"w NT*-Zܹslٲʕ+C5^^^o B(@̝;۷o3d ?(WZJGBdrRפԝ}{d;@,7ShB|9u;vjժ<~aÆammʹiӈU:xA|5kwؘ7RB8sTw}*D.9IU:_ƍs vE͚5y #Gʊɓ'tDܹs3}t5jYda֭T\&MpI# !2)?z`1OȬFt P@ 8r{~ 441c`ee,ə3'SL!00cǒ5kVvIjհѣJGBdRv45KIV:K أF:x.7oȩ4B|u<ޔ}j=<pp!>O={ȑ#4hЀܰ+ d˖ &iԮ]})QMڈP"~j<aOy$^}GEJ2c߫F6!6!2fznYqժq>!?j֬ɮ]8q7&** prr"$$D游ȤIȑ#Gڧ!jOB bdjgMk1@fP" :q¼\޻ۗ%'>SBv?OWNF-J[7|Wm풞+oHYcvhyZ*;vԩSb+Q̌ѣG'rѣQZ5vܩtD!D:KbYT-P1ceT 2\ߐtߐ4vڰwY|XG/wAY=L2΂JOj| qcHA{7HԸfyHٍ,oeׯ+jեs3.3J7TUuj=0=#B>>,^GGG(T/EBFFF 4>}dLiٲ%eʔŅVZVR{*BS{k''3h\~BVdI~wƍĉYz5 ,`ɒ%t֍ѣGccctL񜡡!W^,_ɓ'O۶m)Y$δk+U z(C3m)y^ܼy%K`kk˕+Wر#%KdʕhZc !2蟈iڴgO!z.\Kr zJb(Q.]p5#(Z(ׯ_k׮/^e˖"|Ih# tX(kkk-ZD@@COOUVQT):t2shڵ+W\DHѢEYx1ɟ*BF OD4¹\AB| ,ȼyu ʔ)C6mx 4 ;vҥKPtiܹC>}(\0 , )鿭!|8&&&lڴ+booϩS(^RhժΝcTT0h lll5kJB Rc!ɕ+ӦM#00'''ضmUTqƜ8qB* N>۩R AAA :kkkONll1A O 9cȑɓ'3YfחիӠA9tD&MpIOjԨApp0#Fʊ)StD!=W0B+s]Əwᆪnݺ8p@vvv=z={ѣ{gSqsq}[*Q:RaF4]tR J'!0F{TR"¸~{ɸ{X٣SǏ'---y("(61툈\3f `ݺu~k׎k׺E9͝wɗ_~y)))^z:uAJJ[P@/fiEۙnlCD2e˖eԨQ۷ &Pre֯_OǎiӦ k֬qwr:石~z:uDJJ /2uᥗ^"))-HyZG<b8,ss;""gĈݻ'RjU[ZjG}4m۶O>ᆪsΤ1~x9r$S9%e%̂x/j':iZ2e1]d|[vtR@/FM󷳃b $ۏi@0툈; ƞ={>}:5k䧟~[n4oޜ%K(0r +WdӦMٴxu>< GqwE8S`2r2q&şsGzY 5 k5* xm}IR@/fn6~? M<~DD$oooݻ5kkf˖-уMxb\.۔S4oޜKͬ|SOq!w@ڪw0r ? )Kg]WV:c_x 1|ιt7ql1K{x3=:u}"GTKJb=?OϯyϮ_}KbbbKߛVөWO<afAiaJCmy~'{1\&G=qIJc2}}n8%N->n^&{ ľލ9>ka a_Z}78O<{ـ:^JkYb޽-L0!Ac"Osat:X a51VEFFzXUXdL+MhRÃk.̙Cٱc}n` %Lxؾ};=̚5޽{xO_ra8<({@jiE$Nz3+2w|ϧggk9^2>Mڜ^ xd&=4lхEKop-("r~6޽{/ӤIxG_>3g$71{l~w `oH_2{yLY.*rhjK?x-gPG@INy>.}QeljXGmĻ-l}BJt $/z%3) GܒHa a˖-,]f͚q Bz6m99$S3OvLj^jժXf~!IOR~5ҙͯ9We5ؼ}.yeu.b!d_yIJ顀7DO!A߸%R0 ټy3+We˖:t~u2eJtEy۸!Bֆq%ad}KƗKl8}“8ęru u=Px)=1'+.2Z WzU^ꢀ7,~yBa8 M\xSDD"tڕ~>VZqQQn]&NHff[+$hXDݕj/؊awG3 ܵ/vb‹]?0z7wfox݄x̜, c/SXP@Iz Aﺹ+νˆ Xf mڴ!!!@&L@zz[bLN$uW§yc/W1r<1Bg0PIO`xxR瓘=}q[m&B= ڄ%d|9;~<^6/zlTsxԨrs/Ϻ7Rdo@8 Oo:75(6kPl&7(""W@z3gvG0 hܸ1~sw"r 3)p{)ニ+3 o7(67)""nPn]"##?xq8,Xo޽{믿E]ݙp"ϾrlHrmӕ ,><҅q.{5cy-"##=,佨cb`eS_0IqRڵ9s&w'ӓh4iBHH[nuw"RJ-/"r%\9zWܕC4`UPlbƇF:28\U̻ kEYitZ5(84l579fJYwV\=06؜111uCBB,_e疥hfuqbRF Mȑ#8q"Xd <Gynd1 rU!BF6l?$ <|ڀn?Cy.1>2p{L̪۷'fiUSu%v2M3BDUR' /0i$f̘UXj;wfvmn= GZB-jީ { y.5 G{;R 앪a8,|QǏ /v(sEPlbŎ[ VD5Ocv>DDJJ*1a{9LӉ%66N:1zhڶm6(Óȅ\N+ГN H, {8*Q:5pTBl޾^>'~={/ o /0l2peL=k)Oy4 8S`a|mkPleSDDD.$ q2uT|M>S>SnvFMݦrEzgژΤxgR<;=?W M,8Y"""WH3f < ӧOgʔ)[u=;M){:WՀڧmU_įglS|גCA2/ZDDJe˖eԨQ<̘1I&~z:uD֭=z4w}R7&C'XG"""?/Ce֬Y|s=z뭌=mH)qU>HDD>|8{eʔ)TV7ҥKZh+0\@Dt0l0өY&6m[n4oޜ%K(9)oooݻ5kkf˖-уMxb\by^bAE"""'= b޼yl۶P"""5jvwzLB\E =S@B<<<}p8J<6U`wq)\eaaa׏E+sN رcyׯWޗQ[9Say.""&v~ѷo_/^پ}; bܸq90<==9Ԟm&J9s&nSDt0 BBBزe K.y8p!CP^=MFNNb.""RApp06mbʕlْCOSn]&OLVVb.""Ruڕ~իWsmqQ}Y֭ĉtw"b1tRs|wY6mڐ?O`` &L ==-E, K/ƯCDZs]w_vZڷoϱcx dܸqE9!KlڨNXUsɢM9tqVՌ-ڰ,:QQ孪,zĦ9<:e5}i:ߛU5._XU5OlM/_լq||y$%%1zh3f nQ䚗PresYUn3LXl P3[QlIyIjfi,EFFS0\fk0+aЮ];>3nRRR;v,5ǏEk˧- ~&FU51&w.͘1c\VԼ]i3>2p5v0:~o[U35ט`3|Ī{_ir|f`yˮպuk>c6l}GZZ* $&&Ekw򑝗-}h.YJ+kfpO-ɃofHHQi#aaa9*+k5O@``O緊s(9EV駟;v,+W_筷g\wunS`\.9&>P-Xb7o{dgg3i$6lvw"r """Wf͚dnJϞ=eԩ1tP</Y39WV.+LIxb粹2݅tkM7ŋٶm}!??3fP^={1/J3F?L$$?4?=LgecCI$:$(\C7n… ٱctoӠAN@-GI]v-gr<_,pY{5hFϥ+c-eRbqdGꔻ|oǭ}IQ@5lؐysNixwOk2>_..Q-uçY;j^^H1ݭI1qﷄ"""VcΜ9=!X9? qczͨQ&S(OoȋہgWV#w&\)8¿c/t =yLΎHJ>S枇0H|c58"ulR$gw$3Fuïm"ǹ2H[5=LNͷ ^A7R@Q؂{k86rTCjSbp{+rmh-`Иq|HA'5nūas2־Oƺ8ǧߖP kIDATFjL Rb4'c9Ӓ{e'' hD?J?_k&FL6={3|@ffW. :v5v cݒ"ǧ?3//}-0 l>~Gޞ_) T~f*ɋ&]Q>y{L?xoęD ADOа{H]:ߋl """rNժUcݻ{___/_NV1]Okc: (ӱWէp'{>iiy{ d8g`cYr)oAJ """"RJL0O?~M}?Isǟ5 h~{*8SH^9(vT (l\NUubgmq;_yȅǒRG]DDD.Y@@ ̿+O;c38G_~u0e 쟿¿}YJK^'oE]OJ\ wf\)Y~oGV>s8>p9)cUoGjډ;S" O|o˲'"""R"enŕ_ۮ|˜8$wf?[oʇM, ᗸ.b>-nǙz?ÙzZ NWiͯ96`ՠYN&jجX9+WnٛQK1}iûIk<o8gZ n_7M1S|ZAo?.ը,ʇ>ss'"""R"U>wP?xNT|vEW}< Z5ʇ|谳;G\7]p%S Ϳմ9_vڊϯ+05507(<<.~]N+j.nƻLVZQ3&&9-to/iwmCZ""" ҥۿ²蹫/5[:e3f3av9*""’~cb"a {5&À.Vմa1MVմ;!&ƋV=iÁ<=Q_DDDPr߆0'aNmU5ci̘1.+j.lFn}l& LogUMә?հ{4E>8z83_vajONgir:b ?XDDD*㝚aK/5[лí &@phk>Xoe}.<V<]^>>س؉\MlYz lU\DDDDDJtD]DDDDQ@)AEDDDDJtD]DDDDbEDD䲙F_m uw 4t|IΟ݅UE]DDD.I)nCz[&)ȥ3 o.DJITDDDDQ@)AEDDDDJtD]DDDDQ@)A,]fqlAN>a[Q3&&b`-tZ+j,fiYso4ryκOd+j.{*xq%͊_|H34{5V<݊蹭]/o 1H rxz/KƖ~n8Gl6 jڝ14""",7&&mK7&i+yAV4= 4 ,di،%V= c>&gz*""""%]N* .')?a *鴻+4f3eE͐T`9V4?L'V00~4LsU5\6_&o[UwLas|Q,EDDDJ8#-{ ; &@phX5fXYЁXY3V5na ˢ>àwG}YQtiq@LWhpEQl6 ^+l5.|aw|ӊ[8jirIbEͥs{SLݽwdQT05cbbg.?~.]³4zޫ3\ƃhMM]f 5kV׬ْsZ fA&aI `$ǑSۊ;-i3 T7MU5mvF@cddd,hfGa4-P0l}- ؀cUMGvvy6+^ݪ6fMf3j5']fu5[rYK90~vVeg\n>f5;ft0 ^YQ5ojiUM|kCvU52m{*u?=+T[lUM=߆i#f]Mߏ a;;ZU3㦍FCaU]mQV5kOfu5k\_ZՌ\eQq@$*""""R( """""%H .""""R( >Ie]DDDDD=jBa@?wo/"""""-WLIENDB`lomiri-action-api-1.1.3/documentation/images/platform_integration.png000066400000000000000000001511361455542516300261250ustar00rootroot00000000000000PNG  IHDR YsBIT|d pHYs B(xtEXtSoftwarewww.inkscape.org<RtEXtCopyrightCC Attribution-ShareAlike http://creativecommons.org/licenses/by-sa/3.0/^Z IDATxwx-I6l@D)*+D Ezmzm?v(&B0BEXWaA@JBIo[G H`x?ϳٙwޝ;{dahB!vV盁>NF!B3YK}B!gmB!B|U qs7: !BRiD8!B!tqB! ]!B&D t!B!)ЅB!hB@B! ]!B&D t!B!.EiбQ1.xn҇-sW^oD%o\3{jIɿ3##jޠ%N1Ӕ8~Ja1FWy/ 413Ϗ1WmGm줩󯖥Uj%#fs[Ldc&Mu3--?Oݠ0zύ fJiMt! 9~4: w2*鯣h*b*.O)?ߙ={!1) +2"&B(wV6ݨ};0m3LyFijqJJŨ2ް&}:!Q!CJOFŔ6+mVl%iMJ.FO"]nN^f:ٰ3\,A#JiTH :u]4k,1foUPՈ*ޫ>4*IgBt-beV)WfΜ2*n tڬWS# 1/SڬYi66,LVuf_vBV_'!BKfz6`OSZZJttt?Bll,6Q'B8~@Bބ _57|3W^y%v[<#ZzYtt4^O޽{ B& `B2 pg233ٵkn"##i֬ G5uWVV֭[ #&&u~aV^MLL #G$<<sB=xgb̙[B tҡCj=Cߒĉ}B_ǾhNCqysQeqodܹM&Su1ӵkW|INtW̟?_~￟#Gz<;;իWѴS:ؒ,YB6m@뭷x3fwuk֬aҥlٲct !ıE]~: !IV{}pqooX:l0{;V^͜9sի6lnj?o߾dq.磌b~B!8])R F~ٳ'G_eƍt͛?)((Ek׎:߷o۶mf: !":}v6nHTT:u@AA۶mc߾}Nll,ڵC4^/;w$;;<, ڵV/Byy9ڵE:Gͮ]v@֭edu*^-[ev;:t ((/((`ӦM8pH7o^gBmFNNӢE ڷoioMyy9[]vX:vj M8p믄йs#>crss)--%>>6m`4еB!GըZVz~xwfqwٕeΜ9̙3O<^X}ŊXIm۸CCs-Tc?f"++ аzj^/^z)5'RJ1vXrssOkl{y#>iӦnݺZxi߾}^y^y>(Æ *~mxXP)ƿ/G8EEEBCCʪ.|AVXQ똭Z ##==YfdZë?uT2d[̙30c :t耮_ pmYWH!5j{~zf3]t9꺭[uwNii)s/5JG߾}<^m۶;^z"Zf̘Q|;^{#F(k-ëjՊ뮻Ν;W߿?Ç?>_^=_LAA~)}_|qu{UE)))۷o؞}ٴiӆ4~a/_/€xk?>3ϑ#Gbk-?skӧ[nc˖-~ KH.#;;qq]wU/ 7n-bرjժv]tQ /cҥLn،B!dU;?<5kcƌGux#uq\w6*MV^j+<::.]#G^PJU_z>bccٳg>VuرcG4QFX>h _0e/-++Vֻv:x9Pp7W_}u8vLB!`[uVqDDF"11~k.RSS9x J)j\ x" ٿ?qqquv:t:Oh?f`JJJj=Ν;˫qꉨ򓛛[^/۷oGu.:9KQbVZv-cڵbZ8׺_V, y} !BŰ}РAq֠3`ƌdgg3x`v튦iϬ^ڨqR܈/Vl8>Q zqXV.:ש.--=LoD4ZvBu]Vj[՗I!N9?0G@Y|g tB믿&;;$k֬UWRVVݻq\.:SMMskyLtt4{k92/[\r%.h2P1M|iqqqlٲVu:Bq2}(oK6r\_^N6oqd{ڿ q;3T<:sz9Tu=عsq_~lٲ YbV޽{W즤8=q۷/~XUC.>E.={|;//c{P~hѢ]./F)%C' !N ?|ʾhcHto륊V/#k~tF[߲~K{)5ZBRW@ŚCwS/]vѥKٳgO{ꅦiу-Z}vUXtM|!%%<HXXlذ &Tx2f,Y¤Ih׮eeel۶v҅?_~M1L8pֺ}aŊbaӦM 8>W_}5+W_Gu.;w.'#Gsx!hRtO}\Rdn'5+msW>NE}+ =_~q~ /=../?믿/={2m4Ҹᆪcԩ̝;GYEK{)(cʷoD s0O3coxX;7wOsVohLjx` X`_A6?wvٳ}aZ %::BBBjlqF6mDii)qqq ???rssٲe ͚5;%%%_͛7I׮]~=z*B^/k׮% W*֭֘$*Bw~ĩ].֭_~x<6oLtt4qqq5bmڴ7:NUټy3yyy4k֌N:'H.Bl6[A76mD~~>60bbbh۶muPqoߎjM6t;v ;;mZ#~yy96l`ӦMӹs:nٲ\:w\Uii) 0etWc¯coєX[u_Խ׃O'k.(evn}`/zqvXڡ̵߯hAaz) =-* kBWMg1+(}sرQmMӎ:BRZcrYgչ_ !ĉ*7J~[K s=QsJj[Gv5re2:Z'߉:5sBw@@1>B.KF:R~BI"N=vbرtؑ͛c2ضm+6[o) !i#u5!Ó)Y9y+^U{KKkߋעV;Mry2;ynGt~l;7,}/w."xH}܌&::,1[|h0. ,۠);oyj|$om};{Jz.!`2SB >Yk6ZFaw[w\yM;[iI) 'N҈]iO$O~ֈKz2?;zBFҞuFj.uez#b.IOPO~S_3"iJOFr1 h˃/D^|ڦ"o Zp`iYu=J)^4LMJw$U9jW뱪xn-eBP<3=mWC?g 3uT/oĦ^=@oIyG4WJ;utdنdV00n 1T E@,ddJS-t]lTLd=4 u}(kVu_~\Ji N ڠsQ16T_)(waշ=pL/~^uq^^w5P]P#tŮ;FPB'""x\9qr^uQ 1y3q|J.F_u~]cB 4}Qq^8]-ͨ&A&F\q[6F3̚5{-qbRo0"&dÕyzQ1\c(7Ψ|6d̙0dDqExmvxLe*]L2JrɶRjjTj UQ|~gu׶֭xYcqP[* !لfv-%LȈi֭_.,-+ΜvnXX[{1!p..B41WL𘓦89xȘEy1ƌOII yE@*GڨWII30WRRXldLh6 ^2ymLVq=)b9Q7<^cĺsM/Ua+sYQGW v\U笧ނ\4c1^]<` >\@޻a;/aekOz܉6}P t!NJ l}/80G6'۹VtNJZy<]]ZBG#Wm_x搷Uʝ#w9>[%'߉9 ;#}?ob=rҢu]YWb= lAsv֎mPk ՚E<׿dݗb+lKǗ:ӯmoy)߲B" Sd,W?H3({<QV?Q-jMB9'RtW w=Xk&m "m-=vUռ.$:ڲmТcΨ*Dc]!1NG8+/FuRw9Fw#Cl2yyF\f)'&dĎ9A&yt~31#bU7R~26zl#b.]FIz=qڗFȘauc&N}͈ Uot#b.IO)0u1J"m6+n%i笡g5坩t*vb8`YBVNb}LO DB!hB@B! ]!B&D t!B!)ЅB!hB@B! ]!B&D t!B!)ЅB!hB@B! ]!B&D t!B!)ЅB!hB@B! ]!B&D t!B!)ЅB!hBF˜7/Ry&*e&LaDUfm5YyLKt#bd.LPmT :*c.t}1J2qB6#bΞ=[޾dM S6"_e.z?`qS132R/5]_2r´]FLIID]&N1/HL3?z|bf. 3T>oĈņĔ6+mY۬BxME76s3{=J=gT̃{[ GWٳgoFFJ(e.z14g -u/[4eFt~)ŢYfy43xo-Yi1_RHGmV:}y-goϜ9eTwdֿ50fEW  ҍ9bmFu2٨vUڬ*foBa.-8>gՒ#1!8î` B/P U[ 'd*O!鰯>_ǾNGq}{,!+'em]!tأBFEq^_*zm Y9#BqI.8aNġb+ f F--B/+[V^Z^Vv۹uD+v:?k5 Y9 yB!I"8n[ox?C鄵Mm:cD (µ (U}nٸw;qݎ{\{ӆXT+`BI.nQQ_zLXbڦs孪 54e`Vڿ\6򶖲Mkq =tV$dr!Ba)ЅGt؃(G*` ob5oUմ0z!e{(ik>UxK ݀lÞoB!j]Qao\aEUKTӟC vQ?3 ,L1d"!xH.tRlv%X2z" "y?~(dggq: Y9|B3B H0?*Ikk˧5&kD|iQ{dͧ/tþx(!+gsBq]3TERyFc !#clN&e4(AA4W*oih`a_ {tgi(ݛJ,Vk5NSBq ]ӈaιg?ZjrtZ<>nE!2@\4ٳ tged 22fybbYȘ%##ddw3Y`#c.### sѼF\4+`#3]"fďT74wFFu´:mX9=(>NbfG 12q~gu#O2 Hw:7_!JB8BzIz;~ٰo1@n&ջn]`nk#bC,˼Eo\eTEiה.~ը_xxuFU̞Oн/H̨KD7_(Ybf.L~wZ1*fFƜ GmVfV#?͞ץ ߸N50^ !f[OCN- ;_!bPaDJ=TjBQ޼ƆNT)t°;tLҋݠT?\"uK{"ʼ&\'%%y{8kE=KSq t4UtبfRmT\]Qt^E1u:@5yQœ;{'any,g~ Pf l 1e+^o|L-֧QSs`>a￧M9Xa1O6tWc¯c_#B !N!E߼,yf}03=m0]{$ͯmw?yRWN&Ir\s3[pʑcu@9oa.e֒x۰s 1ϭmZ˞'cXa)&)Ѕ8^'d$w]FqtCnNgOŠux"#oןNr{iaXci_ JG ޒ!-Žwc5_^_BWNjB!N9R q q:A@Ҳ-Y)$i]\xSh$E_KW+N,^h$htPo]13e0?&uf5|lKjlǮ:߉t` !8}I.)r4l pӪA %d W/=X};{'61GW/9[zzYOK s3 dT:Pnÿ47U).~IOB!)Q\`K21G6&FrmTm\lO-8Hs[e[sܹ}>BРzwl4ayz/ Y9:/!MB{"pB|*tvolXcMR}|FZLav0۔_1M٦ $Ɔ`;9ƿ0H뼄B4R 9k3ɷ gETL[s=Gu’n&=pY1*s0?G!45CKe|s(Y9!#|8P6X[(Y5%?}f82B*R ф9v"m}/"wSV^ٵ\9aR@iՓ)Z`-b ]?|=V| .xH}#hȘ{FPa]BB!HTZEnS^PqV{&ԸQxք^V9\!a uzc-anE/-">Fa "ΗAi:!>MH!D!Ma< `&7b_r6 wO+N8f`m}h=?7()$) J}u xTt->NI!D ]\hB{p>0 휋}_x FwU$\;79UgEw{(oI!=)b= J#xuϿ25*l:L奸vn|NOIwPJp sB[R C}{QQU[ylewd!w35)˧>5-ogF¢HKLk"&Ły$e-.炧(=_v [KccQ&3 pa3!+gϱBq]PQ_DV?N!8r4[0?+ bM<Kxz4xlvkD[.)4 Kl}/Bkp+]S'vlF-hXbZߵznҺ=; uK(>F 9#(jE0809 !)Ѕ8 { L6G6'`z&&%6xZp8!Ók[kuӹW-)^la1!+gsBR H{$0|0e+?=kdyt#<}Bߐ]9P |(mL-_Z= MsJF:v Y9:'!'Br ?Ͽ@'8`8Z`/S-8a_\뜄B|R q{0¼bzߵ?AGxB#BZB!eޫ} Y99I!eh(- uLL~[i4πGOH>Oٳgk:B]/199׈ Ӟ@ =)qB*Cb.J^GgD% V ]1G>S_Qʋ#qRtatSJ'qԗxaZGM)OFO2>8@2`hF*<& f96{,V6F6KJЈBQ"3=mCkcCgJdٳgo^q zTˆbQ^nFKo WfKtKIIi bPz'bꊳpkܱ0C;BttG:_.WiZO)΅!B6[m!rrZ=@uxW!<~aGmlhn tѓ^?M&}˼^͚5kD̑#xCׇJ1pǡ1b\ȠǔQ4*+/?sLQq4.sFtJѓfF?V^~A];v?~X S~*ɴ9-\AР:xt;jM!j#)i/tM L?eQqS% SU'$7JfB4a @[ :nrN\eӁm1'{vܟ tWc¯c__#8ɊyNXX2ӶC"QSN#cw@kt!=N} /rꑏ XJu{!b;oxUH.g)Itvf K6hhA@-V<Ó7oߞ\PՏ".IE߄,TwSkB¯^&8zaK뜄BRFt[u<1Sx4׮'ga= sL;'o}(]5%kWQeCw0 xt?Xר10M2[=Kb|9>NI!I"hN= G(` m}vX3a c cE}xP/(^޻# MR&yUپE!#0af6o#p/A:xPB"4ApJU]{nH)EbMZgO_!]r;bA)z"+0oq5YZeT_"RVvq:քr_$I.Nao<$A+x;⌤mXZ 0dO!MTGxڔB ]q3MNӈ )Ѕ h0~1<c4x43§y q:Ƶϳ|BE tQoN= x`Du}o4f 3̗y!8y@t -wrtI ј<ܗy!8yGt5^~lzst3̠I.g)9v;v̈́OSΚ qiAUJ!8CH%tښ£z uZBqL t9.g)E-Nױ/1c uZBL,G[M!Ϲ.4~ =-\K,eB!N)E5>X@YQ~NK3./>zB!NvqY(ҹ]4zbGF\`AK+Ś 3=߀=< 6"(dݾa7>66o}y,]0yR'$2"抅)Q.R/O}Ɉo7nq֬Y^ !ln% -ЕQXC 2"Έٳg?ogFFJO\ Ég ܩk')j{C Rs t5TIJJʳC3,,co\&ڶϦCo{ {msBVΎߣ &kFռ3jWᥢ sw!u]RgΟEC;l0"BE5RO뺎׍i rW^ː IDATdyBj?uV#)ifޒi7*ME?G#b:w(D4ߨy5b~T04vJ 0Dx! ` cK)p{o8ٖͦ%R" \i"ػł^\~RlTPBUPQiDe-! ɶD& 9s泫O94Y2<.`?Þl6veܫSP 9n4&zjS?Wnc"8ztW3Ӱ zBdU6VbJ#`aUE0{3`AS@5Kq|9ެt|NjwoVt:(r7xOLNMƷP8@7w!D5yG 0?19u@E7cn_FН@g'&wtM, !M>B`5^3܊kV [p9>˄k;a,]!/E@\f@g-zBT=='kvoйxwnk  xj`>E#B;yBQuz54.Md.sQP Fb?P٠PbbiޡoM}xVs2~0hnWw;a ,`519U%BB~-Ѓt!@vYmrC΋'Sny{ !`m)a}%ݷLޯk 9+uG!8@5d Zܦw!D Zmغ֭C55 vOaABQ3N>Y~IqQ F}L]O»+mBzþ鰗nByGD-LDBœsbk"GbRہ-4|'z @uȲBVMo,q:쓝{BRRN=6v!⛜:p3E !D : aQzgB>,r:;vH^ 9vkirJMi/2Eq^066>#<Ɏ#ӣ56h̿nW@#cL}m#BT=90|A}>g0Y͘`o]NFH3(zߒ)f#߬UcB (BQ̍Z" dfJ{̞=Ůgs_ !DADL3P&zqRs6[-h9it [Ok j {w){VrQMag9կB[5Ud v@~B*Ϡ~%sbkL3BF $/97` +D'&{mqЏB`L8l\^'#vC!J14̉ UXBwR>WX/w!;58g`'\|s$!;)k#I*#Am.;BT Ct=b_0鰏9BKbiv15D,BQeLQNag!')kA >[ko&5R405lw!y“w/iI@aw'A,K`cp@]ZCq4|~8 _A5KzBSs!3F{< [w QCr;1XRN=7EDGqQTT[)VDk B!5G,,B!j.)k@?B!@= `)ЅB!j2)kPt!BN #@]!FAzB!@ #Ww!Bq@S}9sFS|Z?TNt_1?^!B3>rJmqQF~YB帜[ATA,P4eݼSoW_}1M~fr/3uk!Bq#ck352UNEԗ^4 _~nsjh$C%{@QtJx:R5j~5E; hFj9MBݡ' zU(o{ABuR@wCK7QpL Mu`' ?~+"蜸ȀaFΞ]Cܖ>έ@2E|y9r!&B Q,(3e^0 o¿'Kc&mN4_MO{>z_gq^>!D0K!({}18gS\ _ľ4]7Y{$绹D s6gI^|䱂<YRJQ6T[1) #QkCY?D1sϫglԹ|d-VMZzV:hY*%{O}Igi},)*q컭 =L!McJh)Qm. bŽﯪSÚz)!{ L.|9gZA^d-,o3K9g1͉biޞCǛv!BVk7_P Sl#wUmc @z(!%aՆ}@fU4_PW( sߥ4m[b0R1kHG5B!D`AKcTL1DýuQ~nK.Vr^/;CT 7?}.T KKxeqڍbT uuoVQLyKzfKl]iBEKhz2ɸA1[k,+@1ܥ/KO_%!X]^g|wvMX.hWY!℀AW?|yܕJCȃ)osx/(*y,e]=(qƎd/ }o1}X*uR71֭OP䬚GP.x3R߰gN|Ն/3Bo5,?Q˹'0Ș Xk'e_ޤB!?V$|#*LP3uhSc9GIGpǫ@Uދ!.P4[XQma~]HUx3Q#骒Rʢ|GaWGS^E%Uh7фzԛhUY!p?e~n[n9 DQLMH}_s0%4E+ǽOLُbB+,{ xQC#K 5/VP E<L݇5* | ^(7k7;_vi}Љ)N~#Bs#Cϵ|acGϩ#CXyk N>R,Ȅ[(Za>\טmkqڍ*u냢jl\S!9Ɛx3R ;|Es/'Slc ~0x,b Q1䬚w%.uB!D9n=)`) 9P!HLNMw:ɚ?gռdoB䈇I?Oy F4WM< i?b?0rW;:`n܊V7G1.2>s$rŰ9}VbkpSBS"G%oN?5 D򗤾 ZRމ9]Eƌ7 95$*)h.l?n!D-۷^HԨ*sbk_~#cO0)b%橏Q D~2]y|:|9Ljyc̍Zu_`ۯĠ M07ju߃BH?',1N$(G1Osd/&%~/XZtkX"v?[\zKW F;)QOyDЫn搵hZ|S ܟ9f.S&a.>7DC;{6%4%ojgl/:gS@(7cĶ-Ռ /}ΜҿmӿbK}%&jNmi6nB4 ME_j/y㧶/w}U Ay}Olt]6rr]NJ+Xb~;=vodPuTΓ_bms.Oη] !=hlZ0Vc\:h| ׊ZfݤLFOֹtҧO 1O}|u/b4mOy ۥL/8{juIyB6o1oƔvF_愦(fqк(>6Jt= au>^o>qO+Mɾ.z}^ENj !DZ@pie ݗ=z-?khn諭g50:z !KjFiS.Xt}\zg?׺ V'\K,Qh|,*P-0lmcL} 6x¿6 =6 E%'>#Ho 9@'I+}Y!D` 8CCyX-\pa-+ Th0B{WEtimᲮ<~oYkvg3YEA50TTUUQ *qSRM)תꉾO^jqOj?)dLET0?2JZ- VOREfmOWu:* /vRo Є \X$ofykaC;Jm|&};;%a:1kkOPVeCE+*&vmsxi%!V!]oQfmO Tax#ݷR !K.aH ƺ}rV~qs076%$gL;%u]+Yuƈ] wnTY\q=點'}>f{Z9- !j?)];\w!D-ѻwovs¿xUQ vw'w0ЫGcz-qpY9b2)1fE'ZCUfĽLڻK7CSuϟ& sdVq@qjnczgB*en؂ }qiǂZw&'Ն)q]G>Ipލjbjуu}:vZ5ÓsQbr/{;U>5B\pvz zj%|m_j2z.ZC4o_ylܠyUf̉% eN<1PmFs:M IDATq(*!=˞)B!wQ^̡}F^B!5赘aOD}J8B!@x b"H!BTF?X+B!R=$>|<)fŽ/21kXj <uK !Bp;zȜiǍ`ʺVzgB!pE$]<ǗU E%#B!*) P Cq+!BJDkn];N0B!zM匩j0nM;/6(}acZ ܰq{!!\M\;9oƔE>2iq*z~@{O]LG*Mh7^=B*vʹB"XU/ TߧaԼ |~vN=p(F!W¯"G<73M Ah_z}\'69h-G*t,`CX?#!_KBQmTwaހ7>\"^N]n#[B!j2)k@ScL};B!8R7 w!Bq@uw!Bq@{ ^an\8B!I^uB!餢DB!d@oIBQ_sh1D jוФazFs:@;hB_Qc1DR)Ѕ8GRlqKTkY"?11l3!D zv|z?B,Ң1i)ЅyHf;?B!-@ZX.hw!B'Rljxs!B?r:F Ew!B'R\QbDB!jj-zB!~$,ї3GSfĈ 9Obis) QB!3Ռ)O{}#U@#CK-tOyHєGUˀkO9u|] t!B@T^ jN tҔ)|a4hPD}S2.BLyYP\' 6]]؍?D$#B!̔utq*{<$ZsAB@ fCQzePlzBy=DW{\ oAc|U}-ykM?!*KӶغ]+ QCH^se!-zҤY.h4dS5Y\hy~?.<휥i[b_]j!(]sfC!ZwAQN~}Zovy?nzTS!P4F@d]!_bm sb|FGQW$Mغ^n}Yi(xR1Z`+ڗ7#sнJi jK$%q}ɂ?eh9^q=jX$7~OWI9@3S+Y_ @P.VQ@@B3z* !, e}+r'&>1­ZĽa2UC"GΑ>}޴D\Q7?w2_tib"b*|B?2:BOMQma.u3EKY% R.rEJ sܸ~}`Q6^k ߛ¡Bjts+y̹I\W^(*г+BӴiӈ6+4ױy.{(WF1[[/N]rE~> ܸ9A:ڵ ⛜/ct,P4e"ǎr𱁸Ec`߀B~zl[0-v)ʖdy|9PC"#8ϴk׎mRT"g+{gM8Mid/яE#@;w|WѲUCw{_t+A@Ѩ|p&|Н,*7B\wHLN՜F{-Xu;˥i|+ۉ 7ȼs!jɩ/Q)@BEmYwů7o#v4׮mX-^Qc$}cLf:.|YD CXW9_F@:^8@6[!D3g7|s<^cǎq1qގq+̍Z.`ҧH*F>Ȅ[Z0QC |> %("}4&ۅp£KWhḜ[Ȝn/;[~D{+9&!0SwRlۀB,JBFɌ1yGt{GyzSN9CR^=J+'r#tvF{wq'N;o7V`3*\(;?C=PEhBQN5ߏy.;Uꫯ&;;QFI?0ݷ(&vi@Ϟ=8B?[x}/?G,B՟I޽`L2Uo[nc(Bjt;"o7{!))#Gлwof̘(B~~*4^4|{~),S`aO@7crAS7ȑY^PnD 8ϧUU>R^0t[e5z QS:t$Gnݘ7ofYXB!DBb͘z_G.@(WSUm $jg~ɛg@W4 OU@#Gfi =E3p~c0`df q( β$&~\䭕EE͕E>}غu+[fɒ%K!8+AvMm).]wS6?<^g[> ܟ}=:MsX@H Dkaݺu4mڔe˖]ΌB!DMotm,-or|zgR\.~,_Xc !HLN, Zq0СCYt)111,_ K!Ѝ_8;'&w ݉b;g7n_},]f͚KT?Z"@;/E5@OLNL,k_wޑ8>P/^L۶m$IOA!_ feq3K5P L?0|V p%ITQCde԰ZBH䆄Ֆ}!͓Uʹ^U[~!jc23g={;&ѷw!xh-ȜhΉ(77?}I!(RN3lYw!}G}ɐ!Cw!:u*|7tAHB!DS\QpʱYo~Z7t 7K~ tO2i$f3ͣ[nzGB!j/--;RWҧxvk]\d׀;8Ͻ˼FfΜI޽$BJ_9b-ڶa7D<٢s"q>4iO>$2uT w$! )>QzĚ[crYylԩw}{9RDB!DyAAwCfϞ-܂ik~zGx3R`UIxۈW!Uz3fS|9&`Il*; QSԌ],ok^xfa5D#@ԢE9r$^g}zHHBmrkP&O cG=DzI5e> K!K}rV}qS%r@.=1S⯽)s1C!rzD {\vy?~ޑ8ks@ɚQ7?w}e/VI@xRV`Puk+1pJƧI-x~لz'P,;{8m$gȺc(ضVǔt}`®wq_ׯz뭼zG⬹8]kۮF֢iD 58JgiKs}_PNnsbm 5F[zB_]b޿?QOkcs@[>_ANNÇ;` .$u\(cLYwY >G{2g~-f9= w}x;ֶ]6,R^!ѷ@MD;{ ,Ƶg;FX/AX[QSm-x07jغ^[VN߃ДBw_{v"ƗbρA"ݎ;ի\wuL>U ͆tB#ruC;/+ o|d/)>WaK$sd}=M?O! u14N5%in7W>u)u+)k#w{\y~lрŊ߾%g\0ĿqS_›!, _A.9"绹D|QVa*}|nJhkv| xR9ο{]b2c픤wqٽ{7IIIĬY0ۃYtt47/|٫ 51cвeK]嬘//ȑ`Oڶ+~$Xv-ny=~#&W*>)ѯ!"opv9֋{Es}^Ryş>Ţi)P6LXڵ{;ϱYow,r"G%));wҾ}{-Z&?z<n-Zw|e[v-k׮;}Z*s H{q[~>F+~ǵs G=G9yѱ%)&3Ws\έy3R*tz/{ #sz}D ތ|MĽ5fM+l_!DKs: :Lömhٲ%K,!<<\X4oy4,233)%`&{ٌLMVva碻)jYׯ9KȺB ){e.g09Ec~a7u5@?9@T G07﹄8Uaa! `dzb ~g筷d21w\.r#۶x]N Ƙ1ct&Eu.͑n܂k6̍[aJh @Uغ҉/+HW/M1Q,V [fc:y%;< kf !*0")U_J"jLIGuaKQ3~S&s ~8k/$J.agã>ϖ@cGF"AX`AJ) JEG,ݝHd6ٝ 39DGG7дiScO>Cb٘4i;w:Rˉ )nhT?OLL N+ouS[^re"I|O{_![ɘ9ISm +uQJڦP2C2?L٨~2?'͘޽޶ zMLz%94<3ہ-< mKq|4f)W6qu`3'3Bxn7=xx4Woм@B0 ٳ^:IIIlXaҤIO?w',Y?˕IQAcw~[F-Ch HuȜ>E35h((j?.i$A85tA;~(.lZ$U[|;7(nUc^Ls[ݳqkLwk5n9PRWى~#9.D9re;S]/yqdF4Q1?\[T"<)SvӦMT̙35o&wՑ*nݺK?}epB.;wH D/#❛ :}vEx~^xH[nիWrXp!5j԰:BqLKbZLdYVزe޽;EEE<ΙU|>bccYt)guɜu g*"p|~`3rh}獂\vz_-d]_~o|.Fauf̝;5j:Bq\ߠLƟJy[hzM(k9'3U&?7ԩٓcǢej}Q&OLxx8 d^!/tFu ǟu>]T>B۷ӡCΦp<{0 LhkqJ< xrZ8.33 4ӧɂ ?b)Сwm۶̘1iu,!/(Eީ .*`)gkDSףoމ'F/4KLa.ff4QA=#?PΝ˥^juENغu+[fܹUkQBT"!)x7v?0RjQ Ј, 3h~vٰhz+ |8vSҹsg#˭ʲehРԭ[XB!AFp6Ҝl] $ƎMNQZ3 >dU R;={Z% A?>j"))MZK!0]7趐0&=TQEut*BBλ{VEڵ+wuUZ?0SN%""ygu$!L~U?(ڴY3k8Wj-; %&୰KPiVF" |g3{lXV!D f1].]7>7R/W}YsAMZZG˼v뭎$Bo#@O<\ w=)1ѣdzf~J[IK7!CbtnqvGVBJ!~ucXE35FQ{Z3`#b#!D zUr{vDO;ǿAcZIrrmyyǭ$NCΞ\4|ejI5&:)t]\xjdEfz5'iJpTL?[ȇVXA)**⡇W_:8PA'hťwܞܲRb :G!J|` ~]vjx}+DlK~_80|'q>NLL ~|'VG&9<+s!D =цqe~_A唨ܽ+kyy(;vCs73~xI`ŀ8BAuk'\f𧧖Cr{Sbfkbiu,!LJػw/ڵ#!!#?)Ș~.y"U%laӭQf\nL 4!233ر#۶m㢋.bΜ9ZKx&r'RWA!Q)t}B­Q-w53a|nf֭[GYp!QQQV&˘6hs۳_JLt_`mok)j?\YiE[mh.Rb5\QٓHvOE֠/9!y뭷p8|WoHK٭MfL*0ʁn 4Ҡ !LTJ_ t.FE/# JFbQ'ٻܞ^7Ț1ҬM Q&ƌO?Rqq-XIgw /ɄȐͪvy0ufՌn`\m}o7Bd۬ѱAF)}tv:9ݽ#?˄s}L3k3Yrp6[Du";a0ӹ裏;-N$ʊ@YF4 6v6СC `YJ;p5Bg߻zߠRw1r3iyn3-%&:'>/Q7:%''swyyG$_hj@?cZs.UE>Lu#ZPA!4qi?ꨖq=_`_:Oуb}Qju$Qr'{^@ȊBc ho|΅9kY pmF4FnQ-r{ޡdQ_f:6lM7D^^wu~xƈ 8e>y\n:+!DE /}?A#Y9⢣1r2~_yG 8.g p W9VUPJJ ;v$##]2fT *gftq!H3HBQ|nuOO"Q,"۳h/XOt<۷:o>ZM𗻈ӥ yˁ-N$^7Ά= &__x?\..$p\nj ❛ȍ,ZeddЩS'RRRK :(#Է4 ȹuBqA}yQ'&{^4B[K.B<=A`{J!T^^7tׯe˖n"##%ʈ?;}$ol cq,!FX~qmOoyV݂tRb/ήVy5u20Oqq1={䧟~I&$''Svmc2_wO @s$85'ڞ7k/_"x#,3 hKŞ'ngta 0;HJJN:$''ӰaCc2Rq%{\ڜ\!UaR5kT9_ܞ57rrA<"w}L>jժpB5_D吷l?;`pI8BT:A'\nϋM_fctMVG&398z(kKO 2[]nGGBJO*ܞ!@ `4.ڑfuD`+xFmfq"a*O8v }^?$ZO!fQ{Hwr}ep=))1ѯOesC%+|'tEɤ3U… ;1 ^{p.N6@1K9ŋXзҲXBQ\ݽ:Fr{N~x \ayx>{o%.8(o?#={O /XB[6lnOQՑ+s3^+=`0̶0BTYנӚDYUi.۳x"%&eJ.&˺${!Yk"%첎8mmXQ֭[7L~~>w}7Ց*{(X5KWMdۉ|e.'Y0W> |r{- &"tgi/fƏRٮQs ;/+eݽ]n3j'O*{Gh}>nr{//Rb[wmF_9ŋ8Ke#!_PGOM_(ܸB9oNN̤G|(U84:|ߟȳɜ vEgB/-4E_LޒYOeG7Yg;r C'NSYS&\mg},6ܩj{UJwsgfH?\C;:tP#0/$ZbhY$zנWd6xFk.2|;fzjLi ЪQF}4x`ɬr{D? rݽvmd [X$ $y\͈mJUn\IUɚ~GƄ7~"o [hw^:t:u*vXf#+hC.(u ZB[_MPlx] 6,`R_c[nz7gsgR3l`a( `5}_6m(x%NXV-~ 9BSGlZA4VК!Fwgh^Q5Bmʹ!QɅoaSN9?)hp9bkewty7֬5zMErϡh/nZEƕn#/e!ay@}Jr7պ݋Fr(ر#]vf"88~٪h Gt}vܞ{Sbb@g߁s4:zq6nn#TX$(la"Q \4wmkGKˀ$`9<=fd aeVM#oFhV͚ g4Bg{cOe=5s긦}4=ݍD}<;=N']nOwTT)1э(i6.qQgF86QNlaQBBQaPlC7Y5;N_zKǑ#x#(g7Zp6;r 7b ?|.]J͚5U{'~$C?pfRҀ*J2gH^ws IDAT oXGQNL\+GЅ\n.C7RbÀ)i/.Em__֑Ռ/w='wJL3[-=`moMn"wΊ+8IJJ$ K6=N#[W}JLtМfuVW u?r{2e!(cҠ2uhݲCRbkMv;~ǎz`.ggJLt )/oܠes mՖjv[>~nv[իGrr2׷:Vݠn-WH*sJ]XS\:p={Rbx `Q~ q4֚3sLW… 9sUhK>4!*"ܞ}.1@_ ezcƼyhժՑ*fZݴ-'j]r{?=s{8NfΜUW]euJɟ)9rB!6iЅ8M.v5]V9m}/6I&ѩS'#UZ}ABA'>>~(i{mqJ}x&BAl(9N殻0 z-luJh믥mv=VBA$ǜ3mٲe O?3,jϞ=tЁT:vȤIw4ta>w.gyB6S5S3K Q6xF ۷/-⬳"99zYJ]4?B̡rB" y (+ X;P֚A1k,j֬IRRg} ~ɴ2BԋD'NwqKl?̨9j(gj{m23j$Nl5{?']h8sl3j&NPK;7kmfLHH}ؔܽf."0`@59NUll?ͩߋV{v\nOJJL+>BϿGYsiO< g\p2&?=`90Lj>{dM#͌О}L1Bvgpb!{pY%DݬezذaMHU mKDĵ1&h+5&ASJw~i×A)F5jӬGjR|\=ft jǬN_-GDJm};Ș4ܤW_?$((Yfq[*+XY}&dK$$VL15Yuzڠ+iʬ6eV:taFY =yͨ 1XXdZMjژnVMC0x`YudCOV~ꡰ~3ЦJ+jqfs=> ҙGB3ʞ#GK/aۙ2e 7xcn_~޼ ?p۳Lk>{DMYػh@O1B8 rs9u\S`qE0!!p[H8?p'O_~h3f ,mi}td䖪)%&z1оn[^bu!D9[>Wv=Ovre 7 ΝˀZJsn9\!]3їa0 rd#K.w|>y|2َ8o=g @8B Jt!ʈ)zn\zc瘺5kp-PPP믿nj}qr2&'3/8B Lt!ʐIvn\ɾo2-[ԩۗ#GRWȘZf[I!D' e퀔ͫ\/gTs׮]tCLL &Lfݹ\iqp=3-N%B'%MJ?ecǎ矴mۖӧt،GWAi-\ni !ڤAܞ=@{{߁}@}']#;;Ν;i&Znͼy +⟼{RXgN8tp=S-%]rr{SrNhß/u -,,k׮/4k֌ RZ2,<<-\nc !dA\ˡ^v?؞%>sw,Y Lݺu+rgeC:#7 `6pdB!*#iЅYG0 ZNk3gj"99&MX**X#ۯG.lBQ9 DUr{2)1$LJ:ONpĉvU~'CI5۳hB!*9iЅ.gtJL2`wOJ=u&['$88ٳgs饗ZgGdA̠/tB!iЅ.gSJLPO'Ƈ1M1w묎X1sƢ 4r{6[N!DU" 7 s]Ώٯ os[YRg5}$YsF 1O^v=M'*] |P+bhpyvy'j1fm,NZd_bk`Yka4!U4BԵ4JW=Rbyad 䆒F%dOV9ϧ1_ea4!]/%GpCZJs=5_mToq6@ _d=}V!NVAZNolnmJQ:ͼ*G 5dt3w/(2 Q@G_c0V%Iz̪8[&:+Gk6L6L{/M(M(Ϧzd! R%yC`)˲i)uߥD? zw6L̄OpiD5~E Bb-Hƕ.Sz |u=y__ٿ>{rB e{c5s긦}45#HB¨jM뱑k:ti?F_g.ͪ e˦7=<92;,Z{䨘;_{ll,.Vi~OVe4HpoJ]:s.Q묓yi1)N@o[OQznA}<r{rY& Sh\-D|>`b|Zt!ĉ)B5fyG\&%&bJkV@ߗG$蜒=uA p6j侃5(޾XMJ9.'X QAj;Aw=Ov]Fq)t((=)16\͑7vYkPf_YA8:5lQ%_âcj#W;vF^6FnF^֡}ӏ2uZJz#$!TA)0PҜ* .}UxJLtִkoq?7E'_Mx׭ !4BOہlzys=i TXJLt(pPЭ)|unYG?G>r{R !Lt!ʉRU!J.d쪵^mqr=s!U !A)8"d(%'XE!U4B1=J[k=DB!dreH)M,h'YI!N QFRaq$!BTҠ QR`#+GB!D! &SJGɬqk !"])R2x-JZk+3 !b](@`Gk6B!*iЅ0R:8XtZYJ!4B!T0h l:ksM%BJt!΀R L;Z֦B!DE& I)ed 蠵mm*!BTt7Æ 5Qf( 2F NZ{^O2TQrW_Bq:Y~͚:wM2Ǚ6)qZhg洸f6lmf|Oq[gU7nbZ698+>ZjN׭U&ڬ3iҪE]qsͪw٪EYSژUsqwj$sԸͪ9cj\V-7TSJ]kK[xcVՉS6&$|aVjqWUSYgKU}xjB√ N笩 a3 DWUn Sf5F䂾sToFM MuCsY51J_nZM5jӴG2Uk*T^8PdQJ= <x^ZeG>4Ҩ P4wu -P@oVEge='RvV4~Κڠ{iT7U3f>w-@QСC 3jv:0ж˵M]-ͨ o;¿0fVzӦ5fw-B +5lJwF?U3x^GͪvyJN@Y^)5x0/;(v }e>U5Kz;ǙUSYgKU}d>+!6Y5s긦}4-dBTJWxPkő*%&z1оn[^bu!D9[>Wv=Ov2'A)u#0i΅BQVAR =GB!D%& ǡ:cC,$BJNt!Rl [H!U4BRLvk֦B!DU0HJL焨ZS=Įbez~J: Slu!*0A&}L%F9p.B'S!#h̒B l`CYC!R"Q!B!4B!BiЅB! Ҡ !B@AB!"H.B!D]!B" B!ԉ"q„ZV?w;՝RDeU_mFMH0&YʦǚU3>?idV͜:~eSͬBM)=o&zjqM=hzOyv{n!D)N:EJLb}8Br|>r{zq;k!B!r\2'5?ou*!c{"qVB!0]8N'o|r)XFnL2pÉOyԾb{R(ں+BMc%v:4˶odg5c$EWxƔwuhQ20l?;ݲ B!*tm}5;-4^Z{5Nov]R^|-{>Hךݜoh5@p֦/N~ŅW^|]mT/F?e#zÎq6iF^)أjI!BT~AW6P== (޶95iIh-6jvA9s2(ڴ_Q"Nw5S"tMwsƠ Ȝi@5uͫ ڴ!xlA!~R8|i n2 Bʯb7@>-i m}5*(>KޏʵA/|nkjQ8q!]{ZL"Q,Ϣ`bS~#up68gs,"_di!BT|A?9/uQ=\w6rΦh1 qD7֠.(#kH 7`z 3~7M(ڼ:Ļg; "QH-Ie<{gYbeL~T_sPZ@o?m0!]zT[Hč}]<AjGt}6&k(]JI%+# t^ܞ{RG. ?Mz**8`_ӕЋڟ=w,SΧq6jvt5K]4-k>/gS}O7ʘ<5Kgzf'I npmy5PKLxj?&Rwڦպ߇r=L΂_Ak>~uz/BQUr/];[z<{ \l!am/m7^Ż{*8F(\LU<9 2};pu6jn\Eu^`b984&%z"osvKK( -BPm^C/[|D7}0uSj=ZOQ>#7Mn^2K4a_ͧ6H9[KN)Q4GKxu5c^fǟm_O 77&+sr{XUz}* s4dk)wSeNszs7ӱNi:NM-Ԝ.Y8Z )^Aٷw? yGˍKڿVHBxwyq}m EGշ$e ">mj@UY_?܇-i0 cf5~Ҵ`ރKvyu~iza(Tg'H@W$- 䴸eU2K>hy }JR#w|& [8xf`ܪڗ"};GⳮuK,}_oy/x٪Ht@,QT|!N<>sVc ŷBAȸ#$JCUCDg{d#9" Si 6BjcZvBށUplk/D= (*ή~E쪗~jmr`0.|>Z )ZNC:tiAL\' yKaApo2{o vzߎ3? 8rv܆wP8s!z\@J Ҡ.*eb[7@o$ĞTc܅G!56C]Q8*P}lVY^j{(^J7ݎk;L)L~g޺V.uhkoR/ˆ\1 Wci}kxOSVs b 7@pe7{cLo6܃9:Ln!2>7!h<4%-iP^))]vW1vAf ԰("B0tӮT }(P =cD,?O.#T^}.( Qp噫[MD]'[ޙ#'g)+fhvg|zMs^Ux G7zkދR% """a a;U2B@kR;ygsŧ.k!r&۸N3o<5ZKAP8m]IM|k(#& u(I] Q T6ƾ߻JU‘wd!~H-%c<S56s a4!t֢ ч %(BzK#cOYR}WS%ODDD}/v[.:SF\-™euEJM|w{eSzc>؞4U6o@ "֦ծ-i s.ؒzgBsk߄H,}Ujp}H,صg@Mjq:J?\o#k,}o9Rxm,D GW>A!Ok/>̽rͿ:g7l6?/?إn`qϟP}`~IC?oQjX$#&!|ޙE?6.YO5(7~z9JRصg[$ +Pi%*ypf9q>{jP06xP )u^+P}p0\U@ A s J_GծLؿn~~knV]Qãa7:8&]j1iD= D*pOksCt7ļ/UPs#b^{PQS{x*!%W,9'R=G)䇋-ߘ&|{mڊ "Yp*)Mr"^1K oX|y5\/*ͯn)U}NB, ^hq[X!+[+ _קl%"%!+l h;SN/e5 ˵7q#N_Io.\x4iiU^-$E 5M Jl# zŔ ۅsmbeeX.%6*T+GUw=bw=6n>QEDDDDD~ :aNDDDDG]Y\"Q@{CJ,0-M]bI!E$LMGLb}Z1C*֥X@΁Ԧ&No1׮I!R”nX؛85i1(=8ŃH#溴)5)'L\kפ 2[~PS]@ 2X];J[*B$L4Y3fuAtB -C-ZK7^mp+$Ub t[tR+ @/zŭKJ9 @w /rB(B};iC kv^qv@B11[cccccƬ y^H9ӭj3E.\šeR`bt n0U3UdbZ]ʋ^Uz3am2Aʰs[j 09,:?]r&1b~*QzL5X*& Ftaj{"Tbrr1+ֽ`{Ԥ8:CDDDDD>-50.%""""#LЉt"""""?ȏ0A'""""#LЉHIu!"""" x=۶/DDDDD:IENDB`lomiri-action-api-1.1.3/documentation/images/platform_integration.svg000066400000000000000000005462211455542516300261430ustar00rootroot00000000000000 image/svg+xml Action 1 Action 2 Action 3 Application D-Bus Platform Integration activate() 3rd Party Application Launcher HUD lomiri-action-api-1.1.3/documentation/images/preview_action_signals.png000066400000000000000000001746151455542516300264430ustar00rootroot00000000000000PNG  IHDR YsBIT|d pHYs B(xtEXtSoftwarewww.inkscape.org<RtEXtCopyrightCC Attribution-ShareAlike http://creativecommons.org/licenses/by-sa/3.0/^Z IDATxy|Ld QSKmUҍXVnzmuUڪ.)ZXJK[}R"eC3W!8i9|s||ZfB!Byad 7F!B;7P'`cB!EG%!B!eġ!9vsJB!(]@o <[\ T)ЅB2E!BRD t!B!J)ЅB!(E@B!]!BRD t!B!J)ЅB!(Egt!D Zp^+m:}}fd.j5)]-?$QQQV[?ƞ׌Lea eT;pxiEn.vOz r֌/ݮߌ؉s i<֌̿ZTGٳziF %nga!O5#3<[feJ>+}VY9.-Bz.dYT֜4-ʴ.VzĉM?&**BEj?[9 `rY9w ZPvL%~XkWZdVhd8 4-bQo){*b2 B`N/+}VY7g@55|v 2?ԗfE,h6k> 8"괋}fdUӮ-̊hV(Jfe,vJو#rG1[6a5- 닅fE,jĬ̀a,ҊR/6+WYgoϪea>@l`kl; !`0!B!:2<"gЅ( .pɒnB!wDILL III%ݔUNNk׮ĉ%ݔ"9uk֬!;;ϙ3gܹ3K)B!,.DGGs)ͥrTZ;Ҽys3yS"##ڵ+ӦM+elBv᜜?35k,~? _LoJff&/Ӕ)SjժѼys7dϞ=?޽{X{n.f!qѣG3ggłf`ܹ4i҄ӧSJ kҤ իWM6%ֆsN8&L t?66N:9-샆B!ĝĴ])R 777ڶmK-`߾}8p&M8?~8 ={+R~}*UXo9|0Gˋ PlYҨR ʕזʔ)CժU$11ww|siۇ 4˱ŋ;.BFFF%ϟ̙3xxxPB|K, o6Gf,ڗC5{0]>p9?WT www9ue˖u #\ZZ4jԈի_qqYRSS\2_vNNN<7뮻puu-ΦJ*}W?HHHܹsX,իG%&&r!Ξ=cۢbϞ=SlYjժE:u/!B(;:;;Ӽys֭[(<ѣINNη!CxKf&L޽{˕+رcyGذaӦMc_-[+c+/@FFnJ)ʨQZ1`jԨAtttkڵ 6PbE?y|A?CѡCZlɮ]سg͚5+py7صkW#G'txb/cƌa>| |AyzƜ9s3gc8\a„ >|3|mPJ1l0bX =OǏӨQB5k+WO>7ԩSL0~s^BCw~g \I&L2˱ٳWpԧO^k=ڶm&L̙3Ϙ1B!(L ϩ$''s=0l0INNnݺ?HKKgE|7\7|SvmvٱcG}~wO\ɸqؼy3>(={DDD_RjU'SΜ9kƀhӦ 5jcEƍHJJr ZuVʔ)C֭ m[E;wfbsߟp \*<Ȯ]gw~p߿-Zzsy֮]K͚5i]v튻;6l`̘1̞=dz){9:]6lH ]/w1.]aaaaC~~~8;;|r,X =@ ^3׃ "22ٻw/L8O>{~iLjj*O>$#Gt,*tF777zߟAgGÆ+pppM6VZ 27^@IKKC \B!f6C9s&!!!׏ǣf„ xxx)gǎ899fp'ZkDz{H׮]qvv.t?=˷VZԬYЅ;sNv;w͍z;sNv{W&++={:9;;ӭ[7ɷƍ1 Ç;܈m۶a 7p山̩W*UԩSWb0}tf̘}GRR}=z`ѢEלp۶myf6'n'++cX8}UVba׮]l޼&Bq9Π;vcǎ`*UO>ۗM)#77'N`󝭽兓~!֭s ٰa5/̻rر.KwKsWTMζmlݺJbb"^^^m<+V@)U]zbŬXq&6*U仰 ywڵ ^:nnn=z5/t̙3]lϩS/Xt)ӦMn;} .MΝs,/믿? 77J*aɹj^5SL_nݺ 0^z]W!B2@ܹ3/TX@[6 ͆[7|7 6dϞ=:uku͡YYYt%b;vd߿s! /lݺ6oLc1 gy:|0{QFbox~ɻسqa[=빉OyWiܸ1&LO?eРAWܗ3a8>0݌)>/ooƍ_>Ç\rp"eӇ{w rJy >+8J!(L]]]kz+qqqrʜ={{2e\9L4f͚s=ww}7?#]t)|SmB!ĝاY^Fbƍ̚53gЩS'*TsسgÆ sL"׏srix޽;㏌5RjU2228vsOy àgϞ̝;SN1vX:"##}GjnJjj*]t)tvi֬{a֭1j(bcc9s&IIIt1۷aÆyf+|}}9uVy5jD݉aԨQ<䓸˼y(05j>>>4k oool6?3V.JsAAAlݺݻwӫW/իٳg سqwwѣҩS'M:dbŊq6lOFFK,yT^4֬YZ!⦔Zj̙37x `|vo|7\O|޼yl6Ţעb̙[:N3z7իsɉzȱQFG>}=믿.鿚nݺgVZիW'44qADDDcо}{ʗ/ѣ:u*'Ntz_1?X^^=~wfQ?~oߞzVٳg9u5j`̘1g co6cǎ%444͎駟f̙k̛7+>ˋ_~$BE} ϟ?ϡCTg4LZZUVaÆԨQݻlZhQ`ݹs8rUVۻGraN>MJqWgVk$''ӬY|E={ɡiӦW133}aZh(;;qiff&޴h"߷qqqݻtWN˖-)[#Ã:u\޷oiiiҤIm<{,G宻*0N>ݎ;+WVZ ;^WWW:ıcLjŅロv]ŽAEXgEB[Btdx t!Svv6%οoV\ɨQnz$aG{u>Jnh]+RGkjEՉ[KB!.@/uC\͛4i 6jժo>N<C )& :g @PpS7n 藎vƈNBqCJ,.B\ݝMr 6l;psscĈ̛7Æc:##U]B!%gEֶmktJ]lWeZeB2EEռc=+C\E0ho,TE7H;ՔR]0u4<:qDSY`Ay#Mh^ae״LCk0#/W iϛ͸^^CZ뇀Zvjvg PM)Ôc PAm4W:X/\Ө %eޙ}85| }R qsciqMRZ˵Gˁa]CBBfdv:VtQJ=0_ȵXizQ_}"P.ǘR[ru8Zmݮl 7<E`dFyn_+X,uh. PL;;h7(׮.#F1+rgo>+, QrdEqUGWy ']^guBq#Y3BQjol!7C t!(иw}!(e@BRH6-}\/.Ba)Ѕ2 L0 >B\p"( J1MbB!BQFF>uB!n qBRHaB!BQ :9lŸ ۟BQH.?mŸmC!D)#B^ܢB!nBQJYfuV'E+R !D)Y̡(f !(@BRDsf)6^WBRL t!(j$.Ap&b.xvL%xH.:1I+hPۯ ]A:1Ir9!H.ګnI)^2 xvNW'( !0 :h{m~/<]+C(^uq)WfJB!҈͔a2f{,hQQNjlF&@tDD OM[y˫3#sETX#֡͘כq9m& . RZ?s,/ fikeו~'5f@k~mF&@tDAپ" rAO0#Sg,hwO P'&هYg}Vl鳦q1}Wv2-6Q*H'ި (5N3li-@m@"'A@ʴtQ u2+rZ hkno2~NikYNև@?2 kZы46+W&hh0+S+}YSϠ[,6ՂܬL̇ v 6FcxzOVcQ˱&E'(*hJ5ɞ2bĈr//)x0b_fVjJcؔiw@t[\~vS }>YJ/k}r جLgH>+}Vgղ0 6`PYBr qYJ-B!nLtdxEfqB!]!BRD t!B!J)ЅB!(E@B!]!BRD t!B!J)ЅB!(E@B!]!BRD t!B!J)ЅB!(E@B!]!BRD t!B!J)ЅB!(E%!ERzK|FE2l*%ۮ,ZYrѪtkb!7=z6XiV 32cc'Z&l aF&@tD wfe.G͚9?0pd+jW5T;(8Ό̉'|k3 zbhnsֵB/ˌ̨0O'; )32CCC]? taa5``22}m{\=Gd)}鳭gxA; [nmvkW l IDATW 8}=ggM\ojfڔЬ̳ 5{\mc&NhJ{B+Z+(zfdJ1jwaVvU&k>Rvք:6Ћ 2+jSV3mx׬L ν4z6Wfeb|fʨ B4`:}6l_y? Ñ>+}VJ-5}]Y 14+44?{bQHH݌@ e! [̋5Ҙ¶;Q֊#F1+r^UgbjV ԯ"9xD T.#ά\BsИv6Fgk@nOmuV'E\u gRgղ0 6`PYBQdu^0QQQepǖ-SˌLOwv-zѼ 2h(57s2Fmke{)Ֆ_҅fe. |QfeFG=`Y;o7+3*rV:jXe(-Yg*}Vg}6ϖ>kjn(2ԟAmY@R:&ڀ1)02t f%j&SrdʽF`3hV1v__ dY\l.9f賷ϳ{n*}Vg}6ϖ>,"gYDX32++xJ7N&U_,Ϝ{L0jgUncl޼ʋ/W-^[Rvrl6~?hR wZﱐ٢eaq"|Բ0 6`PYw=5@IW'^z;HK ʕ+o*oe„ _{ypssŅ V+CgvfDGG駟bsŒ3X`>:u*s{=RRR?Ǻlf͚E޽ݻ7>dffyG *x=YBBSLW^3gǺӧO+#0d֭[wvn޼ ~ayN֗7k?m۬\O?q| xdܸqu;wtoѣG?|0x=\Ezz:cƌahB oY`:uʱnԩ޽cG}+?믿_AdeeȞ={6Nb`_ŋ<4mڔiӦqFƎ7W_^VZ| ,Z0Xp!1}_TT Bpp0cԩSY&| TXHnBzغu+J)z-rrr]6<3jՊiӦ_5kR^=N>ͷ~ˠAxzz5k֭W^!==>**Ubڵ >?r j֬ɑ#G4ip`b4jԈFhѢ|E/iܸ1!Ҭs{ܹs$%%OФIƎ˶mx71 |L6m+B 8x 3f &B"]Qj/TPFQlYGyVX~JVKg{cbbe{_~͚57|x\pi޼9[laW,ΝK޽yKrUP}ѨQ#>sz/\ๆa#mٻw/~~~ԭ[Arr2_5III˱{udl6ǏjҼys6mիyڵ+[lq豱̘1^xrʱk.vɇ~H c-ZR3gbZҥ Ʉ:kժu֥y|wlٲE t!D]QbZ_agƍՋ={2l0<==9rZk&O(3228w\%97|~{~aZ9r <رmRR W9rǎ~ȷYfdffNf(W;vM6SOm6 ر#olْRRRhݺ56kҿ= [.qCѶm[uЁ{AիڟB,)Ѕ%Ã_ڶm lٲO?UV>,իWwܙ-[Ƨ~Jll,1TP &9NNNoߞ|kԨPL"k 矯xߦ]vEvrrãVBZnMʕYnYYYRN+9quubйsgl… hݺ5~~~|gsN7lڴ}|Y+V`Xpvv.Ж˿(+gϞͷ8;;:#j-xB&D4mڔM6SfMӧiڴc;0x{y衇ؽ{7۷L2=z@Qw=ʕ+GPP?/ҤIϟbhgg|4i҄q]XQ111TXl)W.====z4V5kZ_&MpB\\\ pXrJxǯMŊ9t6}'!!޽{퍷7'Nql׮] 6lp۷og̘1;vƍsE6mO!JB1p@bbb8p ]t\rYN:9؋?r߿eҩS'9r$3f`k׎sѮ]; &鉳3tWWWv}O?Mvѣ;+r}1e{#FO.]puuEkͿ/^yƌC||oҥlܸ=,EVR%OPPǏgɒ%$$$0y俭 %V>+y}YSϠ;͙_2 Z||~8$$nFfO-6>O3(:6KUE┛GX2=q°n(u|Ĉ9f^NkKlk2s-ްlYs֛6ߠ,Adž1+ׂ=i_Y}vju^رcԭ[/RN*U[oŊ+_>ǎLJ3gٳg2dkӓPlYΝ;$&&ӬY+#66ݻ/(>}c~HjՈٙ0*Whٳi֬+wuaaa%rjժ9q1fGoWJYy#ﳥ.YF;w>$VZƍ 0%f͚l߾/HZZ5#`X6m{fqرS$^UҾ}{Yf l۶ ]IHHgM*U9zvPbˢJKK#33ʕ+:zeffWNzz:hwON*||BQtdxEΠ !RWfAժ7vOS|ySF:u ]oic߅N"B!(E@B!]!BRD t!B!J)ЅB!(E@B!i"oJ B!-I t!D7 Bܒ@BmmI7B[BSYԭp':S!Z/[vҼV ^oF zw`fdDGO<=:>K\32E D@a{wS\ }6#sY4zO'W#=a{~?~ڔ̅jB}wPp"B(o;O7MC_č <"lVF?~832J#}VYgKO5uՓP+}VY鳥Ϛz])5CkVzYrb3vG>!H]>JJOhF&ּ s-_Via7LtuO_\)#F䘕{9h쪫iاlEm7ḆfXmek62 K\(_vM~լ\z^k+j0-S?I>+}Vgղ0 6`PYBl *!1ёq@HT!nOw%݈RRҍB]jn%݈1 ! 27N6iI7B!F tq,!!!foWZkƏϠAhӦ Ç'$$ݔ; !D]"Yݦ(Ͽ7;c |}};(fWذ`5v]{ (1XE7F)&ĂF4D15kAXE|,lD̳pg9sslmm9r$ ,Ceia>뵻uVlcǎlٲ AQ" t+իiժʕ ///p]vё2e[o`{uFMʕNgUz3 4۷ogk?>>뛶GO:Th"SƍyװZj̝;7?РA]6ׯ϶`0uV$Iq]gUPؿ?@۶m?t:ܹgϞ8::biiW*| 6gڷ{n̞={ʯ\B^pvvFR1xTOcǎR|yFO[lJ*4l0[ժU_-b$*xj9sٳgHBBдiSj֬ɲe8t/Ν;lذ3f}v̙'O\rܽ{M?/,X@TTmll 4ommMRRZ2 ׯo߾9>UV=AAA̛7qτ uV6FН;whѢEsニ ۷oCf:ӂ`00|p*UO?Djj*َ)W,UgϞ 2˜0aUT1ܫVёs"IR+V4tqqM6|ɓ,\hv˗iڴ)+Wf֬YXXX_&זiӦ ӝ0@ (]Vy}+,#6. }ZeY~ewwu_.UrSr׮]ծ][[,˲*ݺuv̷~+r\\,˲yfO:u֕ LE-s.Gvv)Feĉ2 oڴ)/]vrs(rٲewyTVjUy9w|ԩ|-S٧~*ٳgeY#Gʶ^7#ELe~3gΔJl0r=J.ߗ&6嶭]ve}b] ȃGŋMebŊh4.\Hzz:Gz껺|rSٍ7]vuCQV-fϞm*wttĉȲN'_YY6NNNwrr#(yԬY*U0b}[İa\vvvtMde˖jѣlww<夤p|݌ quu}j}@ܿm۶e+7LW_pBϟϛoҥKqpp ::\[XϨ\2/_f֭&c8VVV@NRJ4i҄+W*jժ;w..]0Ɲ;whРA2%/^̌3;v,ӦMYft+++ӚG)[,O6mBnu]WTk׮jM2jժ?ʗ$ Jg8.@P0rei,, lK,,d9B60lA. K?-kMA\ɄɖrE=޺daaaJe I:?p9d>cYC4W! [a!NWZ79dGϞ=y9r$ EΠG,#IL8/xS7pB&L{x"ժU3aaa'x뭷Lk׎u1esټys,X@ΝiԨQATrq5km^ʕ+y1fטͺFPvZSF2epaRRR1KII!999G]HKKT޳gOl¢E7n\cwތ?y1j(4hЀǏ4nܸP:_ }Wb> 'aha߻\Ɉ?f JIφYYd$DNp2 h1/32KdRV]eYZ8}t Y,ذzy}sRdzHi.X&IeFΩE$-6-Y5YZ-Is\"- |s%3?FM֭5je˖Ϗۛ"PJKPP͛7'>>0tPuɓ)S o&;vd6郍 ڵ4jԈT*gtޝ] oWWWj׮M:u߿?7f͚5&K,‚ƍӸqc#375o,h4B71fטݹs'uaРAҧO*UdZ0h iܸ1ۛu 6dȑ=qf;Aq-7nk&99ÇӥK&NiL 4Tw̘1t҅qQbE sѱcG=#hRR(ԵL%aEօ.YO@!B$C%Sg_1[`J}2=; 91=%˜5.I& ?KB2|ڴifɖ !C#,ϛC&a50D<TH[A:l\2-!IC%Qȫ efc$g f;`4ǎښ;vO?1p@,,,WBY8q"eʔ_QF J%6m",,aÆaii76*TCx7[nxzz?2g\\\S7sΥyX[[ӥKl3uٳ̛7dYCB >͛7sl}ԩ*T(cxի3`lllb8p4{ݾ}{mFVa( Ν;i׮ 3b~mc[nl޼͛cgg[o,(Jl?СCMcbȐ!YDŽ3x`ө\2gϦK.$~![+Vf? ?ae {+YV!6Lq}lA))YI2!GWaJCUvl.eb.'ZSNر۳{nZj_׀/BOiT2ZIWt={=֭[ǹsprrԮ]]p¼,k@ %k_ZL+-bٲe}&,)~ϰHNҪzz}YƬNZ΀cVQmݱJ x|3 g$pX.)חϊlaLn^_k_Z@'s50 8="?Vo6N* &`['V+@i|kj #o `|. +JC՛@.Y":5F?Q'`Z7—ZVgn4ZY `<0^Q<'VYD :zM؛eFeq,F\偖]en:wº AntӨ,?`"]1ZŢЭ$ӨMGvΌ?CO2/aR7G,ޞ]::< 18"AV\z4:`¸V$g.^- @iT`YÿnGJZ?iT6:s;ӨS?/wuUZ7[2AQxCuUmii$OYQhTkf!}V8 iT$F5Y|^za  FU 3` 9ȶld.iTc!6 -}^ƚN1%d`sW\'HǺΥb?xFh0\+/Z0xkHQ92k ?V׋M \@`ft0hY *^{??2݈0&nHPţ2M&꯼0 RŬyӬƯ$kgt_tf1Wg81F]I촙nS0>zז'#f&8|c `FPDy4 E1df_yVދӲp躸,}/jm?jd>.u)R1xIRX 8>Wkf /gn2;xC`>x&r#@7k&QUEQu˜8[ƹ hPk*28xKQ^A![NJʑX/U2ڐ]YFWO)9Zago&:t*'5@FU]Qma 4jZhbL647l1(TF_%֓b~̇,m-t>Z?”2j>Rx]<Өf" t)iT FE݀8=ZV reV \{3#K>P|.4 M;E\}'=ĠafcD}:)]ˌ0BӨa 9j/V'bǻ2/\_.OwD=$yJ+L.ۭQgR T+uIJǘiT4^ a @Qu˜>QՏUkEId($%UwVpW?wAjSuIH%6LZOSk#1S0FYӨV3@P\(?p$3̢@`lӨUIԳ ˲88@aeҸ"+hCႏyڨI iIZӨa\@x46}N4mfpxQ] (1&z1T߷Ep|;, uղ̄HŎ[ܹJYr?B^rdD) zV.ΥU0XZKMܬ܆@`n E (G̈́q^iTm1&),ՁfVǬ(?Rh}+A\ces|@٪kխ%8B_bLӨJw'b] ( j~IQ x*kP:ӝ}1T6}Ld)[I>-6* 9MN:IiU#IxJ,jNlf4j~cQ%a Ve3\h/ y4PFQ5Wk_ƅ#\$WfU}c$y>,&ImRZGȯLd$VEQM y.j..ӧO/231{XxNk%Ef&2?f9qZWkZ"VZGUk-Z}1_9YN%Y\9d-kAZ2DfA(Wv#6v_^yq94;u۳=WJ~:Vj)]V?ra+4J8Zv5-#,٥[$7{77Bf *v27'K@搹nj {d}iӧOWԭQR z55+@GH2{zb^:3jjI$Jl dn0&دn]6XFZ$}.U$Irc ]^S![nfFڅq.CV3HݻܹsB;>>>xyyUXFdd$5k,jUL'бcǢV4hZ*ڵk8;;hCQ1fx ̌^_QFDuK}I_\HL IDAT HF'!43LRxH2k&*KTr #"l[غ:Nڌ1O7d/+`1leEƌ\4ͮE4O 0,FOc1S0.P &f{cqt:shZ u d%BחTÙ3g6fiǬY|U)bK#g{+nݚdXit^Xd4pdZ٧MOg_s?`[x,GN6,! {.4K ;;;8q".]BP59.{M@@o&L#$|;v|G4h`{0 ̛75k֐m6`ʊ+Wwߙ'NH>}r8x1+\\ 4* p trC5k*.;Sϑq {Gzⲣ} 62ϥLfNTTJ\pD*U2`޽{i۶-_~oׯ3l0>]6l߾]v#2!!!ď?Ç7o-[dlݺj*h,O<êUtI^;w$""o r%l֭[QF6k׮1yd9ž={L958[Cpqq~lذ={{nV… \0yd7oΞ={Xb7/DDDk.-}yǓ>|5kPzuƏ>3AM 믿СC,_<У}޵kj:.s!""طo} ,`ݼ[̙3ˌ0 tmw{(yKb$ +JuB`۰ }7gSAL>}mZ 0uTFڵёdhݺ57n02 I(J$ITRq=5kN֞ `\PYlYtҼ\`j~: "11J/&TR*U ;;;lB>}P*ȲFAq:dyvq@۶mMn$&&CV|:ϋ'NIHHÃMra_7,y ^^^|m6CT*Qոd\lkkk6oL-Th4 Ǐ>@ F.'2p"Hfңt)MOKWQ!:*Q՛UK̇> iT_z{)U&RIRR~!ǎٙwAo~3g[7٥J"999IIIq[eN^~$%%2o>z*] rAQ5  T*l$ AӸfӨZf A_iT 7)Sr͚5\|͛7ʩS>|xKW?RdѢEΚJ=? pQ4P2 Q*L0~k^ѡC6oݻw)]4=,}vغu+_{0{{{^J29d/>fb̘1̝;w}~zl%WT$\:J2̏~ƒLY`l˗LRiӦ"#>S~WjժEll,&LM6TV:u'_I&ӵkWjԨ`f͚|nVZԪU .н{wSƍϏ+rlڷoܹs)S 3/۷SbEt:5ݝSg/PF nݺԩSɉK.ѨQ\ >w}Fi磄s9<4Eq8p gΜaĈTRt:Z2y>߸q#>}`vALL sϏ'O2l0ʕ+w%<>'''VJcXZjѼysQj: .BtԬYr1<9GO:MgAtHDjըRJ<S&їL@ 0_ t ֧egoV'..k׮C»gPf͚Epp\܈7W>%FP?| tAPPc̘1EJAy t"ɓ9{,LVqrr2k[`-Fqám,} xZ] #GDAA,Lt ^ƾE7իwf\x?fo\r^j8bߢ5@s/x2f~,R-%3f0hРVC@(-+TCa}NiӦӇnݺe1gv8q)rDD5jԠB 9^l;wf4i҄#**SNQN8z(ǎё#GF?**_ĢIWdXYot Jzzz/"Q@ R {/8tOёe2c :w.]O>ɖ%+y&MeϞ=h4:t萫HRSS۷L$nݺBy:tݻ~y>|Qչfm|V9קb'pӨ2B./=z0yw^e[XXСCZ-kܹsU%קʳB0mۖ3gŋ DDDжmBUPku)P(2Ȳ-[a2Y޽θqLeDj*lll d1{lCsAظq#n"((Hz1Ν;L zxyyamm͕+Wh߾}ϒ%Khٲe7:upIf̘BӻUV(JfΜIfͰu֬]Ǐog&:\G1ǏgԨQ,޽{ر5Νkz~ܹѣG?g?$11x) tNs$ y-[ƥKX \;wc˛fٙQF1|G&Me˖tj m۶|[oѹsgڴi=>dҤIq6k׮Z9sеkW.]J&MZ QfbYb}1]ٵkkpT֭cĈ:sTT~  K.xs([n888УG|'V^3߿ϼy󈉉bŊeDhh(TRfؙűcǸp4-_&MMFFg޽ܿƍӻwodYf:tGGGzAZHHH@բHJJnݺ:Jۓ/իWILL͍S~luVZ# >0s %::oooM?p-J%/_\~kkk7oFΞ={ػw/ ԫWpeϟ}||v;wٳT*QTy~y);9BW~z*,.\_~L4S2p@tºu̬eNf̘y_b~x芥aaaJs ]64|͊M֮j.V4 _l YnC节rDn6Ydɒs?,faK{=zˋC ￧I&䄧gcƌqƦ2[[[Li+Vڵk  ==PnlrGPP-ZRJ;t']pJژWCfQYs(U6mbݦ˗j*{eǎtGe<==ٹs'Æ ###0zg1|*W̍7>|x𞏓Fjj*d޽ 2Ĵ޽{ 8'NVeĈŜ:u 6d+ Ab̙TXool:~)/J*\zÇso+Pզ(wf߾}믿&%%jժqEUL!7nܠ_~ܼyOOOVZezcԃ鉛VVVXZZ̘10S 2qDbccYfg322HKKcȑt:4iB@4pAIϾ3: <|dIjj*!!!̞=///|||̤eNܹCҥEʕ%Ky (ғΘEr߁iPC$$B!e[!S[GӧOrڴi B T[  2 搙=zw^^^{xC^{{{u{rry|ȱxY-IRKs,c6Bb/g%Iחcǎ1p@p,GTlٲлwotiҤIm]p׳zjW@@@|駹:t(Ufx߿?:u`kkˢEP(t҅={o>[ЪU+={M6vZj5`7L6 0ױclڴ >J*_p!>>>7` 6dt:^͚5cȑڙ8qT"""ڵkX)S<9rx&MDRwwIϾػw/wޥYf̘10>qϟ?{bkkK @Pܹs$!!C\Caeeň#L7/7py*Tѣz=Ά  ݻ4lؐ'\t !!!l۶XTbr2Ƶmۖ;?̉'pttdԩO\bee &,\k׮Epp̙3^GbggǸqhӦ `I?>:*U0~xj׮mjo\xQFѬY'ŌCĮ]6JRH}G t%S0à14 f9s?5GHkOQ00 ӝ4 s<_S[Yf%$Y"E<_3gcǨ[.III=z-Zp1>\.]GGGr(gϞʊ_~T-Vaqvvӧ={_^h۷g֬Y<|???իyVVVYtlzz3qVJdddǜ9swwww&qdYfΝ?~$bbbLQΞ=,˼ұVZ-[@֭[o AIϾMO>Ɔ8Ӿɓ'̙39{,}уoٳqssuQW_}; , ))$1b={dȑ_qƱaÆ\gׯ_+W.@ ȕ)jjݺ5[neϞ= 6w,t,TBjj*>>>pӨV9t-x~K\\\F7}[fԩ 6*UBFSN{ţ`r]˒{wަEIIIhZ,7n~gLR 2yi <5 qѳgOzŠAppp 22B{g:6!!PTǏ/`׮] 0Ν;#Iܼy3[\/dYf X0-[HҥKɓiܸ1C }ȑ#r*U?`q۹&}@m6Ӕ)Sʗ/O֭u͛?{wU?psfdpeLkf.%]S rɛ[7fif--3K\@TQp\2^ӴEe\pepf*Q@k^9273ڵk|7qh \-zuwGܹ3 .dԨQߟߘL&6lXhNX eB{&ts-Z#X*^ TV 7nsNlBVV7fܸqa||W,[ի{ӊ+Ҽy~]yyyqJ_V-233rĉ̜9)SPNC1c 1cބx  xꫯG'Eʕ :m4É#55:uХK:uğɼy0L///INNf͚]=×Ǝ^~+,)'&Cu꣮ȣ?uzg_ =uꫯԨQJ:BR߮Qo}0qDVZEf8q={ܱ}9N#Grwbڵt2,,իW?L͚59pѪU+bbbXh__GmUTa1b&Nȟɝw6lZbʔ)q+Wnݺ駟zƔŞ^`ƍ̘1ѣGϲyftBvX"gΜaќ={ &P~}rrr/= T 0 6еkWڶmKPP'N̞2fѸqcg'ĭ,55'2dȐ"iYb;wdȑ,n cϯ<]̹% `HHH`TX{͇s۷oѣtЁ|3zĈnݚ~dUGVjU깬u1}aذa>>>DEEj*vMZZ͚5ra4iѢSN٢E ٰaIIITؽ{w, 7oԨQH5={6֭#== ˝wѣG=jժPAAA :Գ \~Ǐ&77\$i{/ߟ#Gz~+ʕ+ٷogΜ)'RO?e<VrQkRSS7d5L6 x]OqDBdPB裏[wzB K}oWvJk]]ƍyxӦM -*4dȐKɗ__/@B@@@8p%]vN:ɘ5q9q|= ,h4rYNgoΞ={U-[,j߾} (r񲔔~G\.-[% H[@B"--ʕ+өS'̙)O>M||r9r$7nf޽4jԈӧSB=yhРYYYvZ۶mW_vڤ'k(({Х@tIAru.iZZ+V駟?`6bqqqԫW3 Cj+V`ӦMDFFMBBǏgΜ9{9s0i$+pet;гgO"##YlM6eƌ7e q&B@nOB ҵkW,X@VVqqq < OoI&mj"$$o-[`6ر=7[ 6qk >kE=!.̚5 }ݽ{BzR !_rNZٳU{>si۶-???'O,|v9y$ྱ59ʕ+Yr%MzDY.n}KUV7ؼyիCV ={v t˅no֭,YD9Btt4NgSRR&==;vzB_͛3g3g$&&͛7b7o|󱱱uOE t!˟@nN\oڛ;w}cxHH ,g.ùs;غuk[n;f͚#~=?{Q v>&-{J2M{~ٳ'۷oxIIIՋǏ^LJ~Xc=WB*flڴ &/Cbb"+VعsU]!Xl4`&7}322 x2Ν;ӵkWs>>>9ݣG 0֭[3o<'O&((W^y6m`Z~#]⫓_/;ٳg aӦMƌÛoyʹk׎,.\3DreL(-dC-k;\._,&&ϡ4jԨ> fORg[6eY%RحZ@s+T@ƍٶm۷܋]8mh޼y/0a!!!{+=P*Uغu+/m۶G)2FTTwqgfccccŊL4:Pvm[fΜɌ3hҤ QQQnݚ5j˖-+0Q} O?r=(B Xls(3^GefpF8*3-ߵㆌ v{ջ/i@4MA/G@@@ه=3=믿j*ڴiC:u8s VP^ ^sʕ+uHffghWCzЅπI-N~> pL"79 ` Z ޒM6̜9d[~aΜ9÷~?wl^+W܌y-4MRJb߾}|wKMMdٳgS\9Ͽ{ Cc/^R?N@@*U*2Kž0'q] 1. >i/j~ ;k* mn5i!vYtȱ( 4N:l޼7ϒ)W 6t1xٱ.Yx1of\2mڴ?~UjU?NRRRѣTZzjZVV"''//+ m<+C\Y(q W<SL􊩙rF* WL}4dܸqc+jhJYKc@C `R!kůYl@(}z駤DLuUr1K?B>RGu45M.2fZ -MHO<[@uc@*M@>h^%Zr9!I8Ϥ{ag,6V@ 4EO^<Ew^`Ν@rr24h͉'8u5<믿r!i֬ٳ͛{ٻw/Ԯ]*زe ڵkӸqc{׳oFpp0۷MӸ뮻W^Of޽4k֬*ڵ&MW>~8 Ν{)𻂻СCdddHڵ o4ƍSno۶u;-_%čyh'$n5XJ=>+V)JSKZg^q-6S+V}?*Ѕ(en]D9웻j7Ƿ5[͏n3DSsq Q*1T X ׭=y'Mu'}_c Lzy8 ĕp.B@#BZy `Eް(h_^zNPH\ #z @Y Wx~imǀ{3]3ـHw`=ݍZD64{a"#m tN!DWn{լ)zuQح*d̸fQ!(eUx,6ǎNIqJB\8Ͱ59 p̥iG]혯ױZΗtB[{@'AB&@r*f5g#5י50:!{gsc1SvԠqLp,`*dq%y=cZI#n_vy*1=-6ǑHqI.ĕ:?d?X5JTw`Oj妸O[5p/D(mc,6NK܆Vs`Vޏ[lK2!Dɐ1B\e}!k{ة4C+S-Jj8?t\\H=,6GD $(!҃.D1ЦPr w9 IH\7 |G>`*h'|&vVs -6LQMB\ (r_N;53Umo9[ Wq{n5} q_f٭@x^JYlC%,6G&jN"&՜L+K|0qîXlKLQ&H.5k;v`ռTC_spq!vy IDATpyy2+q_حf3( x2q_X,6GNd(nj{ӓv{=-6e( vYYC͑^ !] بP קJ1gA3ua z g=bZbl4>^!4!v 5o4:lM}ḠEsjiFF`{hAyeqӕI'e؈Ro;x1FGޥXiڗ>w5zs*-&g& WyNH׮C3.bsc0޸Vn5{ lU&~K{G߶fF|wQДrMSJ3|qr6Qڬ84:2+l֜ C@n5̷^Nޗǁ'N/sf,Wam~t)Kc9J<{)f/%!vd ) Y]Ǡkꚦ-(4n8]-ZA$ӔY[@M4n#5 PC)VWKw +R:.7Bf ZC UΟVh\5bs$[lO,6Gk>q_㞳U_5}Uٵl|n57ffVsEjiRkWㆣ-6Feac mBe:}j'cj/{q)ռn5NŃob_[ 4<9r}k`T]/[fCγf]yRU4Y]{Ѝ~tmGI+5iPsر\&!.BCtv-hct:CdbMvatn+f>7&EpzCNY4f_coWnSSN%,| {5Zl}d`j.ǀ3I?!>c=zc8Um6 B8q/C!glm@{,ټ5>[ͳp^főo=/I#˜kvT5q,+_%Xi9lf4>cKγf6W9^˕[jڬQgP]Bn5W=d~;֣29Vj]#pK~,wQn=>Fx[ bs\VN:n+q ^4|Ñ 76V.r!c#&Q!q VWl:є"٭3 @F%;Ԑ~<|/@,_dV vn5_z ܽw]"̅\Ž.7'g9z/ Qf>5@x[ p7`qW=_']y(7Bbsg٭抸{ƃq_o"B\qI.-bs(`_ޣHv9wnK{ʅ={x@e!nKO.܅ԑ]یHB!J!]YB!B\)ЅB!(E@B!]!BRD t!B!J)ЅB!(E@B!]!BRD t!B!J)ЅB!(E@B!]!BRD t!B!JDM3F3|ڳ׀^є5]gA3 1NiRXXSb?4d4-z\4Cо3>~ =HK?@S13z\=˨\B>1r}ݳ9zH(ߣ1b#2=^{$=bJ6OڬYif͖6kAs Oj.+z4:Chqt7>>"6FCsܸq]ƞ' ^KehSlR1#^.zJ٣z  Pn.7pe6B`w*J3YγϳWeitdރ!?;kסļX]+zK)mKGGiujܸqcǎu]o&{By%3|7hD-L.?C=brjK]R 2t= ]i|=Bx;GLsEnJ98(.;>\?[]~ۼ_\ww9e0Sc|"c􈹯o 0f~yOG̤^҃ДJsGmLn 8:{TϡUoХxw&Νzކyz!7뫻WMAI If)^oޙgs{?Bu|SY􈹷 cs}1f_sm+zӈXkbnL3خ[IG̋m)Dn`PeC1Ez}Ff*zb"m٪7)g+wļ6~@J)| ݮz\km%D6TWdح-6GG!# xbsVP qI<DBq<*ץ ˤaDӔ4 VOQs m8q&-D)%y]2@CC) <4ܛ5g5o*:y-9$+Ki h0 4|{jI QFH.DT4¯kg {ZqBRͅ Pz%J޳̩e,T$D;מJ޿};8sJBQf_sR{ L:L(ä@>q*w#)ӡtLBQ?^>zWJC(ˤ@'\kWҴrrBLM^-9$D$Eb_ܹ&vsBޚ% .Ʀj#nxBBAR QQ? =P\QE!.bPFt˺=7)%!)Ѕ(BەbPYurI!ʊz_̹&JsMYQH.%(i4p4SFc؛B^oH+5M1SgnvNBR q sN/*ګRonFBQvܽI4_?{伒IB t!.3? ɝN<{T}"X-xb;x9ƪ= |IBf?Wow5ЯtRBިW>#X57ٳ֪ˇSVVl׮C33j ؞5j= \Wk>ꕌVmq˿ bs4b(n'r|,c#d%Q!B!J)ЅB!(E@B!]!BRD t!B!J)ЅB!(E@B!]!BRD t!B!J)ЅB!(E@B!]`͚5-4JSNNfffI" ֮]_iq[]̙3DGGsԩb=_DEE믿^w9r1bcc4i&L`Ť]wn]b9Q֤Mrrr/M-Zۯ;Njj*III#--8&O㉍%%%s1i$N'{!'' )ЅnRRR9vX3 ^?zbɒ%(0L,]똥F;}4~!. &qoٲ^zۛ˗ctڵk׎|}rJ*L%}%%%a4^:yСCTV ??8NNnݺkvv6y~@7?{Ǚ3g̤O> 6 u1ea`ʕ{deeп^ ŋ1L1{l6mdڴi,Yш/'N䡇*2Ǥ$F͞={ͥI&L:s3f h4ҪU+O@BB tؑ1c_S\9N>ͺuTRh4k:YDNJBB^^^dffΜ9s<+WѣGӹsg]ϛ7sr>}ݻQFDNNZ+B??'O&55lBCCyWظq#&Mзo_Flj翦iO=zseѢEFN>͌3hٲ%.>XL&ތ?Gy=ѣٵkN 2m4OA0fߏdiӦ̚5 UVj*ƏO.]?~<6lWZUdɒ%o*t󏇻wf8p7fԨQaÆc4q:4jԈ`6oތR ___&OLHHo&ׯl]wQn]6n܈ۛwy{ #GȨQ<=ԫWbq1)Mӹsgy\.璠nfرtԉ/~|͛p8U .`0x |DDDAF8wG)::7OPPӦMwaʕ+W@ŨQUgȑ#1YforYNf͘:u*u-0&'|q姟~믿&11*UR8{-+~W_}MHHHwߥ[nF->}:.Yf1ydyXjsaĈ222x=zgXMjj*C '99!CÚ5k`L6SѧOFAjj*Cȑ#\J*1uTNJ: ʕ+ ĸȰS 1ïu,+16pblbb7ΐ]ble+k~b|DzvŌx"16Tb\kz,iϟgݤb0X"_|-[JVQFU|8P`H7`2 ++;v*d×z-_@@9999r\.(Fի۷KҬY3B 믿D9s f| JM['16PB\ bz؈YǖEGާWe1O'F,^1Dޓy41vb CJJ }ݺuԬYRSSi֬u-p<4Lxyya0 YYY?3bժUXV*Vy'8}4G_xߟmzؼy3'Odذaԯ_d28_ ؾ};.Ǽcǎ]xuV9?OݺuiԨ _n{+WQjUBBB<+Wnݺ={{{c0R ۷r7ݻwԩSߟvfen4δ,v؈3uԻ,.bjbld؈/_kuAW4@MSh4WUxxܸqcǺ7ffwwfp?ࣕW5]Pm4TKؤGL\܏F ֺĻ.k}O8'bZK/lСCݻnݺ?55Xi* IDAT_vmƌç~ׯ< &$-ZDLLg{oo"aٳ/wғ}w̞O?} H3fXXy`1ox֯_O.]SDEEѰaCT91{lڴiC||<֭cǎ "d'dƍ?~V^M=; lnذ!DEEoP|۷nݚ?ŋӻw9CNR(<ʊ+oZc^g!z {::jt;y(&֭[_ҽ{wի牌~=5mڔ>}rhӦ -b͚5Xk>Fz_9iSO=E:u lcL"88 2j(q)-[… 0`@f3;wvחg}+Wy<ݻ7qqqۼcOvv6/_ Fnn.K,ZjEvh_ OPPP8eAYjOy'cvQ`16DF/̓O>IINN=.293 wD3ƻ&᭼EQS1[mem*YjiJ%xEAHikf2(ሔ" `&QT~s>̗3省7~mŷP8p 5kMӐ:$((F/yy8rH.g۶m={67oӧOȑ#X'x A˖-zw?>nv :3fi_}Axx8 ͛'͛8e˖aРAxꩧ0bH) hҤ 222\|^N:?"VZp ==#F `61vXk׮oԥq >mڴ@1vXL6 3gDbb"ڷo,}:f3`G(>}/%%Æ bp}7@1b̘1/ۻ.>|86m_={6֯_FGLL ~a_Çi{ШQ#ƢiӦDnn.BBB.ϟW^y @Vt:`L< """i&8!o{닠 Gff&d.tk1Qf[BU<N6I%^SP|w׮]HOOGfXNIIѣGa0xɅ@+RRRp8ТE 'N@nnns/p8w^dffqƸ;ܡEu$''ѣBǎ]@ff&5k>ʂdBΝeee8{,Zlv(>qY&:w ш={ ''fm۶= ?#55Ff:u~dgg & :t~W9zsNju\Jd9r5k,"99999E``EuݻwygY$٫)zXXXݻw#-- v]ŧe~Xرc8t \C!]i'@{ĉ0Lԩ:<4ԨQ:t@&M\gee!??͛7P|vrr2233ѰaCtҥL^vv688~8\s!99@JJ |||\dff";;;vPo޿?:v///l6Fkt:? 77uc/[@UL|k#pX6JoHDDDDD7 :aNDDDDFؠ6DDDDDn :aNDDDDFؠ6DDDDDn :aNDDDDFؠ6DDDDDn :1 _EHL ߤ"U; CwTd@Bl,~Gwzب"Ԩ9_:!UEfN3> 16IE&.5re= 7$l<[t E>HUE08,|Oc"9DBL"*Vj6!v\ ;ӧ*2DB* ȼXi.x@<(i (H xWȺFx 8yH?L *%:EQ)r*&+ebH?ي7)|dd;'NtȽap| C%>Q@:-*2P^@Ro?];$,_ Ю"UJ!^dG *27V۠ 1_J )U ztmBC'Da#ݩ" BC^dX*R'!jhv.ʆ%3ꚭ(:g6埪42sB2}өK]T0`t̓w-qHtuTW2fLѓt #&(i@@<+Tdce^go,cUMn.ՔVs@U<`Izt~(ޏ@~*WBltJS`!V>6-IU="݃jn!$]\t"""""7ȍA'""""r#lЉt"""""7ȍA'""""r#lЉt"""""7ȍA'""""r#lЉt"""""7ȍzDDD2۫zIеSڠ',_ Fqݠ1GTdFFFzxLr_GU Z㖩L\I7WLJѣTd&,[Pzp(qpԒűzHnQ[h`0,/NOSqT)49|FsB"DQKӴB`(7,k _uS,.fY~xЧΨd޴!qqqCљ4!oQyݡG^>W_3:#E1j2}~qquF WE [\A,kE[*2OT~ZHFgvEfL!<<<LFLFu1? ~F3@2w>Qɚi5{CEgCJ3 &NP[yw*":fq0EI!߃(0llRcͺO*=] %FU&h;  xZ@_9<| }AӿR UI+4t|&cS+X`Dת2Yգfr'BeҜ WI38AC*{-?B"JU&k,U.֬Ԭ2nV5t[Iܢ:j`-I:f5mp7$ RYU$b]\t""""7:lقK۾};v;ԩS[egbN7o_|qZ{gKpvNNM;v\ܹsk.MGDDU'//Ç_+;eJ_~ظqcܹs|ǏW4&`N7]JJ |Mdee͙3[n쌌 ̚5 G-NZ~'O5X`ԩSȑ#ˬ b׮][.ڵkwIڵkѺukի#F'u0eʔkU~ ֭[cǎغu+ZjoGnn.n64l!!!?Ԙ;v ,, 6 ͚5iHOOǐ!C\nGXX6oތ aÆHKK7N:NJ+СC/0 ŠAA6uT,X7Fa1zhi0{liǎ{w?cXd L&<===|ƍ֭ԩSfy5p=`Æ loA<nݺaԩB표k>==M6]w݅={o߾زek_U7o7wؼykݎ.]ॗ^Bnn.ڵkWs / 44PfMDDD{W/Ο?ݻ߆? ϋ*C=SNԩS O>@FF vɶ5j<<9rڵó> Wzp $''#;;5j?̚5 X,Y ,@VV~rڳg:w\kխ[7#跘3goѻwK-,,?зo_]"* ѦM̝;{/`HMMŎ;Э[2v`<3+WGAbb"BBB*s̙3ػw/Zn  ܹsϣvژ5kN8={>ܹsg9!--풏,KuuD["55_:C=q]6kŊӧhy&M0~x<38|0ڴism/_ԫWO>$c˖-CVϺ;.ɲhРA4h˻;Uolo11ڵkWns^8|0j֭֬[_6M^^^۷o&&&"00([ر#o/8???h;wVA߸q#:uꄓ'Oɓw\k׮šCЭ[7|0`@˫Lnw(OzM>xuRSSt:$''ny_)$ȑ#WlГVfOJ/LMME8ӉB'+]~y66]ב:b2d4h8s wܺu>/9ÇuQυ~ ,Fff&zYnNnݐ~UcB ϋܗ/S]N~~zm͚5ѤI\Jڵk#//9ӧ}BQFW̡ -D44jΝ+7x;v @~WI6@N:Bl6A4nvvyu6mcǎ]1QFBXnnkgMDDUnݺ̼uшw}QQQ0õ/, ,Y'xu2YHJJB}SNQn˞?k"337lV-.nRGmpM#NjDo1zBbb"rrr.y.-- /s'cݺuE߻woH)}K?pgU ?sٜ/]Gc0ЪU+8pߏ_v{""yc]?3i{KXt)wcǢSNˬh"cǎ3f :/"0dŁu })ɓ1cƾ}m6$%%֙6mN'0|`ݗd{o端$:v>}?f3kh^xի>#:Z͛QvmL<m۶E~SApĉKvލCn11Q4)%6- l6=zl߾={Ruo@i2lݻwk'xBN:L… A,KIIaaam۶qƲw2==]J)ᐯ M4ڵGNӵ}bb6lO]s4i|ꩧ\?~\N0AyOvE?)3 ˀnXIDAT+۴i# $Z端͛l)=<<\.Xk~x@44^>||\8<}hr-/r iʼo\/&ȗ_~.f *yAwɃʜ+sy1p8.y[nrevI]ׯ4Y>*J2(3-!a*K؛.gϞU6m뮻.>3K>cYM=l%&La@OK}EOp"""ƍcϞ=Xn~ٳu+ ;v } ,[ cƌQ5e6n܈|| m۶!((k֬)~vsfI*$FˋDO᭷_Z Fœ9sp1U=5""R(99FÆ E-bFF/^Ǐ [Ftt[6GZsN՘]]ҵ߯^*41.<++CAc$ˈSSv:bO2v:SwĉNի-Z](m۶h޼yq쒦E:jB_mG_zcV]N7:BC'\zqqjyzOUfDDvGۻڻBCCrVtWWu+ߣfGVDllUי2e Lrf;CСCuUzhꥯhvf#UeƯYz?K/@ ?4"O^XH3!6QUcNѷGW_w}Q=*CʕuK\ܲT|&5슏*5[=j616nM 4쎋ޛu.*S[kwUe&D iؗo(4ƚ>5K5>5A !f@8~ɇLSBU)Ek*%2re:8 wy\&@"M(bV5w p244TW{!`P(^7\O&t;)쵐@ βfORbͺQͪ˚5몾513fTf.^O{kednTYe͚5k֬Yuq~nR^VS^y dVf^]\Ht/l3ym x»)vL4*Ur Uťz^UOZ "[ r7lЫ'WQz(6DDDDDn :aNDDDDFؠ6DDDDDn :aNDDDDFؠ6DDDDDn :1V?4'AT%^ *_UO:aNtmZ_Փ ""[tNUO -2zDB|L9>&*MJ 3fh*3!\Kfu7G&_+gHHVyKfɃ_|M:Λ_όJ2+Ht}m[&F=*sݪm[_VUfDD=!6T&.Ю}eжETm[̋%^A@[sUс2D=ЦũTenжE蕪2l0)!&:9.nQ-U Kh";16L,kk5˚eͲfݧf6躦wP@U d;#;>L QO*:#[Y)r/^l!۫!P[@kaZ*noVGB6OcU QU"k5šeͲfYYY #BB qU#~.{O>]W9xR[j"hH*2i09iY*tI .28*s_At='NP{!MII_*a|IB )2:*swτ*34tBn gqU"cXhL,kk5˚eͲfݧfE|Lpe$X좪BDD'!6: @_~QaNDDDDFؠ6DDDDDn :aNDDDDFؠ6DDDDDn :1Vvv ^m}.Lɮ?Jq""R :Q5а٠oJ(ְ=6DDnU毎 MixՑ|S""JߐV__vbO[S"""ؠU3R3 tV-2zR!""ؠU36d؅̫'!fX͘6W-Kj.6*|̄eSR|5,p2UcљWӧ_˝ .+4tDŽGIE&h$]b20x)*UN&:Ϫj\L񤔲O 1NY&<-4DUOa5UeЄϰq?ʕ:Mkzl YILBb`I Y_Y,kﳬYYe%$,ܬj2DDtsm dQN/V弈%FˋD1Ƭ_ :S@.bsNDTA'"x @hFOnsЉYM`JMENlVqiZtDDtؠU6fSq)L]jz+-I%c`NDlVŷB`e#VS[5$ʒ1,U16DD?mIKpa!7PSpa]2vubND8N=T$ {k8E_=DXDDtؠU1$ %DMhSh .uQbNDTh  ƕ6D`g%shWicQ(+hF.V̸8OqS QՄ xĸHe@5t5*WEfrݰUdnaլ2nV6""04 |5K=f50$G<,I<.#!6: @_^$JDTe7a (xy+6MX$We( :QcNDT~ tu-)?QˎѵdJ BDD׏ :Q$3 ĵlSN:vVڠ;-r/XǒQbNDf55,] t%wո^ (/%s "*=C>g}GXy7,ydu""k Xj_ܳKRR (_(墒oQ$"} z^8 5k,V2 H6DDn’dO$4tyRwv.;7^dIMDDn :{yVڬN [~h~]fwq4?_/]XdWTL`NDF,Iv8 7z߯d% q7 BY@BmIGJ>QE-܄'@DDeY96Aj-I[m`XZ?/AдhȀk5u$l Q-ICQA'"rC$f5j44KB% ɳYM$O9(BDJ`0C6-X hp$E9'"r_Z'Su5+cUMMBltHȍA'""""r#lЉt"""""7ȍA'""""r#$ڬ.DDDDDT5 oZU\oNsbIENDB`lomiri-action-api-1.1.3/documentation/images/preview_action_signals.svg000066400000000000000000005730621455542516300264550ustar00rootroot00000000000000 image/svg+xml PreviewAction Signals User selects PreviewActionfrom the HUD PreviewMode User selects Reset User selects Cancel User selects Commit Parameter values updatewhile the user interactswith the HUD UI started() resetted() triggered() cancelled() lomiri-action-api-1.1.3/documentation/qml/000077500000000000000000000000001455542516300205055ustar00rootroot00000000000000lomiri-action-api-1.1.3/documentation/qml/CMakeLists.txt000066400000000000000000000015421455542516300232470ustar00rootroot00000000000000# add a target to generate API documentation with qdoc if(DEFINED ENV{DEB_BUILD_MULTIARCH}) set(QDOC_EXECUTABLE "/usr/lib/$ENV{DEB_BUILD_MULTIARCH}/qt5/bin/qdoc") else() FIND_PROGRAM(QDOC_EXECUTABLE qdoc) endif() if(QDOC_EXECUTABLE) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/lomiri-action-qml.qdocconf.in ${CMAKE_CURRENT_BINARY_DIR}/lomiri-action-qml.qdocconf @ONLY) add_custom_target(qmldoc ${QDOC_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/lomiri-action-qml.qdocconf WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} COMMENT "Generating QML API documentation with qdoc" VERBATIM ) # copy stylesheet files into build directory for shadow builds file(COPY "${CMAKE_CURRENT_SOURCE_DIR}/css" DESTINATION ${CMAKE_CURRENT_BINARY_DIR} ) install( DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/html/ DESTINATION ${CMAKE_INSTALL_DOCDIR}/qml/ ) endif(QDOC_EXECUTABLE) lomiri-action-api-1.1.3/documentation/qml/css/000077500000000000000000000000001455542516300212755ustar00rootroot00000000000000lomiri-action-api-1.1.3/documentation/qml/css/base.css000066400000000000000000000270671455542516300227350ustar00rootroot00000000000000/** * Lomiri Developer base stylesheet * * A base stylesheet containing site-wide styles * * @project Lomiri Developer * @version 1.0 * @author Canonical Web Team: Steve Edwards * @copyright 2011 Canonical Ltd. */ /** * @section Global */ body { font-family: 'Ubuntu', 'Ubuntu Beta', UbuntuBeta, Ubuntu, 'Bitstream Vera Sans', 'DejaVu Sans', Tahoma, sans-serif; font-size: 13px; line-height: 1.4; color: #333; } a { color: #dd4814; text-decoration: none; outline: 0; } p, dl { margin-bottom: 10px; } strong { font-weight: bold; } em { font-style: italic; } code{ padding: 10px; font-family: 'Ubuntu Mono', 'Consolas', 'Monaco', 'DejaVu Sans Mono', Courier, monospace; background-color: #fdf6f2; display: block; margin-bottom: 10px; -moz-border-radius: 4px; -webkit-border-radius: 4px; border-radius: 4px; } h1 { font-size: 36px; line-height: 1.1; margin-bottom: 20px; } article h1, h2 { font-size: 24px; line-height: 1.2; margin-bottom: 14px; } h3 { font-size: 16px; line-height: 1.3; margin-bottom: 8px; } h4 { font-weight: bold; } time { color:#999; } /** * @section Structure */ .header-login, .header-navigation div, .header-content div { margin: 0 auto; width: 940px; } .header-content h1{ background-color:#ffffff; display:inline-block; } .header-content h2{ background-color:#ffffff; display:table; } .header-login ul { margin: 4px 0; float: right; } .header-login li { margin-right: 10px; float: left; } .header-login a { color: #333; } .header-navigation { border-top: 2px solid #dd4814; border-bottom: 2px solid #dd4814; background-color: #fff; height: 54px; clear: right; overflow: hidden; } .header-navigation nav ul { border-right: 1px solid #dd4814; float: right; } .header-navigation nav li { border-left: 1px solid #dd4814; float: left; height: 54px; } .header-navigation nav a { padding: 18px 14px 0; font-size: 14px; display: block; height: 36px; } .header-navigation nav a:hover { background-color: #fcece7; } .header-navigation nav .current_page_item a, .header-navigation nav .current_page_parent a, .header-navigation nav .current_page_ancestor a { background-color: #dd4814; color: #fff; } .header-navigation input { margin: 12px 10px 0 10px; padding: 5px; border-top: 1px solid #a1a1a1; border-right: 1px solid #e0e0e0; border-bottom: 1px solid #fff; border-left: 1px solid #e0e0e0; width: 90px; font-style: italic; color: #ccc; -moz-border-radius: 3px; -webkit-border-radius: 3px; border-radius: 3px; -moz-box-shadow: inset 0 1px 1px #e0e0e0; -webkit-box-shadow: inset 0 1px 1px #e0e0e0; box-shadow: inset 0 1px 1px #e0e0e0; } .header-navigation h2 { margin: 18px 0 0 6px; text-transform: lowercase; font-size: 22px; color: #dd4814; float: left; } .header-navigation .logo-ubuntu { margin-top: 12px; float: left; } .header-content .header-navigation-secondary { margin-bottom: 40px; padding: 0; position: relative; z-index: 2; } .header-navigation-secondary div { padding: 0; border: 2px solid #dd4814; -moz-border-radius: 0px 0px 4px 4px; -webkit-border-radius: 0px 0px 4px 4px; border-radius: 0px 0px 4px 4px; background: #fff; border-top: 0px; width: 936px; } .header-navigation-secondary nav li { float: left; } .header-navigation-secondary nav li a { color: #333; display: block; height: 25px; padding: 8px 8px 0; } .header-navigation-secondary nav li:hover, .header-navigation-secondary nav .current_page_item a { background: url("../img/sec-nav-hover.gif"); } .header-content { padding-bottom: 30px; border-bottom: 1px solid #e0e0e0; -moz-box-shadow: 0 1px 3px #e0e0e0; -webkit-box-shadow: 0 1px 3px #e0e0e0; box-shadow: 0 1px 3px #e0e0e0; margin-bottom: 3px; position: relative; overflow: hidden; } footer { padding: 10px 10px 40px 10px; position: relative; -moz-border-radius: 0 0 4px 4px; -webkit-border-radius: 0 0 4px 4px; border-radius: 0 0 4px 4px; font-size: 12px; background: url("../img/background-footer.png") repeat scroll 0 0 #f7f6f5; } footer div { margin: 0 auto; padding: 0 10px; width: 940px; } footer a { color: #000; } footer nav ul { margin: 10px 17px 30px 0; width: 172px; display: inline-block; vertical-align: top; height: auto; zoom: 1; *display: inline; } footer nav ul.last { margin-right: 0; } footer nav li { margin-bottom: 8px; } footer nav li:first-child { font-weight: bold; } footer p { margin-bottom: 0; } #content { padding-top: 35px; } .arrow-nav { display: none; position: absolute; top: -1px; z-index: 3; } .shadow { margin: 30px 0 3px 0; border-bottom: 1px solid #e0e0e0; -moz-box-shadow: 0 2px 3px #e0e0e0; -webkit-box-shadow: 0 2px 3px #e0e0e0; box-shadow: 0 2px 3px #e0e0e0; height: 3px; } /** * @section Site-wide */ #content h2{ font-size:24px; } .box-orange { padding: 10px; border: 3px solid #dd4814; -moz-border-radius: 4px; -webkit-border-radius: 4px; border-radius: 4px; } .box-orange .link-action-small { float: right; margin: 0 0 0 20px; } .link-bug { margin-left: 10px; color: #999; } .link-action { float: left; margin-bottom: 20px; padding: 8px 12px; display: block; background-color: #dd4814; color: #fff; -moz-border-radius: 20px; -webkit-border-radius: 20px; border-radius: 20px; font-size: 16px; line-height: 1.3; border-top: 3px solid #e6633a; border-bottom: 3px solid #c03d14; } .link-action2 { float: left; display: block; color: #fff; font-size: 16px; line-height: 1.3; } .link-action2 span{ display:block; float:left; } .link-action2 .cta-left{ background:url(../img/button-cta-left.png) no-repeat; width:22px; height:48px; } .link-action2 .cta-center{ background:url(../img/button-cta-slice.png) repeat-x; line-height:45px; height:48px; } .link-action2 .cta-right{ background:url(../img/button-cta-right.png) no-repeat; width:22px; height:48px; } .link-action-small { float: left; display: block; color: #fff; font-size: 16px; } .link-action-small span{ display:block; float:left; height:42px; } .link-action-small .cta-left{ background:url(../img/button-cta-left-small.png) no-repeat; width:19px; } .link-action-small .cta-center{ background:url(../img/button-cta-slice-small.png) repeat-x; line-height:42px; } .link-action-small .cta-right{ background:url(../img/button-cta-right-small.png) no-repeat; width:19px; } .link-action:active { position: relative; top: 1px; } .link-action2:active { position: relative; top: 1px; } .link-action-small:active { position: relative; top: 1px; } .list-bullets li { margin-bottom: 10px; list-style: disc; list-style-position: inside; } .box { margin-bottom: 30px; padding: 15px; border: 1px solid #aea79f; -moz-border-radius: 4px; -webkit-border-radius: 4px; border-radius: 4px; } .box-padded { margin-bottom: 30px; padding: 5px; border: 2px solid #aea79f; -moz-border-radius: 4px; -webkit-border-radius: 4px; border-radius: 4px; background: url("../img/pattern-featured.gif") repeat scroll 0 0 #ebe9e7; overflow: hidden; } .box-padded h3 { margin: 5px 0 10px 5px; } .box-padded div { padding: 10px; border: 1px solid #aea79f; -moz-border-radius: 4px; -webkit-border-radius: 4px; border-radius: 4px; background-color: #fff; overflow: hidden; } .box-padded li { padding: 0 10px; float: left; width: 211px; border-right: 1px dotted #aea79f; } .box-padded li.first { padding: 0; margin-bottom: 0; } .box-padded li.last { border: 0; width: 217px; } .box-padded img { margin: 0 10px 50px 0; float: left; -moz-border-radius: 8px; -webkit-border-radius: 8px; border-radius: 8px; } .box-clear { margin-bottom: 40px; } .box-clear .grid-4.first { margin-right: 15px; padding-right: 15px; } .box-clear .grid-4 { margin-left: 0; margin-right: 10px; padding-right: 10px; width: 298px; } .box-clear time { display: block; border-bottom: 1px dotted #aea79f; padding-bottom: 10px; margin-bottom: 10px; } .box-clear div.first { border-right: 1px dotted #aea79f; } .box-clear a { display: block; } .box-clear .rss { background: url("../img/rss.jpg") no-repeat scroll 0 center; padding-left: 20px; } .box-clear .location { display: block; margin-bottom: 1px; } .box-clear .last { margin: 0; padding-right: 0; -moz-border-radius: 4px; -webkit-border-radius: 4px; border-radius: 4px; width: 293px; } /* Widgets */ .ui-state-focus { outline: none; } .ui-accordion { border-bottom: 1px dotted #aea79f; } .ui-accordion a { display: block; } .ui-accordion h3 { margin-bottom: 0; border-top: 1px dotted #aea79f; position: relative; font-size: 13px; font-weight: bold; } .ui-accordion h3 a { padding: 10px 0; color: #333; } .ui-accordion h4 { margin-bottom: 5px; } .ui-accordion div fieldset { padding-bottom: 5px; } .ui-accordion div li, .ui-accordion div input { margin-bottom: 10px; } .ui-accordion .ui-icon { position: absolute; top: 15px; right: 0; display: block; width: 8px; height: 8px; background: url("../img/icon-accordion-inactive.png") 0 0 no-repeat transparent; } .ui-accordion .ui-state-active .ui-icon { background-image: url("../img/icon-accordion-active.png"); } .ui-accordion .current_page_item a { color: #333; } .container-tweet { -moz-border-radius: 4px 4px 4px 4px; -webkit-border-radius: 4px 4px 4px 4px; border-radius: 4px 4px 4px 4px; padding: 10px 10px 10px; background-color: #f7f7f7; } .container-tweet .tweet-follow { margin-top: 10px; margin-bottom: -10px; padding-left: 55px; padding-bottom: 6px; background: url("../img/tweet-follow.png") 0 5px no-repeat; display: block; } .container-tweet .tweet-follow span { font-size: 16px; font-weight: bold; line-height: 1.2; display: block; } .tweet a { display: inline; } .tweet .tweet_text { padding: 10px; background-color: #fff; -moz-border-radius: 4px 4px 4px 4px; -webkit-border-radius: 4px 4px 4px 4px; border-radius: 4px 4px 4px 4px; border: 1px solid #dd4814; font-size: 16px; display: block; clear: both; } .tweet.tweet-small .tweet_text { font-size: inherit; } .tweet .tweet_text a { color: #333; } .tweet .tweet_time, .tweet .tweet_user_and_time { padding: 15px 0 10px 0; position: relative; top: -2px; background: url("../img/tweet-arrow.png") no-repeat; display: block; } .tweet .tweet_odd .tweet_time, .tweet .tweet_odd .tweet_user_and_time { background-position: right 0; float: right; } .tweet .tweet_even .tweet_time, .tweet .tweet_even .tweet_user_and_time { background-position: left 0; float: left; } /* Search */ #content .list-search li { list-style-type:none; border:0px; margin-bottom: 15px; padding-top: 15px; } /* Blog */ .blog-article #nav-single { margin-top: 30px; margin-bottom: 30px; } .blog-article #nav-single .nav-next { float: right; } .blog-article article header .entry-meta { margin-bottom: 20px; } .blog-article article .entry-meta { color: #999; } .blog-article #respond form input[type="submit"] { float: left; cursor: pointer; margin-bottom: 20px; padding: 8px 12px; display: block; background-color: #dd4814; color: #fff; -moz-border-radius: 20px; -webkit-border-radius: 20px; border-radius: 20px; font-size: 16px; line-height: 1.3; border-top: 3px solid #e6633a; border-left: 3px solid #e6633a; border-right: 3px solid #e6633a; border-bottom: 3px solid #c03d14; } .blog-article #respond form input[type="submit"]:active { position: relative; top: 1px; } .alignnone{ float:left; margin:10px 20px 10px 0; } .alignleft{ float:left; margin:10px 20px 10px 0; } .alignright{ float:right; margin:10px 0 10px 20px; } .aligncenter{ float:left; margin:10px 20px 10px 0; } .entry-content h2, .entry-content h3{ margin-top:20px; } .entry-content ul li{ list-style-type: circle; margin-left:16px; } .entry-content hr{ border:none; border-top: 1px dotted #AEA79F; } lomiri-action-api-1.1.3/documentation/qml/css/qtquick.css000066400000000000000000000317511455542516300234770ustar00rootroot00000000000000@media screen { /* basic elements */ html { color: #000000; background: #FFFFFF; } table { border-collapse: collapse; border-spacing: 0; } fieldset, img { border: 0; max-width:100%; } address, caption, cite, code, dfn, em, strong, th, var, optgroup { font-style: inherit; font-weight: inherit; } del, ins { text-decoration: none; } ol li { list-style: decimal; } ul li { list-style: none; } caption, th { text-align: left; } h1.title { font-weight: bold; font-size: 150%; } h0 { font-weight: bold; font-size: 130%; } h1, h2, h3, h4, h5, h6 { font-size: 100%; } q:before, q:after { content: ''; } abbr, acronym { border: 0; font-variant: normal; } sup, sub { vertical-align: baseline; } tt, .qmlreadonly span, .qmldefault span { word-spacing:0.5em; } legend { color: #000000; } strong { font-weight: bold; } em { font-style: italic; } body { margin: 0 1.5em 0 1.5em; font-family: ubuntu; line-height: normal } a { color: #00732F; text-decoration: none; } hr { background-color: #E6E6E6; border: 1px solid #E6E6E6; height: 1px; width: 100%; text-align: left; margin: 1.5em 0 1.5em 0; } pre { border: 1px solid #DDDDDD; -moz-border-radius: 0.7em 0.7em 0.7em 0.7em; -webkit-border-radius: 0.7em 0.7em 0.7em 0.7em; border-radius: 0.7em 0.7em 0.7em 0.7em; padding: 1em 1em 1em 1em; overflow-x: auto; } table, pre { -moz-border-radius: 0.7em 0.7em 0.7em 0.7em; -webkit-border-radius: 0.7em 0.7em 0.7em 0.7em; border-radius: 0.7em 0.7em 0.7em 0.7em; background-color: #F6F6F6; border: 1px solid #E6E6E6; border-collapse: separate; margin-bottom: 2.5em; } pre { font-size: 90%; display: block; overflow:hidden; } thead { margin-top: 0.5em; font-weight: bold } th { padding: 0.5em 1.5em 0.5em 1em; background-color: #E1E1E1; border-left: 1px solid #E6E6E6; } td { padding: 0.25em 1.5em 0.25em 1em; } td.rightAlign { padding: 0.25em 0.5em 0.25em 1em; } table tr.odd { border-left: 1px solid #E6E6E6; background-color: #F6F6F6; color: black; } table tr.even { border-left: 1px solid #E6E6E6; background-color: #ffffff; color: #202020; } div.float-left { float: left; margin-right: 2em } div.float-right { float: right; margin-left: 2em } span.comment { color: #008B00; } span.string, span.char { color: #000084; } span.number { color: #a46200; } span.operator { color: #202020; } span.keyword { color: #840000; } span.name { color: black } span.type { font-weight: bold } span.type a:visited { color: #0F5300; } span.preprocessor { color: #404040 } /* end basic elements */ /* font style elements */ .heading { font-weight: bold; font-size: 125%; } .subtitle { font-size: 110% } .small-subtitle { font-size: 100% } .red { color:red; } /* end font style elements */ /* global settings*/ .header, .footer { display: block; clear: both; overflow: hidden; } /* end global settings*/ /* header elements */ .header .qtref { color: #00732F; font-weight: bold; font-size: 130%; } .header .content { margin-left: 5px; margin-top: 5px; margin-bottom: 0.5em; } .header .breadcrumb { font-size: 90%; padding: 0.5em 0 0.5em 1em; margin: 0; background-color: #fafafa; height: 1.35em; border-bottom: 1px solid #d1d1d1; } .header .breadcrumb ul { margin: 0; padding: 0; } .header .content { word-wrap: break-word; } .header .breadcrumb ul li { float: left; background: url(../images/breadcrumb.png) no-repeat 0 3px; padding-left: 1.5em; margin-left: 1.5em; } .header .breadcrumb ul li.last { font-weight: normal; } .header .breadcrumb ul li a { color: #00732F; } .header .breadcrumb ul li.first { background-image: none; padding-left: 0; margin-left: 0; } .header .content ol li { background: none; margin-bottom: 1.0em; margin-left: 1.2em; padding-left: 0 } .header .content li { background: url(../images/bullet_sq.png) no-repeat 0 5px; margin-bottom: 1em; padding-left: 1.2em; } /* end header elements */ /* content elements */ .content h1 { font-weight: bold; font-size: 130% } .content h2 { font-weight: bold; font-size: 120%; width: 100%; } .content h3 { font-weight: bold; font-size: 110%; width: 100%; } .content table p { margin: 0 } .content ul { padding-left: 2.5em; } .content li { padding-top: 0.25em; padding-bottom: 0.25em; } .content ul img { vertical-align: middle; } .content a:visited { color: #4c0033; text-decoration: none; } .content a:visited:hover { color: #4c0033; text-decoration: underline; } a:hover { color: #4c0033; text-decoration: underline; } descr p a { text-decoration: underline; } .descr p a:visited { text-decoration: underline; } .alphaChar{ width:95%; background-color:#F6F6F6; border:1px solid #E6E6E6; -moz-border-radius: 7px 7px 7px 7px; border-radius: 7px 7px 7px 7px; -webkit-border-radius: 7px 7px 7px 7px; font-size:12pt; padding-left:10px; margin-top:10px; margin-bottom:10px; } .flowList{ /*vertical-align:top;*/ /*margin:20px auto;*/ column-count:3; -webkit-column-count:3; -moz-column-count:3; /* column-width:100%; -webkit-column-width:200px; -col-column-width:200px; */ column-gap:41px; -webkit-column-gap:41px; -moz-column-gap:41px; column-rule: 1px dashed #ccc; -webkit-column-rule: 1px dashed #ccc; -moz-column-rule: 1px dashed #ccc; } .flowList dl{ } .flowList dd{ /*display:inline-block;*/ margin-left:10px; min-width:250px; line-height: 1.5; min-width:100%; min-height:15px; } .flowList dd a{ } .mainContent { padding-left:5px; } .content .flowList p{ padding:0px; } .content .alignedsummary { margin: 15px; } .qmltype { text-align: center; font-size: 120%; } .qmlreadonly { padding-left: 5px; float: right; color: #254117; } .qmldefault { padding-left: 5px; float: right; color: red; } .qmldoc { } .generic .alphaChar{ margin-top:5px; } .generic .odd .alphaChar{ background-color: #F6F6F6; } .generic .even .alphaChar{ background-color: #FFFFFF; } .memItemRight{ padding: 0.25em 1.5em 0.25em 0; } .highlightedCode { margin: 1.0em; } .annotated td { padding: 0.25em 0.5em 0.25em 0.5em; } .toc { font-size: 80% } .header .content .toc ul { padding-left: 0px; } .content .toc h3 { border-bottom: 0px; margin-top: 0px; } .content .toc h3 a:hover { color: #00732F; text-decoration: none; } .content .toc .level2 { margin-left: 1.5em; } .content .toc .level3 { margin-left: 3.0em; } .content ul li { background: url(../images/bullet_sq.png) no-repeat 0 0.7em; padding-left: 1em } .content .toc li { background: url(../images/bullet_dn.png) no-repeat 0 5px; padding-left: 1em } .relpage { -moz-border-radius: 7px 7px 7px 7px; -webkit-border-radius: 7px 7px 7px 7px; border-radius: 7px 7px 7px 7px; border: 1px solid #DDDDDD; padding: 25px 25px; clear: both; } .relpage ul { float: none; padding: 1.5em; } h3.fn, span.fn { -moz-border-radius:7px 7px 7px 7px; -webkit-border-radius:7px 7px 7px 7px; border-radius:7px 7px 7px 7px; background-color: #F6F6F6; border-width: 1px; border-style: solid; border-color: #E6E6E6; font-weight: bold; word-spacing:3px; padding:3px 5px; } .functionIndex { font-size:12pt; word-spacing:10px; margin-bottom:10px; background-color: #F6F6F6; border-width: 1px; border-style: solid; border-color: #E6E6E6; -moz-border-radius: 7px 7px 7px 7px; -webkit-border-radius: 7px 7px 7px 7px; border-radius: 7px 7px 7px 7px; width:100%; } .centerAlign { text-align:center; } .rightAlign { text-align:right; } .leftAlign { text-align:left; } .topAlign{ vertical-align:top } .functionIndex a{ display:inline-block; } /* end content elements */ /* footer elements */ .footer { color: #393735; font-size: 0.75em; text-align: center; padding-top: 1.5em; padding-bottom: 1em; background-color: #E6E7E8; margin: 0; } .footer p { margin: 0.25em } .small { font-size: 0.5em; } /* end footer elements */ .item { float: left; position: relative; width: 100%; overflow: hidden; } .item .primary { margin-right: 220px; position: relative; } .item hr { margin-left: -220px; } .item .secondary { float: right; width: 200px; position: relative; } .item .cols { clear: both; display: block; } .item .cols .col { float: left; margin-left: 1.5%; } .item .cols .col.first { margin-left: 0; } .item .cols.two .col { width: 45%; } .item .box { margin: 0 0 10px 0; } .item .box h3 { margin: 0 0 10px 0; } .cols.unclear { clear:none; } } /* end of screen media */ /* start of print media */ @media print { input, textarea, .header, .footer, .toolbar, .feedback, .wrapper .hd, .wrapper .bd .sidebar, .wrapper .ft, #feedbackBox, #blurpage, .toc, .breadcrumb, .toolbar, .floatingResult { display: none; background: none; } .content { background: none; display: block; width: 100%; margin: 0; float: none; } } /* end of print media */ /* modify the TOC layouts */ div.toc ul { padding-left: 20px; } div.toc li { padding-left: 4px; } /* Remove the border around images*/ a img { border:none; } /*Add styling to the front pages*/ .threecolumn_area { padding-top: 20px; padding-bottom: 20px; } .threecolumn_piece { display: inline-block; margin-left: 78px; margin-top: 8px; padding: 0; vertical-align: top; width: 25.5%; } div.threecolumn_piece ul { list-style-type: none; padding-left: 0px; margin-top: 2px; } div.threecolumn_piece p { margin-bottom: 7px; color: #5C626E; text-decoration: none; font-weight: bold; } div.threecolumn_piece li { padding-left: 0px; margin-bottom: 5px; } div.threecolumn_piece a { font-weight: normal; } /* Add style to guide page*/ .fourcolumn_area { padding-top: 20px; padding-bottom: 20px; } .fourcolumn_piece { display: inline-block; margin-left: 35px; margin-top: 8px; padding: 0; vertical-align: top; width: 21.3%; } div.fourcolumn_piece ul { list-style-type: none; padding-left: 0px; margin-top: 2px; } div.fourcolumn_piece p { margin-bottom: 7px; color: #40444D; text-decoration: none; font-weight: bold; } div.fourcolumn_piece li { padding-left: 0px; margin-bottom: 5px; } div.fourcolumn_piece a { font-weight: normal; } lomiri-action-api-1.1.3/documentation/qml/css/reset.css000066400000000000000000000015331455542516300231330ustar00rootroot00000000000000/* Copyright (c) 2010, Yahoo! Inc. All rights reserved. Code licensed under the BSD License: http://developer.yahoo.com/yui/license.html version: 3.3.0 build: 3167 */ html{color:#000;background:#FFF;}body,div,dl,dt,dd,ul,ol,li,h1,h2,h3,h4,h5,h6,pre,code,form,fieldset,legend,input,textarea,p,blockquote,th,td{margin:0;padding:0;}table{border-collapse:collapse;border-spacing:0;}fieldset,img{border:0;}address,caption,cite,code,dfn,em,strong,th,var{font-style:normal;font-weight:normal;}li{list-style:none;}caption,th{text-align:left;}h1,h2,h3,h4,h5,h6{font-size:100%;font-weight:normal;}q:before,q:after{content:'';}abbr,acronym{border:0;font-variant:normal;}sup{vertical-align:text-top;}sub{vertical-align:text-bottom;}input,textarea,select{font-family:inherit;font-size:inherit;font-weight:inherit;}input,textarea,select{*font-size:100%;}legend{color:#000;}lomiri-action-api-1.1.3/documentation/qml/css/scratch.css000066400000000000000000000013741455542516300234430ustar00rootroot00000000000000body { margin: 0; } div.toc ul { padding: 0; } div.toc li { margin-bottom: 3px; } h1.title { font-size: 36px; line-height: 1.1; font-weight: normal; } h0, h2 { font-size: 24px; line-height: 1.2; margin: 14px 0; font-weight: normal; display: block; } a:hover { color: #dd4814; text-decoration: underline; outline: 0; } table, pre { border-radius: 0; } .annotated td { padding: 0.8em 1em 0.3em; } .wrapper { width: 940px; margin: 0 auto; } .main-content { width: 668px; position: relative; left: 270px; } .title { margin-left: -270px; margin-top: 30px; margin-bottom: 50px; } .toc { margin-left: -270px; font-size: 100%; margin-bottom: 40px; padding: 0; z-index: 2; position: absolute; top: 100px; width: 250px; } lomiri-action-api-1.1.3/documentation/qml/lomiri-action-qml.qdocconf.in000066400000000000000000000026441455542516300261730ustar00rootroot00000000000000project = Lomiri Action QML API description = Lomiri Action API sourcedirs = @CMAKE_CURRENT_SOURCE_DIR@/pages @CMAKE_CURRENT_SOURCE_DIR@/qml-api exampledirs = @CMAKE_SOURCE_DIR@/examples/ imagedirs = @CMAKE_CURRENT_SOURCE_DIR@/../images sources.fileextensions = "*.qdoc *.qml" headers.fileextensions = "*.h" examples.fileextensions = "*.js *.qml" examples.imageextensions = "*.png *.jpeg *.jpg" outputdir = html outputformat = HTML outputprefixes = QML outputprefixes.QML = qml- HTML.templatedir = @CMAKE_CURRENT_SOURCE_DIR@/ HTML.nobreadcrumbs = "true" HTML.stylesheets = \ css/reset.css \ css/qtquick.css \ css/base.css \ css/scratch.css HTML.headerstyles = \ "\n" \ "\n" \ "\n" \ "\n" HTML.postheader = \ "
\n" \ "
\n" HTML.footer = \ "
\n" \ "
\n" \ "
\n" \ "
\n" \ " \n" \ "

© 2013 Canonical Ltd. Lomiri and Canonical are registered trademarks of Canonical Ltd.

\n" \ "
\n" \ "
\n" lomiri-action-api-1.1.3/documentation/qml/pages/000077500000000000000000000000001455542516300216045ustar00rootroot00000000000000lomiri-action-api-1.1.3/documentation/qml/pages/context.qdoc000066400000000000000000000054571455542516300241530ustar00rootroot00000000000000/*! \page contexts.html Action Contexts \title Action Contexts \contentspage {Lomiri Action API} \part Overview Application which has different views needs to manage it actions based on the currently active view; not all of the actions supported by the application might be relevant or applicable on all of the views. Therefore Lomiri Action API provides action contexts; a context groups actions together and by providing multiple contexts the developer is able to control the visibility of the actions. The ActionManager then exposes the actions from these different contexts. \image context_overview.png Each application has one global context; the actions in this context are always available. The application may have one or more additional local context of which only one can be active at a time. The ActionManager merges the global context and the active local context together; the actions available at any given time is the union of the global context and the active local context. \image multiple_contexts.png \part Applications with Single Context For applications that do not require multiple contexts using the API is straight forward as the ActionManager provides the global context automatically. \code import QtQuick 2.0 import Lomiri.Action 1.0 Item { ActionManager { Action { id: globalAction text: "My Global Action" } } } \endcode globalAction is now added to the global context. \part Applications with Multiple Contexts When multiple contexts are needed the developer creates suitable number of ActionContext objects, adds the actions to the contexts, adds the contexts to the manager and sets the active one. Setting the active context must be managed by the developer. The can only be one active local context at a time. \code import QtQuick 2.0 import Lomiri.Action 1.0 Item { ActionManager { localContexts: [ctx1, ctx2] Action { id: globalAction text: "My Global Action" } } ActionContext { id: ctx1 Action { id: ctx1Action1 text: "Context1, Action 1" } Action { id: ctx1Action2 text: "Context1, Action 2" } } ActionContext { id: ctx2 Action { id: ctx2Action1 text: "Context2, Action 1" } Action { id: ctx2Action2 text: "Context2, Action 2" } } Component.onCompleted: { ctx2.active = true; // now the ActionManager has exported // globalAction, ctx2Action1 and ctx2Action2 } } \endcode */ lomiri-action-api-1.1.3/documentation/qml/pages/mainpage.qdoc000066400000000000000000000034551455542516300242440ustar00rootroot00000000000000/*! \page index.html overview \title Lomiri Action API \contentspage {Lomiri Action API} {Contents} \part Introduction Lomiri Action API offers a way to easily integrate with the Lomiri components outside of the application such as the Launcher, HUD, AppMenu and MessagingMenu. Applications have internally different types of actions with different life-cycles. Some actions are application wide that are relevant and available throughout the whole life-cycle of the application. Other actions are context specific and only available when the application is in certain visual state, such as in image editing mode. See \l {Action Contexts} for more details. Application can define application wide actions dynamically during runtime and as offline (jumplist) actions that are available even if the application is not running. Activating an offline action will launch the application when necessary. Lomiri Action API can be used with three ways: \list \li - using the Qt C++ API (see the C++ documentation) \li - Using this QML API directly \li - Using the UI Toolkit \endlist UI Toolkit simplifies the ActionContext management and provides ActionManager as part of the MainView. See the UI Toolkit documentation for more details. \part General Topics \list \li \l {Action Contexts} \li \l {Preview Actions} \li \l {Platform Integration} \li \l {Offline Actions} \endlist \part Reporting Bugs If you find any problems with the or this documentation, please file a bug in Lomiri Action API \l {https://bugs.launchpad.net/lomiri-action-api} {Launchpad page} \part Components Available through: \code import Lomiri.Action 1.0 \endcode \part Base Items \annotatedlist action-base \part Paramaters \annotatedlist action-parameters \part Non-Instantiable \annotatedlist action-non-instantiable */ lomiri-action-api-1.1.3/documentation/qml/pages/offline-actions.qdoc000066400000000000000000000033541455542516300255410ustar00rootroot00000000000000/*! \page offline-actions.html Offline Actions \title Offline Actions \contentspage {Lomiri Action API} Applications can define offline (jump list) actions in their \e {.desktop} files. These actions are available in the Launcher, AppMenu, HUD and MessagingMenu even if the application is not running. When an offline action is executed and the application is not running the application is started and executes the given action on startup, but for the user it does not make any difference if the application is running or not prior to the action invocation. This example assumes we have a mail application, \e {MailApp}. This application defines offline actions in \e {mail-app.desktop}: \quotefile mail-app/mail-app.desktop The desktop file's \e {Actions} key lists the offline actions. Each action then has its own group entry in the \e {.desktop} file. \e {MailApp} defines two offline actions: \e {Compose} and \e {Contacts}. By leaving the \e {Exec} keys empty for the actions the platform will invoke the Lomiri Actions defined by the application. Now, the Application has to define corresponding actions in it's code: \code import QtQuick 2.0 import Lomiri.Action 1.0 Item { ActionManager { Action { id: newMessageAction name: "Compose" // matches the .desktop file Desktop Action identifier onTriggered: { // show the compose view } } Action { id: openAddressBookAction name: "Contacts" // matches the .desktop file Desktop Action identifier onTriggered: { // show the address book view } } } } \endcode */ lomiri-action-api-1.1.3/documentation/qml/pages/platform-integration.qdoc000066400000000000000000000013511455542516300266210ustar00rootroot00000000000000/*! \page platform-integration.html Platform Integration \title Platform Integration \contentspage {Lomiri Action API} Lomiri Action API offers a way for application to integrate with the platform components such as the Lomiri Launcher and the Lomiri HUD. The ActionManager exports the actions to D-Bus which allows external components and even 3rd party applications to interact with the actions. \image platform_integration.png \caption Platform Integration through D-Bus. One of the key benefits of Lomiri Action API is that it allows seamless integration with the Lomiri HUD; All Lomiri Actions are available to the HUD once they have been added to the ActionManager. \image hud_screenshot.jpg \caption The HUD showing some actions. */ lomiri-action-api-1.1.3/documentation/qml/pages/preview-actions.qdoc000066400000000000000000000061541455542516300256010ustar00rootroot00000000000000/*! \page preview-actions.html Preview Actions \title Preview Actions \contentspage {Lomiri Action API} The preview action is an action that allows the application to generate a preview of the action before the action is applied. The preview is controlled by the HUD UI. PreviewActions contain one or more parameters which form the preview parameters of the action. The PreviewAction has additional extra requirements compared to other Actions: \list \li - It can have multiple parameters whose values can be seen and changed over the bus \li - The parameters' ordering can be specified by client code \li - It adds new signals to control the preview mode: started, cancelled, resetted \endlist The ordering of the parameters is specified by the order in which the actions are defined in the parameters list. PreviewAction does not have a value of it's own. Instead the values of the parameters provide the information on which the preview is generated. \image hud_parameters.jpg \caption HUD UI showing Color Balance action with four slider parameters \part Control Signals Diagram describing when the different signals are emitted: \image preview_action_signals.png \e {started} signal informs the application that it must set up a preview view and start updating the preview based on the values of the defined preview parameters. \e {resetted} signal informs the application that it has to reset the parameter values to their original values. \e {cancelled} signal informs the application that the user cancelled the PreviewAction. At this point the application must return the the state it was in at the time the \e {started()} signal was triggered without applying any changes. \e {triggered} signal informs the application the user wants the changes to be applied. \part Example \code import QtQuick 2.0 import Lomiri.Action 1.0 Item { ActionManager { PreviewAction { text: "Exposure" PreviewRangeParameter { id: exposureParameter text: "Exposure Amount" minimumValue: -50 maximumValue: 50 value: 25 onValueChanged: { // gets the values from the HUD UI when user interacts with the slider // Application then updates the preview based on this value console.debug("range value: " + value); } } onStarted: { // action was activated in the HUD UI. // do the necessary initialization and start providing preview // based on the values of the parameters. } onResetted: { // reset the parameter values } onCancelled: { // action was cancelled } onTriggered: { // action was completed. // apply the action with the values of the parameters } } } } \endcode */ lomiri-action-api-1.1.3/documentation/qml/qml-api/000077500000000000000000000000001455542516300220455ustar00rootroot00000000000000lomiri-action-api-1.1.3/documentation/qml/qml-api/Action.qml000066400000000000000000000140421455542516300237760ustar00rootroot00000000000000/* This file is part of lomiri-action-api * Copyright 2013 Canonical Ltd. * * lomiri-action-api is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * lomiri-action-api is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY, 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 program. If not, see . */ import QtQuick 2.0 /*! \qmltype Action \inqmlmodule Lomiri.Action 1.0 \ingroup action-base \since 1.0 \brief The main action class. Lomiri services visualizing this class will usually be represented it as a simple button or menu item, depending upon where it is contributed. The optional name property is available through D-Bus and can be used to activate a specific Action from external componenets such as the Launcher. See \l {Platform Integration} and \l {Offline Actions} for more information. If the parameterType property is set, the Action is said to be parameterised. This means that when it is bound to a menu or button, the action expects a typed input parameter. The type affects the allowed value of the QVariant that must be passed to the trigger() and triggered(). \b{note:} As QVariant does automatic conversions between different normally uncorvertable types the developer must be careful of the side effects the conversions might have if accidentally passing wrong type of a parameter to trigger() or when handling the value of triggered(). Please, see the QVariant documentation for more information on the conversions QVariant does. Action has to be added to the ActionManager or a ActionContext to make it available for external components. \qml import Lomiri.Action 1.0 Action { id: myaction1 name: "myaction1" text: i18n.tr("My Action") description: i18n.tr("Perform foo.") onTriggered: { console.debug ("myaction1 is triggered."); } } \endqml */ Item { /*! \qmlproperty string Action::name The name of the action. By default an action gets it's name generated automatically if not overridden with later. If name is set to "" then the action restores it's autogenerated name. The actions is accessible from D-Bus with this name. The name is not user visible. \b {note:} Changing the name is potentially an expensive operation if the action is already added to the manager. If possible, set the name for your action before adding it to the manager. */ property string name /*! \qmlproperty string Action::text : "" The user visible primary label of the action. */ property string text : "" /*! \qmlproperty string Action::description : "" User visible secondary description for the action. Description is more verbose than the text and should describe the Action with couple of words. */ property string description : "" /*! \qmlproperty string Action::keywords Additional user visible keywords for the action. Keywords improve the HUD search results when the user tries to search for an action with a synonym of the text. For example if we the application has an action "Crop" but the user tries to "Trim" then without the keywords the HUD would not try to offer the "Crop" action. The format of the keywords string is "Keyword 1;Keyword 2;Keyword 3" to allow translators to define different number of keywords per language. The keywords are separated by ; and they may contain spaces. \qml Action { text: i18n.tr("Crop") description: i18n.tr("Crop the image") keywords: i18n.tr("Trim;Cut") } \endqml */ property string keywords /*! \qmlproperty bool Action::enabled : true If set to false the action can not be triggered. Components visualizing the action migth either hide the action or make it insensitive. If set to false the Action is removed from the search results of the HUD. */ property bool enabled : true /*! \qmlproperty string Action::iconName : "" Name of a icon for this action. When the action is exported to external components the iconName must be avaible on system icon theme engine. */ property string iconName : "" /*! \qmlproperty Type Action::parameterType : None Type of the parameter passed to trigger() and triggered(). \e {Type} is an enumeration: \list \li \b{Action.None}: No paramater. (default) \li \b{Action.String}: String parameter. \li \b{Action.Integer}: Integer parameter. \li \b{Action.Bool}: Boolean parameter. \li \b{Action.Real}: Single precision floating point parameter. \endlist \qml Action { id: action parameterType: Action.String onTriggered: { // value arguments now contain strings console.log(value); } Component.onCompleted: action.trigger("Hello World") \endqml \b {note:} Changing the parameterType is potentially an expensive operation if the action is already added to the manager. If possible, set the parameterType of your action before adding it to the manager. */ property Type parameterType : None /*! \qmlsignal Action::triggered(var value) The value is always compatible with the set parameterType. */ signal triggered(var value) /*! \qmlmethod void Action::trigger(var value) Checks the value agains parameterType and triggers the action. If paramType is Action::None the action can be triggered by simly calling: \qml action.trigger(); \endqml */ function trigger(value) {} } lomiri-action-api-1.1.3/documentation/qml/qml-api/ActionContext.qml000066400000000000000000000052551455542516300253510ustar00rootroot00000000000000/* This file is part of lomiri-action-api * Copyright 2013 Canonical Ltd. * * lomiri-action-api is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * lomiri-action-api is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY, 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 program. If not, see . */ import QtQuick 2.0 /*! \qmltype ActionContext \inqmlmodule Lomiri.Action 1.0 \ingroup action-base \since 1.0 ActionContext groups actions together and by providing multiple contexts the developer is able to control the visibility of the actions. The ActionManager then exposes the actions from these different contexts. See \l {Action Contexts} for more details. */ Item { /*! \qmlproperty bool ActionContext::active : false If true the context is active. If false the context is inactive. When context has been added to the ActionManager setting this value controls whether or not the actions in a context are available to external components. The ActionManager monitors the active property of each of the local contexts that has been added to it. There can be only one active local context at a time. When one of the local contexts sets itself active the manager will notice this, export the actions from that given context and set the previously active local context as inactive. This way setting active to true on a local context is sufficient to manage the active local context of the manager and no additional calls are necessary to manually inactivate the other contexts. */ property bool active : false /*! \qmlproperty list ActionContext::actions \default List of Actions in this ActionContext. This is the default property of ActionContext. */ property list actions /*! Adds an action to the context. Calling this function multiple times with the same action does not have any side effects; the action gets added only once. */ function addAction(action) {} /*! Removes an action from the context. Calling this function multiple times with the same action does not have any side effects; the action gets removed only if it was first added to the context with addAction(). */ function removeAction(action) {} } lomiri-action-api-1.1.3/documentation/qml/qml-api/ActionManager.qml000066400000000000000000000047401455542516300252750ustar00rootroot00000000000000/* This file is part of lomiri-action-api * Copyright 2013 Canonical Ltd. * * lomiri-action-api is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * lomiri-action-api is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY, 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 program. If not, see . */ import QtQuick 2.0 /*! \qmltype ActionManager \inqmlmodule Lomiri.Action 1.0 \ingroup action-base \since 1.0 \brief ActionManager exports the application actions to the external components. See \l {Platform Integration} and \l {Action Contexts} for more details. */ Item { /*! \qmlproperty ActionContext ActionManager::globalContext The globalContext of the Application. \note Setting the ActionContext::active on the global context has no effect; */ property ActionContext globalContext /*! \qmlproperty list ActionManager::actions \default List of Actions in manager's globalContext. This is the default property of ActionManager. */ property list actions /*! \qmlproperty list ActionManager::localContexts List of localContexts. */ property list localContexts /*! this is a shorthand for \qml manager.globalContext.addAction(action); \endqml \sa ActionContext::addAction() */ function addAction(action) {} /*! this is a shorthand for \qml manager.globalContext.removeAction(action); \endqml \sa ActionContext::removeAction() */ function removeAction(action) {} /*! Adds a local context. Calling this function multiple times with the same context does not have any side effects; the context gets added only once. */ function addLocalContext(context) {} /*! Removes a local context. Calling this function multiple times with the same context does not have any side effects; the context gets removed only if it was previously added with addLocalContext(). */ function removeLocalContext(context) {} } lomiri-action-api-1.1.3/documentation/qml/qml-api/PreviewAction.qml000066400000000000000000000050631455542516300253430ustar00rootroot00000000000000/* This file is part of lomiri-action-api * Copyright 2013 Canonical Ltd. * * lomiri-action-api is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * lomiri-action-api is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY, 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 program. If not, see . */ import QtQuick 2.0 /*! \qmltype PreviewAction \inqmlmodule Lomiri.Action 1.0 \ingroup action-base \since 1.0 \brief previewable action The preview action is an action that allows the application to generate a preview of the action before the action is applied. The preview is controlled by the HUD UI. PreviewActions contain one or more parameters which form the preview parameters of the action. For more details see \l {Preview Actions} \note Even though PreviewAction is subclass of Action not all of the properties of Action base class are supported. \note Action::parameterType must be Action::None */ Action { /*! \qmlproperty QString PreviewAction::commitLabel : "" User visible label shown in the HUD parameter view. This is the label shown in the HUD UI on the button that applies or commits the action after the user is happy with the parameters. If set to empty string the HUD UI will use a default commit label. */ property string commitLabel /*! \qmlsignal PreviewAction::started() Signal to inform that a action is selected in the HUD UI. The application should set the values of the parameters to their initial state. */ signal started() /*! \qmlsignal PreviewAction::cancelled() Signal to inform that the user has cancelled the action from the HUD UI. No modifications should be done on the application and the program should return to the state it was before the action was first started. */ signal cancelled() /*! \qmlsignal PreviewAction::resetted() Signal to inform that the user has clicked the "reset" button from the HUD UI. The action is still active on the HUD UI but the application should reset the values of the parameters to the same values they where when the action was started. */ signal resetted() } lomiri-action-api-1.1.3/documentation/qml/qml-api/PreviewParameter.qml000066400000000000000000000016351455542516300260470ustar00rootroot00000000000000/* This file is part of lomiri-action-api * Copyright 2013 Canonical Ltd. * * lomiri-action-api is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * lomiri-action-api is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY, 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 program. If not, see . */ import QtQuick 2.0 /*! \qmltype PreviewParameter \inqmlmodule Lomiri.Action 1.0 \ingroup action-non-instantiable \since 1.0 Base class for all the parameter classes. See the subclasses. */ Item { } lomiri-action-api-1.1.3/documentation/qml/qml-api/PreviewRangeParameter.qml000066400000000000000000000030311455542516300270140ustar00rootroot00000000000000/* This file is part of lomiri-action-api * Copyright 2013 Canonical Ltd. * * lomiri-action-api is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * lomiri-action-api is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY, 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 program. If not, see . */ import QtQuick 2.0 /*! \qmltype PreviewRangeParameter \inqmlmodule Lomiri.Action 1.0 \ingroup action-parameters \since 1.0 Provides a range preview parameter. See \l {Preview Actions} for more details. */ PreviewParameter { /*! \qmlproperty real PreviewRangeParameter::maximumValue : 100 The maximum value of the range. */ property real maximumValue : 100 /*! \qmlproperty real PreviewRangeParameter::minimumValue : 0 The minimum value of the range. */ property real minimumValue : 0 /*! \qmlproperty string PreviewRangeParameter::text : "" The user visible primary label of the parameter. */ property string text : "" /*! \qmlproperty real PreviewRangeParameter::value : 0 The current value of the range. */ property real value : 0 } lomiri-action-api-1.1.3/documentation/qml/qml-lomiri-hud-hud.qdoc000066400000000000000000000001611455542516300247710ustar00rootroot00000000000000\qmltype Context \instantiates Context \since 1.0 \qmlproperty list Context::actions actions registered to HUD lomiri-action-api-1.1.3/examples/000077500000000000000000000000001455542516300166615ustar00rootroot00000000000000lomiri-action-api-1.1.3/examples/CMakeLists.txt000066400000000000000000000001361455542516300214210ustar00rootroot00000000000000add_subdirectory(action-context) add_subdirectory(preview-action) add_subdirectory(mail-app) lomiri-action-api-1.1.3/examples/action-context/000077500000000000000000000000001455542516300216205ustar00rootroot00000000000000lomiri-action-api-1.1.3/examples/action-context/CMakeLists.txt000066400000000000000000000003171455542516300243610ustar00rootroot00000000000000set(EXAMPLE_SRCS action-context.cpp ) add_executable(action-context ${EXAMPLE_SRCS}) target_link_libraries(action-context lomiri-action-qt) target_link_libraries(action-context Qt5::Core Qt5::Widgets) lomiri-action-api-1.1.3/examples/action-context/action-context.cpp000066400000000000000000000051411455542516300252640ustar00rootroot00000000000000/* This file is part of lomiri-action-api * Copyright 2013 Canonical Ltd. * * lomiri-action-api is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * lomiri-action-api is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY, 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 program. If not, see . */ #include #include #include #include #include #include using namespace lomiri::action; class MainWindow : public QMainWindow { Q_OBJECT public: MainWindow(QWidget *parent = 0); ~MainWindow(); }; MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) { //! [create global action] Action *globalAction = new Action(this); globalAction->setText("My Global"); //! [create global action] //! [create local actions] Action *ctx1Action1 = new Action(this); ctx1Action1->setText("Context1, Action 1"); Action *ctx1Action2 = new Action(this); ctx1Action2->setText("Context1, Action 2"); Action *ctx2Action1 = new Action(this); ctx2Action1->setText("Context2, Action 1"); Action *ctx2Action2 = new Action(this); ctx2Action2->setText("Context2, Action 2"); //! [create local actions] //! [create contexts] ActionContext *ctx1 = new ActionContext(this); ActionContext *ctx2 = new ActionContext(this); //! [create contexts] //! [add context actions] ctx1->addAction(ctx1Action1); ctx1->addAction(ctx1Action2); ctx2->addAction(ctx2Action1); ctx2->addAction(ctx2Action2); //! [add context actions] //! [add global to manager] ActionManager *manager = new ActionManager(this); manager->addAction(globalAction); //! [add global to manager] //! [add local ctx to manager] manager->addLocalContext(ctx1); manager->addLocalContext(ctx2); //! [add local ctx to manager] //! [set context active] ctx2->setActive(true); // now the ActionManager has exported globalAction, ctx2Action1 and ctx2Action2 //! [set context active] } MainWindow::~MainWindow() {} int main(int argc, char *argv[]) { QApplication a(argc, argv); MainWindow w; w.show(); return a.exec(); } #include "action-context.moc" lomiri-action-api-1.1.3/examples/mail-app/000077500000000000000000000000001455542516300203615ustar00rootroot00000000000000lomiri-action-api-1.1.3/examples/mail-app/CMakeLists.txt000066400000000000000000000002661455542516300231250ustar00rootroot00000000000000set(EXAMPLE_SRCS mail-app.cpp ) add_executable(mail-app ${EXAMPLE_SRCS}) target_link_libraries(mail-app lomiri-action-qt) target_link_libraries(mail-app Qt5::Core Qt5::Widgets) lomiri-action-api-1.1.3/examples/mail-app/mail-app.cpp000066400000000000000000000046461455542516300225770ustar00rootroot00000000000000/* This file is part of lomiri-action-api * Copyright 2013 Canonical Ltd. * * lomiri-action-api is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * lomiri-action-api is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY, 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 program. If not, see . */ #include #include #include #include using lomiri::action::Action; using lomiri::action::ActionManager; class MailApp : public QMainWindow { Q_OBJECT public: MailApp(QWidget *parent = 0); public slots: void newMessage(); void openAddressBook(); private: }; MailApp::MailApp(QWidget *parent) : QMainWindow(parent) { //! [setting the compose name] Action *newMessageAction = new Action(this); // matches the .desktop file Desktop Action identifier newMessageAction->setName("Compose"); //! [setting the compose name] newMessageAction->setText(tr("Compose New Message")); newMessageAction->setKeywords(tr("Write New Message;Send New Message")); connect(newMessageAction, &Action::triggered, this, &MailApp::newMessage); //! [setting the contacts name] Action *openAddressBookAction = new Action(this); // matches the .desktop file Desktop Action identifier openAddressBookAction->setName("Contacts"); //! [setting the contacts name] openAddressBookAction->setText(tr("Open Address Book")); connect(openAddressBookAction, &Action::triggered, this, &MailApp::openAddressBook); //! [add to manager] ActionManager *actionManager = new ActionManager(this); actionManager->addAction(newMessageAction); actionManager->addAction(openAddressBookAction); //! [add to manager] } void MailApp::newMessage() { // show the compose view } void MailApp::openAddressBook() { // show the address book view } int main(int argc, char *argv[]) { QApplication *app = new QApplication(argc, argv); MailApp mailApp; mailApp.show(); return app->exec(); } #include "mail-app.moc" lomiri-action-api-1.1.3/examples/mail-app/mail-app.desktop000066400000000000000000000004131455542516300234520ustar00rootroot00000000000000[Desktop Entry] Encoding=UTF-8 Name=Mail Application Exec=mail-app %u Actions=Compose;Contacts [Desktop Action Compose] Name=Compose New Message OnlyShowIn=Messaging Menu;Lomiri; Exec= [Desktop Action Contacts] Name=Contacts OnlyShowIn=Messaging Menu;Lomiri; Exec= lomiri-action-api-1.1.3/examples/preview-action/000077500000000000000000000000001455542516300216155ustar00rootroot00000000000000lomiri-action-api-1.1.3/examples/preview-action/CMakeLists.txt000066400000000000000000000003171455542516300243560ustar00rootroot00000000000000set(EXAMPLE_SRCS preview-action.cpp ) add_executable(preview-action ${EXAMPLE_SRCS}) target_link_libraries(preview-action lomiri-action-qt) target_link_libraries(preview-action Qt5::Core Qt5::Widgets) lomiri-action-api-1.1.3/examples/preview-action/preview-action.cpp000066400000000000000000000061401455542516300252560ustar00rootroot00000000000000/* This file is part of lomiri-action-api * Copyright 2013 Canonical Ltd. * * lomiri-action-api is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * lomiri-action-api is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY, 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 program. If not, see . */ #include #include #include #include #include #include using namespace lomiri::action; class MainWindow : public QMainWindow { Q_OBJECT public: MainWindow(QWidget *parent = 0); ~MainWindow(); }; MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) { //! [create previewaction] PreviewAction *previewAction = new PreviewAction(this); previewAction->setText("Exposure"); //! [create previewaction] //! [create rangeparameter] PreviewRangeParameter *range = new PreviewRangeParameter(this); range->setText("Exposure Amount"); range->setMinimumValue(-50); range->setMaximumValue(50); range->setValue(0); //! [create rangeparameter] //! [set previewaction parameters] previewAction->addParameter(range); //! [set previewaction parameters] //! [add to manager] ActionManager *manager = new ActionManager(this); manager->addAction(previewAction); //! [add to manager] //! [connect previewaction signals] connect(previewAction, &PreviewAction::triggered, [=]() { // action was completed. // apply the action with the values of the parameters qDebug() << "Preview triggered."; }); connect(previewAction, &PreviewAction::cancelled, [=]() { // action was cancelled qDebug() << "Preview cancelled."; }); connect(previewAction, &PreviewAction::started, [=]() { // action was activated in the HUD UI. // do the necessary initialization and start providing preview // based on the values of the parameters. qDebug() << "Preview started."; }); connect(previewAction, &PreviewAction::resetted, [=]() { // reset the parameter values qDebug() << "Preview resetted."; }); //! [connect previewaction signals] //! [connect parameter signals] connect(range, &PreviewRangeParameter::valueChanged, [=](float value) { // gets the values from the HUD UI when user interacts with the slider // Application then updates the preview based on this value qDebug() << "range value:" << value; }); //! [connect parameter signals] } MainWindow::~MainWindow() {} int main(int argc, char *argv[]) { QApplication a(argc, argv); MainWindow w; w.show(); return a.exec(); } #include "preview-action.moc" lomiri-action-api-1.1.3/include/000077500000000000000000000000001455542516300164665ustar00rootroot00000000000000lomiri-action-api-1.1.3/include/lomiri/000077500000000000000000000000001455542516300177615ustar00rootroot00000000000000lomiri-action-api-1.1.3/include/lomiri/action/000077500000000000000000000000001455542516300212365ustar00rootroot00000000000000lomiri-action-api-1.1.3/include/lomiri/action/Action000066400000000000000000000000331455542516300223720ustar00rootroot00000000000000#include "lomiri-action.h" lomiri-action-api-1.1.3/include/lomiri/action/ActionContext000066400000000000000000000000431455542516300237400ustar00rootroot00000000000000#include "lomiri-action-context.h" lomiri-action-api-1.1.3/include/lomiri/action/ActionManager000066400000000000000000000000431455542516300236660ustar00rootroot00000000000000#include "lomiri-action-manager.h" lomiri-action-api-1.1.3/include/lomiri/action/MenuItem000066400000000000000000000000361455542516300227030ustar00rootroot00000000000000#include "lomiri-menu-item.h" lomiri-action-api-1.1.3/include/lomiri/action/PreviewAction000066400000000000000000000000431455542516300237350ustar00rootroot00000000000000#include "lomiri-preview-action.h" lomiri-action-api-1.1.3/include/lomiri/action/PreviewParameter000066400000000000000000000000461455542516300244430ustar00rootroot00000000000000#include "lomiri-preview-parameter.h" lomiri-action-api-1.1.3/include/lomiri/action/PreviewRangeParameter000066400000000000000000000000541455542516300254170ustar00rootroot00000000000000#include "lomiri-preview-range-parameter.h" lomiri-action-api-1.1.3/include/lomiri/action/lomiri-action-context.h000066400000000000000000000031441455542516300256410ustar00rootroot00000000000000/* This file is part of lomiri-action-api * Copyright 2013 Canonical Ltd. * * lomiri-action-api is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * lomiri-action-api is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY, 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 program. If not, see . */ #ifndef LOMIRI_ACTION_CONTEXT #define LOMIRI_ACTION_CONTEXT namespace lomiri { namespace action { class ActionContext; class Action; } } #include #include #include class Q_DECL_EXPORT lomiri::action::ActionContext : public QObject { Q_OBJECT Q_DISABLE_COPY(ActionContext) Q_PROPERTY(bool active READ active WRITE setActive NOTIFY activeChanged) public: explicit ActionContext(QObject *parent = 0); virtual ~ActionContext(); Q_INVOKABLE void addAction(lomiri::action::Action *action); Q_INVOKABLE void removeAction(lomiri::action::Action *action); bool active() const; void setActive(bool value); QSet actions() const; signals: void activeChanged(bool value); void actionsChanged(); private: class Private; QScopedPointer d; }; #endif lomiri-action-api-1.1.3/include/lomiri/action/lomiri-action-manager.h000066400000000000000000000035101455542516300255640ustar00rootroot00000000000000/* This file is part of lomiri-action-api * Copyright 2013 Canonical Ltd. * * lomiri-action-api is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * lomiri-action-api is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY, 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 program. If not, see . */ #ifndef LOMIRI_ACTION_MANAGER #define LOMIRI_ACTION_MANAGER namespace lomiri { namespace action { class ActionManager; class ActionContext; class Action; } } #include #include class Q_DECL_EXPORT lomiri::action::ActionManager : public QObject { Q_OBJECT Q_DISABLE_COPY(ActionManager) Q_PROPERTY(lomiri::action::ActionContext *globalContext READ globalContext) public: explicit ActionManager(QObject *parent = 0); virtual ~ActionManager(); Q_INVOKABLE void addAction(lomiri::action::Action *action); Q_INVOKABLE void removeAction(lomiri::action::Action *action); Q_INVOKABLE lomiri::action::ActionContext *globalContext(); Q_INVOKABLE void addLocalContext(lomiri::action::ActionContext *context); Q_INVOKABLE void removeLocalContext(lomiri::action::ActionContext *context); QSet localContexts() const; QSet actions() const; signals: void localContextsChanged(); void actionsChanged(); Q_REVISION(1) void quit(); private: class Private; QScopedPointer d; }; #endif lomiri-action-api-1.1.3/include/lomiri/action/lomiri-action.h000066400000000000000000000062121455542516300241560ustar00rootroot00000000000000/* This file is part of lomiri-action-api * Copyright 2013 Canonical Ltd. * * lomiri-action-api is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * lomiri-action-api is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY, 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 program. If not, see . */ #ifndef LOMIRI_ACTION_ACTION #define LOMIRI_ACTION_ACTION namespace lomiri { namespace action { class Action; } } #include #include #include class Q_DECL_EXPORT lomiri::action::Action : public QObject { Q_OBJECT Q_DISABLE_COPY(Action) Q_ENUMS(Type) Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged) Q_PROPERTY(QString text READ text WRITE setText NOTIFY textChanged) Q_PROPERTY(QString iconName READ iconName WRITE setIconName NOTIFY iconNameChanged) Q_PROPERTY(QString description READ description WRITE setDescription NOTIFY descriptionChanged) Q_PROPERTY(QString keywords READ keywords WRITE setKeywords NOTIFY keywordsChanged) Q_PROPERTY(bool enabled READ enabled WRITE setEnabled NOTIFY enabledChanged) Q_PROPERTY(lomiri::action::Action::Type parameterType READ parameterType WRITE setParameterType NOTIFY parameterTypeChanged) public: enum Type { None, String, Integer, Bool, Real }; explicit Action(QObject *parent = 0); virtual ~Action(); QString name() const; void setName(const QString &value); QString text() const; void setText(const QString &value); QString iconName() const; void setIconName(const QString &value); QString description() const; void setDescription(const QString &value); QString keywords() const; void setKeywords(const QString &value); bool enabled() const; void setEnabled(bool value); Type parameterType() const; void setParameterType(Type value); public slots: void trigger(QVariant value = QVariant()); signals: void nameChanged(const QString &value); void textChanged(const QString &value); void iconNameChanged(const QString &value); void descriptionChanged(const QString &value); void keywordsChanged(const QString &value); void enabledChanged(bool value); void parameterTypeChanged(lomiri::action::Action::Type value); void triggered(QVariant value); private: class Private; QScopedPointer d; }; Q_DECLARE_METATYPE(lomiri::action::Action::Type) #endif lomiri-action-api-1.1.3/include/lomiri/action/lomiri-menu-item.h000066400000000000000000000051321455542516300246010ustar00rootroot00000000000000/* This file is part of lomiri-action-api * Copyright 2013 Canonical Ltd. * * lomiri-action-api is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * lomiri-action-api is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY, 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 program. If not, see . */ #ifndef LOMIRI_ACTION_MENUITEM #define LOMIRI_ACTION_MENUITEM namespace lomiri { namespace action { class MenuItem; class Action; } } #include #include #include // Make private for now. /*! \private */ class Q_DECL_HIDDEN lomiri::action::MenuItem : public QObject { Q_OBJECT Q_DISABLE_COPY(MenuItem) Q_PROPERTY(lomiri::action::Action *action READ action WRITE setAction NOTIFY actionChanged) Q_PROPERTY(QString text READ text WRITE setText NOTIFY textChanged) Q_PROPERTY(QString iconName READ iconName WRITE setIconName NOTIFY iconNameChanged) Q_PROPERTY(QVariant target READ target WRITE setTarget NOTIFY targetChanged) Q_PROPERTY(bool visible READ visible WRITE setVisible NOTIFY visibleChanged) Q_PROPERTY(bool enabled READ enabled WRITE setEnabled NOTIFY enabledChanged) public: explicit MenuItem(QObject *parent =0); virtual ~MenuItem(); Action *action() const; void setAction(Action *value); QString text() const; void setText(const QString &value); QString iconName() const; void setIconName(const QString &value); QVariant target() const; void setTarget(const QVariant &value); bool visible() const; void setVisible(bool value); bool enabled() const; void setEnabled(bool value); signals: void actionChanged(); void textChanged(const QString &value); void iconNameChanged(const QString &value); void targetChanged(const QVariant &value); void visibleChanged(bool value); void enabledChanged(bool value); private: class Private; QScopedPointer d; }; #endif lomiri-action-api-1.1.3/include/lomiri/action/lomiri-preview-action.h000066400000000000000000000034111455542516300256330ustar00rootroot00000000000000/* This file is part of lomiri-action-api * Copyright 2013 Canonical Ltd. * * lomiri-action-api is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * lomiri-action-api is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY, 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 program. If not, see . */ #ifndef LOMIRI_ACTION_PREVIEW_ACTION #define LOMIRI_ACTION_PREVIEW_ACTION namespace lomiri { namespace action { class PreviewAction; class PreviewParameter; } } #include "lomiri-action.h" class Q_DECL_EXPORT lomiri::action::PreviewAction : public lomiri::action::Action { Q_OBJECT Q_DISABLE_COPY(PreviewAction) Q_PROPERTY(QString commitLabel READ commitLabel WRITE setCommitLabel NOTIFY commitLabelChanged) public: explicit PreviewAction(QObject *parent = 0); virtual ~PreviewAction(); QString commitLabel() const; void setCommitLabel(const QString &value); QList parameters(); Q_INVOKABLE void addParameter(lomiri::action::PreviewParameter *parameter); Q_INVOKABLE void removeParameter(lomiri::action::PreviewParameter *parameter); signals: void started(); void cancelled(); void resetted(); void commitLabelChanged(const QString &value); void parametersChanged(); private: class Private; QScopedPointer d; }; #endif lomiri-action-api-1.1.3/include/lomiri/action/lomiri-preview-parameter.h000066400000000000000000000022511455542516300263370ustar00rootroot00000000000000/* This file is part of lomiri-action-api * Copyright 2013 Canonical Ltd. * * lomiri-action-api is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * lomiri-action-api is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY, 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 program. If not, see . */ #ifndef LOMIRI_ACTION_PREVIEW_PARAMETER #define LOMIRI_ACTION_PREVIEW_PARAMETER namespace lomiri { namespace action { class PreviewParameter; } } #include class Q_DECL_EXPORT lomiri::action::PreviewParameter : public QObject { Q_OBJECT Q_DISABLE_COPY(PreviewParameter) public: virtual ~PreviewParameter(); protected: explicit PreviewParameter(QObject *parent = 0); private: class Private; QScopedPointer d; }; #endif lomiri-action-api-1.1.3/include/lomiri/action/lomiri-preview-range-parameter.h000066400000000000000000000043001455542516300274260ustar00rootroot00000000000000/* This file is part of lomiri-action-api * Copyright 2013 Canonical Ltd. * * lomiri-action-api is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * lomiri-action-api is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY, 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 program. If not, see . */ #ifndef LOMIRI_ACTION_PREVIEW_RANGE_PARAMETER #define LOMIRI_ACTION_PREVIEW_RANGE_PARAMETER #include namespace lomiri { namespace action { class PreviewRangeParameter; } } class Q_DECL_EXPORT lomiri::action::PreviewRangeParameter : public lomiri::action::PreviewParameter { Q_OBJECT Q_DISABLE_COPY(PreviewRangeParameter) Q_PROPERTY(QString text READ text WRITE setText NOTIFY textChanged) Q_PROPERTY(float value READ value WRITE setValue NOTIFY valueChanged) Q_PROPERTY(float minimumValue READ minimumValue WRITE setMinimumValue NOTIFY minimumValueChanged) Q_PROPERTY(float maximumValue READ maximumValue WRITE setMaximumValue NOTIFY maximumValueChanged) public: explicit PreviewRangeParameter(QObject *parent = 0); virtual ~PreviewRangeParameter(); QString text() const; void setText(const QString &value); float value() const; void setValue(float value); float minimumValue() const; void setMinimumValue(float value); float maximumValue() const; void setMaximumValue(float value); signals: void textChanged(const QString &text); void valueChanged(float value); void minimumValueChanged(float value); void maximumValueChanged(float value); private: class Private; QScopedPointer d; }; #endif lomiri-action-api-1.1.3/qml/000077500000000000000000000000001455542516300156345ustar00rootroot00000000000000lomiri-action-api-1.1.3/qml/CMakeLists.txt000066400000000000000000000000311455542516300203660ustar00rootroot00000000000000add_subdirectory(Lomiri) lomiri-action-api-1.1.3/qml/Lomiri/000077500000000000000000000000001455542516300170675ustar00rootroot00000000000000lomiri-action-api-1.1.3/qml/Lomiri/Action/000077500000000000000000000000001455542516300203045ustar00rootroot00000000000000lomiri-action-api-1.1.3/qml/Lomiri/Action/CMakeLists.txt000066400000000000000000000020741455542516300230470ustar00rootroot00000000000000set(CORE_SRCS plugin.cpp qml-action.cpp qml-preview-action.cpp qml-manager.cpp qml-context.cpp ) # Build everything twice. Since we have only a few # source files, this is not an issue. If it does # become one, change tools so they use the plugin # instead of calling the classes directly. add_library(lomiri-action-qml SHARED ${CORE_SRCS} ) target_link_libraries(lomiri-action-qml lomiri-action-qt) target_link_libraries(lomiri-action-qml Qt5::Qml) get_target_property(QMAKE_EXECUTABLE Qt5::qmake LOCATION) exec_program(${QMAKE_EXECUTABLE} ARGS "-query QT_INSTALL_QML" OUTPUT_VARIABLE QT_IMPORTS_DIR) file(TO_CMAKE_PATH "${QT_IMPORTS_DIR}" QT_IMPORTS_DIR) install( TARGETS lomiri-action-qml ARCHIVE DESTINATION ${QT_IMPORTS_DIR}/Lomiri/Action RUNTIME DESTINATION bin LIBRARY DESTINATION ${QT_IMPORTS_DIR}/Lomiri/Action ) install( FILES qmldir DESTINATION ${QT_IMPORTS_DIR}/Lomiri/Action ) # copy qmldir file into build directory for shadow builds file(COPY "${CMAKE_CURRENT_SOURCE_DIR}/qmldir" DESTINATION ${CMAKE_CURRENT_BINARY_DIR} ) lomiri-action-api-1.1.3/qml/Lomiri/Action/plugin.cpp000066400000000000000000000051021455542516300223040ustar00rootroot00000000000000/* This file is part of lomiri-action-api * Copyright 2013 Canonical Ltd. * * lomiri-action-api is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * lomiri-action-api is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY, 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 program. If not, see . */ #include "plugin.h" #include #include "qml-action.h" #include "qml-preview-action.h" #include "qml-context.h" #include "qml-manager.h" #include #include #include void LomiriActionQmlPlugin::registerTypes(const char *uri) { // @uri Lomiri.Action qmlRegisterType (); qmlRegisterType (uri, 1, 0, "Action"); qmlRegisterType (uri, 1, 1, "Action"); qmlRegisterType (); qmlRegisterType (uri, 1, 0, "PreviewAction"); qmlRegisterType (uri, 1, 1, "PreviewAction"); qmlRegisterType (); qmlRegisterType (uri, 1, 0, "PreviewRangeParameter"); qmlRegisterType (uri, 1, 1, "PreviewRangeParameter"); // Don't provide menu item just yet. //qmlRegisterType (uri, 1, 0, "MenuItem"); qmlRegisterType (); qmlRegisterType (uri, 1, 0, "ActionContext"); qmlRegisterType (uri, 1, 1, "ActionContext"); qmlRegisterType (uri, 1, 0, ""); qmlRegisterType (uri, 1, 1, ""); qmlRegisterType (uri, 1, 0, "ActionManager"); qmlRegisterType (uri, 1, 1, "ActionManager"); } void LomiriActionQmlPlugin::initializeEngine(QQmlEngine *engine, const char *uri) { Q_UNUSED(uri); Q_UNUSED(engine); } lomiri-action-api-1.1.3/qml/Lomiri/Action/plugin.h000066400000000000000000000022131455542516300217510ustar00rootroot00000000000000/* This file is part of lomiri-action-api * Copyright 2013 Canonical Ltd. * * lomiri-action-api is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * lomiri-action-api is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY, 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 program. If not, see . */ #ifndef LOMIRI_ACTION_QML_PLUGIN_H #define LOMIRI_ACTION_QML_PLUGIN_H #include class LomiriActionQmlPlugin : public QQmlExtensionPlugin { Q_OBJECT Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface") Q_INTERFACES(QQmlExtensionInterface) public: void registerTypes(const char *uri); void initializeEngine(QQmlEngine *engine, const char *uri); }; #endif // LOMIRI_ACTION_QML_PLUGIN_H lomiri-action-api-1.1.3/qml/Lomiri/Action/qml-action.cpp000066400000000000000000000015671455542516300230650ustar00rootroot00000000000000/* This file is part of lomiri-action-api * Copyright 2013 Canonical Ltd. * * lomiri-action-api is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * lomiri-action-api is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY, 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 program. If not, see . */ #include "qml-action.h" using namespace lomiri::action; qml::Action::Action(QObject *parent) : lomiri::action::Action(parent) { } qml::Action::~Action() { } lomiri-action-api-1.1.3/qml/Lomiri/Action/qml-action.h000066400000000000000000000022341455542516300225220ustar00rootroot00000000000000/* This file is part of lomiri-action-api * Copyright 2013 Canonical Ltd. * * lomiri-action-api is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * lomiri-action-api is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY, 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 program. If not, see . */ #ifndef LOMIRI_ACTION_QML_ACTION #define LOMIRI_ACTION_QML_ACTION namespace lomiri { namespace action { namespace qml { class Action; } } } #include #include #include #include class Q_DECL_EXPORT lomiri::action::qml::Action : public lomiri::action::Action { Q_OBJECT Q_DISABLE_COPY(Action) public: explicit Action(QObject *parent = 0); virtual ~Action(); }; #endif lomiri-action-api-1.1.3/qml/Lomiri/Action/qml-context.cpp000066400000000000000000000043451455542516300232710ustar00rootroot00000000000000/* This file is part of lomiri-action-api * Copyright 2013 Canonical Ltd. * * lomiri-action-api is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * lomiri-action-api is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY, 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 program. If not, see . */ #include "qml-context.h" using namespace lomiri::action; qml::ActionContext::ActionContext(QObject *parent) : lomiri::action::ActionContext(parent) { } qml::ActionContext::~ActionContext() { foreach(Action *action, actions()) { removeAction(action); } } QQmlListProperty qml::ActionContext::action_list() { return QQmlListProperty(this, 0, qml::ActionContext::append, qml::ActionContext::count, 0, // at() qml::ActionContext::clear); } void qml::ActionContext::append(QQmlListProperty *list, Action *action) { qml::ActionContext *ctx = qobject_cast(list->object); if (ctx) { ctx->addAction(action); return; } Q_ASSERT(0); // should not be reached } void qml::ActionContext::clear(QQmlListProperty *list) { qml::ActionContext *ctx = qobject_cast(list->object); if (ctx) { foreach(Action *action, ctx->actions()) { ctx->removeAction(action); } return; } Q_ASSERT(0); // should not be reached } int qml::ActionContext::count(QQmlListProperty *list) { qml::ActionContext *ctx = qobject_cast(list->object); if (ctx) { return ctx->actions().count(); } Q_ASSERT(0); // should not be reached return 0; } lomiri-action-api-1.1.3/qml/Lomiri/Action/qml-context.h000066400000000000000000000032521455542516300227320ustar00rootroot00000000000000/* This file is part of lomiri-action-api * Copyright 2013 Canonical Ltd. * * lomiri-action-api is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * lomiri-action-api is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY, 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 program. If not, see . */ #ifndef LOMIRI_ACTION_QML_ACTION_CONTEXT #define LOMIRI_ACTION_QML_ACTION_CONTEXT namespace lomiri { namespace action { namespace qml { class ActionContext; } } } #include #include #include class Q_DECL_EXPORT lomiri::action::qml::ActionContext : public lomiri::action::ActionContext { Q_OBJECT Q_DISABLE_COPY(ActionContext) Q_PROPERTY(QQmlListProperty actions READ action_list) Q_CLASSINFO("DefaultProperty", "actions") public: explicit ActionContext(QObject *parent = 0); virtual ~ActionContext(); QQmlListProperty action_list(); private: static void append(QQmlListProperty *list,lomiri::action::Action *action); static void clear(QQmlListProperty *list); static int count(QQmlListProperty *list); }; #endif lomiri-action-api-1.1.3/qml/Lomiri/Action/qml-manager.cpp000066400000000000000000000076311455542516300232200ustar00rootroot00000000000000/* This file is part of lomiri-action-api * Copyright 2013 Canonical Ltd. * * lomiri-action-api is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * lomiri-action-api is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY, 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 program. If not, see . */ #include "qml-manager.h" using namespace lomiri::action; qml::ActionManager::ActionManager(QObject *parent) : lomiri::action::ActionManager(parent) { } qml::ActionManager::~ActionManager() { foreach(Action *action, globalContext()->actions()) { removeAction(action); } foreach(ActionContext *context, localContexts()) { removeLocalContext(context); } } QQmlListProperty qml::ActionManager::localContexts_list() { return QQmlListProperty(this, 0, qml::ActionManager::contextAppend, qml::ActionManager::contextCount, 0, // at() qml::ActionManager::contextClear); } QQmlListProperty qml::ActionManager::actions_list() { return QQmlListProperty(this, 0, qml::ActionManager::actionAppend, qml::ActionManager::actionCount, 0, // at qml::ActionManager::actionClear); } void qml::ActionManager::contextAppend(QQmlListProperty *list, ActionContext *context) { qml::ActionManager *manager = qobject_cast(list->object); if (manager) { manager->addLocalContext(context); return; } Q_ASSERT(0); // should not be reached } void qml::ActionManager::contextClear(QQmlListProperty *list) { qml::ActionManager *manager = qobject_cast(list->object); if (manager) { foreach(ActionContext *context, manager->localContexts()) { manager->removeLocalContext(context); } return; } Q_ASSERT(0); // should not be reached } int qml::ActionManager::contextCount(QQmlListProperty *list) { qml::ActionManager *manager = qobject_cast(list->object); if (manager) { return manager->localContexts().count(); } Q_ASSERT(0); // should not be reached return 0; } void qml::ActionManager::actionAppend(QQmlListProperty *list, Action *action) { qml::ActionManager *manager = qobject_cast(list->object); if (manager) { manager->globalContext()->addAction(action); return; } Q_ASSERT(0); // should not be reached } void qml::ActionManager::actionClear(QQmlListProperty *list) { qml::ActionManager *manager = qobject_cast(list->object); if (manager) { foreach(Action *action, manager->globalContext()->actions()) { manager->globalContext()->removeAction(action); } return; } Q_ASSERT(0); // should not be reached } int qml::ActionManager::actionCount(QQmlListProperty *list) { qml::ActionManager *manager = qobject_cast(list->object); if (manager) { return manager->globalContext()->actions().count(); } Q_ASSERT(0); // should not be reached return 0; } lomiri-action-api-1.1.3/qml/Lomiri/Action/qml-manager.h000066400000000000000000000040611455542516300226570ustar00rootroot00000000000000/* This file is part of lomiri-action-api * Copyright 2013 Canonical Ltd. * * lomiri-action-api is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * lomiri-action-api is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY, 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 program. If not, see . */ #ifndef LOMIRI_ACTION_QML_ACTION_MANAGER #define LOMIRI_ACTION_QML_ACTION_MANAGER #include #include #include #include namespace lomiri { namespace action { namespace qml { class ActionManager; } } } class lomiri::action::qml::ActionManager : public lomiri::action::ActionManager { Q_OBJECT Q_DISABLE_COPY(ActionManager) Q_PROPERTY(QQmlListProperty localContexts READ localContexts_list) Q_PROPERTY(QQmlListProperty actions READ actions_list) Q_CLASSINFO("DefaultProperty", "actions") public: ActionManager(QObject *parent = 0); virtual ~ActionManager(); QQmlListProperty localContexts_list(); QQmlListProperty actions_list(); private: static void contextAppend(QQmlListProperty *list, ActionContext *context); static void contextClear(QQmlListProperty *list); static int contextCount(QQmlListProperty *list); static void actionAppend(QQmlListProperty *list, Action *action); static void actionClear(QQmlListProperty *list); static int actionCount(QQmlListProperty *list); }; #endif lomiri-action-api-1.1.3/qml/Lomiri/Action/qml-preview-action.cpp000066400000000000000000000056561455542516300245470ustar00rootroot00000000000000/* This file is part of lomiri-action-api * Copyright 2013 Canonical Ltd. * * lomiri-action-api is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * lomiri-action-api is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY, 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 program. If not, see . */ #include "qml-preview-action.h" using namespace lomiri::action; qml::PreviewAction::PreviewAction(QObject *parent) : lomiri::action::PreviewAction(parent) { } qml::PreviewAction::~PreviewAction() { foreach(PreviewParameter *parameter, parameters()) { removeParameter(parameter); } } QQmlListProperty qml::PreviewAction::parameters_list() { return QQmlListProperty(this, 0, qml::PreviewAction::append, qml::PreviewAction::count, qml::PreviewAction::at, qml::PreviewAction::clear); } void qml::PreviewAction::append(QQmlListProperty *list, lomiri::action::PreviewParameter *parameter) { qml::PreviewAction *action = qobject_cast(list->object); if (action) { action->addParameter(parameter); return; } Q_ASSERT(0); // should not be reached } PreviewParameter * qml::PreviewAction::at(QQmlListProperty *list, int index) { qml::PreviewAction *action = qobject_cast(list->object); if (action) return action->parameters().at(index); Q_ASSERT(0); // should not be reached return 0; } void qml::PreviewAction::clear(QQmlListProperty *list) { qml::PreviewAction *action = qobject_cast(list->object); if (action) { foreach(PreviewParameter *parameter, action->parameters()) { action->removeParameter(parameter); } return; } Q_ASSERT(0); // should not be reached } int qml::PreviewAction::count(QQmlListProperty *list) { qml::PreviewAction *action = qobject_cast(list->object); if (action) { return action->parameters().count(); } Q_ASSERT(0); // should not be reached return 0; } lomiri-action-api-1.1.3/qml/Lomiri/Action/qml-preview-action.h000066400000000000000000000035141455542516300242030ustar00rootroot00000000000000/* This file is part of lomiri-action-api * Copyright 2013 Canonical Ltd. * * lomiri-action-api is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * lomiri-action-api is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY, 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 program. If not, see . */ #ifndef LOMIRI_ACTION_QML_PREVIEW_ACTION #define LOMIRI_ACTION_QML_PREVIEW_ACTION namespace lomiri { namespace action { namespace qml { class PreviewAction; } } } #include #include class Q_DECL_EXPORT lomiri::action::qml::PreviewAction : public lomiri::action::PreviewAction { Q_OBJECT Q_DISABLE_COPY(PreviewAction) Q_PROPERTY(QQmlListProperty parameters READ parameters_list) Q_CLASSINFO("DefaultProperty", "parameters") public: explicit PreviewAction(QObject *parent = 0); virtual ~PreviewAction(); QQmlListProperty parameters_list(); private: static void append(QQmlListProperty *list, lomiri::action::PreviewParameter *parameter); static lomiri::action::PreviewParameter *at(QQmlListProperty *list, int index); static void clear(QQmlListProperty *list); static int count(QQmlListProperty *list); signals: }; #endif lomiri-action-api-1.1.3/qml/Lomiri/Action/qmldir000066400000000000000000000000561455542516300215200ustar00rootroot00000000000000module Lomiri.Action plugin lomiri-action-qml lomiri-action-api-1.1.3/qml/Lomiri/CMakeLists.txt000066400000000000000000000000311455542516300216210ustar00rootroot00000000000000add_subdirectory(Action) lomiri-action-api-1.1.3/src/000077500000000000000000000000001455542516300156325ustar00rootroot00000000000000lomiri-action-api-1.1.3/src/CMakeLists.txt000066400000000000000000000043411455542516300203740ustar00rootroot00000000000000if (NOT use_libhud2) add_subdirectory(libhud) endif() set(CORE_SRCS lomiri-action.cpp lomiri-preview-action.cpp lomiri-preview-parameter.cpp lomiri-preview-range-parameter.cpp lomiri-menu-item.cpp lomiri-action-manager.cpp lomiri-action-context.cpp ) set(PUBLIC_HEADER_DIR "${CMAKE_SOURCE_DIR}/include/lomiri/action") set(PUBLIC_HEADERS ${PUBLIC_HEADER_DIR}/Action ${PUBLIC_HEADER_DIR}/lomiri-action.h ${PUBLIC_HEADER_DIR}/PreviewAction ${PUBLIC_HEADER_DIR}/lomiri-preview-action.h ${PUBLIC_HEADER_DIR}/PreviewParameter ${PUBLIC_HEADER_DIR}/lomiri-preview-parameter.h ${PUBLIC_HEADER_DIR}/PreviewRangeParameter ${PUBLIC_HEADER_DIR}/lomiri-preview-range-parameter.h # Don't publish MenuItem yet as we don't have any consumers # ${PUBLIC_HEADER_DIR}/MenuItem ${PUBLIC_HEADER_DIR}/lomiri-menu-item.h ${PUBLIC_HEADER_DIR}/ActionManager ${PUBLIC_HEADER_DIR}/lomiri-action-manager.h ${PUBLIC_HEADER_DIR}/ActionContext ${PUBLIC_HEADER_DIR}/lomiri-action-context.h ) include_directories(${HUD_INCLUDE_DIRS}) add_library(lomiri-action-qt SHARED ${CORE_SRCS} ${PUBLIC_HEADERS} # public headers have to be included here for Q_DECL_EXPORT to work properly ) target_link_libraries (lomiri-action-qt ${HUD_LIBRARIES}) target_link_libraries(lomiri-action-qt Qt5::Core) install( TARGETS lomiri-action-qt ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} RUNTIME DESTINATION bin LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} ) set(API_VERSION_MAJOR 1) set(API_VERSION_MINOR 1) set(SO_VERSION ${API_VERSION_MAJOR}) set_target_properties(lomiri-action-qt PROPERTIES SOVERSION ${SO_VERSION} ) set(PC_FILE_TARGET "${CMAKE_CURRENT_BINARY_DIR}/lomiri-action-qt-${API_VERSION_MAJOR}.pc") set(libdir "${CMAKE_INSTALL_FULL_LIBDIR}") set(includedir "${CMAKE_INSTALL_FULL_INCLUDEDIR}/lomiri-action-qt-${API_VERSION_MAJOR}") set(ABSOLUTE_SO_FILE "${CMAKE_INSTALL_FULL_LIBDIR}/liblomiri-action-qt.so.${SO_VERSION}") configure_file("lomiri-action-qt.pc.in" ${PC_FILE_TARGET} @ONLY) install( FILES ${PC_FILE_TARGET} DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig" ) #install the headers install(FILES ${PUBLIC_HEADERS} DESTINATION "${includedir}/lomiri/action") lomiri-action-api-1.1.3/src/libhud-2/000077500000000000000000000000001455542516300172405ustar00rootroot00000000000000lomiri-action-api-1.1.3/src/libhud-2/hud.h000066400000000000000000000021321455542516300201670ustar00rootroot00000000000000/* * Copyright © 2012 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of either or both of the following licences: * * 1) the GNU Lesser General Public License version 3, as published by * the Free Software Foundation; and/or * 2) the GNU Lesser General Public License version 2.1, 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 warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License version 3 and version 2.1 along with this program. If not, * see * * Author: Ryan Lortie */ #ifndef __HUD_H__ #define __HUD_H__ #define _HUD_H_INSIDE #include #include #undef _HUD_H_INSIDE #endif /* __HUD_H__ */ lomiri-action-api-1.1.3/src/libhud/000077500000000000000000000000001455542516300171015ustar00rootroot00000000000000lomiri-action-api-1.1.3/src/libhud/CMakeLists.txt000066400000000000000000000034541455542516300216470ustar00rootroot00000000000000set(CMAKE_AUTOMOC OFF) include(UseGdbusCodegen) include(UseGlibGeneration) set(HUD_SERVICE_XML ${CMAKE_CURRENT_SOURCE_DIR}/data/com.canonical.hud.xml) set(HUD_APP_XML ${CMAKE_CURRENT_SOURCE_DIR}/data/com.canonical.hud.Application.xml) set(HUD_INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} ) set(HUD_INCLUDE_DIRS ${HUD_INCLUDE_DIRS} PARENT_SCOPE ) set(HUD_LIBRARIES hud ) set(HUD_LIBRARIES ${HUD_LIBRARIES} PARENT_SCOPE ) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c11 -fPIC") include_directories(${HUD_INCLUDE_DIRS}) include_directories(${HUD_SRC_DIR}) add_definitions(-DHUD_COMPILATION=1) ########################### # Generated Lib Hud ########################### set(HUD_GENERATED_HEADERS app-iface.h service-iface.h marshal.h ) set(HUD_GENERATED_SOURCES) message(${HUD_SERVICE_XML}) add_gdbus_codegen( OUTFILES HUD_GENERATED_SOURCES NAME service-iface PREFIX com.canonical.hud. NAMESPACE _HudServiceIface SERVICE_XML ${HUD_SERVICE_XML} ) add_gdbus_codegen( OUTFILES HUD_GENERATED_SOURCES NAME app-iface PREFIX com.canonical.hud.Application. NAMESPACE _HudAppIface SERVICE_XML ${HUD_APP_XML} ) add_glib_marshal(HUD_GENERATED_SOURCES marshal _hud_marshal marshal.h ) message(${HUD_GENERATED_SOURCES}) add_library(hud-generated STATIC ${HUD_GENERATED_SOURCES}) target_link_libraries(hud-generated ${GLIB2_LIBRARIES} ${GOBJECT2_LIBRARIES} ${GIO2_LIBRARIES} ) ########################### # Lib Hud ########################### set(HUD_MAIN_HEADERS hud.h ) set(HUD_HEADERS manager.h action-publisher.h ${HUD_HEADERS} ) set(HUD_SOURCES manager.c action-publisher.c ) message(${HUD_SOURCES}) add_library(hud STATIC ${HUD_SOURCES}) target_link_libraries(${HUD_LIBRARIES} hud-generated ${GLIB2_LIBRARIES} ${GOBJECT2_LIBRARIES} )lomiri-action-api-1.1.3/src/libhud/action-publisher.c000066400000000000000000000650021455542516300225200ustar00rootroot00000000000000/* * Copyright © 2012 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of either or both of the following licences: * * 1) the GNU Lesser General Public License version 3, as published by * the Free Software Foundation; and/or * 2) the GNU Lesser General Public License version 2.1, 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 warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License version 3 and version 2.1 along with this program. If not, * see * * Author: Ryan Lortie */ #include "action-publisher.h" #include "manager.h" #include "marshal.h" #include typedef GMenuModelClass HudAuxClass; typedef struct { GMenuModel parent_instance; HudActionPublisher *publisher; } HudAux; static void hud_aux_init_action_group_iface (GActionGroupInterface *iface); static void hud_aux_init_remote_action_group_iface (GRemoteActionGroupInterface *iface); G_DEFINE_TYPE_WITH_CODE (HudAux, _hud_aux, G_TYPE_MENU_MODEL, G_IMPLEMENT_INTERFACE (G_TYPE_ACTION_GROUP, hud_aux_init_action_group_iface) G_IMPLEMENT_INTERFACE (G_TYPE_REMOTE_ACTION_GROUP, hud_aux_init_remote_action_group_iface)) typedef GObjectClass HudActionPublisherClass; struct _HudActionPublisher { GObject parent_instance; guint window_id; gchar * context_id; GDBusConnection *bus; GApplication *application; gint export_id; gchar *path; GSequence *descriptions; HudAux *aux; GList * action_groups; }; enum { SIGNAL_ACTION_GROUP_ADDED, SIGNAL_ACTION_GROUP_REMOVED, N_SIGNALS }; guint hud_action_publisher_signals[N_SIGNALS]; G_DEFINE_TYPE (HudActionPublisher, hud_action_publisher, G_TYPE_OBJECT) typedef GObjectClass HudActionDescriptionClass; struct _HudActionDescription { GObject parent_instance; gchar *identifier; gchar *action; GVariant *target; GHashTable *attrs; GHashTable *links; }; guint hud_action_description_changed_signal; G_DEFINE_TYPE (HudActionDescription, hud_action_description, G_TYPE_OBJECT) static gboolean hud_aux_is_mutable (G_GNUC_UNUSED GMenuModel *model) { return TRUE; } static gint hud_aux_get_n_items (GMenuModel *model) { HudAux *aux = (HudAux *) model; return g_sequence_get_length (aux->publisher->descriptions); } static void hud_aux_get_item_attributes (GMenuModel *model, gint item_index, GHashTable **attributes) { HudAux *aux = (HudAux *) model; GSequenceIter *iter; HudActionDescription *description; iter = g_sequence_get_iter_at_pos (aux->publisher->descriptions, item_index); description = g_sequence_get (iter); *attributes = g_hash_table_ref (description->attrs); } static void hud_aux_get_item_links (GMenuModel *model, gint item_index, GHashTable **links) { HudAux *aux = (HudAux *) model; GSequenceIter *iter; HudActionDescription *description; iter = g_sequence_get_iter_at_pos (aux->publisher->descriptions, item_index); description = g_sequence_get (iter); if (description->links != NULL) *links = g_hash_table_ref(description->links); else *links = g_hash_table_new (NULL, NULL); } static void _hud_aux_init (G_GNUC_UNUSED HudAux *aux) { } static void hud_aux_init_action_group_iface (G_GNUC_UNUSED GActionGroupInterface *iface) { } static void hud_aux_init_remote_action_group_iface (G_GNUC_UNUSED GRemoteActionGroupInterface *iface) { } static void hud_action_publisher_action_group_set_destroy (gpointer data) { HudActionPublisherActionGroupSet *group = data; g_free(group->prefix); g_free(group->path); g_free(group); } static void _hud_aux_class_init (HudAuxClass *class) { class->is_mutable = hud_aux_is_mutable; class->get_n_items = hud_aux_get_n_items; class->get_item_attributes = hud_aux_get_item_attributes; class->get_item_links = hud_aux_get_item_links; } static void hud_action_publisher_dispose (GObject *object) { HudActionPublisher *self = HUD_ACTION_PUBLISHER(object); g_clear_object(&self->aux); g_clear_object(&self->application); if (self->export_id != 0) { g_debug("Un-exporting menu model at with id [%d]", self->export_id); g_dbus_connection_unexport_menu_model (self->bus, self->export_id); } g_clear_pointer(&self->path, g_free); g_clear_pointer(&self->descriptions, g_sequence_free); g_list_free_full(self->action_groups, (GDestroyNotify)hud_action_publisher_action_group_set_destroy); g_clear_object(&self->bus); G_OBJECT_CLASS (hud_action_publisher_parent_class)->dispose (object); } static void hud_action_publisher_finalize (GObject *object) { g_clear_pointer (&HUD_ACTION_PUBLISHER(object)->context_id, g_free); G_OBJECT_CLASS (hud_action_publisher_parent_class)->finalize (object); return; } static void hud_action_publisher_init (HudActionPublisher *publisher) { static guint64 next_id; publisher->descriptions = g_sequence_new (g_object_unref); publisher->aux = g_object_new (_hud_aux_get_type (), NULL); publisher->aux->publisher = publisher; publisher->bus = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL); if (!publisher->bus) return; do { guint64 id = next_id++; GError *error = NULL; if (id == 0) publisher->path = g_strdup_printf ("/com/canonical/hud/publisher"); else publisher->path = g_strdup_printf ("/com/canonical/hud/publisher%" G_GUINT64_FORMAT, id); publisher->export_id = g_dbus_connection_export_menu_model (publisher->bus, publisher->path, G_MENU_MODEL (publisher->aux), &error); g_debug("Exporting menu model at [%s] with id [%d]", publisher->path, publisher->export_id); if (!publisher->export_id) { /* try again... */ g_debug("Exporting failed: %s", error->message); g_error_free(error); error = NULL; g_free (publisher->path); publisher->path = NULL; } } while (publisher->path == NULL); } static void hud_action_publisher_class_init (HudActionPublisherClass *class) { class->dispose = hud_action_publisher_dispose; class->finalize = hud_action_publisher_finalize; /** * HudActionPublisher::action-group-added: * @param1: Prefix for the action group * @param2: Path group is exported on DBus * * Emitted when a new action group is added to the publisher */ hud_action_publisher_signals[SIGNAL_ACTION_GROUP_ADDED] = g_signal_new (HUD_ACTION_PUBLISHER_SIGNAL_ACTION_GROUP_ADDED, HUD_TYPE_ACTION_PUBLISHER, G_SIGNAL_RUN_LAST, 0, NULL, NULL, _hud_marshal_VOID__STRING_STRING, G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_STRING); /** * HudActionPublisher::action-group-removed: * @param1: Prefix for the action group * @param2: Path group is exported on DBus * * Emitted when a new action group is removed from the publisher */ hud_action_publisher_signals[SIGNAL_ACTION_GROUP_REMOVED] = g_signal_new (HUD_ACTION_PUBLISHER_SIGNAL_ACTION_GROUP_REMOVED, HUD_TYPE_ACTION_PUBLISHER, G_SIGNAL_RUN_LAST, 0, NULL, NULL, _hud_marshal_VOID__STRING_STRING, G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_STRING); } /** * hud_action_publisher_new_for_application: * @application: A #GApplication object * * Creates a new #HudActionPublisher and automatically registers the * default actions under the "app" prefix. * * Return value: (transfer full): A new #HudActionPublisher object */ HudActionPublisher * hud_action_publisher_new_for_application (GApplication *application) { HudActionPublisher *publisher; g_return_val_if_fail (G_IS_APPLICATION (application), NULL); g_return_val_if_fail (g_application_get_application_id (application), NULL); g_return_val_if_fail (g_application_get_is_registered (application), NULL); g_return_val_if_fail (!g_application_get_is_remote (application), NULL); publisher = g_object_new (HUD_TYPE_ACTION_PUBLISHER, NULL); publisher->application = g_object_ref (application); hud_action_publisher_add_action_group (publisher, "app", g_application_get_dbus_object_path (application)); return publisher; } static guint context_count = 0; /** * hud_action_publisher_new: * @window_id: (allow-none): A window ID * @context_id: (allow-none): A context ID * * Creates a new #HudActionPublisher based on the window ID passed * in via @window_id and context ID from @context_id. * * Either one of them can be not used by passing in eithe of the * defines #HUD_ACTION_PUBLISHER_ALL_WINDOWS or #HUD_ACTION_PUBLISHER_NO_CONTEXT * for the appropriate parameter. * * Return value: (transfer full): A new #HudActionPublisher object */ HudActionPublisher * hud_action_publisher_new (guint window_id, const gchar * context_id) { HudActionPublisher * publisher; publisher = g_object_new (HUD_TYPE_ACTION_PUBLISHER, NULL); publisher->window_id = window_id; if (context_id != NULL) { publisher->context_id = g_strdup(context_id); } else { publisher->context_id = g_strdup_printf("action-publisher-context-%d", context_count++); } return publisher; } static gchar * format_identifier (const gchar *action_name, GVariant *action_target) { gchar *targetstr; gchar *identifier; if (action_target) { targetstr = g_variant_print (action_target, TRUE); identifier = g_strdup_printf ("%s(%s)", action_name, targetstr); g_free (targetstr); } else identifier = g_strdup_printf ("%s()", action_name); return identifier; } static gint compare_descriptions (gconstpointer a, gconstpointer b, G_GNUC_UNUSED gpointer user_data) { const HudActionDescription *da = a; const HudActionDescription *db = b; return strcmp (da->identifier, db->identifier); } static void description_changed (HudActionDescription *description, G_GNUC_UNUSED const gchar *attribute_name, gpointer user_data) { HudActionPublisher *publisher = user_data; GSequenceIter *iter; iter = g_sequence_lookup (publisher->descriptions, description, compare_descriptions, NULL); g_assert (g_sequence_get (iter) == description); g_menu_model_items_changed (G_MENU_MODEL (publisher->aux), g_sequence_iter_get_position (iter), 1, 1); } static void disconnect_handler (gpointer data, gpointer user_data) { HudActionPublisher *publisher = user_data; HudActionDescription *description = data; #pragma GCC diagnostic ignored "-Wpedantic" g_signal_handlers_disconnect_by_func (description, description_changed, publisher); #pragma GCC diagnostic pop } /** * hud_action_publisher_add_description: * @publisher: the #HudActionPublisher * @description: an action description * * Adds @description to the list of actions that the application exports * to the HUD. * * If the application is already exporting an action with the same name * and target value as @description then it will be replaced. * * You should only use this API for situations like recent documents and * bookmarks. */ void hud_action_publisher_add_description (HudActionPublisher *publisher, HudActionDescription *description) { GSequenceIter *iter; iter = g_sequence_lookup (publisher->descriptions, description, compare_descriptions, NULL); if (iter == NULL) { /* We are not replacing -- add new. */ iter = g_sequence_insert_sorted (publisher->descriptions, description, compare_descriptions, NULL); /* Signal that we added the items */ g_menu_model_items_changed (G_MENU_MODEL (publisher->aux), g_sequence_iter_get_position (iter), 0, 1); } else { /* We are replacing an existing item. */ disconnect_handler (g_sequence_get (iter), publisher); g_sequence_set (iter, description); /* A replace is 1 remove and 1 add */ g_menu_model_items_changed (G_MENU_MODEL (publisher->aux), g_sequence_iter_get_position (iter), 1, 1); } g_object_ref (description); g_signal_connect (description, "changed", G_CALLBACK (description_changed), publisher); } /** * hud_action_publisher_remove_description: * @publisher: the #HudActionPublisher * @action_name: an action name * @action_target: (allow-none): an action target * * Removes the action descriptions that has the name @action_name and * the target value @action_target (including the possibility of %NULL). **/ void hud_action_publisher_remove_description (HudActionPublisher *publisher, const gchar *action_name, GVariant *action_target) { HudActionDescription tmp; GSequenceIter *iter; tmp.identifier = format_identifier (action_name, action_target); iter = g_sequence_lookup (publisher->descriptions, &tmp, compare_descriptions, NULL); g_free (tmp.identifier); if (iter) { gint position; position = g_sequence_iter_get_position (iter); disconnect_handler (g_sequence_get (iter), publisher); g_sequence_remove (iter); g_menu_model_items_changed (G_MENU_MODEL (publisher->aux), position, 1, 0); } } /** * hud_action_publisher_remove_descriptions: * @publisher: the #HudActionPublisher * @action_name: an action name * * Removes all action descriptions that has the name @action_name and * any target value. **/ void hud_action_publisher_remove_descriptions (HudActionPublisher *publisher, const gchar *action_name) { HudActionDescription before, after; GSequenceIter *start, *end; before.identifier = (gchar *) action_name; after.identifier = g_strconcat (action_name, "~", NULL); start = g_sequence_search (publisher->descriptions, &before, compare_descriptions, NULL); end = g_sequence_search (publisher->descriptions, &after, compare_descriptions, NULL); g_free (after.identifier); if (start != end) { gint s, e; s = g_sequence_iter_get_position (start); e = g_sequence_iter_get_position (end); g_sequence_foreach_range (start, end, disconnect_handler, publisher); g_sequence_remove_range (start, end); g_menu_model_items_changed (G_MENU_MODEL (publisher->aux), s, e - s, 0); } } /** * hud_action_publisher_add_action_group: * @publisher: a #HudActionPublisher * @prefix: the action prefix for the group (like "app") * @object_path: the object path of the exported group * * Informs the HUD of the existance of an action group. * * The action group must be published on the shared session bus * connection of this process at @object_path. * * The @prefix defines the type of action group. Currently "app" and * "win" are supported. For example, if the exported action group * contained a "quit" action and you wanted to refer to it as "app.quit" * from action descriptions, then you would use the @prefix "app" here. * * @identifier is a piece of identifying information, depending on which * @prefix is used. Currently, this should be %NULL for the "app" * @prefix and should be a uint32 specifying the window ID (eg: XID) for * the "win" @prefix. * * You do not need to manually export your action groups if you are * using #GApplication. **/ void hud_action_publisher_add_action_group (HudActionPublisher *publisher, const gchar *prefix, const gchar *object_path) { g_return_if_fail(HUD_IS_ACTION_PUBLISHER(publisher)); g_return_if_fail(prefix != NULL); g_return_if_fail(object_path != NULL); HudActionPublisherActionGroupSet * group = g_new0(HudActionPublisherActionGroupSet, 1); group->prefix = g_strdup(prefix); group->path = g_strdup(object_path); publisher->action_groups = g_list_prepend(publisher->action_groups, group); return; } /** * hud_action_publisher_remove_action_group: * @publisher: a #HudActionPublisher * @prefix: the action prefix for the group (like "app") * @identifier: (allow-none): an identifier, or %NULL * * Informs the HUD that an action group no longer exists. * * This reverses the effect of a previous call to * hud_action_publisher_add_action_group() with the same parameters. */ void hud_action_publisher_remove_action_group (G_GNUC_UNUSED HudActionPublisher *publisher, G_GNUC_UNUSED const gchar *prefix, G_GNUC_UNUSED GVariant *identifier) { //hud_manager_remove_actions (publisher->application_id, prefix, identifier); } /** * hud_action_publisher_get_window_id: * @publisher: A #HudActionPublisher object * * Gets the window ID for this publisher * * Return value: The Window ID associtaed with this action publisher */ guint hud_action_publisher_get_window_id (HudActionPublisher *publisher) { g_return_val_if_fail(HUD_IS_ACTION_PUBLISHER(publisher), 0); return publisher->window_id; } /** * hud_action_publisher_get_context_id: * @publisher: A #HudActionPublisher object * * Gets the context ID for this publisher * * Return value: The context ID associtaed with this action publisher */ const gchar * hud_action_publisher_get_context_id (HudActionPublisher *publisher) { g_return_val_if_fail(HUD_IS_ACTION_PUBLISHER(publisher), 0); return publisher->context_id; } /** * hud_action_publisher_get_action_groups: * @publisher: A #HudActionPublisher object * * Grabs the action groups for this publisher * * Return value: (transfer container) (element-type HudActionPublisherActionGroupSet *): The groups in this publisher */ GList * hud_action_publisher_get_action_groups (HudActionPublisher *publisher) { g_return_val_if_fail(HUD_IS_ACTION_PUBLISHER(publisher), NULL); /* TODO: Flesh out */ return publisher->action_groups; } /** * hud_action_publisher_get_description_path: * @publisher: A #HudActionPublisher object * * Grabs the object path of the description for this publisher * * Return value: The object path of the descriptions */ const gchar * hud_action_publisher_get_description_path (HudActionPublisher *publisher) { g_return_val_if_fail(HUD_IS_ACTION_PUBLISHER(publisher), NULL); return publisher->path; } /** * HudActionDescription: * * A description of an action that is accessible from the HUD. This is * an opaque structure type and all accesses must be made via the API. **/ static void hud_action_description_finalize (GObject *object) { HudActionDescription *description = HUD_ACTION_DESCRIPTION (object); g_free (description->identifier); g_free (description->action); if (description->target) g_variant_unref (description->target); g_hash_table_unref (description->attrs); g_clear_pointer(&description->links, g_hash_table_unref); G_OBJECT_CLASS (hud_action_description_parent_class) ->finalize (object); } static void hud_action_description_init (HudActionDescription *description) { description->attrs = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify) g_variant_unref); } static void hud_action_description_class_init (HudActionDescriptionClass *class) { class->finalize = hud_action_description_finalize; /** * HudActionDescription::changed: * @param1: Name of changed property * * Emitted when a property of the action description gets * changed. */ hud_action_description_changed_signal = g_signal_new ("changed", HUD_TYPE_ACTION_DESCRIPTION, G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED, 0, NULL, NULL, g_cclosure_marshal_VOID__STRING, G_TYPE_NONE, 1, G_TYPE_STRING); } /** * hud_action_description_new: * @action_name: a (namespaced) action name * @action_target: an action target * * Creates a new #HudActionDescription. * * The situations in which you want to do this are limited to "dynamic" * types of actions -- things like bookmarks or recent documents. * * Use hud_action_publisher_add_descriptions_from_file() to take care of * the bulk of the actions in your application. * * Returns: a new #HudActionDescription with no attributes **/ HudActionDescription * hud_action_description_new (const gchar *action_name, GVariant *action_target) { HudActionDescription *description; g_return_val_if_fail (action_name != NULL, NULL); description = g_object_new (HUD_TYPE_ACTION_DESCRIPTION, NULL); description->action = g_strdup (action_name); description->target = action_target ? g_variant_ref_sink (action_target) : NULL; description->identifier = format_identifier (action_name, action_target); g_hash_table_insert (description->attrs, g_strdup ("action"), g_variant_ref_sink (g_variant_new_string (action_name))); if (action_target) g_hash_table_insert (description->attrs, g_strdup ("target"), g_variant_ref_sink (action_target)); return description; } /** * hud_action_description_set_attribute_value: * @description: a #HudActionDescription * @attribute_name: an attribute name * @value: (allow-none): the new value for the attribute * * Sets or unsets an attribute on @description. * * You may not change the "action" or "target" attributes. * * If @value is non-%NULL then it is the new value for attribute. A * %NULL @value unsets @attribute_name. * * @value is consumed if it is floating. **/ void hud_action_description_set_attribute_value (HudActionDescription *description, const gchar *attribute_name, GVariant *value) { /* Don't allow setting the action or target as these form the * identity of the description and are stored separately... */ g_return_if_fail (!g_str_equal (attribute_name, "action")); g_return_if_fail (!g_str_equal (attribute_name, "target")); if (value) g_hash_table_insert (description->attrs, g_strdup (attribute_name), g_variant_ref_sink (value)); else g_hash_table_remove (description->attrs, attribute_name); g_signal_emit (description, hud_action_description_changed_signal, g_quark_try_string (attribute_name), attribute_name); } /** * hud_action_description_set_attribute: * @description: a #HudActionDescription * @attribute_name: an attribute name * @format_string: (allow-none): a #GVariant format string * @...: arguments to @format_string * * Sets or unsets an attribute on @description. * * You may not change the "action" or "target" attributes. * * If @format_string is non-%NULL then this call is equivalent to * g_variant_new() and hud_action_description_set_attribute_value(). * * If @format_string is %NULL then this call is equivalent to * hud_action_description_set_attribute_value() with a %NULL value. **/ void hud_action_description_set_attribute (HudActionDescription *description, const gchar *attribute_name, const gchar *format_string, ...) { GVariant *value; if (format_string != NULL) { va_list ap; va_start (ap, format_string); value = g_variant_new_va (format_string, NULL, &ap); va_end (ap); } else value = NULL; hud_action_description_set_attribute_value (description, attribute_name, value); } /** * hud_action_description_get_action_name: * @description: a #HudActionDescription * * Gets the action name of @description. * * This, together with the action target, uniquely identify an action * description. * * Returns: (transfer none): the action name **/ const gchar * hud_action_description_get_action_name (HudActionDescription *description) { return description->action; } /** * hud_action_description_get_action_target: * @description: a #HudActionDescription * * Gets the action target of @description (ie: the #GVariant that will * be passed to invocations of the action). * * This may be %NULL. * * This, together with the action name, uniquely identify an action * description. * * Returns: (transfer none): the target value **/ GVariant * hud_action_description_get_action_target (HudActionDescription *description) { return description->target; } /** * hud_action_description_set_parameterized: * @parent: a #HudActionDescription * @child: The child #GMenuModel to add * * A function to put one action description as a child for the first * one. This is used for parameterized actions where one can set up * children that are displayed on the 'dialog' mode of the HUD. */ void hud_action_description_set_parameterized (HudActionDescription * parent, GMenuModel * child) { g_return_if_fail(HUD_IS_ACTION_DESCRIPTION(parent)); g_return_if_fail(child == NULL || G_IS_MENU_MODEL(child)); /* NULL is allowed to clear it */ if (parent->links == NULL) { parent->links = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_object_unref); } if (child != NULL) { g_hash_table_insert(parent->links, g_strdup(G_MENU_LINK_SUBMENU), g_object_ref(child)); } else { g_hash_table_remove(parent->links, G_MENU_LINK_SUBMENU); } g_signal_emit (parent, hud_action_description_changed_signal, g_quark_try_string (G_MENU_LINK_SUBMENU), G_MENU_LINK_SUBMENU); return; } /** * hud_action_description_ref: * @description: A #HudActionDescription * * Increase the reference count to an action description * * Return value: (transfer none): Value of @description */ HudActionDescription * hud_action_description_ref (HudActionDescription * description) { g_return_val_if_fail(HUD_IS_ACTION_DESCRIPTION(description), NULL); return HUD_ACTION_DESCRIPTION(g_object_ref(description)); } /** * hud_action_description_unref: * @description: A #HudActionDescription * * Decrease the reference count to an action description */ void hud_action_description_unref (HudActionDescription * description) { g_return_if_fail(HUD_IS_ACTION_DESCRIPTION(description)); g_object_unref(description); } lomiri-action-api-1.1.3/src/libhud/action-publisher.h000066400000000000000000000204441455542516300225260ustar00rootroot00000000000000/* * Copyright © 2012 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of either or both of the following licences: * * 1) the GNU Lesser General Public License version 3, as published by * the Free Software Foundation; and/or * 2) the GNU Lesser General Public License version 2.1, 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 warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License version 3 and version 2.1 along with this program. If not, * see * * Author: Ryan Lortie */ #if !defined (_HUD_H_INSIDE) && !defined (HUD_COMPILATION) #error "Only can be included directly." #endif #ifndef __HUD_ACTION_PUBLISHER_H__ #define __HUD_ACTION_PUBLISHER_H__ #include G_BEGIN_DECLS #define HUD_TYPE_ACTION_PUBLISHER (hud_action_publisher_get_type ()) #define HUD_ACTION_PUBLISHER(inst) (G_TYPE_CHECK_INSTANCE_CAST ((inst), \ HUD_TYPE_ACTION_PUBLISHER, HudActionPublisher)) #define HUD_IS_ACTION_PUBLISHER(inst) (G_TYPE_CHECK_INSTANCE_TYPE ((inst), \ HUD_TYPE_ACTION_PUBLISHER)) /** * HUD_ACTION_PUBLISHER_SIGNAL_ACTION_GROUP_ADDED: * * Define for the string to access the signal HudActionPublisher::action-group-added */ #define HUD_ACTION_PUBLISHER_SIGNAL_ACTION_GROUP_ADDED "action-group-added" /** * HUD_ACTION_PUBLISHER_SIGNAL_ACTION_GROUP_REMOVED: * * Define for the string to access the signal HudActionPublisher::action-group-removed */ #define HUD_ACTION_PUBLISHER_SIGNAL_ACTION_GROUP_REMOVED "action-group-removed" GType hud_action_description_get_type (void); #define HUD_TYPE_ACTION_DESCRIPTION (hud_action_description_get_type ()) #define HUD_ACTION_DESCRIPTION(inst) (G_TYPE_CHECK_INSTANCE_CAST ((inst), \ HUD_TYPE_ACTION_DESCRIPTION, HudActionDescription)) #define HUD_IS_ACTION_DESCRIPTION(inst) (G_TYPE_CHECK_INSTANCE_TYPE ((inst), \ HUD_TYPE_ACTION_DESCRIPTION)) /** * HUD_ACTION_PUBLISHER_NO_CONTEXT: * * Can be passed to hud_action_publisher_new() to request that it build * it's own context. */ #define HUD_ACTION_PUBLISHER_NO_CONTEXT (NULL) /** * HUD_ACTION_PUBLISHER_ALL_WINDOWS: * * Can be passed to hud_action_publisher_new() to request that these actions * apply to all windows for the application. */ #define HUD_ACTION_PUBLISHER_ALL_WINDOWS (0) typedef struct _HudActionDescription HudActionDescription; typedef struct _HudActionPublisher HudActionPublisher; typedef struct _HudActionPublisherActionGroupSet HudActionPublisherActionGroupSet; /** * HudActionPublisher: * * An object representing the actions that are published for a * particular context within the application. Most often this is * a window, but could also be used for tabs or other modal style * user contexts in the application. */ /** * HudActionPublisherActionGroupSet: * @prefix: Action prefix for the action group * @path: Path that the action group is exported on DBus * * A set of properties of that describe the action group. */ struct _HudActionPublisherActionGroupSet { gchar * prefix; gchar * path; }; GType hud_action_publisher_get_type (void) G_GNUC_CONST; HudActionPublisher * hud_action_publisher_new (guint window_id, const gchar * context_id); HudActionPublisher * hud_action_publisher_new_for_application (GApplication *application); void hud_action_publisher_add_description (HudActionPublisher *publisher, HudActionDescription *description); void hud_action_publisher_add_action_group (HudActionPublisher *publisher, const gchar *prefix, const gchar *object_path); void hud_action_publisher_remove_action_group (HudActionPublisher *publisher, const gchar *prefix, GVariant *identifier); guint hud_action_publisher_get_window_id (HudActionPublisher *publisher); const gchar * hud_action_publisher_get_context_id (HudActionPublisher *publisher); GList * hud_action_publisher_get_action_groups (HudActionPublisher *publisher); const gchar * hud_action_publisher_get_description_path (HudActionPublisher *publisher); /* Description */ HudActionDescription * hud_action_description_new (const gchar *action_name, GVariant *action_target); HudActionDescription * hud_action_description_ref (HudActionDescription *description); void hud_action_description_unref (HudActionDescription *description); const gchar * hud_action_description_get_action_name (HudActionDescription *description); GVariant * hud_action_description_get_action_target (HudActionDescription *description); void hud_action_description_set_attribute_value (HudActionDescription *description, const gchar *attribute_name, GVariant *value); void hud_action_description_set_attribute (HudActionDescription *description, const gchar *attribute_name, const gchar *format_string, ...); void hud_action_description_set_parameterized (HudActionDescription *parent, GMenuModel *child); /** * SECTION:action-publisher * @short_description: Publish action data to the HUD * @stability: Stable * @include: libhud/action-publisher.h * * Each context in the application should have a #HudActionPublisher * object to represents the actions that are available to the user * when that window and context are visible. This acts as a set of * actions that can be activated by either the window manager changing * focus or the application changing contexts. * * On each action publisher there exits several action groups which can * be separated by allowing different prefixes for those action groups. * A particular prefix should only be used once per action publisher, but * an action group can by used by several action publishers. * * The values describing the action, including the label and description that * show up in the HUD are set via creating a #HudActionDescription for a * action. Each action can have more than one description if there * is a reason to do so. But, it is probably better to use the keywords * attribute in the majority cases. */ G_END_DECLS #endif /* __HUD_ACTION_PUBLISHER_H__ */ lomiri-action-api-1.1.3/src/libhud/data/000077500000000000000000000000001455542516300200125ustar00rootroot00000000000000lomiri-action-api-1.1.3/src/libhud/data/com.canonical.hud.Application.xml000066400000000000000000000022211455542516300262560ustar00rootroot00000000000000 lomiri-action-api-1.1.3/src/libhud/data/com.canonical.hud.xml000066400000000000000000000041511455542516300240200ustar00rootroot00000000000000 lomiri-action-api-1.1.3/src/libhud/manager.c000066400000000000000000000524421455542516300206660ustar00rootroot00000000000000/* * Copyright © 2012 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of either or both of the following licences: * * 1) the GNU Lesser General Public License version 3, as published by * the Free Software Foundation; and/or * 2) the GNU Lesser General Public License version 2.1, 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 warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License version 3 and version 2.1 along with this program. If not, * see * * Author: Ryan Lortie */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "manager.h" #include "action-publisher.h" #include "service-iface.h" #include "app-iface.h" struct _HudManagerPrivate { gchar * application_id; GApplication * application; HudActionPublisher * app_pub; GCancellable * connection_cancel; GDBusConnection * session; _HudServiceIfaceComCanonicalHud * service_proxy; _HudAppIfaceComCanonicalHudApplication * app_proxy; GVariantBuilder * todo_add_acts; GVariantBuilder * todo_add_desc; GHashTable * todo_active_contexts; guint todo_idle; GList * publishers; GHashTable * active_contexts; }; #define HUD_MANAGER_GET_PRIVATE(o) \ (G_TYPE_INSTANCE_GET_PRIVATE ((o), HUD_TYPE_MANAGER, HudManagerPrivate)) enum { PROP_0 = 0, PROP_APP_ID, PROP_APPLICATION }; static void hud_manager_class_init (HudManagerClass *klass); static void hud_manager_init (HudManager *self); static void hud_manager_constructed (GObject *object); static void hud_manager_dispose (GObject *object); static void hud_manager_finalize (GObject *object); static void set_property (GObject * obj, guint id, const GValue * value, GParamSpec * pspec); static void get_property (GObject * obj, guint id, GValue * value, GParamSpec * pspec); static void bus_get_cb (GObject * obj, GAsyncResult * res, gpointer user_data); G_DEFINE_TYPE (HudManager, hud_manager, G_TYPE_OBJECT) /* Initialize Class */ static void hud_manager_class_init (HudManagerClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); g_type_class_add_private (klass, sizeof (HudManagerPrivate)); object_class->constructed = hud_manager_constructed; object_class->dispose = hud_manager_dispose; object_class->finalize = hud_manager_finalize; object_class->set_property = set_property; object_class->get_property = get_property; g_object_class_install_property (object_class, PROP_APP_ID, g_param_spec_string(HUD_MANAGER_PROP_APP_ID, "ID for the application, typically the desktop file name", "A unique identifier for the application. Usually this aligns with the desktop file name or package name of the app.", NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS)); g_object_class_install_property (object_class, PROP_APPLICATION, g_param_spec_object(HUD_MANAGER_PROP_APPLICATION, "Instance of #GApplication if used for this application", "GApplication object", G_TYPE_APPLICATION, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS)); return; } /* Initialize Instance */ static void hud_manager_init (HudManager *self) { self->priv = HUD_MANAGER_GET_PRIVATE(self); self->priv->connection_cancel = g_cancellable_new(); g_bus_get(G_BUS_TYPE_SESSION, self->priv->connection_cancel, bus_get_cb, self); self->priv->todo_active_contexts = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, g_object_unref); self->priv->active_contexts = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, g_object_unref); return; } /* Construct the object */ static void hud_manager_constructed (GObject * object) { HudManager * manager = HUD_MANAGER(object); manager->priv->todo_idle = 0; if (manager->priv->application) { manager->priv->app_pub = hud_action_publisher_new(HUD_ACTION_PUBLISHER_ALL_WINDOWS, HUD_ACTION_PUBLISHER_NO_CONTEXT); hud_action_publisher_add_action_group(manager->priv->app_pub, "app", g_application_get_dbus_object_path (manager->priv->application)); hud_manager_add_actions(manager, manager->priv->app_pub); } return; } /* Clearing out a builder by finishing and freeing the results */ static void variant_builder_dispose (gpointer user_data) { if (user_data == NULL) { return; } GVariantBuilder * builder; builder = (GVariantBuilder *)user_data; GVariant * output; output = g_variant_builder_end(builder); g_variant_ref_sink(output); g_variant_unref(output); g_variant_builder_unref(builder); return; } /* Clean up refs */ static void hud_manager_dispose (GObject *object) { HudManager * manager = HUD_MANAGER(object); if (manager->priv->connection_cancel) { g_cancellable_cancel(manager->priv->connection_cancel); g_clear_object(&manager->priv->connection_cancel); } g_clear_pointer(&manager->priv->todo_add_acts, variant_builder_dispose); g_clear_pointer(&manager->priv->todo_add_desc, variant_builder_dispose); if (manager->priv->todo_idle != 0) { g_source_remove(manager->priv->todo_idle); manager->priv->todo_idle = 0; } g_clear_object(&manager->priv->session); g_clear_object(&manager->priv->service_proxy); g_clear_object(&manager->priv->app_proxy); g_list_free_full(manager->priv->publishers, g_object_unref); g_hash_table_remove_all(manager->priv->todo_active_contexts); g_hash_table_remove_all(manager->priv->active_contexts); g_clear_object(&manager->priv->app_pub); g_clear_object(&manager->priv->application); G_OBJECT_CLASS (hud_manager_parent_class)->dispose (object); return; } /* Free Memory */ static void hud_manager_finalize (GObject *object) { HudManager * manager = HUD_MANAGER(object); g_clear_pointer(&manager->priv->application_id, g_free); g_clear_pointer(&manager->priv->todo_active_contexts, g_hash_table_destroy); g_clear_pointer(&manager->priv->active_contexts, g_hash_table_destroy); G_OBJECT_CLASS (hud_manager_parent_class)->finalize (object); return; } /* Standard setting of props */ static void set_property (GObject * obj, guint id, const GValue * value, G_GNUC_UNUSED GParamSpec * pspec) { HudManager * manager = HUD_MANAGER(obj); switch (id) { case PROP_APP_ID: if (manager->priv->application == NULL) { g_clear_pointer(&manager->priv->application_id, g_free); manager->priv->application_id = g_value_dup_string(value); } else { g_debug("Application ID being set on HUD Manager already initialized with a GApplication"); } break; case PROP_APPLICATION: g_clear_object(&manager->priv->application); if (g_value_get_object(value) != NULL) { g_clear_pointer(&manager->priv->application_id, g_free); manager->priv->application = g_value_dup_object(value); manager->priv->application_id = g_strdup(g_application_get_application_id(manager->priv->application)); } break; default: g_warning("Unknown property %d.", id); return; } return; } /* Standard getting of props */ static void get_property (GObject * obj, guint id, GValue * value, G_GNUC_UNUSED GParamSpec * pspec) { HudManager * manager = HUD_MANAGER(obj); switch (id) { case PROP_APP_ID: g_value_set_string(value, manager->priv->application_id); break; case PROP_APPLICATION: g_value_set_object(value, manager->priv->application); break; default: g_warning("Unknown property %d.", id); return; } return; } /* Callback from adding sources */ static void add_sources_cb (GObject * obj, GAsyncResult * res, G_GNUC_UNUSED gpointer user_data) { GError * error = NULL; _hud_app_iface_com_canonical_hud_application_call_add_sources_finish((_HudAppIfaceComCanonicalHudApplication *)obj, res, &error); if (error != NULL) { g_warning("Unable to add sources: %s", error->message); g_error_free(error); /* TODO: Handle error */ return; } return; } static gboolean activate_todo_context (G_GNUC_UNUSED gpointer key, gpointer value, gpointer user_data) { HudManager * manager = HUD_MANAGER(user_data); HudActionPublisher *pub = HUD_ACTION_PUBLISHER(value); hud_manager_switch_window_context(manager, pub); return TRUE; } /* Take the todo queues and make them into DBus messages */ static void process_todo_queues (HudManager * manager) { if (manager->priv->todo_add_acts == NULL && manager->priv->todo_add_desc == NULL && g_hash_table_size(manager->priv->todo_active_contexts) == 0) { /* Nothing to process */ return; } if (manager->priv->app_proxy == NULL) { g_warning("Can't process TODO queues without an application proxy"); return; } GVariant * actions = NULL; GVariant * descriptions = NULL; /* Build an actions list */ if (manager->priv->todo_add_acts != NULL) { actions = g_variant_builder_end(manager->priv->todo_add_acts); g_variant_builder_unref(manager->priv->todo_add_acts); manager->priv->todo_add_acts = NULL; } else { actions = g_variant_new_array(G_VARIANT_TYPE("(usso)"), NULL, 0); } /* Build a descriptions list */ if (manager->priv->todo_add_desc != NULL) { descriptions = g_variant_builder_end(manager->priv->todo_add_desc); g_variant_builder_unref(manager->priv->todo_add_desc); manager->priv->todo_add_desc = NULL; } else { descriptions = g_variant_new_array(G_VARIANT_TYPE("(uso)"), NULL, 0); } /* Should never happen, but let's get useful error messages if it does */ g_return_if_fail(actions != NULL); g_return_if_fail(descriptions != NULL); _hud_app_iface_com_canonical_hud_application_call_add_sources(manager->priv->app_proxy, actions, descriptions, NULL, /* cancelable */ add_sources_cb, manager); g_hash_table_foreach_remove(manager->priv->todo_active_contexts, activate_todo_context, manager); return; } /* Application proxy callback */ static void application_proxy_cb (G_GNUC_UNUSED GObject * obj, GAsyncResult * res, gpointer user_data) { GError * error = NULL; _HudAppIfaceComCanonicalHudApplication * proxy = _hud_app_iface_com_canonical_hud_application_proxy_new_finish(res, &error); if (error != NULL) { g_warning("Unable to get app proxy: %s", error->message); g_error_free(error); return; } HudManager * manager = HUD_MANAGER(user_data); manager->priv->app_proxy = proxy; g_clear_object(&manager->priv->connection_cancel); process_todo_queues(manager); return; } /* Callback from getting the HUD service proxy */ static void register_app_cb (GObject * obj, GAsyncResult * res, gpointer user_data) { GError * error = NULL; gchar * object = NULL; _hud_service_iface_com_canonical_hud_call_register_application_finish ((_HudServiceIfaceComCanonicalHud *)obj, &object, res, &error); if (error != NULL) { g_warning("Unable to register app: %s", error->message); g_error_free(error); return; } HudManager * manager = HUD_MANAGER(user_data); _hud_app_iface_com_canonical_hud_application_proxy_new(manager->priv->session, G_DBUS_PROXY_FLAGS_NONE, "com.canonical.hud", object, manager->priv->connection_cancel, application_proxy_cb, manager); g_free(object); return; } static gboolean insert_active_context_to_todo (G_GNUC_UNUSED gpointer key, gpointer value, gpointer user_data) { HudManager * manager = HUD_MANAGER(user_data); HudActionPublisher *pub = HUD_ACTION_PUBLISHER(value); g_hash_table_insert(manager->priv->todo_active_contexts, GUINT_TO_POINTER(hud_action_publisher_get_window_id(pub)), g_object_ref(pub)); return TRUE; } /* Watch the name change to make sure we're robust to it */ static void notify_name_owner (GObject * gobject, G_GNUC_UNUSED GParamSpec * pspec, gpointer user_data) { HudManager * manager = HUD_MANAGER(user_data); gchar * name_owner = g_dbus_proxy_get_name_owner(G_DBUS_PROXY(gobject)); if (name_owner == NULL) { /* We've lost it */ /* Remove the stale proxy */ g_clear_object(&manager->priv->app_proxy); /* Make sure we're set upto do the async dance again */ if (manager->priv->connection_cancel == NULL) { manager->priv->connection_cancel = g_cancellable_new(); } /* Put the current publishers on the todo list */ GList * old_publishers = manager->priv->publishers; manager->priv->publishers = NULL; GList * pub; for (pub = old_publishers; pub != NULL; pub = g_list_next(pub)) { hud_manager_add_actions(manager, HUD_ACTION_PUBLISHER(pub->data)); } g_list_free_full(old_publishers, g_object_unref); g_hash_table_foreach_remove(manager->priv->active_contexts, insert_active_context_to_todo, manager); return; } g_free(name_owner); /* We've got a new name owner, so we need to register */ _hud_service_iface_com_canonical_hud_call_register_application(manager->priv->service_proxy, manager->priv->application_id, manager->priv->connection_cancel, register_app_cb, manager); return; } /* Callback from getting the HUD service proxy */ static void service_proxy_cb (G_GNUC_UNUSED GObject * obj, GAsyncResult * res, gpointer user_data) { GError * error = NULL; _HudServiceIfaceComCanonicalHud * proxy = _hud_service_iface_com_canonical_hud_proxy_new_finish(res, &error); if (error != NULL) { g_critical("Unable to get session bus: %s", error->message); g_error_free(error); return; } HudManager * manager = HUD_MANAGER(user_data); manager->priv->service_proxy = proxy; g_signal_connect(G_OBJECT(proxy), "notify::g-name-owner", G_CALLBACK(notify_name_owner), manager); notify_name_owner(G_OBJECT(proxy), NULL, manager); return; } /* Callback from getting the session bus */ static void bus_get_cb (G_GNUC_UNUSED GObject * obj, GAsyncResult * res, gpointer user_data) { GError * error = NULL; GDBusConnection * con = g_bus_get_finish(res, &error); if (error != NULL) { g_critical("Unable to get session bus: %s", error->message); g_error_free(error); return; } HudManager * manager = HUD_MANAGER(user_data); manager->priv->session = con; _hud_service_iface_com_canonical_hud_proxy_new(con, G_DBUS_PROXY_FLAGS_NONE, "com.canonical.hud", "/com/canonical/hud", manager->priv->connection_cancel, service_proxy_cb, manager); return; } /** * hud_manager_new: * @application_id: Unique identifier of the application, usually desktop file name * * Creates a new #HudManager object. * * Return value: (transfer full): New #HudManager */ HudManager * hud_manager_new (const gchar * application_id) { g_return_val_if_fail(application_id != NULL, NULL); return g_object_new(HUD_TYPE_MANAGER, HUD_MANAGER_PROP_APP_ID, application_id, NULL); } /** * hud_manager_new_for_application: * @application: #GApplication that we can use to get the ID and some actions from * * Creates a new #HudManager object using the application ID in th * @application object. Also exports the default actions there in * the "app" namespace. * * Return value: (transfer full): New #HudManager */ HudManager * hud_manager_new_for_application (GApplication * application) { g_return_val_if_fail(G_IS_APPLICATION(application), NULL); return g_object_new(HUD_TYPE_MANAGER, HUD_MANAGER_PROP_APPLICATION, application, NULL); } /* Idle handler */ static gboolean todo_handler (gpointer user_data) { HudManager * manager = HUD_MANAGER(user_data); process_todo_queues(manager); manager->priv->todo_idle = 0; return FALSE; } /** * hud_manager_add_actions: * @manager: A #HudManager object * @pub: Action publisher object tracking the descriptions and action groups * * Sets up a set of actions and descriptions for a specific user * context. This could be a window or a tab, depending on how the * application works. */ void hud_manager_add_actions (HudManager * manager, HudActionPublisher * pub) { g_return_if_fail(HUD_IS_MANAGER(manager)); g_return_if_fail(HUD_IS_ACTION_PUBLISHER(pub)); /* Add to our list of publishers */ manager->priv->publishers = g_list_prepend(manager->priv->publishers, g_object_ref(pub)); /* Set up watching for new groups */ /* TODO */ /* Grab the window and context IDs for each of them */ GVariant * winid = g_variant_new_uint32(hud_action_publisher_get_window_id(pub)); GVariant * conid = g_variant_new_string(hud_action_publisher_get_context_id(pub)); g_variant_ref_sink(winid); g_variant_ref_sink(conid); /* Send the current groups out */ GList * ags_list = hud_action_publisher_get_action_groups(pub); /* Build the variant builder if it doesn't exist */ if (ags_list != NULL && manager->priv->todo_add_acts == NULL) { manager->priv->todo_add_acts = g_variant_builder_new(G_VARIANT_TYPE_ARRAY); } /* Grab the action groups and add them to the todo queue */ GList * paction_group = NULL; for (paction_group = ags_list; paction_group != NULL; paction_group = g_list_next(paction_group)) { HudActionPublisherActionGroupSet * set = (HudActionPublisherActionGroupSet *)paction_group->data; g_variant_builder_open(manager->priv->todo_add_acts, G_VARIANT_TYPE_TUPLE); g_variant_builder_add_value(manager->priv->todo_add_acts, winid); g_variant_builder_add_value(manager->priv->todo_add_acts, conid); g_variant_builder_add_value(manager->priv->todo_add_acts, g_variant_new_string(set->prefix)); g_variant_builder_add_value(manager->priv->todo_add_acts, g_variant_new_object_path(set->path)); g_variant_builder_close(manager->priv->todo_add_acts); } /* Grab the description and add them to the todo queue */ const gchar * descpath = hud_action_publisher_get_description_path(pub); /* Build the variant builder if it doesn't exist */ if (descpath != NULL && manager->priv->todo_add_desc == NULL) { manager->priv->todo_add_desc = g_variant_builder_new(G_VARIANT_TYPE_ARRAY); } if (descpath != NULL) { g_variant_builder_open(manager->priv->todo_add_desc, G_VARIANT_TYPE_TUPLE); g_variant_builder_add_value(manager->priv->todo_add_desc, winid); g_variant_builder_add_value(manager->priv->todo_add_desc, conid); g_variant_builder_add_value(manager->priv->todo_add_desc, g_variant_new_object_path(descpath)); g_variant_builder_close(manager->priv->todo_add_desc); } /* Should be if we're all set up */ if (manager->priv->connection_cancel == NULL && manager->priv->todo_idle == 0) { manager->priv->todo_idle = g_idle_add(todo_handler, manager); } g_variant_unref(winid); winid = NULL; g_variant_unref(conid); conid = NULL; return; } /** * hud_manager_remove_actions: * @manager: A #HudManager object * @pub: Action publisher object tracking the descriptions and action groups * * Removes actions for being watched by the HUD. Should be done when the object * is remove. Does not require @pub to be a valid object so it can be used * with weak pointer style destroy. */ void hud_manager_remove_actions (HudManager * manager, G_GNUC_UNUSED HudActionPublisher * pub) { g_return_if_fail(HUD_IS_MANAGER(manager)); /* TODO: We need DBus API for this */ /* TODO: make sure to check if the removed publisher was in the active_contexts or todo_active_contexts */ return; } /* Callback from setting the window context. Not much we can do, just reporting errors */ static void set_window_context_cb (G_GNUC_UNUSED GObject * obj, GAsyncResult *res, G_GNUC_UNUSED gpointer user_data) { GError * error = NULL; _hud_app_iface_com_canonical_hud_application_call_set_window_context_finish((_HudAppIfaceComCanonicalHudApplication *)obj, res, &error); if (error != NULL) { g_warning("Unable to set context for window: %s", error->message); g_error_free(error); } return; } /** * hud_manager_switch_window_context: * @manager: A #HudManager object * @pub: Action publisher object tracking the descriptions and action groups * * Tells the HUD service that a window should use a different context of * actions with the current window. This allows the application to export * sets of actions and switch them easily with a single dbus message. */ void hud_manager_switch_window_context (HudManager * manager, HudActionPublisher * pub) { g_return_if_fail(HUD_IS_MANAGER(manager)); g_return_if_fail(HUD_IS_ACTION_PUBLISHER(pub)); if (manager->priv->app_proxy == NULL) { g_debug("Unable to send context change now, caching for reconnection"); g_hash_table_insert(manager->priv->todo_active_contexts, GUINT_TO_POINTER(hud_action_publisher_get_window_id(pub)), g_object_ref(pub)); return; } g_hash_table_insert(manager->priv->active_contexts, GUINT_TO_POINTER(hud_action_publisher_get_window_id(pub)), g_object_ref(pub)); _hud_app_iface_com_canonical_hud_application_call_set_window_context(manager->priv->app_proxy, hud_action_publisher_get_window_id(pub), hud_action_publisher_get_context_id(pub), NULL, /* cancellable */ set_window_context_cb, NULL); return; } lomiri-action-api-1.1.3/src/libhud/manager.h000066400000000000000000000074711455542516300206750ustar00rootroot00000000000000/* * Copyright © 2012 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of either or both of the following licences: * * 1) the GNU Lesser General Public License version 3, as published by * the Free Software Foundation; and/or * 2) the GNU Lesser General Public License version 2.1, 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 warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License version 3 and version 2.1 along with this program. If not, * see * * Author: Ted Gould */ #ifndef __HUD_MANAGER_H__ #define __HUD_MANAGER_H__ #include #include "action-publisher.h" G_BEGIN_DECLS #define HUD_TYPE_MANAGER (hud_manager_get_type ()) #define HUD_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), HUD_TYPE_MANAGER, HudManager)) #define HUD_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), HUD_TYPE_MANAGER, HudManagerClass)) #define HUD_IS_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), HUD_TYPE_MANAGER)) #define HUD_IS_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), HUD_TYPE_MANAGER)) #define HUD_MANAGER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), HUD_TYPE_MANAGER, HudManagerClass)) /** * HUD_MANAGER_PROP_APPLICATION: * * Define for the string to lookup HudManager:application. */ #define HUD_MANAGER_PROP_APPLICATION "application" /** * HUD_MANAGER_PROP_APP_ID: * * Define for the string to lookup HudManager:app-id. */ #define HUD_MANAGER_PROP_APP_ID "app-id" typedef struct _HudManager HudManager; typedef struct _HudManagerClass HudManagerClass; typedef struct _HudManagerPrivate HudManagerPrivate; /** * HudManagerClass: * @parent_class: The #GObject class * * Class data for #HudManager */ struct _HudManagerClass { GObjectClass parent_class; }; /** * HudManager: * * Instance data for the HUD Manager object. This object * tracks the information exported to the HUD for a specific * application. */ struct _HudManager { GObject parent; HudManagerPrivate * priv; }; GType hud_manager_get_type (void); HudManager * hud_manager_new (const gchar * application_id); HudManager * hud_manager_new_for_application (GApplication * application); void hud_manager_add_actions (HudManager * manager, HudActionPublisher * pub); void hud_manager_remove_actions (HudManager * manager, HudActionPublisher * pub); void hud_manager_switch_window_context (HudManager * manager, HudActionPublisher * pub); /** * SECTION:manager * @short_description: Manage data exported to HUD for the application * @stability: Stable * @include: libhud/manager.h * * Applications that are exporting data to the HUD can export data * for every window or context in the application. This includes * application internal structures like tabs or views on the various * data inside the application. The HUD manager allows for registering * and managing all the actions that are exported to the HUD for the * application. */ G_END_DECLS #endif /* __HUD_MANAGER_H__ */ lomiri-action-api-1.1.3/src/libhud/marshal.list000066400000000000000000000000251455542516300214220ustar00rootroot00000000000000VOID: STRING, STRING lomiri-action-api-1.1.3/src/lomiri-action-context.cpp000066400000000000000000000120151455542516300225650ustar00rootroot00000000000000/* This file is part of lomiri-action-api * Copyright 2013 Canonical Ltd. * * lomiri-action-api is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * lomiri-action-api is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY, 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 program. If not, see . */ #include #include using namespace lomiri::action; namespace lomiri { namespace action { /*! * \class ActionContext * * ActionContext groups actions together and by providing multiple contexts * the developer is able to control the visibility of the actions. The ActionManager then exposes the actions from * these different contexts. See \ref page_contexts for more details. */ // property documentation /*! * \property bool ActionContext::active * * If true the context is active. If false the context is inactive. * * When context has been added to the ActionManager setting this value controls * whether or not the actions in a context are available to external components. * * The ActionManager monitors the active property of each of the local contexts * that has been added to it. There can be only one active local context at a time. * When one of the local contexts sets itself active the manager will notice this, * export the actions from that given context and set the previously active local * context as inactive. This way a call to setActive() on a local context is * sufficient to manage the active local context of the manager and no additional * calls are necessary to manually inactivate the other contexts. * * \initvalue false * * \accessors active(), setActive() * * \notify activeChanged() */ /*! * \fn void ActionContext::actionsChanged() * Notifies that the actions inside a context have changed from a call to * addAction() or removeAction(). */ } } //! \private class Q_DECL_HIDDEN lomiri::action::ActionContext::Private : public QObject { Q_OBJECT Q_DISABLE_COPY(Private) public: ActionContext *q; QSet actions; bool active; Private(ActionContext *ctx) : q(ctx) {} public slots: void actionDestroyed(QObject *obj); }; void ActionContext::Private::actionDestroyed(QObject *obj) { /* we can not use qobject_cast() as it will fail for * objects about to be destroyed. Instead we can simply cast the * pointer directly and use it as long as it's not 0. */ Action *action = (Action *)obj; if (action == 0) { return; } q->removeAction(action); } /*! * \fn ActionContext::ActionContext(QObject *parent = 0) * * Creates a new ActionContext. * ActionContext has to be added to the ActionManager and set active to * make it's actions vailable for external components. * * \param parent parent QObject or 0 */ ActionContext::ActionContext(QObject *parent) : QObject(parent), d(new Private(this)) { d->active = false; } ActionContext::~ActionContext() { } /*! * Adds an action to the context. * * \param action Action to be added to the context * * Calling this function multiple times with the same action * does not have any side effects; the action gets added only once. * * ActionContext monitors if the action is deleted and does the appropriate * cleanup when necessary, so it is not mandatory to call removeAction() * before the action is destroyed. * * \note action must not be 0 */ void ActionContext::addAction(Action *action) { Q_ASSERT(action != 0); if (action == 0) return; if (d->actions.contains(action)) return; d->actions.insert(action); connect(action, SIGNAL(destroyed(QObject*)), d.data(), SLOT(actionDestroyed(QObject*))); emit actionsChanged(); } /*! * Removes an action from the context. * * \param action Action to be removed to the context * * Calling this function multiple times with the same action * does not have any side effects; the action gets removed only if * it was first added to the context with addAction(). * * \note action must not be 0 */ void ActionContext::removeAction(Action *action) { Q_ASSERT(action != 0); if (action == 0) return; if (!d->actions.contains(action)) return; action->disconnect(d.data()); d->actions.remove(action); emit actionsChanged(); } bool ActionContext::active() const { return d->active; } void ActionContext::setActive(bool value) { if (d->active == value) return; d->active = value; emit activeChanged(value); } /*! * \returns The set of actions in the context. */ QSet ActionContext::actions() const { return d->actions; } #include "lomiri-action-context.moc" lomiri-action-api-1.1.3/src/lomiri-action-manager.cpp000066400000000000000000001312221455542516300225150ustar00rootroot00000000000000/* This file is part of lomiri-action-api * Copyright 2013 Canonical Ltd. * * lomiri-action-api is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * lomiri-action-api is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY, 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 program. If not, see . */ #include #include #include #include #include #include #include #include #include // needed for gio includes. #undef signals #include using namespace lomiri::action; namespace lomiri { namespace action { /*! * \class ActionManager * * ActionManager exports the application actions to the external components. * See \ref page_platform-integration and \ref page_contexts for more details. */ // properties /*! * \property ActionContext *ActionManager::globalContext * * The globalContext of the Application. * * \note Setting the ActionContext::active on the global context has no effect; * * \accessors globalContext() */ // signals /*! * \fn void ActionManager::localContextsChanged() * * A local context was either added or removed. */ /*! * \fn void ActionManager::actionsChanged() * * An action was either added or removed from the global context * or any of the local contexts the manager is currently tracking. */ } } #define LOMIRI_ACTION_EXPORT_PATH "/com/lomiri/actions" //! \private struct Q_DECL_HIDDEN ContextData { HudActionPublisher *publisher; QSet actions; ContextData() { publisher = 0; } ContextData(const ContextData &other) { publisher = (HudActionPublisher*) g_object_ref(other.publisher); actions = other.actions; } ContextData &operator= (const ContextData &other) { if (this != &other){ g_clear_object(&publisher); publisher = (HudActionPublisher*) g_object_ref(other.publisher); actions = other.actions; } return *this; } ~ContextData() { g_clear_object(&publisher); } }; //! \private struct Q_DECL_HIDDEN ParameterData { GMenuItem *gmenuitem; GSimpleAction *gaction; // for now we support only one // gaction per parameter // for valuesChanged() implementaion; PreviewParameter *parameter; ParameterData() { gmenuitem = 0; gaction = 0; parameter = 0; } ParameterData(const ParameterData &other) { gmenuitem = (GMenuItem *) g_object_ref(other.gmenuitem); gaction = (GSimpleAction *) g_object_ref(other.gaction); parameter = other.parameter; } ParameterData &operator= (const ParameterData &other) { if (this != &other){ g_clear_object(&gmenuitem); g_clear_object(&gaction); gmenuitem = (GMenuItem *) g_object_ref(other.gmenuitem); gaction = (GSimpleAction *) g_object_ref(other.gaction); parameter = other.parameter; } return *this; } ~ParameterData() { g_clear_object(&gmenuitem); g_clear_object(&gaction); } }; //! \private struct Q_DECL_HIDDEN ActionData { HudActionDescription *desc; GSimpleAction *gaction; bool isPreviewAction; /* preview action data */ QHash params; /* menu containing the parameter information */ GMenu *paramMenu; ActionData() { desc = 0; gaction = 0; paramMenu = 0; isPreviewAction = false; } ActionData &operator= (const ActionData &other) { if (this != &other){ g_clear_object(&desc); g_clear_object(&gaction); g_clear_object(¶mMenu); desc = (HudActionDescription*) g_object_ref(other.desc); gaction = (GSimpleAction *) g_object_ref(other.gaction); params = other.params; paramMenu = other.paramMenu; if (paramMenu != 0) g_object_ref(paramMenu); isPreviewAction = other.isPreviewAction; } return *this; } ActionData(const ActionData &other) { desc = (HudActionDescription*) g_object_ref(other.desc); gaction = (GSimpleAction *) g_object_ref(other.gaction); params = other.params; paramMenu = other.paramMenu; if (paramMenu != 0) g_object_ref(paramMenu); isPreviewAction = other.isPreviewAction; } ~ActionData() { g_clear_object(&desc); g_clear_object(&gaction); g_clear_object(¶mMenu); } }; // needed for QHash.key() //! \private bool operator== (const ActionData &a, const ActionData &b) { // comparing these pointers is enough return a.gaction == b.gaction && a.desc == b.desc; } namespace { class QuitAction: public Action { Q_OBJECT }; class GlobalActionContext: public ActionContext { public: GlobalActionContext(QObject *parent = 0) : ActionContext(parent) { } void addBuiltInAction(Action *action) { built_in_actions << action; } QSet allActions() { return actions() + built_in_actions; } private: QSet built_in_actions; }; static inline char * _(const char *__msgid) { return gettext(__msgid); } } //! \private class Q_DECL_HIDDEN lomiri::action::ActionManager::Private : public QObject { Q_OBJECT public: ActionManager *q; QSet actions; GlobalActionContext *globalContext; QSet localContexts; QScopedPointer quitAction; ActionContext *activeLocalContext; QHash contextData; QHash actionData; HudManager *hudManager; GSimpleActionGroup *actionGroup; guint exportId; GDBusConnection *sessionBus; Private(ActionManager *mgr) : q(mgr) { globalContext = new GlobalActionContext(); hudManager = 0; } ~Private() { delete globalContext; g_clear_object(&hudManager); } /* ActionContext */ void updateContext(ActionContext *context); void createContext(ActionContext *context); void destroyContext(ActionContext *context); void updateHudContext(ActionContext *context, QSet oldActions); // updates the exported action group. void updateActionGroup(); void setActiveContext(ActionContext *context); /* Action */ void createAction(Action *action); void destroyAction(Action *action); void createActionData(Action *action, ActionData &adata); void updateActionDescription(Action *action, HudActionDescription *desc); void updateActionsWhenNameOrTypeHaveChanged(Action *action); static void action_activated(GSimpleAction *action, GVariant *parameter, gpointer user_data); /* PreviewAction */ ActionData createHudPreviewAction(PreviewAction *action); void updatePreviewActionParameters(PreviewAction *action, ActionData &adata); void updateParameterMenu(PreviewAction *action, const ActionData &adata); /* PreviewRangeParameter */ void updateRange(PreviewRangeParameter * param, const ActionData &adata); void updatePreviewParameterRange(PreviewParameter *parameter); static void range_action_activated(GSimpleAction *simpleaction, GVariant *parameter, gpointer user_data); public slots: /* ActionContext signals */ void contextActiveChanged(bool value); void contextActionsChanged(); /* Action signals */ void actionNameChanged(); void actionParameterTypeChanged(); void actionEnabledChanged(); void actionPropertiesChanged(); // for all the rest /* PreviewAction signals */ void previewActionParametersChanged(); void previewActionCommitLabelChanged(); /* PreviewRangeParameter signals */ void previewRangeParameterValueChanged(); void previewRangeParameterPropertiesChanged(); // for all the rest /* QObject destroy() handlers */ void contextDestroyed(QObject *obj); }; /************************************************************************/ /* PUBLIC API */ /************************************************************************/ /*! * \param parent parent QObject or 0 * * Creates a new ActionManager. * * Also creates a global context which can be accessed with ActionManager::globalContext */ ActionManager::ActionManager(QObject *parent) : QObject(parent), d(new Private(this)) { d->activeLocalContext = 0; GError *error = NULL; d->sessionBus = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, &error); if (error != NULL) { qWarning("%s:\n" "\tCould not get session bus. Actions will not be available through D-Bus.\n" "\tReason: %s", __PRETTY_FUNCTION__, error->message); g_error_free(error); error = NULL; } const char *appid = getenv("APP_ID"); if (appid == 0) { qWarning("%s:\n" "\tCould not determine application identifier. HUD will not work properly.\n" "\tProvide your application identifier in $APP_ID environment variable.", __PRETTY_FUNCTION__); appid = "unknown"; } d->hudManager = hud_manager_new(appid); connect(d->globalContext, SIGNAL(actionsChanged()), d.data(), SLOT(contextActionsChanged())); connect(d->globalContext, SIGNAL(activeChanged(bool)), d.data(), SLOT(contextActiveChanged(bool))); connect(d->globalContext, SIGNAL(destroyed(QObject*)), d.data(), SLOT(contextDestroyed(QObject *))); d->actionGroup = g_simple_action_group_new(); d->quitAction.reset(new QuitAction()); d->quitAction->setText(_("Quit")); d->quitAction->setDescription(_("Quit the application")); d->quitAction->setKeywords(_("Exit;Close")); connect(d->quitAction.data(), SIGNAL(triggered(QVariant)), this, SIGNAL(quit())); d->createContext(d->globalContext); d->globalContext->addBuiltInAction(d->quitAction.data()); d->updateContext(d->globalContext); hud_manager_switch_window_context(d->hudManager, d->contextData[d->globalContext].publisher); d->exportId = 0; if (d->sessionBus) { d->exportId = g_dbus_connection_export_action_group(d->sessionBus, LOMIRI_ACTION_EXPORT_PATH, G_ACTION_GROUP(d->actionGroup), &error); if (d->exportId == 0) { Q_ASSERT(error != NULL); qWarning("%s:\n" "\tCould not export the main action group. Actions will not be available through D-Bus.\n" "\tReason: %s", __PRETTY_FUNCTION__, error->message); g_error_free(error); error = NULL; } } } ActionManager::~ActionManager() { d->globalContext->disconnect(d.data()); if (d->exportId != 0) { Q_ASSERT(d->sessionBus != 0); g_dbus_connection_unexport_action_group(d->sessionBus, d->exportId); g_dbus_connection_flush_sync(d->sessionBus, NULL, NULL); } g_clear_object(&d->sessionBus); } /*! * \param action action to be added * * this is a shorthand for * \code * manager->globalContext()->addAction(action); * \endcode * * \see ActionContext::addAction() */ void ActionManager::addAction(Action *action) { d->globalContext->addAction(action); // if action is deleted before removeAction() is called on it // globalContext (ActionContext) handles this case for us. } /*! * \param action action to be removed * * this is a shorthand for * \code * manager->globalContext()->removeAction(action); * \endcode * * \see ActionContext::removeAction() */ void ActionManager::removeAction(Action *action) { d->globalContext->removeAction(action); } ActionContext * ActionManager::globalContext() { return d->globalContext; } /*! * \param context context to be added * * Adds a local context. * * Calling this function multiple times with the same context * does not have any side effects; the context gets added only once. * * ActionManager monitors if the context is deleted and does the appropriate * cleanup when necessary, so it is not mandatory to call removeLocalContext() * before the context is destroyed. * * \note If context::active is true when added, * the context is made the current active one. * * \note context must not be 0. */ void ActionManager::addLocalContext(ActionContext *context) { Q_ASSERT(context != 0); if (context == 0) return; if (d->localContexts.contains(context) || context == d->globalContext) return; d->localContexts.insert(context); connect(context, SIGNAL(activeChanged(bool)), d.data(), SLOT(contextActiveChanged(bool))); connect(context, SIGNAL(actionsChanged()), d.data(), SLOT(contextActionsChanged())); connect(context, SIGNAL(destroyed(QObject*)), d.data(), SLOT(contextDestroyed(QObject *))); d->createContext(context); d->updateContext(context); emit localContextsChanged(); if (context->active()) { d->setActiveContext(context); } } /*! * \param context context to be removed * * Removes a local context. * * Calling this function multiple times with the same context * does not have any side effects; the context gets removed only if * it was previously added with addLocalContext(). * * \note if the removed context is the current active one * after the removal there is no active local context. * * \note context must not be 0 */ void ActionManager::removeLocalContext(ActionContext *context) { Q_ASSERT(context != 0); if (context == 0) return; if (!d->localContexts.contains(context)) return; d->localContexts.remove(context); context->disconnect(d.data()); d->destroyContext(context); if (d->activeLocalContext == context) { d->activeLocalContext = 0; d->updateActionGroup(); } emit localContextsChanged(); } /*! * \returns The set of local contexts the manager is aware of. */ QSet ActionManager::localContexts() const { return d->localContexts; } /*! * \returns The set of actions the manager is currently aware of. * * If an action is part of multiple contexts it's still only included * once in the set. */ QSet ActionManager::actions() const { return d->actions; } /************************************************************************/ /* ActionContext */ /************************************************************************/ void ActionManager::Private::createContext(ActionContext *context) { Q_ASSERT(!contextData.contains(context)); static int id = 0; ContextData cdata; /* create a new HUD context */ cdata.publisher = hud_action_publisher_new(HUD_ACTION_PUBLISHER_ALL_WINDOWS, qPrintable(QString("action_context_%1").arg(id++))); hud_action_publisher_add_action_group(cdata.publisher, "hud", LOMIRI_ACTION_EXPORT_PATH); hud_manager_add_actions(hudManager, cdata.publisher); contextData.insert(context, cdata); } void ActionManager::Private::destroyContext(ActionContext *context) { Q_ASSERT(contextData.contains(context)); ContextData &cdata = contextData[context]; QSet actions = cdata.actions; foreach (Action *action, actions) { // remove the action from this context cdata.actions.remove(action); // when actions are removed from this context // we can't destroy their ActionData if any of the // other contexts contain the action. bool inUse = false; foreach (const ContextData &cdata, contextData) { if (cdata.actions.contains(action)) { inUse = true; break; } } if (!inUse) { destroyAction(action); } } /*! \todo remove publisher from HUD when the API is added */ contextData.remove(context); } void ActionManager::Private::contextActionsChanged() { ActionContext *context = qobject_cast(sender()); Q_ASSERT(context != 0); updateContext(context); } void ActionManager::Private::setActiveContext(ActionContext *context) { if (context == globalContext) { // global context is always active. return; } if (!context->active()) { // activate the context context->setActive(true); } if (activeLocalContext == 0) { activeLocalContext = context; updateActionGroup(); hud_manager_switch_window_context(hudManager, contextData[context].publisher); } else if (activeLocalContext == context) { // already active one. return; } else { // deactivate the old active one. ActionContext *old = activeLocalContext; activeLocalContext = context; old->setActive(false); updateActionGroup(); hud_manager_switch_window_context(hudManager, contextData[context].publisher); } } void ActionManager::Private::contextActiveChanged(bool value) { ActionContext *context = qobject_cast(sender()); Q_ASSERT(context != 0); Q_ASSERT(contextData.contains(context)); if (context == globalContext) { // global context is always active. // ignore the possible change return; } if (value == true) { setActiveContext(context); } else { if (activeLocalContext == context) { // the active context was deactivated // this means that only the global context is active activeLocalContext = 0; updateActionGroup(); hud_manager_switch_window_context(hudManager, contextData[globalContext].publisher); } } } void ActionManager::Private::updateActionGroup() { // update the exported action group according to // current actions in global context and // in the active local context QSet globalActions = globalContext->allActions(); QSet localActions; if (activeLocalContext) localActions = activeLocalContext->actions(); QSet currentActions = globalActions + localActions; /* * First remove the actions that are not part of the current active ones */ QSet removedActionNames; gchar **oldActionNames = g_action_group_list_actions(G_ACTION_GROUP(actionGroup)); for (gchar **actionName = oldActionNames; *actionName != 0; actionName++) { bool found = false; foreach (Action * action, currentActions) { Q_ASSERT(actionData.contains(action)); const ActionData &adata = actionData[action]; if (g_strcmp0(g_action_get_name(G_ACTION(adata.gaction)), *actionName) == 0) { found = true; break; } // also check for parameter gactions foreach (const ParameterData &pdata, adata.params) { if (g_strcmp0(g_action_get_name(G_ACTION(pdata.gaction)), *actionName) == 0) { found = true; break; } } if (found) break; } if (!found) removedActionNames.insert(*actionName); } foreach (gchar *name, removedActionNames) { g_simple_action_group_remove(actionGroup, name); } removedActionNames.clear(); g_strfreev(oldActionNames); // NOTE: it is important that we reinsert all the actions so that // the GActions update after parameter types have changed // then update all the global actions foreach (Action * action, globalActions) { Q_ASSERT(actionData.contains(action)); const ActionData &adata = actionData[action]; g_simple_action_group_insert(actionGroup, G_ACTION(adata.gaction)); foreach (const ParameterData &pdata, adata.params) { g_simple_action_group_insert(actionGroup, G_ACTION(pdata.gaction)); } } // and finally update the local actions. // if a local action has the same name than // a global one it will replace the global one foreach (Action * action, localActions) { Q_ASSERT(actionData.contains(action)); const ActionData &adata = actionData[action]; g_simple_action_group_insert(actionGroup, G_ACTION(adata.gaction)); foreach (const ParameterData &pdata, adata.params) { g_simple_action_group_insert(actionGroup, G_ACTION(pdata.gaction)); } } } void ActionManager::Private::updateContext(ActionContext *context) { Q_ASSERT(contextData.contains(context)); ContextData &cdata = contextData[context]; QSet oldActions = cdata.actions; QSet currentActions; if(context == globalContext) { currentActions = globalContext->allActions(); } else { currentActions = context->actions(); } QSet removedActions = oldActions - currentActions; foreach (Action *action, currentActions) { // Make sure the manager knows about all of the actions if (!actionData.contains(action)) { createAction(action); Q_ASSERT(actionData.contains(action)); } /* Add the action to the context. * This has to be separate from making sure the action is known to manager * because some other context might have introduced the same action before already. */ if (!cdata.actions.contains(action)) { /* oldActions still contain the original old ones * so it's safe to modify cdata.actions here */ cdata.actions.insert(action); } } if (context == globalContext || context == activeLocalContext) { // a context that affects the actionGroup have changed. // update the group. updateActionGroup(); } // update the HUD contexts (publishers) if (context == globalContext) { // if global context changes we have to update all the local ones, too // as a HUD context is a union of the global and a local context foreach(ActionContext *localContext, localContexts) { updateHudContext(localContext, oldActions); } } updateHudContext(context, oldActions); // finally clean up the removed actions foreach (Action *action, removedActions) { // remove the action from this context cdata.actions.remove(action); // when actions are removed from this context // we can't destroy their ActionData if any of the // other contexts contain the action. bool inUse = false; foreach (const ContextData &cdata, contextData) { if (cdata.actions.contains(action)) { inUse = true; break; } } if (!inUse) { destroyAction(action); } } } void ActionManager::Private::updateHudContext(ActionContext *context, QSet oldActions) { Q_ASSERT(contextData.contains(context)); const ContextData &cdata = contextData[context]; QSet currentActions = context->actions() + globalContext->allActions(); QSet newActions = currentActions - oldActions; QSet removedActions = oldActions - currentActions; foreach (Action *action, newActions) { Q_ASSERT(actionData.contains(action)); const ActionData &adata = actionData[action]; hud_action_publisher_add_description(cdata.publisher, adata.desc); } foreach (Action *action, removedActions) { Q_ASSERT(actionData.contains(action)); const ActionData &adata = actionData[action]; /* Removing descriptions is not supported in libhud at the moment. * For now, let's just empty the label and that will hide the * action from the HUD. */ hud_action_description_set_attribute_value(adata.desc, G_MENU_ATTRIBUTE_LABEL, g_variant_new_string("")); } } void ActionManager::Private::contextDestroyed(QObject *obj) { /* we can not use qobject_cast() as it will fail for * objects about to be destroyed. Instead we can simply cast the * pointer directly and use it as long as it's not 0. */ ActionContext *ctx = (ActionContext *)obj; if (ctx == 0) { return; } if (ctx == globalContext) { /* Somebody called delete on globalContext pointer. * This is clearly a bug in the client code, but we have to try to * manage this in a way we don't crash. * * Let's just print out a big fat critical. */ qCritical() << __PRETTY_FUNCTION__ << ":\n" << "\tClient called delete on our globalContext pointer.\n" << "\tCreating a new globalContext, but this is clearly a bug\n" << "\tin the client code. "; globalContext->disconnect(this); destroyContext(globalContext); globalContext = new GlobalActionContext(); createContext(globalContext); globalContext->addBuiltInAction(quitAction.data()); updateContext(globalContext); connect(globalContext, SIGNAL(actionsChanged()), this, SLOT(contextActionsChanged())); connect(globalContext, SIGNAL(activeChanged(bool)), this, SLOT(contextActiveChanged(bool))); connect(globalContext, SIGNAL(destroyed(QObject*)), this, SLOT(contextDestroyed(QObject *))); return; } q->removeLocalContext(ctx); } /************************************************************************/ /* Action */ /************************************************************************/ void ActionManager::Private::action_activated(GSimpleAction *simpleaction, GVariant *parameter, gpointer user_data) { Action *action = qobject_cast((QObject *)user_data); Q_ASSERT(action != 0); if (action == 0) { return; } if (g_action_get_parameter_type(G_ACTION(simpleaction)) == NULL) { action->trigger(); return; } else if (g_variant_is_of_type(parameter, G_VARIANT_TYPE_STRING)) { PreviewAction *previewAction = qobject_cast(action); if (previewAction) { QString state(g_variant_get_string(parameter, NULL)); if (state == "start") { emit previewAction->started(); return; } else if (state == "end") { // just skip for now return; } else if (state == "commit") { emit previewAction->trigger(); return; } else if (state == "reset") { emit previewAction->resetted(); return; } else if (state == "cancel") { emit previewAction->cancelled(); return; } else { qWarning("Unknown PreviewAction state: %s", qPrintable(state)); } } else { Q_ASSERT(action->parameterType() == Action::String); QString arg(g_variant_get_string(parameter, NULL)); action->trigger(QVariant(arg)); } } else if (g_variant_is_of_type(parameter, G_VARIANT_TYPE_INT32)) { Q_ASSERT(action->parameterType() == Action::Integer); int arg = g_variant_get_int32(parameter); action->trigger(QVariant(arg)); } else if (g_variant_is_of_type(parameter, G_VARIANT_TYPE_BOOLEAN)) { Q_ASSERT(action->parameterType() == Action::Bool); bool arg = g_variant_get_boolean(parameter); action->trigger(QVariant(arg)); } else if (g_variant_is_of_type(parameter, G_VARIANT_TYPE_DOUBLE)) { Q_ASSERT(action->parameterType() == Action::Real); float arg = g_variant_get_double(parameter); action->trigger(QVariant(arg)); } else { qWarning("Tried to activate gaction with incorrect parameter type."); } } void ActionManager::Private::createAction(Action *action) { Q_ASSERT(!actionData.contains(action)); ActionData adata; adata.isPreviewAction = (qobject_cast(action) != 0); createActionData(action, adata); actionData.insert(action, adata); connect(action, SIGNAL(nameChanged(QString)), this, SLOT(actionNameChanged())); connect(action, SIGNAL(parameterTypeChanged(lomiri::action::Action::Type)), this, SLOT(actionParameterTypeChanged())); connect(action, SIGNAL(enabledChanged(bool)), this, SLOT(actionEnabledChanged())); connect(action, SIGNAL(textChanged(QString)), this, SLOT(actionPropertiesChanged())); // don't care about iconName connect(action, SIGNAL(descriptionChanged(QString)), this, SLOT(actionPropertiesChanged())); connect(action, SIGNAL(keywordsChanged(QString)), this, SLOT(actionPropertiesChanged())); connect(action, SIGNAL(enabledChanged(bool)), this, SLOT(actionPropertiesChanged())); if (adata.isPreviewAction) { PreviewAction *previewAction = qobject_cast(action); Q_ASSERT(previewAction != 0); connect(previewAction, SIGNAL(commitLabelChanged(QString)), this, SLOT(previewActionCommitLabelChanged())); connect(previewAction, SIGNAL(parametersChanged()), this, SLOT(previewActionParametersChanged())); } actions.insert(action); emit q->actionsChanged(); } void ActionManager::Private::destroyAction(Action *action) { Q_ASSERT(actionData.contains(action)); const ActionData &adata = actionData[action]; action->disconnect(this); actionData.remove(action); actions.remove(action); emit q->actionsChanged(); } void ActionManager::Private::createActionData(Action *action, ActionData &adata) { const GVariantType *paramType = NULL; switch(action->parameterType()) { case Action::None: paramType = NULL; break; case Action::String: paramType = G_VARIANT_TYPE_STRING; break; case Action::Integer: paramType = G_VARIANT_TYPE_INT32; break; case Action::Bool: paramType = G_VARIANT_TYPE_BOOLEAN; break; case Action::Real: paramType = G_VARIANT_TYPE_DOUBLE; break; } if (adata.isPreviewAction) { if (action->parameterType() != Action::None) { qWarning("%s:\n" "\tPreviewAction parameter type is not Action::None\n" "\tThis is not supported.\n" "\tSetting the parameter type to None", __PRETTY_FUNCTION__); action->setParameterType(Action::None); } // PreviewActions have to have string paramType as an implementation detail. paramType = G_VARIANT_TYPE_STRING; } QString actionid = action->name(); adata.gaction = g_simple_action_new(qPrintable(actionid), paramType); g_simple_action_set_enabled(adata.gaction, action->enabled()); g_signal_connect(G_OBJECT(adata.gaction), "activate", G_CALLBACK(Private::action_activated), action); adata.desc = hud_action_description_new(qPrintable(QString("hud.%1").arg(actionid)), NULL); updateActionDescription(action, adata.desc); if (adata.isPreviewAction) { PreviewAction *previewAction = qobject_cast(action); Q_ASSERT(previewAction != 0); adata.paramMenu = g_menu_new(); updatePreviewActionParameters(previewAction, adata); updateParameterMenu(previewAction, adata); hud_action_description_set_parameterized(adata.desc, G_MENU_MODEL(adata.paramMenu)); } } void ActionManager::Private::updateActionDescription(Action *action, HudActionDescription *desc) { Q_ASSERT(action != 0); Q_ASSERT(desc != 0); hud_action_description_set_attribute_value(desc, G_MENU_ATTRIBUTE_LABEL, g_variant_new_string(qPrintable(action->text()))); hud_action_description_set_attribute_value(desc, "description", g_variant_new_string(qPrintable(action->description()))); hud_action_description_set_attribute_value(desc, "keywords", g_variant_new_string(qPrintable(action->keywords()))); PreviewAction *previewAction = qobject_cast(action); if (previewAction != 0) { hud_action_description_set_attribute_value(desc, "commitLabel", g_variant_new_string(qPrintable(previewAction->commitLabel()))); } QuitAction *quitAction = qobject_cast(action); if (quitAction != 0) { hud_action_description_set_attribute_value(desc, "hud-toolbar-item", g_variant_new_string("quit")); } } void ActionManager::Private::updateActionsWhenNameOrTypeHaveChanged(Action *action) { Q_ASSERT(actionData.contains(action)); ActionData &adata = actionData[action]; ActionData tmpdata; tmpdata.isPreviewAction = adata.isPreviewAction; createActionData(action, tmpdata); // update the gaction g_signal_handlers_disconnect_by_data(G_OBJECT(adata.gaction), action); g_clear_object(&adata.gaction); adata.gaction = (GSimpleAction *)g_object_ref(tmpdata.gaction); if (globalContext->allActions().contains(action) || (activeLocalContext != 0 && activeLocalContext->actions().contains(action))) { updateActionGroup(); } // update the desc // go through all the HUD contexts and add the new descriptor foreach(ContextData cdata, contextData) { if (cdata.actions.contains(action)) { // remove the old one /* Removing descriptions is not supported in libhud at the moment. * For now, let's just empty the label and that will hide the * action from the HUD. */ hud_action_description_set_attribute_value(adata.desc, G_MENU_ATTRIBUTE_LABEL, g_variant_new_string("")); hud_action_publisher_add_description(cdata.publisher, tmpdata.desc); } } g_clear_object(&adata.desc); adata.desc = (HudActionDescription *)g_object_ref(tmpdata.desc); } void ActionManager::Private::actionNameChanged() { Action *action= qobject_cast(sender()); Q_ASSERT(action != 0); updateActionsWhenNameOrTypeHaveChanged(action); } void ActionManager::Private::actionParameterTypeChanged() { Action *action= qobject_cast(sender()); Q_ASSERT(action != 0); updateActionsWhenNameOrTypeHaveChanged(action); } void ActionManager::Private::actionEnabledChanged() { Action *action= qobject_cast(sender()); Q_ASSERT(action != 0); Q_ASSERT(actionData.contains(action)); g_simple_action_set_enabled(actionData[action].gaction, action->enabled()); } void ActionManager::Private::actionPropertiesChanged() { Action *action= qobject_cast(sender()); Q_ASSERT(action != 0); Q_ASSERT(actionData.contains(action)); updateActionDescription(action, actionData[action].desc); } /************************************************************************/ /* PreviewAction */ /************************************************************************/ void ActionManager::Private::previewActionParametersChanged() { PreviewAction *action = qobject_cast(sender()); Q_ASSERT(action != 0); Q_ASSERT(actionData.contains(action)); ActionData &adata = actionData[action]; updatePreviewActionParameters(action, adata); updateParameterMenu(action, adata); if (globalContext->actions().contains(action) || (activeLocalContext != 0 && activeLocalContext->actions().contains(action))) { updateActionGroup(); } } void ActionManager::Private::previewActionCommitLabelChanged() { Action *action= qobject_cast(sender()); Q_ASSERT(action != 0); Q_ASSERT(actionData.contains(action)); updateActionDescription(action, actionData[action].desc); } void ActionManager::Private::updatePreviewActionParameters(PreviewAction *action, ActionData &adata) { QList currentParameters = action->parameters(); QList newParameters; QSet removedParameters; foreach (PreviewParameter *parameter, currentParameters) { if (!adata.params.contains(parameter)) { /* Keep this as a list now as the previewActions unit test relies * on parameter GActions to be created in the same order as the * PreviewParameters are added to the PreviewAction. */ newParameters.append(parameter); } } foreach (PreviewParameter *parameter, adata.params.keys()) { if (!currentParameters.contains(parameter)) { removedParameters.insert(parameter); } } // remove the old foreach (PreviewParameter *parameter, removedParameters) { if (qobject_cast(parameter)) { PreviewRangeParameter *range = qobject_cast(parameter); Q_ASSERT(adata.params.contains(range)); ParameterData pdata = adata.params[range]; g_signal_handlers_disconnect_by_data(G_OBJECT(pdata.gaction), range); range->disconnect(this); adata.params.remove(range); } else { qWarning("%s:\n" "\tUnknown PreviewParameter subclass: %s", __PRETTY_FUNCTION__, parameter->metaObject()->className()); } } // add the new foreach (PreviewParameter *parameter, newParameters) { if (qobject_cast(parameter)) { PreviewRangeParameter *range = qobject_cast(parameter); static int id = 0; ParameterData pdata; QString actionid = QString("lomiri-action-range-param-%1").arg(id++); pdata.gmenuitem = g_menu_item_new("", qPrintable(QString("hud.") + actionid)); g_menu_item_set_attribute_value(pdata.gmenuitem, "parameter-type", g_variant_new_string("slider")); pdata.gaction = g_simple_action_new(qPrintable(actionid), G_VARIANT_TYPE_DOUBLE); g_signal_connect(G_OBJECT(pdata.gaction), "activate", G_CALLBACK(Private::range_action_activated), range); pdata.parameter = range; connect(range, SIGNAL(valueChanged(float)), this, SLOT(previewRangeParameterValueChanged())); connect(range, SIGNAL(textChanged(QString)), this, SLOT(previewRangeParameterPropertiesChanged())); connect(range, SIGNAL(minimumValueChanged(float)), this, SLOT(previewRangeParameterPropertiesChanged())); connect(range, SIGNAL(maximumValueChanged(float)), this, SLOT(previewRangeParameterPropertiesChanged())); adata.params.insert(range, pdata); updateRange(range, adata); } else { qWarning("%s:\n" "\tUnknown PreviewParameter subclass: %s", __PRETTY_FUNCTION__, parameter->metaObject()->className()); } } } void ActionManager::Private::updateParameterMenu(PreviewAction *action, const ActionData &adata) { Q_ASSERT(adata.paramMenu != 0); /* as g_menu and g_menu_model don't support indexing * we just have to clear the whole menu and build a new one */ // newest glib has g_menu_remove_all(), so we can use it in the future while (g_menu_model_get_n_items(G_MENU_MODEL(adata.paramMenu)) > 0) { g_menu_remove(adata.paramMenu, 0); } foreach (PreviewParameter *parameter, action->parameters()) { Q_ASSERT(adata.params.contains(parameter)); Q_ASSERT(adata.params[parameter].gmenuitem); g_menu_append_item(adata.paramMenu, adata.params[parameter].gmenuitem); } hud_action_description_set_parameterized(adata.desc, G_MENU_MODEL(adata.paramMenu)); } /************************************************************************/ /* PreviewRangeParameter */ /************************************************************************/ void ActionManager::Private::range_action_activated(GSimpleAction *simpleaction, GVariant *parameter, gpointer user_data) { Q_UNUSED(simpleaction); PreviewRangeParameter *that; that = qobject_cast((QObject*)user_data); Q_ASSERT(that != 0); float value = g_variant_get_double(parameter); that->setValue(value); } void ActionManager::Private::previewRangeParameterValueChanged() { /*! \bug preview parameters should use GAction::target to pass the values * instead of GAction::activated(). We can implement reset() only * by using target * * This also requires changes to the HUD UI on the shell side. * * The code below should be updated to actually change the state on each gaction. * if left uncommented we just generate additional range_action_activated() calls * without any benefit. */ #if 0 PreviewRangeParameter *parameter = qobject_cast(sender()); Q_ASSERT(parameter != 0); foreach (const ActionData &adata, actionData) { foreach (const ParameterData &pdata, adata.params) { if (pdata.parameter == parameter) { g_action_activate(G_ACTION(pdata.gaction), g_variant_new_double(parameter->value())); } } } #endif } void ActionManager::Private::previewRangeParameterPropertiesChanged() { PreviewRangeParameter *parameter = qobject_cast(sender()); Q_ASSERT(parameter != 0); foreach (const ActionData &adata, actionData) { if (adata.params.contains(parameter)) { updateRange(parameter, adata); PreviewAction *previewAction = qobject_cast(actionData.key(adata)); Q_ASSERT(previewAction != 0); updateParameterMenu(previewAction, adata); } } } void ActionManager::Private::updateRange(PreviewRangeParameter *range, const ActionData &adata) { Q_ASSERT(adata.params.contains(range)); ParameterData pdata = adata.params[range]; g_menu_item_set_attribute_value(pdata.gmenuitem, "min", g_variant_new_double(range->minimumValue())); g_menu_item_set_attribute_value(pdata.gmenuitem, "max", g_variant_new_double(range->maximumValue())); g_menu_item_set_attribute_value(pdata.gmenuitem, G_MENU_ATTRIBUTE_LABEL, g_variant_new_string(qPrintable(range->text()))); } #include "lomiri-action-manager.moc" lomiri-action-api-1.1.3/src/lomiri-action-qt.pc.in000066400000000000000000000003421455542516300217520ustar00rootroot00000000000000libdir=@libdir@ includedir=@includedir@ Cflags: -I${includedir}/ Requires: hud-2 Qt5Core Libs: @ABSOLUTE_SO_FILE@ Name: lomiri-action-qt Description: Lomiri Common Action API Version: @API_VERSION_MAJOR@.@API_VERSION_MINOR@ lomiri-action-api-1.1.3/src/lomiri-action.cpp000066400000000000000000000247471455542516300211220ustar00rootroot00000000000000/* This file is part of lomiri-action-api * Copyright 2013 Canonical Ltd. * * lomiri-action-api is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * lomiri-action-api is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY, 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 program. If not, see . */ #include #include #include using namespace lomiri::action; namespace lomiri { namespace action { /*! * \class Action * \brief The main action class. * * Lomiri services visualizing this class will usually * be represented it as a simple button or menu item, depending upon where it is contributed. * * The optional name property is available through D-Bus and can be used to activate a specific Action * from external componenets such as the Launcher. See \ref page_platform-integration and * \ref page_offline-actions for more information. * * If the parameterType property is set, the Action is said to be parameterised. This means that when it is * bound to a menu or button, the action expects a typed input parameter. The type affects the allowed value * of the QVariant that must be passed to the trigger() and triggered(). * * \note As QVariant does automatic conversions between different normally uncorvertable types the developer * must be careful of the side effects the conversions might have if accidentally passing wrong type * of a parameter to trigger() or when handling the value of triggered(). Please, see the QVariant * documentation for more information on the conversions QVariant does. * * Action has to be added to the ActionManager or a ActionContext to make it available for external components. */ /*! * \enum Action::Type * \brief Available parameter types. * * This enum defines the available types that the action trigger() and triggered() * support. * * * \var Action::Type Action::None * * No paramater. Trying to pass anything else than an empty * QVariant is an error. * * * \var Action::Type Action::String * * String parameter. * * * \var Action::Type Action::Integer * * Integer parameter. * *\var Action::Type Action::Bool * * Boolean parameter. * * *\var Action::Type Action::Real * * Single precision floating point parameter. */ // property documentation /*! * \property QString Action::description * * User visible secondary description for the action. * * Description is more verbose than the text() and should describe the Action with * couple of words. * * \initvalue "" * * \accessors description(), setDescription() * * \notify descriptionChanged() */ /*! * \property bool Action::enabled * * If set to false the action can not be triggered. * * Components visualizing the action migth either hide the * action or make it insensitive. * * If set to false the Action is removed from the search * results of the HUD. * * \initvalue true * * \accessors enabled(), setEnabled() * * \notify enabledChanged() */ /*! * \property QString Action::iconName * * Name of a icon for this action. * * When the action is exported to external components the iconName * must be avaible on system icon theme engine. * * \initvalue "" * * \accessors iconName(), setIconName() * * \notify iconNameChanged() */ /*! * \property QString Action::keywords * * Additional user visible keywords for the action. * * Keywords improve the HUD search results when the user tries to search for an action * with a synonym of the text(). For example if we the application has an action "Crop" * but the user tries to "Trim" then without the keywords the HUD would not try to offer * the "Crop" action. * * The format of the keywords string is "Keyword 1;Keyword 2;Keyword 3" to allow translators * to define different number of keywords per language. * * The keywords are separated by ; and they may contain spaces. * * \code * Action *action = new Action(this); * action->setText(tr("Crop")); * action->description(tr("Crop the image")); * action->setKeywords(tr("Trim;Cut")); * \endcode * * \initvalue "" * * \accessors keywords(), setKeywords() * * \notify keywordsChanged() */ /*! * \property QString Action::name * * The name of the action. By default an action gets it's name * generated automatically if not overridden with setName() later. * If name is set to "" then the action restores it's autogenerated name. * * The actions is accessible from D-Bus with this name. * * The name is not user visible. * * \note Changing the name is potentially an expensive operation if the action is already added to the manager. * If possible, set the name for your action before adding it to the manager. * * \initvalue autogenerated * * \accessors name(), setName() * * \notify nameChanged() */ /*! * \property Action::Type Action::parameterType() * * Type of the parameter passed to trigger() and triggered(). * * \note Changing the parameterType is potentially an expensive operation if the action is already added to the manager. * If possible, set the parameterType of your action before adding it to the manager. * * \initvalue Action::None * * \accessors parameterType(), setParameterType() * * \notify parameterTypeChanged() */ /*! * \property QString Action::text * * The user visible primary label of the action. * * \initvalue "" * * \accessors text(), setText() * * \notify textChanged() */ // signal documentation /*! * \fn void Action::triggered(QVariant) * * \param value the value which which was passed to trigger() * * The value is always compatible with the set parameterType. For example * if parameterType is Action::String the value can be converted to QString * by using the QVariant conversion functions: * \code * QString param = value.toString(); * \endcode */ } } //! \private class Q_DECL_HIDDEN lomiri::action::Action::Private { public: QString name; QString generatedname; QString text; QString iconName; QString description; QString keywords; bool enabled; Action::Type parameterType; const char *paramTypeName(Action::Type type) { switch (type) { case Action::None: return "None"; case Action::String: return "String"; case Action::Integer: return "Integer"; case Action::Bool: return "Bool"; case Action::Real: return "Real"; } // should not be reached Q_ASSERT(0); return "Internal Error"; } }; /*! * \fn Action::Action(QObject *parent = 0) * \param parent parent QObject or 0 * * Constructs a new Action. See the property documentation for * default values. */ Action::Action(QObject *parent) : QObject(parent), d(new Private()) { qRegisterMetaType(); d->enabled = true; d->parameterType = None; // autogenerate a unique name static QMutex mutex; QMutexLocker locker(&mutex); static int id = 0; d->name = QString("lomiri-action-%1").arg(QString::number(id++)); d->generatedname = d->name; } Action::~Action() { } QString Action::name() const { return d->name; } void Action::setName(const QString &value) { QString oldName = d->name; if (d->name == value) return; if (!value.isNull() && !value.isEmpty()) d->name = value; else d->name = d->generatedname; if (oldName != d->name) emit nameChanged(d->name); } QString Action::text() const { return d->text; } void Action::setText(const QString &value) { if (d->text == value) return; d->text = value; emit textChanged(value); } QString Action::iconName() const { return d->iconName; } void Action::setIconName(const QString &value) { if (d->iconName == value) return; d->iconName = value; emit iconNameChanged(value); } QString Action::description() const { return d->description; } void Action::setDescription(const QString &value) { if (d->description == value) return; d->description = value; emit descriptionChanged(value); } QString Action::keywords() const { return d->keywords; } void Action::setKeywords(const QString &value) { if (d->keywords == value) return; d->keywords = value; emit keywordsChanged(value); } bool Action::enabled() const { return d->enabled; } void Action::setEnabled(bool value) { if (d->enabled == value) return; d->enabled = value; emit enabledChanged(value); } Action::Type Action::parameterType() const { return d->parameterType; } void Action::setParameterType(Type value) { if (d->parameterType == value) return; d->parameterType = value; emit parameterTypeChanged(value); } /*! * Checks the value agains parameterType and triggers the action. * * if paramType is Action::None the action can be triggered by simly calling: * \code * action->trigger(); * \endcode * * \note beware of the automatic conversion QVariant does. See the * QVariant documentation for details. */ void Action::trigger(QVariant value) { QMetaType::Type targetType = QMetaType::UnknownType; if (!d->enabled) { return; } switch (d->parameterType) { case None: { break; } case String: { targetType = QMetaType::QString; break; } case Integer: { targetType = QMetaType::Int; break; } case Bool: { targetType = QMetaType::Bool; break; } case Real: { targetType = QMetaType::Float; break; } } // need to take a copy of the value as we have to try to convert() it. QVariant tmp = value; if ((targetType == QMetaType::UnknownType && d->parameterType != None) || (!tmp.canConvert(targetType) || !tmp.convert(targetType))) { qWarning() << __PRETTY_FUNCTION__ << ":\n" << "\tTrying to trigger action (name: " << d->name << " :: text: " << d->text << ")\n" << "\twhich has parameter type '" << d->paramTypeName(d->parameterType) << "'\n" << "\twith incompatible parameter value (" << value << ")"; return; } emit triggered(value); } lomiri-action-api-1.1.3/src/lomiri-menu-item.cpp000066400000000000000000000062721455542516300215360ustar00rootroot00000000000000/* This file is part of lomiri-action-api * Copyright 2013 Canonical Ltd. * * lomiri-action-api is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * lomiri-action-api is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY, 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 program. If not, see . */ #include #include using namespace lomiri::action; class Q_DECL_HIDDEN lomiri::action::MenuItem::Private : public QObject { Q_OBJECT public: MenuItem *q; Action *action; QString text; QString iconName; QVariant target; bool visible; bool enabled; public slots: void actionDestroyed(QObject *obj); }; void MenuItem::Private::actionDestroyed(QObject *obj) { /* we can not use qobject_cast() as it will fail for * objects about to be destroyed. Instead we can simply cast the * pointer directly and use it as long as it's not 0. */ Action *tmp = (Action *)obj; if (tmp == 0) { return; } // simply clear the action. q->setAction(0); } MenuItem::MenuItem(QObject *parent) : QObject(parent), d(new Private) { d->q = this; d->action = 0; d->visible = true; d->enabled = true; } MenuItem::~MenuItem() { } /*! * \brief MenuItem::action * \return pointer to a lomiri::action::Action * \return or 0 if no action has been set */ Action * MenuItem::action() const { return d->action; } void MenuItem::setAction(Action *value) { if (d->action == value) return; if (d->action) d->action->disconnect(d.data()); if (value != 0) connect(value, SIGNAL(destroyed(QObject*)), d.data(), SLOT(actionDestroyed(QObject *))); d->action = value; emit actionChanged(); } QString MenuItem::text() const { return d->text; } void MenuItem::setText(const QString &value) { if (d->text == value) return; d->text = value; emit textChanged(value); } QString MenuItem::iconName() const { return d->iconName; } void MenuItem::setIconName(const QString &value) { if (d->iconName == value) return; d->iconName = value; emit iconNameChanged(value); } QVariant MenuItem::target() const { return d->target; } void MenuItem::setTarget(const QVariant &value) { if (d->target == value) return; d->target = value; emit targetChanged(value); } bool MenuItem::visible() const { return d->visible; } void MenuItem::setVisible(bool value) { if (d->visible == value) return; d->visible = value; emit visibleChanged(value); } bool MenuItem::enabled() const { return d->enabled; } void MenuItem::setEnabled(bool value) { if (d->enabled == value) return; d->enabled = value; emit enabledChanged(value); } #include "lomiri-menu-item.moc" lomiri-action-api-1.1.3/src/lomiri-preview-action.cpp000066400000000000000000000130721455542516300225660ustar00rootroot00000000000000/* This file is part of lomiri-action-api * Copyright 2013 Canonical Ltd. * * lomiri-action-api is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * lomiri-action-api is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY, 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 program. If not, see . */ #include #include using namespace lomiri::action; namespace lomiri { namespace action { /*! * \class PreviewAction * \brief previewable action * * The preview action is an action that allows the application to * generate a preview of the action before the action is applied. * The preview is controlled by the HUD UI. * * PreviewActions contain one or more parameters which form the preview * parameters of the action. * * For more details see \ref page_preview-actions * * \note Even though PreviewAction is subclass of Action not all of the properties * of Action base class are supported. * * \note Action::parameterType must be Action::None */ // properties /*! * \property QString PreviewAction::commitLabel * * User visible label shown in the HUD parameter view. * * This is the label shown in the HUD UI on the button that applies or commits the action * after the user is happy with the parameters. * * If set to empty string the HUD UI will use a default commit label. * * \initvalue "" * * \accessors commitLabel(), setCommitLabel() * * \notify commitLabelChanged() */ // signals /*! * \fn void PreviewAction::started() * * Signal to inform that a action is selected in the HUD UI. * The application should set the values of the parameters to their initial state. */ /*! * \fn void PreviewAction::cancelled() * * Signal to inform that the user has cancelled the action from the * HUD UI. No modifications should be done on the application and the program should * return to the state it was before the action was first started. */ /*! * \fn void PreviewAction::resetted() * * Signal to inform that the user has clicked the "reset" button from the * HUD UI. The action is still active on the HUD UI but the application * should reset the values of the parameters to the same values they where when the * action was started. */ /*! * \fn void PreviewAction::parametersChanged() * * Notifies that a parameter was either added or removed. */ } } //! \private class Q_DECL_HIDDEN lomiri::action::PreviewAction::Private : public QObject { Q_OBJECT public: PreviewAction *q; QString commitLabel; QList parameters; public slots: void parameterDestroyed(QObject *obj); }; void PreviewAction::Private::parameterDestroyed(QObject *obj) { /* we can not use qobject_cast() as it will fail for * objects about to be destroyed. Instead we can simply cast the * pointer directly and use it as long as it's not 0. */ PreviewParameter *parameter = (PreviewParameter *)obj; if (parameter == 0) { return; } q->removeParameter(parameter); } /*! * \fn PreviewAction::PreviewAction(QObject *parent = 0) * \param parent parent QObject or 0 * * Constructs a new PreviewAction. See the property documentation for * default values. */ PreviewAction::PreviewAction(QObject *parent) : Action(parent), d(new Private()) { d->q = this; } PreviewAction::~PreviewAction() { } QString PreviewAction::commitLabel() const { return d->commitLabel; } void PreviewAction::setCommitLabel(const QString &value) { if (d->commitLabel == value) return; d->commitLabel = value; emit commitLabelChanged(value); } /*! * \returns The list of parameters added to the action. */ QList PreviewAction::parameters() { return d->parameters; } /*! * \param parameter parameter to be added * * Adds a parameter. * * Calling this function multiple times with the same parameter * does not have any side effects; the parameter gets added only once. * * PreviewAction monitors if the parameter is deleted and does the appropriate * cleanup when necessary, so it is not mandatory to call removeParameter() * before the action is destroyed. * * \note parameter must not be 0. */ void PreviewAction::addParameter(lomiri::action::PreviewParameter *parameter) { Q_ASSERT(parameter != 0); if (parameter == 0) return; if (d->parameters.contains(parameter)) return; d->parameters.append(parameter); connect(parameter, SIGNAL(destroyed(QObject *)), d.data(), SLOT(parameterDestroyed(QObject *))); emit parametersChanged(); } /*! * \param parameter parameter to be removed * * Remove a parameter. * * Calling this function multiple times with the same parameter * does not have any side effects; the parameter gets removed only if * it was previously added with addParameter(). * * \note parameter must not be 0 */ void PreviewAction::removeParameter(lomiri::action::PreviewParameter *parameter) { Q_ASSERT(parameter != 0); if (parameter == 0) return; if (!d->parameters.contains(parameter)) return; parameter->disconnect(d.data()); d->parameters.removeOne(parameter); emit parametersChanged(); } #include "lomiri-preview-action.moc" lomiri-action-api-1.1.3/src/lomiri-preview-parameter.cpp000066400000000000000000000022601455542516300232660ustar00rootroot00000000000000/* This file is part of lomiri-action-api * Copyright 2013 Canonical Ltd. * * lomiri-action-api is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * lomiri-action-api is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY, 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 program. If not, see . */ #include using namespace lomiri::action; namespace lomiri { namespace action { /*! * \class PreviewParameter * Base class for all the parameter classes. * See the subclasses. */ } } //! \private class Q_DECL_HIDDEN lomiri::action::PreviewParameter::Private { public: void *placeholder; }; PreviewParameter::PreviewParameter(QObject *parent) : QObject(parent), d(new Private()) { } PreviewParameter::~PreviewParameter() { } lomiri-action-api-1.1.3/src/lomiri-preview-range-parameter.cpp000066400000000000000000000113721455542516300243640ustar00rootroot00000000000000/* This file is part of lomiri-action-api * Copyright 2013 Canonical Ltd. * * lomiri-action-api is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * lomiri-action-api is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY, 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 program. If not, see . */ #include using namespace lomiri::action; namespace lomiri { namespace action { /*! * \class PreviewRangeParameter * Provides a range preview parameter. * See \ref page_preview-actions for more details. */ } } // properties /*! * \property float PreviewRangeParameter::maximumValue * * The maximum value of the range. * * \initvalue 100.0f * * \accessors maximumValue(), setMaximumValue() * * \notify maximumValueChanged() */ /*! * \property float PreviewRangeParameter::minimumValue * * The minimum value of the range. * * \initvalue 0.0f * * \accessors minimumValue(), setMinimumValue() * * \notify minimumValueChanged() */ /*! * \property QString PreviewRangeParameter::text * * The user visible primary label of the parameter. * * \initvalue "" * * \accessors text(), setText() * * \notify textChanged() */ /*! * \property float PreviewRangeParameter::value * * The current value of the range. * * \initvalue 0.0f * * \accessors value(), setValue() * * \notify valueChanged() */ //! \private class Q_DECL_HIDDEN lomiri::action::PreviewRangeParameter::Private { public: QString text; float value; float min; float max; }; /*! * \fn PreviewRangeParameter::PreviewRangeParameter(QObject *parent = 0) * \param parent parent QObject or 0 * * Constructs a new PreviewRangeParameter. See the property documentation for * default values. */ PreviewRangeParameter::PreviewRangeParameter(QObject *parent) : PreviewParameter(parent), d(new Private()) { d->max = 100.0f; d->min = 0.0f; d->value = 0.0f; } PreviewRangeParameter::~PreviewRangeParameter() { } QString PreviewRangeParameter::text() const { return d->text; } void PreviewRangeParameter::setText(const QString &value) { if (d->text == value) return; d->text = value; emit textChanged(value); } float PreviewRangeParameter::value() const { return d->value; } void PreviewRangeParameter::setValue(float value) { if (qFuzzyCompare(d->value, value)) return; if (!qFuzzyCompare(d->min, value) && value < d->min) { qWarning("%s: trying to set range value (%f) below minimum (%f)", __PRETTY_FUNCTION__, value, d->min); return; } if (!qFuzzyCompare(d->max, value) && value > d->max) { qWarning("%s: trying to set range value (%f) above maximum (%f)", __PRETTY_FUNCTION__, value, d->max); return; } d->value = value; emit valueChanged(value); } float PreviewRangeParameter::minimumValue() const { return d->min; } void PreviewRangeParameter::setMinimumValue(float value) { if (qFuzzyCompare(d->min, value)) return; // make sure min is not bigger than max if (!qFuzzyCompare(value, d->max) && value > d->max) { qWarning("%s: trying to set minimum value (%f) above maximum (%f)", __PRETTY_FUNCTION__, value, d->max); d->min = d->max; } else { d->min = value; } emit minimumValueChanged(d->min); // make sure that current value is not smaller than min // if so, update value also if (!qFuzzyCompare(d->value, d->min) && d->value < d->min) { setValue(d->min); } } float PreviewRangeParameter::maximumValue() const { return d->max; } void PreviewRangeParameter::setMaximumValue(float value) { if (qFuzzyCompare(d->max, value)) return; // make sure max is not smaller than min if (!qFuzzyCompare(value, d->min) && value < d->min) { qWarning("%s: trying to set maximum value (%f) below minimum (%f)", __PRETTY_FUNCTION__, value, d->min); d->max = d->min; } else { d->max = value; } emit maximumValueChanged(d->max); // make sure that current value is not bigger than max // if so, update value also if (!qFuzzyCompare(d->value, d->max) && d->value > d->max) { setValue(d->max); } } lomiri-action-api-1.1.3/test/000077500000000000000000000000001455542516300160225ustar00rootroot00000000000000lomiri-action-api-1.1.3/test/CMakeLists.txt000066400000000000000000000000541455542516300205610ustar00rootroot00000000000000add_subdirectory(cpp) add_subdirectory(qml) lomiri-action-api-1.1.3/test/cpp/000077500000000000000000000000001455542516300166045ustar00rootroot00000000000000lomiri-action-api-1.1.3/test/cpp/CMakeLists.txt000066400000000000000000000011771455542516300213520ustar00rootroot00000000000000set(TEST_SRCS main.cpp tst_action.cpp tst_previewaction.cpp tst_previewrangeparameter.cpp # tst_menuitem.cpp tst_actioncontext.cpp tst_actionmanager.cpp ) set(testCommand dbus-test-runner -t ${CMAKE_CURRENT_BINARY_DIR}/cpptest -p -o -p ${CMAKE_BINARY_DIR}/cpptest.xml,xunitxml -p -o -p -,txt) pkg_search_module(GIO REQUIRED gio-2.0) include_directories(${GIO_INCLUDE_DIRS}) add_executable(cpptest ${TEST_SRCS}) target_link_libraries(cpptest lomiri-action-qt ${GIO_LIBRARIES}) find_package(Qt5Test REQUIRED) target_link_libraries(cpptest Qt5::Core Qt5::Test) add_test(NAME cpp COMMAND ${testCommand}) lomiri-action-api-1.1.3/test/cpp/main.cpp000066400000000000000000000034021455542516300202330ustar00rootroot00000000000000/* This file is part of lomiri-action-api * Copyright 2013 Canonical Ltd. * * lomiri-action-api is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * lomiri-action-api is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY, 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 program. If not, see . */ #include #include #include "tst_action.h" #include "tst_previewaction.h" #include "tst_previewrangeparameter.h" //#include "tst_menuitem.h" #include "tst_actioncontext.h" #include "tst_actionmanager.h" int main(int argc, char *argv[]) { // needed for QTest::qWait QCoreApplication app(argc, argv); TestAction tst_action; TestPreviewAction tst_previewaction; TestPreviewRangeParameter tst_previewrangeparameter; // TestMenuItem tst_menuitem; TestActionContext tst_actioncontext; TestActionManager tst_actionmanager; if (QTest::qExec(&tst_action, argc, argv) != 0) return 1; if (QTest::qExec(&tst_previewaction, argc, argv) != 0) return 1; if (QTest::qExec(&tst_previewrangeparameter, argc, argv) != 0) return 1; #if 0 if (QTest::qExec(&tst_menuitem, argc, argv) != 0) return 1; #endif if (QTest::qExec(&tst_actioncontext, argc, argv) != 0) return 1; if (QTest::qExec(&tst_actionmanager, argc, argv) != 0) return 1; return 0; } lomiri-action-api-1.1.3/test/cpp/tst_action.cpp000066400000000000000000000247641455542516300214740ustar00rootroot00000000000000/* This file is part of lomiri-action-api * Copyright 2013 Canonical Ltd. * * lomiri-action-api is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * lomiri-action-api is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY, 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 program. If not, see . */ #include "tst_action.h" #include #include void TestAction::setName() { lomiri::action::Action action; QSignalSpy spy(&action, SIGNAL(nameChanged(QString))); action.setName("myaction"); QVERIFY(action.name() == "myaction"); QCOMPARE(spy.count(), 1); QList arguments = spy.takeFirst(); QVERIFY(arguments.at(0).toString() == "myaction"); spy.clear(); action.setName("myaction"); QCOMPARE(spy.count(), 0); // sets the name once to the generated name action.setName(""); action.setName(QString()); action.setName(QString("")); QCOMPARE(spy.count(), 1); QVERIFY(action.name() != "myaction"); } void TestAction::setText() { lomiri::action::Action action; QSignalSpy spy(&action, SIGNAL(textChanged(QString))); action.setText("Foo"); QVERIFY(action.text() == "Foo"); QCOMPARE(spy.count(), 1); QList arguments = spy.takeFirst(); QVERIFY(arguments.at(0).toString() == "Foo"); spy.clear(); action.setText("Foo"); QCOMPARE(spy.count(), 0); } void TestAction::setIconName() { lomiri::action::Action action; QSignalSpy spy(&action, SIGNAL(iconNameChanged(QString))); action.setIconName("my-icon"); QVERIFY(action.iconName() == "my-icon"); QCOMPARE(spy.count(), 1); QList arguments = spy.takeFirst(); QVERIFY(arguments.at(0).toString() == "my-icon"); spy.clear(); action.setIconName("my-icon"); QCOMPARE(spy.count(), 0); } void TestAction::setDescription() { lomiri::action::Action action; QSignalSpy spy(&action, SIGNAL(descriptionChanged(QString))); action.setDescription("Lorem Ipsum"); QVERIFY(action.description() == "Lorem Ipsum"); QCOMPARE(spy.count(), 1); QList arguments = spy.takeFirst(); QVERIFY(arguments.at(0).toString() == "Lorem Ipsum"); spy.clear(); action.setDescription("Lorem Ipsum"); QCOMPARE(spy.count(), 0); } void TestAction::setKeywords() { lomiri::action::Action action; QString keywords; QSignalSpy spy(&action, SIGNAL(keywordsChanged(QString))); keywords = "Foo;Bar"; action.setKeywords(keywords); QVERIFY(action.keywords() == keywords); QCOMPARE(spy.count(), 1); QList arguments = spy.takeFirst(); QVERIFY(arguments.at(0).toString() == keywords); spy.clear(); action.setKeywords(keywords); QCOMPARE(spy.count(), 0); } void TestAction::setEnabled() { lomiri::action::Action action; action.setEnabled(true); QSignalSpy spy(&action, SIGNAL(enabledChanged(bool))); action.setEnabled(false); QVERIFY(action.enabled() == false); QCOMPARE(spy.count(), 1); QList arguments = spy.takeFirst(); QVERIFY(arguments.at(0).toBool() == false); spy.clear(); action.setEnabled(false); QCOMPARE(spy.count(), 0); action.setEnabled(true); QSignalSpy trigger_spy(&action, SIGNAL(triggered(QVariant))); action.trigger(); QCOMPARE(trigger_spy.count(), 1); trigger_spy.clear(); action.setEnabled(false); action.trigger(); QCOMPARE(trigger_spy.count(), 0); } void TestAction::setParameterType() { lomiri::action::Action action; QSignalSpy spy(&action, SIGNAL(parameterTypeChanged(lomiri::action::Action::Type))); action.setParameterType(lomiri::action::Action::String); QVERIFY(action.parameterType() == lomiri::action::Action::String); QCOMPARE(spy.count(), 1); QList arguments = spy.takeFirst(); QVERIFY(arguments.at(0).value() == lomiri::action::Action::String); spy.clear(); action.setParameterType(lomiri::action::Action::String); QCOMPARE(spy.count(), 0); } void TestAction::trigger() { lomiri::action::Action *action = new lomiri::action::Action(this); QSignalSpy spy(action, SIGNAL(triggered(QVariant))); /*** parameterType = None ***/ action->trigger(); QCOMPARE(spy.count(), 1); action->trigger(QVariant()); QCOMPARE(spy.count(), 2); /* expected failures */ spy.clear(); action->trigger("foo"); QCOMPARE(spy.count(), 0); action->trigger(-50); QCOMPARE(spy.count(), 0); action->trigger(false); QCOMPARE(spy.count(), 0); action->trigger(5.5f); QCOMPARE(spy.count(), 0); action->trigger(QRect()); QCOMPARE(spy.count(), 0); /*** parameterType = String ***/ action->setParameterType(lomiri::action::Action::String); action->trigger("hello"); QCOMPARE(spy.count(), 1); QCOMPARE(spy.takeFirst().at(0).toString(), QString("hello")); // these work because of the automatic type conversion QVariant does action->trigger(-50); QCOMPARE(spy.count(), 1); QCOMPARE(spy.takeFirst().at(0).toString(), QString("-50")); action->trigger(false); QCOMPARE(spy.count(), 1); QCOMPARE(spy.takeFirst().at(0).toString(), QString("false")); action->trigger(true); QCOMPARE(spy.count(), 1); QCOMPARE(spy.takeFirst().at(0).toString(), QString("true")); action->trigger(5.5f); QCOMPARE(spy.count(), 1); QCOMPARE(spy.takeFirst().at(0).toString(), QString("5.5")); /* expected failures */ spy.clear(); action->trigger(); QCOMPARE(spy.count(), 0); action->trigger(QRect()); QCOMPARE(spy.count(), 0); /*** parameterType = Integer ***/ action->setParameterType(lomiri::action::Action::Integer); action->trigger(-50); QCOMPARE(spy.count(), 1); QCOMPARE(spy.takeFirst().at(0).toInt(), -50); // these work because of the automatic type conversion QVariant does action->trigger("-50"); QCOMPARE(spy.count(), 1); QCOMPARE(spy.takeFirst().at(0).toInt(), -50); action->trigger(false); QCOMPARE(spy.count(), 1); QCOMPARE(spy.takeFirst().at(0).toInt(), 0); action->trigger(true); QCOMPARE(spy.count(), 1); QCOMPARE(spy.takeFirst().at(0).toInt(), 1); action->trigger(5.5f); QCOMPARE(spy.count(), 1); QCOMPARE(spy.takeFirst().at(0).toInt(), 6); /* expected failures */ spy.clear(); action->trigger(); QCOMPARE(spy.count(), 0); action->trigger("hello"); QCOMPARE(spy.count(), 0); action->trigger("true"); // QVariant does not do QString -> Bool -> Int QCOMPARE(spy.count(), 0); action->trigger("false"); QCOMPARE(spy.count(), 0); action->trigger("5.5"); // QVariant does not do QString -> Double -> Int QCOMPARE(spy.count(), 0); action->trigger(QRect()); QCOMPARE(spy.count(), 0); /*** parameterType = Bool ***/ action->setParameterType(lomiri::action::Action::Bool); action->trigger(false); QCOMPARE(spy.count(), 1); QCOMPARE(spy.takeFirst().at(0).toBool(), false); action->trigger(true); QCOMPARE(spy.count(), 1); QCOMPARE(spy.takeFirst().at(0).toBool(), true); // these work because of the automatic type conversion QVariant does action->trigger(-50); QCOMPARE(spy.count(), 1); QCOMPARE(spy.takeFirst().at(0).toBool(), true); action->trigger(0); QCOMPARE(spy.count(), 1); QCOMPARE(spy.takeFirst().at(0).toBool(), false); action->trigger(1); QCOMPARE(spy.count(), 1); QCOMPARE(spy.takeFirst().at(0).toBool(), true); action->trigger(0.0f); QCOMPARE(spy.count(), 1); QCOMPARE(spy.takeFirst().at(0).toBool(), false); action->trigger(5.5f); QCOMPARE(spy.count(), 1); QCOMPARE(spy.takeFirst().at(0).toBool(), true); /* When converting strings to bools qvariant uses to following logic: * * "true" -> true * "false" -> false * "0" -> false * " -> true * * "" -> false * -> true */ action->trigger("true"); QCOMPARE(spy.count(), 1); QCOMPARE(spy.takeFirst().at(0).toBool(), true); action->trigger("false"); QCOMPARE(spy.count(), 1); QCOMPARE(spy.takeFirst().at(0).toBool(), false); action->trigger("0"); QCOMPARE(spy.count(), 1); QCOMPARE(spy.takeFirst().at(0).toBool(), false); action->trigger("1"); QCOMPARE(spy.count(), 1); QCOMPARE(spy.takeFirst().at(0).toBool(), true); action->trigger("-50"); QCOMPARE(spy.count(), 1); QCOMPARE(spy.takeFirst().at(0).toBool(), true); action->trigger(""); QCOMPARE(spy.count(), 1); QCOMPARE(spy.takeFirst().at(0).toBool(), false); action->trigger("0.0"); QCOMPARE(spy.count(), 1); QCOMPARE(spy.takeFirst().at(0).toBool(), true); action->trigger("hello"); QCOMPARE(spy.count(), 1); QCOMPARE(spy.takeFirst().at(0).toBool(), true); /* expected failures */ spy.clear(); action->trigger(); QCOMPARE(spy.count(), 0); action->trigger(QRect()); QCOMPARE(spy.count(), 0); /*** parameterType = Real ***/ action->setParameterType(lomiri::action::Action::Real); action->trigger(0.0f); QCOMPARE(spy.count(), 1); QCOMPARE(spy.takeFirst().at(0).toFloat(), 0.0f); action->trigger(-1.0f); QCOMPARE(spy.count(), 1); QCOMPARE(spy.takeFirst().at(0).toFloat(), -1.0f); // these work because of the automatic type conversion QVariant does action->trigger(false); QCOMPARE(spy.count(), 1); QCOMPARE(spy.takeFirst().at(0).toFloat(), 0.0f); action->trigger(true); QCOMPARE(spy.count(), 1); QCOMPARE(spy.takeFirst().at(0).toFloat(), 1.0f); action->trigger("0.0"); QCOMPARE(spy.count(), 1); QCOMPARE(spy.takeFirst().at(0).toFloat(), 0.0f); action->trigger(-50); QCOMPARE(spy.count(), 1); QCOMPARE(spy.takeFirst().at(0).toFloat(), -50.0f); /* expected failures */ spy.clear(); action->trigger(); QCOMPARE(spy.count(), 0); action->trigger(QRect()); QCOMPARE(spy.count(), 0); action->trigger(""); QCOMPARE(spy.count(), 0); action->trigger("false"); QCOMPARE(spy.count(), 0); action->trigger("hello"); QCOMPARE(spy.count(), 0); } lomiri-action-api-1.1.3/test/cpp/tst_action.h000066400000000000000000000017461455542516300211340ustar00rootroot00000000000000/* This file is part of lomiri-action-api * Copyright 2013 Canonical Ltd. * * lomiri-action-api is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * lomiri-action-api is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY, 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 program. If not, see . */ #include class TestAction : public QObject { Q_OBJECT private slots: void setName(); void setText(); void setIconName(); void setDescription(); void setKeywords(); void setEnabled(); void setParameterType(); void trigger(); }; lomiri-action-api-1.1.3/test/cpp/tst_actioncontext.cpp000066400000000000000000000063161455542516300230720ustar00rootroot00000000000000/* This file is part of lomiri-action-api * Copyright 2013 Canonical Ltd. * * lomiri-action-api is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * lomiri-action-api is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY, 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 program. If not, see . */ #include "tst_actioncontext.h" #include #include #include #include using namespace lomiri::action; void TestActionContext::setActive() { lomiri::action::ActionContext ctx; ctx.setActive(false); QSignalSpy spy(&ctx, SIGNAL(activeChanged(bool))); ctx.setActive(true); QVERIFY(ctx.active() == true); QCOMPARE(spy.count(), 1); ctx.setActive(false); QVERIFY(ctx.active() == false); QCOMPARE(spy.count(), 2); QList arguments; arguments = spy.takeFirst(); QVERIFY(arguments.at(0).toBool() == true); arguments = spy.takeFirst(); QVERIFY(arguments.at(0).toBool() == false); spy.clear(); ctx.setActive(false); QCOMPARE(spy.count(), 0); } void TestActionContext::actionOperations() { lomiri::action::ActionContext *ctx = new lomiri::action::ActionContext(this); lomiri::action::Action *action1 = new lomiri::action::Action(this); lomiri::action::Action *action2 = new lomiri::action::Action(this); QSignalSpy spy(ctx, SIGNAL(actionsChanged())); ctx->addAction(action1); ctx->addAction(action2); ctx->addAction(action2); QVERIFY(spy.count() == 2); QVERIFY(ctx->actions().contains(action1) && ctx->actions().contains(action2)); ctx->removeAction(action1); ctx->removeAction(action1); QVERIFY(spy.count() == 3); QVERIFY(!ctx->actions().contains(action1) && ctx->actions().contains(action2)); ctx->addAction(action1); QVERIFY(spy.count() == 4); QVERIFY(ctx->actions().contains(action1) && ctx->actions().contains(action2)); } void TestActionContext::deletedActions() { /* When action is added to the context and then deleted without * being removed we must detect this and remove the action from the * context so that we don't get dangling pointers. */ ActionContext *ctx = new ActionContext(this); Action *action1 = new Action(); Action *action2 = new Action(); ctx->addAction(action1); ctx->addAction(action2); QSignalSpy spy(ctx, SIGNAL(actionsChanged())); // this should now also make the context to remove the action delete action2; QCOMPARE(spy.count(), 1); QVERIFY(!ctx->actions().contains(action2)); // make sure the pointer was removed action2 = 0; delete action1; QCOMPARE(spy.count(), 2); QVERIFY(!ctx->actions().contains(action1)); // make sure the pointer was removed action1 = 0; } lomiri-action-api-1.1.3/test/cpp/tst_actioncontext.h000066400000000000000000000016001455542516300225260ustar00rootroot00000000000000/* This file is part of lomiri-action-api * Copyright 2013 Canonical Ltd. * * lomiri-action-api is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * lomiri-action-api is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY, 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 program. If not, see . */ #include class TestActionContext : public QObject { Q_OBJECT private slots: void setActive(); void actionOperations(); void deletedActions(); }; lomiri-action-api-1.1.3/test/cpp/tst_actionmanager.cpp000066400000000000000000000747761455542516300230370ustar00rootroot00000000000000/* This file is part of lomiri-action-api * Copyright 2013 Canonical Ltd. * * lomiri-action-api is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * lomiri-action-api is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY, 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 program. If not, see . */ #include "tst_actionmanager.h" #include #include #include #include #include #include // needed for gio includes. #undef signals #include using namespace lomiri::action; void TestActionManager::initTestCase() { manager = new ActionManager(this); dbusc = 0; action_group = 0; dbusc = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, NULL); QVERIFY2(dbusc != 0, "Could not get session bus."); if (dbusc) { action_group = g_dbus_action_group_get(dbusc, g_dbus_connection_get_unique_name(dbusc), "/com/lomiri/actions"); QVERIFY2(action_group != 0, "Could not get action group"); } } void TestActionManager::cleanupTestCase() { g_clear_object(&dbusc); g_clear_object(&action_group); } void TestActionManager::cleanup() { // after each test make sure the manager is left in a clean state QVERIFY(manager->actions().count() == 1); QVERIFY(manager->localContexts().isEmpty()); } void TestActionManager::testGlobalContext() { ActionContext *globalctx = manager->globalContext(); QVERIFY(globalctx != 0); } void TestActionManager::actionOperations() { Action *action1 = new Action(manager); action1->setText("My Global Action"); action1->setName("Global"); Action *action2 = new Action(manager); action2->setText("Foo"); QSignalSpy spy(manager, SIGNAL(actionsChanged())); manager->addAction(action1); QCOMPARE(spy.count(), 1); manager->addAction(action2); QCOMPARE(spy.count(), 2); manager->addAction(action2); QCOMPARE(spy.count(), 2); QSetactions = manager->actions(); QVERIFY(actions.contains(action1) && actions.contains(action2)); manager->removeAction(action2); QCOMPARE(spy.count(), 3); manager->removeAction(action2); QCOMPARE(spy.count(), 3); actions = manager->actions(); QVERIFY(actions.contains(action1) && !actions.contains(action2)); manager->removeAction(action1); /*! \todo verify from the bus that actions appear there */ } void TestActionManager::contextOperations() { ActionContext *gctx = manager->globalContext(); ActionContext *ctx1 = new ActionContext(manager); ActionContext *ctx2 = new ActionContext(manager); ActionContext *ctx3 = new ActionContext(manager); Action *action1 = new Action(manager); Action *action2 = new Action(manager); Action *action3 = new Action(manager); Action *action4 = new Action(manager); Action *action5 = new Action(manager); gctx->addAction(action1); QSignalSpy ctxspy(manager, SIGNAL(localContextsChanged())); manager->addLocalContext(ctx1); QCOMPARE(ctxspy.count(), 1); ctx1->addAction(action2); ctx1->addAction(action3); ctx2->addAction(action4); ctx2->addAction(action5); manager->addLocalContext(ctx2); manager->addLocalContext(ctx2); QCOMPARE(ctxspy.count(), 2); QVERIFY(manager->localContexts().contains(ctx1) && manager->localContexts().contains(ctx2)); manager->removeLocalContext(ctx2); manager->removeLocalContext(ctx2); QVERIFY( manager->localContexts().contains(ctx1) && !manager->localContexts().contains(ctx2)); QCOMPARE(ctxspy.count(), 3); manager->addLocalContext(ctx2); QCOMPARE(ctxspy.count(), 4); QVERIFY(manager->localContexts().contains(ctx1) && manager->localContexts().contains(ctx2)); ctx2->setActive(true); ctx1->setActive(true); QVERIFY(!ctx2->active()); // if new context is added and it's active // make it the active local one in the manager. ctx3->setActive(true); manager->addLocalContext(ctx3); QVERIFY(!ctx1->active()); QVERIFY(!ctx2->active()); QVERIFY(ctx3->active()); /*! \todo verify actions from the bus */ gctx->removeAction(action1); gctx->addAction(action1); gctx->removeAction(action1); manager->removeLocalContext(ctx1); manager->removeLocalContext(ctx2); manager->removeLocalContext(ctx3); QVERIFY(manager->actions().count() == 1); } void TestActionManager::actionPropertyChanges() { ActionContext *ctx1 = new ActionContext(manager); ActionContext *ctx2 = new ActionContext(manager); Action *action1 = new Action(manager); Action *action2 = new Action(manager); Action *action3 = new Action(manager); Action *action4 = new Action(manager); Action *action5 = new Action(manager); Action *action6 = new Action(manager); QList arguments; manager->globalContext()->addAction(action1); manager->globalContext()->addAction(action2); ctx1->addAction(action3); ctx1->addAction(action4); ctx2->addAction(action5); ctx2->addAction(action6); manager->addLocalContext(ctx1); manager->addLocalContext(ctx2); // force both local context to be disabled ctx1->setActive(false); ctx2->setActive(false); action1->setName("Global"); action1->setText("My Global Action"); QSignalSpy action1_spy(action1, SIGNAL(triggered(QVariant))); QTest::qWait(100); g_action_group_activate_action(G_ACTION_GROUP(action_group), "Global", NULL); action1_spy.wait(); QCOMPARE(action1_spy.count(), 1); arguments = action1_spy.takeFirst(); QVERIFY(arguments.at(0).isNull()); action2->setText("Action2"); action2->setEnabled(false); ctx1->setActive(true); action3->setText("Action3"); action3->setName("InsideContext"); action4->setName("CallTo"); action4->setParameterType(Action::String); QSignalSpy action4_spy(action4, SIGNAL(triggered(QVariant))); QTest::qWait(100); g_action_group_activate_action(G_ACTION_GROUP(action_group), "CallTo", g_variant_new_string("tel://+0123456789")); action4_spy.wait(); QCOMPARE(action4_spy.count(), 1); arguments = action4_spy.takeFirst(); QCOMPARE(arguments.at(0).toString(), QString("tel://+0123456789")); ctx2->setActive(true); QSignalSpy action5_spy(action5, SIGNAL(triggered(QVariant))); action5->setParameterType(Action::Bool); QTest::qWait(100); g_action_group_activate_action(G_ACTION_GROUP(action_group), qPrintable(action5->name()), g_variant_new_boolean(true)); action5_spy.wait(); action5->setParameterType(Action::Integer); QTest::qWait(100); g_action_group_activate_action(G_ACTION_GROUP(action_group), qPrintable(action5->name()), g_variant_new_int32(1337)); action5_spy.wait(); action5->setParameterType(Action::Real); QTest::qWait(100); g_action_group_activate_action(G_ACTION_GROUP(action_group), qPrintable(action5->name()), g_variant_new_double(5.5f)); action5_spy.wait(); QCOMPARE(action5_spy.count(), 3); arguments = action5_spy.takeFirst(); QCOMPARE(arguments.at(0).toBool(), true); arguments = action5_spy.takeFirst(); QCOMPARE(arguments.at(0).toInt(), 1337); arguments = action5_spy.takeFirst(); QCOMPARE(arguments.at(0).toFloat(), 5.5f); action6->setParameterType(Action::String); action6->setParameterType(Action::None); manager->removeLocalContext(ctx1); manager->removeLocalContext(ctx2); manager->removeAction(action1); manager->removeAction(action2); } void TestActionManager::deletedGlobalContext() { // detect if the client accidentally calls delete on global context // and make sure we don't crash delete manager->globalContext(); } void TestActionManager::deletedLocalContext() { // if local context is added to the manager and delete is called for it // before it's removed we must detect this and not crash ActionContext *ctx1 = new ActionContext(); ActionContext *ctx2 = new ActionContext(); Action *action1 = new Action(ctx1); Action *action2 = new Action(ctx1); Action *action3 = new Action(ctx1); Action *action4 = new Action(ctx2); Action *action5 = new Action(ctx2); ctx1->addAction(action1); ctx1->addAction(action2); ctx1->addAction(action3); manager->addLocalContext(ctx1); ctx2->addAction(action4); ctx2->addAction(action5); manager->addLocalContext(ctx2); QSignalSpy ctxspy(manager, SIGNAL(localContextsChanged())); delete ctx1; QCOMPARE(ctxspy.count(), 1); QVERIFY(!manager->localContexts().contains(ctx1)); ctx1 = 0; delete ctx2; QCOMPARE(ctxspy.count(), 2); QVERIFY(!manager->localContexts().contains(ctx2)); ctx2 = 0; } void TestActionManager::deletedAction() { // if action is added to the manager and delete is called for it // before it's removed we must detect this and not crash ActionContext *gctx = manager->globalContext(); ActionContext *ctx1 = new ActionContext(); ActionContext *ctx2 = new ActionContext(); Action *action1 = new Action(gctx); Action *action2 = new Action(ctx1); Action *action3 = new Action(ctx1); Action *action4 = new Action(ctx2); Action *action5 = new Action(ctx2); gctx->addAction(action1); ctx1->addAction(action2); ctx1->addAction(action3); manager->addLocalContext(ctx1); ctx2->addAction(action4); ctx2->addAction(action5); manager->addLocalContext(ctx2); QSignalSpy spy(manager, SIGNAL(actionsChanged())); QCOMPARE(manager->actions().count(), 6); // delete action1 directly from globalContext delete action1; QCOMPARE(spy.count(), 1); QVERIFY(!manager->actions().contains(action1)); QCOMPARE(manager->actions().count(), 5); action1 = 0; // delete action2 directly from ctx1 delete action2; QCOMPARE(spy.count(), 2); QVERIFY(!manager->actions().contains(action2)); QCOMPARE(manager->actions().count(), 4); action2 = 0; // remove action3 indirectly by destroying ctx1 delete ctx1; QCOMPARE(spy.count(), 3); QVERIFY(!manager->actions().contains(action3)); QCOMPARE(manager->actions().count(), 3); ctx1 = 0; action3 = 0; // delete action4 and action5 indirectly by destroying ctx2 delete ctx2; QCOMPARE(spy.count(), 5); // actionsChanged() gets called multiple times (once per each action in a context) QVERIFY(!manager->actions().contains(action4)); QVERIFY(!manager->actions().contains(action5)); QCOMPARE(manager->actions().count(), 1); QVERIFY(manager->localContexts().isEmpty()); ctx2 = 0; action4 = 0; action5 = 0; } void TestActionManager::actionInMultipleContext() { /* If Action is added to multiple contexts * the manager has to be aware of the action * as long as it's part of any of the contexts. */ ActionContext *gctx = manager->globalContext(); ActionContext *ctx1 = new ActionContext(manager); ActionContext *ctx2 = new ActionContext(manager); Action *action1 = new Action(manager); Action *action2 = new Action(manager); Action *action3 = new Action(manager); QSignalSpy spy(manager, SIGNAL(actionsChanged())); gctx->addAction(action1); ctx1->addAction(action1); ctx1->addAction(action2); ctx2->addAction(action1); ctx2->addAction(action3); manager->addLocalContext(ctx1); manager->addLocalContext(ctx2); // 3 actions have been added in total QCOMPARE(spy.count(), 3); QCOMPARE(manager->actions().count(), 4); spy.clear(); manager->removeLocalContext(ctx2); // removes only action3, action1 is shared. QCOMPARE(spy.count(), 1); QCOMPARE(manager->actions().count(), 3); // and now add it back manager->addLocalContext(ctx2); QCOMPARE(spy.count(), 2); QCOMPARE(manager->actions().count(), 4); spy.clear(); gctx->removeAction(action1); QCOMPARE(spy.count(), 0); QCOMPARE(manager->actions().count(), 4); QVERIFY(manager->actions().contains(action1)); ctx1->removeAction(action1); QCOMPARE(spy.count(), 0); QCOMPARE(manager->actions().count(), 4); QVERIFY(manager->actions().contains(action1)); // remove the action from the last context ctx2->removeAction(action1); QCOMPARE(spy.count(), 1); QCOMPARE(manager->actions().count(), 3); QVERIFY(!manager->actions().contains(action1)); manager->removeLocalContext(ctx1); manager->removeLocalContext(ctx2); } void TestActionManager::localContextOverridesGlobalContext() { /* If local context defines an action with the same * name with an action in the global context the * local context action must override the global * one. */ ActionContext *gctx = manager->globalContext(); ActionContext *ctx1 = new ActionContext(manager); ActionContext *ctx2 = new ActionContext(manager); Action *action1 = new Action(manager); Action *action2 = new Action(manager); Action *action3 = new Action(manager); QSignalSpy spy1(action1, SIGNAL(triggered(QVariant))); QSignalSpy spy2(action2, SIGNAL(triggered(QVariant))); QSignalSpy spy3(action3, SIGNAL(triggered(QVariant))); action1->setName("MyAction"); action2->setName("MyAction"); action3->setName("MyAction"); ctx1->addAction(action2); ctx2->addAction(action3); gctx->addAction(action1); manager->addLocalContext(ctx1); manager->addLocalContext(ctx2); /* no local context has been activated. * triggering Myaction must now trigger action1 */ QTest::qWait(100); g_action_group_activate_action(G_ACTION_GROUP(action_group), "MyAction", NULL); spy1.wait(); QCOMPARE(spy1.count(), 1); QCOMPARE(spy2.count(), 0); QCOMPARE(spy3.count(), 0); spy1.clear(); ctx1->setActive(true); /* ctx1 is the active one. * triggering Myaction must now trigger action2 */ QTest::qWait(100); g_action_group_activate_action(G_ACTION_GROUP(action_group), "MyAction", NULL); spy2.wait(); QCOMPARE(spy1.count(), 0); QCOMPARE(spy2.count(), 1); QCOMPARE(spy3.count(), 0); spy2.clear(); ctx2->setActive(true); /* ctx2 is the active one. * triggering Myaction must now trigger action3 */ QTest::qWait(100); g_action_group_activate_action(G_ACTION_GROUP(action_group), "MyAction", NULL); spy3.wait(); QCOMPARE(spy1.count(), 0); QCOMPARE(spy2.count(), 0); QCOMPARE(spy3.count(), 1); spy3.clear(); manager->removeLocalContext(ctx2); /* removed the current active context. * triggering Myaction must now trigger action1 again from global context */ QTest::qWait(100); g_action_group_activate_action(G_ACTION_GROUP(action_group), "MyAction", NULL); spy1.wait(); QCOMPARE(spy1.count(), 1); QCOMPARE(spy2.count(), 0); QCOMPARE(spy3.count(), 0); spy1.clear(); gctx->removeAction(action1); manager->removeLocalContext(ctx1); } void TestActionManager::previewParameters() { ActionContext *ctx1 = new ActionContext(manager); PreviewAction *action1 = new PreviewAction(manager); PreviewAction *action2 = new PreviewAction(ctx1); PreviewRangeParameter *param1 = new PreviewRangeParameter(action1); PreviewRangeParameter *param2 = new PreviewRangeParameter(action2); PreviewRangeParameter *param3 = new PreviewRangeParameter(action2); action1->setName("MyPreviewAction1"); action2->setName("MyPreviewAction2"); // goes in to the global context manager->addAction(action1); action1->addParameter(param1); ctx1->addAction(action2); action2->addParameter(param2); action2->addParameter(param3); manager->addLocalContext(ctx1); QSignalSpy spy_action1_started(action1, SIGNAL(started())); QSignalSpy spy_action1_triggered(action1, SIGNAL(triggered(QVariant))); QSignalSpy spy_action1_cancelled(action1, SIGNAL(cancelled())); QSignalSpy spy_action1_resetted(action1, SIGNAL(resetted())); QSignalSpy spy_action2_started(action2, SIGNAL(started())); QSignalSpy spy_action2_triggered(action2, SIGNAL(triggered(QVariant))); QSignalSpy spy_action2_cancelled(action2, SIGNAL(cancelled())); QSignalSpy spy_action2_resetted(action2, SIGNAL(resetted())); QSignalSpy spy_param1_value(param1, SIGNAL(valueChanged(float))); QSignalSpy spy_param2_value(param2, SIGNAL(valueChanged(float))); QSignalSpy spy_param3_value(param3, SIGNAL(valueChanged(float))); // no context is active, we only have MyPreviewAction1 from globalContext g_action_group_activate_action(G_ACTION_GROUP(action_group), "MyPreviewAction1", g_variant_new_string("start")); QTest::qWait(100); QCOMPARE(spy_action1_started.count(), 1); QCOMPARE(spy_action1_triggered.count(), 0); QCOMPARE(spy_action1_cancelled.count(), 0); QCOMPARE(spy_action1_resetted.count(), 0); spy_action1_started.clear(); g_action_group_activate_action(G_ACTION_GROUP(action_group), "MyPreviewAction1", g_variant_new_string("reset")); QTest::qWait(100); QCOMPARE(spy_action1_started.count(), 0); QCOMPARE(spy_action1_triggered.count(), 0); QCOMPARE(spy_action1_cancelled.count(), 0); QCOMPARE(spy_action1_resetted.count(), 1); spy_action1_resetted.clear(); g_action_group_activate_action(G_ACTION_GROUP(action_group), "MyPreviewAction1", g_variant_new_string("commit")); QTest::qWait(100); QCOMPARE(spy_action1_started.count(), 0); QCOMPARE(spy_action1_triggered.count(), 1); QCOMPARE(spy_action1_cancelled.count(), 0); QCOMPARE(spy_action1_resetted.count(), 0); spy_action1_triggered.clear(); /* we don't actually have a corresponging signal for this state, * but HUD sends it anyway when the HUD UI parameterized view is * closed, so let's send it */ g_action_group_activate_action(G_ACTION_GROUP(action_group), "MyPreviewAction1", g_variant_new_string("end")); QTest::qWait(100); QCOMPARE(spy_action1_started.count(), 0); QCOMPARE(spy_action1_triggered.count(), 0); QCOMPARE(spy_action1_cancelled.count(), 0); QCOMPARE(spy_action1_resetted.count(), 0); g_action_group_activate_action(G_ACTION_GROUP(action_group), "MyPreviewAction1", g_variant_new_string("start")); QTest::qWait(100); QCOMPARE(spy_action1_started.count(), 1); QCOMPARE(spy_action1_triggered.count(), 0); QCOMPARE(spy_action1_cancelled.count(), 0); QCOMPARE(spy_action1_resetted.count(), 0); spy_action1_started.clear(); g_action_group_activate_action(G_ACTION_GROUP(action_group), "MyPreviewAction1", g_variant_new_string("cancel")); QTest::qWait(100); QCOMPARE(spy_action1_started.count(), 0); QCOMPARE(spy_action1_triggered.count(), 0); QCOMPARE(spy_action1_cancelled.count(), 1); QCOMPARE(spy_action1_resetted.count(), 0); spy_action1_cancelled.clear(); g_action_group_activate_action(G_ACTION_GROUP(action_group), "MyPreviewAction1", g_variant_new_string("end")); QTest::qWait(100); QCOMPARE(spy_action1_started.count(), 0); QCOMPARE(spy_action1_triggered.count(), 0); QCOMPARE(spy_action1_cancelled.count(), 0); QCOMPARE(spy_action1_resetted.count(), 0); // activate ctx1 ctx1->setActive(true); QTest::qWait(100); g_action_group_activate_action(G_ACTION_GROUP(action_group), "MyPreviewAction2", g_variant_new_string("start")); QTest::qWait(100); QCOMPARE(spy_action2_started.count(), 1); QCOMPARE(spy_action2_triggered.count(), 0); QCOMPARE(spy_action2_cancelled.count(), 0); QCOMPARE(spy_action2_resetted.count(), 0); QCOMPARE(spy_action1_started.count(), 0); QCOMPARE(spy_action1_triggered.count(), 0); QCOMPARE(spy_action1_cancelled.count(), 0); QCOMPARE(spy_action1_resetted.count(), 0); spy_action2_started.clear(); g_action_group_activate_action(G_ACTION_GROUP(action_group), "MyPreviewAction2", g_variant_new_string("reset")); QTest::qWait(100); QCOMPARE(spy_action2_started.count(), 0); QCOMPARE(spy_action2_triggered.count(), 0); QCOMPARE(spy_action2_cancelled.count(), 0); QCOMPARE(spy_action2_resetted.count(), 1); QCOMPARE(spy_action1_started.count(), 0); QCOMPARE(spy_action1_triggered.count(), 0); QCOMPARE(spy_action1_cancelled.count(), 0); QCOMPARE(spy_action1_resetted.count(), 0); spy_action2_resetted.clear(); g_action_group_activate_action(G_ACTION_GROUP(action_group), "MyPreviewAction2", g_variant_new_string("commit")); QTest::qWait(100); QCOMPARE(spy_action2_started.count(), 0); QCOMPARE(spy_action2_triggered.count(), 1); QCOMPARE(spy_action2_cancelled.count(), 0); QCOMPARE(spy_action2_resetted.count(), 0); QCOMPARE(spy_action1_started.count(), 0); QCOMPARE(spy_action1_triggered.count(), 0); QCOMPARE(spy_action1_cancelled.count(), 0); QCOMPARE(spy_action1_resetted.count(), 0); spy_action2_triggered.clear(); g_action_group_activate_action(G_ACTION_GROUP(action_group), "MyPreviewAction2", g_variant_new_string("end")); QTest::qWait(100); QCOMPARE(spy_action2_started.count(), 0); QCOMPARE(spy_action2_triggered.count(), 0); QCOMPARE(spy_action2_cancelled.count(), 0); QCOMPARE(spy_action2_resetted.count(), 0); QCOMPARE(spy_action1_started.count(), 0); QCOMPARE(spy_action1_triggered.count(), 0); QCOMPARE(spy_action1_cancelled.count(), 0); QCOMPARE(spy_action1_resetted.count(), 0); g_action_group_activate_action(G_ACTION_GROUP(action_group), "MyPreviewAction2", g_variant_new_string("start")); QTest::qWait(100); QCOMPARE(spy_action2_started.count(), 1); QCOMPARE(spy_action2_triggered.count(), 0); QCOMPARE(spy_action2_cancelled.count(), 0); QCOMPARE(spy_action2_resetted.count(), 0); QCOMPARE(spy_action1_started.count(), 0); QCOMPARE(spy_action1_triggered.count(), 0); QCOMPARE(spy_action1_cancelled.count(), 0); QCOMPARE(spy_action1_resetted.count(), 0); spy_action2_started.clear(); g_action_group_activate_action(G_ACTION_GROUP(action_group), "MyPreviewAction2", g_variant_new_string("cancel")); QTest::qWait(100); QCOMPARE(spy_action2_started.count(), 0); QCOMPARE(spy_action2_triggered.count(), 0); QCOMPARE(spy_action2_cancelled.count(), 1); QCOMPARE(spy_action2_resetted.count(), 0); QCOMPARE(spy_action1_started.count(), 0); QCOMPARE(spy_action1_triggered.count(), 0); QCOMPARE(spy_action1_cancelled.count(), 0); QCOMPARE(spy_action1_resetted.count(), 0); spy_action2_cancelled.clear(); g_action_group_activate_action(G_ACTION_GROUP(action_group), "MyPreviewAction2", g_variant_new_string("end")); QTest::qWait(100); QCOMPARE(spy_action2_started.count(), 0); QCOMPARE(spy_action2_triggered.count(), 0); QCOMPARE(spy_action2_cancelled.count(), 0); QCOMPARE(spy_action2_resetted.count(), 0); QCOMPARE(spy_action1_started.count(), 0); QCOMPARE(spy_action1_triggered.count(), 0); QCOMPARE(spy_action1_cancelled.count(), 0); QCOMPARE(spy_action1_resetted.count(), 0); // now check some range value updates g_action_group_activate_action(G_ACTION_GROUP(action_group), "MyPreviewAction1", g_variant_new_string("start")); QTest::qWait(100); spy_action1_started.clear(); // param1 g_action_group_activate_action(G_ACTION_GROUP(action_group), "lomiri-action-range-param-0", g_variant_new_double(1.0f)); QTest::qWait(100); QCOMPARE(spy_param1_value.count(), 1); QCOMPARE(spy_param2_value.count(), 0); QCOMPARE(spy_param3_value.count(), 0); QCOMPARE(spy_param1_value.takeFirst().at(0).toFloat(), 1.0f); g_action_group_activate_action(G_ACTION_GROUP(action_group), "lomiri-action-range-param-0", g_variant_new_double(1.1f)); g_action_group_activate_action(G_ACTION_GROUP(action_group), "lomiri-action-range-param-0", g_variant_new_double(1.2f)); g_action_group_activate_action(G_ACTION_GROUP(action_group), "lomiri-action-range-param-0", g_variant_new_double(1.3f)); QTest::qWait(100); QCOMPARE(spy_param1_value.count(), 3); QCOMPARE(spy_param2_value.count(), 0); QCOMPARE(spy_param3_value.count(), 0); QCOMPARE(spy_param1_value.takeFirst().at(0).toFloat(), 1.1f); QCOMPARE(spy_param1_value.takeFirst().at(0).toFloat(), 1.2f); QCOMPARE(spy_param1_value.takeFirst().at(0).toFloat(), 1.3f); g_action_group_activate_action(G_ACTION_GROUP(action_group), "MyPreviewAction1", g_variant_new_string("cancel")); QTest::qWait(100); spy_action1_cancelled.clear(); g_action_group_activate_action(G_ACTION_GROUP(action_group), "MyPreviewAction1", g_variant_new_string("end")); QTest::qWait(100); // then the others g_action_group_activate_action(G_ACTION_GROUP(action_group), "MyPreviewAction2", g_variant_new_string("start")); QTest::qWait(100); spy_action2_started.clear(); // param2 g_action_group_activate_action(G_ACTION_GROUP(action_group), "lomiri-action-range-param-1", g_variant_new_double(2.0f)); // param3 g_action_group_activate_action(G_ACTION_GROUP(action_group), "lomiri-action-range-param-2", g_variant_new_double(3.0f)); QTest::qWait(100); QCOMPARE(spy_param1_value.count(), 0); QCOMPARE(spy_param2_value.count(), 1); QCOMPARE(spy_param3_value.count(), 1); QCOMPARE(spy_param2_value.takeFirst().at(0).toFloat(), 2.0f); QCOMPARE(spy_param3_value.takeFirst().at(0).toFloat(), 3.0f); g_action_group_activate_action(G_ACTION_GROUP(action_group), "lomiri-action-range-param-1", g_variant_new_double(2.1f)); g_action_group_activate_action(G_ACTION_GROUP(action_group), "lomiri-action-range-param-2", g_variant_new_double(3.1f)); g_action_group_activate_action(G_ACTION_GROUP(action_group), "lomiri-action-range-param-1", g_variant_new_double(2.2f)); g_action_group_activate_action(G_ACTION_GROUP(action_group), "lomiri-action-range-param-2", g_variant_new_double(3.2f)); g_action_group_activate_action(G_ACTION_GROUP(action_group), "lomiri-action-range-param-1", g_variant_new_double(2.3f)); g_action_group_activate_action(G_ACTION_GROUP(action_group), "lomiri-action-range-param-2", g_variant_new_double(3.3f)); QTest::qWait(100); QCOMPARE(spy_param1_value.count(), 0); QCOMPARE(spy_param2_value.count(), 3); QCOMPARE(spy_param3_value.count(), 3); QCOMPARE(spy_param2_value.takeFirst().at(0).toFloat(), 2.1f); QCOMPARE(spy_param2_value.takeFirst().at(0).toFloat(), 2.2f); QCOMPARE(spy_param2_value.takeFirst().at(0).toFloat(), 2.3f); QCOMPARE(spy_param3_value.takeFirst().at(0).toFloat(), 3.1f); QCOMPARE(spy_param3_value.takeFirst().at(0).toFloat(), 3.2f); QCOMPARE(spy_param3_value.takeFirst().at(0).toFloat(), 3.3f); g_action_group_activate_action(G_ACTION_GROUP(action_group), "MyPreviewAction2", g_variant_new_string("cancel")); QTest::qWait(100); spy_action2_cancelled.clear(); g_action_group_activate_action(G_ACTION_GROUP(action_group), "MyPreviewAction2", g_variant_new_string("end")); QTest::qWait(100); // update some parameters action1->setCommitLabel("Do Stuff"); param1->setMinimumValue(-50.0f); param1->setMaximumValue(50.0f); param1->setValue(25.0f); /*! \todo there is actually no way of verifying these right now without accessing them from * HUD menumodels or creating a HUD query.. */ // remove parameter action2->removeParameter(param3); g_action_group_activate_action(G_ACTION_GROUP(action_group), "lomiri-action-range-param-2", g_variant_new_double(100.0f)); QTest::qWait(100); spy_param3_value.wait(100); QCOMPARE(spy_param3_value.count(), 0); // removed parameter should not receive updates. manager->removeAction(action1); manager->removeLocalContext(ctx1); } lomiri-action-api-1.1.3/test/cpp/tst_actionmanager.h000066400000000000000000000032131455542516300224560ustar00rootroot00000000000000/* This file is part of lomiri-action-api * Copyright 2013 Canonical Ltd. * * lomiri-action-api is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * lomiri-action-api is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY, 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 program. If not, see . */ #include #include typedef struct _GDBusConnection GDBusConnection; typedef struct _GDBusActionGroup GDBusActionGroup; class TestActionManager : public QObject { Q_OBJECT private slots: void initTestCase(); void cleanupTestCase(); void cleanup(); void testGlobalContext(); void actionOperations(); void contextOperations(); void actionPropertyChanges(); void deletedLocalContext(); void deletedAction(); void actionInMultipleContext(); void localContextOverridesGlobalContext(); void previewParameters(); // do this last as it creates a new globalContext in the effort of // preventing a crash, but anyway the functionality of the ActionManager // is more or less undefined after this. void deletedGlobalContext(); private: lomiri::action::ActionManager *manager; GDBusConnection *dbusc; GDBusActionGroup *action_group; }; lomiri-action-api-1.1.3/test/cpp/tst_menuitem.cpp000066400000000000000000000076431455542516300220370ustar00rootroot00000000000000/* This file is part of lomiri-action-api * Copyright 2013 Canonical Ltd. * * lomiri-action-api is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * lomiri-action-api is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY, 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 program. If not, see . */ #include "tst_menuitem.h" #include #include #include using namespace lomiri::action; void TestMenuItem::setAction() { lomiri::action::Action *action = new lomiri::action::Action(this); lomiri::action::MenuItem item; QVERIFY(item.action() == 0); QSignalSpy spy(&item, SIGNAL(actionChanged())); item.setAction(action); QVERIFY(item.action() == action); QCOMPARE(spy.count(), 1); spy.clear(); item.setAction(action); QCOMPARE(spy.count(), 0); item.setAction(0); QCOMPARE(spy.count(), 1); } void TestMenuItem::setText() { lomiri::action::MenuItem *item = new lomiri::action::MenuItem(this); QSignalSpy spy(item, SIGNAL(textChanged(QString))); item->setText("Foo"); QVERIFY(item->text() == "Foo"); QCOMPARE(spy.count(), 1); QList arguments = spy.takeFirst(); QVERIFY(arguments.at(0).toString() == "Foo"); spy.clear(); item->setText("Foo"); QCOMPARE(spy.count(), 0); } void TestMenuItem::setIconName() { lomiri::action::MenuItem item; QSignalSpy spy(&item, SIGNAL(iconNameChanged(QString))); item.setIconName("my-icon"); QVERIFY(item.iconName() == "my-icon"); QCOMPARE(spy.count(), 1); QList arguments = spy.takeFirst(); QVERIFY(arguments.at(0).toString() == "my-icon"); spy.clear(); item.setIconName("my-icon"); QCOMPARE(spy.count(), 0); } void TestMenuItem::setTarget() { lomiri::action::MenuItem item; QVariant var(45); QVERIFY(!item.target().isValid()); QSignalSpy spy(&item, SIGNAL(targetChanged(QVariant))); item.setTarget(var); QVERIFY(item.target() == var); QCOMPARE(spy.count(), 1); QList arguments = spy.takeFirst(); QVERIFY(arguments.at(0) == var); spy.clear(); item.setTarget(var); QCOMPARE(spy.count(), 0); item.setTarget(QVariant()); QCOMPARE(spy.count(), 1); QVERIFY(!item.target().isValid()); } void TestMenuItem::setVisible() { lomiri::action::MenuItem item; item.setVisible(true); QSignalSpy spy(&item, SIGNAL(visibleChanged(bool))); item.setVisible(false); QVERIFY(item.visible() == false); QCOMPARE(spy.count(), 1); QList arguments = spy.takeFirst(); QVERIFY(arguments.at(0).toBool() == false); spy.clear(); item.setVisible(false); QCOMPARE(spy.count(), 0); } void TestMenuItem::setEnabled() { lomiri::action::MenuItem item; item.setEnabled(true); QSignalSpy spy(&item, SIGNAL(enabledChanged(bool))); item.setEnabled(false); QVERIFY(item.enabled() == false); QCOMPARE(spy.count(), 1); QList arguments = spy.takeFirst(); QVERIFY(arguments.at(0).toBool() == false); spy.clear(); item.setEnabled(false); QCOMPARE(spy.count(), 0); } void TestMenuItem::verifyTargetType() { QSKIP("not implemented yet"); } void TestMenuItem::deletedAction() { Action *action = new Action(); MenuItem item; item.setAction(action); QSignalSpy spy(&item, SIGNAL(actionChanged())); delete action; QCOMPARE(spy.count(), 1); QVERIFY(item.action() == 0); action = 0; spy.clear(); item.setAction(0); QCOMPARE(spy.count(), 0); } lomiri-action-api-1.1.3/test/cpp/tst_menuitem.h000066400000000000000000000017531455542516300215000ustar00rootroot00000000000000/* This file is part of lomiri-action-api * Copyright 2013 Canonical Ltd. * * lomiri-action-api is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * lomiri-action-api is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY, 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 program. If not, see . */ #include class TestMenuItem : public QObject { Q_OBJECT private slots: void setAction(); void setText(); void setIconName(); void setTarget(); void setVisible(); void setEnabled(); void verifyTargetType(); void deletedAction(); }; lomiri-action-api-1.1.3/test/cpp/tst_previewaction.cpp000066400000000000000000000060161455542516300230640ustar00rootroot00000000000000/* This file is part of lomiri-action-api * Copyright 2013 Canonical Ltd. * * lomiri-action-api is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * lomiri-action-api is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY, 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 program. If not, see . */ #include "tst_previewaction.h" #include #include #include using namespace lomiri::action; void TestPreviewAction::setCommitLabel() { PreviewAction action; QSignalSpy spy(&action, SIGNAL(commitLabelChanged(QString))); action.setCommitLabel("Crop"); QVERIFY(action.commitLabel() == "Crop"); QCOMPARE(spy.count(), 1); QList arguments = spy.takeFirst(); QVERIFY(arguments.at(0).toString() == "Crop"); spy.clear(); action.setCommitLabel("Crop"); QCOMPARE(spy.count(), 0); } void TestPreviewAction::parameterOperations() { PreviewAction action; PreviewRangeParameter param1; PreviewRangeParameter param2; QSignalSpy spy(&action, SIGNAL(parametersChanged())); QVERIFY(action.parameters().isEmpty()); action.addParameter(¶m1); QCOMPARE(spy.count(), 1); action.addParameter(¶m2); QCOMPARE(spy.count(), 2); QVERIFY(action.parameters().contains(¶m1)); QVERIFY(action.parameters().contains(¶m2)); spy.clear(); action.addParameter(¶m1); action.addParameter(¶m2); QCOMPARE(spy.count(), 0); QCOMPARE(action.parameters().count(), 2); spy.clear(); action.removeParameter(¶m1); QCOMPARE(spy.count(), 1); QCOMPARE(action.parameters().count(), 1); QVERIFY(!action.parameters().contains(¶m1)); spy.clear(); action.removeParameter(¶m1); QCOMPARE(spy.count(), 0); QVERIFY(action.parameters().contains(¶m2)); action.removeParameter(¶m2); QCOMPARE(spy.count(), 1); QVERIFY(action.parameters().isEmpty()); } void TestPreviewAction::deletedParameter() { // if parameter is deleted we must detect this and not crash PreviewAction action; PreviewRangeParameter *param1 = new PreviewRangeParameter(); PreviewRangeParameter *param2 = new PreviewRangeParameter(); action.addParameter(param1); action.addParameter(param2); QSignalSpy spy(&action, SIGNAL(parametersChanged())); delete param1; QCOMPARE(spy.count(), 1); QVERIFY(!action.parameters().contains(param1)); param1 = 0; delete param2; QCOMPARE(spy.count(), 2); QVERIFY(!action.parameters().contains(param2)); param2 = 0; QVERIFY(action.parameters().isEmpty()); } lomiri-action-api-1.1.3/test/cpp/tst_previewaction.h000066400000000000000000000016131455542516300225270ustar00rootroot00000000000000/* This file is part of lomiri-action-api * Copyright 2013 Canonical Ltd. * * lomiri-action-api is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * lomiri-action-api is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY, 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 program. If not, see . */ #include class TestPreviewAction : public QObject { Q_OBJECT private slots: void setCommitLabel(); void parameterOperations(); void deletedParameter(); }; lomiri-action-api-1.1.3/test/cpp/tst_previewrangeparameter.cpp000066400000000000000000000075141455542516300246100ustar00rootroot00000000000000/* This file is part of lomiri-action-api * Copyright 2013 Canonical Ltd. * * lomiri-action-api is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * lomiri-action-api is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY, 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 program. If not, see . */ #include "tst_previewrangeparameter.h" #include #include void TestPreviewRangeParameter::setText() { lomiri::action::PreviewRangeParameter param; QSignalSpy spy(¶m, SIGNAL(textChanged(QString))); param.setText("Red"); QVERIFY(param.text() == "Red"); QCOMPARE(spy.count(), 1); QList arguments = spy.takeFirst(); QVERIFY(arguments.at(0).toString() == "Red"); spy.clear(); param.setText("Red"); QCOMPARE(spy.count(), 0); } void TestPreviewRangeParameter::setValue() { lomiri::action::PreviewRangeParameter *param; param = new lomiri::action::PreviewRangeParameter(this); QSignalSpy spy(param, SIGNAL(valueChanged(float))); param->setValue(100); QVERIFY(qFuzzyCompare(param->value(), 100.0f)); QCOMPARE(spy.count(), 1); QList arguments = spy.takeFirst(); QVERIFY(qFuzzyCompare(arguments.at(0).toFloat(), 100.0f)); spy.clear(); param->setValue(100); QCOMPARE(spy.count(), 0); } void TestPreviewRangeParameter::setMinimumValue() { lomiri::action::PreviewRangeParameter *param; param = new lomiri::action::PreviewRangeParameter(this); param->setMinimumValue(-100); param->setValue(-100); QSignalSpy spy(param, SIGNAL(minimumValueChanged(float))); param->setMinimumValue(0); QVERIFY(qFuzzyCompare(param->minimumValue(), 0)); QCOMPARE(spy.count(), 1); QList arguments = spy.takeFirst(); QVERIFY(qFuzzyCompare(arguments.at(0).toFloat(), 0.0f)); // verify that the value changed to allowed range QVERIFY(qFuzzyCompare(param->value(), 0.0f)); spy.clear(); param->setMinimumValue(0); QCOMPARE(spy.count(), 0); // verify that value can not be changed lower than minimum value param->setValue(-100); QVERIFY(qFuzzyCompare(param->value(), param->minimumValue())); // verify that minimum value can't be bigger than maximum value param->setMaximumValue(100); param->setMinimumValue(101); QVERIFY(qFuzzyCompare(param->minimumValue(), param->maximumValue())); } void TestPreviewRangeParameter::setMaximumValue() { lomiri::action::PreviewRangeParameter *param; param = new lomiri::action::PreviewRangeParameter(this); param->setMaximumValue(500); param->setValue(500); QSignalSpy spy(param, SIGNAL(maximumValueChanged(float))); param->setMaximumValue(200); QVERIFY(qFuzzyCompare(param->maximumValue(), 200)); QCOMPARE(spy.count(), 1); QList arguments = spy.takeFirst(); QVERIFY(qFuzzyCompare(arguments.at(0).toFloat(), 200.0f)); // verify that the value changed to allowed range QVERIFY(qFuzzyCompare(param->value(), 200.0f)); spy.clear(); param->setMaximumValue(200); QCOMPARE(spy.count(), 0); // verify that value can not be changed higher than maximum value param->setValue(400); QVERIFY(qFuzzyCompare(param->value(), param->maximumValue())); // verify that maximum value can't be lower than minimum value param->setMinimumValue(100); param->setMaximumValue(99); QVERIFY(qFuzzyCompare(param->minimumValue(), param->maximumValue())); } lomiri-action-api-1.1.3/test/cpp/tst_previewrangeparameter.h000066400000000000000000000016321455542516300242500ustar00rootroot00000000000000/* This file is part of lomiri-action-api * Copyright 2013 Canonical Ltd. * * lomiri-action-api is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * lomiri-action-api is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY, 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 program. If not, see . */ #include class TestPreviewRangeParameter : public QObject { Q_OBJECT private slots: void setText(); void setValue(); void setMinimumValue(); void setMaximumValue(); }; lomiri-action-api-1.1.3/test/qml/000077500000000000000000000000001455542516300166135ustar00rootroot00000000000000lomiri-action-api-1.1.3/test/qml/CMakeLists.txt000066400000000000000000000020531455542516300213530ustar00rootroot00000000000000add_custom_target(qmlunittests) add_custom_target(qmlunittests_1_1) find_program(qmltestrunner_exe qmltestrunner) if(NOT qmltestrunner_exe) message(FATAL_ERROR "Could not locate qmltestrunner.") endif() set(qmltest_command dbus-test-runner -t env -p "QT_QPA_PLATFORM=minimal" -p ${qmltestrunner_exe} -p -input -p ${CMAKE_CURRENT_SOURCE_DIR}/tst_api.qml -p -import -p ${CMAKE_CURRENT_BINARY_DIR}/../../qml -p -o -p ${CMAKE_BINARY_DIR}/testapi.xml,xunitxml -p -o -p -,txt ) add_custom_target(qmltest_api ${qmltest_command}) add_dependencies(qmlunittests qmltest_api) add_test(qmlunittests ${qmltest_command}) set(qmltest1_1_command dbus-test-runner -t env -p "QT_QPA_PLATFORM=minimal" -p ${qmltestrunner_exe} -p -input -p ${CMAKE_CURRENT_SOURCE_DIR}/tst_api1.1.qml -p -import -p ${CMAKE_CURRENT_BINARY_DIR}/../../qml -p -o -p ${CMAKE_BINARY_DIR}/testapi.xml,xunitxml -p -o -p -,txt ) add_custom_target(qmltest_1_1_api ${qmltest1_1_command}) add_dependencies(qmlunittests_1_1 qmltest_1_1_api) add_test(qmlunittests_1_1 ${qmltest1_1_command}) lomiri-action-api-1.1.3/test/qml/tst_api.qml000066400000000000000000000051331455542516300207730ustar00rootroot00000000000000/* This file is part of lomiri-action-api * Copyright 2013 Canonical Ltd. * * lomiri-action-api is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * lomiri-action-api is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY, 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 program. If not, see . */ import Lomiri.Action 1.0 import QtQuick 2.0 import QtTest 1.0 /* This test will make sure there are no unintentional changes to the * schemantics of the API (default properties work as expected, etc) * so that any files written to the prior release of the library * will not bail out when loaded resulting in client applications failing * to start. */ Item { ActionManager { id: manager localContexts: [ctx1, ctx2] Action { id: globalaction name: "NewMessage" text: "Write New Message" iconName: "email-new-message" description: "Write a new Message" keywords: "Compose;Send" enabled: true parameterType: Action.String onTriggered: {} } } ActionContext { id: ctx1 Action { id: myaction1 text: "Foo" onTriggered: {} } } ActionContext { id: ctx2 PreviewAction { id: previewaction text: "Color Balance" commitLabel: "Apply" onStarted: {} onResetted: {} onCancelled: {} onTriggered: {} PreviewRangeParameter { text: "lorem ipsum" value: 0 minimumValue: -100 maximumValue: 100 onValueChanged: {} } } } /* MenuItem { action: myaction1 text: "New Message" iconName: "menu-new-message" target: "user@corporation.tld" visible: true enabled: false } */ Component.onCompleted: { ctx2.active = true } TestCase { name: "API Test" id: test_api function test_api() { // just make sure this file can be loaded properly by the QmlEngine. verify(1) } } } lomiri-action-api-1.1.3/test/qml/tst_api1.1.qml000066400000000000000000000051671455542516300212220ustar00rootroot00000000000000/* This file is part of lomiri-action-api * Copyright 2013 Canonical Ltd. * * lomiri-action-api is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * lomiri-action-api is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY, 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 program. If not, see . */ import Lomiri.Action 1.1 import QtQuick 2.0 import QtTest 1.0 /* This test will make sure there are no unintentional changes to the * schemantics of the API (default properties work as expected, etc) * so that any files written to the prior release of the library * will not bail out when loaded resulting in client applications failing * to start. */ Item { ActionManager { id: manager localContexts: [ctx1, ctx2] onQuit: {} Action { id: globalaction name: "NewMessage" text: "Write New Message" iconName: "email-new-message" description: "Write a new Message" keywords: "Compose;Send" enabled: true parameterType: Action.String onTriggered: {} } } ActionContext { id: ctx1 Action { id: myaction1 text: "Foo" onTriggered: {} } } ActionContext { id: ctx2 PreviewAction { id: previewaction text: "Color Balance" commitLabel: "Apply" onStarted: {} onResetted: {} onCancelled: {} onTriggered: {} PreviewRangeParameter { text: "lorem ipsum" value: 0 minimumValue: -100 maximumValue: 100 onValueChanged: {} } } } /* MenuItem { action: myaction1 text: "New Message" iconName: "menu-new-message" target: "user@corporation.tld" visible: true enabled: false } */ Component.onCompleted: { ctx2.active = true } TestCase { name: "API Test" id: test_api function test_api() { // just make sure this file can be loaded properly by the QmlEngine. verify(1) } } }