From 264eaf99139025ee306917d2d69fe1fcfdd4e223 Mon Sep 17 00:00:00 2001 From: Andrey Paskal Date: Fri, 19 Dec 2008 15:37:54 +0300 Subject: [PATCH] First import --- Makefile | 66 + README | 122 ++ VERSION | 1 + applications/ananas-cfg.dtd | 150 ++ applications/money/money.cfg | 170 ++ applications/money/money.rc | 9 + build/altlinux/altlinux.spec | 407 ++++ build/fedora/fedora.spec | 231 ++ build/icons/a-system.ico | Bin 0 -> 16318 bytes build/icons/a-system.png | Bin 0 -> 1283 bytes build/icons/ananas-16x16.png | Bin 0 -> 355 bytes build/icons/ananas-32x32.png | Bin 0 -> 799 bytes build/icons/ananas-designer.ico | Bin 0 -> 4286 bytes build/icons/ananas-designer.png | Bin 0 -> 1328 bytes build/icons/manual.ico | Bin 0 -> 4286 bytes build/mandriva/mandriva.spec | 219 ++ build/menus/kde/README | 4 + build/menus/kde/ananas | 5 + build/menus/kde/ananas-designer | 6 + build/menus/kde/ananas-designer.desktop | 11 + build/menus/kde/ananas.desktop | 11 + build/win32/AnanasInstall.iss | 247 +++ build/win32/AnanasUpgrade.iss | 135 ++ build/win32/setuplogo.bmp | Bin 0 -> 292856 bytes icons/a-system.ico | Bin 0 -> 16318 bytes icons/a-system.png | Bin 0 -> 1283 bytes icons/ananas-16x16.png | Bin 0 -> 355 bytes icons/ananas-32x32.png | Bin 0 -> 799 bytes icons/ananas-designer.ico | Bin 0 -> 4286 bytes icons/ananas_splach.cdr | Bin 0 -> 336118 bytes icons/lit.png | Bin 0 -> 5244 bytes icons/manual.ico | Bin 0 -> 4286 bytes src/admin/admin.pro | 59 + src/admin/admin.qrc | 22 + src/admin/atreeitems.cpp | 157 ++ src/admin/atreeitems.h | 88 + src/admin/deditpermissions.cpp | 82 + src/admin/deditpermissions.h | 25 + src/admin/deditpermissions.ui | 218 ++ src/admin/deditrole.cpp | 50 + src/admin/deditrole.h | 22 + src/admin/deditrole.ui | 72 + src/admin/dedituser.cpp | 90 + src/admin/dedituser.h | 29 + src/admin/dedituser.ui | 135 ++ src/admin/dselectrole.cpp | 80 + src/admin/dselectrole.h | 29 + src/admin/dselectrole.ui | 71 + src/admin/dselectuser.cpp | 89 + src/admin/dselectuser.h | 31 + src/admin/dselectuser.ui | 75 + src/admin/images/administrator-splash-en.png | Bin 0 -> 100739 bytes src/admin/images/administrator-splash-ru.png | Bin 0 -> 102180 bytes src/admin/images/cat.png | Bin 0 -> 401 bytes src/admin/images/cat_g.png | Bin 0 -> 697 bytes src/admin/images/doc.png | Bin 0 -> 456 bytes src/admin/images/doc_g.png | Bin 0 -> 748 bytes src/admin/images/journ.png | Bin 0 -> 403 bytes src/admin/images/journ_g.png | Bin 0 -> 671 bytes src/admin/images/metadata.png | Bin 0 -> 1354 bytes src/admin/images/reg.png | Bin 0 -> 425 bytes src/admin/images/reg_g.png | Bin 0 -> 717 bytes src/admin/images/regs.png | Bin 0 -> 433 bytes src/admin/images/report.png | Bin 0 -> 636 bytes src/admin/images/report_g.png | Bin 0 -> 835 bytes src/admin/images/role.png | Bin 0 -> 1507 bytes src/admin/images/user.png | Bin 0 -> 1267 bytes src/admin/images/users.png | Bin 0 -> 1498 bytes src/admin/main.cpp | 165 ++ src/admin/mainform.cpp | 131 ++ src/admin/mainform.h | 41 + src/admin/mainform.ui | 127 ++ src/admin/mdtree.cpp | 962 +++++++++ src/admin/mdtree.h | 158 ++ src/admin/rolesform.cpp | 36 + src/admin/rolesform.h | 26 + src/admin/rolesform.ui | 26 + src/admin/usersform.cpp | 39 + src/admin/usersform.h | 28 + src/admin/usersform.ui | 24 + src/ananas.pri | 24 + src/ananas/ananas.pro | 46 + src/ananas/ananas.qrc | 34 + src/ananas/bkground.jpg | Bin 0 -> 5119 bytes src/ananas/images/a-system.png | Bin 0 -> 1283 bytes src/ananas/images/cat.png | Bin 0 -> 401 bytes src/ananas/images/d_document_turned.png | Bin 0 -> 505 bytes src/ananas/images/document_turned.png | Bin 0 -> 384 bytes src/ananas/images/editdelete.png | Bin 0 -> 953 bytes src/ananas/images/editdelete2.png | Bin 0 -> 783 bytes src/ananas/images/engine-splash-en.png | Bin 0 -> 93995 bytes src/ananas/images/engine-splash-ru.png | Bin 0 -> 94298 bytes src/ananas/images/field.png | Bin 0 -> 155 bytes src/ananas/images/field2.png | Bin 0 -> 156 bytes src/ananas/images/group.png | Bin 0 -> 208 bytes src/ananas/images/group2.png | Bin 0 -> 174 bytes src/ananas/images/lib_database.png | Bin 0 -> 1039 bytes src/ananas/images/lib_dbgroup.png | Bin 0 -> 681 bytes src/ananas/images/msg_error.png | Bin 0 -> 964 bytes src/ananas/images/msg_fatal.png | Bin 0 -> 964 bytes src/ananas/images/msg_info.png | Bin 0 -> 1756 bytes src/ananas/images/msg_warning.png | Bin 0 -> 964 bytes src/ananas/images/object_markdeleted.png | Bin 0 -> 953 bytes src/ananas/images/t_cat_e.png | Bin 0 -> 329 bytes src/ananas/images/t_cat_ed.png | Bin 0 -> 404 bytes src/ananas/images/t_cat_g.png | Bin 0 -> 329 bytes src/ananas/images/t_cat_gd.png | Bin 0 -> 402 bytes src/ananas/images/t_doc.png | Bin 0 -> 353 bytes src/ananas/images/t_doc_d.png | Bin 0 -> 435 bytes src/ananas/images/t_doc_m.png | Bin 0 -> 373 bytes src/ananas/images/t_doc_t.png | Bin 0 -> 396 bytes src/ananas/images/t_doc_tm.png | Bin 0 -> 405 bytes src/ananas/images/t_doc_to.png | Bin 0 -> 505 bytes src/ananas/images/t_doc_tom.png | Bin 0 -> 361 bytes src/ananas/main.cpp | 198 ++ src/ananas/mainform.cpp | 314 +++ src/ananas/mainform.h | 116 + src/ananas/report.sxw | Bin 0 -> 6806 bytes src/ananas/report.tpl | 21 + src/designer/actiontree.cpp | 257 +++ src/designer/actiontree.h | 74 + src/designer/aliaseditor.cpp | 88 + src/designer/aliaseditor.h | 54 + src/designer/atreeitems.cpp | 274 +++ src/designer/atreeitems.h | 83 + src/designer/cfgform.cpp | 860 ++++++++ src/designer/cfgform.h | 71 + src/designer/cfgform.ui | 775 +++++++ src/designer/deditaction.cpp | 366 ++++ src/designer/deditaction.h | 48 + src/designer/deditaction.ui | 663 ++++++ src/designer/deditareg.cpp | 76 + src/designer/deditareg.h | 31 + src/designer/deditareg.ui | 123 ++ src/designer/deditcat.cpp | 174 ++ src/designer/deditcat.h | 38 + src/designer/deditcat.ui | 266 +++ src/designer/deditcfg.cpp | 171 ++ src/designer/deditcfg.h | 29 + src/designer/deditcfg.ui | 449 ++++ src/designer/deditcolumns.cpp | 266 +++ src/designer/deditcolumns.h | 41 + src/designer/deditcolumns.ui | 293 +++ src/designer/deditcommand.cpp | 241 +++ src/designer/deditcommand.h | 39 + src/designer/deditcommand.ui | 577 +++++ src/designer/deditdialog.cpp | 337 +++ src/designer/deditdialog.h | 38 + src/designer/deditdialog.ui | 374 ++++ src/designer/deditdoc.cpp | 131 ++ src/designer/deditdoc.h | 34 + src/designer/deditdoc.ui | 225 ++ src/designer/deditfield.cpp | 326 +++ src/designer/deditfield.h | 38 + src/designer/deditfield.ui | 355 ++++ src/designer/deditimagecollection.cpp | 49 + src/designer/deditimagecollection.h | 28 + src/designer/deditimagecollection.ui | 84 + src/designer/deditireg.cpp | 85 + src/designer/deditireg.h | 31 + src/designer/deditireg.ui | 130 ++ src/designer/deditjournal.cpp | 197 ++ src/designer/deditjournal.h | 44 + src/designer/deditjournal.ui | 398 ++++ src/designer/deditlang.cpp | 78 + src/designer/deditlang.h | 32 + src/designer/deditlang.ui | 123 ++ src/designer/deditreport.cpp | 83 + src/designer/deditreport.h | 31 + src/designer/deditreport.ui | 142 ++ src/designer/deditrole.cpp | 76 + src/designer/deditrole.h | 32 + src/designer/deditrole.ui | 91 + src/designer/dedittoolbar.cpp | 228 ++ src/designer/dedittoolbar.h | 39 + src/designer/dedittoolbar.ui | 503 +++++ src/designer/deditwebform.cpp | 89 + src/designer/deditwebform.h | 31 + src/designer/deditwebform.ui | 154 ++ src/designer/designer.pro | 182 ++ src/designer/designer.qrc | 82 + src/designer/embed.cpp | 312 +++ src/designer/embed.h | 1 + src/designer/formdesigner.cpp | 159 ++ src/designer/formdesigner.h | 58 + src/designer/formdesigner/designer.qrc | 9 + src/designer/formdesigner/formwindowsettings.cpp | 103 + src/designer/formdesigner/formwindowsettings.h | 48 + src/designer/formdesigner/formwindowsettings.ui | 319 +++ src/designer/formdesigner/images/designer.png | Bin 0 -> 14607 bytes src/designer/formdesigner/images/mdi.png | Bin 0 -> 59505 bytes src/designer/formdesigner/images/sdi.png | Bin 0 -> 61037 bytes src/designer/formdesigner/images/workbench.png | Bin 0 -> 2174 bytes src/designer/formdesigner/newform.cpp | 244 +++ src/designer/formdesigner/newform.h | 59 + src/designer/formdesigner/newform.ui | 254 +++ src/designer/formdesigner/plugindialog.cpp | 122 ++ src/designer/formdesigner/plugindialog.h | 50 + src/designer/formdesigner/plugindialog.ui | 134 ++ .../formdesigner/private/formscriptrunner_p.h | 87 + .../formdesigner/private/pluginmanager_p.h | 100 + .../formdesigner/private/qdesigner_formbuilder_p.h | 113 + .../formdesigner/private/qdesigner_integration_p.h | 96 + src/designer/formdesigner/private/qtundo_p.h | 274 +++ .../formdesigner/private/shared_global_p.h | 58 + .../formdesigner/private/sheet_delegate_p.h | 63 + .../formdesigner/qdesigner_actioneditor.cpp | 56 + src/designer/formdesigner/qdesigner_actioneditor.h | 41 + src/designer/formdesigner/qdesigner_actions.cpp | 998 +++++++++ src/designer/formdesigner/qdesigner_actions.h | 223 ++ src/designer/formdesigner/qdesigner_formwindow.cpp | 180 ++ src/designer/formdesigner/qdesigner_formwindow.h | 62 + .../formdesigner/qdesigner_objectinspector.cpp | 56 + .../formdesigner/qdesigner_objectinspector.h | 41 + src/designer/formdesigner/qdesigner_pch.h | 41 + .../formdesigner/qdesigner_propertyeditor.cpp | 71 + .../formdesigner/qdesigner_propertyeditor.h | 44 + .../formdesigner/qdesigner_resourceeditor.cpp | 62 + .../formdesigner/qdesigner_resourceeditor.h | 42 + src/designer/formdesigner/qdesigner_settings.cpp | 202 ++ src/designer/formdesigner/qdesigner_settings.h | 66 + .../formdesigner/qdesigner_signalsloteditor.cpp | 61 + .../formdesigner/qdesigner_signalsloteditor.h | 41 + src/designer/formdesigner/qdesigner_toolwindow.cpp | 138 ++ src/designer/formdesigner/qdesigner_toolwindow.h | 63 + src/designer/formdesigner/qdesigner_widgetbox.cpp | 77 + src/designer/formdesigner/qdesigner_widgetbox.h | 42 + src/designer/formdesigner/qdesigner_workbench.cpp | 881 ++++++++ src/designer/formdesigner/qdesigner_workbench.h | 181 ++ src/designer/formdesigner/qrc_designer.cpp | 1198 +++++++++++ src/designer/formdesigner/qtdesigner.pri | 44 + src/designer/formdesigner/qtdesigner.pro | 15 + src/designer/formdesigner/saveformastemplate.cpp | 128 ++ src/designer/formdesigner/saveformastemplate.h | 50 + src/designer/formdesigner/saveformastemplate.ui | 248 +++ .../templates/forms/Dialog_with_Buttons_Bottom.ui | 100 + .../templates/forms/Dialog_with_Buttons_Right.ui | 100 + .../formdesigner/templates/forms/Main_Window.ui | 27 + .../formdesigner/templates/forms/Widget.ui | 24 + src/designer/images/a-system.png | Bin 0 -> 1283 bytes src/designer/images/action_g.png | Bin 0 -> 576 bytes src/designer/images/actions.png | Bin 0 -> 271 bytes src/designer/images/arrow_down.png | Bin 0 -> 595 bytes src/designer/images/arrow_left.png | Bin 0 -> 693 bytes src/designer/images/arrow_right.png | Bin 0 -> 667 bytes src/designer/images/arrow_up.png | Bin 0 -> 707 bytes src/designer/images/cat.png | Bin 0 -> 401 bytes src/designer/images/cat_g.png | Bin 0 -> 697 bytes src/designer/images/columns.png | Bin 0 -> 208 bytes src/designer/images/d_editdelete.png | Bin 0 -> 1297 bytes src/designer/images/designer-splash-en.png | Bin 0 -> 94291 bytes src/designer/images/designer-splash-ru.png | Bin 0 -> 94921 bytes src/designer/images/dimensions.png | Bin 0 -> 208 bytes src/designer/images/doc.png | Bin 0 -> 456 bytes src/designer/images/doc_g.png | Bin 0 -> 748 bytes src/designer/images/doc_h.png | Bin 0 -> 686 bytes src/designer/images/editcopy.png | Bin 0 -> 724 bytes src/designer/images/editcut.png | Bin 0 -> 1011 bytes src/designer/images/editdelete.png | Bin 0 -> 953 bytes src/designer/images/editedit.png | Bin 0 -> 224 bytes src/designer/images/editpaste.png | Bin 0 -> 936 bytes src/designer/images/editrename.png | Bin 0 -> 343 bytes src/designer/images/editsep.png | Bin 0 -> 196 bytes src/designer/images/element.png | Bin 0 -> 208 bytes src/designer/images/field.png | Bin 0 -> 231 bytes src/designer/images/filenew.png | Bin 0 -> 454 bytes src/designer/images/fileopen.png | Bin 0 -> 850 bytes src/designer/images/filesave.png | Bin 0 -> 430 bytes src/designer/images/form.png | Bin 0 -> 477 bytes src/designer/images/form_g.png | Bin 0 -> 755 bytes src/designer/images/function.png | Bin 0 -> 814 bytes src/designer/images/group.png | Bin 0 -> 208 bytes src/designer/images/help.png | Bin 0 -> 1605 bytes src/designer/images/hi22-action-project_open.png | Bin 0 -> 778 bytes src/designer/images/hi22-action-run.png | Bin 0 -> 810 bytes src/designer/images/information.png | Bin 0 -> 678 bytes src/designer/images/journ.png | Bin 0 -> 403 bytes src/designer/images/journ_g.png | Bin 0 -> 671 bytes src/designer/images/m_menu.png | Bin 0 -> 264 bytes src/designer/images/msg_error.png | Bin 0 -> 964 bytes src/designer/images/msg_fatal.png | Bin 0 -> 964 bytes src/designer/images/msg_info.png | Bin 0 -> 1756 bytes src/designer/images/msg_warning.png | Bin 0 -> 964 bytes src/designer/images/object.png | Bin 0 -> 1208 bytes src/designer/images/p_menus.png | Bin 0 -> 276 bytes src/designer/images/play.png | Bin 0 -> 742 bytes src/designer/images/playprev.png | Bin 0 -> 868 bytes src/designer/images/print.png | Bin 0 -> 801 bytes src/designer/images/project.png | Bin 0 -> 1368 bytes src/designer/images/qsa.png | Bin 0 -> 1235 bytes src/designer/images/redo.png | Bin 0 -> 667 bytes src/designer/images/reg.png | Bin 0 -> 425 bytes src/designer/images/reg_g.png | Bin 0 -> 717 bytes src/designer/images/regs.png | Bin 0 -> 433 bytes src/designer/images/regs_g.png | Bin 0 -> 739 bytes src/designer/images/report.png | Bin 0 -> 636 bytes src/designer/images/report_g.png | Bin 0 -> 835 bytes src/designer/images/resourses.png | Bin 0 -> 208 bytes src/designer/images/script.png | Bin 0 -> 951 bytes src/designer/images/scriptnew.png | Bin 0 -> 1013 bytes src/designer/images/scriptobject.png | Bin 0 -> 1096 bytes src/designer/images/searchfind.png | Bin 0 -> 909 bytes src/designer/images/separator.png | Bin 0 -> 157 bytes src/designer/images/submenu.png | Bin 0 -> 292 bytes src/designer/images/table.png | Bin 0 -> 258 bytes src/designer/images/table_g.png | Bin 0 -> 569 bytes src/designer/images/toolbar.png | Bin 0 -> 234 bytes src/designer/images/undo.png | Bin 0 -> 457 bytes src/designer/images/webform.png | Bin 0 -> 550 bytes src/designer/images/webform_g.png | Bin 0 -> 756 bytes src/designer/interfacetree.cpp | 359 ++++ src/designer/interfacetree.h | 74 + src/designer/main.cpp | 195 ++ src/designer/mainform.cpp | 496 +++++ src/designer/mainform.h | 80 + src/designer/mainform.ui | 1391 ++++++++++++ src/designer/mdtree.cpp | 1190 +++++++++++ src/designer/mdtree.h | 115 + src/designer/pixmappreview.h | 51 + src/designer/roleeditor.cpp | 135 ++ src/designer/roleeditor.h | 55 + src/designer/templates/inputform.tpl | 22 + src/designer/templates/inputform.ui.tpl | 22 + src/designer/templates/inputformcat.tpl | 30 + src/designer/templates/inputformcat.ui.tpl | 31 + src/designer/templates/inputformdoc.tpl | 30 + src/designer/templates/inputformdoc.ui.tpl | 31 + src/designer/templates/inputformjourn.tpl | 30 + src/designer/templates/inputformjourn.ui.tpl | 31 + src/designer/templates/inputformrep.tpl | 30 + src/designer/templates/inputformrep.ui.tpl | 31 + src/extensions/README | 44 + src/extensions/example/aextexample.cpp | 62 + src/extensions/example/aextexample.h | 64 + src/extensions/example/example.pro | 17 + src/extensions/extensions.pro | 6 + src/extensions/meta/aext_meta.cpp | 217 ++ src/extensions/meta/aext_meta.h | 77 + src/extensions/meta/meta.pro | 16 + src/extensions/te/README | 55 + src/extensions/te/aextte.cpp | 99 + src/extensions/te/aextte.h | 71 + src/extensions/te/te.pro | 27 + src/extensions/text/aexttext.cpp | 203 ++ src/extensions/text/aexttext.h | 72 + src/extensions/text/text.pro | 17 + src/extensions/xml/aextxml.cpp | 425 ++++ src/extensions/xml/aextxml.h | 83 + src/extensions/xml/xml.pro | 23 + src/lib/acfg.cpp | 1818 ++++++++++++++++ src/lib/acfg.h | 495 +++++ src/lib/acfgrc.cpp | 266 +++ src/lib/acfgrc.h | 72 + src/lib/acmanifest.cpp | 247 +++ src/lib/acmanifest.h | 98 + src/lib/acontainer.cpp | 402 ++++ src/lib/acontainer.h | 93 + src/lib/adataexchange.cpp | 631 ++++++ src/lib/adataexchange.h | 84 + src/lib/adatafield.cpp | 213 ++ src/lib/adatafield.h | 106 + src/lib/aextension.cpp | 50 + src/lib/aextension.h | 61 + src/lib/aextensionfactory.cpp | 136 ++ src/lib/aextensionfactory.h | 64 + src/lib/aextensioninterface_p.h | 52 + src/lib/aextensionplugin.cpp | 126 ++ src/lib/aextensionplugin.h | 139 ++ src/lib/afilter.cpp | 219 ++ src/lib/afilter.h | 81 + src/lib/alog.cpp | 169 ++ src/lib/alog.h | 98 + src/lib/amenubar.cpp | 183 ++ src/lib/amenubar.h | 82 + src/lib/amoney.cpp | 604 ++++++ src/lib/amoney.h | 110 + src/lib/ananas.cpp | 160 ++ src/lib/ananas.h | 131 ++ src/lib/ananasglobal.h | 87 + src/lib/arole.cpp | 423 ++++ src/lib/arole.h | 101 + src/lib/aservice.cpp | 547 +++++ src/lib/aservice.h | 86 + src/lib/asqlfield.cpp | 155 ++ src/lib/asqlfield.h | 85 + src/lib/asqltable.cpp | 1111 ++++++++++ src/lib/asqltable.h | 139 ++ src/lib/atests.cpp | 239 +++ src/lib/atests.h | 62 + src/lib/atime.cpp | 119 ++ src/lib/atime.h | 64 + src/lib/auser.cpp | 402 ++++ src/lib/auser.h | 95 + src/lib/dialogs/awindowslist.cpp | 176 ++ src/lib/dialogs/awindowslist.h | 69 + src/lib/dialogs/deditrc.cpp | 127 ++ src/lib/dialogs/deditrc.h | 36 + src/lib/dialogs/deditrc.ui | 460 ++++ src/lib/dialogs/dhelpcfgform.cpp | 42 + src/lib/dialogs/dhelpcfgform.h | 22 + src/lib/dialogs/dhelpcfgform.ui | 94 + src/lib/dialogs/dialogs.pri | 24 + src/lib/dialogs/dimportdb.cpp | 64 + src/lib/dialogs/dimportdb.h | 30 + src/lib/dialogs/dlogin.cpp | 52 + src/lib/dialogs/dlogin.h | 26 + src/lib/dialogs/dlogin.ui | 96 + src/lib/dialogs/dselectdb.cpp | 520 +++++ src/lib/dialogs/dselectdb.h | 54 + src/lib/dialogs/dselectdb.ui | 181 ++ src/lib/dialogs/messageswindow.cpp | 140 ++ src/lib/dialogs/messageswindow.h | 67 + src/lib/images/lib_database.png | Bin 0 -> 1039 bytes src/lib/images/lib_dbgroup.png | Bin 0 -> 681 bytes src/lib/images/print.png | Bin 0 -> 801 bytes src/lib/lib.pri | 17 + src/lib/lib.pro | 132 ++ src/lib/lib.qrc | 7 + src/lib/metadata/ametadata.cpp | 117 + src/lib/metadata/ametadata.h | 105 + src/lib/metadata/ametadataio.cpp | 77 + src/lib/metadata/ametadataio.h | 51 + src/lib/metadata/ametadataioxml.cpp | 373 ++++ src/lib/metadata/ametadataioxml.h | 50 + src/lib/metadata/ametadocument.cpp | 61 + src/lib/metadata/ametadocument.h | 56 + src/lib/metadata/ametafield.cpp | 176 ++ src/lib/metadata/ametafield.h | 95 + src/lib/metadata/ametaform.cpp | 40 + src/lib/metadata/ametaform.h | 45 + src/lib/metadata/ametaobject.cpp | 386 ++++ src/lib/metadata/ametaobject.h | 162 ++ src/lib/metadata/ametaobjectgroup.cpp | 220 ++ src/lib/metadata/ametaobjectgroup.h | 185 ++ src/lib/metadata/metadata.pri | 19 + src/lib/objects/aaregister.cpp | 585 +++++ src/lib/objects/aaregister.h | 104 + src/lib/objects/acatalogue.cpp | 1146 ++++++++++ src/lib/objects/acatalogue.h | 175 ++ src/lib/objects/adocjournal.cpp | 726 +++++++ src/lib/objects/adocjournal.h | 110 + src/lib/objects/adocument.cpp | 1522 ++++++++++++++ src/lib/objects/adocument.h | 140 ++ src/lib/objects/airegister.cpp | 554 +++++ src/lib/objects/airegister.h | 93 + src/lib/objects/aobject.cpp | 1136 ++++++++++ src/lib/objects/aobject.h | 170 ++ src/lib/objects/aobjectlist.cpp | 548 +++++ src/lib/objects/aobjectlist.h | 112 + src/lib/objects/objects.pri | 17 + src/lib/rclistviewitem.cpp | 69 + src/lib/rclistviewitem.h | 71 + src/lib/report/acalctemplate.cpp | 151 ++ src/lib/report/acalctemplate.h | 58 + src/lib/report/aootemplate.cpp | 645 ++++++ src/lib/report/aootemplate.h | 146 ++ src/lib/report/areport.cpp | 574 +++++ src/lib/report/areport.h | 121 ++ src/lib/report/atemplate.cpp | 208 ++ src/lib/report/atemplate.h | 134 ++ src/lib/report/itemplate.cpp | 108 + src/lib/report/itemplate.h | 184 ++ src/lib/report/report.pri | 13 + src/lib/sys/aapplication.cpp | 46 + src/lib/sys/aapplication.h | 55 + src/lib/sys/adatabase.cpp | 1668 +++++++++++++++ src/lib/sys/adatabase.h | 208 ++ src/lib/sys/sys.pri | 7 + src/lib/widgets/awidget.cpp | 1108 ++++++++++ src/lib/widgets/awidget.h | 156 ++ src/lib/widgets/widgets.pri | 5 + src/plugins/README | 69 + src/plugins/actionbutton/actionbutton.pri | 15 + src/plugins/actionbutton/eactionbutton.cpp | 138 ++ src/plugins/actionbutton/eactionbutton.h | 34 + src/plugins/actionbutton/eactionbutton.ui | 206 ++ src/plugins/actionbutton/wactionbutton.cpp | 106 + src/plugins/actionbutton/wactionbutton.h | 90 + src/plugins/actionbutton/wactionbutton_plugin.cpp | 100 + src/plugins/actionbutton/wactionbutton_plugin.h | 53 + .../actionbutton/wactionbutton_taskmenu.cpp | 75 + src/plugins/actionbutton/wactionbutton_taskmenu.h | 57 + src/plugins/aform.cpp | 1896 +++++++++++++++++ src/plugins/aform.h | 207 ++ src/plugins/atoolbar.cpp | 91 + src/plugins/atoolbar.h | 61 + src/plugins/awidgets_plugin.cpp | 58 + src/plugins/awidgets_plugin.h | 44 + src/plugins/catalogue/catalogform.cpp | 986 +++++++++ src/plugins/catalogue/catalogform.h | 84 + src/plugins/catalogue/catalogform.ui | 50 + src/plugins/catalogue/catalogformwidgets.cpp | 435 ++++ src/plugins/catalogue/catalogformwidgets.h | 154 ++ src/plugins/catalogue/catalogue.pri | 19 + src/plugins/catalogue/ecatalogue.cpp | 203 ++ src/plugins/catalogue/ecatalogue.h | 27 + src/plugins/catalogue/ecatalogue.ui | 116 + src/plugins/catalogue/wcatalogue.cpp | 443 ++++ src/plugins/catalogue/wcatalogue.h | 79 + src/plugins/catalogue/wcatalogue_plugin.cpp | 100 + src/plugins/catalogue/wcatalogue_plugin.h | 53 + src/plugins/catalogue/wcatalogue_taskmenu.cpp | 74 + src/plugins/catalogue/wcatalogue_taskmenu.h | 57 + src/plugins/combobox/acombobox.cpp | 272 +++ src/plugins/combobox/acombobox.h | 140 ++ src/plugins/combobox/acombobox_plugin.cpp | 91 + src/plugins/combobox/acombobox_plugin.h | 53 + src/plugins/combobox/combobox.pri | 7 + src/plugins/dbfield/dbfield.pri | 15 + src/plugins/dbfield/edbfield.cpp | 137 ++ src/plugins/dbfield/edbfield.h | 36 + src/plugins/dbfield/edbfield.ui | 134 ++ src/plugins/dbfield/wdbfield.cpp | 423 ++++ src/plugins/dbfield/wdbfield.h | 98 + src/plugins/dbfield/wdbfield_plugin.cpp | 104 + src/plugins/dbfield/wdbfield_plugin.h | 53 + src/plugins/dbfield/wdbfield_taskmenu.cpp | 74 + src/plugins/dbfield/wdbfield_taskmenu.h | 57 + src/plugins/dbtable/dbtable.pri | 15 + src/plugins/dbtable/edbtable.cpp | 521 +++++ src/plugins/dbtable/edbtable.h | 48 + src/plugins/dbtable/edbtable.ui | 448 ++++ src/plugins/dbtable/wdbtable.cpp | 1901 +++++++++++++++++ src/plugins/dbtable/wdbtable.h | 323 +++ src/plugins/dbtable/wdbtable_plugin.cpp | 100 + src/plugins/dbtable/wdbtable_plugin.h | 53 + src/plugins/dbtable/wdbtable_taskmenu.cpp | 76 + src/plugins/dbtable/wdbtable_taskmenu.h | 57 + src/plugins/document/document.pri | 19 + src/plugins/document/edocument.cpp | 153 ++ src/plugins/document/edocument.h | 27 + src/plugins/document/edocument.ui | 116 + src/plugins/document/eselectdoctype.cpp | 77 + src/plugins/document/eselectdoctype.h | 28 + src/plugins/document/eselectdoctype.ui | 102 + src/plugins/document/wdocument.cpp | 420 ++++ src/plugins/document/wdocument.h | 83 + src/plugins/document/wdocument_plugin.cpp | 100 + src/plugins/document/wdocument_plugin.h | 53 + src/plugins/document/wdocument_taskmenu.cpp | 74 + src/plugins/document/wdocument_taskmenu.h | 57 + src/plugins/eaddobj.cpp | 48 + src/plugins/eaddobj.h | 24 + src/plugins/eaddobj.ui | 39 + src/plugins/engine.cpp | 874 ++++++++ src/plugins/engine.h | 198 ++ src/plugins/field/addfdialog.cpp | 126 ++ src/plugins/field/addfdialog.h | 36 + src/plugins/field/addfdialog.ui | 83 + src/plugins/field/efield.cpp | 168 ++ src/plugins/field/efield.h | 32 + src/plugins/field/efield.ui | 212 ++ src/plugins/field/field.pri | 22 + src/plugins/field/wcatalogeditor.cpp | 411 ++++ src/plugins/field/wcatalogeditor.h | 93 + src/plugins/field/wdateedit.cpp | 77 + src/plugins/field/wdateedit.h | 78 + src/plugins/field/wfield.cpp | 720 +++++++ src/plugins/field/wfield.h | 149 ++ src/plugins/field/wfield_plugin.cpp | 101 + src/plugins/field/wfield_plugin.h | 53 + src/plugins/field/wfield_taskmenu.cpp | 74 + src/plugins/field/wfield_taskmenu.h | 57 + src/plugins/grouptree/grouptree.pri | 7 + src/plugins/grouptree/wgrouptree.cpp | 416 ++++ src/plugins/grouptree/wgrouptree.h | 95 + src/plugins/grouptree/wgrouptree_plugin.cpp | 91 + src/plugins/grouptree/wgrouptree_plugin.h | 53 + src/plugins/images/acombobox.png | Bin 0 -> 549 bytes src/plugins/images/doc_copy.png | Bin 0 -> 724 bytes src/plugins/images/doc_delete.png | Bin 0 -> 742 bytes src/plugins/images/doc_edit.png | Bin 0 -> 939 bytes src/plugins/images/doc_new.png | Bin 0 -> 950 bytes src/plugins/images/doc_view.png | Bin 0 -> 1043 bytes src/plugins/images/wactionbutton.png | Bin 0 -> 543 bytes src/plugins/images/wcatalogue.png | Bin 0 -> 570 bytes src/plugins/images/wdbfield.png | Bin 0 -> 339 bytes src/plugins/images/wdbtable.png | Bin 0 -> 691 bytes src/plugins/images/wdocument.png | Bin 0 -> 456 bytes src/plugins/images/wfield.png | Bin 0 -> 301 bytes src/plugins/images/wgrouptree.png | Bin 0 -> 570 bytes src/plugins/images/wjournal.png | Bin 0 -> 403 bytes src/plugins/images/wreport.png | Bin 0 -> 636 bytes src/plugins/images/wtable.png | Bin 0 -> 691 bytes src/plugins/journal/ejournal.cpp | 201 ++ src/plugins/journal/ejournal.h | 27 + src/plugins/journal/ejournal.ui | 116 + src/plugins/journal/journal.pri | 15 + src/plugins/journal/wjournal.cpp | 351 +++ src/plugins/journal/wjournal.h | 92 + src/plugins/journal/wjournal_plugin.cpp | 100 + src/plugins/journal/wjournal_plugin.h | 53 + src/plugins/journal/wjournal_taskmenu.cpp | 74 + src/plugins/journal/wjournal_taskmenu.h | 57 + src/plugins/plugins.pri | 12 + src/plugins/plugins.pro | 84 + src/plugins/plugins.qrc | 20 + src/plugins/qwidgetplugin.h | 54 + src/plugins/report/ereport.cpp | 201 ++ src/plugins/report/ereport.h | 27 + src/plugins/report/ereport.ui | 116 + src/plugins/report/report.pri | 14 + src/plugins/report/wreport.cpp | 145 ++ src/plugins/report/wreport.h | 68 + src/plugins/report/wreport_plugin.cpp | 100 + src/plugins/report/wreport_plugin.h | 53 + src/plugins/report/wreport_taskmenu.cpp | 74 + src/plugins/report/wreport_taskmenu.h | 57 + src/plugins/table/etable.cpp | 288 +++ src/plugins/table/etable.h | 38 + src/plugins/table/etable.ui | 297 +++ src/plugins/table/table.pri | 13 + src/plugins/table/wtable.cpp | 216 ++ src/plugins/table/wtable.h | 115 + src/plugins/table/wtable_plugin.cpp | 91 + src/plugins/table/wtable_plugin.h | 53 + src/src.pro | 8 + src/test/main.cpp | 47 + src/test/test.h | 45 + src/test/test.pro | 20 + src/test/testametadata.cpp | 176 ++ src/test/testametadata.h | 56 + translations/ananas-designer-en.ts | 2061 ++++++++++++++++++ translations/ananas-designer-ru.ts | 2224 ++++++++++++++++++++ translations/ananas-engine-en.ts | 48 + translations/ananas-engine-ru.ts | 105 + translations/ananas-lib-en.ts | 1518 +++++++++++++ translations/ananas-lib-ru.ts | 1608 ++++++++++++++ translations/ananas-plugins-en.ts | 964 +++++++++ translations/ananas-plugins-ru.ts | 1153 ++++++++++ 630 files changed, 89883 insertions(+), 0 deletions(-) create mode 100644 Makefile create mode 100644 README create mode 100644 VERSION create mode 100644 applications/ananas-cfg.dtd create mode 100644 applications/money/money.cfg create mode 100644 applications/money/money.rc create mode 100644 build/altlinux/altlinux.spec create mode 100644 build/fedora/fedora.spec create mode 100644 build/icons/a-system.ico create mode 100644 build/icons/a-system.png create mode 100644 build/icons/ananas-16x16.png create mode 100644 build/icons/ananas-32x32.png create mode 100644 build/icons/ananas-designer.ico create mode 100644 build/icons/ananas-designer.png create mode 100644 build/icons/manual.ico create mode 100644 build/mandriva/mandriva.spec create mode 100644 build/menus/kde/README create mode 100644 build/menus/kde/ananas create mode 100644 build/menus/kde/ananas-designer create mode 100644 build/menus/kde/ananas-designer.desktop create mode 100644 build/menus/kde/ananas.desktop create mode 100644 build/win32/AnanasInstall.iss create mode 100644 build/win32/AnanasUpgrade.iss create mode 100644 build/win32/setuplogo.bmp create mode 100644 icons/a-system.ico create mode 100644 icons/a-system.png create mode 100644 icons/ananas-16x16.png create mode 100644 icons/ananas-32x32.png create mode 100644 icons/ananas-designer.ico create mode 100644 icons/ananas_splach.cdr create mode 100644 icons/lit.png create mode 100644 icons/manual.ico create mode 100644 src/admin/admin.pro create mode 100644 src/admin/admin.qrc create mode 100644 src/admin/atreeitems.cpp create mode 100644 src/admin/atreeitems.h create mode 100644 src/admin/deditpermissions.cpp create mode 100644 src/admin/deditpermissions.h create mode 100644 src/admin/deditpermissions.ui create mode 100644 src/admin/deditrole.cpp create mode 100644 src/admin/deditrole.h create mode 100644 src/admin/deditrole.ui create mode 100644 src/admin/dedituser.cpp create mode 100644 src/admin/dedituser.h create mode 100644 src/admin/dedituser.ui create mode 100644 src/admin/dselectrole.cpp create mode 100644 src/admin/dselectrole.h create mode 100644 src/admin/dselectrole.ui create mode 100644 src/admin/dselectuser.cpp create mode 100644 src/admin/dselectuser.h create mode 100644 src/admin/dselectuser.ui create mode 100644 src/admin/images/administrator-splash-en.png create mode 100644 src/admin/images/administrator-splash-ru.png create mode 100644 src/admin/images/cat.png create mode 100644 src/admin/images/cat_g.png create mode 100644 src/admin/images/doc.png create mode 100644 src/admin/images/doc_g.png create mode 100644 src/admin/images/journ.png create mode 100644 src/admin/images/journ_g.png create mode 100644 src/admin/images/metadata.png create mode 100644 src/admin/images/reg.png create mode 100644 src/admin/images/reg_g.png create mode 100644 src/admin/images/regs.png create mode 100644 src/admin/images/report.png create mode 100644 src/admin/images/report_g.png create mode 100644 src/admin/images/role.png create mode 100644 src/admin/images/user.png create mode 100644 src/admin/images/users.png create mode 100644 src/admin/main.cpp create mode 100644 src/admin/mainform.cpp create mode 100644 src/admin/mainform.h create mode 100644 src/admin/mainform.ui create mode 100644 src/admin/mdtree.cpp create mode 100644 src/admin/mdtree.h create mode 100644 src/admin/rolesform.cpp create mode 100644 src/admin/rolesform.h create mode 100644 src/admin/rolesform.ui create mode 100644 src/admin/usersform.cpp create mode 100644 src/admin/usersform.h create mode 100644 src/admin/usersform.ui create mode 100644 src/ananas.pri create mode 100644 src/ananas/ananas.pro create mode 100644 src/ananas/ananas.qrc create mode 100644 src/ananas/bkground.jpg create mode 100644 src/ananas/images/a-system.png create mode 100644 src/ananas/images/cat.png create mode 100644 src/ananas/images/d_document_turned.png create mode 100644 src/ananas/images/document_turned.png create mode 100644 src/ananas/images/editdelete.png create mode 100644 src/ananas/images/editdelete2.png create mode 100644 src/ananas/images/engine-splash-en.png create mode 100644 src/ananas/images/engine-splash-ru.png create mode 100644 src/ananas/images/field.png create mode 100644 src/ananas/images/field2.png create mode 100644 src/ananas/images/group.png create mode 100644 src/ananas/images/group2.png create mode 100644 src/ananas/images/lib_database.png create mode 100644 src/ananas/images/lib_dbgroup.png create mode 100644 src/ananas/images/msg_error.png create mode 100644 src/ananas/images/msg_fatal.png create mode 100644 src/ananas/images/msg_info.png create mode 100644 src/ananas/images/msg_warning.png create mode 100644 src/ananas/images/object_markdeleted.png create mode 100644 src/ananas/images/t_cat_e.png create mode 100644 src/ananas/images/t_cat_ed.png create mode 100644 src/ananas/images/t_cat_g.png create mode 100644 src/ananas/images/t_cat_gd.png create mode 100644 src/ananas/images/t_doc.png create mode 100644 src/ananas/images/t_doc_d.png create mode 100644 src/ananas/images/t_doc_m.png create mode 100644 src/ananas/images/t_doc_t.png create mode 100644 src/ananas/images/t_doc_tm.png create mode 100644 src/ananas/images/t_doc_to.png create mode 100644 src/ananas/images/t_doc_tom.png create mode 100644 src/ananas/main.cpp create mode 100644 src/ananas/mainform.cpp create mode 100644 src/ananas/mainform.h create mode 100644 src/ananas/report.sxw create mode 100644 src/ananas/report.tpl create mode 100644 src/designer/actiontree.cpp create mode 100644 src/designer/actiontree.h create mode 100644 src/designer/aliaseditor.cpp create mode 100644 src/designer/aliaseditor.h create mode 100644 src/designer/atreeitems.cpp create mode 100644 src/designer/atreeitems.h create mode 100644 src/designer/cfgform.cpp create mode 100644 src/designer/cfgform.h create mode 100644 src/designer/cfgform.ui create mode 100644 src/designer/deditaction.cpp create mode 100644 src/designer/deditaction.h create mode 100644 src/designer/deditaction.ui create mode 100644 src/designer/deditareg.cpp create mode 100644 src/designer/deditareg.h create mode 100644 src/designer/deditareg.ui create mode 100644 src/designer/deditcat.cpp create mode 100644 src/designer/deditcat.h create mode 100644 src/designer/deditcat.ui create mode 100644 src/designer/deditcfg.cpp create mode 100644 src/designer/deditcfg.h create mode 100644 src/designer/deditcfg.ui create mode 100644 src/designer/deditcolumns.cpp create mode 100644 src/designer/deditcolumns.h create mode 100644 src/designer/deditcolumns.ui create mode 100644 src/designer/deditcommand.cpp create mode 100644 src/designer/deditcommand.h create mode 100644 src/designer/deditcommand.ui create mode 100644 src/designer/deditdialog.cpp create mode 100644 src/designer/deditdialog.h create mode 100644 src/designer/deditdialog.ui create mode 100644 src/designer/deditdoc.cpp create mode 100644 src/designer/deditdoc.h create mode 100644 src/designer/deditdoc.ui create mode 100644 src/designer/deditfield.cpp create mode 100644 src/designer/deditfield.h create mode 100644 src/designer/deditfield.ui create mode 100644 src/designer/deditimagecollection.cpp create mode 100644 src/designer/deditimagecollection.h create mode 100644 src/designer/deditimagecollection.ui create mode 100644 src/designer/deditireg.cpp create mode 100644 src/designer/deditireg.h create mode 100644 src/designer/deditireg.ui create mode 100644 src/designer/deditjournal.cpp create mode 100644 src/designer/deditjournal.h create mode 100644 src/designer/deditjournal.ui create mode 100644 src/designer/deditlang.cpp create mode 100644 src/designer/deditlang.h create mode 100644 src/designer/deditlang.ui create mode 100644 src/designer/deditreport.cpp create mode 100644 src/designer/deditreport.h create mode 100644 src/designer/deditreport.ui create mode 100644 src/designer/deditrole.cpp create mode 100644 src/designer/deditrole.h create mode 100644 src/designer/deditrole.ui create mode 100644 src/designer/dedittoolbar.cpp create mode 100644 src/designer/dedittoolbar.h create mode 100644 src/designer/dedittoolbar.ui create mode 100644 src/designer/deditwebform.cpp create mode 100644 src/designer/deditwebform.h create mode 100644 src/designer/deditwebform.ui create mode 100644 src/designer/designer.pro create mode 100644 src/designer/designer.qrc create mode 100644 src/designer/embed.cpp create mode 100644 src/designer/embed.h create mode 100644 src/designer/formdesigner.cpp create mode 100644 src/designer/formdesigner.h create mode 100644 src/designer/formdesigner/designer.qrc create mode 100644 src/designer/formdesigner/formwindowsettings.cpp create mode 100644 src/designer/formdesigner/formwindowsettings.h create mode 100644 src/designer/formdesigner/formwindowsettings.ui create mode 100644 src/designer/formdesigner/images/designer.png create mode 100644 src/designer/formdesigner/images/mdi.png create mode 100644 src/designer/formdesigner/images/sdi.png create mode 100644 src/designer/formdesigner/images/workbench.png create mode 100644 src/designer/formdesigner/newform.cpp create mode 100644 src/designer/formdesigner/newform.h create mode 100644 src/designer/formdesigner/newform.ui create mode 100644 src/designer/formdesigner/plugindialog.cpp create mode 100644 src/designer/formdesigner/plugindialog.h create mode 100644 src/designer/formdesigner/plugindialog.ui create mode 100644 src/designer/formdesigner/private/formscriptrunner_p.h create mode 100644 src/designer/formdesigner/private/pluginmanager_p.h create mode 100644 src/designer/formdesigner/private/qdesigner_formbuilder_p.h create mode 100644 src/designer/formdesigner/private/qdesigner_integration_p.h create mode 100644 src/designer/formdesigner/private/qtundo_p.h create mode 100644 src/designer/formdesigner/private/shared_global_p.h create mode 100644 src/designer/formdesigner/private/sheet_delegate_p.h create mode 100644 src/designer/formdesigner/qdesigner_actioneditor.cpp create mode 100644 src/designer/formdesigner/qdesigner_actioneditor.h create mode 100644 src/designer/formdesigner/qdesigner_actions.cpp create mode 100644 src/designer/formdesigner/qdesigner_actions.h create mode 100644 src/designer/formdesigner/qdesigner_formwindow.cpp create mode 100644 src/designer/formdesigner/qdesigner_formwindow.h create mode 100644 src/designer/formdesigner/qdesigner_objectinspector.cpp create mode 100644 src/designer/formdesigner/qdesigner_objectinspector.h create mode 100644 src/designer/formdesigner/qdesigner_pch.h create mode 100644 src/designer/formdesigner/qdesigner_propertyeditor.cpp create mode 100644 src/designer/formdesigner/qdesigner_propertyeditor.h create mode 100644 src/designer/formdesigner/qdesigner_resourceeditor.cpp create mode 100644 src/designer/formdesigner/qdesigner_resourceeditor.h create mode 100644 src/designer/formdesigner/qdesigner_settings.cpp create mode 100644 src/designer/formdesigner/qdesigner_settings.h create mode 100644 src/designer/formdesigner/qdesigner_signalsloteditor.cpp create mode 100644 src/designer/formdesigner/qdesigner_signalsloteditor.h create mode 100644 src/designer/formdesigner/qdesigner_toolwindow.cpp create mode 100644 src/designer/formdesigner/qdesigner_toolwindow.h create mode 100644 src/designer/formdesigner/qdesigner_widgetbox.cpp create mode 100644 src/designer/formdesigner/qdesigner_widgetbox.h create mode 100644 src/designer/formdesigner/qdesigner_workbench.cpp create mode 100644 src/designer/formdesigner/qdesigner_workbench.h create mode 100644 src/designer/formdesigner/qrc_designer.cpp create mode 100644 src/designer/formdesigner/qtdesigner.pri create mode 100644 src/designer/formdesigner/qtdesigner.pro create mode 100644 src/designer/formdesigner/saveformastemplate.cpp create mode 100644 src/designer/formdesigner/saveformastemplate.h create mode 100644 src/designer/formdesigner/saveformastemplate.ui create mode 100644 src/designer/formdesigner/templates/forms/Dialog_with_Buttons_Bottom.ui create mode 100644 src/designer/formdesigner/templates/forms/Dialog_with_Buttons_Right.ui create mode 100644 src/designer/formdesigner/templates/forms/Main_Window.ui create mode 100644 src/designer/formdesigner/templates/forms/Widget.ui create mode 100644 src/designer/images/a-system.png create mode 100644 src/designer/images/action_g.png create mode 100644 src/designer/images/actions.png create mode 100644 src/designer/images/arrow_down.png create mode 100644 src/designer/images/arrow_left.png create mode 100644 src/designer/images/arrow_right.png create mode 100644 src/designer/images/arrow_up.png create mode 100644 src/designer/images/cat.png create mode 100644 src/designer/images/cat_g.png create mode 100644 src/designer/images/columns.png create mode 100644 src/designer/images/d_editdelete.png create mode 100644 src/designer/images/designer-splash-en.png create mode 100644 src/designer/images/designer-splash-ru.png create mode 100644 src/designer/images/dimensions.png create mode 100644 src/designer/images/doc.png create mode 100644 src/designer/images/doc_g.png create mode 100644 src/designer/images/doc_h.png create mode 100644 src/designer/images/editcopy.png create mode 100644 src/designer/images/editcut.png create mode 100644 src/designer/images/editdelete.png create mode 100644 src/designer/images/editedit.png create mode 100644 src/designer/images/editpaste.png create mode 100644 src/designer/images/editrename.png create mode 100644 src/designer/images/editsep.png create mode 100644 src/designer/images/element.png create mode 100644 src/designer/images/field.png create mode 100644 src/designer/images/filenew.png create mode 100644 src/designer/images/fileopen.png create mode 100644 src/designer/images/filesave.png create mode 100644 src/designer/images/form.png create mode 100644 src/designer/images/form_g.png create mode 100644 src/designer/images/function.png create mode 100644 src/designer/images/group.png create mode 100644 src/designer/images/help.png create mode 100644 src/designer/images/hi22-action-project_open.png create mode 100644 src/designer/images/hi22-action-run.png create mode 100644 src/designer/images/information.png create mode 100644 src/designer/images/journ.png create mode 100644 src/designer/images/journ_g.png create mode 100644 src/designer/images/m_menu.png create mode 100644 src/designer/images/msg_error.png create mode 100644 src/designer/images/msg_fatal.png create mode 100644 src/designer/images/msg_info.png create mode 100644 src/designer/images/msg_warning.png create mode 100644 src/designer/images/object.png create mode 100644 src/designer/images/p_menus.png create mode 100644 src/designer/images/play.png create mode 100644 src/designer/images/playprev.png create mode 100644 src/designer/images/print.png create mode 100644 src/designer/images/project.png create mode 100644 src/designer/images/qsa.png create mode 100644 src/designer/images/redo.png create mode 100644 src/designer/images/reg.png create mode 100644 src/designer/images/reg_g.png create mode 100644 src/designer/images/regs.png create mode 100644 src/designer/images/regs_g.png create mode 100644 src/designer/images/report.png create mode 100644 src/designer/images/report_g.png create mode 100644 src/designer/images/resourses.png create mode 100644 src/designer/images/script.png create mode 100644 src/designer/images/scriptnew.png create mode 100644 src/designer/images/scriptobject.png create mode 100644 src/designer/images/searchfind.png create mode 100644 src/designer/images/separator.png create mode 100644 src/designer/images/submenu.png create mode 100644 src/designer/images/table.png create mode 100644 src/designer/images/table_g.png create mode 100644 src/designer/images/toolbar.png create mode 100644 src/designer/images/undo.png create mode 100644 src/designer/images/webform.png create mode 100644 src/designer/images/webform_g.png create mode 100644 src/designer/interfacetree.cpp create mode 100644 src/designer/interfacetree.h create mode 100644 src/designer/main.cpp create mode 100644 src/designer/mainform.cpp create mode 100644 src/designer/mainform.h create mode 100644 src/designer/mainform.ui create mode 100644 src/designer/mdtree.cpp create mode 100644 src/designer/mdtree.h create mode 100644 src/designer/pixmappreview.h create mode 100644 src/designer/roleeditor.cpp create mode 100644 src/designer/roleeditor.h create mode 100644 src/designer/templates/inputform.tpl create mode 100644 src/designer/templates/inputform.ui.tpl create mode 100644 src/designer/templates/inputformcat.tpl create mode 100644 src/designer/templates/inputformcat.ui.tpl create mode 100644 src/designer/templates/inputformdoc.tpl create mode 100644 src/designer/templates/inputformdoc.ui.tpl create mode 100644 src/designer/templates/inputformjourn.tpl create mode 100644 src/designer/templates/inputformjourn.ui.tpl create mode 100644 src/designer/templates/inputformrep.tpl create mode 100644 src/designer/templates/inputformrep.ui.tpl create mode 100644 src/extensions/README create mode 100644 src/extensions/example/aextexample.cpp create mode 100644 src/extensions/example/aextexample.h create mode 100644 src/extensions/example/example.pro create mode 100644 src/extensions/extensions.pro create mode 100644 src/extensions/meta/aext_meta.cpp create mode 100644 src/extensions/meta/aext_meta.h create mode 100644 src/extensions/meta/meta.pro create mode 100644 src/extensions/te/README create mode 100644 src/extensions/te/aextte.cpp create mode 100644 src/extensions/te/aextte.h create mode 100644 src/extensions/te/te.pro create mode 100644 src/extensions/text/aexttext.cpp create mode 100644 src/extensions/text/aexttext.h create mode 100644 src/extensions/text/text.pro create mode 100644 src/extensions/xml/aextxml.cpp create mode 100644 src/extensions/xml/aextxml.h create mode 100644 src/extensions/xml/xml.pro create mode 100644 src/lib/acfg.cpp create mode 100644 src/lib/acfg.h create mode 100644 src/lib/acfgrc.cpp create mode 100644 src/lib/acfgrc.h create mode 100644 src/lib/acmanifest.cpp create mode 100644 src/lib/acmanifest.h create mode 100644 src/lib/acontainer.cpp create mode 100644 src/lib/acontainer.h create mode 100644 src/lib/adataexchange.cpp create mode 100644 src/lib/adataexchange.h create mode 100644 src/lib/adatafield.cpp create mode 100644 src/lib/adatafield.h create mode 100644 src/lib/aextension.cpp create mode 100644 src/lib/aextension.h create mode 100644 src/lib/aextensionfactory.cpp create mode 100644 src/lib/aextensionfactory.h create mode 100644 src/lib/aextensioninterface_p.h create mode 100644 src/lib/aextensionplugin.cpp create mode 100644 src/lib/aextensionplugin.h create mode 100644 src/lib/afilter.cpp create mode 100644 src/lib/afilter.h create mode 100644 src/lib/alog.cpp create mode 100644 src/lib/alog.h create mode 100644 src/lib/amenubar.cpp create mode 100644 src/lib/amenubar.h create mode 100644 src/lib/amoney.cpp create mode 100644 src/lib/amoney.h create mode 100644 src/lib/ananas.cpp create mode 100644 src/lib/ananas.h create mode 100644 src/lib/ananasglobal.h create mode 100644 src/lib/arole.cpp create mode 100644 src/lib/arole.h create mode 100644 src/lib/aservice.cpp create mode 100644 src/lib/aservice.h create mode 100644 src/lib/asqlfield.cpp create mode 100644 src/lib/asqlfield.h create mode 100644 src/lib/asqltable.cpp create mode 100644 src/lib/asqltable.h create mode 100644 src/lib/atests.cpp create mode 100644 src/lib/atests.h create mode 100644 src/lib/atime.cpp create mode 100644 src/lib/atime.h create mode 100644 src/lib/auser.cpp create mode 100644 src/lib/auser.h create mode 100644 src/lib/dialogs/awindowslist.cpp create mode 100644 src/lib/dialogs/awindowslist.h create mode 100644 src/lib/dialogs/deditrc.cpp create mode 100644 src/lib/dialogs/deditrc.h create mode 100644 src/lib/dialogs/deditrc.ui create mode 100644 src/lib/dialogs/dhelpcfgform.cpp create mode 100644 src/lib/dialogs/dhelpcfgform.h create mode 100644 src/lib/dialogs/dhelpcfgform.ui create mode 100644 src/lib/dialogs/dialogs.pri create mode 100644 src/lib/dialogs/dimportdb.cpp create mode 100644 src/lib/dialogs/dimportdb.h create mode 100644 src/lib/dialogs/dlogin.cpp create mode 100644 src/lib/dialogs/dlogin.h create mode 100644 src/lib/dialogs/dlogin.ui create mode 100644 src/lib/dialogs/dselectdb.cpp create mode 100644 src/lib/dialogs/dselectdb.h create mode 100644 src/lib/dialogs/dselectdb.ui create mode 100644 src/lib/dialogs/messageswindow.cpp create mode 100644 src/lib/dialogs/messageswindow.h create mode 100644 src/lib/images/lib_database.png create mode 100644 src/lib/images/lib_dbgroup.png create mode 100644 src/lib/images/print.png create mode 100644 src/lib/lib.pri create mode 100644 src/lib/lib.pro create mode 100644 src/lib/lib.qrc create mode 100644 src/lib/metadata/ametadata.cpp create mode 100644 src/lib/metadata/ametadata.h create mode 100644 src/lib/metadata/ametadataio.cpp create mode 100644 src/lib/metadata/ametadataio.h create mode 100644 src/lib/metadata/ametadataioxml.cpp create mode 100644 src/lib/metadata/ametadataioxml.h create mode 100644 src/lib/metadata/ametadocument.cpp create mode 100644 src/lib/metadata/ametadocument.h create mode 100644 src/lib/metadata/ametafield.cpp create mode 100644 src/lib/metadata/ametafield.h create mode 100644 src/lib/metadata/ametaform.cpp create mode 100644 src/lib/metadata/ametaform.h create mode 100644 src/lib/metadata/ametaobject.cpp create mode 100644 src/lib/metadata/ametaobject.h create mode 100644 src/lib/metadata/ametaobjectgroup.cpp create mode 100644 src/lib/metadata/ametaobjectgroup.h create mode 100644 src/lib/metadata/metadata.pri create mode 100644 src/lib/objects/aaregister.cpp create mode 100644 src/lib/objects/aaregister.h create mode 100644 src/lib/objects/acatalogue.cpp create mode 100644 src/lib/objects/acatalogue.h create mode 100644 src/lib/objects/adocjournal.cpp create mode 100644 src/lib/objects/adocjournal.h create mode 100644 src/lib/objects/adocument.cpp create mode 100644 src/lib/objects/adocument.h create mode 100644 src/lib/objects/airegister.cpp create mode 100644 src/lib/objects/airegister.h create mode 100644 src/lib/objects/aobject.cpp create mode 100644 src/lib/objects/aobject.h create mode 100644 src/lib/objects/aobjectlist.cpp create mode 100644 src/lib/objects/aobjectlist.h create mode 100644 src/lib/objects/objects.pri create mode 100644 src/lib/rclistviewitem.cpp create mode 100644 src/lib/rclistviewitem.h create mode 100644 src/lib/report/acalctemplate.cpp create mode 100644 src/lib/report/acalctemplate.h create mode 100644 src/lib/report/aootemplate.cpp create mode 100644 src/lib/report/aootemplate.h create mode 100644 src/lib/report/areport.cpp create mode 100644 src/lib/report/areport.h create mode 100644 src/lib/report/atemplate.cpp create mode 100644 src/lib/report/atemplate.h create mode 100644 src/lib/report/itemplate.cpp create mode 100644 src/lib/report/itemplate.h create mode 100644 src/lib/report/report.pri create mode 100644 src/lib/sys/aapplication.cpp create mode 100644 src/lib/sys/aapplication.h create mode 100644 src/lib/sys/adatabase.cpp create mode 100644 src/lib/sys/adatabase.h create mode 100644 src/lib/sys/sys.pri create mode 100644 src/lib/widgets/awidget.cpp create mode 100644 src/lib/widgets/awidget.h create mode 100644 src/lib/widgets/widgets.pri create mode 100644 src/plugins/README create mode 100644 src/plugins/actionbutton/actionbutton.pri create mode 100644 src/plugins/actionbutton/eactionbutton.cpp create mode 100644 src/plugins/actionbutton/eactionbutton.h create mode 100644 src/plugins/actionbutton/eactionbutton.ui create mode 100644 src/plugins/actionbutton/wactionbutton.cpp create mode 100644 src/plugins/actionbutton/wactionbutton.h create mode 100644 src/plugins/actionbutton/wactionbutton_plugin.cpp create mode 100644 src/plugins/actionbutton/wactionbutton_plugin.h create mode 100644 src/plugins/actionbutton/wactionbutton_taskmenu.cpp create mode 100644 src/plugins/actionbutton/wactionbutton_taskmenu.h create mode 100644 src/plugins/aform.cpp create mode 100644 src/plugins/aform.h create mode 100644 src/plugins/atoolbar.cpp create mode 100644 src/plugins/atoolbar.h create mode 100644 src/plugins/awidgets_plugin.cpp create mode 100644 src/plugins/awidgets_plugin.h create mode 100644 src/plugins/catalogue/catalogform.cpp create mode 100644 src/plugins/catalogue/catalogform.h create mode 100644 src/plugins/catalogue/catalogform.ui create mode 100644 src/plugins/catalogue/catalogformwidgets.cpp create mode 100644 src/plugins/catalogue/catalogformwidgets.h create mode 100644 src/plugins/catalogue/catalogue.pri create mode 100644 src/plugins/catalogue/ecatalogue.cpp create mode 100644 src/plugins/catalogue/ecatalogue.h create mode 100644 src/plugins/catalogue/ecatalogue.ui create mode 100644 src/plugins/catalogue/wcatalogue.cpp create mode 100644 src/plugins/catalogue/wcatalogue.h create mode 100644 src/plugins/catalogue/wcatalogue_plugin.cpp create mode 100644 src/plugins/catalogue/wcatalogue_plugin.h create mode 100644 src/plugins/catalogue/wcatalogue_taskmenu.cpp create mode 100644 src/plugins/catalogue/wcatalogue_taskmenu.h create mode 100644 src/plugins/combobox/acombobox.cpp create mode 100644 src/plugins/combobox/acombobox.h create mode 100644 src/plugins/combobox/acombobox_plugin.cpp create mode 100644 src/plugins/combobox/acombobox_plugin.h create mode 100644 src/plugins/combobox/combobox.pri create mode 100644 src/plugins/dbfield/dbfield.pri create mode 100644 src/plugins/dbfield/edbfield.cpp create mode 100644 src/plugins/dbfield/edbfield.h create mode 100644 src/plugins/dbfield/edbfield.ui create mode 100644 src/plugins/dbfield/wdbfield.cpp create mode 100644 src/plugins/dbfield/wdbfield.h create mode 100644 src/plugins/dbfield/wdbfield_plugin.cpp create mode 100644 src/plugins/dbfield/wdbfield_plugin.h create mode 100644 src/plugins/dbfield/wdbfield_taskmenu.cpp create mode 100644 src/plugins/dbfield/wdbfield_taskmenu.h create mode 100644 src/plugins/dbtable/dbtable.pri create mode 100644 src/plugins/dbtable/edbtable.cpp create mode 100644 src/plugins/dbtable/edbtable.h create mode 100644 src/plugins/dbtable/edbtable.ui create mode 100644 src/plugins/dbtable/wdbtable.cpp create mode 100644 src/plugins/dbtable/wdbtable.h create mode 100644 src/plugins/dbtable/wdbtable_plugin.cpp create mode 100644 src/plugins/dbtable/wdbtable_plugin.h create mode 100644 src/plugins/dbtable/wdbtable_taskmenu.cpp create mode 100644 src/plugins/dbtable/wdbtable_taskmenu.h create mode 100644 src/plugins/document/document.pri create mode 100644 src/plugins/document/edocument.cpp create mode 100644 src/plugins/document/edocument.h create mode 100644 src/plugins/document/edocument.ui create mode 100644 src/plugins/document/eselectdoctype.cpp create mode 100644 src/plugins/document/eselectdoctype.h create mode 100644 src/plugins/document/eselectdoctype.ui create mode 100644 src/plugins/document/wdocument.cpp create mode 100644 src/plugins/document/wdocument.h create mode 100644 src/plugins/document/wdocument_plugin.cpp create mode 100644 src/plugins/document/wdocument_plugin.h create mode 100644 src/plugins/document/wdocument_taskmenu.cpp create mode 100644 src/plugins/document/wdocument_taskmenu.h create mode 100644 src/plugins/eaddobj.cpp create mode 100644 src/plugins/eaddobj.h create mode 100644 src/plugins/eaddobj.ui create mode 100644 src/plugins/engine.cpp create mode 100644 src/plugins/engine.h create mode 100644 src/plugins/field/addfdialog.cpp create mode 100644 src/plugins/field/addfdialog.h create mode 100644 src/plugins/field/addfdialog.ui create mode 100644 src/plugins/field/efield.cpp create mode 100644 src/plugins/field/efield.h create mode 100644 src/plugins/field/efield.ui create mode 100644 src/plugins/field/field.pri create mode 100644 src/plugins/field/wcatalogeditor.cpp create mode 100644 src/plugins/field/wcatalogeditor.h create mode 100644 src/plugins/field/wdateedit.cpp create mode 100644 src/plugins/field/wdateedit.h create mode 100644 src/plugins/field/wfield.cpp create mode 100644 src/plugins/field/wfield.h create mode 100644 src/plugins/field/wfield_plugin.cpp create mode 100644 src/plugins/field/wfield_plugin.h create mode 100644 src/plugins/field/wfield_taskmenu.cpp create mode 100644 src/plugins/field/wfield_taskmenu.h create mode 100644 src/plugins/grouptree/grouptree.pri create mode 100644 src/plugins/grouptree/wgrouptree.cpp create mode 100644 src/plugins/grouptree/wgrouptree.h create mode 100644 src/plugins/grouptree/wgrouptree_plugin.cpp create mode 100644 src/plugins/grouptree/wgrouptree_plugin.h create mode 100644 src/plugins/images/acombobox.png create mode 100644 src/plugins/images/doc_copy.png create mode 100644 src/plugins/images/doc_delete.png create mode 100644 src/plugins/images/doc_edit.png create mode 100644 src/plugins/images/doc_new.png create mode 100644 src/plugins/images/doc_view.png create mode 100644 src/plugins/images/wactionbutton.png create mode 100644 src/plugins/images/wcatalogue.png create mode 100644 src/plugins/images/wdbfield.png create mode 100644 src/plugins/images/wdbtable.png create mode 100644 src/plugins/images/wdocument.png create mode 100644 src/plugins/images/wfield.png create mode 100644 src/plugins/images/wgrouptree.png create mode 100644 src/plugins/images/wjournal.png create mode 100644 src/plugins/images/wreport.png create mode 100644 src/plugins/images/wtable.png create mode 100644 src/plugins/journal/ejournal.cpp create mode 100644 src/plugins/journal/ejournal.h create mode 100644 src/plugins/journal/ejournal.ui create mode 100644 src/plugins/journal/journal.pri create mode 100644 src/plugins/journal/wjournal.cpp create mode 100644 src/plugins/journal/wjournal.h create mode 100644 src/plugins/journal/wjournal_plugin.cpp create mode 100644 src/plugins/journal/wjournal_plugin.h create mode 100644 src/plugins/journal/wjournal_taskmenu.cpp create mode 100644 src/plugins/journal/wjournal_taskmenu.h create mode 100644 src/plugins/plugins.pri create mode 100644 src/plugins/plugins.pro create mode 100644 src/plugins/plugins.qrc create mode 100644 src/plugins/qwidgetplugin.h create mode 100644 src/plugins/report/ereport.cpp create mode 100644 src/plugins/report/ereport.h create mode 100644 src/plugins/report/ereport.ui create mode 100644 src/plugins/report/report.pri create mode 100644 src/plugins/report/wreport.cpp create mode 100644 src/plugins/report/wreport.h create mode 100644 src/plugins/report/wreport_plugin.cpp create mode 100644 src/plugins/report/wreport_plugin.h create mode 100644 src/plugins/report/wreport_taskmenu.cpp create mode 100644 src/plugins/report/wreport_taskmenu.h create mode 100644 src/plugins/table/etable.cpp create mode 100644 src/plugins/table/etable.h create mode 100644 src/plugins/table/etable.ui create mode 100644 src/plugins/table/table.pri create mode 100644 src/plugins/table/wtable.cpp create mode 100644 src/plugins/table/wtable.h create mode 100644 src/plugins/table/wtable_plugin.cpp create mode 100644 src/plugins/table/wtable_plugin.h create mode 100644 src/src.pro create mode 100644 src/test/main.cpp create mode 100644 src/test/test.h create mode 100644 src/test/test.pro create mode 100644 src/test/testametadata.cpp create mode 100644 src/test/testametadata.h create mode 100644 translations/ananas-designer-en.ts create mode 100644 translations/ananas-designer-ru.ts create mode 100644 translations/ananas-engine-en.ts create mode 100644 translations/ananas-engine-ru.ts create mode 100644 translations/ananas-lib-en.ts create mode 100644 translations/ananas-lib-ru.ts create mode 100644 translations/ananas-plugins-en.ts create mode 100644 translations/ananas-plugins-ru.ts diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..3376b79 --- /dev/null +++ b/Makefile @@ -0,0 +1,66 @@ +NAME = ananas4 +VERSION = $(shell cat VERSION) +NAMEV = $(NAME)-$(VERSION) +MAKE = make +QMAKE = qmake +MAKEFILE = Makefile +LIBDIR = $(INSTALL_ROOT)/usr/lib +BINDIR = $(INSTALL_ROOT)/usr/bin +DOCDIR = $(INSTALL_ROOT)/usr/share/doc/$(NAMEV) +INCLUDEDIR = $(INSTALL_ROOT)/usr/include/ananas + +log = ~/.ananas/tests.log +#BINDIR = /usr/bin +#MANDIR = /usr/man/man8 +#VARDIR = /usr/share/$(NAME) +TAR = $(HOME)/tmp/$(NAMEV) +TARGET = i586 + + +first: all + +all: Makefile + cd src && $(QMAKE) && $(MAKE) +clean: + rm -fr rpm + rm -f $(NAME).spec + rm -fr *~ + rm -f translations/*.qm + cd src && $(QMAKE) && $(MAKE) clean + +tr: + lrelease translations/*.ts + +install: + find src doc -name Makefile -delete + $(QMAKE) src/src.pro -o src/$(MAKEFILE) + cd src && $(MAKE) install LIBDIR=$(LIBDIR) BINDIR=$(BINDIR) INCLUDEDIR=$(INCLUDEDIR) && cd ../doc && $(QMAKE) doc.pro -o $(MAKEFILE) && $(MAKE) install DOCDIR=$(DOCDIR) + +uninstall: + cd src && $(MAKE) uninstall + +tgz: dummy + mkdir -p rpm + mkdir -p $(TAR) + cp -r -f * $(TAR) +# cd $(TAR) && make clean +# cd $(TAR) && find src doc -name Makefile -delete + cd $(HOME)/tmp && tar cf - "$(NAMEV)/" | bzip2 -f9 > "$(HOME)/RPM/SOURCES/$(NAMEV).tar.bz2" + rm -f -r $(TAR) +srpm: tgz + if [ -e /etc/altlinux-release ] ; then\ + iconv -f UTF-8 -t KOI8-R $(NAME).spec.in |\ + sed s/ru_RU.UTF8/ru_RU.KOI8-R/>$(NAME).spec;\ + else \ + cp $(NAME).spec.in $(NAME).spec; \ + fi + rpmbuild --target=$(TARGET) -bs $(NAME).spec + mv -f $(HOME)/RPM/SRPMS/$(NAME)* rpm +rpm: srpm + rpmbuild --target=$(TARGET) -bb $(NAME).spec + mv -f $(HOME)/RPM/RPMS/$(TARGET)/$(NAME)* rpm + +tests: all + ./tests.begin -log=$(log) + +dummy: diff --git a/README b/README new file mode 100644 index 0000000..1a13849 --- /dev/null +++ b/README @@ -0,0 +1,122 @@ +_Об Ананасе_ + +Ананас - программная платформа автоматизации учета для Linux и Windows. +Ананас является программным обеспечением автоматизации учета, +предназначенным для использования на небольших и средних +предприятиях. Ананас позволяет автоматизировать основные +учетные операции. Ананас умеет работать на операционных +системамах Windows и GNU/Linux. + +Программное обеспечение распространяется на условиях +открытой лицензии, позволяющих копировать Ананас бесплатно +и также бесплатно использовать его для ведения +автоматизированного учета на любом количестве рабочих мест. + +Получить исходники Ананаса можно с сайта http://ananas.lrn.ru +Там же можно скачать rpm для Alt Linux или Fedora Core. + +Ниже описывается процесс сборки из исходных кодов. +Чтобы все собралось, необходимо наличие в системе Qt и QSA (Qt Script for Applications) + +_Компиляция_ + +Сборка стандартная +Распаковываем архив в каталоге /usr/src или в другом каталоге, сделав после +распаковки симлинк в /usr/src, +и переходим в каталог проекта +cd /usr/src/ananas-engine-qt + +Запускаем +make +и, если собралось без ошибок, +make install + +После успешного выполнения компиляции в некоторых подкаталогах появятся +исполняемые файлы готовые к запуску. +Первым делом необходимо запустить Анана.Дизайнер... +смотри раздел _Использование_ ниже + +_Использование_ + +И так сказу после успешной компиляции запускаем Ананас.Дизайнер +cd /usr/src/ananas-engine/src/designer +./ananas-designer + + +В нем нужно выбрать конфигурацию (в диалоге выбора конфигурации +есть возможность задать параметры доступа к серверу баз данных) +и создать базу данных на сервере, воспользовавшись пунктом меню +"Бизнес схема" -> "Сохранить". +Иногда этот процесс занимает довольно продолжительное время, +поэтому лучше не нажимать кнопочку "Сохранить" несколько раз подряд. + +Теперь ваш Ананас готов к работе. +Сначала, стоит еще немного времени уделить Ананас.Дизайнеру +В нем есть много интересного ;) +Чтобы увидеть дерево бизнес схемы, воспользуйтесь меню +"Бизнес схема" -> "Открыть" +Откроется окно с объектами бизнес схемы, организованными в виде дерева. + +Во-первых, вы можете менять бизнес схему по своему усмотрению. +Добавлять/удалять документы, поля документов, табличные части документов. +Работать с другими объектами. +После изменения бизнес схемы ее можно сохранить, а также обновить структуру +базы данных тем же способом, которым мы ее создали выше. + +Двойной щелчек по корню дерева откроет доступ к параметрам бизнес схемы и... +- Внимание!- редактору глобального модуля Ananas.Script - месту, где определяются +общедоступные функции на встроенном в Ананас интерпретируемом языке +программирования. +Сдесь можно увидеть определение функций +on_systemstart() +on_systemstop() +Это зарезервированные названия функций, через которые осуществляется +обработка события запуска Ананаса и события выхода из Ананаса соответственно. + +Уже сейчас есть возможность создавать/настраивать экранные формы (диалоги) +документов, и определять обработку событий нажатия на кнопки диалога. +Для того, чтобы форма работала, нужно определить обработчики событий. +Что осуществляется на закладке "Модуль" редактора свойств диалога. + +Вдоволь набаловавшись с Ананас.Дизайнером, можно пойти и проверить, как работает +то, что мы "наконфигурировали" :) +Для этого нужно запустить сам Ананас +cd /usr/src/ananas-engine/src/engine +./ananas-engine +И выбрать именно ту бизнес схему, с которой мы работали +в Ананас.Дизайнере + +Во время запуска Ананаса отработает код функции +on_systemstart(), упомянутой выше. +Вот пожалуй и все, что хотелось сказать об использовании. + + +_Использование с PostgreSQL_ + +Для работы системы с сервером postgres необходимо: + +1. Перед началом работы надо установить сервер postgres из вашего +дистрибутива. Желательна версия больше 7.3 + +2. Настроить сервер БД для работы с TCP/IP соединением. Для этого из под +пользователя root в файле postgresql.conf вашей системы (например, для +ALT Linux Master 2.2 он находтится в каталоге /var/lib/pgsql/data) нужно +прописать строку: + +tcpip_socket=true + +или найти и раскоментировать соответствующий параметр. Порт 5432 +используется postgres по умолчанию, но при необходимости его можно +изменить, добавив или изменив параметр: + +port=5432 + +Затем следует перезапустить сервер БД командой: + +service postgresql restart + + + + + + diff --git a/VERSION b/VERSION new file mode 100644 index 0000000..b0bb878 --- /dev/null +++ b/VERSION @@ -0,0 +1 @@ +0.9.5 diff --git a/applications/ananas-cfg.dtd b/applications/ananas-cfg.dtd new file mode 100644 index 0000000..a53fb76 --- /dev/null +++ b/applications/ananas-cfg.dtd @@ -0,0 +1,150 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/applications/money/money.cfg b/applications/money/money.cfg new file mode 100644 index 0000000..f6ef05c --- /dev/null +++ b/applications/money/money.cfg @@ -0,0 +1,170 @@ + + + + + Ananas-money + 130 + Valery Grazdankin + 2007-01-11 + + + + + + + + + Платежи + + + + + + + + + +function on_systemstart() +{ + debug("system started"); + d = MetaData.documents(); +// i = MetaData.info; + System.println( d.name ); + System.println( MetaData.test() ); + debug( MetaData.test() ); +// System.println( MetaData.info.name ); + +} + + + + + + + + 0 + + + + + + + + + + + + 0 + + + +
+ + + 0 + <ui version="4.0" > + <class>Catalogue</class> + <widget class="wCatalogue" name="Catalogue" > + <property name="geometry" > + <rect> + <x>0</x> + <y>0</y> + <width>500</width> + <height>381</height> + </rect> + </property> + <property name="Id" > + <number>0</number> + </property> + <property name="Name" stdset="0" > + <string/> + </property> + <property name="caption" stdset="0" > + <string>Статьи расходов</string> + </property> + <widget class="QPushButton" name="pushButton" > + <property name="geometry" > + <rect> + <x>20</x> + <y>330</y> + <width>83</width> + <height>28</height> + </rect> + </property> + <property name="text" > + <string>OK</string> + </property> + </widget> + <widget class="QPushButton" name="pushButton_2" > + <property name="geometry" > + <rect> + <x>20</x> + <y>290</y> + <width>83</width> + <height>28</height> + </rect> + </property> + <property name="text" > + <string>Жми</string> + </property> + </widget> + <widget class="QRadioButton" name="radioButton" > + <property name="geometry" > + <rect> + <x>20</x> + <y>250</y> + <width>101</width> + <height>24</height> + </rect> + </property> + <property name="text" > + <string>RadioButton</string> + </property> + </widget> + </widget> + <layoutdefault spacing="5" margin="5" /> + <pixmapfunction>qPixmapFromMimeSource</pixmapfunction> + <customwidgets> + <customwidget> + <class>wCatalogue</class> + <extends>QWidget</extends> + <header>wcatalogue.h</header> + <container>1</container> + </customwidget> + </customwidgets> + <includes> + <include location="local" >wcatalogue.h</include> + </includes> + <resources/> + <connections/> +</ui> + + +
+ + +
+
+ + + + + + + +
+ + + + + + 2 + 102 + 0 + + + + + + +
diff --git a/applications/money/money.rc b/applications/money/money.rc new file mode 100644 index 0000000..6906350 --- /dev/null +++ b/applications/money/money.rc @@ -0,0 +1,9 @@ +dbpass=111111 +workdir=/usr/share/ananas4/applications/money/ +dbhost=localhost +dbtitle=Ananas-money +dbtype=mysql +dbuser=root +dbname=ananas_money +configfile=/usr/share/ananas4/applications/money/money.cfg +dbport=0 diff --git a/build/altlinux/altlinux.spec b/build/altlinux/altlinux.spec new file mode 100644 index 0000000..989610c --- /dev/null +++ b/build/altlinux/altlinux.spec @@ -0,0 +1,407 @@ +# ananas project +# Spec file for building rpm and rpms under ALT Linux and Fedora +# $Id: altlinux.spec,v 1.1 2008/11/27 20:20:54 leader Exp $ +# $Name: $ +# + +%define ShortName ananas +%define _qtdir %(echo $QTDIR) +#%define OSDISTR %(OSVENDOR=REDHAT; echo $OSVENDOR) +%define OSDISTR %(if [ -e /etc/altlinux-release ] ; then OSVENDOR=ALT; fi ; echo $OSVENDOR ) + +Name: ananas +Version: 0.9.5 +Release: %(if [ -e /etc/altlinux-release ] ; then echo "alt2"; else echo f`grep -o "[0-9|\.]\+" /etc/redhat-release` ; fi) +Buildroot: %{_tmppath}/%{name}-%{version}-root + +Summary: Runtime and development environment of Finance Applications +Summary(ru_RU.KOI8-R): Среда разработки и исполнения прикладных решений автоматизации оперативного, бухгалтерского и других видов учета. + +License: GPL +Url: http://ananas.lrn.ru/ +Vendor: Project Ananas + +Group(ru): %(if [ -e /etc/altlinux-release ] ; then echo "Офис"; else echo "Приложения/Повышение уровня производительности"; fi) +Group: %(if [ -e /etc/altlinux-release ] ; then echo "Office"; else echo "Applications/Productivity"; fi) + +Source: %name-%version.tar.bz2 + + +#Requires: %(if [ -e /etc/altlinux-release ] ; then echo "MySQL-server >= 4.1 "; else echo "mysql-server >= 4.1 "; fi) +Requires: %(if [ -e /etc/altlinux-release ] ; then echo "MySQL-client"; else echo "mysql"; fi) +#Requires: %(if [ -e /etc/altlinux-release ] ; then echo "MySQL-client >= 4.1 "; else echo "mysql >= 4.1 "; fi) +Requires: %(if [ -e /etc/altlinux-release ] ; then echo "libpq3"; else echo "postgresql"; fi) +Requires: %(if [ -e /etc/altlinux-release ] ; then echo "libqt3 >= 3.2"; else echo "qt >= 3.2.0"; fi) +Requires: %(if [ -e /etc/altlinux-release ] ; then echo "libqt3-qsa >= 3.2"; else echo "qt-qsa >= 1.1"; fi) +#Requires: %(if [ -e /etc/altlinux-release ] ; then echo "qt3-designer >= 3.2"; else echo "qt-designer >= 3.2" ;fi) +#Requires: tradeequip +Requires: libqt3-qdataschema + +BuildRequires: gcc-c++ libstdc++-devel +#BuildRequires: tradeequip-devel +#tradeequip + +#BuildRequires: %(if [ -e /etc/altlinux-release ] ; then echo "libMySQL-devel >= 4.1"; else echo "mysql-devel >= 4.1"; fi) +BuildRequires: %(if [ -e /etc/altlinux-release ] ; then echo "libMySQL-devel"; else echo "mysql-devel"; fi) +BuildRequires: %(if [ -e /etc/altlinux-release ] ; then echo "libqt3-devel"; else echo "qt-devel"; fi) +BuildRequires: %(if [ -e /etc/altlinux-release ] ; then echo "libqt3-qsa-devel"; else echo "qt-qsa-devel"; fi) +#BuildRequires: %(if [ -e /etc/altlinux-release ] ; then echo "libqt3-mysql"; else echo "qt-MySQL"; fi) +#BuildRequires: %(if [ -e /etc/altlinux-release ] ; then echo "libqt3-postgresql"; else echo "qt-PostgreSQL"; fi) +#BuildRequires: %(if [ -e /etc/altlinux-release ] ; then echo "libqt3-sqlite"; else echo "sqlite-devel"; fi) +BuildRequires: libqt3-qdataschema-devel + + +%description -l ru_RU.KOI8-R +Платформа Ананас предназначена для автомматизации малых и средних предприятий. +Обеспечивает автоматизацию ведения оперативного и бухгалтерского учета. +Платформа позволяет создавать приложения, поддерживающие многопользовательский +режим работы, сопровождается документацией на русском языке +имеет русифицированный графический интерфейс пользователя. Для ее +использования необходимо иметь установленную систему X Window System, +графическую среду KDE и сервер баз данных с поддержкой транзакций MySQL. +Пакет ananas необходимо установить, если вы собираетесь использовать +прикладное решение на платформе Ананас. + +Разработчики +--------------- +Валерий Гражданкин +Андрей Паскаль +Андрей Стрельников +Павел Миколайчук +Александр Ковалёв +Григорий Панов + +%description +Ananas is an Accounting Application Framework for Small Businesses. + +Developers +--------------- +Valery Grazhdankin +Andrey Paskal +Andrey Strelnikov +Pavel Mikolaychuk +Alexander Kovalyov +Grigory Panov + + +%package -n ananas-devel +Summary(ru_RU.KOI8-R): Статические библиотеки и файлы определений на языке Cи. +Summary: Ananas development library. Static libs and C header files. +Group(ru_RU.KOI8-R): Разработка/Библиотеки +Group: Development/Other + +%description -l ru_RU.KOI8-R -n ananas-devel +Статические библиотеки и файлы определений на языке C++. +ananas-devel необходимо установить, если вы планируете использовать библиотеки +Ананаса в своей C/C++ программе. Если вы планируете использовать прикладное +решение на платформе Ананас, то пакет не нужно устанавливать. + +Разработчики +--------------- +Валерий Гражданкин +Андрей Паскаль +Андрей Стрельников +Павел Миколайчук +Александр Ковалёв +Григорий Панов + +%description -n ananas-devel +Ananas development library. Static libs and C header files. + +Developers +--------------- +Valery Grazhdankin +Andrey Paskal +Andrey Strelnikov +Pavel Mikolaychuk +Alexander Kovalyov +Grigory Panov + +%package -n ananas-inventory +Summary(ru_RU.KOI8-R): Прикладная настройка для ведения простого складского учета. +Summary: Scripts, Documents and Reports templates of Inventory system. +Group: Office +Group(ru_RU.KOI8-R): Приложения/Учет и Финансы + +Requires: ananas >= %version +Requires: zip +Requires: unzip + +%description -l ru_RU.KOI8-R -n ananas-inventory +Прикладная настройка для ведения простого складского учета. + +Разработчики +--------------- +Валерий Гражданкин +Андрей Паскаль +Андрей Стрельников +Павел Миколайчук +Александр Ковалёв +Григорий Панов + +%description -n ananas-inventory +Scripts, Documents and Reports templates of Inventory Accounting system. + +Developers +--------------- +Valery Grazhdankin +Andrey Paskal +Andrey Strelnikov +Pavel Mikolaychuk +Alexander Kovalyov +Grigory Panov + +%package -n ananas-extensions +Summary(ru_RU.KOI8-R): Набор плагинов для Ананаса. +Summary: Ananas plugins collection. +Group: Office +Group(ru_RU.KOI8-R): Приложения/Учет и Финансы + +Requires: ananas >= %version + +%description -l ru_RU.KOI8-R -n ananas-extensions +Набор плагинов для Ананаса. + +Разработчики +--------------- +Валерий Гражданкин +Андрей Паскаль +Андрей Стрельников +Павел Миколайчук +Александр Ковалёв +Григорий Панов + +%description -n ananas-extensions +Ananas plugins collection. + +Developers +--------------- +Valery Grazhdankin +Andrey Paskal +Andrey Strelnikov +Pavel Mikolaychuk +Alexander Kovalyov +Grigory Panov + + +%prep +%setup + +%build +#export QTDIR=/usr/lib/qt3 +export PATH=${PATH}:$QTDIR/bin +./configure +make +make tr + +%install +export PATH=${PATH}:$QTDIR/bin + +if [ -e /etc/altlinux-release ] ; then + +# пока libMySQL >=4.1 нет в Sisyphus, чтобы не пересобирать MySQL-devel :-( +%set_verify_elf_method textrel=relaxed + + make install INSTALL_ROOT="$RPM_BUILD_ROOT" LIBDIR=%_libdir BINDIR=%_bindir DOCDIR=%_docdir/%name-%version INCLUDEDIR=%_includedir/ananas + %__mkdir_p %buildroot%_sysconfdir/ananas + %__mkdir_p %buildroot%_datadir/ananas/translations + %__mkdir_p %buildroot%_datadir/ananas/templates + %__mkdir_p %buildroot%_datadir/ananas/inventory + %__mkdir_p %buildroot%_datadir/pixmaps + %__mkdir_p %buildroot%_menudir + %__mkdir_p %buildroot%_datadir/applications/kde + +else + + rm -f `find src doc -name Makefile` + qmake src/src.pro -o src/Makefile + cd src && make install INSTALL_ROOT="$RPM_BUILD_ROOT" LIBDIR=%_libdir BINDIR=%_bindir INCLUDEDIR=%_includedir/ananas && cd ../doc && qmake doc.pro -o Makefile && make install INSTALL_ROOT="$RPM_BUILD_ROOT" DOCDIR=%_docdir/%name-%version + + mkdir -p %buildroot%_sysconfdir/ananas + mkdir -p %buildroot%_datadir/ananas/translations + mkdir -p %buildroot%_datadir/ananas/templates + mkdir -p %buildroot%_datadir/ananas/inventory + mkdir -p %buildroot%_datadir/applications/kde + mkdir -p %buildroot%_datadir/pixmaps + mkdir -p %buildroot/usr/lib/menu +fi + +#clear debug info +strip %buildroot%_bindir/ananas +strip %buildroot%_bindir/ananas-designer +strip %buildroot%_libdir/libananas.so* +strip %buildroot%_libdir/ananas/qt3plugins/designer/libananasplugin.so +strip %buildroot%_libdir/ananas/qt3plugins/sqldrivers/libqsqlmysqlu.so +strip %buildroot%_libdir/ananas/*.so + +cp -f %_builddir/%name-%version/translations/*.qm %buildroot%_datadir/ananas/translations +cp -f %_builddir/%name-%version/src/designer/templates/*.* %buildroot%_datadir/ananas/templates + +cp -f %_builddir/%name-%version/applications/inventory/inventory.cfg %buildroot%_sysconfdir/ananas/ +cp -f %_builddir/%name-%version/applications/inventory/inventory.rc %buildroot%_sysconfdir/ananas/ +cp -f %_builddir/%name-%version/applications/inventory/inventory.sql %buildroot%_datadir/ananas/inventory +cp -f %_builddir/%name-%version/applications/inventory/inventory-demo.cfg %buildroot%_sysconfdir/ananas/ +cp -f %_builddir/%name-%version/applications/inventory/inventory-demo.rc %buildroot%_sysconfdir/ananas/ +cp -f %_builddir/%name-%version/applications/inventory/inventory-demo.sql %buildroot%_datadir/ananas/inventory +cp -f %_builddir/%name-%version/applications/inventory/inventory_pgsql.sql %buildroot%_datadir/ananas/inventory +cp -f %_builddir/%name-%version/applications/inventory/inventory_grouprc %buildroot%_sysconfdir/ananas +cp -f %_builddir/%name-%version/applications/inventory/templ_*.odt %buildroot%_datadir/ananas/inventory +cp -f %_builddir/%name-%version/applications/inventory/templ_*.ods %buildroot%_datadir/ananas/inventory + + +cp -f %_builddir/%name-%version/build/kde/images/*.png %buildroot%_datadir/pixmaps/ + +#if [ -e /etc/altlinux-release ] ; then + + cp -f %_builddir/%name-%version/build/kde/ananas %buildroot/usr/lib/menu + cp -f %_builddir/%name-%version/build/kde/ananas-designer %buildroot/usr/lib/menu + +#else + + cp -f %_builddir/%name-%version/build/kde/ananas.desktop %buildroot%_datadir/applications/kde + cp -f %_builddir/%name-%version/build/kde/ananas-designer.desktop %buildroot%_datadir/applications/kde +#fi + +%post +ln -fs %_libdir/ananas/qt3plugins/designer/libananasplugin.so %_libdir/libananasplugin.so + +#starts mysql server +[ -e /etc/init.d/mysqld ] && /etc/init.d/mysqld status|grep -v pid > /dev/null && /etc/init.d/mysqld start > /dev/null || : +#creates system base for mysql +mysqlshow -u root| grep ananas_system > /dev/null || mysqladmin -u root create ananas_system || : +#touch %buildroot%_sysconfdir/ananas/groupsrc + +if [ -e /etc/altlinux-release ] ; then + rm -f %_datadir/applications/kde/ananas.desktop + rm -f %_datadir/applications/kde/ananas-designer.desktop + %update_menus +else + rm -f /usr/lib/menu/ananas + rm -f /usr/lib/menu/ananas-designer +fi + + +%post -n ananas-inventory +#cat %_datadir/ananas/inventory/groupsrc >> %_sysconfdir/ananas/groupsrc +#starts mysql server +[ -e /etc/init.d/mysqld ] && /etc/init.d/mysqld status|grep -v pid > /dev/null && /etc/init.d/mysqld start > /dev/null || : +#creates databases +mysql -u root -e "create database ananas_inventory character set utf8" > /dev/null 2>&1 && mysql -u root ananas_inventory < %_datadir/ananas/inventory/inventory.sql || : +mysql -u root -e "create database ananas_inventory_demo character set utf8" > /dev/null 2>&1 && mysql -u root ananas_inventory_demo < %_datadir/ananas/inventory/inventory-demo.sql || : + +%postun + +if [ -e /etc/altlinux-release ] ; then +%clean_menus +fi +rm -f %_datadir/ananas/translations/*.qm +rm -f %_datadir/ananas/templates/*.* + +rmdir --ignore-fail-on-non-empty %_datadir/ananas/translations +rmdir --ignore-fail-on-non-empty %_datadir/ananas/templates +rmdir --ignore-fail-on-non-empty %_datadir/ananas + +%postun -n ananas-extensions +rmdir --ignore-fail-on-non-empty %_libdir/ananas +rmdir --ignore-fail-on-non-empty %_datadir/ananas + + +%postun -n ananas-inventory +rm -f %_sysconfdir/ananas/inventory.* +rm -f %_sysconfdir/ananas/inventory-demo.* +rm -f %_sysconfdir/ananas/inventory_grouprc +rmdir --ignore-fail-on-non-empty %_sysconfdir/ananas +rm -f %_datadir/ananas/inventory/templ_*.odt +rm -f %_datadir/ananas/inventory/templ_*.ods +rmdir --ignore-fail-on-non-empty %_datadir/ananas/inventory +rmdir --ignore-fail-on-non-empty %_datadir/ananas + + +%clean + +%files +%_bindir/ananas +%_bindir/ananas-designer +%_libdir/libananas.so* +%_libdir/ananas/qt3plugins/designer/libananasplugin.so +%_libdir/ananas/qt3plugins/sqldrivers/libqsqlmysqlu.so +%_docdir/%name-%version/ananas-*.sxw +%_datadir/ananas/translations/*.qm +%_datadir/ananas/templates/*.* +%_datadir/pixmaps/*.png +# files menu for ALT +/usr/lib/menu/ananas +/usr/lib/menu/ananas-designer +# files desktop for Fedora +%_datadir/applications/kde/ananas.desktop +%_datadir/applications/kde/ananas-designer.desktop + + +%files -n ananas-devel +%_includedir/ananas/*.h +%_docdir/%name-%version/*.tex + +%files -n ananas-inventory +%_sysconfdir/ananas/inventory.* +%_sysconfdir/ananas/inventory-demo.* + +%_datadir/ananas/inventory/inventory.sql +%_datadir/ananas/inventory/inventory-demo.sql +%_datadir/ananas/inventory/inventory_pgsql.sql + +%_datadir/ananas/inventory/templ_*.odt +%_datadir/ananas/inventory/templ_*.ods +%_sysconfdir/ananas/inventory_grouprc + +%files -n ananas-extensions +%_libdir/ananas/*.so + +%changelog +* Sun Dec 30 2007 Andrey Paskal 0.9.5 + + Please look at ChangeLog file of Ananas Project + +* Fri Sep 08 2006 Andrey Paskal + + Meta extention has been added + +* Sun Jul 02 2006 Valery Grazdankin 0.9.3-alt2 + + Trade equipment extension added + +* Tue Jun 20 2006 Grigory Panov 0.9.3-alt1 + + Added extensions + +* Mon Mar 27 2006 Valery Grazdankin 0.9.3-alt1 + - Automatic generated cvs build + +* Tue Feb 21 2006 Valery Grazdankin 0.9.2-alt1 + + Add ananas extensions plugin system. + +* Thu Jan 05 2006 Grigory Panov 0.9.1-alt1 + + Merge with st05 branch + +* Wed Jun 06 2005 Valery Grazdankin 0.4.2-alt1 + + Files list was changed in the inventory package + +* Fri May 06 2005 Valery Grazdankin 0.4.2-alt1 + + Added support some configuration files + +* Thu May 05 2005 Andrey Paskal 0.4.2-alt1 + + rpm build procedure was changed. After install ananas-inventory.*rpm + we can immediately to work with "Deport accouning" configuration , + by running ananas-engine. + + Debugged (by gr) report procession in OpenOffice format under Linux. + +* Sat Mar 19 2005 Grigory Panov 0.4.2-alt1 + + Added template in OpenOffice format for ananas-inventory + + Added section for remove files and directories after deinstallation + + Added ananas-engine-qt requires to ananas-inventory package + +* Tue Mar 15 2005 Valery Grazdankin 0.4.2-alt1 + + File name ananasrc changed to groupsrc + + groupsrc have Unix file format now + +* Sun Nov 21 2004 Valery Grazdankin 0.4.2-alt1 + + Correct installation procedure + +* Fri Nov 05 2004 Valery Grazdankin 0.4.2-alt1 + + Added spec file for build ALT Linux packages. + + win32 version build completed. Ananas - is multitarget application now diff --git a/build/fedora/fedora.spec b/build/fedora/fedora.spec new file mode 100644 index 0000000..00ccf30 --- /dev/null +++ b/build/fedora/fedora.spec @@ -0,0 +1,231 @@ +# ananas project +# Spec file for building single rpm package of Ananas for Fedora Linux +# $Id: fedora.spec,v 1.1 2008/11/27 20:20:54 leader Exp $ +# $Name: $ +# + +%define ShortName ananas +%define _qtdir %(echo $QTDIR) + +Name: ananas +Version: 0.9.5 +Release: %( echo f`grep -o "[0-9|\.]\+" /etc/redhat-release`) +Buildroot: %{_tmppath}/%{name}-%{version}-root + +Summary: Runtime and development environment of Finance Applications. +Summary(ru_RU.UTF8): Среда разработки и исполнения прикладных решений автоматизации оперативного, бухгалтерского и других видов учета. + +License: GPL +Url: http://ananas.lrn.ru/ +Vendor: Project Ananas +Group: Applications/Productivity + +Source: %name-%version.tar.bz2 + +Requires: mysql-server >= 4.1 +Requires: mysql >= 4.1 +Requires: qt >= 3.2.0 +Requires: qt-qsa >= 1.1 +Requires: bluecurve.so +Requires: zip +Requires: unzip + + +BuildRequires: gcc-c++ libstdc++-devel +BuildRequires: mysql-devel +BuildRequires: qt-devel +BuildRequires: qt-qsa-devel + + +%description -l ru_RU.UTF8 +Платформа Ананас предназначена для автомматизации малых и средних предприятий. +Обеспечивает автоматизацию ведения оперативного и бухгалтерского учета. +Платформа позволяет создавать приложения, поддерживающие многопользовательский +режим работы, сопровождается документацией на русском языке +имеет русифицированный графический интерфейс пользователя. Для ее +использования необходимо иметь установленную систему X Window System, +графическую среду KDE и сервер баз данных с поддержкой транзакций MySQL. +Пакет ananas необходимо установить, если вы собираетесь использовать +прикладное решение на платформе Ананас. + +Разработчики +--------------- +Валерий Гражданкин +Андрей Паскаль +Андрей Стрельников +Павел Миколайчук +Александр Ковалёв +Григорий Панов + +%description +Ananas is an Accounting Application Framework for Small Businesses. + +Developers +--------------- +Valery Grazhdankin +Andrey Paskal +Andrey Strelnikov +Pavel Mikolaychuk +Alexander Kovalyov +Grigory Panov + + +%prep +%setup + +%build +export PATH=${PATH}:$QTDIR/bin +./configure +make +make tr + +%install +export PATH=${PATH}:$QTDIR/bin + + +rm -f `find src doc -name Makefile` +qmake src/src.pro -o src/Makefile +cd src && make install \ + INSTALL_ROOT="$RPM_BUILD_ROOT" \ + LIBDIR=%_libdir BINDIR=%_bindir \ + INCLUDEDIR=%_includedir/ananas && \ + cd ../doc && qmake doc.pro -o Makefile && make install INSTALL_ROOT="$RPM_BUILD_ROOT" DOCDIR=%_docdir/%name-%version + +mkdir -p %buildroot%_sysconfdir/ananas +mkdir -p %buildroot%_datadir/ananas/translations +mkdir -p %buildroot%_datadir/ananas/templates +mkdir -p %buildroot%_datadir/ananas/inventory +mkdir -p %buildroot%_datadir/applications/kde +mkdir -p %buildroot%_datadir/pixmaps +mkdir -p %buildroot/usr/lib/menu + +#clear debug info +strip %buildroot%_bindir/ananas +strip %buildroot%_bindir/ananas-designer +strip %buildroot%_libdir/libananas.so* +strip %buildroot%_libdir/ananas/qt3plugins/designer/libananasplugin.so +strip %buildroot%_libdir/ananas/qt3plugins/sqldrivers/libqsqlmysqlu.so +strip %buildroot%_libdir/ananas/*.so + +mv %buildroot%_libdir/ananas/qt3plugins/designer/libananasplugin.so %buildroot%_libdir/ +ln -fs ../../../libananasplugin.so %buildroot%_libdir/ananas/qt3plugins/designer/libananasplugin.so + +cp -f %_builddir/%name-%version/translations/*.qm %buildroot%_datadir/ananas/translations +cp -f %_builddir/%name-%version/src/designer/templates/*.* %buildroot%_datadir/ananas/templates + +cp -f %_builddir/%name-%version/applications/inventory/inventory.cfg %buildroot%_sysconfdir/ananas/ +cp -f %_builddir/%name-%version/applications/inventory/inventory.rc %buildroot%_sysconfdir/ananas/ +cp -f %_builddir/%name-%version/applications/inventory/inventory.sql %buildroot%_datadir/ananas/inventory +cp -f %_builddir/%name-%version/applications/inventory/inventory-demo.cfg %buildroot%_sysconfdir/ananas/ +cp -f %_builddir/%name-%version/applications/inventory/inventory-demo.rc %buildroot%_sysconfdir/ananas/ +cp -f %_builddir/%name-%version/applications/inventory/inventory-demo.sql %buildroot%_datadir/ananas/inventory +cp -f %_builddir/%name-%version/applications/inventory/inventory_pgsql.sql %buildroot%_datadir/ananas/inventory +cp -f %_builddir/%name-%version/applications/inventory/inventory_grouprc %buildroot%_sysconfdir/ananas +cp -f %_builddir/%name-%version/applications/inventory/templ_*.odt %buildroot%_datadir/ananas/inventory +cp -f %_builddir/%name-%version/applications/inventory/templ_*.ods %buildroot%_datadir/ananas/inventory +cp -f %_builddir/%name-%version/build/kde/images/*.png %buildroot%_datadir/pixmaps/ +cp -f %_builddir/%name-%version/build/kde/ananas.desktop %buildroot%_datadir/applications/kde +cp -f %_builddir/%name-%version/build/kde/ananas-designer.desktop %buildroot%_datadir/applications/kde +cp -f %_builddir/%name-%version/build/fedora/qtrc %buildroot%_datadir/ananas/ + +%post + +# Fedora 8 does not provides %_libdir/qt-3.3/etc/settings/qtrc +# So we install them manualy +if ! [ -e %_libdir/qt-3.3/etc/settings/qtrc ]; then + if ! [ -e %_libdir/qt-3.3/etc/settings ] ;then + mkdir -p %_libdir/qt-3.3/etc/settings + fi + cp %_datadir/ananas/qtrc %_libdir/qt-3.3/etc/settings/ +fi + +#starts mysql server +[ -e /etc/init.d/mysqld ] && /etc/init.d/mysqld status|grep -v pid > /dev/null && /etc/init.d/mysqld start > /dev/null || : +#creates system base for mysql +mysqlshow -u root| grep ananas_system > /dev/null || mysqladmin -u root create ananas_system || : +#touch %buildroot%_sysconfdir/ananas/groupsrc + +rm -f /usr/lib/menu/ananas +rm -f /usr/lib/menu/ananas-designer + + +##%post -n ananas-inventory +#starts mysql server +[ -e /etc/init.d/mysqld ] && /etc/init.d/mysqld status|grep -v pid > /dev/null && /etc/init.d/mysqld start > /dev/null || : +#creates databases +mysql -u root -e "create database ananas_inventory character set utf8" > /dev/null 2>&1 && mysql -u root ananas_inventory < %_datadir/ananas/inventory/inventory.sql || : +mysql -u root -e "create database ananas_inventory_demo character set utf8" > /dev/null 2>&1 && mysql -u root ananas_inventory_demo < %_datadir/ananas/inventory/inventory-demo.sql || : + +%postun +# Если %_libdir/qt-3.3/etc/settings/qtrc не принадлежит ни одному пакету, +# значит это мы его поставили и должны удалить при деинсталляции. +rpm -qf %_libdir/qt-3.3/etc/settings/qtrc > /dev/null 2>&1 || rm -f %_libdir/qt-3.3/etc/settings/qtrc \ +&& rmdir %_libdir/qt-3.3/etc/settings 2>/dev/null && rmdir --ignore-fail-on-non-empty %_libdir/qt-3.3/etc + +rm -f %_datadir/ananas/translations/*.qm +rm -f %_datadir/ananas/templates/*.* + +rmdir --ignore-fail-on-non-empty %_datadir/ananas/translations +rmdir --ignore-fail-on-non-empty %_datadir/ananas/templates +rmdir --ignore-fail-on-non-empty %_datadir/ananas + +##%postun -n ananas-extensions +rmdir --ignore-fail-on-non-empty %_libdir/ananas +rmdir --ignore-fail-on-non-empty %_datadir/ananas + + +##%postun -n ananas-inventory +rm -f %_sysconfdir/ananas/inventory.* +rm -f %_sysconfdir/ananas/inventory-demo.* +rm -f %_sysconfdir/ananas/inventory_grouprc +rmdir --ignore-fail-on-non-empty %_sysconfdir/ananas +rm -f %_datadir/ananas/inventory/templ_*.odt +rm -f %_datadir/ananas/inventory/templ_*.ods +rmdir --ignore-fail-on-non-empty %_datadir/ananas/inventory +rmdir --ignore-fail-on-non-empty %_datadir/ananas + + +%clean + +%files +%_bindir/ananas +%_bindir/ananas-designer +%_libdir/libananas.so* +%_libdir/libananasplugin.so +%_libdir/ananas/qt3plugins/designer/libananasplugin.so +%_libdir/ananas/qt3plugins/sqldrivers/libqsqlmysqlu.so +%_docdir/%name-%version/ananas-*.sxw +%_datadir/ananas/translations/*.qm +%_datadir/ananas/templates/*.* +%_datadir/pixmaps/*.png +# files menu for ALT +##/usr/lib/menu/ananas +##/usr/lib/menu/ananas-designer +# files desktop for Fedora +%_datadir/applications/kde/ananas.desktop +%_datadir/applications/kde/ananas-designer.desktop +%_datadir/ananas/qtrc + +##%files -n ananas-devel +%_includedir/ananas/*.h +%_docdir/%name-%version/*.tex + +##%files -n ananas-inventory +%_sysconfdir/ananas/inventory.* +%_sysconfdir/ananas/inventory-demo.* + +%_datadir/ananas/inventory/inventory.sql +%_datadir/ananas/inventory/inventory-demo.sql +%_datadir/ananas/inventory/inventory_pgsql.sql + +%_datadir/ananas/inventory/templ_*.odt +%_datadir/ananas/inventory/templ_*.ods +%_sysconfdir/ananas/inventory_grouprc + +##%files -n ananas-extensions +%_libdir/ananas/*.so + +%changelog +* Sun Dec 30 2007 Andrey Paskal 0.9.5 + + Please look at ChangeLog file of Ananas Project + diff --git a/build/icons/a-system.ico b/build/icons/a-system.ico new file mode 100644 index 0000000000000000000000000000000000000000..f8fcdbd66a0486458549629b138e672c86187def GIT binary patch literal 16318 zcmeI3e{fXSb;pk z=f3xLpXB}VglPYXFT8i}IrrZ4Ip^H_?%M^4=nncEl|D(TJd;E8O|+&=(d5N{L9`dT z>C-iN_uWMI|2@&yAeQ2K6W1LCCCZcsRi)kTK!r<6N!R$g#@96(#&w?S%aVqN(Z)4A zJdApn2338Y&Y!!X>bs_!9f}r7^Z>2GZY^9i24R2 z)HQe-x&i9zJ5PuI>lF38b%8ntPSXB?KTzYqAcY1_p&p=veQ#q-A9Ww?qmDy@w)G9r zFW%~-*Nz;f{coJ1x;KwgPfrhZ^mNmXo

;7wwJ?^0i!}9L#G&`<37Rj#mHf5QX-> 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 VJ-)89J^=lH;74Ld!TLn1^1t7y_4NP% literal 0 HcmV?d00001 diff --git a/build/icons/a-system.png b/build/icons/a-system.png new file mode 100644 index 0000000000000000000000000000000000000000..6638dfffd429826b0f6b152a1255762a855bc285 GIT binary patch literal 1283 zcmV+e1^oJnP)ff z?ml$jF!N^az2|$*`JNw7_vD$s4}OTmU{jdp5sSmLI$*GH8n&7m=Q`Z+FY`mDA1* zE)~V-hdloha5E&YgW6RHmT%lxY#%=S<9bm%3*dnY*Z>{^E2=2aGPCZ5aOq9&Uwbfd zwOJqDc`(6CqBs@569Da@v-)q~+gX~&eib+dS+U_BA`7Mf}=*d2&@bA zMHm{00E|Q!g&+oCoHzy`xSiT<9YhN_C<0LK6JczpdRr%E;+E1UqNuhKYD9eA)m`7z z<6}2*M&;h*XX#a0k031mQP|o5JQE&FT^~!an`f+w*2%;J#j<5fNK!Q_PtuiYlYCjN zF;#9C6VLRjfOTML5@UB&l}^$LW2cFl6i{o`5qqM%0Gyj=8VUwr*#P{e$|BGfnYz9U z?5mlYCux_s-vPy3A&3WVOdj*q#L5a-1on&2n}i6lZ159>5mTN{NOO50^#ma2ynn}d z*?l9+-hV2~cwB_8mF=1}c`}E_Y;e1t3H8xeS;A_0T7*NuV`iE@x<}X=ifmRTY*Zea z51c-q$TAj;S;K^o2?wN>?y?;KN!>lPbQ=O;lhs?UMcWkD_ieqUXPD(kw^OVKz@Mu8 z0}QQ0h8Yp6uOAqQC0MQ%)M8d5qI&2fyZ+XesX;uDD@ma~o>zh@2qA7lJ|GMH3u tjw}qdxxPvO(}6TtKSRv1wTFS6cb+beAr_~5Cn@qb8wj-8Py3uAX4}7Gzr#0Y z0ps7c!p47uM6#AGk~3^QKH0#~%Iempy-Qv$-TD2~uXh51N$#QPVoR!ASPnYJPB(5a z6sRuGkea>IN_b+%=Z_H=x9PeDG8phMGhAEuWJQDirSF!@FH2Z_a^-uIAQQf6RnpqC z+xQkq{s^c|PugZym-=8sdc8R_tIYQI#k?oc@KAn^KTCa#!iyH{x~%Y3BIC^jj6 z{(S#;_mWgu^HMF_6E)i^8Uoq%zVhFc_;UKPe0;=Z^93&j52f+T1cpwx@-5*wR-wJu n_Cs3b-81%@0v&HAFvhL-5NvI69|g0)o<{)+bRGpv@XqrBcfft9Vgnd~z5XD-_jameSs&9q zJq?2==N!&NO6mB1_P6)q*E`@L_zVEcvgH3ppwFBHye}m7ea`mWj@$RYL?ESffb<~( z0Q?8cd!Ks}x5RE^8mVI;AQezRHgHpzNbq*e^pR*tR$|K!PNsp#f;uBtQ}* zCIi1$qEiak03k@W3{@2(9wIyxFqK3Es(hLKX#xN`62P`aEX!QwFQ67N#%X9^=iI}? zq6ZDZ=MW@2=Z?dBpG9z7zZ$nco+@xHd#yH`89zQgFwZk$jF{)9MDGz*eTwnagw8pv zE2nj3C#M2H1y2wm<~bq8c-#kA&#z<11Gfe&GXVey@5{7QE!QP;fvR44;1SL+0rLV$ z^lleHHw!97@%a6FJqWyAg4+Q|)C?Q=y&(0jncq^NUxxb?uaN1oXL(@Kk52EG3T#`P zNCC9~Hqh&NPZR@MlNybo5~%7V0zd(-gb)x_1o5z*6l27`?^h)oiJ>37IHd~z22DFNqP-E`KjSLL-Sh`Rf2tbV|R zf3|I+{ST;_vaSotHva))B~E7#3~oq1_dSz(`0QxKg~40WpCSMhQ(i*I)b+S$S%2kU d@-Ts)ioYT#tq%E*e_8+l002ovPDHLkV1nyYQ3e12 literal 0 HcmV?d00001 diff --git a/build/icons/ananas-designer.ico b/build/icons/ananas-designer.ico new file mode 100644 index 0000000000000000000000000000000000000000..9e815ab46b63c175b9c5822d27e36b626715044b GIT binary patch literal 4286 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 KF= 4.1 +Requires: MySQL-client >= 4.1 +#Requires: postgresql TODO: Для postrges нужен код создающий БД при установке или первом запуске Ананаса +Requires: libqt3 >= 3.2 +Requires: qsa >= 1.1 +Requires: zip +Requires: unzip + + +BuildRequires: gcc-c++ libstdc++-devel +BuildRequires: libmysql-devel +BuildRequires: libqt3-devel +BuildRequires: qsa-devel +BuildRequires: postgresql-devel +BuildRequires: libpq-devel +BuildRequires: postgresql8.2-devel + + +%description -l ru_RU.UTF8 +Платформа Ананас предназначена для автомматизации малых и средних предприятий. +Обеспечивает автоматизацию ведения оперативного и бухгалтерского учета. +Платформа позволяет создавать приложения, поддерживающие многопользовательский +режим работы, сопровождается документацией на русском языке +имеет русифицированный графический интерфейс пользователя. Для ее +использования необходимо иметь установленную систему X Window System, +графическую среду KDE и сервер баз данных с поддержкой транзакций MySQL. +Пакет ananas необходимо установить, если вы собираетесь использовать +прикладное решение на платформе Ананас. + +Разработчики +--------------- +Валерий Гражданкин +Андрей Паскаль +Андрей Стрельников +Павел Миколайчук +Александр Ковалёв +Григорий Панов + +%description +Ananas is an Accounting Application Framework for Small Businesses. + +Developers +--------------- +Valery Grazhdankin +Andrey Paskal +Andrey Strelnikov +Pavel Mikolaychuk +Alexander Kovalyov +Grigory Panov + + +%prep +%setup + +%build +export PATH=${PATH}:$QTDIR/bin +./configure +make +make tr + +%install +export PATH=${PATH}:$QTDIR/bin + + +rm -f `find src doc -name Makefile` +qmake src/src.pro -o src/Makefile +cd src && make install \ + INSTALL_ROOT="$RPM_BUILD_ROOT" \ + LIBDIR=%_libdir BINDIR=%_bindir \ + INCLUDEDIR=%_includedir/ananas && \ + cd ../doc && qmake doc.pro -o Makefile && make install INSTALL_ROOT="$RPM_BUILD_ROOT" DOCDIR=%_docdir/%name-%version + +mkdir -p %buildroot%_sysconfdir/ananas +mkdir -p %buildroot%_datadir/ananas/translations +mkdir -p %buildroot%_datadir/ananas/templates +mkdir -p %buildroot%_datadir/ananas/inventory +mkdir -p %buildroot%_datadir/applications/kde +mkdir -p %buildroot%_datadir/pixmaps +mkdir -p %buildroot/usr/lib/menu + +#clear debug info +strip %buildroot%_bindir/ananas +strip %buildroot%_bindir/ananas-designer +strip %buildroot%_libdir/libananas.so* +strip %buildroot%_libdir/ananas/qt3plugins/designer/libananasplugin.so +strip %buildroot%_libdir/ananas/qt3plugins/sqldrivers/libqsqlmysqlu.so +strip %buildroot%_libdir/ananas/*.so + +mv %buildroot%_libdir/ananas/qt3plugins/designer/libananasplugin.so %buildroot%_libdir/ +ln -fs ../../../libananasplugin.so %buildroot%_libdir/ananas/qt3plugins/designer/libananasplugin.so + +cp -f %_builddir/%name-%version/translations/*.qm %buildroot%_datadir/ananas/translations +cp -f %_builddir/%name-%version/src/designer/templates/*.* %buildroot%_datadir/ananas/templates + +cp -f %_builddir/%name-%version/applications/inventory/inventory.cfg %buildroot%_sysconfdir/ananas/ +cp -f %_builddir/%name-%version/applications/inventory/inventory.rc %buildroot%_sysconfdir/ananas/ +cp -f %_builddir/%name-%version/applications/inventory/inventory.sql %buildroot%_datadir/ananas/inventory +cp -f %_builddir/%name-%version/applications/inventory/inventory-demo.cfg %buildroot%_sysconfdir/ananas/ +cp -f %_builddir/%name-%version/applications/inventory/inventory-demo.rc %buildroot%_sysconfdir/ananas/ +cp -f %_builddir/%name-%version/applications/inventory/inventory-demo.sql %buildroot%_datadir/ananas/inventory +cp -f %_builddir/%name-%version/applications/inventory/inventory_pgsql.sql %buildroot%_datadir/ananas/inventory +cp -f %_builddir/%name-%version/applications/inventory/inventory_grouprc %buildroot%_sysconfdir/ananas +cp -f %_builddir/%name-%version/applications/inventory/templ_*.odt %buildroot%_datadir/ananas/inventory +cp -f %_builddir/%name-%version/applications/inventory/templ_*.ods %buildroot%_datadir/ananas/inventory +cp -f %_builddir/%name-%version/build/kde/images/*.png %buildroot%_datadir/pixmaps/ +cp -f %_builddir/%name-%version/build/kde/ananas.desktop %buildroot%_datadir/applications/kde +cp -f %_builddir/%name-%version/build/kde/ananas-designer.desktop %buildroot%_datadir/applications/kde +cp -f %_builddir/%name-%version/build/fedora/qtrc %buildroot%_datadir/ananas/ + +%post + +#starts mysql server +[ -e /etc/init.d/mysqld ] && /etc/init.d/mysqld status|grep -v pid > /dev/null && /etc/init.d/mysqld start > /dev/null || : +#creates system base for mysql +mysqlshow -u root| grep ananas_system > /dev/null || mysqladmin -u root create ananas_system || : +#touch %buildroot%_sysconfdir/ananas/groupsrc + +rm -f /usr/lib/menu/ananas +rm -f /usr/lib/menu/ananas-designer + + +#starts mysql server +[ -e /etc/init.d/mysqld ] && /etc/init.d/mysqld status|grep -v pid > /dev/null && /etc/init.d/mysqld start > /dev/null || : +#creates databases +mysql -u root -e "create database ananas_inventory character set utf8" > /dev/null 2>&1 && mysql -u root ananas_inventory < %_datadir/ananas/inventory/inventory.sql || : +mysql -u root -e "create database ananas_inventory_demo character set utf8" > /dev/null 2>&1 && mysql -u root ananas_inventory_demo < %_datadir/ananas/inventory/inventory-demo.sql || : + +%postun + +rm -f %_datadir/ananas/translations/*.qm +rm -f %_datadir/ananas/templates/*.* + +rmdir --ignore-fail-on-non-empty %_datadir/ananas/translations +rmdir --ignore-fail-on-non-empty %_datadir/ananas/templates +rmdir --ignore-fail-on-non-empty %_datadir/ananas + +##%postun -n ananas-extensions +rmdir --ignore-fail-on-non-empty %_libdir/ananas +rmdir --ignore-fail-on-non-empty %_datadir/ananas + + +##%postun -n ananas-inventory +rm -f %_sysconfdir/ananas/inventory.* +rm -f %_sysconfdir/ananas/inventory-demo.* +rm -f %_sysconfdir/ananas/inventory_grouprc +rmdir --ignore-fail-on-non-empty %_sysconfdir/ananas +rm -f %_datadir/ananas/inventory/templ_*.odt +rm -f %_datadir/ananas/inventory/templ_*.ods +rmdir --ignore-fail-on-non-empty %_datadir/ananas/inventory +rmdir --ignore-fail-on-non-empty %_datadir/ananas + + +%clean + +%files +%_bindir/ananas +%_bindir/ananas-designer +%_libdir/libananas.so* +%_libdir/libananasplugin.so +%_libdir/ananas/qt3plugins/designer/libananasplugin.so +%_libdir/ananas/qt3plugins/sqldrivers/libqsqlmysqlu.so +%_docdir/%name-%version/ananas-*.sxw +%_datadir/ananas/translations/*.qm +%_datadir/ananas/templates/*.* +%_datadir/pixmaps/*.png +# files desktop for Fedora +%_datadir/applications/kde/ananas.desktop +%_datadir/applications/kde/ananas-designer.desktop +%_datadir/ananas/qtrc + +##%files -n ananas-devel +%_includedir/ananas/*.h +%_docdir/%name-%version/*.tex + +##%files -n ananas-inventory +%_sysconfdir/ananas/inventory.* +%_sysconfdir/ananas/inventory-demo.* + +%_datadir/ananas/inventory/inventory.sql +%_datadir/ananas/inventory/inventory-demo.sql +%_datadir/ananas/inventory/inventory_pgsql.sql + +%_datadir/ananas/inventory/templ_*.odt +%_datadir/ananas/inventory/templ_*.ods +%_sysconfdir/ananas/inventory_grouprc + +##%files -n ananas-extensions +%_libdir/ananas/*.so + +%changelog +* Sun Dec 30 2007 Andrey Paskal 0.9.5 + + Please look at ChangeLog file of Ananas Project + diff --git a/build/menus/kde/README b/build/menus/kde/README new file mode 100644 index 0000000..b406cec --- /dev/null +++ b/build/menus/kde/README @@ -0,0 +1,4 @@ +Каталог предназначен для файлов и скриптов, обеспечивающих +интеграцию Ананаса со средой KDE +хотя бы на уровне включения Ананаса после его установки +в меню запуска KDE. diff --git a/build/menus/kde/ananas b/build/menus/kde/ananas new file mode 100644 index 0000000..6d0047d --- /dev/null +++ b/build/menus/kde/ananas @@ -0,0 +1,5 @@ +?package(ananas):command="ananas"\ +needs="x11" section="Office" title="Ananas.Inventory"\ +longtitle="Inventory management and accounting system" \ +icon="ananas-32x32.png"\ +extra_opt="\\nName[ru]=Ананас.Оперативный учет\\nComment[ru]=Складской и бухгалтерсий учет" diff --git a/build/menus/kde/ananas-designer b/build/menus/kde/ananas-designer new file mode 100644 index 0000000..32100fe --- /dev/null +++ b/build/menus/kde/ananas-designer @@ -0,0 +1,6 @@ +?package(ananas):command="ananas-designer"\ +needs="x11" section="Applications/Development/Development environments"\ +title="Ananas.Designer"\ +longtitle="Design and develop Ananas applications"\ +icon="ananas-designer.png"\ +extra_opt="\\nName[ru]=Ананас.Дизайнер\\nComment[ru]=Разработка и настройка бизнес схем для Ананаса" diff --git a/build/menus/kde/ananas-designer.desktop b/build/menus/kde/ananas-designer.desktop new file mode 100644 index 0000000..3444fe0 --- /dev/null +++ b/build/menus/kde/ananas-designer.desktop @@ -0,0 +1,11 @@ +[Desktop Entry] +Encoding=UTF-8 +Name=Дизайнер для Ананаса +Name[ru]=Дизайнер для Ананаса +Comment=Design and develop Ananas applications +Comment[ru]=Разработка и настройка бизнес схем для Ананаса +Exec=ananas-designer +Icon=ananas-designer.png +Terminal=false +Type=Application +Categories=Application;Development;X-Red-Hat; diff --git a/build/menus/kde/ananas.desktop b/build/menus/kde/ananas.desktop new file mode 100644 index 0000000..94fae8f --- /dev/null +++ b/build/menus/kde/ananas.desktop @@ -0,0 +1,11 @@ +[Desktop Entry] +Encoding=UTF-8 +Name=Ананас.Оперативный учет +Name[ru]=Ананас.Оперативный учет +Comment=Inventory management and accounting system +Comment[ru]=Складской и бухгалтерсий учет +Exec=ananas +Icon=ananas-32x32.png +Terminal=false +Type=Application +Categories=Application;Office;X-Fedora; diff --git a/build/win32/AnanasInstall.iss b/build/win32/AnanasInstall.iss new file mode 100644 index 0000000..2560b1f --- /dev/null +++ b/build/win32/AnanasInstall.iss @@ -0,0 +1,247 @@ +; Inno Setup Installation Script. +; Version 5+ of Inno Setup required +; (c) Leader InfoTech, 2004 +; (c) Valery Grazdankin ( leader ), 2004 +; (c) patched by Andrey Paskal, 2005 +; (c) patched by Grigory Panov, 2005-2007 + +[Languages] +Name: Russian; MessagesFile: "compiler:languages\Russian.isl" +Name: English; MessagesFile: "compiler:default.isl" + +[Setup] +SourceDir=..\..\ +AppName=Ananas +AppVersion=0.9.5 +AppVerName=Ananas 0.9.5 + +AppPublisher=Ananas Team +AppPublisherURL=http://ananas.lrn.ru, http://www.leaderit.ru/page=ananas +AppSupportURL=http://ananas.lrn.ru, http://www.leaderit.ru/page=ananas +AppUpdatesURL=http://ananas.lrn.ru, http://www.leaderit.ru/page=ananas +DefaultDirName={pf}\Ananas +DefaultGroupName=Ananas +AppCopyright=Copyright c 2002-2007 Leader InfoTech, Ananas Team +DisableProgramGroupPage=yes +AllowNoIcons=yes +LicenseFile=COPYING.RU.cp1251 +InfoBeforeFile=build\win32\secondstep.txt +Compression=lzma +SolidCompression=yes +OutputDir=.\ +OutputBaseFilename=Ananas-Setup-0.9.5 + +[Components] +Name: "designer"; Description: "Äèçàéíåð"; Types: full compact custom +Name: "runtime"; Description: "Àíàíàñ"; Types: full compact custom +;Name: "webengine"; Description: "Âåá ñëóæáà"; Types: full compact custom +Name: "doc"; Description: "Äîêóìåíòàöèÿ"; Types: full custom +;Name: "doc\user"; Description: "Ðóêîâîäñòâî ïîëüçîâàòåëÿ"; Types: full custom +;Name: "doc\designer"; Description: "Îïèñàíèå äèçàéíåðà"; Types: full custom +;Name: "doc\script"; Description: "Îïèñàíèå âñòðîåííîãî ÿçûêà"; Types: full custom +;Name: "sources"; Description: "Source code"; Types: full custom +;;Name: "sqlservers"; Description: "Database SQL servers"; Types: full custom +;;Name: "sqlservers\mysql"; Description: "MySQL Database servers"; Types: full custom +;;Name: "sqlservers\postgres"; Description: "PostgreSQL Database servers"; Types: full custom +;Name: "acrobat"; Description: "Ïðîãðàììà ïðîñìîòðà äîêóìåíòàöèè Acrobat Reader 6.0"; Types: full custom +Name: "applications"; Description: "Áèçíåñ-ñõåìû ïðîåêòà Àíàíàñ"; Types: full custom + +Name: "applications\inventory"; Description: "Îïåðàòèâíûé ó÷åò"; Types: full compact custom +Name: "applications\inventory_demo"; Description: "Îïåðàòèâíûé ó÷åò. Äåìî."; Types: full custom +Name: "extensions"; Description: "Ðàñøèðåíèÿ (ïëàãèíû)"; Types: full custom +Name: "extensions\text"; Description: "Äëÿ ðàáîòû ñ òåêñòîâûìè ôàéëàìè"; Types: full custom +Name: "extensions\xml"; Description: "Äëÿ ðàáîòû ñ XML"; Types: full custom +Name: "extensions\meta"; Description: "Äëÿ äîñòóïà ê ìåòàäàííûì"; Types: full custom +Name: "extensions\sql"; Description: "Äëÿ âûïîëíåíèÿ SQL çàïðîñîâ â îò÷åòàõ"; Types: full custom +Name: "extensions\service"; Description: "Äëÿ äîñòóïà ê ðàçëè÷íûì ñëóæåáíûì ôóíêöèÿì"; Types: full custom +Name: "extensions\dateservice"; Description: "Äëÿ ðàáîòû ñ äàòàìè"; Types: full custom +Name: "extensions\minicalc"; Description: "Êàëüêóëÿòîð"; Types: full custom +Name: "mysql"; Description: "Ñåðâåð áàç äàííûõ MySQL"; Types: full compact custom; Flags: fixed +Name: "office"; Description: "Ïîäñèñòåìà îò÷åòîâ"; Types: full compact custom; Flags: fixed +Name: "office\ooo"; Description: "Èñïîëüçîâàòü OpenOffice.org"; Types: full compact custom; Flags: exclusive; +Name: "office\mso"; Description: "Èñïîëüçîâàòü Microsoft Office"; Types: full compact custom; Flags: exclusive; + +[Tasks] +Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"; +Name: "quicklaunchicon"; Description: "{cm:CreateQuickLaunchIcon}"; GroupDescription: "{cm:AdditionalIcons}"; + +[Files] +Source: "build\win32\setuplogo.bmp"; DestDir: {tmp}; Flags: dontcopy +;Source: "doc\*"; DestDir: "{app}\doc"; Components: doc; Flags: ignoreversion +Source: "src\designer\ananas-designer.exe"; DestDir: "{app}"; Components: designer; Flags: ignoreversion +;Source: "src\designer\testwrite.cfg"; DestDir: "{app}\applications\test"; Flags: ignoreversion +Source: "src\ananas\ananas.exe"; DestDir: "{app}"; Components: runtime; Flags: ignoreversion +;Source: "src\administrator\ananas-administrator.exe"; DestDir: "{app}"; Flags: ignoreversion +Source: "src\plugins\ananasplugin.dll"; DestDir: "{app}\designer"; Flags: ignoreversion +;Source: "src\plugins\rcplugin.dll"; DestDir: "{app}\designer"; Flags: ignoreversion +;Source: "src\webengine\ananas-webengine.exe"; DestDir: "{app}"; Flags: ignoreversion +;Source: "src\ananas\bkground.jpg"; DestDir: "{app}"; Flags: ignoreversion +;Source: "src\designer\my.rc"; DestDir: "{app}"; Flags: ignoreversion +Source: "src\lib\ananas.dll"; DestDir: "{app}"; Flags: ignoreversion +Source: "COPYING.RU.cp1251"; DestDir: "{app}"; Flags: ignoreversion +Source: "build\win32\README.CP1251"; DestDir: "{app}"; Flags: ignoreversion +Source: "translations\*.qm"; DestDir: "{app}\translations"; Flags: ignoreversion +Source: "src\designer\templates\*.*"; DestDir: "{app}\templates"; Components: designer; Flags: ignoreversion +;Source: "src\webengine\tpl\*.*"; DestDir: "{app}\tpl"; Flags: ignoreversion +;;;Source: "*"; Excludes:"*.exe,*.dll,*.lib,*.~*,.qmake.cache,*.tds,*.obj,CVS\*,tmp\*"; DestDir: "{app}\sources"; Flags: ignoreversion recursesubdirs +;Source: "c:\mysql\*"; DestDir: "{app}\mysql\"; Flags: ignoreversion recursesubdirs + +Source: "applications\inventory\*.*"; DestDir: "{app}\applications\inventory"; Components: applications; Flags: ignoreversion + +Source: "src\extensions\aexttext.dll"; DestDir: "{app}\extensions"; Components: extensions\text; Flags: ignoreversion; +Source: "src\extensions\aexttext.lib"; DestDir: "{app}\extensions"; Components: extensions\text; Flags: ignoreversion; +Source: "src\extensions\aextxml.dll"; DestDir: "{app}\extensions"; Components: extensions\xml; Flags: ignoreversion; +Source: "src\extensions\aextxml.lib"; DestDir: "{app}\extensions"; Components: extensions\xml; Flags: ignoreversion; +Source: "src\extensions\aext_meta.dll"; DestDir: "{app}\extensions"; Components: extensions\meta; Flags: ignoreversion; +Source: "src\extensions\aext_meta.lib"; DestDir: "{app}\extensions"; Components: extensions\meta; Flags: ignoreversion; +Source: "src\extensions\aextsql.dll"; DestDir: "{app}\extensions"; Components: extensions\sql; Flags: ignoreversion; +Source: "src\extensions\aextsql.lib"; DestDir: "{app}\extensions"; Components: extensions\sql; Flags: ignoreversion; +Source: "src\extensions\aextservice.dll"; DestDir: "{app}\extensions"; Components: extensions\service; Flags: ignoreversion; +Source: "src\extensions\aextservice.lib"; DestDir: "{app}\extensions"; Components: extensions\service; Flags: ignoreversion; +Source: "src\extensions\aextdateservice.dll"; DestDir: "{app}\extensions"; Components: extensions\dateservice; Flags: ignoreversion; +Source: "src\extensions\aextdateservice.lib"; DestDir: "{app}\extensions"; Components: extensions\dateservice; Flags: ignoreversion; +Source: "src\extensions\aextminicalc.dll"; DestDir: "{app}\extensions"; Components: extensions\minicalc; Flags: ignoreversion; +Source: "src\extensions\aextminicalc.lib"; DestDir: "{app}\extensions"; Components: extensions\minicalc; Flags: ignoreversion; +Source: "c:\Qt\lib\qtmtnc321.dll"; DestDir: "{app}"; Flags: ignoreversion +Source: "c:\Qt\lib\qsa110.dll"; DestDir: "{app}"; Flags: ignoreversion +Source: "c:\Qt\plugins\designer\qseditorplugin.dll"; DestDir: "{app}\designer"; Flags: ignoreversion + +Source: "c:\Qt\plugins\sqldrivers\*.dll"; DestDir: "{app}\sqldrivers"; Flags: ignoreversion +;if qsqlmysqlu exist in c:\Qt\3.2.1noncommercial\plugins\sqldrivers, replaced it with src\plugins\mysql +Source: "src\plugins\mysql\qsqlmysqlu.dll"; DestDir: "{app}\sqldrivers"; Flags: ignoreversion + +Source: "..\MySQL\MySQL Server 4.1\bin\libmysql.dll"; DestDir: "{app}"; Flags: ignoreversion +;Source: "c:\qt\3.2.1noncommercial\bin\pq.dll"; DestDir: "{app}"; Flags: ignoreversion +;Source: "c:\qt\3.2.1noncommercial\bin\cc3250.dll"; DestDir: "{app}"; Flags: ignoreversion +;Source: "c:\qt\3.2.1noncommercial\bin\cc3250mt.dll"; DestDir: "{app}"; Flags: ignoreversion +Source: "c:\Borland\bcc55\Bin\cc3250.dll"; DestDir: "{app}"; Flags: ignoreversion +Source: "c:\Borland\bcc55\Bin\cc3250mt.dll"; DestDir: "{app}"; Flags: ignoreversion +;Source: "c:\qt\bin\linguist.exe"; DestDir: "{app}"; Flags: ignoreversion + +Source: "icons\a-system.ico"; DestDir: "{app}"; Flags: ignoreversion; +Source: "icons\ananas-designer.ico"; DestDir: "{app}"; Flags: ignoreversion; +Source: "icons\manual.ico"; DestDir: "{app}"; Flags: ignoreversion; + +Source: "build\win32\makerc.bat"; DestDir: "{app}"; Flags: ignoreversion; +Source: "build\win32\makemysqlini.bat"; DestDir: "{app}"; Flags: ignoreversion; +Source: "applications\inventory\wininstall.bat"; DestDir: "{app}"; Components: applications\inventory; Flags: ignoreversion; +Source: "applications\inventory\demowininstall.bat"; DestDir: "{app}"; Components: applications\inventory_demo; Flags: ignoreversion; + + +Source: "..\MySQL\*"; DestDir: {app}; Flags: ignoreversion recursesubdirs; Components: mysql + +Source: "..\7-zip\7z.exe"; DestDir: {app}; Flags: ignoreversion recursesubdirs; +Source: "..\7-zip\Codecs\copy.dll"; DestDir: "{app}\Codecs"; Flags: ignoreversion recursesubdirs; +Source: "..\7-zip\Codecs\deflate.dll"; DestDir: "{app}\Codecs"; Flags: ignoreversion recursesubdirs; +Source: "..\7-zip\Formats\zip.dll"; DestDir: "{app}\Formats"; Flags: ignoreversion recursesubdirs; + +Source: "..\doc\*.pdf"; DestDir: "{app}\doc"; Flags: ignoreversion recursesubdirs; Components: doc + +; NOTE: Don't use "Flags: ignoreversion" on any shared system files +[INI] +Filename: "{app}\lit.url"; Section: "InternetShortcut"; Key: "URL"; String: "http://ananas.lrn.ru" + +[Icons] +Name: "{group}\Àíàíàñ.Îïåðàòèâíûé ó÷åò"; Components: runtime; Filename: "{app}\ananas.exe"; IconFilename: "{app}\a-system.ico" +Name: "{group}\Àíàíàñ.Äèçàéíåð"; Components: designer; Filename: "{app}\ananas-designer.exe"; IconFilename: "{app}\ananas-designer.ico" +Name: "{group}\Àíàíàñ.Ðóêîâîäñòâî ïîëüçîâàòåëÿ"; Components: doc; Filename: "{app}\doc\ananas-inventory-user-manual.pdf"; IconFilename: "{app}\manual.ico" +Name: "{group}\Àíàíàñ.Ðóêîâîäñòâî ïðîãðàììèñòà"; Components: doc; Filename: "{app}\doc\ananas-designer-quick-start.pdf"; IconFilename: "{app}\manual.ico" +Name: "{group}\{cm:UninstallProgram,Ananas}"; Filename: "{uninstallexe}"; AfterInstall: ananasAfterInstall +Name: "{userdesktop}\Àíàíàñ.Îïåðàòèâíûé ó÷åò"; Components: runtime; Filename: "{app}\ananas.exe"; Tasks: desktopicon; IconFilename: "{app}\a-system.ico" +Name: "{userdesktop}\Àíàíàñ.Äèçàéíåð"; Components: designer; Filename: "{app}\ananas-designer.exe"; Tasks: desktopicon; IconFilename: "{app}\ananas-designer.ico" +Name: "{userappdata}\Microsoft\Internet Explorer\Quick Launch\Ananas"; Filename: "{app}\ananas.exe"; Tasks: quicklaunchicon; IconFilename: "{app}\a-system.ico" +Name: "{group}\Àíàíàñ â èíòåðíåòå"; Filename: "{app}\lit.url" + +[Registry] +Root: HKLM; Subkey: "Software\ananasgroup"; Flags: uninsdeletekeyifempty +Root: HKLM; Subkey: "Software\ananasgroup\ananas"; Flags: uninsdeletekey +Root: HKCU; Subkey: "Software\ananasgroup"; Flags: uninsdeletekeyifempty +Root: HKCU; Subkey: "Software\ananasgroup\ananas"; Flags: uninsdeletekey +Root: HKLM; Subkey: "Software\ananasgroup\ananas\groups"; ValueType: string; ValueName: "0"; ValueData: "Áèçíåñ-ñõåìû ïðîåêòà Àíàíàñ" +Root: HKLM; Subkey: "Software\ananasgroup\ananas\groups\0"; Components: applications\inventory; ValueType: string; ValueName: "0"; ValueData: "{app}\applications\inventory\inventorywin.rc" +Root: HKCU; Subkey: "Software\ananasgroup\ananas\groups"; ValueType: string; ValueName: "0"; ValueData: "Áèçíåñ-ñõåìû ïðîåêòà Àíàíàñ" +Root: HKCU; Subkey: "Software\ananasgroup\ananas\groups\0"; Components: applications\inventory; ValueType: string; ValueName: "0"; ValueData: "{app}\applications\inventory\inventorywin.rc" +Root: HKLM; Subkey: "Software\ananasgroup\ananas\groups\0"; Components: applications\inventory_demo; ValueType: string; ValueName: "1"; ValueData: "{app}\applications\inventory\inventory-demowin.rc" +Root: HKCU; Subkey: "Software\ananasgroup\ananas\groups\0"; Components: applications\inventory_demo; ValueType: string; ValueName: "1"; ValueData: "{app}\applications\inventory\inventory-demowin.rc" +Root: HKCU; Subkey: "Software\ananasgroup\ananas\config\variables"; Components: office\mso; ValueType: string; ValueName: "defaultOffice"; ValueData: "MSO" +Root: HKCU; Subkey: "Software\ananasgroup\ananas\config\variables"; Components: office\ooo; ValueType: string; ValueName: "defaultOffice"; ValueData: "OOO" + + +[Run] +Filename: "{app}\ananas.exe"; Components: runtime; Description: "{cm:LaunchProgram,Àíàíàñ.Îïåðàòèâíûé ó÷åò}"; Flags: nowait postinstall skipifsilent +FileName: "{app}\MySQL Server 4.1\bin\mysqld-nt.exe"; Parameters: "--install MySQLAnanas ""--defaults-file={app}\mysqls~1.1\my.ini"" "; Components: mysql; Flags: runhidden; StatusMsg: "Óñòàíîâêà MySQL..." +FileName: "net"; Parameters: "start MySQLAnanas"; Components: mysql; Flags: shellexec runhidden + +;FileName: "{app}\MySQL Server 4.1\bin\mysqladmin.exe"; Parameters: "-u root create ananas_system"; Components: mysql; Flags: runhidden; StatusMsg: "Óñòàíîâêà MySQL... Ñîçäàíèå ÁÄ ananas_system" + +FileName: "{app}\MySQL Server 4.1\bin\mysqladmin.exe"; Parameters: "-u root create ananas_inventory"; Components: mysql applications\inventory; Flags: runhidden; StatusMsg: "Ñîçäàíèå ÁÄ ananas_inventory" +FileName: "{app}\wininstall.bat"; Components: applications\inventory; Parameters: """{app}\MySQL Server 4.1\bin"" ""{app}\applications\inventory\"""; Flags: shellexec runhidden; +FileName: "{app}\makerc.bat"; Components: applications\inventory; Parameters: """{app}\applications\inventory"" ""{app}\applications\inventory\inventory.cfg"" ""{app}\applications\inventory\inventorywin.rc"""; Flags: shellexec runhidden; + +FileName: "{app}\MySQL Server 4.1\bin\mysqladmin.exe"; Parameters: "-u root create ananas_inventory_demo"; Components: mysql applications\inventory_demo; Flags: runhidden; StatusMsg: "Ñîçäàíèå ÁÄ ananas_inventory_demo" +FileName: "{app}\demowininstall.bat"; Components: applications\inventory_demo; Parameters: """{app}\MySQL Server 4.1\bin"" ""{app}\applications\inventory\"""; Flags: shellexec runhidden; +FileName: "{app}\makerc.bat"; Components: applications\inventory_demo; Parameters: """{app}\applications\inventory"" ""{app}\applications\inventory\inventory-demo.cfg"" ""{app}\applications\inventory\inventory-demowin.rc"""; Flags: shellexec runhidden; + + +FileName: "{app}\makemysqlini.bat"; Parameters: """{app}\MySQL Server 4.1\"" ""{app}\MySQL Server 4.1\Data\"" ""{app}\MySQL Server 4.1/my.ini"""; Flags: shellexec runhidden; + + +[UninstallRun] +FileName: "net"; Parameters: "stop MySQLAnanas"; Components: mysql; Flags: runhidden; StatusMsg: "Îñòàíîâêà MySQL..." +FileName: "{app}\MySQL Server 4.1\bin\mysqld-nt.exe"; Parameters: "--remove MySQLAnanas"; Components: mysql; Flags: runhidden; StatusMsg: "Óäàëåíèå MySQL..." + +[UninstallDelete] +Type: files; Name: "{app}\lit.url" +Type: files; Name: "{app}\ananasplugin.dll" +Type: filesandordirs; Name: "{app}\MySQL"; Components: mysql + +[Code] +// +procedure InitializeWizard(); +var + SplashImage: TBitmapImage; + SplashForm: TForm; + SplashFileName: String; +begin + + SplashFileName := ExpandConstant('{tmp}\setuplogo.bmp'); + ExtractTemporaryFile(ExtractFileName(SplashFileName)); + + SplashForm := TForm.create(nil); + with SplashForm do + begin + BorderStyle := bsNone; + Position := poScreenCenter; + // Adjust the height and width of the SplashForm + // to the size of our splash image + ClientWidth := 400; + ClientHeight := 244; + end; + + SplashImage := TBitmapImage.Create(SplashForm); + with SplashImage do + begin + Bitmap.LoadFromFile(SplashFileName); + Stretch := true; + Align := alClient; + Parent := SplashForm; + end; + + with SplashForm do + begin + Show; + Repaint; + Sleep(1000); + Close; + Free; + end; +end; + + +procedure ananasAfterInstall(); +begin + { copy files } + FileCopy( ExpandConstant('{app}\designer\ananasplugin.dll'), ExpandConstant('{app}\ananasplugin.dll'), false); + +end; + diff --git a/build/win32/AnanasUpgrade.iss b/build/win32/AnanasUpgrade.iss new file mode 100644 index 0000000..00db3cf --- /dev/null +++ b/build/win32/AnanasUpgrade.iss @@ -0,0 +1,135 @@ +; Inno Setup Installation Script. +; Version 5+ of Inno Setup required +; (c) Leader InfoTech, 2004 +; (c) Valery Grazdankin ( leader ), 2004 +; (c) patched by Andrey Paskal, 2005 +; (c) patched by Grigory Panov, 2005 +; (c) patched by Alexey Chernov, 2006 + +[Languages] +Name: Russian; MessagesFile: "compiler:languages\Russian.isl" +Name: English; MessagesFile: "compiler:default.isl" + +[Setup] +SourceDir=..\..\ +AppName=Îáíîâëåíèÿ Ananas +AppVersion=0.9.3 +AppVerName=Îáíîâëåíèå Ananas 0.9.3 +AppPublisher=Ananas Team +AppPublisherURL=http://ananas.lrn.ru, http://www.leaderit.ru/page=ananas +AppSupportURL=http://ananas.lrn.ru, http://www.leaderit.ru/page=ananas +AppUpdatesURL=http://ananas.lrn.ru, http://www.leaderit.ru/page=ananas +DefaultDirName={pf}\Ananas +DefaultGroupName=Ananas +DirExistsWarning=No +AppCopyright=Copyright c 2002-2006 Leader InfoTech, Ananas Project Team +DisableProgramGroupPage=yes +AllowNoIcons=yes +LicenseFile=COPYING.RU.cp1251 +Compression=lzma +SolidCompression=yes +OutputDir=.\ +OutputBaseFilename=Ananas-Update-0.9.3 + +[Files] +Source: "build\win32\setuplogo.bmp"; DestDir: {tmp}; Flags: dontcopy +Source: "src\designer\ananas-designer.exe"; DestDir: "{app}"; +Source: "src\ananas\ananas.exe"; DestDir: "{app}"; +Source: "src\plugins\ananasplugin.dll"; DestDir: "{app}\designer"; Flags: ignoreversion +Source: "src\plugins\ananasplugin.dll"; DestDir: "{app}"; Flags: ignoreversion +Source: "src\lib\ananas.dll"; DestDir: "{app}"; Flags: ignoreversion +Source: "COPYING.RU.cp1251"; DestDir: "{app}";DestName:"License.txt" ; Flags: ignoreversion +Source: "translations\*.qm"; DestDir: "{app}\translations"; Flags: ignoreversion +Source: "c:\Qt\3.2.1noncommercial\lib\qsa110.dll"; DestDir: "{app}"; Flags: ignoreversion + +[Code] +// +var +ananas_path:string; + function InitializeSetup(): Boolean; + begin + if RegKeyExists(HKLM,'Software\ananasgroup\ananas')=false + then + begin + Result := MsgBox('Íå íàéäåíà óñòàíîâëåííàÿ âåðñèÿ Ananas. Ïðîäîëæèòü?', mbConfirmation, MB_YESNO) = idYes; + if Result = False + then + MsgBox('Óñòàíîâêà îòìåíåíà', mbInformation, MB_OK); + end + else + Result:=True; + end; +procedure InitializeWizard(); +var + SplashImage: TBitmapImage; + SplashForm: TForm; + SplashFileName: String; + uninsPath:string; + + ErrorCode:integer; + +begin +{ if RegValueExists(HKLM,'Software\ananasgroup\ananas','UninstallString')=true + then + begin + if MsgBox('Íàéäåíà óñòàíîâëåííàÿ âåðñèÿ Ananas. Óäàëèòü?', mbConfirmation, MB_YESNO)= idYes then + begin + RegQueryStringValue(HKLM,'Software\ananasgroup\ananas', 'UninstallString',UninsPath); + if not InstExec(ExpandConstant(UninsPath), '', '', True, False, SW_SHOWNORMAL, ErrorCode) + then + MsgBox('Script.NextButtonClick:' #13#13 'The file could not be executed. ' + SysErrorMessage(ErrorCode) + '.', mbError, MB_OK); + end; + end; } + + { if RegKeyExists(HKLM,'Software\ananasgroup\ananas')=false + then + if MsgBox('Íå íàéäåíà óñòàíîâëåííàÿ âåðñèÿ Ananas. Ïðîäîëæèòü?', mbConfirmation, MB_YESNO)= idYes then + else ; } + + SplashFileName := ExpandConstant('{tmp}\setuplogo.bmp'); + ExtractTemporaryFile(ExtractFileName(SplashFileName)); + SplashForm := TForm.create(nil); + with SplashForm do + begin + BorderStyle := bsNone; + Position := poScreenCenter; + // Adjust the height and width of the SplashForm + // to the size of our splash image + ClientWidth := 400; + ClientHeight := 244; + end; + SplashImage := TBitmapImage.Create(SplashForm); + with SplashImage do + begin + Bitmap.LoadFromFile(SplashFileName); + Stretch := true; + Align := alClient; + Parent := SplashForm; + end; + with SplashForm do + begin + Show; + Repaint; + Sleep(1000); + Close; + Free; + end; +end; +Procedure CurPageChanged(CurPage: Integer); +begin + Case CurPage of wpFinished: + begin + if FileExists(WizardDirValue+'\unins001.exe') + then + DeleteFile(WizardDirValue+'\unins001.exe'); + if FileExists(WizardDirValue+'\unins001.dat') + then + DeleteFile(WizardDirValue+'\unins001.dat'); + end; + end; +end; +//procedure ananasAfterInstall(); +//begin + { copy files } +// FileCopy( WizardDirValue+'\designer\ananasplugin.dll', WizardDirValue+'\ananasplugin.dll', false); +//end; diff --git a/build/win32/setuplogo.bmp b/build/win32/setuplogo.bmp new file mode 100644 index 0000000000000000000000000000000000000000..a0053c6dfa73e4623d81209eeb834c9ae0d062d1 GIT binary patch literal 292856 zcmeEvXH-;8*6!T3?w`BvzdIw{O%?>RC>fC)C4=OglM*H8peQOLK|stIQH+>TQ8DLC zFe``>%z_A&%%tyY_zeQ`NN}>U5uOjcxmr|L0%eKTY(% zN$7v8{>NYb@&*0>|M&|Zo&WNebEyCS{O`Zu|6v04}1vaUM zH0niNw1{rh3_c?7QY+A)K^!>?&a-_Vb` zI5)acC-{hx$Not^d#C#Bo$Rt(C*+7$=!t2ryC%78Qw=(zn{;0;_$uGENzScF$@#RD zMcovqy_!A;XFApx`)*cq+bCtSM%H+(y!mDYn;JErqcc3}C)n;%@i?5d^IP=#E=8*y z6ZF=r7;M$hO<9rTac=#eO|t&=FUo(Y2L9Ie-%I5mn*rg$}ul=<2&Yrv`%w-qU_oxHLr#5+#=z8kLP?#%KM=ptVL=5L%oDM`mwi7PqvC$hF!H>1(3z=j2TUWcX6^hDx8utUmpbLy z<egJPcQnm zRr(#f)ayEtjnjON7$)9!TKd8TgtbIxs2n5zq6cgxv)hyNhym zO_Ij-6D+q+Fkh==Q8~?Fiz-zboW2 z6SA3E8O)57{t4k7eAnBO_BUi*?npabkhD9`x46c)dn9mwjHHb3c1t?ARWj!J#IWn? zkvH@f-g7N{IxoL@c1+W>fa9L4-X?Az@LSxh8+vZC-#IDkqmsH+N;U^41mEL(+~L_a zN!wnKHa{mYI4ozdMZu_Yyh(|?MJ0buwLq(quenvh27OIvMY?`3T3 zPu%rg%dcKZzht6zQA&8=xpkiZv@HBn^Y%OY?-}?nm;v#Bs>JvHyRYXzG&-VJGm<_i z1$Rwc@O^SFqm|9f&SKP)zbS`3k#xT)Wp_i${<^@XiEn#>H}?k5?h)U;jqh0w3_4E=t*5kTg9fm~&WKXQQlc$#|n;IpbA4&6Rw$)qJ%YW$R<+$+taMybRs& z9!Zv6{Jpd-UlVtKHw->9(YRD)&f@B9ucqH`Wc|55diZy*m*4#V4Q7Dom0kg(p88>O zNS9J{-|RfbB!^K;ADk86p%nB$(&@UC)paSGD*~&FeCx|Rs~bG~7D=}@zRMk+%T4Lv z$C3*k%LHAT7IDqK;Ehk|m$0pa&a2*Py?j1XnQD`Q4h~*X5l~O|jpr;(2m< zWQ%;rBZ1pxDaQ+PR_CSk4@qgRkDrF>F}c{U;7uB7ud8QZHewpaKj7x)&J`PTP%wylyb zEdrN&JeONC(Jy5dzK{*LsuF+Cx%5N8+P<(_CSc2;L)k~a>i*OkCTtsHlGmf;ePyE4 zndvU*brK9F?3gzhwDtA`d?MWe{d%M zpxeKS)o+~NGvGt?YFa*Hu!J$p|DYB5Ts!2gal&WE#X~09!|JIYkz^?c-j;E^tYCLl z&h9GT?1I4dGT-I_maH~u_hy-Zwu!kPr)IpH81cYx(QDrgUqZJ1n7@Y!sTp>t`r)^3 zFr}99sbpqGK9#dQGQsY|REHx|9S=_px;-WAk(}2xsd*Qqtj|g69hA}p$>OOONoZE{ z)OPTv?i9@0H^t_pdCGm8l^sFr-h1U;HS*l$6mmEq>#C05K_}1Dv(@hCjrVgK{5E9U zZq9RPT<7-({`CB^%6@75y*z%;z&|hpzt_?~Flm1@gy@yZLPjHT*kb9h+2UT!i0687 z-8QA)oj|gNw93*Yc+CpJ05XASKkt>S@3YDCU#aGPGAJ81TG~Hn>5#=L#;cME-pI_aW!yF}dQ1DQiod&7GRFDe z$GcpTve-Y}?SzKcQB}_qGehrdE_kfwe|?hUMOpJx(z-jOw2CBV=KXd065gEce4T^* zDSLU-56I81*AKs{6MuiY*)cVnJtp3@mYzEdJ$6`l6cwaIgm{?lTIzIe{U6y}{Wn>D zzlZsI2F99!e;aA~<-HQoD@p72iN4*cu^+S(KbvKD8Ku6`ig-3B_^nA|k5&Fh|=zd+=tVv*UPT+Ed@6{pU^-enY-Gulqjm7;Y<&6H);aN+V*((^g zawd2k6TX9S*}@nvA22WMw<}@va{CnAo8+x_sd}8y@;jjyc*ZFDncnl{_J+G*&vZHCoa4a>rH zOM;HB_CCAr&-p6+Ia!Uhl7HKO&%mF328dqqO&;>CUMl%^sKxebCw?%?dZ(ZGOvC@F zS;jky^fwk6Z;f-_=_ez}dJK{ka8uFkinQegfz?^QSF1$uk8vU21o7V{r}XJ9`=P&z zQORQ_EoO9#iF&v-tl^Th7zoz}MKrSKiH^wpUVZzl_#lWrIc~-9yt& z*G@JqlbMxUmFanD)1Q5kfBBcdzRe{1xmomUlbEL#8E=fUUd@hrp&8Mp9)cw6hNAmbDYJ_L^UDJ7c8SQraSH|| z6Ne_J_Zuu9(l2II^O-428I@&>)hfmo9jh6;HH^WE0o{ym#*2n^v%bv?zoF(_uNiuJ zPWUfhD-(&p$Is-(nr1k5ijL%D( z+?SvCYD&y|{p_#yOL}Y;J+sSyY?b)PBenJ?*&t=UPtmeo$zrdh=ElFNlt`P_ zDwrJ?s2t!=+as7(CprC~jC#Fb!n(gHuFx`!J6Ph;h`yc!&ti!_jy391+^jZ;d+_p? zIHHLF84&QpV56a`#>o4VeRQBWN@HOD4*5L;|LHS8^h%($P1>Md+W5Sj#XWh~7t`av znCENs`vdF-nS=)-;;K`!`EmK=%15x zZs+;`kO&_XBz#v+`mA3tpud<=%3u@<8Kou6#HGWEOVF38f9MnpX)GF^o%_RL>5xf& zk6u)ZVeI8OiFf8EwYjexwnKM|vELNjnkCIo$yqf_cDOXz;i9a5y`<*$DbA-nKBOQRt29fX)u)@Va zqBz~~{wWJqFyvqLN6=_qymLUv-Y5zVl5Ru;=jD2TdR%rS4N+JYjSgWH|53d^U2+_R zGeCU)2+kkz`6=V*M86$=&j8E-)hpd?(sOppnl#8-UY%fbX@dI`jg-$W%RajV;>LWU#~ z2gWCSnw|S?Qu?rTA|tn$5hOAEY(_ednU?WGGk;L6fH7Xe*cN^@%Y9?NtlgpDrAhj0 z+q^-KG6vlkYDRxkaBh_}yC`RUZL;$XmB2?TZa36?&saw_X}cbmnN`c5vYkJ%T5{4_ zdDXq@8abO5d7fQ|YaG;u9B63B!c_{_z;>twQBRl$Rx3s|VAs?D&Y(XhD}^}hqxIMV z&#Zc%Mn|>J={4x^MGc&Spb_mNvEB_VD^Nw$7L@|gwvZA{%4(62gJ=q9Lpbyjy=DC= z2N)p1=dxfe<;0n5AU87Pk@zH>jsj1Y2r^}hEi66|7?n{tC=!d%=x~0)7CW={QGXG} zNG(D`IGhnl@%)ImaRf$;=&40ZH8&S-pBWlcveemsS1G zPYu1Nm;c^>?HA9L-Scw0+zJP@0-nel9GU8MZIT;$QoT`W-j&H-_f>rSQ`bo-trkoyclRnfv)1d(8n2Nn1Q#!?I$=f7+F1ko!VYW*9Pz0*?ipsqzqEBm<;L2_}24@ojY1K=b9hWgUpi2Awt{gg`Qf&z&#Pj{ zrRbYYR*zlofM@BT-7-cawqMb;P1@wLlHL6oez%NL9=k7o?2vHHD(b`>k2+<84U)6g z^QKm*>MSnHnGZkL087XhRoTf(FS>`p`vh3PBZ>&W;`Bvi3ySP0kQ>-xU7^xIASWt8 zk?Kp`YnD20TkNoF={$7avBYs#q0@n4*L^Ep>sGkbE_2>nS zd9ZxYCjtnKY_7bIul7XtGu1xqCJpDRK#~gzhRMT9LyZQsqa&2)5C}IqM$`)qcwZ+n zMsC#s2tK$5!lb>V0MP)CuJ$-y;fa(MiSUs!B*k8&fz%iX;Dgp3iKVkjkueU&hh889 z8L=nZg@=IcY2egNH`D(LG*~C;xBIKmN5 z0`cJj;S!^<7Is?LkzzZW7mUIKCE{`+JA$GFun#vhk&F~v#3Do!MHbf{!FKF$dOtX0 zv!w2EnYmZwEYD7HKd&AA+90J}KkmNT{Kxvay@5!wmUqpKZJ!g}J;~vcyndas1OFFjkT;A|KJ9*x{5}th$p5Mlqypu3|!Lx7Y`wdD2 zFn#=g<}H^HOiyE;upAbH_CEYDv`!-i%U9=YoyPB9D~19YR~6Qjeop zCD7dB-2%)u+aQY^EMP>N9Qt|@3wde4h>8?MuhMH@vD=O%^ETu@Y+0UcxjJ=jdCJ_%G^^?i>kT=!I|>{R6uY5a*@0qr zL=5lH+>pv4%f2GlL#3c*NYjp#LD#`m;B&Cp6@{QSQb=@pXcY|SaH%`eH$)gwLYp^q zpau%uTjaVQ`LA+AQiF~o>dcTp=S$ z7zbt>8{rZ)I0xv3MED>+@G{{je8vb+HPFCrG!`xiIKiZCVJ{`a_L5hhp0N?aF($1S zd^sYDvcjAp1R4Z^1VS7B*s)CTSVoM9vv9dYGD0A6py2qDQxDMr5(j)HqlPRj6imfP z96}XOAWL2ZfzCgDvGBME0>xop9qwf!17u0E;2?CuyaWyT5Rx!74u=}a%m~jo9UhK| z=ZJw2z2YgA@+YsC(mpC}c}>CY(yZWn`Z?bW^WN&mwW-a2qL2rlofc_5vlsSEis+T{dMoYymhaXh;nF+K;>|d% z+Y&k#B<$Y_f*C;|NS0h2qq&qZsb=ifG0tllr>X&;ig&^5Ui+1_x)$DZ$bIONf8S&2 z1M}2Y^`M)E^KaQNd*xl$?Z0X$a&>P+>C1U>XDowv8#tFtGg&cSt7MktDto{36inNMWF1dF@^LYZQ73L5XGHhm0qYAVO%`>h_m@(8oTJCkQ%)4f# zcS*K$Lb!Q!uz9$@aj=(usF&V+AH7(AgX9q7v@ny52-EZk(}jVCY2l{Gk`!c=5{wRm z`~}9VQ|4~Yv)i}Q1$|Ly>mrA>nKtXPtk_7>F9s7%( zSdi9I6F>+9KZ)nsZ(q2r zE2`p=SL$*1_!|4r)yA%Qs^-}mrU_xeL6M0m%i=82wrA@i`LpN6g4|gL^4Xn43Ax;SckI%*<8TO4Cv zm1V!Bz_}#V2DNkNo8`imRH_nYTSrTowI^AY{uH(8~$K?rgkxxdLQCg@G zI-?_hf$5?JCX419A)!Ou4wkqbDfis9%z1sDLs=RIj5NuKG)9}fCDA4&NfzW-xzM~c z(V{fj5^ed=POl<$Zt+4hB$69*Yb;K@RS_`o7K(b(& zvC0DyL>3_wGFgN~e{hw-f+x!oixrk8;zr6417bAfhNXaA|Ckldh$|gu0Urzwup}L( zgzK7wEG{(G2kQobh0(Df1Oc2W0&37)*a(+|06OCaC;&9b zYybzW>X->eLtSK;q(Kw|+JqReB4mh#USc^WN*lKAj!>KtKM4N#+~%sAn@mpQ^`n&hWZ1$?U*H+XnQ0xKYw; zqvWT0nQuU{@_Nj3zN;;0pXl>oN^pm4P`8BTQwfzO^yOuVS%>*1%@cgSDJ@{6V;J=u zCU6Uru>VJ5U6*(1b<@}#bNp87`Yq85%rOpKtm~1b>9%N=LynqrkzT+quYya(2VQKu z`Z{~dX{UwjOnr;>U32vuGSw~PXBzo9+vxatS;U7}XGa*WTxfG~@7vdJckbRPT(RiTk^Lvn9B*hmaq8^J6Q_@#JaeMq3~Dzto@>~#eQjir zMQ*&^s$AD)Ii4wTP9grLE{;0x&U5@c4LzK7eOz?|-DammSmYw`#RnQ>Mi>_-S|Z6pZ?7FiZ%?fW*u2~) zH_0(&p>sr-V{nLbV2HDCpp##qQ&5;|K(LdWo0+Gpft#I1gqL2tuU=k+(dtwyG-F8B zk!Hdwr9}iwm&yXSlA*L&p%8TwEkjtwWPP&bIU*ddPh2C^4ccs7Kz4`~=EZz)Qc^Ow zrr5H=fh=LfM_7hLNmw-S2RDR6&+I555!;6HBo4%17{aAs8`ur;$Ki-D@W-XiaiB9G z#K%Jh0;G^p3c?3lFfoh+mt>4Up5S8@LPoG)1k4%JgE@rM#E#DpMLeMk`Qu*N1(#ee zW`Yq&BF-6eAiXSMB99~;z>;D4|tLTTd)z!6u4nP`aFZY z{*G}IOUB6*Nyx6?DQ*DCvbZ%Kc3H2HWEtdq)QoDL;(BGKMO&y%Kt%$vMR zV&*|fgWHq*K21(%WaAmF0w({&;E_k4YMNRr_FgEc+LvEev#4rUe)Z10^6j~0wYjCW zzKN?10xN7&&J@(NHotp!^4jg{-G`S|*X69(UQoJgaoOJ7mAi^di_6Lu$He(Y1sG+` zH_M7NO$#$l4K+>)F-i(DOb#;43^z^>F<2gNS&?a1mF-ZHW}hEzksfZ68DWAvlY$M= zeH_~PMa66S6!3fR4S*{jZ1tV)gk{~teu3O2frVV*vJ>=$Uge93~NM>ZcgvSVBA z`iixyR+bf(R<10sUR7FIRJmqlQBiL6{CP_kM;|@9ZSSFNTWi)=tuI|wwyeCWxU{0E zxNKQz`Ld-2$x(r(g$Y(07dh`L3#?uhwq)so6~#Ff)x~Qzlp(jGRR!@2L!DhrU0jS@ z-HhDaP3E~6IXN4mhO3(ioLvmuoMxkY*o<(Ks&t!u#qRsd{dZMF6c&V(tj@39x8u^) z%kR3ozI^@q>GS8$Up{~R_VvSu54UdL+EZ7Plp5vYY~oiv`t0t zk3s3ddV@8_tv%6Y$vWT)C3VW3arv`Lm*C*)BbtCP$tuOwinGv_Pl_F?2}*$EB_#%n zpYTCv!iQdxdM8lO27l6pap(|G8`l@$(89qMZbZ;vyMP89oQ05KtBhnJK0p;?!bGtS z1P5pk1z?8&4uk+DgB>Vg7%y=EWMpKWp-nlHTx14tjbj|zi$kCd!^bl~0D(N=My3VM zA_w5myofDsBiax`pa>0Or{H*!!NT%k)rrDl9Ks)7M2x@YDjFVk8PIe_vajRffgTUgpoYVcO!LL=~KdVOfYD7L$w!b20d|ui6(bUi< zGs9nM#`WliKcD4wd9qu>RG-VH8SNICFU@k^TV(ax=D#=3?nja}BjlAz@>j(SMk3^^ zgz-JzlsXBOBa&v1RKoiVvX~iJOh*0Sz|io|RnJ*A)is(1mAYo0EZhHtGydE_7>f(i zf&whUgXjADmUp^8c{=L^d(6p-wara%$W3!iM0=h<3tul|Hy1s3 z7dchHRV(aVjsDP0kE^WMduQ~W{8(`S$U{cJaHEdDOCF&h=z^YLR`YQ(O6 z+eX<%FI%3pg#=hEO?F&c=(C|Z>F|l#m+de6`o9Z(hKIj?{d)Ywk$ngDJZgP(@8P`% z%@6KBx{r=~58-_O(Y=<|M`_8SQGWX6X|}sodT*mtS1q)wJk!(| z9PZ)aG&{^)CvU!SRhkvLD@1R3%$&>&9tFl1 z0faH)M3^nnE46@Tvy3-W1Md7)b;sXiO2)~R@f3GRsy0a4Kag^GAnW{my!V$$;h$8a zIwpJEmNz*!!R6l6pvSWov>T=Lny0=pj=859@<=QGxpTpL+pKp+sc%iw-kGEG!uP6y zPiOc%RZsmsHJ_1;9pt&Z6X;%$nAtSm?zLI$Kxhe*SU=qRO`KlsJalGmc!_V;!Rmu8 zzbY(hYj1C_*}CrBnZw5$4%Hvqf8cQ4?tL}2`*!WCudCg=vuFMoFON-vKcl${5h^xB~@B8~(7o@val||pWe|bdT|I5YFW$96YCdFy?+sZ@2_?XGfswQ^2=%0x(8XH3gtY)h41%kJAaezRLr6wo(g4rnv1^`110OK5ARIT~ zfO%32;Vg2-2oTFUKngIjfBmr?PYCfLwagBg4TlgKh-VLYfnREHEe(&LZFjtCn0Y?97deMPs9IqMumdUdT?!5KPo2YKhNyF9bsa z0+=>r1RpY9LIzI=ScshvhBh~F8qST2-VZ9+o|@%**D||jTF|Y(s_*=pOofDOB~NLG zK(#?&d_&UWfsAd3z~+OTd(ZT!?kOH^@^;r0+-^?|y|26QxqViT%cA%8OTL(9zctP1 zabDDKk<~dn?yY*rbG7i7TA^>II^3V`-L9SSLt{BJDTSFB@J(-8zV5jPyvpw8Fap@qIXb4paQ3T`hpJ

C|laXR@7$EjU;n*KtLWnRa8v+9n z-Q96M$bp4ocVbkpRJ_kAJDfp#B)cUaR3jcp88`iH@}6;u)w~JYB&Qz}%(*5oyDu+*Kmf{!!9->HQ^o#J<0HTTB0!-vUY*zmj2_MIX#EdmR>i(o1+f!RwK{ z)2*o?uhc`{DB3npnD<&Ib5MUdqmeW)#s96m!&9F1E48Tpn0?HX?!jMH3Nc=}d^s^O zAvZt2@$5OVZWm9VIw8j4$l(JS=?h+o)vM}_Wl=G%+iR=D;JkU$-qHSAjKhoPPvgSe zwyi7vKKA~qx2I=GPQv~@TgBi!X=_QD?^c!<(t7Wb7`MOMRk9){AJ1%@lcS;zCfFKLNVjsMK z(IrIT6^qi5F5-iX(2H}ynU({rbIt+9Vg$VSg@A+u8_wAg0?tm)1Q`g>EF>LKQBLJZ zE}DgeU_cB)=Lfinu!Rr`ONNHs@YuP*;t}E0Y<6U!QFKCZEa@c~x$G324wFt1=mwn} z+(6;YA0qG;DPPUYk{6VV_0%=V^h@r1Yx@m(vo{M|azPfyQ>U`J6qr1f5RFp2;xn->who?{45+dE}wp9!aj5#iJKUk2HaP)w< zM2}mWlOo;9mqd4Uj`@xgy5+of`GOc>L_F7&EXs*--cgb9q37LLwEO$NZ&v!5NA05>?{HWXao~`k|>&j)gO`z+-UWY5F*GzR%{fE8avbB z114ceIkVM=Q`24&B4QzSz+sJ;2390&A?d)4`T#8Wu(@C!U@t@&Qb2SG4p`{eE+G^d zGVu|`;X*h*;6urfX(9OduL%Z6#NclS&W^&lT&$7hNtKY&gD5;Az{d?dKo}!RNAyY~ z^0})272S|4bAm2v1l}-6?Xq3mXPfs$YksGU;q7r#_DINA@Z?qs6l(-3=lDAJdHSv6 zUE4KdKF-Y^nw#6F9@#o8=)PH6kN*ZHd?Vvqf_{79yLMuST6`x`s_}NWc#y@tOBCM^!!J#c1)?8{jEj0bqI&t(+R#N2a zSI>Xy5gImDugZ@1K7X=KX!@yDQBt^}y7VWr(D3}}(Lst5@b_#kd@)DH9`WFJ3$^$cnq% zbZSJT$VF|<=ExxPWra7z2JcPU?^5b zs0GwU)EWEG*M%}CDaeS(nVmfn2z&?#ONQiyUfe}+=p`Uvi6fIkX&_G`o=E@c0Fi}L zRAht{fY0icW9hI?e7i>I9o^s?bAm6c2i-DA?y}DAwa)6*p8rN>?t^i&PD_kOZ^GyB z6sq~tPVjZE@r)iQc)Zby`C^*ZZ<79DM#z&%KCK4nU;MW)q1zePDrRo!5ADoum7v#( zZm(r+Z^@ZoR`G4u3GY?%dOmahr=%Jtzn)3m!z|dwY&eJR2mdL_`u44F`O@6$m&Luo zb^7Gd?3DTKV&A{oP*t3}(5FePUac-!wzguWNGXqQK6~007w)!uYkB|oF`pSgdX<^H zpl;XZ(ZM3uPuiMOqrBFyN`K!yrX1b4c6o7DLi_76H(&^_YSp6LIQKJ$Hi>!9{^5gr z$uU6}&W`y8;EAILqeHD%rrM(K{v1b-G~g=0XINu+nc-p?Ax*H-gk7u~v2bV9_{G8E zka8du0dDw9kwmZXrATVXMamO1q3MK1`iR zI*=|B!Ub|Pz!`aRiMW9fdYCqn9pVFL0*mb&B^-{oSQrhmU=AakvC2Ug*b;(E*~-ja%gn7DR!?}R==@yKyf6rX379b<}4G5a5isU(pC9=rMOUDv7=1$S>=8QX<9b>i@%jF{Ii#qF;) zRjn=% zE8VS|*U}Rs(GwJ7IUsv^QEo<*%jxX4h&nHDYtxC7wTZG=f za>uI_){poDFFX++R)sjh;g%@1a1OsjCcTwt!zQ}LLJ~w%pp6{6)QJVwyy)(ZONTvC zFUt*NP^32TCF#W>q!*ky1U6O(LJ|oHAXbzZ@}X{`;RG4R!qGqtZY&~g>Hwn?LWz*U z2yEa8G|@p(9iS-)6Hz{*fmDJpCh{Q%I|`5~k-!m@L_p}ch-z^lIFNQ>KvB7aHU~~Q zz~m5rNJR9?rxFUr2aC*JpR&H{8_cdYrs@W>vt{T*-;kJU`nz3^A3s@Jwfe!G z8)7_>Ugf1lp_?@^K5HwBQlnju*Hw%0sXtJ+bWw&F2lV-1;(X8T8&-WEdw=!5_kD6) zSXH^WeOg;fb6Sko*3~&;-gmlt`v$^6@0f|9WPo=D^MVcf**3e?Lw00`@e6JcfM5V!^jAyLH0fw1K9kU7zy3WJ$&a>2d?tempS zKx$D7t`dSBOyey!;BN?_6^F{Kenmc;l?ys5_p zT2}=IcVy;0Q4Hvo_k1tw*)8YRD&u}jIiN!=`G>)B#%u{=p7}#7s#7cWjrxK&vtm2- zvOhX5>vJplo^pse`jR=-!E9?CeD+@4M}%V)5of=8_3EaL8&QFCmY*BP4j)*!z`wQm z(a&9+WzFgp;bC?=x2+U&ciQ#tZSBr&gM))y)TjnhkJvC*w7(h{82fqAo}T$3o@K@2 z_GypXnv>?ctzDV?p=Zqd!G{m-$43RDo!BT2qL-yBaQ#5glltwc2P*^M!$DX)tS)g4VU>Y&aOH`YD^d~&fnwzRX{~WMu##!1LO2pG0)icc z;G|5rC}D&3rxigIOteORE)bDk4u>5Yn^71=Ea(gkc7UXfwE|0lupaTiF0?EsPi3t^H1ap#_ z1HlaGK!gO?Si+w@Ll*887vW5jLUu5Y7#gw=y>cvLyw@?l8<}AAg9+t*s-e%M&2LER zG)Zfmm(@j2GMtgqIXJ`ZvP#GcMVF^iW^KG#XUC1N;wkJFsGQ+zT$MDqDLe16tXG$$ zYcJ2PUDEz8Z(ftYtz&w^kRkf%<7~z_v0p2?(qZOsgTbsxHcnd|X)q}l^jC$AcY^+=# zKYmP4ioSPO+=B|MSLP$VYB(tFz5V8g_amdc4>#5i4i63d7#JA(fsP+TgZTJ?_P$-O zA2jStII20C|ghlSX$@|IzzkY3dD6y{Lz^nq}Yi+fua`JAc;DI#EnEi zumqX7kxRC+a4cprIu{p3sA49RAx}FlnXvj7?6rg3}F2 z-HVc%=LD*a0`>EJwNvQVk|(=eo#Ojk$>Z^OzqeBMFCRB=(MOMx!O-S6?`{y5H?v6$VjlM#UcqK=9BE1qrcy!FKu903v&39Q+5YhHjoDN@T zI``<|{a*o4TiJ@dbaa!uf0G!WmgWZu@&1eRL$__oJ#=JsYfDDO`297sqld5Zu6% zEnC1LZPrM_!2zcuz0{41!VMt^b_P}?id;gW(c@=3fd6z51jxu9q|I5#U`Z^8iH+pW zl$#A0Gz2#|8iW;1gr|bg7EQ!Ci+0gb zlNSOLzR=-WRTC8WDJ@YFa{Zn zbpd0!q~9R#lULb~gzZcTdcXbI@Uww2-@khG>eZ4ZOEz!bJl4nY=sUkPHM_QLD1Grn z+-=dv5AR<-f7w|ea5wb))sG)z zK7TbEj z)o+SAxG`$anuuMMVSB5?53LQ`SK)uO$`Abn*2xOAzamQ%gbT?RUQ6uqMruaa9{4~n zy8`h#WSzk-azGTuBxrP>jeyU(!MM1L9ARW3c0zz$Vpxhv?3{%I5kZCliiYDZ0!y=tqyP@s znR6hl2vz7338$BwksS;2A>jm##FAVD4bM5zUXg7!iXz}_V+0OoWXDKh@#qLFSTGr3 zcFLCM)$ANbKcCUbWQ_6{hk|~q?AK-q_ow(=;G3P2&^*kag(XYlyg=iWyvebdzLzy( zUg##hHOcIo9`{2&;H$KAhd}STui%r$VX%W_|Gv{qx?!TriDyJ}Z?WXb@S1~vB7o)$*!B%C*OT~d(8XK(Q%`%%U9-R$GM+8DDK$_^nQDCq-$Zk z_3E^_YqQ{|!_aU2txiF|e`ryWYJq+$4E-|L`fTf+1rF%VcKH4vUhN_xgDj#4Ugy{c z*_LkNdf7m>ivZ$PjloGe=%osY9q>MoC@L=B}_*_0;w}cj2i-K;6OSL92$6v%mW9` z&ItiT!+}7NUV;W^E(M`VMuF|%PY%onlV@`wJ27Gh$U<<~^N4gD2;qQy$bm^>Sax&- z4TBSWIAd_&iS1k>${a$7Ud@PSbaNQ(d}dlQqnE+hFZpIL|LzR8bJBAg_y)&#+J^*4 zvNW2cbS}xxX`F0#c9!35wa9kEM%N*G-QMx0v?zajdD64CyR7XW{QpgBiqj+QDsw!yEDtHk4~FWi^sCM(!G`H!M#(`2DM9+_A^J$Bu;ov)liI- zK;*zp1yxH-7~?=9$OV8SnUG8B2~6k3PQF*<^+mMN)T`sj6j&<385)~9!r4o zA?e7_Sn?vH=BUzKm>ZXZG(>&qYlqo_olF`#pV&fH0(%BPqE{0_7$R9J3CzSuMm_nH zep;`J+jUu!lLC`tyxDa;wOUE^>+a?^6wU8Vn|on~%Q^LcX6=|x^m{T!8Q+j(O^O&+ z@OmRKZI-r1zvS?OZ_vuqzR5FuETM9dCtt^(ctS$;mYmJo=?eyCMt;+d{h=Pm=tm7( zrF^r>|CDfW=wQpx*MTwLa<8bUIB?*=SfzUZ{==m?3u{&L}lsQdOs_D9Ry@M4BFh7NY= z(#FqS#4_5ATaa|!QYbE*Ye40Wa%S@qJ1r~f12s-^acAT}+U&|_Igf-DW+ar*d87j# zFNGq`06Wr$OT;M>c(Rm4xnWkgsL60J&Imwc5rSjwB2r1|kyv~NPt+j#22qevM9r{p zVKfmpm_1AkCXiy%*Oa@YB*BeMM6=*@Bnp#cnR9L;P~bo%QDj8e0hE(Kv1d#k+(;Bk zK^*{u=#`A^N97nsEuGOwWoASVD+In(3hYz~=$ttBl8osINy9@t&7FLW8iCoVi2;ud zBA(2NYnz?WsTui3EA~A|R%-9en7-+ejH35D8M7BMHl330-GaH#Bxhe2pa)G=FY)E; zcuGelX5Eywd@gPMO3|TfW@z8+xMABxj8pLsj}-%}n})l-jQL2zmMvROo;*3K61mH! zri)c&%WJDrI$w(WxQ+7{)7ZSWBs0q8gxFiBt(&TDUB4^_r1{~!%y_^3J1hT5y=rT1 zjt_BIk?OvqIAV8Ya$!MCK$MS9pi4xcYgTIP;X`}hy&dy=I->MSmuD?b^ty6d+_%Ni z{a|kDf+PF3UO9KP=~VsUL%VnG-nM(+&bYBMq?F zaBY${IjL&va38k?d zGX8TweDL%V1a!s-bbmE&+O6@PUnaybN)gP=g^Wu0TPcq=DZAH-woepI&&ryCWbw6k z3Uv2OaKGlVqTi=_(5_^_Ec=sIRJVHU2mQpis(#O=dcT<-_)W>{gRJ>0S(|Pt?~elK z*V5K4<9#~>2G{uV_58_a_-L19{(OSZmk9x%<|O~H&KmYEVSFowQ+E!%d@ovLBiaWK z9=vpE%->Wwd9tCpyl78VQs)bC&tHu|9OD9gA1802cjM79?>$i*(#8XO#O+n?-?@dp zM^j(BR?Ph%`sffn_R!rWPH@ouU{Zv0S$_Ddr}z86ed+D#>U{UM{Y^*boA%eQUc7wq ztiP|nr@O1Wd(3Y!lTofJ%s|hJo~{>nKZrON4q|}?R>3WDq#IN^Q13~wQ-8b;p^LS!YQutKI|(NU!bBpmP-Xa%%SbMTNwK1e zCK~O@ArSuLjEM=6i7XQ%=LUJ%5+fYAF4Vvl;5@1eU2+!M7^M=(0l~7!qc9AG~nk0(zuj z42@y-)a~6+Sy)%K@ZD>1k9m(3E^1$2xiT}xdy==_n4Om*{>lFW$51 zxHu8MbL+<9oW#z~G2b6M({v^(+@>VeZqIV6S9lp?H9&8_!#nWkplSdLgA}O(U1A3j zJG;)oANRrsjsyy%0P7fh1W6j8X#@dEh7~RxNTa~cI#U7|nK*-`0Y1>g2TKxD#a*~e zC^BT^qA)D&1*yRZ^h`$w#GnfZ;4``8z=@q)5@gns@PR0HbaaduN3@st5MtoWhS1d5 zpAZ()L#?| zwYhZUe$ZqiqwM!V*1K0RWJubdk$3Hz==xg5{4QVjow-jt{%UEBOvv`IiOELV%l$b9n zA-y_jpOyUDrK}%G=si+)?KI9}G%~+W3hXjZ>GNB{_!kfFI6db5;1m3xXbp1h{{H?Q zJ9gIZuRT+{r1O=y&j;UhyuNwu;+HRlEFyy3Da?p{2q2I|DcD0a1tuVT352smD6t`2tf&Ktg;8*mLxxYH*r^~KD1xZNs1za~ zfK2qtY&~PRhMBbR`^1<*g;++)cSy#rTgK`hdc>VS>y|+Gse;Y3DK^(<`rVx5cU8`! ze!AD0c}1UMYnkX>Ou$CQqxgqzT(6Sr+wr!qWwma|XeQU(v6fa-2zPenD!@0(j zh3P?O>bH#b00xRhzc0EpC-GpNxcf?UKbR2Vx@LKjnBQl(dE;tUa+H`K_4?M=SF|Xp zFxC6oX>pszJGX9Tr^br;orn5k2Qm_!*X23YuW~)U8ht(p>y6eCRsh@#Z`}^;1ae~*p3rXapUL#GD$&5 z;u^udm;lir57zh?F5wn_f?6)fsiywA^D*%!N;iQWy5#5*n@oDu#((X|uZ z_sMGAlGnOD-ueNOELpSXat>X}k%Ov9P^P>mpiBV#H=lMY0*5x^#+n2c> zM?cO$7AIQ0>;i^03~g2-pbOR^UV)_Cz`~Y>&=ap=;t57}(E_qCRz!J_k;_8Sa4s;C z15?6v0SJ^KMWBgDZGsOQ#WkqJ5%SQB3WpE_d=dVb26CV&Py-JcC4#D?sv?91Ps$Ke z0ynlnVyOc$qChqmBmx{dpDYNx1i~!%6#)y$j;Ue?7y{-`M+9it0*w*=Gz%E94|bqq zhk3&sxDZSOFj*XKbY%F*A6_XE2t4t6z-O2!KodD|MvQ>7(?I-Mvj_+Z0}{QOQ^pvs zW(-#_ni-68JTp0snUc;(g)=<#7S^oYl4|F9vu+Cv+9r9vnibxr5&dkE_rvifr&N6J zIv4$ju496>GcKi!aq8E}?j4FYZR4$)p=qY z?GrJc==b{a)BcWLZCPI$HQ&ChB>v5tXJbJjNgY#FaZLTLs(ovdZ=KsCW`Bj=zgm>~9!#cD|{u zEI~KdzvMGCG`wZqvg+mj2TI(LUct>ES#@-ck=2VU4wfRWac%)~4N|iZi`Fd;A+-bR z5XZt9)+blm&|p1bdE=zifwW04B!z?Z$BP^sPy^@UKqx*ee%2YHXgE!cIgoUsWN7u_ z0djT9x)B86AToT;2;+qV69XS`qe;m?2!Gr~${9OAfy04QlMpH$)Pgbb=&&bE!TOMK zkwo-NM@?Yij0vN>Gz+*vILr?_jd+ZhGrRN8c5cpbVfOy5rhs)7~B?2-6c8w z0$=5ZK(BS8+shgLZL^|YO!RyzW6(6s^^QYf--0^EcPnF;|5YQRQ_1PEqFw8F>t?BaAa%QOoA~`z!|}sNuf+fU)yC?T^F!tqEe>e9dF+>!`*)4+d%6y7 zS$up`a@+MoV*XK^-k#pV+@vE1#J#74o^Ov^;98U)^7!GkvGSsQ+Np+PVuTS%S?RL) z^(A5TyYoMM`1L(C0!Q0d^d;`GvUI)e+*Fymvov6Dk;}1i^zao~W@KU0rN|b7=yF9n zG1Ti0YZaC>iUJEPQSP8!#1q>gM2L*nGZ&6QFaj+T78!$6RziFNMRJiSA`XNMjwLuW zWTX%6;?l8bFa#2daEOt$z|3F^rA^#00t}hE#0@$L(1s!v1_C`OQi4VcmgUS*wIA=nJrojFr1S=ICAUK2Iz~wLUBIa;Vp5Tc`ft3@tA)KWl(!k>d zh7_Oc!t;Rb5Dt?-5HKuiBMwBb9Jev18yUy#jN4|$rkv5uWhSCsRyw1EBr9x~XK;%@ zX_w^G^ZcpT;bTO{XH&dd)M8#v@_sI3d}X?8t9?PAZ`F`aXoptdOU=l4lRY~X=RH?& zY*BQ)Kf~snN$`b;4d301zoTE3nHt`sy6}xr@_UE8K6Dr+f3!$=<5T=2q>}M38+!C= z%#R3vSxTr*_o9D=V%M%m4<9|dd%EkjxaS#;A32B~F%tiK$ZIQC#D!axFY>J2nbrJS z+`IR`W|kawAs3V6kvqKED{3CnDwD{ia=@LwGALR9LG{vwwg$p z5M&HRG2L+#*x8{88CD50HrVh3V` zGhDLx960tI8Ow?lDSr_@BL>K(CPO3mBo{}R8w>IwZm5egA+VGN%1E|q$c^Y5ks8cI z#1p~+0r%q35xEm)q(*kGK)3NUVh{vQ^eXNU6Mlek+{^^+XF_)~u4@>*TxLoF+!ant zXCwm$d2_DuChibSImMrPjjx3yt5qfZv3lHV1<&WwCikW}KAIi&X}m?7g2^NOuy(ze z?kWE76kQ)r^t?6Q>$Zl&N$13eaXT3Al77v|&Zz;<(EDJT^Pic-ys}yN&OE8ZdGUwH zO-%T<;p;EQ{D|1 zHq^2t!=bh!_}I~vZExHDxPYQ9%H!sXhiWqGH$0geE z7(3fvlov&#e};bd?t;!wU1B`NbX{xOUt2wYU%7An`tXy-i(kGU^NEGAKt6Q8Ia0T5 z|GLN{tG!OFMq)(@XGHA~S-`6riGzrMfHSdB(Lk5%%4gl!T4=yhM%9U{3yMJMg{lMw z5r*R>jW6-qCK*R&VWkh2Jpw__;151DgboUZKope>6MNzcRo$3TdL}LtNWGcx)INy6s)FV(3KHo2|yRe zv7&_}r66>cL%R{ma=e;-iRH}?uBUGuGU zD|o;y;H-OzD>)-?2e!XesNF-)I=8(lCHmLe<6Gl`N0C#0<<3`X^{`@(R{?Eb7wT}o zbh|56I$f;W@oGwXLg0>{!$>epcgz zxy_SS^xU~;&b{Qn{m?>Yd&_$B`uU#tIa`9q$*Wk-H09({8m8C0 zP?AJXa@OQEuB_5jo52-*=qf|-s+KLb-=yh9J(>g)g~=ZXDde+%Om=|TczW!1vk1C zIqY8WxLbvDIqF=`SNnRNhzDM^?|78o>{(`oN5LfbyoY_uU8vmZarmH56-Iun)a`M# zPFKVFUx^uUqsO0L1}0j~W_>Bq`L2KT+5C0S1V-Pk)cJM2KCi<@zHhfQE&kF!6GP_p z^z7-=VY6qA-*;g3wpocsSKdzjr(dkPa`E)qWz*ig{-=$~o`jXLqnj-sAGLjI^!Axe zcP;6dxVnE*!jvPY)?dGO=E1WYk6+%WBbm=H?>%^O^~T*(M~|-DxnolN%Dzc|v`?Db zZ0FpjiHqAGKDzRsqDi+-9$tC+?mzv2^QU(&6ITq{Jhx54{5D&c_t}4J<@1kkGMC`* zub(}+nY3lf=0#l+=C;5Sa{4sjf>xlc#Q4eQZXJK~_4D7GQV$-^-@17!Vat?+m3`vp zwZh+^*E5snrpFJ$dncnn&f0o_#`pQiseeEdySgI zo$}5e3Bh<2WI2Y9J~*7r_UniGiv_3M4_VLe}&m^&uf7%;%y>R$5um7}o1sL)SD}-vs5q!ud1Ezh7GvgX!P^m%fAiVYqgyFrEJ>=g&Ldz zWfgAtpmNu@^@e?DJR@b+&cFQ#)(;ogxeFJDEL}49(xr{N|Jc5M#GQ99f2bzH$M>)A z+P(bshqwQrbLG^IRdYISozZwpY-HlhhWN(l&iO5NF7A-HqF2J&f$^J0#BUuFzioW{ z_VIMyGA4f0ZwYG#Bx2vPxC3dweM z=-*|LmY(+J&GSnab|!5Zzj;w-kQK$lOOhHuTiPXI{g7Sz=AXW@>)ESEuRkQe|NPz@ zA3nW(@%r)QEBJ)S!mVqD#xLudw4fDzCxQ_uyG#eFlu45DlHN?D&zCyYWRlA&5V?{3 zP|c~S6$~553R3w0fWvD+?G_B6Q(xMwmKn`-iFcZ#X%9)CT;-)jxk&Aj2}Xl2#Z=Kn?{f|xwvzqLf9=(&E)ih8~Z00mcn)_?g{FYd}i3{5# z$+4g{$b{seHJ$)Tvl_q(AOGGtr&-d%)(J~HC9Ld~u)04ujSn>XC#>$5u%c(el1@oW zIwmdYkg%+4!m2(bR|jiCXL*lAaNxpL^aXi<&uO$1-f@e%Zg67a)DvenU%GkZ#{IK5 z9$rw#gY!4;oxX5&-^r63cJ7#%uy#Pw(oQ?)HCJTCtirhv2`4RVh5J@`Ox!X$DPeNb zuDGN2xm)?oo-5E@W z=HKcV7f}8?{lAkNM+O89QO;z7OF4wfjG8o@CJsYGEEK#$ZWoF$H6gPC5fL+IJtdpsZ_N6|ebMzn(whg?oid*>g{J@r`x$ zSmN%z)~jezo~T=a9p9Gj_^xKBl zZp_RtlXhEg{{K9|N;?T??dYvXVGlBORxxa8pR)ubS5bY6S#*ouRD=kHlJbmyYBw4ET@;gzTwL_{Kl zoVxHf84le`OvPkH6vvA?X?CNe*-aAXG)eU)?``{m}T0BjPuYppDCgyH8u=~^rTlktr>&#Sqa%)tJ7EEU z)nlf+$0EPjy(|2N#C6!h&HFVGoP&KA zws~mG{gt_n-z=u-%5i3xw~S^mY4@mdL_;4cJYq0wnGVTDYx!lqa?W>{5bSQUm_MZ2d5w6pTHNXZfX*ssYeuZCaTgRgnixa<{j zKS$mB1;VcsjJ)k#J}IkTKNqjzuAVbId{=vwI-D=+W}&9fN;Xa|*ZN8E#;5btOe)#r zNUIrN25h&QPx}zk>v_%2H-iUUX+7)pv0MLBvP%D!y7%s#6&t5*i;dbbEiy5#L1J9Y zju|odH97nN;>20%z!n8G?q1Ugh z3!3Mwuhh7gy4Z?W0k1)tS8PlAbTE!;i>=Hek{fg7m*Sz(*M>Yz2fS72|Um1)S6* z7d{idQf7S7SF@24R8~sDBf^nO@N6!@=y+HYN%7cm@T5--6)+SeVA3QP5`dV{r6j_E zk&q<$E>zJ}7=SX>7QdoQF4!Y_C1AQ#F&OWTfB}nS zWzuqZuu{l&w1gl+4aMLBYrsuI$Kc49U1z9(9gL%BTq5A`p)&e`6-^;J$dPVH+ZnTj zq14!&?5}b(KJQa*k9*}Se$76DvZAM2WqYIswoc32!7A3@sy5b&jz+sTtG=NRa@BiKIP6NH`Zs+l;P2Oua`heQ=DpA( zPhzgB=ZiGEpTE&_|2hu~MqT!nfPfA4btHjB>WXCD!qA9=1Tm{3S zI=~52Ib}y`)J!m3OpbxPNc`+toGRB;daZ@~$JX3oCNzq8Rj{ib-Xp`JmFIOT<7Dld0;`hJ?UsI!NP`Z8-+fp}^>nQDZM` zE6C)Cl+~D`t@Xuww{*W zXK8wesVOzPzpUErX`3ncmhXSN^^CRWzIFP&b?TFK;Dxp4xpgerdYqnqIoW#f+&Xg0 zI`zuJZ!sJ=u{r^FMkqLT7c!1CBI-c0yhzpAzLe@w(YQ;S7zJq%poS70rvlnM`dmx{ z#SJx-TBu{72`Qt`ur%S73q2(SQ(#3|6qH=2BOvx!;V__fN+#?M2xyQ;PKW0wciEaU zCpkQtGs=*{pf*o$g&^}yrEDUkiA4A~lQ}t3zI1UYLDJz!2#{>$l3j2vte~be6lemA z3$_(29iH;YIE-dHmH2I2<(iiR$3sg)qw79e-WQZ=YRXQ9M8A{|DQ@lv!b(_tVYr)|` zRE7*o6;M#BLD|vRv0u@*eUT1D2xOIlN<@SLrOt$)BGJk^X4OTu?8wMxHWa?9H7>o{ z6stg&uRfuV+{<6`Yw)VvNGk}xEfew4E&Q8TOj=-HD{`*YXqHuTvQ=rE6}{9Nd%~J| z#u~aNy}{tu#k+m-Y@F&|?Y?)7E4~qrbB8}H9&@u;!v{HPAIz37*42N8d;X2yWe)~6 zzFnjle!$_b7yc|o=?&R^=J{1VR;ll&kRfl|O!&}oYD%r1FRFEa7CQWHw?%J9Y_{Ug zSSw#z^KV$c9kYgCv*tdqW}dTR52R1poj&oPHSpk(z$AU&7eYW(g8JIHEH) zSFE6QSi;q&O_%OsO`f`B$n|6#1trs)(bxs!&uox5BQkz!{lpp30*=dssiBE8qC|)H zb);!R!e-Cu$Uw>H)1ZqZlhLe(>>>@Lil&DC7H6?6nD}0i3>C|EuN8HO@YAkF=#usVo zBFK1&3rdIZ=@1{(!kwES&Syy|~+3H|ETGQG@jtHCU* z@p3D4o>g_M)nctR;kY&P6eugL;gB~$-9Py@N%5`uI7giuzA+E-MLn<3^Gk(p$^M~d zJc=%G3s~k+HZfh^x#WWv3EOW%yxV2#^tO-QsxZLkK%TVu{zlP_4~_E~*az3;j5U5_aTH^u(CYZmB2 zQ4>=H-Tm>vQ9~p+C&oo3V8TobPl_Y`gy|7zLxKaG0DT-vI6XpkYl(5uqL45hzfh-K zB#>2j!t_Y+(#ee@ZXQ{FU~$Lz*m^r+LyxZNckB4-W2*=3m{JcqiPIz4oIDbh!O?W_ z7@kCz;R!P$;88R=U=SdJ1bDdU@0b#DV*Sut$5vh4zi{{5U*o5Saqtb2kPAa0DO!UF zp0W#%N1Vuxr(y!TKn#dn!A^s_NX}aP)`xf4attU!6qSX%>!<(~#}ed%UM5e3bZA+Z zn@3mPIP&M-1+9=cJaP=E6;%dn6HZTT7 z!*nVj1_(s}!_bgXg@MEMggb^s0R;qIln5n-bSONu35P&*0T~%Xb9U=EuGsR^o5%92 z8(t`he1Il6w9Gjp#0HPT44gjZOe87C#Q<5wKstKdiC&1?c?hJfXaV>#6I8EeD#%&c zHc_?&!hD6ZrU-)!9YGUibyobQVj!AgVqq%+AzwmtWUgR|g~SC#LUrI!IUXo;7%U;0 zA`m+3#>@u7R}}_-sW|vs=+yMOQ>+q$tX%bS?y+?==-^&9=X?eojoGetF;w0 z*a}~2wc2Gx%(tqHwK}Y~VozDKPFq7(r#Be>wp`z@d7Gx@2>#12{IO5NvC7x9~614a@*U% z-TtcC^{+ZTpS7Oxu>XqBgV$NTS6bch?ZO3VT~?%yI% zU-4sSrWD00x=oaY15;?}ShnIHZ^3KV1$JPvh;gJ=+;StB4`7IAD>2zxIsH3awu z$JY&_afyrG|3~}NFxfcb(DEK9HV%h^V1E7l{>;{KFx)f01!g$Tr#Fp);l4lG@p_5a z|3^FELjf_4t=!ugOjI+A70TD>0dke2hzlsCC}qyVC#qOThta*EVTj-bhiFp z1H28LZz&(nY#&cy&uejLS@$zr#vWSM^~Acti0a77-cUY>&!2P&PWrX(tvIni3CBFK!XJJ#L$D95E6U= z4efn@v;_hxj4mBRSL}QaF6&AIy>76~77PSHFj&YA1>~rP0OZKZUU=2OD-@;;vN-f- z_Y>=f9bVB3%6Of^vO2k8IO>cT;02ick{A9&f6W|4JHBBkMi8_NWsEP>FuQ27&1-&o z3&wQRzD2DOC*Isgz-Km(!Cb=3#E2u9<7)=O9j4zwd<-uRuP?mP)tOf`w~1S{5DnoL zViM^U8ZktX*@X2;$DvQ8q2xj}>JqjrCn_Tra#%5}>J`@FNF*L2G|gjTMQ4FBhIC0W zFoQ`(w98WWgA=WC1JlY6O%0uz2FeN=Wcj!J=uz>yN3~0Sp(lK+UvjPVGFw!dduyx6 zKr3{y)hfw~Tws+Sp5AtOdh9uC=2@%%y7Z{uK3D3SRp_Ro#4wZ;JTCT)vB#h3?cs4oYV>a}+bsMzbf+~0pS_QJHDb`9U2!z@JP=Gx z>h6QKRp1;d0x?hcvDN)Qd|3vwEbY;i-S{K6&u$&z4_iR+?Z%O1w@=VtoB;r?)A18gZ2s4s6Dc2(zovYA za4`wcI48x~oi|5>qiPsJ;Mi>5x`NNBe56;u?^V~bT z^~3AO?_b_~di?+{uN_zf@=Q^m;H9AfZNB4pp5Hq5_8EQp7x6#6aS)BoE z_s{Qu#Dse7z#p$3UqL)@L<4PEsCoRtzbLi`7ZcAXOc6sc+h2F7_^8#n zgel*?s-I_ka{U0T&TJc>o{sMjq~c`)WcB#!UJNsoA-R5d8LENy>!;VCobvG%oTBIX zos+`S(2=Zf9bW@#0&VV@-~7e>voOKGYloJ^$A)4D4%ip>=-Z?oHuI8GLULvvq8EoU;TQ>%hCv`q zG10ctMQo!H$Xt^fw{38tAfYDXQM_kDa0Q5+Rg*GsbR6H zbtZnRFeW{)+gIOukKC)@@Tq&mqvAQ&3eU6E|K`)iDmK8Xx5R3-)e4zl744GJW?332 zEB3h6c42z;0bj}v_*Se(TEWgA3Uv9HtJSAc9lx}QOAYSx9Dl5^MCUtsqAmwCe^I{c z#|ogVCa=AVC1vyd&Bc3=tKalorPdb@J5)U4aGAzOE4O`8w$0PZ9iKE9@u11r7foVQ zf1Q@vVBCxPgRV51^s>)dtJBJ_GsgAVH;e9fsC0PV&RZ!*19hV=ydYwkV7RehKfj|N zLdT`>)tl!xv2}su@wI(e`)Is>^$4r@%cr+j_Rhoh0BaMZ0Xftz?V9=R3;kJ#_xyd~ zPw)OZyM4k({<(vf56%m*fH$zrQ@^EPjXb)%8%r3o7k5U0f}yY$9Nj-hKQ;5}@nu=Rcxwiko`FJ!CXUh9z zG{B-V)v*LX#i?IEVVy#bh5YEsUNk7kT{Azwr|&L3zOqMBxO-+Z_!E+kZ=V4g4X_;e z3Jv@_A3qtp6tFbf?_S)+8I^hSoIZMjYT(`w4dnRwJ#odWCs%G9rQdl52}rHpJiCbs zLxL3w@UJN!UOuG19)i2+C)bIKfC(WQw@$3Zpr8RJ7e}DzXE%>Rf}~JqG+sTrn0)^n z8t-1*N#kE2ymn~un`iU_1nOYwwl3|NgB6WcFYJd>eEs|mH4~zPCSa4f$f&1~2||@& z!o~^PC+OfGUdWED>?7^B{A-XHEZp2dg1R9uG+uJuk{@1rc8lV~Kw!Mkz(CMLfVik# zbD9Z@LU{lDcH9o&h3WF%IpA$bkg2@zAv{SL^oYH#fWNqV8oMuK3QfGw$P5I}&NbQgMs)s^!l_1X_?aqPoad9U4~K3U83UxX@=1ixNs0N?*Ka zSk+~Gv7CfjL8Cb&HleX=qbd8V4r{C?3$02+Kw0VKhNV{+@U{BTlseO`vO}#rjo-P~ zyx~*luy-Z=$>yiO)cNGyGQId9D>&9_G~22<{A>P3uNy7+Huj`7DBh|xGObYOHw9b2 z$=~>0p~kNYcmGtV)0fcEU%M_(jhgtjLeJMh9q#4FBdm5W%XRqx$|~OYbQQxyxNYS(94A)t`=@`y+X&!A-$eNjeON$(z~eP4};quiyZl= z-Lfx>r}y6-$4{2%qepyzvV^$IIW7i#_4GRJQeHi}EHBwutfzsa;jd*8w~4=xZ_V5Q$WLBEa;4mq)5IJ!VtL^arV zrKe#z3mM96gvYz5H<9w|$M1N?5?{@3jAucYcEv%C0AvS+84DVL1Zz;34Z8^8I&9%& z@qz*5Wjgu6dBFz*yyF*Z>;{EEkS{=puRx*1z3&eF*%kU|Kfbcp@YPEufluHortZso z<}hDjXJVb(F$wo&;9k7AKfQSb5>y7ZXdnfU3>v_H_2?2B*s$F`xgL#_kFWo_dkPI~ zoMeaa>D_Zw2Ac$QL5@drLK;tR9QpK?{73IU%Kx z=LV4AAKevh8G{CL$Gtf=y)e9eavi;>eS9tKfw6!Bs`r$+7qDMb=tc1MiM6=X1Z5px zH$-L^gs8*SgMXl5{=K|^R_^-YUD*5C%_E>Vi3$b8CJlQz=;Jj@m{9Q*Q3qB%ZY^c) z)0sJeFKLS+5+^MviKaEuv6;caMTVCIMA3zzCjHKlq9Dy$gtLGGS9+aiZ9yVs`Q&xvDeq&p&uh=TU94m1zNoKsEJ=W zKIR>K(Y0oBw)&sF+ob2~VU-+dMb5NJ_WYD1_))D4Ih)YatEGWzh*%V=i zfawG|`0B=y<(PF?Yq%eQBrWv|_(~WCFR8dSfDnrUvmITS&$8Sg#65`Ih@p*tpo{Yf zlVy^NMEDBp>(Wl*EBOc30!v&!ycCyM-LeN@zM{P%mSOTE+JoWs_pdv|32&d@!ebLW zeL{}1?m(CzoMY<--8j4q3gE6sSN5QR-6I~|2vHcm!fn_2#8|#{f(rd(zUnLObMcc7 zFIW33+^Io`5=;Qxd_{N4U}hl}=BvGs;2$a@jDa@u6>aKJfoC@k zBbQ6NXGz^~+bEoN@2uKi0bghwV}#g*69^IabbIFsXUZkc*yUmeV)zP-ePmT%+yh?O zH&5%(9U|Iz4)BH_4nPMF3Qlbri9h{$cH4MS!$u2_n56yU?isKscC&Z^qAb{4rVSK8 zEN8d>{`J#aQN~&JS9s2eXmN>`C!8^k@~VMRz~mJafry(rSJx6GGiFZk_OIl5K+h{kTsu> z0+}$H@CMGzV6=ZD*L-%g6&fpxg6LBW<`578B&Rl%m~$iwnXE)X^o6fFZL<3BvRbdP z!e?0J2U#Tt&|a%p`_C1Jd%?nd|__lNoFKMfl689TQ=;4AzwomFYk6W*2Yo?N2S z%b+gcu6I=iq|_W>RqXV!K&^v00)O`_KEb=_{QQ+x`OL zV*K>(ncSLP+BFOJfY8T3tY181k^L23{UJf!=&6q4E81Hk9idPMU%kfaLzk1Uut?u? z9U#Yxg4~1}2BV?j-41%?pW!Plu#z8KxO;ZX*H7;NrS?|`P+_&>l68G4WWRk-aZpXQ&lH%oU3|LW5uHAg2aXNxr7I`6zo-SaGSJ>b{m z;NR1$jkF54|D31MGynQeigbEWbNsjV%dOrU6lFzC_z*JWUG&(LS_4yR4gOSnxK(F> zRlW0zLcu%pl%Jog%vA593-VT6m9yk1pTLnhODyuQv^jT;J>I1fJ<28&u9Z-+{r#|> z7fVIVAJ;Q--yGp3CMdiIjk8#A%@%!Vt&fwj_Ze(%1sb9 z-k8jo^EZyJ;8*Z;S-iN*z^f!?3s#mqtVVnPA8oNw!5jkx;XyY|X6&yvVSn`%J29G{ z^c)_~uU5)~5v&*JfTM8Ng9hkJ=A_M6d_M?ZvheZL<^BbFundW;;@6L_U{R1H<-I%& z!)^yV6G*UlL5OJJ21<61U@An5wIjD1$P^3)1?T<>OXJhqzaRur2z7wZW$%Xv(Py_! zkWC04@Z#MuJWPjX@*~_9V7OxBPkPSh~bHcaJZpr;13?E!be98f% zja%&Jw@;vfM?-QScl*SexBUF-#obf#2pU8x4Eg5iH6aI_WO&SP{)VD7m&_L0)Pp-3jPE(m|*fpil7V)VJCGizMKts&( zd;pP4%9uHLb&z602k&(venNhFL#lKkX&PvdH&;X&ra>Gcgun}&FNIQAO}(b8U702v zHfQ3JmwrVcL_uH-KA4US!zem}BSj+`oYgoUML|q5CPIy7haqZwR_-(uQ=;w2T*k%7 z{;KY{^ys-3o?^9LZ-p(hs!p~__OMFyw`xza%JoXAH0VRqg;tZfR>N6V)KshLXe&og zD|>UxCH#}`uU~UCdGAs6l6$#}o0dPlzK;Bz zegKdtYqiy3k=1r~dZ#&G!$y4$8Zi;`oPcz^RSD$zm4?W*6QymZvcy!KNLvRMrA+L$H3aQO8^MSRkT+GafZ0 zPLII5b-4R8Ld?d~TgPH<;{{xv8lmf4{A5{`qK5g2j}U<3jFsjq+&IjJ5XjC+3TINo#r@>$v9=JZ11)HB=0peg|33q$_lwoaZ9Y5^XpZITxnk>Gikyp4-X>`u*{ zBlzk<(sYc7s9`&e4|{B%R2%Pj;xz+83=>F|-j!eq#Yo9?!gI)zn@7mD5NddR1knl2 z3e<$x|=!FPDv4p%j>q~S&PA}Ywj)aRe1K4WXTuX=<6J%Yzpk(<_x@0I;D;9T(wok;@C!5eotb*$tpdF*mqy=QYA5@|y!8pWv=^Q~2!)pCAX?GbNFx4%_1{ABLRNAp+TQK;q`|H^CgR$J^BG~7M!D320zd`hqL zES}_7XzH}SF((#uNP**h0oBTU8pi`wC{ z-}rnK-Wi7p77IR9fRO?kc58?VixF?5W69&G1zt(%y7OduN_>pZ((a71CS&~ zS0E#-UqprHRIIripD6;T;l_uojxN7*V%?doW5MBYA#X8Y?cgm2T;elqcqi^4vOe-B zqQb*EB!bTrp%+wuoeziI)?qfc)ggEoo=@<%Rs7=_63?C$dJ z*=S(DdUnU}cp!EmX$C&=g$CZN#D@W}{PCU$h7WJ&;ZYTa<6_cu9#f>b0-y1qPn^cl zXE^b+5cnW%++-bG+8LM^cTUF;1D`%DhmSu^3&)-ckDIRUTY!&>o!l@?62~4J4SZk> zAAiDFz!2}NVlLq}87>eB9;D-A9#TNWhG$Cn02QJ_4e^W=nn(wq;JSTsE!BKc8w|>g z!%OkB9C2RVKOaNDc}>HRK_6oQ7pMugWSFP`K>*Oir#0}~uz1bAbz(IhqT<6jc%f7a znO>k}b;~O?x7DjQ{;aJ-h&CM#Dj-8)IXP<_Arqz@o2-nj$O(t7GO0O*;!Ei}UFaBu zR4GVJyile?D}Nu!OtruAD0|+&;mhKEtlDF(N`1fOZ=YUlSX%Kx?}~Q))^M>kV2f3M zTuSJ;Pp$t*$1bbUOsjF6Rd1YCu)F2jD8)7Sg-_UHpPDD#OKf)ySnE;vpl8|JZe<^M zR8P*);B}s6@A5Q%SG?`>h*8N6rloaSZuQ55{n&5e<3Bf__OZ^e54DGXi5{0)Yry*w zt)CVNzYq{|GGDDTK@Il@)?1gS>Z;t;7JC%@ExY$f*8;P%1gs6IJ1A*J*v^^Je~zxV zWeR;Fn#l?Y(jjfbS567m^|r~iw@@HVz2!fD2W^5@2C1oY96Fo?Xa8 z4{ZCfOTmv~VPfx?QU@kGVngU-gk%+kJ-;9mAZ({cK!P@4#RcXqKEMgsZIf$30Uv9J zJ3xsVbkHSZlrRmph^mgVol*x+YemAb)rJ+O9Nu+;M~<97@s7`IPpz+g@kiWeL?J>! z=3Jy##fcOUHY-q^6viY(ODq>ZwVp`e2%n)r6Ep&E8muby1RmI)v9!X;P^ zhRAx`6wW%f9?Ak1f(ejK*uZBr)So`~Pwh!a2VdBs2aL)o4NbI|;L{yoX4VNqd;6qX zU;`W!D&EQ`D-$XQfPp|SV5iWqqLQ>WX~`f{k^`1M`56HO8a|l=ItJ09;iIn@PXzQ7hWu8M6xCdNDsjEG^>Np!Sd3hc}0d(>d+jZNa}7!UL21K zEH(t1W(3hd%!mZAQc~0*X+{*XR!;d_PC7dW3n^xhCGR*3Qz;UVm125@!PN4RfHkcV zGA}4Dql0{i2F;~76_PP>q9E4EtOmKD>0YBL2z17w)kvAbP=WEK?5{k_oOCaD-Y+US zptDt>PkP}dpM9Hr4e0Q`Nc$J12Y>6Z(HfR$bzPj=W?pK$C03I;R%85>A5&I9cgr0= zDO2y2U;W3v!Kd9y?r<%%#-l)zN8nlaBDdViJoKrPoFg(hXXwM?jqZn!dKEP#wcP@% z?=q`#Y)a_hC()x{R_Xh?RM+RFdcLpN<6}_kXGNke21cDN5^=snqD_}Z zfg2*nx8$(I)QYA#&^XycUHlI}_5`&~>dX0(d)%pINT-1!R zvw^nra3YABQ8rzU27U6M7Y;~|-<;Kv=$WR#ohIx~->o~mLr3-i)KH@!=4#%e*Wd^U z#YQ*&G^@G6#n+gOLzDbFL#R2{0&T_3C40>1Nbq5Th7N!{l2ckW?44uCl(oKO1%5!m z2)yoCUzy7~RarYD`4O^N^}KTJ0MtUxoElRZC#A}w$|Ystq$FjDN~nWDj3YZW)`48Q z_>8hk1$3P$X1gYcitEqi(uP_=YN*giD1N2EZ7DCgpdh*Uj8D0cP~8u9d+A;OhFh&< z_vn|ox}=sJlAgE8dzX;6xtlyKKlDw+V){AvDaWkAo2^butqx1Art__sd9=$4n?OG} zkx$0i(o=3IEUX|~9RlSx!^ltE=SCNyy zb((K=U1-(n|E6ZIyLEs2E2z`6;$4!%Ct39;eW^O&Wy#JDO0~IBDD+I;ntOaJ;Wltd zwt^E}+&We*(RSsS$USo;3&Ry4E5%ndT@^~6_#|f?;Xpy-+EM_j$kK=cGAqkj13J{i3t2I&BUB2~02)||lQ30MrXhy5zKY6J zNzf1vF#kWy#jo;C`sxrD#t}6fxjTDJ+Zmo|f8T(<5EnJ*uvvmHGbbxT!O;pbt23Sz z3mG)vkb)TMwptDv$Mmu?uNu)bN$G~o0~(4`%XF;4{>$U_#I3!VtP^r~W3gNJv z3u3}H4URz+Y&8fu09`}5WEZ3_d{urN{t|sk?slI&n!k5x^xCV36)-x@E8ax^oyV#0YWQEVCjaEb~edREBSG*_qHL%f(LgBaaSKXDf zY=URdd9RB1J%jGKm%Z;+@xDjJ+a4uv%`)bv(!t*~+FWm`U|*zsDe5zj03 zeo=Syx6X^LHjC0DrhTr||4C50n|?J5{|a;DsLP%!I}nDK9K!Qer4#S28C}j*WvfR+7Af?cuiqLts5d=`5SuTFn*~IyG4UtpW`mkfjC^2%;#AW7&EN}#)8>FDx z%mX%!JHyk@sT81-4aCYW5yv13bT-r~u}MfwT$$1lWjkOej)0h4g!f2+D4Go^1vG3H zQsx;riZikkXTIf2Ma5cK_^Q(I^suQ`jR~p623tA1rMb3Eck6EX_f7Yx^XTVtr*b!Y zRCi)JD688}EB1snV!H)m!ABrM=UWjAn6jo=B?r^rSFJucwQA>&mD)Y8*zs;)^keTD z&%DY#@+@}Gt<+_=5?4G*-*PW`Cs+NK)dsu^nV1?9YgOp9~>O;&7 ztH+;K`=wUY^pr{io)&0)&8_4%p=G#RvaP9(h>NYq3JrOdox7m9^yX^;+2Y^8(g zEeFaXT{7WmNdf_9meW}+d7udhJ0dEe@n!EkG0-cv`{fpXbO|@ zRr=H>N4gFaBu8cE&SRmX5_e=Gm7$Cz1rsx;Ng#xSGXrujOGKZ}&|zN^A?2kG1;~Cm zJoY8M0P^Q8&61=V|bVLmxnQ$^m3}qQLrveL!NCohFSY|oJ zkeNKfO8BZkk56@Czcyc#UVoldezaAvzva=5v9UW90JS-6j#)HS zI$R2EYy3)%6fk+Qv(`AuiWDe*N}0;Yhomf41jzAIl^BXE#xb)*SxMU@OP8dtViph% zhC#R{P*5W!Xe5+?#RYlfz)THQ!&Va9VItV z+(j<CbpW=)PQg&d==24~~x!9^T-KsQ-ehAB>z2(}(%Gu?cd(^XEs-4Rd zeYs@&2c^3{Yq8+t(1TX5dpEbzR-%ALGK&Z8j&74>|4~(l*(;iRqgt! zdcRje?LYa|ec@I0o=3T}E``>+=2`AhB;KR=8K0_;inV-Ms{O~@5qEP{+n=ZIp&ET} zH2wWW^n|-nQ=hk8_O<@#WUodqJ<6V(H>~BpIrwQKlm$ugYUMevWwBIFzIlw@~d!6@a)3qI1FhyP`=`q$AZ%r zr-Z2^*DhGuHlcVZc=9ND88l9f%{eJmAB{}PTCPEqJJJ+1ojyxAYx2dV790~E4*>&e zkDMB1M-lQU*eP(yT7iokU+4YpOOaj2?{P+%QOoI!NT0;`HC!H|gpH26{|QdS-X zL|o_?By6g`LLguEVFxJ%5x(*bJ6YrRHz89~!e*u8&!h%V!#9`di-ewCEceb1A}79$nQetl`c`Kuwq91#nd$YXq!;V)HVk)mqf*K? ze;(B0dDY(Uf;xW55%R*L!ZnW)M_dBdx#nHz5xB#>=pN4s=ki8AF4Q8~zut*lRdyAs zcd&N9o8jZ`RB9hzso&MYEgzPwzok>Fk=v%=0|4M6Igk|dl4PfZ!c_Q^6P&WlUQ)=U zNxhoZbQd90t+-r~x>w-{f|Omiwzb&MBsWGCwkjN5F^rPJU#28qy4gl4<#h0BPkl@SoODgewhYLmGE=!f@1LRvZh`qvWmfYp=m6B^%7$ol?b}z5Fw&vWjgE9Db0)uyqZLZvo`u{E^AF8 zD~ZZc;hXuR%cus07Aar}lM~^FUWs<5Vy>J@l_*DAvlOSQHnka_x=5%sIV8?eYC>n@ zm)k5S&QZZgNOWcpCI=NE`*jQxdlc8K%-|*xGKYjp$7k}(VXFoYx9Es>>XncX46Q%y%e%LgcVxOx+b3D; z9Lm$=V)aqq!X|tT8S=VV^P45xKdC)3wf30w+LP%=-J{}CYsBKSTVL_hf8j$@O8ok= zaRTb9 zTKCIiM^BhMykm*5Ih|W|+drE>NI+rZV1A(DprN=zYNdDvLK+m^MI-Cb6ogFXjLbu6 ztTb!cP62B(47ny3qHh|GsA$wgj&}z*a*B!-;)K&!s1Te1Q!kH^DCn7Ba@Qg0d^0Gp zA;sxHkRY9E92-Tb1Ct8ioJpbrR+=g>)}iSn%En5AP?w`k!5B?WE%RkY1ifA;7^6uI zh82m*P78TrD4x+Kj!Q9=s&ZS>)R@8voVz2=3}KKhFE>Z190S?XVGL#Q%Hk4b?h** z!Er97R~7DXtI>>Bz}a}Kad;D;J|ym1LVl&8U|GQB=k z8~mku*N1uPod{@ftMb5a)kj+R{h6pg@V5)o@Eh+zzgdw}tya@hqb7Z=H!&@ERC*Qq z?qN!<+IRg*?{v@iyNmx2*Zia00@r$!*`KrewSv))a#Y;@ljrmX;eB_`ir(~ltq#rV zZk^U}*Gzoa5;3dg|9#_!y$)d}Te-y9$ej|An=ZpeYSnY~G6^$X3WCyico8*`JKM&) zHc@0NI+^0pmoz;Lsgj{hU(A7;r3KS4q!Uwh>3VV)GIOXh`Y;k|2oCeMOjo0(iit36 z9Bya8u~#C{i2qGsq~_G;>_|dFRS;Suc3>nYU!;=>jV_HQM@vzWvXXP~WToV)VF#eQ zQ~+X&Gs&fHWJ2l4w1iv^4%o(F6Xi%_n%I;YK)8$0BrxU35gvo9UhRkipulj@>c$}m z)KGF2m0Z$UY*~}}L6fi`NJeDNtVqPdu`%tSZOSE)h$91w1|6hE%tH-1m~E&{LQP6K zLWY8nBTK>jSIka>1)c#TXX3H~nS!nb--aKLGOutXgvqjEaOuJXlD@af%EvKIr*KJ)f zyB89>SJaHHG|VOSG9`X5H#(+EU~%b?sA+G4`C$VSz{nluHlYci=!k-GVT3m6RM9fj53^R0>qMYqC&;jkfY3I_gsTqeA~F@>Fb(npnLI= zE=32{sU5L*cEsK}(UW`B9Nw-xew$sdDSSbO|Ly?IQZ$g7H291<2p2KoXa-{wQdZ1n zpcp|6)j1>eL8!QkYR#Kky^rUvKeI^B!)1D$^exlMuWZv?;p6?oH|46m zwP3S-MY^6ZGw^Pukze!mc;w$8F<;b%9QD=(MsEp-N^%L>=3D)6(Kfd#4t-U3+Lwm2 z(xS&atTOUVv0*9I$60OuOm8y(uTpIu=5CZ+q{CbPde^+mZSf2k>*~`cyHDHf9?{vo z%4E;qE`Op2#q@P?3v6j11h|3-a6L7If}iIgubhZYjStyC~WEU#cCPS5kq6HBD7Nw zWt`>EF;HMe=+H5VaM2iz)HJ@)6mvlnA-Ad823dOPQZoiY>9I2nqxOA6^qrd07C9kn zK&Ou27>VeZv(rl2qHp9z^G6M$1*fJ#Fv`x}Ov<9;q)n}C_(#=B3^h1&kxte)G7VOv zEwPp;syB>E3c^?Q#_x!kc`9o4gBEM=1^0~27uq|Z-Fm-@P2Ie6y5-34SEFB!`m=p% zjrEUOUEtSUrMh3LG9tNXpW6i+@AMD-!>8tgBGD@Y!q>VM-uWdVT4^=YvK(ulf7uMzcRw>UrO<_H~a+=kr!Qm#fTL??PieeLJ}Nw9M`rl`UJ| ztZuGZbC${OT{ygYp{-Nu@1CjVKd}mbWtgagip+mONoYj=rjpERS}ddq9iEnki|Fgd zuriBIzBn&a*Jz?aZTe2VHpE(>Ljh_lLSs!}iX&>!A&XjtXCyWnBT(>4lUKJwGYGQe z1&YpMuAQ5pfYqHZinMlmxLi@_#7eWe;W}SgTgX<3= zn^SCdn}zC9!Vo~Pv___0Zfh%JPVPi#&Zc1^`9aJo5*3euB@=#iFecxp4`qiwXPNm+qb!Z@6+~is#Wtf*F-fK_y`hpa;!GrC z4ilc)E1E8&X>`y9YT~maP2P`@P&Q`5SH)XSs5fk5RY0IVyMa zELhepM?p8g0=_kR`qdrb6FeeEA6&A!EE zd-;cX`c-vxFP1HvYnCkk{yEFfKWEMJ-#@ue?^AW(oEY$rVF_UpwdB?0$GjqX!3?M6 zz+|Q7xsZmioLY}qw!{^zAXc=Hd37+Aks3pBgC>=}loiC&m^`v0aV<{iY|CY^C@>V+ zxR6x<3Bl6At_h0tnNitC^FbOJ0D&Wze6|%dP9|k2u#TZnN05ReDX25EoZ05t3bH)4YgV=gUEQ`DWc(D8 zY5$<1VrIIQwnRvglhF9mZBrZts})pgk{}#ueF{%>j3)BpHX(?bed&lHQ?w3q##E7; z2)Pd0m)Ht;W*p(G63vDcZ#yAm)Y|Yd2{mT!3mUw@yHZ2XLY2LX1$z`I>*kl=-6y|y z@krm=1N~|Z&lx#4u=TduBhEFL{l4aJ_kvo-=LwnNQ*KD!+B3XMkIh=3caBO6e5B>%o4ZH0 zY*~N)<)?rB{BySK*=7%@hTjgwbRr(WAE~5qWRjtQphNh9vyMn$O2=NEmn~BVt$k(; z(u6*>p)6=T4{4?FB`+do42>yhpS3B60<1qS@2cqw3_&$Gx_3!BT;HXhk_CQ0d=Sb=V-?XD9tvui6aI|0k95a z3Xjg2W*aJFW%MSN!pIQ3hEg7dugdkFShD??a)YLYFW4Qv@=D#U4=c|*kRz&x zXUV!=MQV8DD@D63@7&(SYWvq6m^Wl-zL*)sTdb}zXm`Ynd({S>3#dQew^X-m{tex7 zhy3E|{)=l)*TA;fi*<7kj4V`tbfK8OMVb#P++jq%=0k$|tf@TwNujpe+=8mQc=>qe zDD36!@8a(5=I-U<;`&RrtpE2v|0}m|_BCTecFjWMv{-h=MXnte5|ht5CeMcrMW#AX_?ko~uidOBYQoR^$3enU zD@y|svgOrH5_Uv}a_}_H043hJ7qf__t3swp1#^W)!SlgWP7nl~Ji#Iv zhEP=O!o;kVO~C9_msp1}#Iwp>OhXx|X6r^1V>uP%w^Oaq2fji{AGb5i~!HyRQ6?(@F6F>A)w?HW_0YLItOe%GO`OM||6X^?^( zyeKlal@MbsQ=O1y`Ow)m5e1g~P)Js+LvuiTR8UGHQ%k`rkc_a(R>wdApbZ^CHn3WO z9btm0m`Pt9?2F{oYhV?Q4Jc}Ypm0QAOq8L3(3#PAa*Au3V;Q|`bDB;PziMzW1SlEV zR;(t zK}le;vZ&2yqCjWXQE?Ko;4=cM!M?;DM=P#rNm3Un=#@yJl7yjHf!mBgUF=%QCFYbk zvR1jkujo@97?!fI58DwdPyie`gUA#T2~Qs7n*H+lioTAS)6@u#m^priQ;k+mOt%&E|Fa`8qJ3x$rzTfR-cDm`*m8R#C^F^fy? ze`opW-&ub7`R8AL$)4S>LRjvwmia=O7i~5)PmPYgm0~=L1-ln0ox4V8p6X%VzBxR+ zd|f3wU&^DoJuZo7!VqOqG= zIi^ngh{7J(|NDROzrz06*H5U2otSVMjh8+W@vD_G%C!&asGS64D`E1jvUnVFa~2Gj?e;ne&K{FxiS`EE)!iCNOtV@I1*Ky}UYv z3P?w$w~m1fZ8YVAzzvNEMJRW?n%G3V!(7EL%L-?SRyn1pM1iP7uRab#A|XJ|i*RU3 zN+Og6XQ#Xi4reEkD=SG;E9)R7cu9@g0;PHhmVEJua8$|>#mTTFV4;iqy zT+8vr8jdVbyN`RG8ZJJSv*!%{#ivY`Z0+>6z6vyNjFK&snqO&f&ghT-{Y;>h^11Dyn9IE)7e} z9aNKk1b9Zo9&D&)M{S-I7Tc?GbhX^>*%VWOuKu6@{J%5%;rTrMP%YPi&Rh!BU?C*T zIecHqn&F9Pg9&j^^>DB`{S+{@H9`h7qekqcpu|?0kOCo4uXte-X)8@acGxu96-%GSm94Q4YR4%@^g2Wt9 zb{@8}BS%@TbJ4=!=}PM@o%6s$Mc@4unK4c6KVTItyE$f?*tD04}dSOL!E9NEksY z6A4QIq~-{QovJEPBtkWagmk1n6b~OdLfuQs#6lWSM?#of2g+0hL$(xv9Gt8k1xkc9 z2}<}XBz8&FG4o3foLpq+)RN;C=NmL7|A6tuCod_oacAj$7xK?p?HSX~t7^1osahT- zYj~Ba8_=+4tx@ZuMsKRndUE0Dq5hRRx_A}Hnk{QKkDS^43uVdfL6r3ic3D}oxO(`O zt&+cby}ac@{eq&r0;{{+vB#jT*bd-lKrUVc8V#R~Wi zYE@=iY<=vt_A?R9>{qRGbn%jfeg6Bu{!8{$=3KvWF8ae0loT@((GDFn;!GVhyA-{E zM!1W}gho>|S!iGKGN+{{a?*hnF&n#JTk0h*B2f*(H0&o0I#Vy?tPD(;m;*v(EAx}P zw5IMd`hZfo7*f*oOR;fyI%ea@;8R0_(STecm52~56+t4g;}KZxQDR^yVqFa-4G9lz zm4Xf8NLl0S%Aku~nAnUJ8Z0y^n9EG~l8BuS8>-kiVA|GZ6spTizVxLeVtX;RqToDB zDWndfW|V~)oC+DsWmiuCGk`D~&^onCmswvq;{K2~7vTCdiThV?q zq8A=*Jal;J&7?Z;GQk|Nramo7ili)-P?(L@115^Ahywz+z-yI1_?%ZHfz4 z5O7Yxu|hc`F=RBg^i-yX10@k2P^BzwQxJAaT{4R#D%PR!oXTvXI97+JU32^pD&Edm zD^pCkQ244r(K=liSka^c^4zAgHX$#LgXNl;B@440I4YfmxYk4CL_nLXr-I2~uInjr znlQLw^i|jrp)ofNWBWG^J8O=gE*Xxfvf#h(<6>NvOYJPsPPs17nxxo3g@x^5XnMCKsOZN5L(d%j`TBxO}TmpRpdzy1K`7@Qm)5 zqfNh3zb$OA>}124@nzeNDiF~tXN88YK6#0bd~*GgyHFMv_bk7-xaZ675nR_ZyiuMy z5&5gu%3ZXio0nhK>`Ym1?%CZuT--ceTs`pQ%H7R1yjsC!BWoX75VLJc{olJ*jHy{5 zAdlD2S$_FfmaIQz#lv{Ke~ABO`H%nlkN^FD{x>MAL_znhvGw=NLM}`iSdwOSOG6}1 zp-5<;9m>W$Q$y5@P}^#ba)5{ntsor5>_jt)=M^gppr|=boNdwPEe9JCp=lb_9<@HN zK}RA?KD4I9g_{4E01ll@@qh=EGIYpShGo$|Ch2i0naMU&I7yK?y6!3 zZ7c#L5L!TDDRzOxs(nL9VwV813XlW>Ar^^!)e4BU3Toe=R;pQxDyqxvu5x!Lb~}!f z*yGqvoJ=OGCr;*>8E2;LocBHF`|kY(HIq=c?sM+>-t(UKeE0i~?*HqT#JoYnDIr*=RJ(yo0ePl8GK(ps(*ZP#KdT1H z21y^0;Y%+Mh7+K9y~i6ys7RIJ1O!7`i(`{mg!4du_O>&S)cawx`|0b!HE-Xo{QT*f zufDB*@{5v3f0X(8KS;lIH|_H6DOW#U^!`^FAKpuO@BO(CpU(L7Nz(C)@mu%DuWJ~$ zaZg&~q3n}yu6*y8)z=;@u4~VzYD!tUeni4VX<1PTNl{6YqSIcUxT$UK#-=ePRS6Yq z(+VmkEy_!tK6k|EgeduxRa{(5+=v)yR&k?7j*LIKW8u@Qm2V!)-(ER=+QiYrh7Il4 zfAEmOL*-Rw?1;G7;c?Qfh7B7Q9Tg?tg8ab`f0RBU?xXW%@(sjiwph8mKMyCDnHiUs zKkBu^dpKhPD~F+AT_gkt&S1zPm0SXYq2-cPQfL$eINLDl@#jkv*$2~0LLV!mAx_*! z844Kmc1L;?;9-6EecuZApJzFj?xSdEgKN_SU zg9->SM5tA5J{Cr(ieSdLVf#`6Y4a&VZem#xYd2aHu9MGM(%O-T`qcn`APhH4LkKoW zIw3$l6RR*#*|cz$fV7nWKS!AeSLxKTJM%eaxN{<2N2k z+jd~;zEg|4-dl6$mm6<>v1mv8^i>Dba@NT^R58(U(PI*aF0354qr2eX)vQf>N0(G4 zR;**o%9p3CxDlg<$3Hcp5XOT>pLS$PdDF$lomD+9gbkMd$Z#L1hE|7gcOWT5 z;!tPU=wmBbV2amKwY9EDzwgNbxsUY%d{X0iF1eEz@M9%IaNu#5VP>~OBf);(xsthw zoJidxe#lZ=gR+cnE7@LCusNM7x%9G~S|$RO5A-(5VF>hle8@I{47o&NxF&D&5HLit z*_?Pu!3>}yfza^m62a?k`T=mAN?<_RY(PAFa!5Q|92F|3kpro0`Zdd7?0e$ZyZ|5< z!X1yMBO#tGaj6Gj;c&g=Srci$+Va)UHh%RxdB68v{;&VZs_*{MnqU59<^S>@7ysVB zPJ8{k3Edxz>v?zL8=p+P`?K-yy*v4x4<^0#(YRB+BM+Pzzw3BD~KqzLwS+IlHx?U@u1 z%$4&;_O6g%gyS**C?RJC^J7YEPTZxFL4GI6SIww^2bZ{0>IwTb9JxY-dTD1TRa<=+ zDYhPALhtcTAEF+g$cI}-<^>&)UJX zn~6N@S6@8c{N?Yg{OX&9-~BxI*Z*kcKl$^`fBA1W{Hyz^*W{7Tl|vokgyOj z%*?D2Q)kD_TohlvBeSt{S=%*z%1S7&PR%V(n>{an+<19!N*pXI_6mH_(?95Ov4;r-JkKfPXwovtgEoq3HyCGFknDWFb3-hmO>bCAS3g_Hl#S|cV`Dv z9**+qh<*hFPX-MnQrSRmht3!>dXKKC;91KJnIwPdn@=!fU_%N=9wZ7TFjR=btoK?) zAtfOsImyia?59^4WGKjp5P@me)j~YLE}z#_onTcSn!}(RYsJ3f`K0h5BU4-95to|R zWjD2o_jzqJREP)YkZtV{zxg>89*pwClcNp6X$uc&he*^LRvXn<8m2o zDAeoJgSM<8A$h(%0u!zaNdKs&{c7F4N9(?Ly7KXp1)qO9{U;yK``Ne4{`fC8{l&jo z|5ty#=nwx*#y5XF<>7ak|KN`||JUEt{BM7q@$tvwyDpA7ePPJnV*_@dOgz*v$dxQd3XhK^;2<%QwCQHzU4Ey_vC zoIhd8^pRr{q+j8M9$)=QyBaDjOxl-R4jZEXq-C*tMai33D{|BCoGt$9ip)Snqj+?Y zi{xUt{5fx3v2Nc<;pWkhaG+oWkFzbdFcN_rH3ml*U>q}2>!=z$>x2U=t6jGqG1SR) z8log>`+cDdikD^Ykk2tVN~s}EhHGkMcPWB!=h0DYSeGK$kKC#(mOae@Jev$j6fe=r zfl8LK5aRhLEj`R&%Km!NBn1T`u?$h!$kx9g^WTsxTnIpv@|{#p;KCJ(xvn zp~r6)3jyA!$i|H76mn5w0ATFWc{n8engZ#>%e3NUaHV6E-COR&1i{X zEk0I|9JO@Jg1lnr858Kluw%=R9v+}z&){dndlV^&%y1(0Qek~;LwXq$)+e=>;lUw* z_N$6_ZdcxWwEVMsi{E@_!rQk}?%tX8vv13!W&Ml)u;H)&w&1V+)1rU+=cWJjKQ#XB z-?jby-#7ft|2_Nh7b#b6#Gg1jX!ntUyH6$^?3j6^YgTK=?Bf>;IxkjTx>$VrTz1Rh z`OQaW?LL;YZpWz7O-U4uK4D9<=59Lp71`(FHDwaQP-xH`Tm2|&ffLt(lQ=g z&*DLY0t~B#&5FwgO9HEcM}WtrgmcJ&LoiTbfw=>A&;X6!j~b7%g|ch2Ra%cxTBirX z6abG)0S|0hnFjC%@E2tTT9n5i+#LeeLrCDX=@Q#5T^EiaS3XCBbUvd|IZpUxM_4Z1 zSzuNrA#fm)qbk^79#0-1H9NyCF!Iq9v!Ogh!uA@(fGRz(7mQ8)9I}~&#{-ZVp+m(juc1fCBp{R3s-Y7}75#1bel9G-xw)h{r*IoiXHO zhi+CN47CHJlM{+^fyTglZD0uC!O01xF7Uh2P(`ZB0^Kx1lG=z>4cf12Zr`nZ`*ziX zN0oQ)Eq(jl)OTM``TV14-+sH~FaBl4zyCkV{^S2y{ulpt^gSMOi4yQAX3g{kwG4jw!JuLNUbaNsvH1T9Nm0O|vk{B{{_SkkWs4IaEI zf6~6{S*LbnUv6G}>+sUM9VPO9`|C$?J~?0f1zM1Hp`bgVb(oXe4LeTSi}f_zsf*|~ z>cM{0Es4FUe%vPOT^!XL2d4nIg&8gkVG{H=;nYUw0D@P)4w2dQ2kIoJr6aj-s$heD zIg?pqBNSrDiKk|UFwkGBp$tk0JF*H72Ee7WrJ^&SSvYEdkS8E#EZCfE9r9;Y3xGR< z`3JdQpAm(qDlg2lsh`_3G)1lig?Y7p<+~`WRFx3s_CB>am`GAF-UzgDNH>&Kq#hR{ zPK^2#9?vGDn)}dV1|T*3=xZ}0d2RC=KUKA$1c|tr^9cWRGomq$uxjt!m6(HHQU+sMGP0j7kmcMg*#r?<2 zK7TOf=FNl~S0;RPd(wA5pZOR6GXFpPm$HBLpUVI7Kdb)pf4=8${_~;V{N3UI_wV=r zUw>En-LI0mu8lf)W<=BRCPM)ji>|S=Rz36mD+1Z|)lU-AG zwI;0GnX+bI&hB%|o7<&j4UrEk$eUHMF~j80mL(rCl{eY>o)ub_d%%*9HORl;exd&l ze)!^V{kZ>&{rbJ|q1{D$I*pSBn4vlhCOl#iXou7$1S4c`#BY!qYXpo3|k zOb!g}HS`(RYSaKB+Y!mJ-v#ONYTMM7i0ohh-t+)w3PC~!da!?irxL1SCn2+KdE&`Q zVOW!_j)X`-4|&WEoR*i_jZ-wUIz-`M31DU`rbrW`#S(*D7*frwjyAM;r^#bEssy7> zxiT1!CS|NL7zwNJ)d9@vj13}nx=arwsZ-^JZ6_5N9aWF&iF5`!1;Z4o%3`U(a#_b< zUYA0{vE3BO6v`lH3GAc657EHJBtSPWZ;Hv&J?lLR^Os@-0L|igco`7Vk3iRUOp?lT zdJONu0YBT0^9Qs}xwbC~Lz@i%Dgz$Zk)B5aRhEmeJ`5^P`_64{c7i*{b|eJ{Kvz8_jgDB{_k7< z+iyyK=NCyG*GC*Yo!E42%HGpc51gHM=+uJK7c!5WU2^Qi@{W%3bJDLm%iDWPPWR5( zb9n6P9aC$X7uTOI-F;^Ayd^^h50anUk*+151(o;PhsX;+K2o7U4UwlRJXZA|IPk@O z173Kse@xVn)Nyh1rjA}ZE1_`yxcU`SPi~w0c~_}4EAA#Cj{&BYG6Wcea6&+(BuodGE*oV4(s|U+ zbRgFu9mN^4NvnHMv#>51C4d@WqY%@eL%s^e@?H>Q;SdSIJX5e-I-S6p~?uqP2u@XFp-b(hJ%r4I=wV7-%@_I=h&U12FkFcOwBGA zo)g|05+ax2wO=)U{ySB#-Y&ZO+N@J&Qd;(>w;i2y=1gM8nX%WeBz=4*<#)b%`H%il z=AZntB|rN`_3!;|)1UtO;J^D{+y2XcZTZ{(XYb$srsCV*Pw#zW#KALT_8duRJd&~Z z_>8?r=bgMT_sHobM~{@ZpI>(RT=A*)(z6$ePIt}N(>iJW-uZP$a(137YdAG|{*s|l zLxF(!vH07&z#q{sVsdg?=yf8xRvcICJWl?G;n6A6W9~`J(&XrC;>Q zZ%bY-Z()5cf9*?GBesKXieO`6lXBF~+%l*gn?=?b&WaJIv$@or--mP0IyRX@P%)j( zt>Hb1jOvn5j0O7Cpbe>IYL}Nos*1}7R4Og7>iu6dvF?X@&$_NPvatq$wd1sUF7aC8H>S z;`NT3PL%}N2Jqo(1hN^6C?26&BoN^yKopv6*2u}E3|BrYa(EPo8eMj)g@mBxl2Afd zpwER{9Kj=bO@^BUnSU_*i2@;JLy`Ur4~O9KQ$cMKtA%4ld5=pCk1N3p^$={Mu#prD ztSIDsOC#9`z z{F$?3+Rw^UR_e#MQ@{CQ>hFIy?~i_2_~g;XpMKTw2fx_;hkw}eXMef>um7h0U;q2+ zU;Wd?@88Qfc5Xubq12s+Qnocu+`50}fm5^gAIjXnKmW+_;$x=@j-FX|?m|W9e% zEIWC*;Lyc_rZdYLPfgEXE+1AHJao{2Awz!Le^9>x@<=r(E+*>bv{9wmNr!9a+&Hl0 zeoyH)H{`eT$uDXsm#3*OdhOo1oy9rC?U19)&X?5i&a%fG;#~{ly&b~qO~I}AgdX-> zPk7XKr%0!<(JB18*r=I{P;ms14z^!mlei41+DBK53AV%aZFM7^MuX z5H)0Bm_d?|3;}T2AR`wQ4d8978i|H5Db}F_*nSCXQyzGv5aUrc)!;S=0F>vq43+pm zRs;Z(5==>c283L5aauSz0Kln3vb$mEUS=**X{9LKm`$Y302wIE&xyM!N=N}<27?aa zY~e6;&%)!Kl)+2kCyy}b%tN`}DJ=&8P7a-x!r35{K!*50k6{)k1`08^ILN87%tegx z2tZ+=^@oS4p%^1{0#Jg9XCP#wDBd*`C3qk1Wm6JIIak`RDsR1A^~RmbSKpq!yESdk z{_%}_$M0zx*Va1v%$bpFSrb2eH}#vx(|-Nkf^WVq{Ol(izx<;9m*4IFgFo2+$A7Zx zkNjUXZ+F<@6KV=e>C}_d!pYw5FfRL)10- z+?v!P{lxVmy+=61qtlDK7IB37kNN4r9khdY#7G>u4n-sq{vZXypJ8^K+7h`1bR&e> zf-Ueo&C*U4{JrOpj52OLo+XM4EF#?LL8WSkJxmm0BgU;#KRFioTn1s&BRn&T3@7q7 z3~X5H;rjGok9n>Kd)&>N3)j@tk9|a)Aa{2&(og`-#DK&JFxv@po5iFO@5$kWR6Qdp z1PBIB=Z90+aBy!@IW7%=QPqQaBL*G z41mrO!P>9p9Xp?S`h518Gg$}QrtH|8)YLq-ac{z&J!4xBjq2=(zji6{*7Zpry_fdo z!>ONqy5O_Vm;K~H-B({X{_4Bk|M2%4fAxo3fA^@%T8Y`KYuI#@TCQt59Dk=IJbJo%IbnA z7mL4r6%Fdk%Y29mdX&^6hcpWGiibGVE)#>c0u=Mi`GN(K#3PkN!H)TYl6wXk2oItn zZIc1#1&{G~Z|G2;OYii4Z^)3?-*Xu}I=Ytie0hBsbOE??Xg)%=1ezC(**A`jDTB_ZC!aQgyb`W;~iBdNI`F=VPjqkY)8?;>G+ zz+h4oyQX|U&wgyaLT72 z&;H=U^1JtH9z5Cg_0xuLzuolY>vebTZhrJ_J|U_D)*7a8y!KTIT%OtE;n`59S>?TXyDBMdup@ZCA23w=CY;vUKaNwHr#_ zIFcu?{_b`Z|D;QPXS?o>vPar*E@*4w-Z5Lc1TI5e%ZEtSKG65KWe**djS7!?tU0)F zOd1pUGg}#(l4g7cATpEt)+YkgZhy9A*~Vr&A-0_aV=9hDQ}ZHl*`IVMBI-!1_=rz&jle_kxuW zu(?r7p^5Y?L%}F_N@z697JQ9x0NZ!i+I<7b>70&V@J8r7swbR9JnqtkyL4VW0TH7b z66yawfbi>30B{+7>d*v+vZJxsrH>8unE)xH&d*$k3i?$aa)870pjF73Ix*yuYM}P3 zsVkOGsVaZDX3f-^HIthgChlpNP`7i;zC8(t_9q_NH|FsEQ3nrE|HY|hwJ zm$IpTM$6Hx=6#cMmW-M(A#L{TnWf9;uCC2(I8=1_blH*11&1$ZZrVSuX7|jR9o4m^ zC%0vt-#PEWg;K61t|;qHv}G~KZc-07J9>f#h`~#ZwLa!Y*;3dLWDX6fEybFK#>$yJ z5G3psuB9+Fhv2b9e#3f?!5A)Ckc&yVP($)S?t2lFI+#*1P+}ofZ8-Pt!HL0ZzI590jYG?N$SAd*-3Fg7H zI2m4#8hy?R^Lf?qv3~UX0J>%5sV|ItZi?qV?uMeU_2e?}a6k58Hh}G7Up@>R>JN>o zpHaHCLmT`V7#XA$P|0Igk%xIhMG8zka@GSHB-W(};Z2?b`uO`?Y9XOo+>@BAkpO+r za@|aaF4^>K&YrNoEt zrGNYLnZNkG+4t`+yYuO$&+cvi{K4*rPquybdG5t)%WvM^^65{veDTXoU;aVOYagxZ zxlnbkqv%N6%T0}`+Zq-eJG!K$c}ia1sN|H1v**k#S~jO@U3T^6#Wi&$&Fy&y&d*x2 zBfWfML*vRvT}3~=Quf6q*%#8XT-TD-9(1r$X)>~dtTpMT1HjsX4q=P2eQ8Gm6&NH| z3>%XB0+=2SYne3emJ=33UWj8&B>Rpm+2vUY7rY2BA_s%>m*bA0`_5#1-o+k#&y7lh8`n!*s9(=jwgO78&uUFi>z5SCfYd`+7;?^gtJ1=kS zxm440vHaYrIW0|-n|3ccdo1_pv6-vaj!sWcn>lNGUeWA|by?M$7p>b?(tIla;F%e# zwq%u*)bCt=v90Q}_Ts0#B~Ro_fUbGhtg!yI;b22y8PgLwqc1Uv4NAHbF>F={B!kd`2XAYr)LID4c>Rc4m&{QhMxsay&p0Uo>6 z)56cgJi3=1fSj^KLl_EhVDXcUS;Xly0ME-%EM>z94Tgkm*?o6%+N`UPA!xkpR8|7_ z4rnbF*_B+gJ90V&!oB)An&kn#Y`M9es5Fi0*?UUcZ=p_k)bD9;SZtA;=1rL^*JQ2Tw0LX%;+maBdyeNfAD>xOJ9Wjj`J48v z*t+HHfr^jM7C!AQm1iw3ci@DiFKUSdbeKRmW^l%7Bn>6$&nIi2TIHU7$0Ry8A z4b!UtrqKBzMo73UkqabxX#$j1IU&hzt7!vgsCQ{n6$4IHqGAvmQi4E|Fx>OABGyGo z$Osa*B^gD9x>~3QvqafS2wTNlAa-9Ok0EY+AElSx zulzxuVbx(mZwE-fkx6cTxeI6o%&uP`m{&)GCZjV$m?OmOX&}#T=6yp5h3Itoj4+gn zeM6sJz0-kRM+FbapA*g$*8Loz@q{lmofGC0L4(4|?D;A`Z&G32l&Tfe*Vj&6zd_!9 zpH^R=wsq_H+SL=9>Jr+TN1tqqKiv|4wKL(pn@OL%oA#62DIb0C^405wx8B?G(cOkm z@9(?+bob|v*Ia)$zw`R)SKh08_uk4^-k(}fG^?nvxaIKLjx)8_FV$SVwEpU)wO220 zdE>RM@4vI_{!i-O|6tS2H#WZUer5ON%F{jTuD!OrqbI-dz|vj&mh5gT+IOy`X5+rP z0{MxXudm?l*fzoTVfVlyvAv9KYkqGihG6U(Ah89^wowF%M<&NHC^^}qY4ZW z01~VO<;R(oVp_B!D%6DsLLR6Q0J#h%im`AqkfXGji`7{on-G=9)S6w($K*3nh+kEi zFiXl>c#A1jD?+^l_pJ`GS|+A0um!9lX=pi;od8S`Mln}<)5(C_p;Q`67`3@+L_ z3^@`u4QV^d;9@;F4QnjQ0}tymjI*mk7fvO=c6G$NH^$z+mG;4# zlU}(syX#8f&3CqZa=-DjM|B;T&*a-O4iDCh6J`_6_F|I|1|S71QW@GJI29xzkIt>Ya3DKUSidqc zw%^$SSZu^B`FZeSluCCrq{^z+=3^yeZgu5j!D}uz#O^RVc=3k=9fQ$wNT073ZmM6r z`|#Z6BXf4_TD|~|@x9!$H&$P`weiBMqf*nN;-bgR znl*Xp;;Iv^n{M>(dhO1qaMI$!q-k?zEXZzas{Bc3k#wyuu%vN3?2&T`41b7+&cMSVk8ws2 zB_2I21mPt2oRNlO`2T?k+p|dZc)w;0UyAJyUxIqLHnepF^)eQB*}$^JLTWi0q0>_d zTV!@zD*jmppW0&rX5I_$*I4Xy$dF}edR$&fA!;KeAvOe4D&H%7A`l9UNVm4bg1K41 ztjiwRslf#BQauphhMYn$>ojtsF;_r^q!MdjhNI1@3{}NjpbT1_;u%8Cy6LP6HwmsN z6R(^|#5sY0P-EdN0Vz?c!Oa`;ifsTE4hDw1xl)WnG6jm#o&W6Blw0pDa9l zX33#bS@I!-y{%K54yA6}p1f(zxccp5+ge6<9!u>ymeg~6%$2T**RD=`<(28zuFvhb zRQ}rgJ3f6>_wmDqPrly%+TF5quPtuvT-E#f^yMpFdf~U?MvqLKF?Dk8;;Q4Vn{V_s zzJ6=xYx0Qo*4_{A9Q^#VBTv3)e)xFTrw?mid23@=&-$yqRo(6RhYl^-zH{E%+F9$i zX0F>jYu(N{HI1ux?dUjIar<=MlZz#frBh*&*?D?O9`@k!NiWwVE~T55a1>`;%Gobe zHYM{1Lx4R(6z&lYGLXu79EtQv<>bmSa}8_ z5N#?C{BHKVDoq-s#uRCL5iy$GX+St92MvLvq0XRcRg!im@OW+1Po2Tc=%op;0?Dt5 z^h*^}P?8Lx5LM;RR)`2=hYuQ~7Q%CYVQDHJjZ5|W6cU1H7Zv0Jw!9BIiocQWI2+l2O0iM^L5UAdZl z?drnouVkOURC@8|_D>#cyYry&-NzfQ-YGtHW9h;6y!w{G(Zl)==r?@KsHCj9X}ODw z_V2Fg>fH1C>-BHGUia=>JKuTdz~`SG`}%3i*FS4|`ir_Z-rLyGwf^drHNCyd+B=Io zua=zbTC}T0TGpI(+h^7`&)v{gvUX*8dDg+r^S-)N@ngS;5b6fLEktf=ztP0N;kuCPC+Gki5-J+nc_K+<{b-+2w$R!299tyDCSZ0Owk*a9 z1GC`XF_9)!r&i(HNT3AkianE20MjF9m)8~LXo;ayL*%S#6+kwx3SwOI48!P$&d}is zq3q_7|&x-k;*knF{Z~8dP6Ji8|X`RVmw|9Z~K{f#^8o!tb)TK&o9u?di=8? z;_*(`QpBUVw39q%_5{#}(}jfD%yvUQBwPq=1BAPuHXJ!?pV6w(3IOHi8W-L@mv^_L=z7b-omEq|FHgVJ zl%<;#?Zpmm2iP)KuK%cky{QM+k7Cs6ZGWkI7Ji1fzQIe|q2!ktW-f(kl-zd&y0cya z#_ef@AthK##KT~eg0%$et11I$_e^MPybMMigHnk+B_}{_JF6ZI>;v;)69y71C)A6q z9Aae2p=4Jh<^hLHj`n=N)J-jrNNTeOgDJc=TnYovcnY;n$elvJOF@rm;7u3X$EsiP z>er;Sk&Ag%1_;fsYIzAKFIhP5h!1%dY(vlE!H`acXHd2D3za3()OvoF$AOvJf1RQ# zfW0T8wC~etog|#g+nR`%)*ICml7w(xDgb9SIUYtOw}w5Ky|)~x;m z@pE3DxU6_=W@bu3arTymODEUdyHIwct!(@HoPrf)1?$%>-?wjlN7u50 ztt*b7Uf0{Z_VVSDbM3_)*Gf)xFQ`8>r+VAW>YdZqHcnr&FEPI|Av-T4J#kEI|6zk) zY}qjDqq7C_hWw+8Zkuqk$U~RgH6;&vO5|hnSP9Pz8K$RHFa+4X@Ub))8)Crpf=W4c zl;K!x%Hv0AfIO1f(kU1V%;YHyxx%yxAcL)T1cv&RPip>9?{dtNLiW4nB|lzTnhY9Z zs|R8b#nmNF;S_+^6CzZSW>YZ#Ddm3 zfQ-ugc-laoGIMgQ7J3W-2J+CL9(Zs#SjZW?BuDD-Gc!Zzgx?rkQeL7=0XPi!oo%%4 z0o5^6KpzZLd2Pn86Da5K0sin2dfP$$K4~P(MQL8&{hSfZ0LhV2h6L<&hLci~=U1J) z^qnmTG*t-kZ4eb{zp6ZSbA9Jqo4ej$ar{b7%ZdE`=gQkIE!R3-%p&d3Qr<-7aZanWs-LxOO$?wHqbxyjJ?=t)gq!mtDD1dF5K}(KBU7PFJ^I zUw@{1eaF?xw%)~?wEB;|qt#18qlcv|$xbUP8asd9_`K5ME$d%7R{C{s(SxqS z_l_>=ZJ2Xl!>p#-?Bb$1v**vu%w15lZq3p)YcjX(oV8_F#?t)stn8^vbCPGzO_-EE zE@NuaoXo^ISwn^n8Wq!j&*~}foXB}BkFS1}V$n*2Dt_1_huail>yisRen<>AN{scc z=i;3cJ&;u1kX-7CNaXNdiD5k0>k*_oJdZab!WAZgVRCP);V;AdYIDfT5RxE^EHluC zCX+UrzaChSA$%VVeJ&Bgm9Kv0HGZ{ypHZa2boGX+1Bvz%b-LZ;NI2?qxp3~C(0)_^ z88jVAV{^01$Q0O{F2oCCIo62a}`&z}}jwRdoFWlU;WKZk#4Ljl&E*+k= zFkyMsoUIKdEyr^XAD-S=pS-nhO6%#ut8W*+@m|U8cUHgu?%FrsD!qKYysM|O_ex&d zvHZHa75fgXXggVTqNkww*!-2{qm#$Wt3qj6apT6M7A{RK$saQ>Gcm6;d&8!)hgU!7 zDgNqm$(OyQ@|M(>7mFTr7QS*g-3QSxze)udh`5CjdObH=kzqp zz1TSSO4GboT65kyQSjdJoR7~HaQ<;e*rQ;C58aHC2mlOe6Js~SY-3u)ug_z)a~)En z7#P9_{G?Kn!0EQL=E6O)6ke6&3es6$RaL6o*?pLm%Cw;nQ%e|Z1z0~p2UdVgi?7RT zFfd3$y;?Ks*(wUeJkY05^*am-(IXIMvl@}h*t9@~I1gq+>^?k>pMKdU3UIqDz+;Hj z5##;dP#(`lKemGydboSxcCHg2gfOYUw9P1bbl*8)0U%)3qR`)vi%G@S!}h82_@vC` zv}t3s-lZfsJ3ZLiy!1of5C*dYu&X!ROhVa(HYiQ~J{D}QhX6)lPO2obL-9V!6N(3~ z;@u3WU(Sw`lOvq^#l`Lp?hyh>ZqHYx?U%~hy7Tv*sW^FaefwL5J6m5aTREkqV(jE8 z@;ix#jffqYId4XFZE^Fl(nBY5PaL1sdThbb%PV`{T>Hl7wRaxwzw==42cK+u{jJiT z%jKOtRlQe=_8-XGu&HwQp2FtCc}<5FtgD<|k~<=PUOXQ$k_SNOGr@Z^M4uxU22}bzP6=DEokh3145W>vw$;BBCWL{eyw)Y*6 zh8PJ{v2|D*44weN7IZMTTwN9!WsQp0L;)sHD6z=Qo@C#e>}_(m6Xk4?#FWupcASMY097epd=!Y#*rmn(}-nktj_KLy?ZQZ#t_B z3Nhqq_2DhVqe?6VVbGw4#`?4ReMWDnNM`X0H7Up)8=kcs()`Lyo&fK7d|;3DtGv@^ z^V_>iTF>Y1Jz3n^Q6hglBDXkc%GB8SQTziCgQG?cA3Ha5PEBpmp;N^jHwrJjQPKJF zs_r{AuYO+l?vv)*U$%Ypu;sl^Hr+tWTGoA`swp&&C42hFRrbfk-vCuS^o5; z3!~#=rDa9Oj~KrsYjS1j#H!_qdAZ3eS7p~VZray)^ThH;T?LP^r-DOwt9s1tE`HeU z0JPl}!(QN8#c0@RfpmIu55U61ykRpw5W*n4`N77F%EQG8Fp(A*itc4|)54@sU=45wd70xB>woM8HK7yO|-LWT8D84=CRBdtrja-3AHE=Z?% zYf3H)E;&~+$`rtx(!bAWySk(d!vP3XDTI1A9=Ts#)d%xsL!poi93bzO=o)=v-&^_J+v|mrTxDkTEYiaq?vOdl2$BAf#mt9z0N5)|lzj zr&g|=yR#?v>^r3w-&}L;(biYLXn5zFy&wMk(4DVaZ=+>xzVTK`NB81wb&IRk=GN4f z)NQZawQF`>?!;NsX67uMICJWdp@RqZe<^0{XlYrKDoavVE+1b}F=c)2g2n?yEvGiO z>^a}M;-j;Y`<0otfPw5K#i5A=VB!s403jz zN0|L3_(4LvZ2@R73^;ujC&m$a{Z6E%Kx(71ymILh0i$>m#uDIET3!Or5My>3tpo-0 zY*7mKNtM$(<hkyX!Gjg3fzs|fzDoKQL+iQ*)nyqSA0xwMlRZ%=fb$;aR(jk^e z6|YqO?42<5aIuzDIYVq35-w8%B?}J6gK%D=X_$c&>W9ugU6myt0lIa&T}jr{GuL4yYl8Z>awz=4AY4j4HxZEDrJxjVaa&b(cA;f=LdA8vj1 zal^ac?ECQNhwnUX{oql{+n?25xw&xbj(KHO3#(QZZro7WP``H1-nqFsDKAf+mNjR5 zS~3ayOUp`Jl9gIfoWhnhxu$kOLv!A~(-jBK>}cK7d9d)ab2;+%JAQ0Xrj)CfD_MJm zu4d|t<(u?+O-A~+=}V^yJ6q@0=*xrhOb3h9At8w#AztQZdl3^$8efJ95wSU4F= zaNu`Y%=3Uxzd*X)>i}eP3?R|$JWHddJnI0k%}?3xiJDtpH7lNy>gGQ{S(hk_kO$(2O$=Fz%5xlt)6H3#Hib_`mPc}NIb zC(RkG1y1;x4&ic1fW~^8VE6sO<=xjR&Udfs?p@u}v+Ug2xi!@z#wW&&iH{vSc4%}o z{>GO3Cp~KrTGm8sS?As@>wbIPl}FodezD`tr+eOgdieI!)?1&}_r6}z*s^$S?VQqz zg;lGHHf*fk-L!FUOJ+{qg!I&e@rmFYBL5GF8#gu~Yj$G6(s5-)38m#}Yis8d>j0UF-L4S@=qG=Dm)Br&r{2?4^(K@hZKu+-t7A@Ck=KMEgm&tI&=B==@_z z%hq5=(w!?v+rrLpJe*RWk%=HfGdjalfdq%&O-idxlFrbmW#lb0LT*@WLo^LixsnBJ z<$b zC@4spm>eA&C7go>4;mUZWc0)dW2a}t&zm`N?wqkX1*y{I8uu@3JiN52Er0*nX{+lp za&s5YPg!4>ET3@rL|!Le#P?^+=vAxvj9XuzCIN)30}}7+CQ-iZh3t zlaC6HfxFE31)vz-WusMqV}R2Zh6CgN!q#(0E%I``IRT{QqS7_SDBL)TL3S=VvWXoC zFaSm=UPDlnT|y-FfWaFEzBFP^IiB;v6H*-4^QPAc_tY3U4LREx53mZK!PRecpE zQfGj*PzLISK@Zq?U@ybNNx&Y_R%Y9TFa$~>!Rs2(so)GKp@B`9k`S!9D4TgPAt)9~ zOc?WG>OiiNcvc&D3x{~xI)~H~QcF%$r+7JwW*19I3@3@g!h{y+Qs`_T9S=onc0Z(} zT8jd_FwF~vE$BrI3cC>uXbHKm>1JJVY!cZEQyq%Sl zwQx#Bb$Y?ZjLN1Nn@*J;esxXf`)hmNsXBRe(Z+_wYq#gE+q$rN(@gpFXHn6T6{}X% zZr;+kx1qVMa9QPqNh#4WXjyVZ506QloH}MoTFm&d(WB$z($Ypue>piXXJW;wSsR*` z?QdPRWlc_Hetgon$w@IK^Aon0r?=Hk@2tve+FDjrNrt8VYj#&p16H4Xh{}WKa)QixPT6J5q4z zs-TCx3n9vkv-!n?t{C`1t5d|hE~#Tsrey39@a~L#5}{JwOb<8YuPbmRK|%*SEkbzsyc#-Jit=`qo5F%q(v60g?NHl zh3cW0Ko|;S6^soERE4Y>oSX;Ci%XqJ)y%W@tKFa6liv=y{OTK(7jIT{TqrqtI{(Cp z?A`UL3+9hX7!yA}VdS{6@>iIpO|fMSzzewn{bCcwq?fNr&03l?FDGfy^3=R_nKgTI znoi{$xiEWuL)M1+r8PU|m#vz-IB)8Ltht3n`72ki+_-6TL({H(ZDlLgX1qLYSoBaK z6tdX(;fd2GCQO?Yo0Nb*Oh0t6{B3$^l7r(Di%N4pYcKrrQt{pHl8?{k-#(T5?y)6r z9$9?z(88ed>nOaBDHTtIQ*Qy!VSgW_M)}x2NS{uOXYB~^!$3fU z-^mC$b-CIyQ0Bg8w@CW>g{|*UnC)4c9xV0mN!Qmec(;0;a%un%))<|#bf3M9lxlfH zPI?%~5}2iLb`z;;UAhQ8PJke7TWJa_PzcG1U7&`q0+*`63Q;PCTMF|SiB~95Vh8EC zkwK+@xCJBHRMGg-yH@j9BnQ6Hu>t=!alA zJhQeJbsDpdGKyjtf=fS3w8f)+MhMw|sKoVKEg$osl|l?}2QT5ooOtnsF&2q{(SB8b z`)>X1Pgmc3r>N_C;n@p0ZKvlQXkB{pL{{Ujl)1BqkB%RiICkW?gkdq!_|_huujDCf zz<~aVvuDj*vnhGbJo$;6;R$1+Mhs7wk(pM#VfvOGvuYZ$YU&qP*G(k@J_YhN&6ixYnB z7zhsz;vJ`g{V4B|-l;y}8l^+udsZGL5t|0Yd)lz=onhlyfO@>&8$rpgH0SZkzgM%6 z=%J|tPWr=o#D4B*IJ^(O&t)hat6DEZ&R}x-1ZwkvliRKDsLd+3b7+RKyZw*`{(prd zyW5*o5`c~8xue!9eIgo)eD)0eri7fdJuM7)Y*Tyjes}9=P#5|Ds%B5XW_KYvlX{7B zq!Pm`m{EptFtiSgvTGT@N%cc!gvk}JNI6?eM1!Jc$zpvh>`~d81)SQiR`gu0x^T7X zmDkI!+{``Sv+%_Enfs1q9>5>rN?l$uHZ3J?^-s#2 zJ#+Qu1pyyW1?cBM^DU1DlJQ2w|UaC>#O7OmYjZc@g`@#Cf~T9jQ{T(F{Q z#rln#8uskm-?nP~w#@9sv9Zwu2KJYSx9AbEiD?tYq)iYbdU)Kh*qC84QGic39#5g5gD!`5KQrw!UBm@ zh0l7Rnc{;I0zKrxWk@sRMd*Yi!MGVCp>=pw%XJF|Xx7fpjPz)Bn>`;3o#4b7Fve0m zCyZ6#N*x4rQ{Nb)}e)5hWp!M^t0pf3-* z0i4zZ5XGM9Ndf~T9{>EwB-lM`f$Dj%2&Zp8cuaEmK3UvlUjgE0PqU&7<^{7B?N^1T zdKMf#o_+LKe&@x4_TIUNPE0>|V)CX<ewp4DrKejidsb z@dvQL!y&)rA=2hVqR4}AoiQ`yk_V7M+X)q-CFl%@?G=*8bc&N2B4(RT0AN^+3ZuuQ ziftrR8?pf~ZAzutRV_UP=(IpsWURaO0TOJy9pN)8au}5dnD>}|7ZT16j7~@}8t{h$ zz3rL5&v+K;Jz{vfPx$xw`@r}}W2HSaLF5rPZe!shb z+p|F4JCZ|py?7$FyzN%Ek!6vCLGHMo$)hV@kQfE>J~3+GjH5uDVmN?-ZP)lL%AouX z3=BL$2zZp1N&O|4D5WwsB2dF|woYhj!R$9L8-+_J;ZUw;rc-|SU0wwQc?k~GYEp{l zZlyNG=;qZSdQgQ8iNT!?C9+(te9Md4T{GvXb<2=!2=L5?!Hm(V+ea@+9?lDLLvnt6 z!!ac~dzdjqi3~F+SYrc^>rP4{wOdhozgQZ;0SvSTw!$GsJj|{YF|QX%B^tuKDjqzp z5M>CRBhvxKTkP^G5_Q=@wT{sHAqGye>8Rn6nlLxiXH;P-&)J?9*^N15cxH!p+PuiH zVb52`&d+T=n!aaG!p7VzXC$VkM#V}@^ymo_Clr@VuC1S6dthB#=gJ*> zlP6D|IDh`k1zAf93yRB^mshRcu)Set(}5MMH)hUT5E~n#FAQDF8XgxHJ8oiHd`gl$ z%=H^Mpuha5-=iEnsNaD8Km4uV{;ePVaPs(J2iH&g?0nwWS4!kh7JhZPSl*m}a!KCZ zDv~Dl;pv<^r*kL7^^T&f=Y!9g^6Kv2n|M}i=UU4mtZeOMFx^I5VEz$x=qaz49x6W2t2Ha;!UBF z!z25}5h8^uLyDbi$wz>0)UJ*dY`5#*^q0I)g~C3uq&N~)uzvbx-CI2qQR zBwPVu!`q?xRG3RaJw6Z`9FLY}&sPf%98B4{En&l&u`4Tv7v>C089#LBpkYx%qoiNO zM9F(r@?stinw&B@J$X{vw7IiOw${$yuxiex8u@DxDKn;z zN=zIQH7qu6c+!*^6Ia#DscTzWf3&8pdu3fy@}!J}@#81FJZ09R#ks{LMawGJZ`-+J zU(1R$8#1#N#Ia?`JNl9|K5?|Py}04AX$$9#mv0@$40)kn{~!JMr60f8@5Pt;zt~Tn zvR?Ypk6-w~4}S2&AO2u^O3a4BlwFnS)dk5bmW*GyWW3nzJLlYJ$^PVA9v`vTj`%Eu z9_6|d7m4pwa;LOA8GyUb9@W^{{L^+x!N!H57+w5k z<7Vkb<5CBSidR2v;UT#!Ep54EVDkhsb%Ml=LL{~r^?*kVWYL3cB9c@#3V`A@&_Y0> zeynONGe@F%3HDBxMPYJgI73Xf*vg}N^vsz-B8)1(<#h}slp&0Q)^&Kj)DYO53QbD2 zp|24p-bhG=a=b_w=s)TVV2TO(QH~2#!4Z?7$^}4Jc*w+SxU0oy^tANIPItYX z^dA-%J!ZnV)M-;DPMeaMvv}93Q|nrq3mfVd@7Xn@a{0K7ba^LA!bgmXPnt1z_J-XH zcb_S3JhtiBh03jsW5*^$jfkyZJG-oGQP$GJ+@fXcchuLl9I9HoeqPps_|c;V%6nM@ z1`L+Btt7krFi=#?hBaBQ9$Zwva>|OO$@z1~&CVD#c|zRFsc|zWjhHcU_{_AJms4Wq zWehKwKX&EP@%2^dM{8$vHq5ZxCJK0J0*pX14%=Xxbz-|15YP+A_<)bfgxr{#kzG#u~l7O z$}lRA5df*247*eT%42L0fL5RyV0)2))0DeFVl+@CF&8E_6yl$FIn|~%l$4WZ;xVd+ zR;txupPHZgjb9bY5Vn9X5ZQspp-xv3RMD?D9h_{5#-Or6C1O|<@umj?WU7%GX9;w% zj+W&5)esmmn0^IYI%Qx|aO$DVZV2J3iXIa~PGwdZz-S9%xLk((V4x%?TdABg;13F9 z8&N%O4wVok`-4MzNdcjm(O9-4{kov7i6q(sBgE+I!O2_qq;B6aa#>+i{K%n$2Fg!2 zirf>YMvqAzpE^0cd_&EF%a)Hh0ea ztR?xy)qD2T9Y0>RZbR0>#iPf>qh$>oD4)W@n`Q$CO-~#7&aoxm-YEO(l1x#-Pdf7D zZL81P^FD9S`$>ELJ!veR`SK7YF9V-mF8;b#|CYUcheBos%Q)g-7s5)A1A#V*CFgA7 zEf$zQ49~l?6&o=`1`7`>;pz>LTqLT8=TJICIc9GMf>DAyh!jjXks>3~kj)lw3H~#u-l0z=OFk3P7NQmsF*GjWTlRcWemJSknnYlt90ZA`wTGUu-gf z*$$R$QLuFg+h1%)0w-f>FsWvdGx<@M;#nFlh0}}CNp`6*0|Y~ZcOt}B$D1PAZPXX& z0T}XP#L!DSL(DUWQsJ@6hI9saX)o2aU!|<7p0IA+i2UrR5pnXJIQ^Xr^2u}gNoTpz zrz|{TMa!!~`6wqof~74hDlR5c*q%_nk@@mppYs)TifiA9m;OtC>A>=CpZ>a@IHR-*x6} z#g?t}7cLqzX0&{SUfQO$tU-fP65`J7nlB|t%lhJC;iK+?hh6e^x;xwCqvt&6%nu%o zq+Q6R+z$4Q2VMErf6Q+~2*FAq%!S|Y;wWwpAN zG__+3U?Ak-4M){SmB|(uHMlI{SQM*jL!*+~W1Ni?VVeMx;q?nsY1)59wt(L2D(BV9^F`N(gxu=MXcB9k=Xz(5AcXzdzwv`&XV^db$6lmtMOH< zlS)hC7i7l8kBp9v#&glIA@X4b{)pe;A+BZdwV^z3MTtvVmi%(#!O>AU)vI@&J=M_B zUf7jJCyynr%-+$sWdK30-8qn;Pw;`8-i~s*t0m)ue+XS^|)fJ@3twlDEO4DqB@s<1qG+yTKZI}`CzR2h#^8H|3wII0@_ zSvifw>T*w^xI~Wyk8k@Q}wRUtTQy;KbtX6;pB-&8*(Nd+WLOif!A{ zCQTYNKt7ZO0Z}pXzFOQ6KJR7BnmIpv=CZ|UXLn@2du*}%az8wAT`1I#G`Q|03yfO{ zYftx-?LO>NIc)i^TT+cBf55EEAmsEsDqeEo0F2q4Aq;Thfe;JK5~-mWDpAb}FlNW2 zA!Ozfjch&`1wW?_EyVKrpc2LVDB^vTHynwOBZ`mKoIurvjG=><`ov2y5eltU zJ`>_{8Lew{Xy!VEv*~0m$6$m~lzN=sOH#jtyA%lbw)cBa5a{}e_k<1LnJZ-Y_i26K zkVJ(nA<}~e637r+FZ&4d4bA5jHnp9BONNV~L+W9Jf=3OzJ9y+nUSPCeEoeS8Zq>?B zSxZJHPmGO=kr#bvQ}S94KYC*=OPunnLFMD?F>x`m!(-97Vq&J3e&m~y(mrEiqehI3 zlizIT`g)<6)XidI5(cl(Pax4JSdYJmd*)3d`u8MKCW>k_O3r49Ecj_KS z#n7#aLU5@b(_nR(YyiY#DHyI%8t4Vk2xyr?qR6RpbmllLwWFgsNvyJX9u|eBb8?+4>mZ$eWQb|*#l-Tn+o+A7`MP(Dg$x>sf4t> zQ~?9;8&NQ7Q5qWo@L;qc&drqvn(Erm zHTHBjbaw3S?mBqoYRjcdtJ)6NTX(5>ZsVb{x7@`6*VMj(xi%Y+xND1?rH7V zxTAS|>ZEa_hu%Dx{Z#&{S7-j?9(g}1_ul!%Z=A?K*1CFS?TU$MNx%JKzZd!q`0-2q z<)f;xak0`!hsVWcOimv;YSfD__3QUi|Ce6uH+aB{N%4boXT=|0Kke3`Y;sc0HZC0%CBdv z7CVAO%Bkm&0FP9I{f)71LBj8%h;bP$g%cCXh@@=kK2|yvsumtnQI+uk>0(twC>__W zj%utavFB2)TBAI95UyYg39_3itaj1Eg^d(WkJ+v+7anMXN4G;L%ES81oA`0C5M<;L zcsOJ-IPI`QPF00K9c8~VjLLu?P0WxkTu2}iqo$SyH#_-Nj5Qn!XETINL)9vS3sFLp z;|~lOEiy7`aK@!;kETs8UE3iu0|RZwV{Gt?N1c8MhEwI8fhxwj5Mgi{L~6eFtLgi8 zOs?CSv88szlu7af$WgIT@`J|Gqg=nj_X_1{Yse71DwLKreB_AH;}c5uG?eV#xv+Lk zVg1&k-F2%D@88+gv0L7C@9A#p>1n-ot>yCN6-N)Rztp|`)~m(M`;%s7%6A-x4I7-C zK4s;`#=VC-8V{Uax1}K=IW;3W=0;1_m-1YMTZ0bps4MUD^SK|LE4bN~yKn8wwI!)* za#N?I$afuMM~;kr;iUoc=L`o&Me!+cp!`&{yqor;AN`hm7V8H;{K2q6FJxxK?OB!n z){#X&>BxI>QQqk)l$V?|DuYIm%BACDA(KLq=XWxc zfoIpLAWxqLwO`HHxp~sIH4`@1Bor)-9XTBDw+|g64^;Y;B|QP(6O^mLgXANl^1%lA z5b5wyBXa9D*LJoq+t*l7zoTexLs|3gwa43b_H^yObWyriQ_qFA>#rQRa&6VIw(1LA zb+6xA(Q#?Y%G&4&6XW7XrO(J*xAWkhgJnwa+0m~-uUPs=8 zuDpj`d5?SYt=n8ExN~aBwdVP!>*lU4n7C-hn9M1olE=p2lUf4?43YQ$`}P094}OG} z<^J`1;kTE{6W4}mtsAE8U7gXiYI4)+$*;6z$u}k4X4mcMxWh;xKB)8wIshaApsW<(jX0NsOKKFbd>F%DHsu|byt#kKTd+oK)J!kO) z1QNt}t~OPciz;6#3;YJo7@Vq50^|@dwg{$&=cUI4D{P8{#cc5B zB$#!We?9p6{%PHtUR$&D#f~QX2a4?{+s&ZxO(TA2pT?TA ze97i(*R~D~be%b|_{6crCy#cWKDMd%;(oKN8>0t?hhM)wdf`{Uz4+_jt?TLCczvk* zowrsFjn3M8{Mq_NPfwaLrG5E^LudEBetys43(Gg{eDSrhPe1Xq1FNTfJz`%K+N#IO}MaqhMCpJSLWKV9{dpik(9wx%peC#$zNrv}z zvn;TYA=R?1j1yEPBKauVAa{}J5wz?@cQEkKK_~Sj0M`xt2_P^8u#gtb@tICBE6eY~ zC#o1EOd;b-e1bJj=}A=nsKgL}Sw;#a0RVG?DaeT8c0xS`UE@rFpH{;`(RFIS7$8OD z$-x3|g;FhURC4M>dm-eeE2*{8h0zIMS*3|NGp5pP!UwZ?nzMN%`ydn;$jcZCasx!X zL=u9qufi~`Ss~@^N{n1CkvhdEG0T!)HNNpi#jfqIu37qQQ|*)EUwQKRXY6m^;NM>0 zXDa^eD1M04EDK)}{_^Mcw`Rspo6@j(!I0uMVv4xxD=R*=1)=tU7;UOJC2v zk&%O=*Y{r=e&fc?fe-$4^-rJg8M(E2bh!KNyDLX-)f~C}+OkbAG_IK5wSDcrlijvnZXFuhIeKl|)xq`seO;H%FFSj3UC-HV z0|RDR2S%^&yEc5{?pwD$`TCvv|91SH_cvV|-umX7E3e;fyD%_q%i*yrx+~Z0TGf4I z)ArZ*9y+sn%bu~*XFUDlOLbL~1`agX7lX7HIu%`uiy3=ZM^fH`F-!(uLXONcv*LTl z`Qj1dz>F@X$of1Ben=RdP#A#2wU~&PZd(*r#0^Q9rxSn@c;f+6A!oBf?f1zB0ANnV zESpkR=p>ILSz2Qr8K$!qJ0*|n5i_J3zC7K6>O$l;rV{jp>S-1Wh;-ErD(EB;hS?FyiD1%?#?(tfzy-2_aRc&02b73H2@#$^Z`%ORP*Q12&0|EIbxEl}HTNqySS! zbOe#P46cS2);rRy(lJ&#tE-|~V`3Ooz!-#voJ1m>P*YScX0aJwS%RVE;MA1EkS-78 z0!o!~Z7jbUyKC3Dl}n!+|LPM@J#K%+`0+6>JPpfw#=h~6?`4^3;gc5rt#$k&!k_)* zh4HVwI%{V2rVUF^A76i^Z^!WPuF;WgSFdika%Jg-Gt15$U*C6e`_;j{BP07pM)!~2 zJpY^Dzx~Dk{N4Tkb>Y1a%(6CLzqw>+w7qY*@$iKyTlURdyL-uoeQP%E+H>&q>aDvg zs^+{jcHE>X6?@mtvft6rRKuDgxke#iSi&4vLAt8~T?36u%iptS4B=Pccn#!wFBxkXn3D321k(f0St_GM1 zD-Wt!VhSDwBNq%3lSdeIw#2N($-$W7am#YGjNY}#kr-c1TT0?l3t})N<38(CTr~Lx zO2m1jIcr(82wv35VbtCid3aRCPcvj8lq25TkDzi*29Gv*ARa9+h&ZO8fxR=)r;>S! z*_RP8tbq3z>18dWO%_eLsG@QnrzF}G3faIfO5$31Q$fWNs-A%%Mt=3;yq2dXkF$R+ z#(uv2$>*MW^6_6h{?ZHfv!gG*_R5pbJ66=<+K(Js zdFebX>l!R;bN`jj-pfnQo$fq$a^scW?xEq`*RJm!xpCgr?OGc8!sRA4;L9m_;-7VlU7S(51TjLO+;Hc`2%ST0U^cfep1ssuMS8H!vP zUA8i4guyU*NX11BusgCjr>iBuVBm*HrVwn2x;z(Dtl~>&yVp~^P2`dRw3y{Niij)0 z=>RQq(T+IL2y;2*$|)Ey@_3@e2&TGZ5F6{V1qh%FDse*bkk&bU94R1I?=f&5X%-=; zk^od;irqE#J7pIYBg;#;rFc_F;guM$N~8@oxlPfCrvz<0%5b#8K_0bocY`PG;iQ=YS5O!M3`_QUP=mEhyg*!RX`TH)i|$iNL8eNCSh2AyaMRNT?0$!C9m)n;LpGysM!D$1|>pjHZ4wc zs&WSbwTI@mxpC^lE9NtAM+?cY<7=<iO4Revbd>@l($~^Z1ibJoCK$BQR6zRxGLSTs*Cz>D8IDo_g+?U;NVk zPR>uvxL%y_TIG@j)7#r7H`YyUZC-HZ^oDE08?Fy+9=^Kk#`T@ouPyDlylh}#MStJA zt5*NKltqzu&j%}`mk}!?pGHto4#v*<(@YtZ$0?hs=cqS z+fgxp(cFby8#eDHxW{Ztd}MAqcV(q@ep9a4NSnmq z&=mmn!Y=aaELymk;VpvW&q2DUfet>q2F$78E$E1BDC%(mz$R68m$7&x*n$c$miCjb zEO;hW88c_mi&qie^{`*MM8XRu|M8%xoUpVIg6P7K0WL~=gQ%!N-f||1;8+}QDl0ea zpRZmV`^s}Kzx4deFFj|!ZSc8gD{87+w`^Q?=s?H1RrOtqD_dJ9 z&rYnFHM?`ktj?v==C)Qe*Vk-Zv!cIu+nt+RZj5dl8Qy#A#ddud0dw1_#uxjDV_L|ogHoW$({oIs&#G(VZ|0I`y$-psaP3>O* zlX-}n%v_6qA?x5hvkrh^eVJMLY{KKk(Hm9N{fCK;fj7oZCalb(d>_~TLF z(CodC941iWMXa9O6*fYn^Ac1NY{sLatQbBMgjO^JaEc$>49V)@OVl8wz6=K^%m>y) z{)E>fr{u1Xp+}pt0ga1}D~4cOE{t=~{p1xzo!I?47$| z&9r&VbGjBSIkdlR{hEr}Inz3ttClaeAHFizn%delrM;>B=;3uE*S6igv+d@M?bk;R zym@=WU~lWG<6YP9tQ@(s{`y_BtQ{jawhdq3diDB=yT7^n(O-Y_`M-XAbKB=v8ZUQG zZ)+O&!n8?GR7`uOs`Z7o6)(+O@?vAtq`Jng6`l7kF8p?+?JGM?gSPGIC-fX1c^xHM zke_j4@GjgCa0clNv?&~%hyW8~4I<0c*kIs$MVPu;oq*2n+bZ|>dsxWDaRM%%v}XzAHA zXZnm+e`tT@=gB92`ph#wd+yoCUwZN78PnPp&+9+32!|KG z5qBTZNm5(`?f)3_m=i`PNeqhHDzT#O!A8^2$qhYmpfE*ks^T(S6@1T56YoK5c;@1i z*{nY*NGi?R9$jKE2cIat3IG(PKu;IP65bRY5CYvt^N(19pj1y0kNQTLQsZAx)SObgm zLZVCcSC%+^5DK9rvY6uQtaW1{RgWG^@rhO~WO!F1085m10UnD4xinCfTKIo`Pvt^M zYBLSO#Qq=GDr`AEI+l8Axs4CC%dcLTK5cyU?DjYI@3}RyYv{_Zk)eH~BYSR+bR5|; zxxTJ$Mdy;kZ!9@}Y;DhlZT-E=_wB7)wXV9W(=2P&f_XDq8tr@URqMN!_g&ob=9}H` zzT5rg-M#O=ck08BHVqFopFP`kg2JF9QKz3t{(+pgW%e05|?@70rce*4a!zxw^P z?OzNueKp+vFQXmz&Nfb~c=5aTcbk9k{U81a*FXO3pPrpCZhFi73kMh9A8LCr+=ioy zQ`z?A)ikDe`5DwK0Yh!v%-VH!Z^Jp|aZ3Y#j3ddz=(IeH#)d*RM%}o)bSN<~loaHQ zdse6dLsS!FxO>MKr#(ZB}+6Oj(OOT zXq+JiNNJErJOU3@4ujokk&(qj2r!K2VxWpKt10q?FoI*D*c3G|qI4YRR2@Z03xEb( z96jQtP!-n!k|3Cp2+&*eIKX1&zyYM?RHUQps6|3NBE?q&1F8aBl1CXz%5d#;HrZ5{7DFf*V5AsJ`B#~b|H@|W0s`i%C2M^u8{rat&=2!N&Y*zQ2 zpE9p?a!cKUW3P9eyU=<5eCPSI7F>7vZ0qJNwXm$NS&J6VTF^1QrD1Yo&7AcsI{Png zee=%tci!H5=k}rBynp`VFSp*h*>Um0qM;iLhHkFD^UkJQZ*9DGW5d9;O_v9c-}&cv z-yZy^fBu(OTkREpd%fd#=Ne~Ee(DE5_`#3tuL3^yqaXh02ao;ZkDeX(N>yw9sa@@V z>6`oYHEYT&1+GHhhymI+-$?c%L(7r&(g`-C?2d-Utz{9e9ySIryv*NX%#D_wXtATxLV1=5Jx-CxB~po)%F_KYA#F+m0_LYcB%X+K0Zu$}Op#a(@o2Xb z?6q{1NDi2%D;EdNb6p0HjKD_aSq%C)5`!XHJGC^bR-jH6tV2!kwS3-pTuLT03;+iQx*s8F8LCX zP%A1{6kcx-i$G>Is46Pt<(Q~A*Fn9<=d0%zHjP=?G4CzV_1x zD%UJ&+qHSaP~WP{msec4Y?ig;%;~P)3-j%tEbdxWvtmtEXXmWN3ukuBo!U?{p`p5Z z^V$`I{abF|-ul*Co8Nr%@cSS2fBCmVzq+@ex38^lXuyj+j_pvblFlF5!7V*u@eFrPuB2qR8X z2?KC?B&;OPt!24la4<`I7IPgCJbDzMWXks>*gTz7S{4LZ4tG%jhV81jyxktY>B5I>lShT}#;mU54u$}4$|4Bz-1!~k5^s&LsI&Q-6-g8V7?+wwcW4BU z>@<|K3fPLNs8X8lV$?<86?9czOUxlgK^(NAM3e(E6C-VYr&Oh+L~x=hnp>;}4ll(6 zMz)+sB`mI>%7F(|o=9zS3C79eRFY8`j<*9IxJq;f0l5rkOLb*pY6L9=o@0Q;#ul6h zmgVtMXG1Q<%ckh?O!uz`CoJw5zr17G)>SKeF7Cf`+x%+t$Z*%d9IHFZP`}8a&1-T>e`iNSzWUh&YRZOJfUXxgoc{d!~0ha4{dq# z&ZfI}w!iuI@ee*7`u5*WeDK-wp^?^}!Ffa1SKWPg^{uxm@n>!m{eC$Wx|L*s`kKf$IPg&28dv#)Mb;tbrOMB|>UxjNKSSKaF zb0^1Ef5^&^lFW^>daYlY3q8zc0K9a&XN3fFFtRwCU|eV7<)V=efR{inADuRhZIH%Z z8j(_mWV1jTzvSV+M1YFH63#>@TEWmu$troS8qq8d1@;Udeed}c3WbM6T}(lewwaAR z1rbaEkI$&t@0F#u0%d=$5?*?3NFw8$mc6iTO<6F&jW4F>#);1!`kv?v!rS%*#OQXDXr z0JAlsOIc20AJRw|JRrwKdravXn1f{uHbzmVd)pY%B`zAP93qI{M(<-$O|2Cpqw5BTSD)!Qc;@u)uB`s@ zYReac_Jv{VSHt#oU;DtGnH8`8;=A8B&$91j{lI=5&&w0XPHCvN4_e)8tN+s5^uWIT z?(Sh(I1!KXoK^(gUWmzIjPvaHR2pl5ds(gu>8`09AVS>(nT!i3B7!Aq>702B8O+`$ zK0rRCL4zQ-Nqn;ZZ}N_xbWGX{atNEAYl%+Z1)$!YR5YhzrIo(7nehL|dt)j~9qBke#% zQ*o3mJp_~#Vo^oBcfty9L0z18^3$nYlK;72Q@XqNn^A^3~11 z{`;jrf4i)IsPgFH`ip0l+_=4X^!n1F{$>4ri_i4zId$^=z9kQaTF}v8t1bRtM>{_1 zYu>(itov;7(TQN`=(@ex7WpM~<2?gBK0 ztWstv@vb>lkdUyfP&OOuV5S|3W&E+2rhx}dcLVbZW}QI^!x8fmX^=PNg%XAu5M(5n zje$y3G#yFroz6hb!Y6Gil!ADqQDD(hMdx(eL21z9q;ue%I!ROn7019QWQu6k;=UAa zeeuXz65s%^i3b==h3zEUBxe-GY>d;uofbWUHW=hrwL3PD_TRd>|JJP?qr=;83~#z|t>etGXI^>nv7i2|t@`Cp2UiGQY!|j9pbNhPRFI<>^>f+Jk+du4W|7xg(wu6@KgVwhr?N@eJP8{=#|MuPQ{loXa zXMZ!OqITxAmf9%|b?pmkMvgX_#eFs0_PM+Qclw5PZCe5t&px&XMFtVLed-uO?lIJT&_h!K#uJss#X)#acegpyG_k(@@AB znSzMGe$PszMB=pxv)n`yvc-_d)1%VuG4X`+gpAOfHnzZ`%6TlJD+}W61i8;9Ou|1r zNX8Xl@uh;9Sxm$f##xof^%C|dS`BbK*`0#c zDXAC?k)e(2U_r`r5*-xBHOp4jbgh}QX!)F_%ci%tPibqO z+}!X=ef6yFjZ3feEg2lN&s3Xkzjff=`@Nt3?Z&_SuZtgk-G1)Un1u_cZe8EhbEdiH zeAA_ibIzP>J$ClUv8{jUYqf7r!Buo!ZM7eD`2D&1MRhNH|NH;&-S2>-Ih%~h4{ z^;4T0=X5k4+ST%5PxFHz;bAPFdt&Sydo)7lR1g@#{Lv3S65A9n43LDM%d$e4J1TZ2 z>XuMpe};IC@t8RtvY1#%B187*fD$Tkl04%_X(+TfX|ZQe&i4j8f=CZ)DFTVO#vEWw zssb-s1lcl~!Ko5pvz763XbKE|S4Bmjic=QE7>OmN3&BE)ld#0;xtMaZ5^bUaiTIVC zsHB#U28dcD@e*|P$aUHvNgdgM;*sd~%LpH%FJ?sv4<p z$egW17Sxn0RF-DbUBRRw8x)^KQ&7%qr7g?5);Rf(3FFvl-Hzxyh|AVo6(1EuM3RbH zz7Anl!AyVz$gi5t9jn>5Yud(DQ+BMGeQ4{kTtH7FRA=S+%IMdeQRP^A}HVX`b5NGQPQX zY)gIB?(U^mt}N>9U)K{^CzlL z9GSU)U*nMzhmUXmsJG?oA^Y|_Pce2&>w{}^zZsc(dehYB9)IlnKmF;{1uZk?H_Tqp zG-F;<<${)#n-|?W-uz&&`M$drQsN^JNa!d0<`~&9>p@#FfOQe(QyTlpaxgeOQ5Iow z?0@We;5Ei;O)$8hsQkPeQeYJI>Ip-tLK3Y2{9-V?Q+Xkm4FEYQ#$Iu`BxG5T@vt4& z?D{i6R?h0O7bgt0*k)qWtjD?iERHRQj*wM?M7)quh>vxE^5~Sg{umv_ibV^lF2$sB znKm#dwMBIjCVUzQjH1kf)I6P!AXiffqtyNKrKY8L8 zKm75J>t{Uw*_D?2SKI7^(4Tu-<}YrZI&W#^;^lJ|FRxm>tg>UiS=N*eSl0OV=9)db z7WMYczuePtv1h}z+eh#HssFS8+4sp`_uP1UR@agjE5_T;cg^0kYTDlJDLXe$+OehK z$cb%-x7F*tM*E&f4V* zcC9~gVD6tUH{v^B2G%uTdk;2c_c#a|D5!T`+;PfqD0Bhy#ehGGCzvw;`58}%7>Fmb zN~SbhS}U)ca!azJ1y`Qw^l~|2KAVr(T4AAl^eP1mt6ice!BPo^9Vz4b`T0zOeC;|(_pDt@vp%o7#UDN7g*BoD^~r86Fn zgi|pcB+*fvK?ksLwkCca)x0S18A+0ax+u*%0g0LEa{Izg5mbuUERnfIBRLh3A}naB z%^qDdt7A41ia!8~Cp-oz#i`t9ybA^?o{J+M@uw1jajK{Y8M;c4@~fG9$s7V?e(_L2kh*a zYqcEQR5Pu)W#)pVvzK;NE$gaUx@^|GdDB{&E83eUv^9*MKeuMjo&}dLw_Uif@bZ;y zH}0PL?Vkre`P+%#e6;-hg-J`=UYas-Vq?|J&czeww~lXX9KT|D{fQIp`}eQts_Nf0 z{llKdzw|VHc)9W8E6wIz_9O1!47ZK$o3VU;#heujDwnpIUsZQ^)xNQ{^~l~W2Ufgy zzV*Rill@_2@^Hq@aOhgJ4jp#4EC6EG8nK=4_QJmC4=v0Ms$_a%c0Ac&YhVKdXYD1Gp~;M$}eC0&Z|3h zwqx(sm2+QNKX=Tr*)coeCe_lgKpd1NVxc4WyChDK<`te@9yhz6_IUk=DOz&OYF|qrw%#Y6_3S%FrAh zF;yCuIT+rNZYhzT9)pmMk&INDVK00ayvw~UqKm5}JHnk_rW~otx~x60YpIyl$X>W=pgETkiIYp6&D1!POP~ z<~9%JK#TpH=ciYimM*FuU)?xsZhO_T74@q()~{GyxpY~@lKB-KO_S#~jc=`=uyjGy zfqe}pPB)%9wQOK$?_2L(djFIDKiuDZvA251+KMG@FHf5^v3}0f`OOpR=Zu>*bU65`sF~=?c?=Zx?5*1YO3t&sN1(@?&-aA&m38F zbpNrF>wkBl#VpIr4F&=a$?kF_Kj}^ga@qxsq&!Cefpv1lW8)YU|@t zT&QIO)kQ59lK;db0E&kg^K*y^Fe;)bIRgWEAjcF3szOP@U$PDWI|HaF33u}7k&ECA zY|2}(?i^1N@K6s2 zBYBppOQA}nasHT?)2s&R@jn2E?-e>>r-dVh%@!{xT&sx0E6|?{*`E&HOZNFz5&2d7 zzM~yGUT@vAuWHNs*29P9o$N9Obqx;hf9qcF2cMpQ>-Wn~otd*^b;Z)TuS}aXsbTi?c})}RX4}6O zIB9;5d2tAK57wg zXBFH9v%A&8xQM7nBm$OF1WP55C?q+tO3@=;pMtyxk4h9%B-FaO9`-0b9>MxkVL{Hi z;*2|_2B1Vn(i|F8-J7x$_p3w4=k7Z?Z|{+1XU}aI9$YTmLo@+j~<=Yx$Nl| zp0(fX^|N36)UnK^apg4SC-E562OBox9@;LfqFHiGtH9-pKB(%U%nM(y?;jcvP^ zH=o$mc;aBg8~YZ#esI&q);C|D`3?RBEv%=dz^?|~UiivD!b<~?`%b_MWeMye#8olw z%);Bjz_uCLJVl%cN;9Pr073|0mW_!~l~9F!3!RZJW>$}Kk?5sWU7Qdf<-Cz77mt?Z z0tkjk)v~*&5K%4a#F!0=xdf&j2^O1kW>i>&U?>Ji)Jsu=#a&{Q@I9ROB*p;D53p0-aa~ zUM@0pN)=0El>n34Z0WH6o?9XVSta{8==EpPXAetorxtHi@zSceNRJztuJ zp_cmtO}{-?f9ZJZmSdgEk8Nq#yQ6yR&N)qU?3-Y}I#JEP?^C3d*p44?&E^g2?WDT- zR01Q&gPh3AV77S@xDHfPCPy_NJi3i((_iss#29WSkBq|ZiG@J}9NkB$Q%JM1bw+lyJ zQ$;+ol$&)&wycWh(zu+Tw4NA#Vhqs9%LiIyP{G+4)E$fFt|A#Mm(t-a!bc*(bRolA zF5;-g)@XM{b-;k9&#P`3Sf8&NUq98l|M0TjOWk+hwI37Ra_7wzgEyKF9htph<15pq z{`BWRHNRTd{wja?+%|)`NAu_XxPN9>f0KR9b>l$gKmGXozkK=S2~~Ah4%B}&*wB4= zP5YsPjoUVxWldZ-e|&4hYYlTIHq6|9Y}KsYnM_4{!M7a?Q@I zHP!1nCa+jDwz_i4-1->{TkW&f%T<+COWW`DFZpJOMXfF_39tda9+V8mo4>l+{MBI7 z7yXUz_cY%)(=u?R>ACy2;qAiglO8}n8SpkX^7K%srs5rmQ7PBSg6tw#zXH%5`B!6&{q%*H&!Q$eccb;$w zJ{B(IvvDGFB^(RMO|CWzS40r$dPjEGUPU_(FM>rf5=+F9LE|FPpCGU@kJxPR2Q1++ zkh8I(nAMlXMJNp=DdJIys2=S@GifO)4jsG0l*@}2;7Gdi2vs=`#^mI(L^_PxCAk1^ zlR;Wj0wg^}MB3EnwKPa=nVt8aPcw6$f+H@b(xm|CmS1 za%U@;2V4B>!E=||PMz;K+ut>CedXoLi|w~9A0M8-=Z&dLmyfThwcqpn$p*8R;nN)pj_zG}cwf_wty9;op0sfO z*p`Ngjg|LK*Y=)VIHP;>*lk-|j-On2?e_VBBcJrOd^ON`>sU?q&X(HM^UT>Q+8d`Y zZk;->;nlk8hL!W~^)J7VP3uktpHyiWro}@~xR8C~vY#OR+Fb5Rx1Zw3ErSKEVaSZE5{&TqJxfW<4-Xzu%SirSb;f;5i$7H?8>HEE1X9EXiQfik z%s9w%fX0NSy2<)1*MkBWIN`CSc}(!-L&P5*FcCaVG`4~;B3!g&o5>A`6d`Kiv=-Hq z9ukJR831C^kw@v|h(cb=%?f`&xK}5DTF4dV zYoc*15!0=1DC8{G$F9I&pm9XxSMyE{c3c>od#b1P;JF0{Pt|YU+tPh_!Qs=D%a^}2 zVf>GO^3&RB&wt$4Xbs}TL6se3_!ZAPPQ87^>e(^%zkTOB6|esMquxgQp3;ZCO&brd zwjYaH`o_+>?yVJT)=XNs;N^yzquo{ia;@?Fr45yPcD=TFee#yAz?%#R8zaBq? z(BF9HOp|@XzOs2%#iEwV&UrHywv213Z&X2Pn&+4R`U&*ND0q02D)>f| zEvb2zeHqLDR+s?Rg`R z-GGlo)JiR2kXtl;RQtDjAV_w|nte$}B*}@3m42r;Oa|>e2M4PO%^*3d_|- zX)vV5%PRgohVpniMr-mL0S*`Yf2a|idno7 zkBdr=DTp?`Bf=anN#aTJFvt>9IRz7}EM7cjEtK$Z5gtL3*OJJ@;8S)|tUKMKO~*VU zm|l&4Zz1PT%skhR)?8pzG*wTv(jbY+Bl$Q1(m)@ga%PR=Zl0sdTQ;`zSSTRXT!Z@Jy$*&e&`F;D*o2>_~wC*|8xa08bwOd}CH0eh_`oWV=Ke2P= zw51JWPH&n5zrvYq{H)(Domm`4T-bh1_T8;{bDo_u@t3w6zc9}+2fJAN%F~Y>Truw3 zp{AZA^INuW7~i#aa$EDY!!_SrZT!Q<`ilcQnohkjcEkFHLx&Ha-u_`v%a`B>+c!ha z_C?&L)pMqH&YQhyMb(-m_MaNJA6WH=zWIj1`HH&0yDgLq07&wvP{<-q66U($s1aoe zX4}<*NG!_XbUTLb!4qKskfbaQfD8tEFI*@c)nKzAFo_4_IOd74On~# z947&)Zg&|`UXikq%UQI><6rdR?-$I1p$Z9o;Nv(=g(Tpq3R9$|wXVk!@!M3J6&9v&o}K2?@gJi?$1 zlkjPPczk#FVg5%=mGC?wC4Ii?`%TO7+l_lJHtsrIxASPlimi{^FRA(YPc|-|^59yl z{e=0@zL^h(t<&UG?pi#yjh|h?Wj~0ud+FHDh8G?T*@D1Q%(9NHop^3@#n;2l-wZZf zJ2AI$^Xf4RS8Q8f``~J$ed+f}Z~c|w9c>rRRBYYWxbMKZGwZ(WZ}@_iWz3fT(dF9R z8)nz6>Zsbap=$fuX`KtZ_bq?FcfNhfV(IV=>=0<9oyM`{$u-TUgqH@X1;Tu);1Ml0 zVd<236wL1;w+*bbR%AsN+}j0zVn&LU&|S4$u+)~!8ZupCNVy&l9z1GKf|I9-gFj3AebzyZdJAkn5=fb)0|?X!hokR-i3RkXX5 zW1!{YT@6MR@qkL0lpA6Y$CQ)=k0L&mawR4``aqwrR^EDV?wRX#JI~gwKQ?pyt}%5D z|M;_?&1;@OT|>e zKBs*-&~W8I)xwSKjfb{X@833c<+2@nmjAJ@BR+|_|6n~K&mTE}FkRG%*)(8W?I^2+ zM{FeID<-qG6ND)dt07oAfLf*C2Q3$^xcih@I$xY-*|In8gub>#39hG?3k+zZ7PdjK zA!r!D81y)Iti~x$2Jv{a;sHQ}%wl!IM5rK3l!_^+z#K3XwQ=MsuAmA@Z7w)fPYQtv zF>x-uT!Bdd=#SHZx_&B!jDv$9WcX$0LgN^afeH};Apq_$;zzm)aY}6l%%{{Z8JLc@ z7E_{yY$JzYf@L+Rh(}tAs{37Q3q9(Q$Db`zRVYN2C?tCcXUJe7CJ9i3&dlm;oSI2k zi1)f!6SS{dTvcBa0zf6H5~h_@kXeOJCzQNc6Oza0tM-ArO{WHG_noQS^v3h`t^fGT zUyOO-i5st1*?;Eawr{k*k%tdacKqQyJcIm9#RxuJ*?)#J%tyTq@1L)=U(rPj2sUTA8fIod9ViW_c#3JLer5edzTGeo4I{g^`_0krxrdKY{2lJ?$I4JM-NO}vubnqq7Qo7?A!0a0OqQoGs%mAtiUBHh`TP}St~SaBhg@i zAtCo3@P@>ei*$eVqL2}_3{${}M+B?n{9c{RcwfMKBPo$Va0=kLtm0Fp<1&TiJSY(t zb(R2JL$)lC%~#1b(VZF*QmQyEdXb)l4^AW!ueJt( zl*k}Rbb$)J#NC&ak2uaj6&QipKC^_kSt6y}D zN?0_I`#K|+i3)OkXk~0x0%%iFF50w2eZFcqf3xzyh1vU0PFlC)7tcNS!gEia-9FP? z!rg$rfxYVH!2PMQrXp?|6=tQN@Y?@4r%1Q^H$#mlHcnl%u+n}gonQJj-XExc?_ATq ztH&1)zd32$hS^>7`;N4IebrOMX5WOjzg*LQtaZH*^iuUNfi^VWGE_cp__qJ(vd zlOp#BNhM-R)Y@BPM|gc2I2EN@7b(t;n2U85I8j+dW63CHg$$k)H!!`OvN21|Q5sYr z^g<{X6*VT_aw*cm!n^DwBMr3p;_)CgdkZW9RZtRL6HruPAWW3xZZPuoWS;=5r zfb1^*RE1gYHsr@RA5e^c{$Y2Cmeu1!T_Utxrbv$^y3|lEsqV4J0-i*HdW$#P#&bA34Y$EsIn3tu6Z| z)r~{5{@kk%QHbB~ulrTc{O-}-g@d=JtnQq*vf<*vM*qUlvcLnd{RhNfpQ+n*c3u6c zV-@Q*?%3Ay*_C>HVJM6Qm}UX?#VO)grP4w=?BbCOj?>~4 zogyB&8rwbCda!0Pkowv%;L5g9E?GD8gq*&a~}J9J?S`*w!iUyU(MSW=WQGr z*f2cw-i6kq+h$$dS7YD%GH^k4rNO?_{>KY7Z=7FamNk3Rx;@*Q>~k8v{T_9p0T+uR z$Sd5EaRDsurGr1qat2_m!RXyOBAZ$>PH#%VLPHTR!6ZvpUE!Hq!lOu#LrKC!&}4Xu zIJuY#7U0NoBp*|v1#v*g^YA^VDjTOq(R!|J?}8t+36=(qj48ymhcgX0F}2Duy_7(1AcW8%qkI8iUv!|aY>n2lw&QdY83Sqj?xgLDMnNxzpLxSkk&yw5XL{t zKoShaSmdgeX1ytV)^#zAfT~zVV~ekz0_LBu#&@57adr0-b6VP)CjQ|6I)0(S<(YdYJB7fOeefQ$x)%}-Fo?Z8Kf9=SjS?`^x z{(@p69Rj}Wum8NSzUS=1jw8D!Y}m45%fersvmcKaGqj;)d!b1`)`S<{G8%y@L~svg zh^OD$tWQxqTLvK#L5`L2M~+E_6kf%Y9#x2VOpzIOSAdJL7*tCDDr7lNj4G0Wdy($K zSOv9+0R#KWX-zXw4k7;sHk}2p0Y5=mMc}s2gNuoUB;u? zgehT8Cp0_h2`}s8BMrfnWJeOS%*vQ~MhJt|#5tlF0$kFyDNJXLNbvCR%BGSGW)Iz5i^6hniHC6iupQD0j8FI|tt`72=^-_rk{3l? zECmRKq!@smIR>oD2C)JxfpUpfQ<4fmO4rzE8EMq#t7m4-`|-GnxlI%P*wbug_34#* z9t7KaHmH{!MKB)mU;TK-XsV{n}`cE(FJh9_Ni@>1?XT(gCS*%_AW$%y55)kfrMUBQ+DS-PC{QQ*gTg#=3_BXk5x21(G)usvWR2z zNCp(*Dptedio}!@vSLU|xdijLIU&ZH4Gap23K7%k4hapsTw%gQUD8@3YKkX|oQ$&y zkyx(aK_j{%=->e8v5=&AR7{QMuo8x{ilym>%)xr}VCX4)iOW)gVLGf#Rs6C1bvR)u zCh?Tz23V(_FS@XIsYSVf5fG0Sj47AIN28)s*{p0Q;bBBHF1ePcd&I!%owQ+<#85L~ zAe3cMlGs2izj|&~^O{AI|9GL={+k_r2B!3BAI+){0}CP^18#WD)~8tpZSe`SENs{0 zd)#2)Z1@a>rRO>xEycbL{k*68#G&>RM;ClGkkYM+m?018(AHpoh3AVab+=BpbgiGi zWL5h+ryK7N3K`|nkzrBnZPwzzbP5KlBCZscV+&4Y7&XYd&Q1|Yv!LRYa+QT(l+JjJ zL2n9!IFbrFc_Oqy87I$sAumVf<0OE!3Vd?o0GkpoA!aW}2ZOytUnx#}k%dRV+*qP6 z0NIs4rd$nd!wVVKRFde-F58iA>9SdsMw_`2fdp$C8f?IimmdV2_zjPl4KSBq4D}x&SdSD#`|f@vx#NI+6kuFIL0PEUFkRNH~B`^)~@QB_>AX5t4DX|Vw`ML?uJLI`wuZVUcl8=Mo(fCx+Q`n%V zcsVY0l=h;mE*O+F$gjQ{sQtVj2LZmp!^?vPkHRAsR`=R{n>kfH_gifYZP0HX`br77oRR>8wp zsZ|Ya?7eiIodJ8s*toC-zn2iE&=x7?CauhHWMQ+(Z1j$77N~`+`wK6(7@P5wt1yI%iN77lv8Z z)#qna_sdV5wlvSU zPt_#=&zIwI%5cykooBN^V(X@hn>j1QGZN{xR%ThOZUd*qF)zjiRgf6${$Rrg=WER3 zSQMSgB@%Jl$8Ob=Dwcq+%GpoY*%*?6<$^rGwnIe$;f)+hjE4gdLJ!*HEW3bIi^tMYA!dV|V5M*cq{Inb z74eQq{457%o5dA%{gE2-v9GExZ?JiycPix}si;mKrR2dZ5_S=}8Gq{3JacVo&v-(%}(xAoJs%@LRDNG8w1uvFrNyM zn4&q@AhNuo&?d0Dy<(yo3{4T$j2dvr!eoEbd+*B`nRo zROo^A`K$zh91+!m)C_<|;?WDC97-e34T-%feolc(5gY`-jMGZ+l5#98%87wZIZ`|Z zW-b?jY9-aX(<}%nfDNJq>f*vH#v@6H0U?!;nUbgk`jJ8~@NA7zG37GUf@eXq0N~U` z8G2-0zP==Y80QRRfO9H}bj@OL4Xonrc#njsx{G{NL@nr^DyGL2(IAiKQ!y?vt_b=H z*rOsw!i#!Ys+Kkc;_gtPxiU;QVA3Dl)HcSUXvWn)hd14&+y4>Zmbl~tB&kGg~` zV<;iP3x(R0V!N(R=OyAX3uF$CxK3745gQ)4W_KmzMq3skvJ?|afTR)^6OwG76jA{$ z9#dbc9xwv<`WR;lyAA;QHIGFhuOdz*Di~vw%dVuV7!YZ~5Q(u3{871BAI!Q8&I(XO zvRv}m#&eQ5p^2ZKP$oV~_^1XhD8z@%K+OA_w`uR`-- zr(lTQAp;j?AqM<7RtiF4NHo?xwsFxj4JKRqKa4(0(=l-Jr+_?kz$BXeHjTvMleW9 zR?KGW-LLF0;>)PGWM7J;xDV`kcpM5CE2=4#!1=;aGKDxhsSqQOZI@hv z%tQt!X7P4l6k_Apvos4rZwiG9evn`#B~r&cl$Z>f5BWJpl~Q?F0g^K=0n&pp*M}ws z8A3W<FsBISNlZn35ar-S0l?VeQj4=JQ!NBb zl{0&F$}UL2W*y;9TDzyq3(=nuqy{3(%tVhAX73_n(AZ=^TM;jNR0;u1hwOsK`z6Ce zi2-AYRGP4u%IaeAOO@m)vEikYe;kAi`fVb#K^g}*uj1n}OwoQS3LdR|d5Ut&3LzM) z6ab{hxX_R%YF04C^LvUX9vkRVBEUG3MawDOVYCaSr>PvTsRU3~`iP#TlzdK33^q_o zAoVGol1iLPBI9E-1v6I;WBLII88#L^C(k~dCuVpKFA=6O0Pvz9#QM;j#VqnPP6NU+ zWSD2dyH2tx=qYr(NH4w~v@JmgfEDN<)1zn$VK~5O=ZB3T1y+Vb&2!CDMsw3q0-Lpl zS-|4di-##`N=P{y87$H8&X0G;EGLO6(_<0l!o+|<#pnX(ltH&RZ;i}Qr4nokwI~%8 zHTF9=85A2!7XX5jcnnOEGf0fF;i7Uz0Pq1yBLyWi5JNnAt{5^T!K@Wi!GJ}`vZTcI zK%3#sF8o6&gyo4E7t0uJA|;TC-y%*(4Jj)H3E+ljQS3S*rGcfBux#pKuwE-Rv&0ij zHZPHAmCJj{R9^ZK{8{xJsS=8$dm5;yJ*F$GUNoC#Q=%d{m}5Vui8ddkloSLT+`|iL z;GgTXKIx-rz#Q|C;M|(T&wDb`%vFq2mZiEjCb{A1goZ49GJ-A=g1xjb$(K0D{&YyD z8iGk{%;8t`2RoAXigDMalTJ5aBuoIa+P!W9Hj5L-AWx#k2+~YMD`qCzkp!*5xLq|s zx)XxLF6$0=kZ7N0@+8JdP?{Pj11Wf97SeIh$jt6g+L)yc5sbl%aw?>D;3~*f5GAOG zcc!qr#KWRgLPE9^t3gR>r>G8cUeJbGo&qH*>Z(m5(}3k;Ak%W?66Qy)R~{f8ioa`1MqqA9ymd?}kRHM5E;Oe`ML zY$>4u5=Mjk9!u@j^Qni&0xO>PYmo%bXVW-UNs%-Vk3H(jY125(CQQmogM{&{`2JPx zCq1%=@;eR=tOMr-_jF+!I^MU|1`rN(x~%a(y6S zp@-+IAjeJ?Az<3o1)=I1AOzU5kUuFw3KPKtkpK%5nw739esWncq(T73*gPV)0fTV`cCsaiVWEGmxniNJ+E-!a7GNE&T=soMOgx>*q|3;6_q2Q#{hV>YV)h%Fcj@kYW$NLd`9L&iaO?tdCBcscDJy{~`4#uAEUQN2PkZx0 z4fmM6cfV}*p@{aO`=0Ny0$sjS?AdSmXAWxP; z%zpq=BJd#zgTmzy_lty@^{j^@tm_P#O)_jJ;J5`_AOTis>`BVd0EvirEn(~)gd8M7 z+ct^Www#Xzc3M^B6nA?tBckKL>MWX8Pa4D!V%P{pq8-zN)@-1<7?a=IfiQ1P` z4e|n+)%EnON=YP;B|%bQ-NLWvA?eh^0g8yZN{_8W&8IyzpY+(>*3FTK*otu$L7T;v zOFXp!Mg&{8+@LJ3OC)kI@HmO%QCcp?Ee$r6^Sfk_Dg?NGmkm70$>Xi1tW-rXN;T$0 z#d4~Mb;vY;mN4>1;}H>3Qw8kd+2C|!lq<-Qf>XdXED>3x1g#=oTEWt(hm|;q!Ag-h z4k=O$sKmv%Dmx11LgcI0Sn45Wzr=u6$|VVf$e_CF#Tclq(2(>5 zfAFALj`5m^ceN(N({12W>I)UMN+?}?zLHDCDfUBcXHXF{r2=3<>ole?FgLI>!pjD7 z03`~BARGX+?hi`wdstb1#)D0?eB-usya-E0K^PHt+B}k{K!(&tgCT>$xUcBU+(k}{ zqTu%xATmfu&Q6o<*uZz7t72|J0^jC3NOP=A>O!T{D!Fq)gP22AtY^L^9J34S%c|f? zixy-3q2o>EvjI?6>LMrM*pJmi@u;5H%{hxP8KN{4rm14=C(CCOzy=uGtN=kJfTnZ? z!H-jrG{-oV^P>S+661Koq!Kg=#8E2_cr2`+SWQXBP5s zW-(EUTi@Ka%!MR<$AL>LN0=s|bhAhmf!p5u#*_FcBe zxv&hHB(4nCnG1zA!LoxkF0LMO)sa%L8U$D{{0b*dXBqd8anMR1X*hYXd>ko7t~1CG zf-s|Xi_4isf_r4al+u_aVkiK4u(XQUQfo*g6(Xc{D#p{S2W{mA=uXhUTt^}i zFkP+?hKv*_NdqX1&sW$CpY&97pI7tr)qJc|&{O@f#WA)4tt{?Li7e&Xly7WN;gLMX zKoagccp6BEi7Mpx(wOx)`CS02%MX2)JT9y}1s!E1Y!HhUL1{o0J46gp8#{$O?g|Zf zhhQJjuaL#%^83d|o-`+_NbxCES1@73gIq9#`|+_zk8*HDYV!eLj8KM4GH{5=8PGmf zz^_y{FyLVjTLlAxeNZMq@&q7l;Elvv@LEX;z^Met;eJ`JG($s71t$b!96btvbj39g zRjf}iLyurus8~P*ap4q@#}j4d_zcV{gppZ-(`tZ|iHeiTc!YOO4@NqXoJtW0C^R5F zJ^CObS*L+f3jt6gxFh0zl^XO}UvRgDB%@@O3~oLNpLEKmXg)yMhsc)Vg_OOo<|NFEs}o6=(nmObVSW#c?0jSXXCCkYe7 z##6tUJK?+=GNwF{k77u7uNzavBaDlGI;f(^5iFRE-%UPd{nUp@+DrB-R0_<^olW9{q0s3vB*1bp2okJPI=^VSXd&Vt%wcf0hf_$%7K|Yz z6|hKQ1Z0RamZGUdjz{rmAU6BxWrOSjXM%x^ zepM2|KJmH)>(TGwW;uX_wqi+Y+G)W9{!(M4BugpCsiBAz9~!|NagF2dDbDQfEl#9c zmLWa;A#WEz%(hDQ2&DCr{xpe!^W#w!ec&=YF+@_T*oqP%#>)W{)?K0yL0v9`iE1Rv zMY{zIM0&8lu{t=WQCsei5KVBg0v~l@&g!Q z1(=u;D?>+ax$vl1x5QRN^4<$4i4>gHux<^ADQh9KLCEte#!T4)ONQNXu_Md|0JB9Q zG9;LIqDPR^l)yB2T%Bq}(#VCzo};a0W$KHc07F&S6}9KPe&)fHXL*U?f3A zY($C&XDZ@}S+ogkaaPaz0G=f<-$g>E0kR~ixZ|z4X0^aVk5CovkrCYWh`DUJcC-1~VlImuKazK>JWCSvU`D}_5gYbT;Df!^aw2u8IR|_Ei=3Rb^wi8MciB;BP&aYZ$=zh*@A{eH??0NYTc&r#EsF zDgtr}z#!t7Dm0YFLF>v5Po$1{IV{9P9AZk4p3b5YA6+9QW3G{%W)TADv5C|6JOFlQ zp;VngmJUzGJB?;lNQoTVCRB9|#EA%)sfu?WD_x0M+;bIIqL5i3=Y$w%#sH32@^!uH z7KFqjH<=7MwXkG}MOHl3<;Oz89FUVSYs@-dhlPNr|ix=hq^zV#bg<^+6&@7!8Ve^0bGjC<#1q z#n*#0A~=j0kuJD|Oa^ZmW0;Z-pyG_ki11EfTyPK13MZkDi8Br+z+~g*5iJc6epL`+ zjM8KVtqYSvs-j?rVOD3~MTS*EHr^C3f+dwa2pYba6&u>|pk^IIG1TvDZrx-+T@1Ja zisU>P)7#lpR1CkRNH9lAF2I9P1)57>B;l;4M2-d@3VPk>4)!ZdAY%>PNL46_@s|?m zii086Ee(7sbf&r>Om>Ydp2Q%`4I#t>U@$&vjP^?iy^2ndO^LI3^fOKv1R&ipn#v-H zSpX>%l}rgfknl-A6h<%l+#48x{VRRLSgxmwIf+3DAVH$iyxUO?TDHtbFu;PMsPL(& z%&Evp>rh{wUep4A-m)H3kOS9XV-!{U(#bo^$x^hisX-;mOTEzl)tNc67EWtqd!E*?>)M1Hcm#2r1=OJ%h;29E^e)Ga=khOBS^Qj#fQ7}LNFYJ!<0A*GX* zL>FSz%wwdY@ia@bNRqa$r{yM^knY5M-VfS|9;pHkbH}nYAY=bMxHISXfBmF;F{k~f zIDOr&_wDDpagVO|W3nlfGErTJati4^`0#)uS#~n~Jj` zyn*dwC7k(n3T6_%DTN>$z}Vw)M_QU^C8@+9RpJ12yTz|FBL+uPh0=U7%T^UjwMTV} zktFI;r70wC3-+_6a!L{0ogRD5cvC4Y(D=LJkkpW}_B`os9Mo4UQ?da+kfNc@R0NLna=Tk-U0(0Z> zIG1f1u%1chvB$QG;#mgOy_Zg@lC7><&ARaq%JY?eU=2kC$JaF*uziN`6;)#Xz3rfQV)IW2Ialr9W*4X5kYR1zN% zJGVfFZL*wO2J`3;Hr+DHAbx#H4yS2n3D5E$TGt}V&El4EyfIvt%QDLxDpfSVdUBSW z?s7_x7)T~P?E}WF$V8xmHhu7XU(i1-)rgAJHORi+z&}%>?wQYgDP|wH4Mj)wRPxA|7PHw7}-O5F4VX zw?z$3$o)o}*+LRF0D)o1R@Q?d2OxbBV$*0xDSEqo7%XxPZ{sYZN6bW#TD-+)56!SV zlv4}xFmp(ha);cDqaH89@XL0L`A-cK8o&Sfk4Fs3%>)zPn|Y5xdxVGQ7-wFc0rmIa zXFz3qO>0b^-}uBHK|6@_72;nT;{reY7sL3MXN?!|y%gq*%}pP_VegV$QJ=s!YPq>) z*m-yeZvlT~Z;A3GUHDV>b$V%LIadjNO;jP(T2+WKzu9snN!JrL6;0`ee52JMQdu4t zO|hIp)atCThaC%;4HrgWWl5(#P+(w!Zx$&k+6guSXize=57q<5T}!Qa?5O}T+b_cU zm(BY?J82xF9eI~J@#Ie-@Sa!vtkQtuf_&yz7LP~P=b1knou+g{Cp0j<**&G0;R18l ziv!H;dhlhk4j6bk=`(tY`eRz=zPIblOS9lL*rMx0tc*cgj-5 zdC?wi5?QLFZ9Q*|rJc~b&keZko63nBUBj4bnbW?7PN-MxczQK14_i$xH}t3-=Z#tN zKQp*T!|C!lOb>VWT&7LZRckQF z(+n9xo;D>6v|&&q*eM}~q=d~<;dDFtBARJxghJwXxxmCfocVplz2?=yP( zBT!M0CsZo$!LY{Cj_aKk%0}?$n*al4maXZk==IeUm6kzjZGD7)}ut&Z%|48YW%3=$X~{ z4|uay+Zde>(&@?I5-WQLY(2xTd7>U&g5EQBmXpCnt~9`ju^!DdwrDy!kG2t*JJPQ; zS`cRERR+c9A35Q=ce#4H_`iMraUNa0AA9}>hUfQx+RqsvF;|#-%Bhe?}+VebBP0!m~;ntzCxL6 z%(MibUb;C0zH-AKOvbpY5HgsruM#TMVK_X`q5>!DOeZ+efU2FJCX^CFqqFn;G;)z2 zHm58POEH%m4U-r^r7o31l1))0dFu?AECb{>k1-+K^cPt15r0Rk$L+sxN=XFAUi^@l z_ImFG3y(1_ciT&{Mx(xxx`|g^F*Nk*SFN36L_u1W5-ld_RJ_5qZ_m5@_gLF0y3Uhc zk;ikk0%7An=?P_wlj6~|Bp&QqmN4KIdFIuO9ZjC!H99mv=Im(}ae0|1acVg*JzOHr zzn743(^-}c7{_?Vg(rq)2w5-$%+<@>8;?i`g-!ff&Zn8Ip;F4cWkdr?1Q0WI&45TM zq82B)Nt7M6YDD4%AonV*6gI)>YS0~-Hh%Rk{w*XK&O$9q?a7J}0D0$$_(48W2H?4; zTnly<4Z5jAB4Iaj>@6yrqU-eT$z$f0KAV>GIc(x#1jV?-Z;0KyZ__JArFT-jM$vHh zaUIL6%bV6xCi4=0~O(>5^Tm^e!i?nCndV(+Vq+GB# zoia$k8ucNmy(NM%GKH+f%A-H&7vQaDss5|bfR7mdKUem_v-CZx&ZwuDB~i+InEdyv z&LRyB#)zKW++KwE=RWGrF3eYNmf&?@6v{XP>|te2odf_SQPwV}+1N5TqPf~O9OWJX znc|QWSTLHM7^By!s)WR8Sl^nTDw--K znac%6*FW1uD6|QYsOtvp8g4uc&yx1(%?eWee+aI6dEI*qkJ)rMz;8G z4OZe3SIXSt5#Nd04IHpOLHeR8^=0tdZq}R%wFT0}`RIr-b^Sap`C`uW)2ES!(xNl6 z+nR@7blT~`i|y&;eN&IBqAen%pVRc%e-ARLbT~D#m|7Z8Kl9e}!*8_@Y!2ig@fY^< z5Aq}hn{)ub8?#kHTO?=OHt)5EVM%aOZlc2`u$G#!^~k^JD{MV$v@e$|q#|usk7DBCz$pwS`ef?u$E;<%_Y%r=L%GXq}$Hg-A{;0x%W{gDb zB3Bs1z#vYS7U3l_Cvf?x$P5&12uX)Tp`9_a>ehUJ z{XV5N6Y?$GdlJ=72gS&Ue(j$2gm07$ah1D$ZCWdOTcmll4OpdzB)HOU(Yt_F!ks zZfn=Hdo}2W2s+&{izuYDU0X3 z4+(^xnO8eIe6h|@E3v<=wv!8)wmo|Db7db6WS5^c*0b_fDPVz{f{tR z`SFiuQe+$w!!D{v-6uHY3vRS*9i9eE^oe{hTa2nV{oc&vPRa_lf#=FPlBQN43SsA; zt0tMOFen7c7;=VC%lU`Ac_ykvme_L?TRMcCWU9oEEo5Qlx!>Zs*p^wjAf*anA%|0s zC;U{5JQtmig(+ph?MvW>ny4zJRiRT9ZT*i7?e2(KhB4NTyb$h<_U3zgB>2H?7aJ=3dvK3p*u;BIFC{Ju>s?{n%_VWSsA`z?~wyWeOHI|tLK#qf5b zjq8yiL{Jh7ADR+vHR0u>s*(1cY34K zBqfKW!U!4G6j$F5I#;XI7pI~c-NHafgTNkQ#5Tl2ncaKF?@ zmWSt*XbOc4t}#m#jx*_%ca}a~_RmF=K@?lc>s(G7%dkeaPPN8qzl~kOuZmm9u(wP6 zy7*FpFi0e3Q*3Z+BzrL+p90`-E?}qVy|@05tFCBu(M)bx^@(x#_S zCC#5O{)$CU4ak>v?Ed%m?|=I=x6kK%-YmI~di(aVoPF@%8o%&5t8-$N_-UGwpO9=0 z^TmlR+8W}tlMNC0;Ad(64cTK@LPs_g$Jx^GXla8gccQ3p7KVUgP*NWILoSRw`l)$i zxbN*+w3HLz#cx&CN$A4N5JN_-tu7ebFkHNO( z@adajHTGlq9ka`xz4*pxrfqZ+xj_nzktnlHPVwOH<18a_s@A4MwN9nPbJ;Km2GWn_ zr`d)O&W4h{@-C^tTp?&RrE8o*B~)MBsSSCsYsa9{wW7kE?vYQJRxMH z5!>;|Y5p5SmGDPi`8k0WBRyF*8mU>jg;L=ZCk)bKj|(ZpJl|Yn@Q~$`pQg;SGWap6 z#$gUa@RJCvbr%q)vK(#V)i_kkbA;)KCCmJXeIKSo^GA}|-V*Mpdb^z4AreQ8~>MQvn5KL4IQcvoL!q`IQO6FRv{{3L#* zNFJKmmQr<#Tx-V^2G7<~ij>SpL6v(?xv(kZVRdBq6Ab^H!nF?-qn<^18inU3m2_RM2R(X6xpH_?O%axrnTj5+Idrm6moB; zORuM#B0nXXf*4g7iK*t6K_Z3lH0yY-Xk|!@kQx+Dmp17Pv%6NhN<_S(+en=iU=3_*mD!HlW6~Z zbm0Y_j#vWY&SoGu%dno?+-o^GHl|gsNPL#0(AOU}DHJWkL?T_?Md9oTgb+^Y5kL6V zpmcObFkl3eMLT-NBSMzaGlummy+~KF;4p~R9$F9*Hp$lgQfU{hZ1$~njnUhs(b?tN zh>;{h%@xd7;7Ylo3r;TziBo4ag9;zqgK`qa#0CR3Hn{wFH#R6ow1vIDyx_BlM>N6pt z>a@s=orDV56dOcc*W`xT#-E>^#+d5S-6a5>C3&eb%l)Gu`|7t0Z&N^ulh)>uo&$5U zVV>#N>GVg0-N3_ekjmY8rMo#-$rlR4kM5UjF7KZ?iTV&4X1uTb_~TsT;^dBd{+J(3 zJ-V|mxh&;(mTgU&ORWkW&9kd*ZG~AC{($$IGps^8$KHJ%kK1I&{3KmSYpXDQO-l0| z+469;X;aOPryWghj>-V+lsr|5)c7Mzd)4%4=gn?MPrgYm~&F=ciws2plaJY6nq3`>Ii&a&o9ZD7LiW1Gv>6!fUg zWN8|kP=2cP(Y{4qIYlKBYp8hrGGB$BRB8cO1sklJes!I@UsbLik(zZYI9<@uR*wMn zs5Vh(fZj}%#heKyN#zM(mVP8yoz~M3%zD;v?mE5CSz2T`qiXT)cN51?NK)-QzppY+ zIOKEQzV%W^nhW)Kbj5lB_a;6ty$cWLgXD!Xb^ieGigU=F<%>{fX}JZp-!Xg*2QaYO zxj55H1Ru^hQJMzg)JK;mOGXMixfPMbGIyNZ(J&sv=DlpT4d|#0o)ld@`SYb*#Z>MK zP6TVRsji}k=_VL}0Le&okt0d^9kR%MbA-G_R0*MaQOgw;W>qArD!kLUx-bK^$W@5_ zQD16-T5ORX>LPnZ$|x8mvW*!wzN0y_X(~sdk{CbaqV*?GMKpxXU}Yi9Vw7kMu*e%8 z+II`c5R6V$BCy*o56l5G#K_hAlyG!mB6kV+xwdm*uMHs`4-6MzG>l&ZSrum~JwonS z=o|=GDJgAC)Jh(M0^0JlsDHa&R01>wJc&GG&_WWg)^JL^dl^8HB<@l+GUhqIuReYI zYsSb6iy-%oSj~(v^!gU58t_n8hz) z*XXlgsXC*k-GxV;>as``DMP61Lv`#FwZBdi5)ybC*%C?d_U@jL=pN0fJ%lq(?H=8= zx<8Qml@mYZ+Te=BqrGJls=PL>QCgw$SfL5A4R+K!yeUrK_iebA-rm4$l-aK6qq><@ zYqM?vnst&SC4}@(d(W$1KYjP>-1=U8mL4)Q#Bln(XK4(a_=QaFJz+i)5+H*D!f^`Y zP(R$uC{qvjpP{c$A#bGK>-Ao!As#1Sw=b9I0lm$9MBYt7oeaDmX@$86cAJz$--_ zmG*c+n3pD0r>4>bQ`D2kf_XC*E&-Za@Mv7D!4yT?7Ro4~Yas>DF3p57t?-UIcWm>N z9Kry|f=cq-9igFOih2(#$ui<6l&;+rgw|>NC=V_E%qx!bN8EJj>II30uCtjbZb&oHj}HWYgpk52|Dk@{E$lJPn8 z%@&$XX)th7TF&*?F#pROD^DA-a;UOPj|LO1!n8^5kcaukjQ!?uvypu z*u8Y(c>uUj1zUD2La2)@JU0}>;Ke+aRl*eN-FFtu<1qto*lv=iO|#=^b?&}P10yk- z!SEP=iYk#5sz)|aFG(K~@vJbIRS`BvU1+lKTf9|?3fSRs7K!l4-*?yspMMW>aXOc5 zfBNRvPv6+->6GjI@f(&JESzWCeUE2COe8+2KgxCDQkgtiRAGnXJc$-iB?cg-%o5{$xZe?Q!L}VqVy|9nJ!u6yRnBrXtjPb1 zp^NXthsgIT{ulfg?VZKN&!{<#0I+l3P4uX_ay6+?tajR?^J7njnD34*g0sH)G9xZLd|X}6yy2X4 zk~^!3Cwo%jRJ4FaVzhKP!4$kz1RDW^7vaz{Z_C4_L&;4=il~5DZ4La2-gp?6rvP$A z8)NQ{IqejT5Kk}WI*Unl5ZY0&&J;9jj`yA7gwRt;E&jj(%MVbOEj{@26Bsr zx%(4g1#EQv^wqhv(RYl(lBm}H;J+~JV6o=6;{~-EO;=OVFyOc8_PhmO9{1aS4|;BR z^33NOgNFmDhYimt7$u%d%miT=6iqRVM8n4KAvO%Mdu|JGAw^Fv2Wb*{`$3qLz;+Wh z5g0`y8v$D4@ef6X1kfnENRmqmjad2E6or<4l~{nzd9qqp@+vqyN{2+WVlK>uL`z*g zNG+JXbyn0u!V@IM%aYtskvoq!@Q8V)r;9~`*A*`FO+q>Qs~pWPVUKtyx-uLUOu}?W zdiRw(p5i?KONF)~kwIyJsp2^!rzGvB!Rag)-FD(EgA~FOZQN)oI$cJprxy~n1BPk- zOl}meB>bZCfYQX4V9mxlr;$mtUrp7PfZR}Q-%uG|>Vp=*Jn6O^aF~Nvp^8r}mj8luHWiLz8kV9Aq6QBh*?2I#G+KID1;905w%T3nEcs&N|z1c*=*W7_XfCFG$|{_!w~x*TJ{-Uo-Mp2RU^yI` zM%r~I|NbbIJQTWxvQgLRdW%6@>gDw&agpCBP6<;?kf&$FQ# zx;yY=46RGdyCoK|h4@BIKT7b#zbQ53ulP-$XaFCaIQwQLHs*~X=Kw;!70nZdM2nFa z=Zb`M;Q_?2>BN$+?8H=5cflLne&_qT%_Hnwd8u`-%7Ik6iu&BPi}5e#)#hj`vsAHE z#k@(^83Xo8-Y&FbDmNvfAGRpR=zwcpYj`4Q8RytvGirDihH);4qnzH-2Co}5 z_Jr~tfG|eR+o8n^7G~_Pv1L@M**YG%8Uwp&pMd$Ss(!!kO{jku26?|ZA&HJL2Qq*dnb>wN@{p8`T=O_l_PMr~bE*eC z&V9r)$8wpE?c8Nhx?q6M4YCr=&yXm^s(7>X1yo`^fMrKNOJI=KpLAU}{Aocj+e1Fl zdwP$*0=RAy0yzdsf)terEw4qb6WEkiITEpXV9T4+(9P7HG{bJ)yJ zG=DUqrL>j13l#!6rSbE(M%86kXY~-0_>I~)@9oRgpHu@|B(^Y~cx@*YcWIdSq5mHA z-0-cJJv-w`!cgji$59)?fHZiV^{}zZGD+B)Zq86SUHGJnXVQ~vRf0jQ2jsDJoGzYw zSh+OsJJFndhfPb@O`(*|AZo>3Qnya}6;H&3p&~)H{XdcCEI6k$)wi`ZvI9bX2`8iS z)Rm-JzIYJuP-Ve!8tkkzc!S+$nU{yN7bR@PsaWTWXTZ0|<(BPTtM`($?xkQyl|6@P|Rnqi~jo4LeO4Pl~$UtZQ;wZSlkGa#FRnH!VB} z@MN1TZ{{krTIm$S{(DfjV=t79UwA)nnE|>=iVE=Yn_tEwWQ^Q3oFM^_2hViD`)lDF zk~1DN2;*xzDZiX612a!~vJ7*`uj}a&?ZsjycdI~k?Erw10K04##Z%`LJ+_?2te7xg zC7iw_;go;{L#vG%n2fFklH%&)jNj>xuHEtxxeR21%pkHKr`Z%*r+f4={pxq= zFg%>y3X}K^UXm^nF1YS~guNwE)Dt5kB6Tf~LK-;XSwg@kSK~;Dp<<*=3K!o~B0Sv( z`PIdc2+TXBnOAq+h&QKUZltixA5qb7TQIYBKnjs0JxR=16QKQ)e$6Y(bLq+Q?<>ua z=k)mS^*CpGXyB~z)f_E(F!X%&%g40?Zb%G*h2+CmbGB_`aEY{Br#aWpG1hbZvvn0C zSa_Nua-ILy-EvTwFfCaByu}IrB&vn_XNMo5982^wMXm74bs_w6vMj@fObA0|#4x%1 zM3+IZEc;hrNSrl(z``3tJNp=aM@73D;Bld=I_X|sX#WNeEKmuQvSh7kU!310`Mphex?@A zhX+DG@r&Ou)!H%j5q{O;ZKG_L9`P@7#DFP@@y$9s5c<}bnS-q?87U`#nE{g$g@ES^ zD)*hYhG$Y1V@Vm~%B{!;(zEWtpTY9d1z&2(ib~a zX0OiQ5jF0m1Wc7yjGoqo!A}6<_fGnY-+F9!>PC;q^=YWG{JI742>A=UA%H{F-DPEv zK1wbmDe^$Fb`wviiKflO5G`5FwOs+a<4!~jci;K}gm64NW2K~ci?M)}ZRO^7NL1Wq z;}_7Vt~s0;I3aY)eZTNGH=JS?Pw**s%h(h8S?+X_EgAWC z6J>cA`rq3#TQme_4sct!H5pmgkYP&bE>Gwmfpsp)&z^kc(7bi^%H|0pr}&9#Lf(nv znR4S966)%ZrQ^dJ$TE1vgI9dfsz(sD|S#9K^u!23{z7t-ZS zzNNhtyL@epK@lo%%ey2e9VOf;d6awfufI)M_6?40lD5$9O6zo$fP9S?yfw%OSVNOw%r~n`Jg3TWp6w031gZL*NF-K%7 zsw4F!0baVV<;SVSdE1$+E~({58Yb$}7^a=*$~N1L9E?+J2)u-?<Gch zbyj3Zo0K#9c($UKbs};Gj@4rCgL4b1DOK+nH{pdplJW;aRN=SnHuLX6Pp!Y+f9=3u QJMh;I{6F7;zy0lh06c*q)Bpeg literal 0 HcmV?d00001 diff --git a/icons/a-system.ico b/icons/a-system.ico new file mode 100644 index 0000000000000000000000000000000000000000..f8fcdbd66a0486458549629b138e672c86187def GIT binary patch literal 16318 zcmeI3e{fXSb;pk z=f3xLpXB}VglPYXFT8i}IrrZ4Ip^H_?%M^4=nncEl|D(TJd;E8O|+&=(d5N{L9`dT z>C-iN_uWMI|2@&yAeQ2K6W1LCCCZcsRi)kTK!r<6N!R$g#@96(#&w?S%aVqN(Z)4A zJdApn2338Y&Y!!X>bs_!9f}r7^Z>2GZY^9i24R2 z)HQe-x&i9zJ5PuI>lF38b%8ntPSXB?KTzYqAcY1_p&p=veQ#q-A9Ww?qmDy@w)G9r zFW%~-*Nz;f{coJ1x;KwgPfrhZ^mNmXo

;7wwJ?^0i!}9L#G&`<37Rj#mHf5QX-> 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 VJ-)89J^=lH;74Ld!TLn1^1t7y_4NP% literal 0 HcmV?d00001 diff --git a/icons/a-system.png b/icons/a-system.png new file mode 100644 index 0000000000000000000000000000000000000000..6638dfffd429826b0f6b152a1255762a855bc285 GIT binary patch literal 1283 zcmV+e1^oJnP)ff z?ml$jF!N^az2|$*`JNw7_vD$s4}OTmU{jdp5sSmLI$*GH8n&7m=Q`Z+FY`mDA1* zE)~V-hdloha5E&YgW6RHmT%lxY#%=S<9bm%3*dnY*Z>{^E2=2aGPCZ5aOq9&Uwbfd zwOJqDc`(6CqBs@569Da@v-)q~+gX~&eib+dS+U_BA`7Mf}=*d2&@bA zMHm{00E|Q!g&+oCoHzy`xSiT<9YhN_C<0LK6JczpdRr%E;+E1UqNuhKYD9eA)m`7z z<6}2*M&;h*XX#a0k031mQP|o5JQE&FT^~!an`f+w*2%;J#j<5fNK!Q_PtuiYlYCjN zF;#9C6VLRjfOTML5@UB&l}^$LW2cFl6i{o`5qqM%0Gyj=8VUwr*#P{e$|BGfnYz9U z?5mlYCux_s-vPy3A&3WVOdj*q#L5a-1on&2n}i6lZ159>5mTN{NOO50^#ma2ynn}d z*?l9+-hV2~cwB_8mF=1}c`}E_Y;e1t3H8xeS;A_0T7*NuV`iE@x<}X=ifmRTY*Zea z51c-q$TAj;S;K^o2?wN>?y?;KN!>lPbQ=O;lhs?UMcWkD_ieqUXPD(kw^OVKz@Mu8 z0}QQ0h8Yp6uOAqQC0MQ%)M8d5qI&2fyZ+XesX;uDD@ma~o>zh@2qA7lJ|GMH3u tjw}qdxxPvO(}6TtKSRv1wTFS6cb+beAr_~5Cn@qb8wj-8Py3uAX4}7Gzr#0Y z0ps7c!p47uM6#AGk~3^QKH0#~%Iempy-Qv$-TD2~uXh51N$#QPVoR!ASPnYJPB(5a z6sRuGkea>IN_b+%=Z_H=x9PeDG8phMGhAEuWJQDirSF!@FH2Z_a^-uIAQQf6RnpqC z+xQkq{s^c|PugZym-=8sdc8R_tIYQI#k?oc@KAn^KTCa#!iyH{x~%Y3BIC^jj6 z{(S#;_mWgu^HMF_6E)i^8Uoq%zVhFc_;UKPe0;=Z^93&j52f+T1cpwx@-5*wR-wJu n_Cs3b-81%@0v&HAFvhL-5NvI69|g0)o<{)+bRGpv@XqrBcfft9Vgnd~z5XD-_jameSs&9q zJq?2==N!&NO6mB1_P6)q*E`@L_zVEcvgH3ppwFBHye}m7ea`mWj@$RYL?ESffb<~( z0Q?8cd!Ks}x5RE^8mVI;AQezRHgHpzNbq*e^pR*tR$|K!PNsp#f;uBtQ}* zCIi1$qEiak03k@W3{@2(9wIyxFqK3Es(hLKX#xN`62P`aEX!QwFQ67N#%X9^=iI}? zq6ZDZ=MW@2=Z?dBpG9z7zZ$nco+@xHd#yH`89zQgFwZk$jF{)9MDGz*eTwnagw8pv zE2nj3C#M2H1y2wm<~bq8c-#kA&#z<11Gfe&GXVey@5{7QE!QP;fvR44;1SL+0rLV$ z^lleHHw!97@%a6FJqWyAg4+Q|)C?Q=y&(0jncq^NUxxb?uaN1oXL(@Kk52EG3T#`P zNCC9~Hqh&NPZR@MlNybo5~%7V0zd(-gb)x_1o5z*6l27`?^h)oiJ>37IHd~z22DFNqP-E`KjSLL-Sh`Rf2tbV|R zf3|I+{ST;_vaSotHva))B~E7#3~oq1_dSz(`0QxKg~40WpCSMhQ(i*I)b+S$S%2kU d@-Ts)ioYT#tq%E*e_8+l002ovPDHLkV1nyYQ3e12 literal 0 HcmV?d00001 diff --git a/icons/ananas-designer.ico b/icons/ananas-designer.ico new file mode 100644 index 0000000000000000000000000000000000000000..9e815ab46b63c175b9c5822d27e36b626715044b GIT binary patch literal 4286 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℞T z1H`VqjxW<)@}~(lWsSuL;5TzS)IS}E>Zh~NEW3?>KaL`J1>N(6W02=D$iZp+; zaT5ceyFEjh5E;DbKWPfUGm;gQ_=(xxpvebepuxhaqLsYgyC}`b@~QUkKZ8wkwhGLDQfM0 zfX<0V!G9t3$&Y8C-JcEBS(@t-ENF1G2rX|A$KL!D@>&DrBWdGy2>w5C)c7&?!$Z z)VZF6uob7^H+3y)?tP9qZ=68`OB{+0xh6r=WeOUty9Zt?9_Mk(9W7R&*-JATo_vg` zpSGgU(aXY4ow41-1f3i*YA-@3o<+>$6XxpBbYLyBthmAqKULU{D_k7>} zElsWUN6&jj!pzsM0A3@EdgexKnhQM*PDM-7rqxpI2;5o-vFa4aeqA7{n?csLflu|B zP<8tgVXI$w&lIYTkQQE*3f0O~!qGU0U&lk7U*`3v;PZeXHo{|<5wTX2ch6-=k;|u} z)gm-Bn&Ep!58q3C_D_$d#FbhSw`xP&iE}J{_gH9bCqNu>1tGgLNFS%6=D`e%HG8B! zI;SFfOE$hL^T>VUON7>`7F5{u6qUE%LzQ*6(c;8Qe4gWxyPQl%(Ci)1PFjP|g(sn! zu^)bOb|d(gjZn?r4ROXfsJA7fX0hIzUCMP;k#>{UJA-RP+Z7gLs-Z};%VO%lxWwzH zF{xJ4{04*>tOzk#5n5tLWT6e!i!G>_RE7}J!&M#{Q0*Z-*Qr8O+);$6RmrHnF&>R} zB%{i&7f_k5`diY`@rhe#ust6^V-69fZ6y5sll1(0NM9X>dd7LEzb73!_YC}&#zDLD z0er6&B8WJA1$ylmy4R|_W}>sg|D4Xt(M}f?jNw{ZuG1X))}!oO?otf2JAJAV=ktp< zA(C(>ns}dPX9A=?(}?rVhB)myG^-QQ>RKN9JvA%T(^n#BQY_tfivh}Ec?I|MmJjds5k7~kex2nIx z=~HR-Jyctl2KHCxeA6y&i|`@MS*@-lqQ|*7VUf;IY1Ew}pGtF1A$Zy@M9w;lhU>0i z_>(Nf0*}4oT8FJc%PyTzze_KKMMnP9L+^e2FKIjz*BtQ$K6QAcS~*T{#yR^`L_Tz) zNsb-Cr^?{FFdI_ajnIrZ3Q1ENk`(bSA1P=A7KLjIZSKvN+8 zNP6#^9Qa<%_vT-+Hs|`H!5+6ymu#z0|FIn*r%DmBB_4H2+cBr=_13N6eI(9Y3wUIM zdQ%pZqfbH{dy$^=w%3PP`uqs$(75iSb13RRbD;AJ!dueb^=@0xKEsBt$yTBD0<=^1LHomg_|M%2dE$Dg<`AYXxsRaBSqOikgX*3gzG-&v zS@{o$S8}c7M=qzh(rKxESXVY+mCIg-Yd?eIi5KrFfPWG7k5aJ=}J}De2|Sm{n@JmNF+pBs@MeR`2TI_3w+szl z6=P_&Q8C)$64~36eXUkH?X{=px&1d=Z6ADXbE~2s=uo>C! zE|bvOY!ccUO#QI_y)xg+9tlc{3gN#liv&6~aVUw+^Itt}{`651p< z;dj*y^+Ok`7uwP6yaknM>;*g}zH&eZ_0O5`|MosqepMifL4>1`grgsjw(kwO`x#We zWdhgp^mRHE6|Uq$oRR|R7bE1QCTPwY(9CWGdmMf7+N~Z`;8Zj`luH_{7*#f3!|>N` zCD*u*`1|VRaVP>GIN*22i0He82-y`6?XCid6Q4mjinQ(*T%Ud)et$e7ZT}P%mfs-V zyAHn7_Mswa-9{%<(Sfw?&_@Qv$V7`zqdiwqY2`WZ`e@LiIH|6>$FP0+kVhO^YSP(&aw>s&~=C7^byrk)G90B|Fx}GOWibk#@F2noXO^kZPmg&4$ z8)~+CIbmp)9n}pcggq#QhVCKoR5pV4WkS2=6#^DMhIaZnR9<`=9gh{D$?w$8vsEPyy@HI$zbNB)%0aIJy(-3Dk^-a*LiLd2BVP}O2W zRrUt&D~evKW--)t-69%+is%y+LIWNSgQEdV~LoaS*jT{ z^*fZKL*u=!>G7F z1*)GeLpg9Sl;h7sIrJEm!};vfO47PRnKg`+mxtj%YIPkP*} z+fa^N2jw_=f1{T}`NeK1C#;1y;~4xem7q$I71anIYguV-@)*&{Wfb_#zy^o4$tstv zF5^mb!dU0pz*DoN>d?p8CzeUu43n2GjNqxNo zzLO3>J>?{{3vPJ#;55J8MmTAOb_sff9nXgLvIQ~OR&T9Sb+ZZLHPZ20ACvCbN4)e3 zRA*A)dy(d)=Y<&Ua!H(XG*9mgn{ReTt#R1ve_l@7+-g@a=d4~_>aFK*O!wQE_%w6T z7WA`enF$SYE#4ZbHU=}=>WsoLw@dk%)h)F=V+Pm1^7*Y%dXLEK7b8pT%F0W3qW=De zG#8ym|Dy@Qr`KQkwA^q4Um4x07AwPU4RH|ML3dQ?ut=kG zb0BGaZK8{Gp$+2HG$=nh0H5KfA+}rqsn14;y%s|`WEI42>ml~0e|KC6W&e#(eoR`o z|13xyzJoYnHGJn?LGX%OsC)1kS{%zk=pV$X4iur{H9JC==Rz|(5z*HyXj@_vIusa$ zx{r$yvf(_UPA8%E%K}u&H=<&;5p{GX@7booZ#_Pox3}J5YsB^U%%!|*bZ^{>uHG}| zE`j&QITNpaxm9RmH40TpCkMo3A@pzx{I{kcY{LsL9{GNI3<1-QB4$Y(+F!^*(}S7B z{ff{wS%+cyZlC6N2>VthLpAq0>1)pZ*a79(t@Qh5;)|~k7*F~=*N*5y8~ipVpef-! z*ZQw@S{rV%TboUExYboIn-TKJ0o7R@G;w-pwj@Eloy%whRy!jBJr{YobX*Swq7GYkwGn8}Rc}FD zjRKz|<(krFr0YAmEkeUA3$)XYL)Cs3)E#FdW^+EG7F|H6=XQb59E?qIh>LBG*eM3L zmh1NUx%%dpDgr0Zg67ljQQ_Nd7)Uyd~X>bM{tJ6V91(IP(}2?N7suK z^Q_LW`sb~XCOwAy%`<2h6W=!$+&aiK69^Y|q+;TMQ!kuMMZOe!JXENkvsl>tdLHP-B&p|s0KS|ei zCr;LHGwJ%nP=0=naP|c5fU4XN7cs<4~|qcJJ2?MblRWh}nAyp)=Q`?*6Cf^q?3M z4IUMr73KZ1U(C)3)-b$QI_xixvPV&wpczm1_Q@PX&e?uzD*<6{3!x%x)GI_wdn za~;ZW()99o+qNkiwEXb>dg%N1Z*P92<p&xu35+>EmODc}DSfT% zneayFu)0j>ythpFF5RtZcFaN=JRJjGxD?au9=|Cbx3;g&t%$m&L*VUv_+KRqnR^4` zw5x=rsgRevg!D7v>9kuAKRXX`$~|vAx{|cM`p4@~&Av*!X_dEbU2H==j7_17-R`#+tLS9}<{gnab zxHHs8J0MRY9GKx_-CJ=pd7fI<|E?%lh#8yXC2{l9Np&&)X6A88>`OiMbO`3Q*Z{}A${3^bq-rY znl~lhKj$+{t!>2V-?)875pU#k_aFULu4KD}>Q(0}_4Mc59MCIl8(DpzQHkz!Bml|zV zelR+Nrnp?%ImM*`n{rAUv}oPZ>*4giy>I`{rtP;CezP7R`f4HC84NO;BEA zFJ<}}yBJdB4^Y=%iqU6FeGZoD`*zxpEhy{GgmUx|1f0u5lM(}>EcE!74pb?$W7=z% zpO<60Jieb>%H?iX48quKm$<~?tg^`FtX%t)9o>@4h4GoMrB!A}onPI~h}H%p*b}Xi zfos-H@Vl==a02I{6(RTvT^9-wdAkfzXY-*NcaSjQ9BN!8%{uial(i;94(ym8|+NRr3{fQA_SM%u7qe-q66)qSNeU`NR#$>RE zNykSnd`Orz#Od;x_|~Oi9l2j`=y|%RaP)e+tr6#Dat(X0zdS;W$LP&ti!c(m)frJa z&47?Q1*rJMfU1dfJt{@`*&IY3d5H$Mict9oVfV2tgq$k_*B>x%ZD%(MP4n%DdEtQe ziV42QbKtit3H}!g;d_rg_MPy{C0&qYB@Lb8&1q&2D%Qx1HGa#pAkNAl?yiG4@hRcw zZK(cu0O|YvP=34+{!=%g<-t1`9iQ*><%@iA%!53imb-2seD-$8Rr`C_Xq2kDgrgro z``Kc|{CN@;mR}?;zXnqK8IXFC_kEy@Pi4cmXMEXPfG|x&4_$L+N0bIUiX;t z#-%+{Ryv3?1pB*PiYhuQ)R&FW{E~n=`DU~)w+MU&pFK<1hmhBD`C@O@FaFLH`^w~zC)?ecPj9FBtS>aw|84hvl~U>RPY=2G?Z2$~w)>HE=4DiSqDPxD zGlF+zB8D|>DQA?~NFzUiIOrk#TP(++B3-{#S=L%rR^~%FjQHP|_q|z->gN{HzEz0{kjCQ*v_9FV>wJY!w3-OV%*UIHaM~(f(#$L=T8k^0K zA6g*ZHb8mP2-WT^s86OtyYCr%HzYzP91Om#Lr`1^aY#O6bOp*0d`|xyq?W%z4(anQ zL$}3Tgs+dsaD&r_ebRasn1taLmvT^{UD2!5u4qN~S)X3(1CPmjRp<4^J0`TZ8-yMY zp9>9EUxaqjW5VI<2wRwi;dZxjoZBt45A|-7sWbZ=Gj?&kD0`7Gr{Wyx#;=LTzjZ3= zS&gV!WJ2sK>Wd63S{O}eQfx+LdT-5Mn9=yT5p`27sK{p}^XzCq^9KK2BfS~X&q=Sp zv?1uOp5_n}f>Lbof8~HCgYYwhbOG^l&5~t+lJb?16 zIPZD@=O}BZ|A`@wvlQQC=;Y5|l!!y`yi|0%_#Ev{ry_FJen|BO6A!INI9dgwZ(Ycv zm%{IR!q$NcAjNz{7`g~S>u8QW_!x~Yy+r4<5}{p2F{19}LiO!V;>z1m)nGt3(&Jyh zary2u7`rcYI%0--+{%boq&W@~-=@z?yC}=MXJ7M`9vyWCfjvrClQR~wzYBX3u-_ni zn6Q7=M!U7yUZb)5(Xx`EjLUnBrY`JZaxA}O*f)=Ds^u<6b)Mgv-%Um3{q+13H$naJ zZq!_S5u;Ph%I{om4g2eTYjOL2_TZKBw}+)6I|>c0+q7-_PY=2G?Z2#PYP3PnPfrkW zq7WavG9dC&5u#t{ytxnZ5i7*n$DpjT8gi96Sd(L}{rh!exbN3jXsl*IIpz-JJ;e|o znGsT8K@E=qJzO@$Y`ZJ4OPNEc@Pc?2VOAsF$Ii8*DQSK7zo?Ytz?YWS@^+)O?eW5r z;k?!r{fy7l8{wNuuY0Z#^1%$K_a;HJ>mlT&grTbw;ZK^|_dyw9>MJNeJp$z@;!2Zl zLj3N$ckNEBHXc&jh3J}~7e*O9;uym1J~?(poy#R?l2C%q4ztkljYDWm*vVNSZT|LK zZuizHu(o86(am;C^A&bSt+v;WoFD`4Ri3a~%PDIx&9oc<0A|@s~%%`4>I@ zatoX_!uZybcw$4n2@Ogt;5wtmWfpv(v!H&44RwhJSIe?{J^4b3U&b2Es75$giTHc1 zVhbu|TfJ+ap#=^E<~zLkc$~xO^&A*+0)f{v!Dr!reeJ5iS#y3D%n*Obe0P3mc|NpT zpCEkCefa%;7}Au*2>)dR`aj4K2FK?sIzP z5GS1Ha)uo$(+yxRD(~(l;i1TCl%-U$h9=Y``E|5Az^4| z!o7a~t6b5QcqDtcvsWmOWv&G1?9I+vle3%Hf0VOA zJ|`R<^;fz039ru)zVV)Z$8xK{+SOaLV>6-|?>8ko5PaY4<-I{Pj|36F49syNh;TBJ zFtl=^6%oWueV;mrcRIa(1MFwzn@u>njrya*1k@}o##e7WzRcU&yG(*=ZXU#Mav@I6 zfH?aZG=E-1#QL+SwDSV0?7c$V@i}Ureuc3GHgSg4;rFe{>D%d5iBRjpGgRDt8`5-| zi$-jMvhPl)z9(F4I}=h}!cV`xkTo43R-J^<&8etyIS;k3lp=TsX@m7oQSng@YGjn4 z#_e?UNHz!~(w#n2jcz|)vpii;@G0XV`-9Xg(V;W-N7Pd*G!JcPVld&utWtDL)?s3) zOV#qwWqkC!SizihuGtyN^+;Tg&szRllgoFk(=GMz*cBaJX5mMhD`Z)ov)YtfI@LU* zGmLOLuEh=oxNB?w}qHB&t=wPr4s-sr#+M25SX&Or%Nh@zf)$ihP zFi+oS-UCx$r#&wq4ci9k=jRZwme5$Yd$V$@6AvBtmq(sub_I@1cKXOCNLzC5FyrP~ zJ5-(KL%XMx_)8A@rrH%-%(fQ$%8Wghxg6DE6D*K!slyw)zB?=kNu`T`8&Uf`7LLSv?p#_ zpLl5~<0H*0eDOMGNWK&PgppB&4#d!F1ZFuQCO9Ccl6EI-RTIYgayHA65=5kzfuEN% zp!?bF3N`hKIQ9X=--@9ee+SC%&On;83t?N%p!SUvM4ozz(Bls=xYXvuzEh;LdmJq- z9lX(IYr5WMZ#2hb3u<+#5cN+N!vEL1sCJ|jjgA&VRkOEuZB+K_2`Tn#1g%Ixotvcy z-I@TuO^?ttJ_lde+%o%N_sO#<8r&^Iz@{X0F0cukt=8rjvoohMpZ~+-tkgLr4}INs zMIXCOp}M2@`jU3FT7=K(@8_7TL0ykrLf5l5F)mdnPRMad{gZS;o5wl~%d#ozpGii= z8@UKdv4e9^<``WeEpL9@hg`{-8#((|1+F-ZiDic9rAG_Dkqvz;V#z}X5-^xr*fIjQFWWi`XP_! zrs-x>N-IUxLY>z?H29T?I4~$Gp_Y;Jt*C2M@2f6JUs28QY z^FHaa6;k^p@FTphceVi4P8tz#(T2|LtQr~x8r!wa; zGcP5csOF3JoyPp-kr?+FOFO={33c@r_$QeW_>wqj4qbUp1Q$CHLKs?&?k~z@LAZgQ zzl5-pUQ-!QbI+0-s81E3IrT5U2J^4r!_>FKZb@9*~NrK<07YMta zgZ>7Km*0^duFV;kjA^`gzR2yY{6mpDsK=>Nq2;kW^h$IJfs0h5%8F>erGY%OOw&I)GBPUS)0Y> zW`D!=U%wF6x6dm;=&fY1_h`iZJOrm&=s8L-D8;0htG9&=zj$Bq<*PF3i>C$RXIU<( z)%g@eZF!97l_wCm@&bJKrlI0X8`v9Xp@r^W?}+VqCI_QTZjt+fJ)f&?+lJ^JH!!B$ zDSu;esmI$r@-)&4y!SWF=JZ?Sbi~%`&>orwZBb|TJ~Ur)1MPpkjR{Nl`-sZ-`AYBG z|Ewt#KKNkcX|%s>LjAi=^dx>0c*joKSr2gxVOIYW#BE3~jysR=pU$Gm!5oDBaurg) zm4s!hpxO8YAr>pbIBVxG7kaxa3O=(Pa3vifr?Mfh%Of6Yfi{)6gu$w)m1{y|h92L& zc4=2y9kq`YmkisZH+A{i>QN1{I(@o0&E8Bjb-V%c%9oJ07eHQ`0cjrL#CJImr-L_1xfO#6NBfhOui@6AB4KE4;?Zs0MuF=PNso@*WiWRfa$(H31Y|(KM+5AC&44^vsHYOwMe| zgZ4rW1~^?lTdbCre6EYvGAFqmzQc=cKEbE1BjRi#sy=>+u$SzmmxP$*EAV-`S(^B= zSn9Ct97f$p_386aCj`vd3Ev-%LHWrXh?T!e*gN2Tp%OPdW=d*im3OYqHW zmu4v8aud5A?Xn8dBCQZ3iT88v0PpQHhO*y1d#V0ru|(Bu(+Ps0@N$OG8uiffx2tIN z%WZ^4zSs2c+yAVwmT92>bmx0_Mk~($-h-o46kV6E>si&KGETtPqiVGg0$_9km{s zQ7c}L-cFmMGx5+)f4PJ~gr6P%mq(~cJhTeoXB~Ro#^y5omQxmXvbg9I*1RKcXDB*e z&ct+&%a6ULs+VwP2F(fA^^oFBP?N@1-7`a*Y(qq`-J99Ya{&7$F;C(ePOdL!e##ig z_}z|PyA@r$Cd>P9l?k8ud@Xxd*RttRm9R9@W`^oX8RW`+p=vb{jjSc!ntHzK6UHj9 z5Vzl9hIEYh`tf1}-^oV{m)?8MpFR496F=*zw<(6`o!+xnj48Y?(}K?rY$-4-RUACaUlB2GO;^oA1{ zk?Zssb}viOX6Fs`J$O|Zo>->vn|}z>l$E4A_QUsJ24b$IW4O(!MItbii|q zVwTGh(A#WLR3|L&<+dq$xUCAVk>IS7ck`Dkkk_nv{`e-fNUA>OH~4A-{{GSn2&+*G zp~JSJLI3w&c<iRxl4ug|vt` z=}N{{Bc$os@cs4)T3j-r<-sh3%smIW=kJh*u0+6B8xc8gKkDszhM3il5w-3)D(*`~ zts8mhW;O}`s_kYD+Wf6UsQZR^>R<10wQXTBmZla)o-4@voc${2mpdcpT5KVci(Q)j zM!O>Pjsc-JN)Qxpf!~o#$ouo4+MY@Ci~;ILH2)-7;s3&piY0chFA>*5vS;4Rzd0$7 zbJqUd{_+T22)~=tYc?P(Z9*6OMRC@9Gs4sQ)DMw_*P3;YP%WEthdpY>WIoRmn&X5z z@!dXDHKPF?+$Mo*1DIDc*KO-C2%Rhzp;5XKy$h_0&mC^n7`-=d zsByxKI=g6&>$ekP(*=+_Z-f*(8ltKpY4~=KLr2ih4#b6L!~gd)h}`*@xacc1$kC&= z)rcAvBVu)&nWDp>a<>ojzD;(^2k-JwJ(|vXoe*(`xZaZWs1=ulR>?)E^vaB?Ne0w> zn1`x|($H}8NwnR64TDcV5c=QF6@un(MD*sf2)u7Z&?7UN<`_{Y(}W)Mo#K5a-hb?Q zD_K}hc>2{_r*B)ALHJkZ0q^bcT*X|Sv6J@)w^}V94!HD8s6Jy0sXnb`;m>tT)6yZYC9ZSAhRWAU z(DJzs)vgnU4%!8==PpRUC3`(ItCSOuA{<~`sGe(v{4r-WZHGAF2*jc55P38OAD1|l z^-^fu5*O*7V-NV$@oy611y=P^(M!pl>Z%e|l7IgKYu{gkL_u=(C_G(&C?mgqJW&SpcGnuV!u}O&@ z!AFu2bg2{#^N5EYD1~ZmhPO^O=x`SCG2*2w=zbrtH?jkMbVZWZ@9433{Xuw)e@S>a z_OEh@vzd5ZmM{K&w0CdcBYyPOE%qsQDw?~E;2b@!rR0p!p-z{wi_s>0WOFGeym6}- zS0@l|5a;z_@4${UAACSOxPirlN(m-}pLmY$ugZjenPx@1r#i6rkvL>Kq(Q_BhwMSX z+$8uHpVsPKDblB_gp4C#f zqZ-%o|MbQc#<_*e`G?Y+$o={QaZo@qZaS%mRcm)t7bh=B%&PqSNv&>p&vuqP#GrZa%gsxV&h8OEw6BUJl1OY{lxP2zaR z%b-3>n*Oqmw0!}TgU>_R=zA!e{0iSmPY|*p9~F+Xe}@?#oXbVseVM3B+_YPQSs0LP zQ`Fz}5;Zm^>P`b{6Mj}R6Mp8}pgoZWzfE^h`%*f3=9z`&@udh^c^~5NH4yu5 zfYfIPwBKIB2Z!>}?r1T(UbP5X&S{P538~spNR>Zw2_mq2^q5tJhqKN;v)C_>Qu%Lx17B0{GgLBOZ05Ic1lV(0FJJbDs>m##(V#>=R6AqOL^E+y9-A1x^z zay~crE8e%_+I-Gt8T-~H*L#$MYB!#vx52F7vj?R2qnFwoRhK&LRr%kYPu@VS>08k0 z#|?t?_j&oCuuzOYm!;hGBD+a&aNs{Y3g5T?>(21+MQgBl=45yFBHUS&%mvp}cE{_{$Pzlx3Mr?)9SEHGoN!!1?0M3}gYu!r<;P=e9xXU=1SYlYa8IXIyV%0UO9 z9C86Nabo!nJ?}*w#2JJG?P**#n@s<2iT5$moR`E6%g`dng63C=NB?pQ!M|Qd)3^dO zznqH}$6lh!iU;WQxX62ciG89tuZgjf_54ucfn4LnYldfw^FCu9`g@r@`ls@D`!KvW z!`L^0?ysNIp=f0>3Jr6OG}l~!Ce8rOu_6SlyoE0J%7o_EauI&$8GJXTLRy##@rM-1 z>#5JqnGlrhM9nfQS~`qgjn7_~T))qCsr-}khB-fUkIC5Oh^}wiD_yqQd~ScW(^hxPYnR;ENnDV0f2`YpaDxTDG{^Z~*Fk+QAFAay5qc&S{j7FH z{TBv=?8<_AK@!9 z=I425p}wd`y%Gz87hZ(A-9$(=d9C#mNKM8e^y9D5@7Qf2Z035z>^X~=z4uY)UI7L; z96n>;dSv#nKUrM#@$Ho7OO6zm4Q8#*-xuD)`|Pb#HKMe@r{VSU_}OC*-)6D2+FE33 zzQSp%&6wVG?OLI7^A-poto+x?XGmBGj-}-eJp26B=!mHI-uCa?|9cY@3Iw#636YdKBc z{gJR|7SiBX;5%_M+TJTc#PJ+NCz=pV7|Zqh74MkQ^`TzyUvLh-t8PJF@`U&raneLH zxGsG>VaZ2tJ>rMuW+6Po0QFYV?cY8kzDt;X-az*f2eIQ!NNvA|Jb5Sa};6r?H>M`o?NkP|Si}2N3m+!~KLkF?f1!3p-zshCC z0p9oFy^t$eX|ou^zO#8WEfehMVX!M0>v*4={YbjoOp3lbtD+_Gz0d>;wCqbq^GL|H zGz>{LD+VT*6t#~&g*g2r#9tobf3x?V!BJdYxA5xGboV5UazKb65J}{mbI#a+2`1Ut zV6e#sOpYe!oO8}OiHr~k2}vLX$~jKXGZNtE+h_3m>)!k4e)U{exj0o_BZ*t7>q!CeHbApGpO1wxAn;D0y*`ND?~=hJ%6^mL&;}N(w z3Jso>piPO%-QVkb`aZDu5UclOHS>p!=62t|$nlt2=I~@OJHqfV*0-A7o8wwz*Qj?% z8yT3G=~rLTujBuAFbwtXwHGq4 zfe;lPAgbHA_sqmO&mgQM%|7c5@hO^*56ob_cAMx8@ViYK_Jf@;%?8;qEBKL5Av`vq zl8Nwvbhj{QD}*jfP+`#-1a3@&d_^2Qk27so0x!~yt?m~=G5-v_PQHbF&wB{V3f*xc z<+V~YG?CUPj>h84?O5)+kvQl)!r3*c5Uy(=J3(4`@k2;Q>;OOMIHVKLf}b4=*@Y4W zCL7RPql5SQ%aAQ4uDl^0!6)CNQ+xrMKGC6PuEouD8K-3PpXG3}I5%nN5XPgJ7yRwK z?8!{S53)Kv>ZCalp5jC&o6+sbJouwa%4&}q5pV90VnOXZ!iqDw@O?#E{b&jXy){W# zzY70#mm&Oq8Pdr&ApP+IVdz~b_oNedPl9}N3UU2xh^sRpte|_dKiA!3H27I5yk43h zyKRIllJ#q&^(mU}@oQS6VyyIeM5Bwrz_EJr%caG`nWksh&iqSR9s`T*2O7=vTn)r) zMNnR%*WMim<<7@wn5u_@)-2ibOT^hPlfKvke&{;LCY^%k!e|IXuDk0MR7>w6=wdqj zPo_b!>M@in&eQuIfH3z2c;fZa=_hH8{TYFW62N?xmVa~vZ*f^`ulney$h<+nbvQkk z4|U~a3shH%;dNI7IqOe6_YxhE;D0#>p~q4P-zEL)+sVg&-|VDSuM?2jnw%P z%{R~AyxDyJ{rfq~lizwyd-qn5$^KWrJ8zW=&(2>Q866+D{Zw{wcYo6MU&q(+e>XTN zf*KMJZ4Xh|212!=kPbP7pc6T$ek~KK4N;`IS)W`xLP#q%wCfR0b3~b7clXti9oIqj zT#JBGJ1Ui03A^IJkJt^N(HJO(u7Iq~aqunZ=o1Oqs%%ueuSLBp8Bndb3FRi@XusZv zbkH@L+k}w|3f)JAbgNq@j{K{PXC9N`TEg)4ne<-y;2#sFo-HPh^Z?Q+#PufMhp?7- z=o1aRZWN*RMGacs&Vp*=OTwr`2(#~@NkS3YrkgR?>GWVdkyt${iy<@a!uB5b*~~4N zcD|@78A|vW{;kX9Q9a!W?h+I^^F4qtop{)c>+sq71YYazL;T|ooipQuci?#_6;*E*BVbn& z6g%I!dlLyOa>0*#1;te@{L<)tzH>kzo~l|GjiH}iQo@YDQ+j=GmN(DzfA`N$Nqv@U zT4q29abx+l9LVT(Wrt%4pJO2|d4?9*26%411936o`j~^@8HRP9MjCqoJcb=1?YOk8sG36S3awXRZ#9T`ry(BtlJv}KNC)qQ(1G5w{&2$V<&cGR#_&UtlC!y`{a3|V zDtLc?&F%HYR~x6Uk?{mJRQ-)e4orKD)&GMBwV?PD33VsR=a zX&vHW0$mfL7bNGR#^51;`%iBUe8BZf*GA$CT;*>Gm9zB z{Nz$^cUbGOp2rN2P8bc{nIC*_hfNZ~YB1kAQ6_r(ME&QjBuBgr21q zPCfG>yq6|npx!QNL|7MkAqT@#Y#xKNoRTVZEmbe1L7a99!qn5m^-jQd*%hef6K9@! z6Y}3Kq9I{^(-(U95w5b{N&E!jhx6&$m#4e;SnJpg2+)$w|KLE?d^0LWnD_FGPfj(9N3+^hmfITc)WI*u3gK=k$}YIm)ODLTMsDEnM|U_6kN>mZUG>V9 za4cQhp+)D;{|{%}*YR%~5{VRIt?`f!I0N;fJE*)f1F|2VK-Tv*BF+(K-1M4ossw(| z?HFctNxv~VJVIZWqOMJgX60t|A}-XztS2md1)(d=m73#ee$IsuJ_ge2t04OP4k3`Z zPt#*i%zgsZ>S%cGNCQtg+;7cIG>M|Qe}eeeuPKlYPX#|X$<0UAId;?~Y-W3xtWR91 zjd)fT>D!xnNF#{@?_o8d&xn^2hkZbp@koa@ITo}ct?mDqxN4*U!WrVQM{?ZtmHza4 ztQY)Hdc8@XT?)2`x1r2lo$;w77GnpNU)7lOuvZdsP~x983vFP2z)Yhu&ymp<7eA)Z z$&WLa3AN5?Ap9By)?c)CQ~~_AKSt-sOf)$ik1Bg!quv88e0IjunsE~qcRhzMVWrpB z7z7>8K&#hAba-im_sl)S3)g`sPAWT3*Bh^a&wJCC+;!rVHLV6TbI|(a(7N;IS)S8y z($I|i{f~b=2lAccU~=zsy4rY5!VjTGY|$Q6bkte<$vLr^ww`bin5_3CkU#a|mTQ zOsp=5_1^4dw@PZ!8mrioOP|Sm$Tp`zI^qaCXYa+x482FEmxYk^Tm~_)1BBY+=sVF3 za-Vjn`_nCW_c#k#mxJ(|eG>sI?x4cDX9(Q!5WWXupxzmafRk@A(OD*A`TK{>rgoEU zPI)UW-IL-Hbb1<#$?3(yl45hf0h77qKCQO#kI$^a)7!?mCV~)n^)&4>${0Vy$Gv6U#`5RQY zrG@;G6{;vF`W3q*Q!Qo6k#;Bl9r3aeHW$x&(g#IZp*&6eu-_eb?_`*T~kS5x|U#EXRoCo=xObE{n5KrWxVSx!h*~&!LV^@}7 zapx5=|0tfG@2excBdlSV{Of0zlGU@YnDQZusU7Qw-kk80VW;Y)6Jd;lYOLsBuyE`; zdl~GKE;%-?{fk0$d8t7c#fByPO8!nlyjE z$B=&a2GUXQh^xj!h&B@+HJ}M$M2OP>Z;KV48asp(!qH?iD(Q9bEU-iRoNzwDif(qZ zq$Tk;=HtQobnprEm}`fx*@DXS{~2$d^0~~DcvKMUhspFj>p|iD!UfqA2kIKW#Dm9_ zxrFabE@_8S8`p~Ujizg@bGsM;YaSwKNhI;5H^k`5=L zQM#sG@LG8lm5#ha+f*w?8C-m;2f6TGdK}{N^HAT&L13y0ez}BES#&LrOCaug4L-&I zX}kqO>X&nO=RWKvjNM=4&Szgh*w6CWSv})#pPed}W8VL-a!HT>lyU9;`>F8%(B3%ko`>9 zt+&I6?scHX=Jso0xvh-9_jOn$O|?e!VEvFj+9Wme34`zFLUExO;qQ%T9AAh!QFN_G zlc8Ag5dB_gx$QPvy}sA;IAxD55UYOc_5>3>yU{w^9kP(0QR&x*2w(FIs=1e-SQ-iW zc3Nxp$D>wMI#`X;T#dzhRK8i-GA0rJ7ZOk-r4-?3wxHdaa~S<3$zy)D-g{Z9(SLf9 zQ@JnO+?4Iru$-_a)4uFCI+C%NuQn-^g>=Yq2&RdaOXghfRU-^KB^KIN+1* zfbT^;D&EkbX}%pzGo2W&DVO%RW#^{nyHvlFe3UJ6IsH4P>rv@>34-rvNv|hD+Tb{Z zDbWzR?}n&oM@L7RFJlQq#}e=O9zv~&5E@N|&~Y)O-);pzHwt|JgW!7~hV+}8r0EGm zhrT0j`U2v19V+N7Xi7S~3h7mEiv?-};YtS0bFBl_iJ$uD*zbfxNmf)~K6Ne~f@$8% zNc&6U>~0S}=8Y2Z(d6c#%(IDM0n3YFKKori*|`QKgehqbw6PgEw|+OeJbo~h3)5UK zWsf8$*YHjW{IVa0SXuaZubVhAPfV+`TwhpZP)V8d4X>d{Ntec5rNuy46Pu*PPW9 zk@l^SS_01}IZ($K;h#zOBl}C7P;s}A@Y_W9$qN29ok!6Z{Pbb?NxYxkH`ddh)%vse z5zA#@`K^@;tzdO!%pJ6D{5adn&M6>O$iQgZDxcD}N#n+)&dmZ0s>>ey1VY=O> z>{qOl)Oi^P_2x?mx{!pvc{)k6L&wqUQY<$y*(l6?Z%`jdH#R$6T-tliCx;i?FK+ll zkAHfaeI5Ve;UN_u>v$d`?-zTlxU2J(ci9iVCh6`G2cf=|hXxu0x-h>-ZMitvS}yOK z?UDriybBczoo@AUf`@B?>%??^}QtHed`LOLK0{Lk6o`&@zih8ESG zdV~`;GCePSKy&^M9k1xUv{tBzhsrXEL(%;A*V)`2OP(Jbgq?(;uLxf+SrJrXL+6h+ zZo=O+fh;c1;vsb{#GB~&?vqQ}oA@WYmY!z2WKfAyGN9BY>6UHfYMxC+rCm4Sv*9k( zYiWM}vY&8%B?Q)6IqA zPJNVx;8ZQtuS*e*z^7pc#xSEdIg&MH<)h{2Nito#u0^4hhARW&W7#&73)9T=986cM{9(;7jc=9iy+(!w;AA@ zXGaj-C*NYy4{X1NI3!Pcobgd5tI4M|Nw{4KMUv5712yDtuYZ;o*1Fux1?AZgRA_Pc z!Rquf^r^Ukg4e zzPag;oX{A%w{aRc=>s#o6O3qCY(n71Ov1z~@LUiLF<=t$4B{IB<5Bx)CMG7^#JY1{ zLecx2+rLga?lxp=lOR8z3Hg@C;HMM*OpgISISc&nG_R**xbuDFgooAa2GkS~8Tyxmvz9qtbn?yT&P)G>zV&EtI216aLgOve|l*$zS@znv@vnlibgYn ziQfm9NV}KPI&)VKd4dUw=r1*4iX=V6j$A{#n15u0E6bOKsmPr>eDYs1@FIlt~IwKVuM#Tcxp zG9EI|(S)HBAPf2tiZ;t3`;Iiwz7J@gZ2|MKbJvOy9*)pBr7d6OAaKuqc+T64`VWfG zAhrmK(Z3;L$5XU8la48gM%jWii_a#zy(aUF`6aJZkSk>W^fdcA{>8&5unH7yFJnWh zvFgs}rPb9#cM}J_0Dcx>+U^Y0%+-VWfzHiwc(2KIR6bs6>Uv6}@3YlruifgP8SRf1 z;9QAzkQ+lu2lB6sP{$I-S)C4P<$3OY#zOE+nkU3XeZE7Nlj*pbn>X=PsiF6Gi55xF zt|WMFOorE~94IaqLHSk(@l7fC7{WdlFWy7HA25O+5(QzxQ+Var(8NVJXESg?F-7iv z>z?P5p?X{h`LXx#ds~V+MguyQnYgYdBiF&8=X#afB?CW~NmvY9=daH<|&y*`MI2-6GAIfH8Kb@Pol6bV<>2 zoiqlHd63k1YSHRHF1HU}#AhqQNOP-VvQdvTJIftsHSxpjPN~-wBPtbH;GgD%5X*d- z?GWDEQPE^ZgO6rZC7mrK+TA(%evE@_EpC5OmKVlqhnOD-^L(P872gs5F>e*tL#i?T zU*@?NY&W{~y1-&STi-x&C>5#&&*4q?SFG6vp1t*66vKPm9qcj$U`&8K~ypK>fFRgx$+S`^Q@R^u{V2EU~oNZ?HDsW3n}_ z)MpEQH%35I_JZiu4^=0g2j6%jD%>c+P`Y-;yIJ3)p`{LwN+%O(Ju5|(BhL}Ma0{B; zdWW!U36M=#imJPwpy|h@l~t;>1pQbyR*sHA1vxjZa*{idC)3q)~)n0F1 zT=kuC*ji$)#rk&&grCyq#0BF`@Z6OH(fk5WD?KTv9E zS$q9Mh<#T>*5^;CS3ZMxWC_%91_YAk_9-TQ^?`JHjv0#I6CsR_hq&UkJBP7}T@RLP z#QZ=QPx|npMeKnSAIN0TqPH>jVraN7# z@0|{w`O}SX+4&B6rD#byw5!g-4J&i~ zHv{5Ndx&rE0zc_0q=Pqt@3oRJU>3yo8&Gxga}3toJ=pvGY$+3KU(H15m2@=8FrbIS zEb%2hU;C5UjiaspQ^tkS&lMd8c)vB!|8sb-+Qq&WyCmFbgl~=o%6Dcc<7hp(Pk4Fn zOS~zFdF#7a{LDn0ocK7c3CbiLyz?yxCESfL>)mV4;JAV>WpoK)XED51UqcI%4q>tB=vHpwSnnu?!^|Uv)#Eac7}kgG8{*V#ZDR3x zcK>U|WunIA1T=h6h^BYbQT1$=JD)53f)?#!oEViFng%96vm=63ZbT!P^L z8+|wW($Nde7T$!c|7Envvw-#OobTR$b*h`im{9#mDVoQYpyIZR2wrv=wf8?l&}Ler z2QGs+?li(zMPc%jVqwA~ov=N(wB{V0R(;T9Xt{C4a)pHZ>Jj>N{C5V&c_5_cVl2_v z1J@=RLxmrYgCBO5^xI-6_NODF$mI4A->I?Hzm!uvY<8?my};=5n_(+c4b<8tbxtN= zQMSQ{)%*D8SRuV*CZ1%57t@1P7P|Gj=rRw;BQ0GYCIS2-bh;v+S=kgT-os?C0X4e zI~YbX>|uDxFk{3=7eCnUkPfxdL0Yqm%gnVg8o2>hyM*<{V9)QQF>&gd#Bnd?A~;d= zWly)v$aS@uIo9){Z-Gtny~ZVFSjyrQQ;cPbF^O8~=s2UaQ)D`1BX#!AFPh+)obg8Rbq@F^L(&<&tJ=&itZonk}$g#>XZW1vS<*YA-udy+WQD`$7@!|qK)vP^+tHE zhm7@4CLYM&(Sm=Zf&6eTyx!RmrZuA}VeQbrv6R&r{qR?r8%w(res?4;+=DQ+=SQ2Q zkHaqMtG7!=eRK(IZDcuMERUAuG_m`-({62WTBq;BYA;!C7>jeU8rnfNyGK`@foqCPYPSkd^^OMBju)feB@+fc)=SQ2Yx+M*PF-?6BY*tNCj~O0@fL{cfpm1o z(BlabuTIaS2~)}+T7q)B7#<5M8Nz*2wHLi%8_d!)ENpzmuVP$ z;3hZlWHR?>e4*dmq$1@igFbY7X=$x%@vr+Rs`sn8+AO#*sa%H3-_I&Ogh5pOd`60) zruXoV(n7KNJ`@L&Alv;OinDa>f4+qLN-<=Y^C5dkTvKC3%Q7Q+mfIv#|Mq-md0wpk z>5C_y)0?doZ2yAwVq&#OERX7M4j*!eaPxXW{ts6R3&*hj@9ghWK01{nT~5A5PN92$ zvL*50kw&Mq_VH-=uYQ5B<5~o6&Vu(ZR}lKg4Gg}PD;aplBw3m32>CtFu2#ENJ??6hZ4wz50NR4nRv$Xq>%=~6EV^d^n3-T-MOUsM!_VW6tr`gx>FCJCuHo%XWE}`~g z9b_|4K(Ra$l~WC*=XaomRRfkkxxK_(=UQ&T*b~L3?xXLSrOjSg(9h_Qj5QNiNi|Ei zI&5`VOreV248IaPf=Q3dM?G-schPGSag3ko=Ygm@<_sQwNL_p*J?F;(S2DSvmA9an zL(iKN39r*>ge`iAF?y)8O$Z~6>GM9{omXC8r-Awn^KH5WpBEZbHtO9z@AVv7gqlo{ z?WObm`5yezP3~B;SH8pTD1LpxYaTu^}> zAtp1b5r)IuNWM2Z`60PZkM8%2xrWGYOH*@v}gpwdFIm>P^d#KyTZoUWqqlpkVBtW(~6GEI7Uhl2&NwlJo*@&s1ohsII zh&W&1x-xqh%k^USgyALQfvgT`vb#5vOT~Ep0js&?je@-KH}mo)oYd=kGT$Vo?c3y) zBJ6n<+GiA_OQDhLk#FHDZoUKcAGhE$|1JU#7eMy&Dagm}MDW@e1RqF8@XZobxL1UL zNLt_eZ-X-Y7i`QmRBeAQ*NveJ&%3;{a#i=_pzSLoI;GjU7S9c+wlfmSakC+`7!I-L zWXOWLV8ipAz*Bj}J(k88efK06)jp6>)Ud_=i77LgIadttqc7oiF&ec<`$@k)fl8T0aM$!0?Y@_aiiaLFSXxiGsuxs)x1bei_Str) zy6&m>_}%GLvwgo-PCci7rzd`8fpU93ME}u*pEDs-O>)PThVIXlJbUwQU1WOtoYB`Z zJ^ZF!f^0JL4!H@%`E2kvbl`6qAXlT?Ru!!{UF6LvOM_Sbg=_4al zafBn!&0jd#Wes@JtY7p?NQk1?zJ`O-t);WgFaQuce9!!bjKkyoYHs`==RXlvQra-ki7XGKw;Cmt-z7H}GR-%Vr zkq%WIIy5IO-;waM+keX4y1GtAA@*9#O|BIejA7WtJf@luw)z>2V9#SYuB|^>xIi;~ zPA}C(xGeM|L0k>ep~|C>L~DYA3=697yJVQJY!7oCOoS3 zp15718GW?wngVfv#V+Zhv2tzn7OolTfqI0q5qA0R}Y0<~>rH@mK7#$i$7Qlbq9Vn)s0Y7#Vgdf+!bIuh6Y>P+G*$ntz z%|%c=Vfw*5C|a(^(syRRVfS>BvD$KeP@Y3lVP7t)Tq;EMXIj*M>p+DIMX0#*5xgcZ zgrf1cP<%HRvbx={CMv`CM1E=K_3tcI&Zid*JXKuMV^Ul?KR!8M`rGwO(i(N^{L|Cy z>-ZNBj^ogI&mB%VOH+DW5j_}Nz|LS8}DUg z&YGBL5f#IUvklw^>30XABn~CA{v+?c^sBE(dcHzV37AK6OS_hMr3SL2r4W|U^LA<> zJ6{TAv;~UG%uBui!m473oAh7e_%jNiK2JDt&jewE9v=6;)J!sez6jQPE;SpCH?PNL zm#t=7i;=5lGP*I8)k!uct=pA(c@oe5Nna*RGnc6*7njL9Ki8u1Wdqt?*P`a?=cu^& z5j@AAgktP5h=Vpk9K0UNUrs@2wGMoh84x-U9~>SD*_0=!c8aw2mglIj<32(T(&Nnp zgqP~znO=gL#J5`$F1G(0Ls`$dRs}^ktJMrRsWtRqIXX;tkNK;dXB@dYJ--#{`qrOq zTqx;&b&eIX$69pF&~QEDZCuDRD+K1XJmE0vUwnn$Z;Tv2@eJhqQXxN(4Ee4URC->F zz?-@7J(hxii`l4ttpFA75{?~6rK5oKKi$KpHt?}FckZZS?IR4fIXu|@=dHY)Ne|OM zEV-a59lVsd>c}!DU*QGu`^WFljz0U|E}LYK!|5@^;`I2g)ag;{(mQxAISa+CqfoE9 zhmbR=P|>~czLbH=X(oi{TTv^E`0*c)QG4ZU_>8*?&%qBMpAZG#GaC4vN=CrBJoxQP zga7i&2wk}s^FI`MPK-{L`pn!4RsSEbHZsNM?uYl2j-_flT+hoLx6Wj&vNXTYcku0K zZqR`G>fLD$l~t z2{!S5M%w(_**R0XU&`ZTeK&ybwiJAqweWeOfil+Ot~d17+2LPmMLlOJCj3<@LRGjJ19o#Kcny+=d3Pa&({A!z0`_)fhJ)%1rDJ8p)w{&G5>Ywo^Kp7Woh z`k|MIIPnN|&b>s#=uFht=@3w2K-G^%)cwoh=9fK4v$Ni)Gwlx5?fmRt*A|;AGd?`- zlT#%9E*|i zQF&nTceX!zK~pj$D*5duwlB)|LwjnB64k*Q@Vk?MIz<{Zx9h-z05x z=q&;cr@?#01vEN)7yV-kxo=~1k{X+zLf+?3)LwHIKOMj0@iZZM#gn)1SDesjyDl_Y zd}pN>C>m}(js{EiBPguKKRwO9j(_oxczB@pwiu}UO@VJv5PB1a)-50&`oiR{`|)#- z&eiDAlsH=5Y&&Y5&P0_XF{pGt3!U|5ZkWa?ooaR|x};h-zx#Sre`f*n+GP8Qf!Byv zhRq-jIuU&6Vswbq;ef@`@^VS>@Zr%~iEP|K2yJGA@3$G=grUI&gq>PDeCeo7*v$;V8q;DrI_9bQ#>e->anS5lB4B z|7a2_T_(J^^vcbNH`$jj&yDXn8vwL$l42E>06y&89^S<`weU4wm24<*zbs$VaF2h}qQP zdSU*!)izsYwkJ9IuQHzHCv|g~Ifk)J$5+*xP?2!Hnb`mqa~o-M@)L9}Q90=dgw^jM z-w}^S*FNCqT$fmJ=Y6RDyost8-l5`-duVk2HQLh}*!>NCW;6FfXg>wgkz2q|jU+Cg z31LYN_&J$`sqY{^lz>Lrh3=kLEC#jDW^T@S=$)Lbsk`jfMyxl0|LNxtNwdrMN1;ZV z0mI9k{2;y4qjjMf^$V=1TWCXrVk;VySlsjm+ob=KzLn@pm#;^OLn4jsf}a#nRVl|Xm2!egN-f^mS;KDR;Fk~y3+Gp z5t^0iG4dl}li9>6dK`qzYXbP%>rv~02CK>(m3G@LO(qn%MAo}bXgd$m(MKVFqK9vq z9f2iZJT4l4wt@A4XK{Jfzp{eC4C!OS&(=u8O$%{R8+=oZ==0erVf8dUGV{4*<<{U?E{A6ir&+@Mp;*3o zkb@rSXBN|na1zFSD1mxQB$Ts{!GF~aRNwU&jrPZ*HN9{1!^If>MDH=}gHze%QXU!{ zjK#1QC6dNh3n2UTuKS#%Ep~$Ma1#6g!t(*=!H>RyN~BBM5{|SXO#`eFX*aX4UOd)Fiz=;=RqI()N1@+V%iJJMJTN-*fbPUBdN`GfI5Mtp-1s?pd!T z?)?<$DB{iY@`*bq6R+P5`MUdP@TvskT&$l|nT+KKu-vhWB_-e8$;qC=Vob~frQw?r z$ag=1@?sR)>a|?k3?u3!*ieh~jQ=Gq0w0?Zo?%5p6Y*xV(VZK>uBRd0gH{#LPhf<|R zw~KjP(1i0)d3j>MhnrkG;yT`DE4=7%=gmjwyLGPWjT0?(7PK~+(8p$#^tIU}-r*-v!%HefxdX-W`n^Ti>A8-uLM7 zP|vkImWA3!)6wp=0fXNfB|`|GD(_DP|63$s(`E2I2|N2TKmQZ-JBy*kL7W*2AHq6T zyBgut5Xb+bmzl5rWlhoWRb}={JxwM_OX9@M2yzpOfMA*|69i^V#c`Z{+G8e~cz~GBN0B3OD-p zE6KMfUUJ)C=U0CH`0?2v&pz__<%LPOlAQnjsvLbtxBCgG^xG;lT>T6SlI=bkD zDF5lH_I3PAhf=A+-1t&e=pQek^z}u($^Frjbfu5Y3~%C~Jn1R<(G*m&m>}FFj7xRE zFTsJ9rB)2KIX#9MUD9t$$~`)zIk@i&ozl>IB~YF;Lm2-W0S`=QoMMJ7WGv*Z)}U9J zO~UdJXWR|+5=DTM530fZ~82VD+=v#n_S(E^5_#6#UZH=7fd@psK`pLc%j zBk(^YgCCj%Y3)@|_1}iNkp{?^-*D@FP@mQlhLT>qRseo_EIl_7!a5xkAMEfiB0ZmA zgd)WN?=0qXtaZoX**Q)AT&7?-M67P8868dOX!MuU?EzIWUQ2xUIpHU9n;qv-_jnYl zY>z>eJsGHTA|DmjC8E;FTtp=5&^z74jY>C5dnKB<&|Qg8uX#rN?**!zOhVX&G*pfx zK7YL!ia%*B81)3=uP@cGT6GFvR7Qjxjm; zF{Ms^REa}6LFW`(zbb`t)mw;@qaaLw1=SyM?%pBtl`#m~5Dl*-HwZgpp;~kU{;TgI zVD4e?-!Fu6;b~NTsYmTx8)Q#teL6~f{r9I3I?Vqcr?Si=FA;euTA#RLy6UY2jCa}5)mg~lPsCG6PxLS7;QT4_X zD4KSHs>5{Drt4=pr7Rbf^?=@Pv(;UhQ5e8pm*q<_f9VY_TXpuj-&h?UUEY*%L9@2O zYxn}xS#}OHqD$q|9;FM*ALpnU_uTj)J7{8tRh;!8P1bR544Uk_i1r7bV#wJ9$(BrG zc$G1$zIudy9sjkVBrSj7Wk$_TM>U*ha44$wY47G6Y){ZfPx@DDLsh#TRgFf7=dDo2 zJ0aX9oGY+^<(m)AaY@=HJJ3Gffp0SHlF%nKr;nCGHt>o&zsKjE1?nGfLDg#`Sgkel zO=5oNT^uH^Vk%){Bw_PK14P0;>Gv1m{ZLZr(U4O z(YFXcn~REvvf;h?4ZIH*68|%zi_XYRu{jlEa&3Hz8|et%{Q^}^yg|zs#prLeNfC^K>Th<&#j2xq#Ugr`Iu)u`}zj(Z*)rd}zIrKB04rwjn&-g8l}Ff zq)T)jI^2y%jSUCkzw``*iRU04dk=i8MG!0Ygc#C|)|21CcisSg&;|%Y)M<1!XCJ{9yRG(7ow3uog5m)u4f>wU3+9hcP9MfaS?|04ADxm8kKaMwWg3Eq zZNS8Lg?z8`v0Rg77ct>dqIC8B6t9tQiachzoSqY6w0w)B@o0VcEW#IFfU3t_bl#iH zO?i|ps64;c&3_&LogoS$HeY`2v-z2!N&MS7SYUsuo%x zyK9GVi;goERC!^=7(+Qfq^QiJ(HjS9oGU>C)`RJp0WI!XG475*>Noi=_z5xaJ*k6g z@P2n+b>=D5(4mL#D^{OP9Q7^p8796vCK}?5yQt&RgZZ?v+D`bShDIK0?^9VkX37^KR0H^R>@vmyGlgP?8*A?#ZSRR)8vJC3k(4(aLX;76||j=2@m zKF7gNdjij`uOM4|2I7J};OA_H^v7jTZaNG9E6))S84tzjhmak42%k%dsGDxW=yIpP zJPKG|{p3$B1;b5N>&aqGGd{W0tWOp5*=KvCbLih@{rxxgZ;b0R4-w{bu%z4(IM?9t zo|96lI;u5vI900ev)5#6vdrqJ@W&^I_h^?>Xp&M0*4woo>Hc;%;vwrh4~ka5Bjkr8 z@Sl1DAyc-Y;*<@jv*9?t%eQz;`RGzE$hP@TiOvu@?!SySJMJOy$32Kx@(_P!SVO`h z8vWB#?d$lL4yJKhPu+(_kp{0C?Ylx3BcW!1H=4!nG#S*LJt}uk3O$DiZ#*_+&*N!meS2X)T?k(NCM*ILJ?VPWqC# zZRd56etQc1Ji^q)#4p?5b9?=S9L$E|x*6dKR@8cDhYy{T{IS*DZ&><>@btO`;#nhP zXIQSO3F0O##O#8sQV23w8ggnDWV~Vm*Thk9_Lt>6)L>+7fAl`lSu^ON?khfRWPx1>Lz_VK?F?Ci;ZXg45W;VpAoN)Zq3vo&zc~RZ z@m9r#+h~}OhpIQ>@V}l2&z-kWD=rP=%N(+GPFuB&rJAa@<7KBxBMTDIpT8}&-Rtsy`#g2Ju_Y;CsJ zY;AhBR6F2mQQ@f5rTTt*b+#rOw8U+lwi=D^y@O)LVKkw8)bEp1Qg!oXh+}s^7`79N z(c94I;$wuaJdCiV`_Sm(rQD~DbykyM)d6sn2OFzUWZ z+Tr`3@YQ+b>-cXB7O(W}@CSz6GDtd(9?wYy0jlo%AgxMzuEuW=+N^=sbo$Po*Fbq* z2jz}DNCzE4(AGB?n&FWArYlo~5+|+o$^!38285G7oEB@AZ%VXQpZ3b3sIxo={MbZP z*qQ3~?;P;aCGm|cKntf9tt~pPhS>ncjXZ?t3~rAR<{ixH;d_0wOB64i?%a7{X$qvH zPSg7mR`lHtzUMB&g6pKyvmkA>8+_<55Nk~(yoiO@=4^!CCM>^hCEPN@_X=t3vjtE_ z>Y#W@c=^Hx{@xc}%FoUK|7$k!RQfydYgw`b5jFz|M`f&62~j1d934tORx z+*r(dLi^q*M2$EN8YO8^^|=lK&uNWewNtN5?z;bqSylw6TM?d1IGJLBI>Uwl;=2qx zD>#hs*Au4ya2_?DWr6j`WBodrUuY9nyLyiPZHpGN8zy)?H=_D`Exfkff#<@V#Ovon zzHl3SkK97gwYLa3mk6&NPas=<-`z)4XiWDav>U{#-4L+iBs^K4_^!lNo6Q72ITG@1 ziD>Yq0N-mZ(or@i-`{DMv^VKE&x27=ZoE&|LKyndC1d-X57JW?v6`e6WsV9h3an6{ z)53qpdojTU3eo#JohPUWwkol3?xncqIsV>yTOA<_^-llwPJ8v5bWiFPYr%4184vCHn9h0M1Ju}b z9W{5~Lf;azq-$;w*Z$@U^m$v%jd!`kZ|zPGR#QLXmBwTGvn+94s-co+&vg*`9z~Uz z571=nD!0eZ*YS1yH%4&R5g7EwA!*UC-xprG;Q{=6ABD{88}L=8k$(P@IKUZru1=sM z2GSubX)Yf_opU)Dli}dM%_)<3pDu;s&m`16Q-FanCdrNzYu)AVoWa2pZV=YR!+&cU z>VGhT?UO~kEphit?^a~s7>+h@>D>6)kN79^4rabWp_#;Y&)D3(g!uW1kPg@gq5D$s zy|zGTJ)gMf5%3dyu?EO1}x8HK5xa?IrX)IjC zd$U{5_p?|f5g*KGTA)X(+*0(^m?U))3eX|37=v|)BcB)vt8;k2-Dl8s$z-(zT?t_K@qtxa-?yZwwXmI=yvkC} zx{)OM233Gpqc-sQX+OOCE(9+s{^_aqb^J?5NTUvzWcVm+)UgAkQXXxOB;uPwm&Cv4 zb|`x6fs*)(dd^FDPJag3gnLk~d;#fqhoGGM1a%H4q1!_Zr=ETv{J_HqJxf~m1o5l` z8ZEFzA;Zr!2rJ&hW8^7FzduCpy9Yvtd8Fyrg6~7Ttmh8!t=B^I8vs$=4?^Gsh+f3Q zdnnKd`X1ABInmA{p zaua?b93A&pnaI4Hfm1{3h?^Y~o?0*2i=_^rX&K`Vo_dPe@MG~hNPxqxi%k5tW z)%?@MbvHxWcroO&BGKDykqpq=Bpov}Xr5Gr1}P=z=pqhj)1j75OYcEz#f}7b-|9Ze zcJ4}1(I{4vbl7BS|Hnt0_s``n*}!~@WOS*6@BBf>Reh3!mLKTz)HpnbYaG&Ahi{|j zOAXik<$G>;vcY3$qCqnFgGDm6)S+l~JsID{7E3x@eT^UU9KsTVEpT?KPBkk_uNv?$ zgIlh#Rp_uYk(-!o5y$GBd}o)LtIqmE+x6)6>Md7$@kUf%ybevzJi|8{o5#2^r^q}^ zfBak~GVeWxq5aC8l0U3g@9qb#aXxLo2h&uH6a2L8h)27%*Py7`?yH{vI{quew?Y-n zPB(bgZrA_{l@}t8zeP*E5p6Xl)H+g#Hl$TszBZ!r0pclhW8k^`4a6DIkk5XCuwAcE zW6uY8&v^`C;0bund+YAq!B30@KjtLF;Rg`3<1M@v-$jK@k5T{X3;g!csq9y1k+iuP zj~{a#!gQxo^<55OX_{T~N4e9h2l1SWgeBrr;&&$tz|VUGVcr$UR$YaB^9%6P&Vui- z9DKFO5Q4`;2pSJDfO+h(UXgv>UX()nl@LNlf^Re(e9egv+AV@~=z7TKokj2)(#kPr z2=T-z(FWTJxB)-LVbopfCe*Ro0XE7idVJPE~%qN-kAZ9uFHOmZc z&-n0i1DgNkbl1Cg{ZAR!f;1@eu&YS?vm)_O<|S2y`73Me2p~KaqBW4siv;U^$70df ziVH@cFdDl5f9!o{bQD*Y?XFf=Rkw0N5)u+32oPCh5YZ$NOwPdsW571X7;J*UU~FRy zHaTZwY{2B4GbSg2goK20?wo@}n0HR&H*3B1X4ab@-^@2_o-V6a3#q$RRqDI%-shgP z5BHm6k5caK7O&Hwqf;+%9wo;f-?JHoJ`TI0bAeH4^+*HmUDD=ZK4MnvN8MFN(d$^6 zu(;41HZeml2G8H?$(vVA_zj_(9zr={526m`qi2CxXq%}+lLy6U`do+i^ag=*I@`O5 zix%q<`b-biF1inkZlT3B1CEm3zVrCu=7U=8prz%G=&zmTz)|@ouRgc(g|?@jA^zkI zG&%JgLkgWL<160uxfX#dQ{l7x z8RR*)X^x&k^s1+*%kjZQX~Z|_dtYTjwJ3%7;%?%lt047TfS{3^5dHOTME`UQ9Uhlq zwAC$+w!6hCj&c=y6@R96dv{2-V4AtYdxg^x_iec|yt~t)Xy!CPeL+LmnF`g85~z0S z2vd!aHWUH(7|3x ziEr6+$t{d|TOo3edYRt-_6GE zm$EbFoi5Cud@=jw9Ij8|e$BIAyMwsz6Z_6{eos%QRnewci)Lv>sB`=tLYC}9iCweqLl!B&PZez%a9L3Pnxr+XmGX=k|e|s1Im~lx1J@hVLr-v^&^X4dQCH1 z)DxfQDg(yOK>WrtXmR`o>h4X!kQY`(hl}ZmShybTj$gyb7f!FlV-L{jS~kYLG>M-* z*Q>tBxA}gWV^d8_Gpl0fAI0$Nd5WJkrs})2=Jvacmi8wKipOoSS)2FFE*08n2;(bk z0_SoJu{)Jx4K8uG&gnJY;gScxaeHyy1?Qa&{+9|b#!${n<@Jv90pd6AM)gmYqGs#% zP|&~7pkN$+^s-mq)h7f|Rq2CQIsS7-YZ3=8?a>I`9Hx0s)GJDiMjiJxaE=Nu7o8J13U8qYs zx>}JQem6^?UjH1@;$+Axvmk!-7nI|!K{;SQVI%4L&Obm7Z1b*veLznrYb{2|+?!}{ zxCm7?WI&pH3F0Vv?qJfnpPhtyEv*F?OAwrHfOm=xf%(KopRkrE{(Hdc>Fcgab$Zqj z#?bm2;^8JE;t4z1KZ!B19dXaz|5BmgK5cVeyMxy|t&O%gEG>Vx7`w6WC*xo5*Dgh; z3ac=hFqZSD`oDH7IRA(F=Mi1$u)PLDFZQtBZ8mlO#ci+6{+;a2<*HO`f_=i%w{q zT!4^GCn1lS1!?3=s6JVVsBQOdS3N_-&SXUId5VbbgsF$`q1n@1baR-5mV`w$Tn30&${-)ih5uhU7;STj7xJ@a zUd>8h%>GeJU0l2G3g8^ii5iPk^~>*}N*sW?>yM*ba-lHvrCBlHu~AWN-a>RZbQ@zc zoMPOMo6zCv3ygkgRd(HVN|^J~=>LPk7BwZ!F3-!i1g^B$;#O%4wbvMI_4epYT~8Gh zPGX<@K?bu|{bwZ}uW0rS>*zKKJ?%C{51Uodjn>xIudG7CYb#={TJZhhexsbP%AVEi zw?FLBQ$^En_u|7plf9}&$AEi*e7fL!ulIM|7UY1+KA)B2KWF&+1t7840Ps$IbmxJn zcO@HvKsEMf;GDYuJ!##b(Do5q` zM-TQ9ZQXCOC+5yI^l?95LTE~fr$1zGTK^~7*>}RN;{56kT7%HysR_;R7!kK87okhj z5WOi2fithbcUu<1lC6lkO*+$R7TUV>Ld2zP_)pk}2;zj1&rIN6^zuW}%;(H#QD#8T z6urQGiiX|NDMp^nRB#_n#;m4xEh4oBgqE1#|D*uEXC6WNo^WBoCHUXWAnel;pL|Z5 zemz9u!&1GENzW%hiuw@hddo4vP$9LyZ$22aaLHs@T zgd+~rg!$ypPHRo}3*nwa>+JT1o2|BH8|=2m^Gwd5q)e00yVRnn|H6ilr$*Gz(V@M` zB(%vW!>=ZDhm)m+<9{x<*W_5hM{mnjV~O9gcU5P%QD~{rqRxfusIl)BY8`um7+Oyv zR{Vt;8y}a76=XI-A4Ccp9=GmP5yIIEdD`L=zewD0kIu%^)4GwWywv% zAA5+d#X5m`@i4+rj^XzFmkMD3{Vv|yW1h@4r|ebFwMbmIKF;crroD0ba31Rzt4o|@ zb;?N@S|NPZL8wN|M*Tex(do=fBy2r_5l>BCbvIo?qvNTF-F^{abJwE!++}FA>jQP}+G`LWLcGvWXSwZ}+<95WXe?fDTH2S<$s1~Oa2fc#4@juGNB9c(D8*%aqwfpmesd0?4DLJ-{uP88bPj;PpB{=)?z@6f#%Tt zVu;_Ir{glz#|XC_2B;3?6Gm)+IO#m`(2pQ{w};IAdFrpnRC9%DNS@Oxc-aF_-zKTi zM}(mtLph2xZm*x9oOTAPgZZT2%@CiPq1u%RIgPH#X`pL2W0={c9By_idzx&DB&$_1 z`Hf5ciM3o!yfXOj9vb1x${p1=*{unLpIx}e(4RV8{{vcG|J^2Y=O4`Ws6IC|LdVNy z_$}B6pC2xu)`J36VV-NWpvNn_Vwl6F?DC>S*l0C1K4{PkcT&NT~ZG_lr1C&j^gWPi~V$Y;hOcUesxh=2B9 z?XuP5HDkQPEpeS{f4569=CxZI>T)Ru+MQnAN-aXoOB$$#PJ{Q@xrkbN7+p_1L9Z)? zg8!mJ2wrgn)wW(ivjgYQEv-NZ|K)d7Uv~iE-~L38+Yt4~O;o+1!SGjZX|=;qxBW>YdSp9=A@sX?vzMaNs%V^{NAprG>St-e=Q73NRP8XE+Z@zr2c62x z9>1WlAYhTj95(*oR>h|$&MPAtHU2+7-(fLv@b5GUQiGXL`G@_JW?ALC;7+iUoJvtq(Mt+M*OU8wQh zN_0Jzfe&+B(m0y8k&p6GwOEHL8Vh3VCWPde;CCnu@{h?-|DFkN!f|o_ed1Vzi9Pm0 z4jBm9ryFGd4t45)85A<=FW{9al-J&T7KoL=1XZ;aU~ zZnaulForVsWG~TnyuVLJ%~xgwXO-lVjCC!DZ?KHG3G9aFKW8h0Os-)|Qm%6>U$5AVj5mB3;LjL#yd`L$}EK5hV&86^J zm&74~9%j7%7;+7}sT+$4u%XgXE5zD?jbM3CcuMExruA%1t zf9$MKk2X|@pF7+>@sCmwov%YcrU_973;Z9H!S}ZZ5C^V@a?CEm!>bTy-|^ss^a(vi z&Vv*>$Ah7&pm7MFc@;I*KSJB<21IYqfIR&q#J-y$cKaF1A@us?cOf4s^YBplHyu>l z2$Rp1BGhC-*u89w*H}f?@SH=*F^t4=vk>`=FgDi??_4L;Sx$IozVkbc(pgbcYevmH zBfO^^N7TJCw0&(C>XaK$-A-KEVMI%Z9u4T{AvtFBEjBBbI2_eDUfM&e7uGs$4fdM! zNz6lg5&ukh>qhKrD{9eEpSXBKtqzS-a}d5|9|9Nr4Atas;r+=Hs6YOm@N^3TXB|b< z_qR}c^CQIV{EPTtI=Y{Eg0UF}Wzr+9AWl5`w=eYf5WDPx-~0z?QfLJ4-Lc2@T9>WC zA0|VOomO*ujxREP^7_FzHpJ%g8t!(9oQu`Ez>2C@H3(gP6EW+aq3YU9sHPr-+;}*o zE?+_#e-Ps6y%5K(LY?onpv}%F@SU;|u{$mx?C4WOUdlpT%1dKTO@2_z@_9x=|d|n(&-eR{l=Xf*M#%{J-n-Tx-eyF%`z!sA+ z;rnt&t;^ws6+JRL<|IN?2LZL)J!_M%n68T>|!z#!B^uhV{lJqWrE--Nbqz;Qv z_1C9pTxfy!b0@?b#04J}d-OefK-MP?)`T=yw;Oh$#qJ_>Jzj)1=Z(bso}kLHGSnn& zipw^kflUwIBN|j<_v)0c!FYpP`Xr}ZHKMq}Yqa*2a+0k={fwL680w$z5q^@cpG!E}bvu+JZ$jB%JK^YeQ2CAV z9qNB4io!QwRdO);#E}{!`Q!r{iAw$eE7yLsmew@DQY73*rCiZq%f|UwflL=w-GlK6Sage=9R~;kwT~22(e# zt^fY-y*TE@{550f@^VKk_qpe_hA^}RV=4DfW{ll#v$R=LR#cO{OnGhQ`l{bFhR&hU z|2{@WMn@yQT}z-c>%MaQCk>ytR#1O&4RYcSsJ7!NVhAt9`wqza%m~Y|qJzyOG|twc z#y@c>nki;nxZgnnC=`sz-|w4LW9NF}B#L{Ko34 z^0Drfs+++fbTit8Ax@XF)iXQlJ#`@H2;uGn3%Eb-=n9tKIH=KC;2D*x`9?HH#UX%k;r3m)w!wgKIvy?x-Dc*q((Jp$+lLwzj~lKc1VM^6UJXewe9y2 zFylM;eKa3cZsgE?(;@U)KHf{#38xARC*4R-U3NOZ;G>OpTNC!zW3O(`S>l`r=E>|$ z$gx_EK{JkWJbHYETb}mD<;%GHRjJmG`#W=v*qQA7kH5e1*jHBl+xzbvt7`TB2*lQ@ z%yX(7|KK4A|GFv%#I!*0oMfol{{*?+*N8ci59vB#=n;ph#~eFa zYOEOIa4D;i{txH6^c6Xt-Vuy5tS5Q@AnZvg)SDi_`<4mnJ61&Hl6KBFz z^POnxG722e?M%2Coa;c1Vk^39t-^chRw4eS7K7X_FZKrDJp6hZ4T8=+N7%(QusW&kL*nJT(w+rZ=nh|*_7wWm!Y28^*m^T4(=xE3Zi_z~|iNM^C za}F3kyE&|i7R0OLbL|K|r-A?S%aHoA2h9XX%_c(K^INEgZ-U%s6@7m_#5&_4)ffo5 z&IEMap9-J8gstPwKt1#*f)^Y{lLHsgC8t#AYNfT8_&IwV)+A2OJ!7wAzgT!J^Z5_^ zb^5+so6mkF%>UWDWQfzL98K#B*Tm2Ec$B)lXPKS;Q?xF*Rf-1v>~_WMSGIsJbwwU5 zo%P#ZapXr+72%PQ|1QJy_Vz}{egjC;SMJSMj(^-x`vefDe1wDr+u;*b6~XO3LhOzL z$URp=Z2BeSZePOxf)>h4grB>ukhc;q*^&ys%Y~5U{|R~41%&UywrhnPXZV%0=U+MkHogQ2nVH!Kp^bGmk?>+PjCt zqF_8>F33EsEAhK}S_5%FBWmkOH2MF9-iVlQl zpTBndO(}P)TR$#?G>WdL_sS^AaUE8uS{V7W!Bf6uaZ= zx@UlNL<8kR8&uhL$SDR7Cru!|-syz}y-REg-{TsOABlI06ZK2X7^*4v>SD79HH+=& zOpk3ZnNjy-0qVUd^=N(eWKFQ?;C+<1;ZKC^UtC7RQWKa1a-KNfqfd#0O(z_k{H9#R z9`Q-99g2opTBFX=`R=)oHrMiybTwZH{P7S%&*dXJm+Jsb2+z@>+5IfE&D0|HQ3*O2 zj6yuEW7Q01sLmHcoO}en8`6o(o`;;Y1#;K~h;g$}bJcx}a=AqI%WslzMs?B;vB@U* z{d|dZ_$&l{u^o+fT}PkWT4BH=v!ca*;>ABDLmd7){6_o=b-P*cYyT~xKHCdrBaXZ7 zCoZ}T0beYI?~J9WbLbXY&>B)#V?ec1J*pLJz<7BjJAEPN$MTxR`;H$w%GLd~R>iOa zi&xuw8R%YM5IB!`n%?a_ve2oVoNt$VKhX*GZ)9Mw)8*CvS~4cv%H<);77@k#e{1uI zs^L(pRR0CDs&f4QH2k9Kqv>VhOoWks^U~ox{Sm4xd*SH^q#RG$ywe(pqgTE2;ymH- z)Rn8&r67Rt&wGCc@u0(yf4qg@JA|R@?~u-;Ih6DRe7?JcdIfqg&-VAv|4&+TG5FhaVy#wN7J0c4#h$yh3 zb+!flQ=N*|C06*PI^grrg4$^oe5fy%dXNroLRde>>K41+)(cU4QV{iAkMMjuY7(9W z(e;YooTKwO0jcp!_%3;g#0rZ*{L^nC{eI?!jHMqEevW@zE^&@oGrIvH4~>X@phwaR zo6zK3IwG$YAmBnVVhZ2&c#h07qJz~Sv?c9dtH^|~7wnH>MOC^M_5L)dYV}0ZG96~T za`}EyWbU)Yf=|1=k*$wZZ+n}s5>zy_jx)-Ycqdhvl`rfN(`mhX5 z=<}c^{EJ8}0c(=;`PpA^{lN_S`*Qzh;+p}@AEzNHMJKd-kd5vs8lfxckPkA<$_~WW zhutq!)ZMTjk=rkWwfrQfTmCFZs|pAX_z!*7xo)X)RE~e_5TI_o9R6zwFQyS5zIPeQ z5qF{b;tA9r9Y)}ihmhta!+TRY)F<;iecr{>grgg^@H>|apC@|wUCf35#bQ(^&gpZ# z0Lqc1?~;Ck@A?ObP1B>rYb)BmaS9w4eBWVHEUj=v^WG}wP=5MCFL$|0`tBsnQQ}P! zy{D9FfPY2_S`y#u`Nrw-WM&*;eal!nmcH&(ZV^IKN!zcNx3(?|k z8CsFPh&xw;##glHo@x~8?fDDs55GXWL(dU7dOwtnSHLT7HN+mr=x=`>Vslz^+x!A~ z^e$BUr37@n*6q0)r&B6?3;3__K~w_ zcRmemXiZMaH3{u+amu)$EaOLh$<@l!#?`8|2 zUZR2A^(<-kZIA|@LEH%)dS1yDn(oPf@2uPK-I9)=$E39n(Q(uP)dnkke@#U-s|f+= z2BZ~IZkK5xW8U{P0Djg zwSFr?YvQ$jHwz)B5#J)78UBpsu1QC_-Grb!#pp&jGJ$aJ@4g-0-HB($6j&i2(?a@| z@IQJnVP|KEs-{rJE`;ClJoMptNx!!>YvOhRc=;>3;xvw+d z^{)u1OV=dba?&*rc1|R{IyVcdKMN5>I9a>Qia0vAst+viO{R0aRE#b+wdj^@5*ll) zh)uU6QD;SatySo(u?u5zUCQ=_@Al#1i>wH}Yen!A2fT05J=P7@kJcUlD>Af~yK&{iy5pW`hxIba&A9?6(vI;w`=61WSrcPgz&KN`YpM95G z*o=tSeF+KsZliss1zqy&Lg!mLbibn)S{}QFzBgY8UFdT$!s1lUdgbz;R$^2IhX?<& zr%>hi|9q%?!w}egE~2^*hksOc$Z8*`eFG6uCjm7U-G|g@F{C!%pvvA%sIQknJWD)u z2kH6GP9n^1Lb%E7$=_jr_F6gv{D`lrkI+H58cF;p&S^kBmkzz(x)t0no@0HS*WF5E zLc--2m{e$&8lE*FYDXdJKG#5Xwv;rf1tAY~@Hv$YpZi9ro{?UDV)OLc{M+-)D&625bM zfcJnIuNd!@SLpqQ~gG?WuFAaBa%up{7s1L`XrQzl-#TLWoP5yV;9 zgrmgch987{Sd02D1K0?Pe!YvHWrkURHa=vod$ufn1 zuLDr_yXxs-Ep;X>-+DEC=z7$nk0P8t69IS45U(0hgVq%8ue9A}ZcExdXt3Mq#d)|* zEILFIkN3ZriB^}g(XqgcHt9C>dSnm=y>KbG@5hIRa;aB=Rng;ij=*)nZ9f=Z$w4c} zf6Jj%dZFnj``|zEHt90bX>LV7-2!s( zDEK`#dpwEiRM2_Y%DfS z3*Yf(-+8wX_`^*MFL#NYmwvLiaQt3_q4$p!&T8BXX((andlrMx@MVE#-;Z%M{PJ^p z-FgHs`~|As6CpKCgxqfie81R=>KkvP`(I_k$eX!}F;_CYTK{+u-G9C+{F1DTj`<-O z%E7lFCGLdy-XD;M9Ye^Bs|cKY7C~!rQJ>bK5wG1M_gG?ofJv_%s;cLGBJX9x z?^Hfo78=nlRVO55+0gd69X+2~gl3QI=#gs?;*XS}>W0VYd@2>+Jt%@XNPCI#)&-JrB&62E46Mbfrh{2TrK=TcJ9nMa@S#Bs?xf#F}jMO|>bS zm0I9Uc;o-biV)Jvs`bUBtJ9%6Vj)dxf$F*ufyrhxB8(aM4o7|3mYW6TE#jCpz99^4 z1vzXYVQK+XoAcnEp+yAo%Rr;egQ4C<4k(}7AdOgwB!^kS`!`$%Ag2(nZK3D%NQ2n& zE}kL-y+lrK&#UfToaQ2SbV;L)?A3 zC-+=_|7XHl!l5|_;lJ`8{4X2ed%6Vve_7yjldv?|2#Iz5BLm@PCZwfLAb$OXG`${y zsb=&c9naoRtKIf`90Oq<%6nd%%fq#$3tzdym_KtJB%Fv zm%G(-UpWJRwVFB})s&9-Q?Gk}gTvNj{%fbF2Pemv`CudD{J`uP+5=k7=KEf3J-j})}no`DW~ve9INd_T}Qo@X-K+Z6jr2S4Ke88JIV#6LWB5nZ zN8q4y=zKtj#=G(nIQ1xLxpjo0Wr%)iM`ES}BOGq=^VcrVemVCOX1|PD7K3LWxQdDR zr;ae`31RBCCrJ3aXXjvgUPIFV(n-cE!q=Zlpgw0nP2#NqOLH*br9+Wqw<-LSZ3uhe zfZu)Mm)kTRoh!9i3~A&VG$4#_Zh03Q>|inooD=^(@vuNTC%M%+$i7LCqP~E1!U*L( z6XZ;KZ;cJXF5-d?3j!>}i&ORRp7Jd|eB)HHrfo?aTHZ#u+T}6Cw)Y|SNheO2|E>?{ z4lTqf=ONbp2y$c+1l7501V1J{U#vwxms7#} zCR~HF-D+vG+hXd(dogRBw)*Sswuan4Zn?`*V^M`IjQyiFIIT@qJMHzj7Lxbv=xEQm z=j{m~T#@){p1Vbn_!LTmKMUj}~HLx=R{)rBo5~`8aC*i&48LB_hpyst4RJmA+1g!;42t#X} zDnaCuvyg|cMEK%s@EiLLLT0Z*wMAPn>daHcpwXi$0km@bw;kT$J>lK!2!=kc@S3E1 zB~7rorI@u(5ON_IiEo`kYl9iBGu@c(EcfBs5{{>_*D&)K_P1jURizTY+L8vJOIc`5 znwj(0Ie#TMi*RwD9rEvlS;wr9H@zz8AKD?!$$95j zKWr_c4-}*6eLI>Kn9xRVLL__FU8gzcFnD;WM7S>p5?<9>2;~*h|HSXaWYWu*bspdP zV7nRqTEfty8R%*-2pn(Z*c^L?%Ihsq_Ph<{m`sQtr$GGjB2?=hLY#90$`5uyYX2>1 z_s<};n*+JcXOI&YKx+Isq*_x6TmQ}pP}hN|iiar2K@NEjQq7^nNk>3x^A*J2%b=X_ zE0j|YL;CRsRDY&Heefkzr?QB179r?GKB{SSs9vf;g2{mQoel;2N3}k$MaTPA%r&`! z_LdoYpUKOgdNw!j)5H0ip(pc-ChjZM_TFkXHanmx>vuLk?~`L?C8Pc@7?KD_+p#w> z*F*CD(V}vD*hGh0ZeuW^>Kz*fTU=foC-|1Q>_>0PRU8utyF{4PtQ%B6o<_vUbkscY z7=8=3LjCCy_|DjZz}W}jGkF!_H{U}I!nJzqGw?xPxj4O~+-Lah5{2)?d5{N8N5l^) z@c-&5#H1tesyUaibT*`jS&-_@MW2^eMPHp&5wRx)@`AmdwIt}Y2KAm>5qMsM8rL;o z|5N!r_HFnG0iW)G&*+~J{P`Nh{h5ruw{wIc`;Q5s5w-r=)1-1#j(>Nk!$%_WgB=)t z+~CzUt6b=Bc6klbIK86p<)ij1Gq`?cWQAKC_1Y~Guc^jyJN6dgeIE9%iziGAd7**d zxrgZe#;xGzv%ebeUwA(z4BbtbwapBX>z{UOq58cT@{bv)cf*8;TNX%Xh`-(?{d~dT z$(ND4&PSCEPY`#?hURAqP@6C@=AIG$d-9>$YlP1s;xWX3gK197A%t;B=OErRLcC2} z^p*+Y{A?&M5C=8bQI)VZ=*$x=tgwW#XT_K|Zi#(EIX*MjSKxF=oq~Uty>YHFxY{(<0!28PsXm!j? z{P78`JzT5t4ODIBBXZ^$4AwinYF^HO&+7Z|U3UxK%kRKCE@T%|kY zhykeaMps0zFMn-*X;Ruy1<~|%HAH83bR2$P zo<;o&4g`ID3F^t4p`L#kzB^u^&c#AVpAlZpBhK>`&DRNcpiI~VpILVhRc3{HM;283 zHIPs0;GbzleZqg<)8cx3*2koUn{q6%pk6>cx~{Os$tE9w$P zvu9M5JPYFO#BpD_6s-!%Jf0)$ug`h3?8)5JrG@X2E2wg}7+kN^D5VSmq@CqH#J`73 zhCFaC)Kj-XHRB+>XCFh|yZNYf?HSawHy~g>_c9=?o&Gb#8EX)G&ww6fW?@39OPXzU z1k8Hn^dD_?iSgHS5w`U#qIcaz!!s`tb@&AWc4b2zw;EE1FNm{$3^}+p)OAOp)o;%* z^v`U?lBdRq#538L;db~gtT0!Zl~LvsTqWe6Jyj}4<@h&;+BX#H#-yEPmB*Jk;EoHC z&)w+duq&7+g=~;2PjJ*hhI(_`w<=sN_zu3FZs3@c##q9FEO zf+Z%o*M>2g7>$}6O=5{%?A>S*NNgAE*rFyz5mB*=iUq|6Dj-~dm>?dmBK}HvdaMMpUrM0P(?Xq1c)Bpt z;|~y$SBY*eBiF-d=3+8+2wGbJK9abv&vZx|&4ds^*x6oCmiluoE~dX0CwWdkf0NxW9)$unT}o>)FY;1eA>R#c*WNhQKq-fn&s zgtO0)P_Dz6I@0vIYOuYGjV@b@Y5%C<^zQ$>kaT-#<2us&iz%ai+^mMrmK@@t;~|Wg z41V-X@E;PV{POS6Y`K8ePpZ-EQ7JT=_M-WbGibDjH2A!2P;NPoc*C0-01WTh`uP>} zV!dAt)oS9F`|{E5*nPxqyMXv}HIPr;3EAK!;M+_ktX@MH+6lo)n-IJ1EQTMhltfMc z1u;8LVAe~kdf^Lez|=eCq9!olkDe;^Q6K*{yo00R(|(ZWYv#=mmU0=94;*Mqde^^< zwD+lM^r5-h(`Dw=Pi+X&+0emdM0?^0L%x`BD z>E;BQ-;JIUCnBB_#C$~NlUDzHH~0yJQE|&5jb2V%ZY+ezBnZ71K|1yTeCA{!ddqEu zttN~ey#YeMDTqwJjqt4nq!oVz-(@qT!$~WDM*4at;qljZ;FVd4CN?Ab)j7FO*}d~R zx7gWi;JP}DT(guctjpJi?a><&hg8@kvL%EQ$qyhsZTIAlGGAu#kp&{*r#z>Sbo)W- z3vsbdlZXSKL!-MoL_O3)&G_n9ry%s&MDzX&@WG29giiMKU(^hP&@c&nG;z|Qn+Zd6 z;j?rn_@w!ef0qNlhozpH^x-cI9>365ubpT~t<`G>TDo-DX*Ts@zVZ|69P&wahpd18 zbB=kIL|cteKO#+TB7JYvVe|{9!0NX}n%{V>hS^QfXl)2BGa#<891*vOSD(2@Ytn7_ z=RZR)n}LfZ>~3S$g5@MI3}rPySk4slWM;VzJqbr+tBmkJMLd39I`w%LVdy0ApUee6 zW(I`uiy@!A8H(?ZBbHvH$I~iwFRDUlb^+x3?jo{~*4a9jl+{XM-UE|~A9s9agfC&M zJoPR#yBBHzFXj3i4%Fz)wCy*q23IG95y@xsb8FMRg+S1p=}ORrcx`>C?+*C7ld3~4orF#b#MJ?252 zdJev6&!N~+27bm(NZxCJr}T4zPm*R_ay?czGs)p8j|-5_=b&-OCoii`11m5%$1t+qi2 zhaN%Y>^#2`2^KAeRMbimNv|_sso+X0l+SFW+btf9Z+=k=?~E(NKg%GdT_;Zc1U`@T z&=l$rPtRp{@|jLxb@JHR{6D>-n734GgAR)CuF^Pu2kH3LP_Nnx<&5P}FWm$cHOjdgE*T3EVqjJfU@K(XR>+nmYNcu^nONjHjgx4 zjRo@JTKH@22sNA0%wa$@;c8^H9o_9_Zg81h!uIOe`Aw+aiU8uSZ?UswdVMp5#uJIleGH+|XQbCxLFkhL^^9XkAg(ho`zfdBzXGyJhoPKK zdVVkS zTBxo+r_Vwa8tY78_i$P6Df83osWotlX@95n>?G8`K814IRRnLz!h87!NxvILPP6hR zqBdTEV(2V1U3LoUE(;+9PKVfT8)P)5p?}Ll2l{+`Lppv~ex>C7E5%$;MED;#OX{OO z{&Pq;Dg53Z@w>-7xH@0~R12~Z?a)DEv%s5qxZk(J`@Rjb3kEbSvO-qKeBB*TS2^HY zUW-uXfuXmvJu%rNgG*!{5$s%~ztbX#sIVZMxNNl6fY6+B1Ri+|W$GEy<69wZG825* zR0zzAV_X`L|XnF;q5gOWJPB98d$$A zh#<_3ptV4CuLj~O;d`sH(Cq!nPN7Iwn;h&X@kSaYwUl6ai6Mnv+MmVY=3}t(w175o% zn`2x9LckWN?#@fhLjl}e~@l|X**Jc4f)A<=D@F#gH%^O--^KXH_Kys-OA z9nHj9cRz-7;tF{EbP@jNiqTGMLP8yDvi!h5zsgu8;coV}sS3Y1DtJ2RHw3D8rjW zz2F-9)tV)3U$Oh1Hi#3l5cJ3f#jjQH-Bkp6MkT~Niw8@is;y{9I22A?mDPt_>UM<8 za5`0tR}HUqNP9a>T(?)XT&z(CpLEj7bAN&Fr4pzz3u(S>ARHwW|@pTSavfCWE&1&t?<7g=+JKSCk9~uy>Gom5km9NtbuM)fGKB!n^gK)e8 z{JfKd;~C%+Q^9xr?u|!gmt}9b>Bz$nllCHX=|%Lr?ckzU+<*`~g|z*02>mvLAGC(v z3+eoKzk%Y*6g1Ac>%l*E?i1iLzu}>^R!{S%*KR?4lwldmeUI1cAfDGEn0c@kYSG24 zkBE{IVWh8q2lkpuTK? z;?P5cTq#E1!W!=V8lxo9V316yb1K<=u`$GJN4cCl`#UW6A!7Gc$oejTCiNEL^Gm_< zLfhw8AaLbA_)JTIYVHw)u00P;@&PEuEQi;K_3%#Gfanz`AoTu?)}|cdq=f&PnNWOi z9bs!9!f*KZztc(eQ6GP%U>84{w@dKUSNi=AIQR{ijh=ZXFpr<8dwR4p>OFO8TNm3A z_~Ts!?tTuhLp6|Hvm>1Nsr(x8IHLj6U%6Dor_`+O9J?pO>L<0->A^gXBS_0@&OZbH z*ENuiN`-9q9Z1I?g|y8)!cCgz`^pgVBRw|!XTmF*Q&Vn2w!RbrzgDB`ty;ug)x&G$ zRfsDtLbmlTgyf5menk9mS*|CalifiVca}lSs6e>I;K?T-Z17^|#4ImpMxjgfh0ZO1 zM`x2HkY;9gR+)|$nJ2&*EBL#1h)1-LPCh``O&WgCO6p4*>GdVx-=0FcKG~B$FAm&* zAmUQ3j#Z*xnS~3OL!3HdA^46zLE3sTHNxCJ^!$(KL6dVIEnRv<5-(_QOq_iGGf2;xAw6Y8aG4p*N3`jU65_hwdi?U_)3Oji{Bv-gnHzA~ zz{$tWM$5fdNhdocoeAssk+X=G-iGQ#A>{k+!)yHs$QIKYv@RXWgO{K=k&D(9H6E{3 zcGq(SjSKUEp7qM*=c!9VILdqpT3Gau|6Bsa1?KJg5WQ;*o?3dIdUkq4|3g)kA7tqC z1Gm~N32dEYb>FAIaC&#XsYTxsJ=dp9$Hm+$M|Y=@Yk#=_%F*MX_;?}YpYNk_yMU17 zY=q1>jM$C2Xp(#!Ve@vtXZmUIolb)9d=AovX=o7nBduKJDVwx{g4ubE!ny`{Ie9u%!|B^+Ra|w!h z`QSgj0O^NkJm>D-Tgx!SRx252cZ)+RZ4&>p#5I?(^Z3iel?ZP?A`Bk26=G@uVJPvZ zE!7Y=>7XjNqRlHilK$aUzs_ZkT4Ztt_q^i3h-ycJkegMAaU0>MC;ZGNp1sN9@$Q$N zw?j@`)GLK>dBHK_mWw>OOMLVv)W%R70lwK72>lmE3)A8;22%i1#uqjjywV<+-!^YhTp4l)YZsIOR1Xgrg=185Rh? zTA_Jr_0+rTNZehqG>zRXd@WzYdB;Yav^>9OC>fP#?OD7L_{meqrUt*0}|CUt*)v7R`KKSsobk zHtF!v%0=j`hS7FBaTelT-L$$??+X z6E|6`ZAU-RN+Z(F!TaN-2)kK?*y1My8ZWtu zvA0dqf%$r_SE-Q`haIK0A`@c&oe<;KKxjv;!xDIDBL0AxQ6Kg3--jskLa)U;x%H)% z#`|mZL$+FM?WetRdQY^!kaZzl++xKgs8*atlY`~xW-)ScH0K#tW%`cQ3TOOk-YbXS z7@C(IUpqLaTYal-kew)k*TLs#Fk&BZto4w-vkTI2;%yBHBf4&fbo5#9GwwjSp%~%+ z%ieiMMRm1n{F&jjnW2LS5>T=C*kU))SO~_JSYnU8ca5<|V~f2d#u_yml^7E&h$ZM} zNmN9XqSBGh^fMh$bML#4-~H?UnY&ijcNcrDv&IF;Idho(?B8?tTOQcaA=i%ZGX)6R zbqC=O${?L7B%gf@Vyp>bq6tBFOVKp70=~5pX;mK zb%tbAs-p{Cs_rI>DvUh6_{dJ$(sy6)Aap`;h2kv-qIRHGa&F7j+T#DT=E^=3ipzX;OwBgC~u;BOkB$+SXu zBO9%&S-sFI4Xdfj^s^)Jvi7nO{2kKq6EcKt26!jiP%qztzEuu&%L*I3Pn0ONUiq*u z!L{5*IuwVFPzr*4no{~4c^zwl^U(A4)T^NSKWh7TZesaM@yFL#A=wfwOTRS?%}t)Z4Hi@^_@?Y zmUlmuk=*>&)6|teBpKQr$gsbAHMd~F#lq5wtIAwKtzt6}b^R&2zbIF{OJ`aa8s(Ls z*2aDC9yu49(cdUJonfo4L;CEXvL~pcHJa599qaJ$eacKK-O}@jNUT8rET?K@lB}-x z#TDqfPJ-I2rayem_|F|W-#`SD?~b`^RjqP*f>*qD2e7>Pm`tat!;hJ0A6JAPcWkUD zoDl7HsQcON>LIert9fpjQYWNEUIk{oa%ubjRiz3i?yF^&;hRzpj+lfSNArF3Y4AhO zgKxhNLhY}>hkgOCDAIt>|Dd^_gn&cE;AgRV(aVTYc0;o#1^f*I_eO4-b%#GX%e#9EOzjPlbeGReyNC?9xfS*BY)Tgu_yuTd$0OI5=_tDB|0qaf2 zVmn!lrypcnw^h~dAoh1&=dgxu%1ZaYl9N3-E<0=3`DX=#j_1fdHav6J+5XZQwd}sZ z`|Ib{TH8I22J;-UwngkM^vuwM{T=$ga;e*76e4i(N@&KcgfwwKg4ZP=a4oGXgJwaP zvIE)`htcd#DF#{{>hNE#Bc{-*o?@>OKfYsB)tMX%srO3gTJ`x~&+BVO&G=6nA&uIi zbzB8D*x9o)x8GP}CEw`GOLV+ejBdBg_~?;aHO*8l_9%0pJI((gPPbP}qX9vr0gdz~ zwrAqU>a9gpTM*(Vt)j1UGxiZH5z7tx4*YoXJ7?U4FoPIyW)k>* z$HDhF1mVjpXik%+UN@89B_7SOL0d@v`wyp54}RpEDvrhOM4M%G<3bDGBW(@Ial!Yg zj4stS)zCL@YZ>>bl2xomG<#mkdV;Vxa~8*1*G1Q7AqFiWCe0`P%yL1@c0oh08u}f= z4bsA&%Sp$Rz)imZ{>wWMkL5y&FF?!3B}zZ3DB{Q9Ck9B<=)LsY32qRr4+~QvEd3L$ zWutO0SpMb*9$BURMJASJd9HTUEw-Vv+obAblF{E~SNAhI)cyyvzz;eNuLjF$T_H{n zTLZ~=1Vrx`@KS5=nr3t~f>>uDvF{XcjY*q2Ed@7xCxls>p;^I-4@^i=k`6OlU zz0|ZFCko{c=02^|uKDAJX7+=}{OI%N)F+FLy$;&swhP@(@3CeFA5&pdv;HleWD`2w z&xh~SbwRsg^Dh=WeI}|GgDHDNeB30&Jg~#jiHW zlo4>L9Q?$K;2JK07|imZWOb?Rr}S+Pj<>`Cp{FBNM^3IRw8CPAPS#eb+uB z4J(7N%?v)#j!ty0kE`A4o)(KLBC!Ag=kwrywh-LZYjhtrfN%FTgow#>Od;kR0U?rD zRM#D1!{N|;vJQ>b-9(2=FCfh#o}YUK{Jb0BChUWDZ36rbKSG^fpP|;(T<9(qqjs_h zzPDMAyr&3=PeX&$A`Gtbs9B9>R!<<-U>y9j-Z12wM@7L4?v_bkq!_%9mzcZ#s5kZ6 zlv5hAwoo7Rd2${%Gs7%wsjx*JmTet&S2~(Zd2N?^n+>Xlh2`jCHlUx`rf&Ru8g$FI zlAhD`&t4DjL-*0T*nqwz1{JGu676!R>p!5+L!ucUmdL7QdZ+)KhYsmfuC;GM{>#}L zGM%A*+4 zi>@K)cs4OE>A=|Qq@l6k-zUG{Yp)V-#7#U3-OkJKO)-!MCRY1b1^8;%pWt%l6@Y zjilK{^u6D$X!cV!bS>vWjGO_!{U-AF=@54nLPIPao?U{_$At*E_?UF&A;i5;A#8pM z-`E_bRvb6|H}Ji;gKItyT(iYWZ4>dG82Aid4c*{%Xt?Jl#6brjbl(bY{9$mP?SU|J zAAGl8NApK4zsQ2_4vVUz-Gna0h*1wq5OU!O#<)EE98aZox~*DV=&JPIT;+~jSM3h% zcrpRqP9$K?bCdYtuPK=MxLi0QTRUz{D+!#DR>C*gdKshcl&beyElt^;{r|-4vv?`i z<2r_zx?PD8!Ewp(J$N1gM=v1w%sm8NEkhT#SvAD%@rv=d)bHgO5S3y@+ftjduQcG7 z2dc2~CvY+C<@mVV(s7HD?7F6_$$N<6KRpF%M$P!!qjppz7U<2oRisbMBR8&)A#KW0 z7*Pltr__1pqLxFmI1##26_DcX5HFGEze`6PY1bhG#N(u;@p`bj&8#1BoqQXl@6u_` zZ-Edqmo$`o=(OYTk4=MrLN>%zsc$v(gKxpNT@0boX!_Y*&>qh~a0c;hCiCzX;!)zc zR0qO{{|5h8wVLHJGVKc_E{tIPpR5M7cN-y*hV!#;Auyiwig8;UX>Xhf!X>)C^QF-2 z&xBu&74>W;v>^>{M+bXuI`OY6q0ei#I)Xg9_FO5%_1O?Mlz~fdDy->eb|BbdM;)t- z#a(6t?74Hqqg;rqx5NKhI)dmuHb^Z;M4k;D9aaqUcsQ2N z#`f=rzN+*Z;Buw2eUl66H`d$H`nH}2`CnnX5&WD&NXahp zuQsJmlO~Bg{f;DX3l9;K5^K%+5xU>95m`_H{{s&oj3C|UzaQMtBM`dGQ))YDccmln z5$U6z*w18#?@NbLzo^YC8$SQ5n&pItvG}1dSw?_tM^mQ(o$N+pqFahii)#}Ra3~3y zH8;ukCW2qXYB1+PO2~&ux+>i!#=T|&_s|Kye1}qdh1KZnOFG)hL429z26vD2lNhs> zLq@1XzfiGwe-`ugzT2XbE|fyJ zUxsiKv8#jC8I%$D(u(GEt*l1VJ12j~@U(LEyi%8LZjoCXy5t&!4)Y;|kAQB#N`$Wb z9^%l=@cESZy~j>OY&eaGT^FHU^b<5I&%y79G}KR((X!l*4#dXo>1e4pKw7v9y_0fq z-dH~3MqbXc0}e;qVd-XdOo~ah#9{LpS!(neUSw8}O15|nePUNHDz@l0mFvS6JplFxb3KC=ys7kII{F#0Xp5p!C5}pWE*F9173w}ILosik|wjPhNdAQC8E~DkNy_kDCjgL>b^TCew8?+xCy|40(Z1zuo>}y8N z_&*z7Y7X^hZbN^kUCloG?^ntyY3!fGp)(=+b%R)IG(_Ki5CaB7Xuk}?iZp1h*`fQ> z0q(X<=>yDvSq^bqv9gcexyq^vt#Cq@OuFaEQSlTMS* zA43{D`53riD);df3Sn`8Bl~=p-hlGMOep6agSh1v(&;y#NxuozcZ8?Ms0Q3&KBG2x z7s`kryzcKZb3GXr*^THV*P{nkb^|jS=EDLFo$?o$X zd3xpWE0vs2DqZKF=E1Xf8rp9B2|~hhc#hr*?*~Q@|$h2iPLh7 z%5E2JNHIFqJIto8BhOcGGxLnXiSo(`YYf(~@y}}%tRHEZ!>(X+4D2zRY8T6DVm(|f zZajzQ$pUmNG9j*_4#Q=Kf^kna!^Uz(+5E-AMp>6)a;Q7K_bx))#~>&q3@TA@&weDO zpWxKmX8-!;^~YM;=p=aWe(COq8BID&)onXO%|P&~SmL6i==mVh^&f(dmELIcfc8hi zf$uBanaTXmRe<{|JO z?t%KJJVX#Shvu3{3x5I4m`(6mnN2)*DukpIC?_l@3_VO7?iBdM&EO|}53damp-iS@ zR+PP-i#kqP{;3rmOePFzklZ<(%pacRz`1?mWm|`h^zVWOhxgE@7H(MfFC5!%WZ7|p z@@qIYryoP_Gvt-Y?RVlsbwF2bM6hH;XO{u(3Fo}1cIb}W$5gvRSm|XwB-+b!X{^zWv>pVWZVc-Mf;+rSso7W#| zd3ozF=YdHK$Xcp)_f0;6(oR4%CIgMIau?}BpT_fU@8MfkZ1;=Bt`rJRJ&jb5AdJ;e2- z@3&P$*jz!JlyLY)9fI!@e=ahkf4KquYYf~Fm!ycRHK6qi1LEuI@sU|pW$J53A2b*f zd)3yUYois>O%hr)+1) z_$%d#=q+~;vFa9l68Av$P8Oo}P>q?C4fV8D;3v}~Z9jYuJVn$CD?*;w5N$And8sn) zJMK4^lGPhF1D`}XBHm@@B1_B&%&Ek?M!Uycr&Hbkr5Rny2+s*a6LXDR=S)4k)6PJc zasaK?l6H=(&h%<>+~>8Z+yiV$x>|IgfvvMN$a@4xYFavGC$c&+zsg ze#dWn^J-rI`zxqr1eO{dEoK%vMX!xH@VR1z|Lp5f4?m7Mk7d<`{K8LDFPl`c+X|o> zz8c;$cOfS8K6hZTS^myNH`!`PUrzul0zlGU7|plq{=)Y1g?H*>kbW?vq?C zi`{NlLwl}@@aqM{j8b<#sBqc_UAY61783@@X6`>d)JHTr6}p#%pZo3L7gU2!CJs93 zo|_l*y_P^oTmx;!FX&Wgf%jDdG)Kx2mQ{hk_1EF~=S-*<&~Y;l5nk+p&*v9N>)(Me zWF`3FgsH;`hx=_J&bkf!{AmD7Xq z)H9W3AO2`ICv+uk&b*@j^qZ55{>_1qCL019EeLLSt>Yt!qlVVn;9n^r;F;vk|C?Ma zDaYQfQ3T9Bi0IAd(P7h7MDNZ;%f+|Aw_J`cJIkP(OBgpM4azAi;FW$BEzZA0$8syW zTj^S;#xQTtlqQ!KmE%t#V%sD5E~Q$NoQ06|+i1VzBy_9N5p?t+BL7~BNwVzTBRF4DIR8q) z(^c#0Y^^>ma_CkVq~KZfSq^+u%eA{jnE&T2cSdN!69WW4t_?9q3{bs)4P(xm75A@RKXN#)_U*C9 zDio1loI{&$o*-cHal{o?x$pnzZq>Lm+%>22;geerRaPj*=MzaF=_=h%adR&;e4@g8YYb}xf@Sau~GQe{fuQ>&nS z=OOs9FCe^e0?N*WeQl>h=&{h>;a}E>7BfUK6GpI(cbN9JwuhO};5+~hQ4e_gT@Hb6pMRg+lr4eoQ zCVH`@^H>N`zIuXMB40o>5NUPl=wNdtBdz{Q8 zE5l)r*(TXzzSWyzSLrPwql(RnE>A1r`|~qsHrz(1Csqu%5NA(ICCqHb$>#OPUmCR! zVm|oMjis>@=OeY&rP*V$_W7jFrG5JsiHqJ-jdnX~ajLj-`stF28OxsA{73w?SkZFv zC1~gVgwR7d=qc5s2l2C*s#<6kU4r`ao6w}+hib`Lc#(#Vp<}1tHSy~$_SRcvdwa%B zS+?aMhgISC)B)u=!p8@ad#|A zw0T?x_?`OXAnlGL%sYew4a_N{dx*wzxi~` zX$V6%!f*R^1b>@@fK7LxJyZSKZ}c?r-M`T_J(S#D)V^gBG)1JLiQf%slDYA(oILZU zKWwNUcCxN=;>S%c&Cq|mQuH7UjUp`{Kp4t=n1d_^w?{MMp&@k^w5TU8%KBf|T!e4h zc69&i6}0^7ggakTIsPjsQx8GhcA09zItW3ZBXC0wRPza2SDm8&-vPg)c}SG4?iqN7 zpX}cIGT9LrP4%mr*@*B8!p~nN2$u}-JW>QN<{S9Q35XvbhUbdgP>wqbRo`9k9djIF zAL8MOJHhwf0%6d12%m8b@11_kCEY0FV$ME?HuE0Z6;@)ZOBR{`_AJr_EKil;=^VXF zHP0$*$5%@pU5ly_e(yQFZ3QthV$932dF|7i25xiMJ1|}|tHJ5{ zu3h#Bd@4gnk4~iFM>aS;Sl$TBT_^q6ip`Sp7YNT5)e(l0zV1hysmC@bqtXZ`KLJmg zoXt4#0|^s4r$Fd1hctc$MBgL`s+QnA+dvF?7eY)5#Bm28M5RIqo=lvJ<%n*FnlL7C z>mBejc0zN!6#O+4_>)$M2W*6+gr$F%;8!gn%2tm)jW*7m^Hx=bKKTV${mKz~uCyp^ zhr`-^PLoT`_-2S~1e*cS6jwl3M%>V1gnykCx^f#r3|43^mO?r4D+mK-LmZI?G4Uhf z(8*9v_ztQazq)(#HTxgZHGYAx4Uf^9c(L|aA^4Gd5S*P4mSsiw8MWPE?Z*21SwAMr zcV@YPfsdG9K@I#4l@Mm$r1wOh>!@|$2d{y0G;!{MRA0JK{fMA*b{I?8xe=;_wU~Zg zul&4H@*DEd%=Ig;N4%ux1~l3^=HtTnF7p^1*W^?VY;te|=yOggF>%B542pzm0~dL( z1iBwC!}CNHB43#Cc9oTzb@{SVrS|;2zuL{KdHuhvpcbK+GA~2H7=yQOARcRn`?9d|i6dxljiGmj-QIDl!ycV3OHqqlvTmyE z6lS_ys#UKXA^VJ`fd>r6!3>Xe#l)+Q5T4C^Nm!XnTROo`;*3xC5+YfhKEuMUez9A80phi<01MDhv+o`qW=fr!`HzhV(V)?yC4^y zKa@aN#QI9JUuP~YdH~_P0h*^)c$eAXZ#E;CG`6E#uC#F#{k zCTiS4Vl<;fjd6)YQ8BJ)T%rhqV9VC~z5zP(zIJBL`DK1*{v79=;hj^b4&8mKtBUIT z-TQs--B%CkN;>u=I_`k^#Ak`0_gzLDo&HYy5aNV)!FR}ppc)2gAHwiKtB|(s5?0pR z+lK#nAKL9MMsK|qBWT>pY_f7Jr+(%Wk95crH^=J3m`5t>iT!-7o*Qx9z&&?Qk50$w zzU7u8^sEKr)OOLbYFp5YGiJ0B(AM~$iRkFA*m}4!Qjk2I{}+jTyxzDHp2w`cXT@W5 z9#IVAWmyLiz3~omTHNxp&Y9_VRlOO)*+vMr z43Ly)A-UQJe}f%?r00F_=%KvU2)?Ke^1^$N?kApER1cw`im^VN{=xIx%YV@zBQVdY2&kuO7* zu?{KQ%8~j*E%+fcw#1I3@ni&KBR_&_$`-tKUgy(e$3ukW9z^7s>ljGbnL=0@>(YXG zyo~&7lc-Cx1sQ~+(RAI3Mgs;nnz*5tv|L9z_n;FEXm>=9$q${9wd%(3DTnX*ge4_E zKkKA?H`(1i!cfK}R29tjF!cYEqbY2g8hr z!xiw|at$F@bx3mPF`TsSE5t?FXBLyr99!!k?Q28g0|y4Gt=u$+M__&!Y+ZXwvs=hC z*|^k36SA6I;%QB8>72(NUzV$rMp(ppdbA^b*uK($p^u%S&L-k;XS9gb7|~m20;{Kb z!C~UE98PiSWi2}Gs6_bM^YEX05PSx4(%3l=1}sGKo?^s&`7@-E!yzb!5PnVupS%o; zd8g5K!>{N_80D8=0r{3P@b91Z_HvRer9GQ7U3~`p(K4vCHiWP`eYX*z<;3@LK8Npu zJPfb5h?t)T>yN^EfUrK8tT$ZNV~fHq!WJw5c&eT4n)% z+X()2EhM*e#6gK~R+zmtO(EqP@RJH54kupS{awh%EXI^(7t7TQW@~L@T0B1S2Ew`; z(g>HH`kJT?l)-oIZpcT^gWtOaNcyo7Gu3Wk)JX#uGCCjP*yY}St3tE{h9mABN`+ z{R-cE4s>x451}oaG&aKtwl0)fr$tb)27!0%=xQ>1z3?Uy2C}}qjK{Eb_<{9CF5nvB z#_0y6Ta4TbMl+XY({r6oCdfBDfb6ro@VjY3j9QN{!VXr`!}_}gXr1s~UJhB-Vhko8 zG=#LW{JIfs9#{}@&x%e*^@u(95Ist6V~pA+8m+O5Mn1HPy6>q*o1BABJyU|mBX~gp zGEQEHBAvKs&|C<8K1Tlw4H&O>_@tk^kIYIv$2eUitC=U9lU%bwa>EYUCE}d7>XA{W z;YOIPqD+sK%Wzq^G{XG8wK@#a8ND@|Z2p1eZ!K+csaT#7+ds|ca<^e~id_hkI$F$# zaqGRkog>@^udlwJj_}lMMH{*gK~@t&>?U+@8NGe!d$!onu8eSW!ncrgT!}U>?Z_y10Rp>zfTNRB{3C(5$5o@()KdB45?r5!T^Vn>&3W;!-(0WwOOAtw%#zvZsJs=b$w47(9dn+nD0E( z^US}5)z8docFEFodL&dfU=ZPF!UHoDC29m~=yyr{j=yDt_!Q~Ul4?kD_Jdz>3*u5c zg#ErI-S0)j^jUxOBVw$+ofxsIUwB4gd;x}a&^oxO;ZS~0JI^6O;KkLw* z^#bj;5`zC!2uZWiHTMWqGd4pUGaunws__S{Tash+2m{WQBYO8`q*pY0b1MTh%pcTA z`0YRxT`Th$SxmUd<`+gb+CFCX)+>11g3NQw*yDXM~m)nmT# z3xr)}@ITnS9!snTQd=kK{U=R639Obord)3IkWc5kj zQU(8ozd$;1FZfPVAhdZI(&&i@oVOFcREi ziQ-tVV=M7s!nfc?ySLW}tCL#mw#UR@GeUJ)&w9#n>2?DbS=s>A@tg3!P>)_F9r~Cw z2(KZ{{>B0X=WfSfx0&4wG4tzSzDLXhiPa3uZ*lv1`6=BKm4Ubk0A3=G%0g*;C;^FK+Kp;sN=o*&A38$v5JNF-exMLf7ojT4Frr*|LxfcRWt4dlyCLOQDufp49K za^^`0!?!^gyA_I*B@hCqKstOWRPPqRcg9A@U;P@&>;eR@Jcsyw*D>&d8Z$gD={Vxe zDIOD;zg{Te8|x>`H2FH0JuXFSK`e1oHeWHS$suZUx)RcjSHYiFqnnZNOQYi=bVf+e zs^PoqEPS{A4B6`|5L8^OUT$`6mpNjU-PV3)ot|g7%GTQV7z{&Meo`O1 zkxM3?6G1#idB=thl@>%CX+(!L*ATS&8pK%zkSwf#V*Mk8ZhZiL$uUT`*Fe}|g!m`> z)86p(dzRcWleVt{|K=J5oVtgu#NFaZ`-V3XM>1HDU^5V3BA!@q1N^jIkk26uopuWH zR}Ld)K@sGA2vgElVc@A6(*6}tPCWqSTSW-`_#za4%16-7Gw7!`BEw?jm|r`q_m4K4 zklt+Lm|qd&j|^WU2)`K@W;iKxnBNX@v1AmdA9dp77oXWx-jT;WT0|m@uiu&9gCYT$9_Ur^W)+CDQAsOi-M(KuTj0 zKjs7Y&i@v&2_HlLdLGj9E3y7!O;}X-q}B}j)@Y62#nAq*a69*DQjVM{AKyK`>px%T zI1c~N`2Pr*REqvH=V5-W!`t8eQN#gcE}|J7ym*66_2x0q+pP^V3lc-soqw)^m1b`|o)zhU5a_tAUP zZSeiqLm0T3_!J$#_n#pdyb1hE>kzR0H$+yLkZd+0&1~@2=`U(=1+ckJ#?jckB%9x5 zIMc<(yg?1<;n3k#dVl<5w^(uDHsnioBjHdP{B~V~gw;dsAwK=VJ}9@Jg<{`r_#G>U zf;7MMaxL1bEr=(~?_wwY?6Gh&n%&Y_2B*O4x7Zp#ZK13`%WA?>mIwNo+Yz}}uOB)3 zmYQSp1F3)Ya2-hZ2WlI^pHoAAQ-h!@HBjZ#m@$6?q@xx>I^lB!&Dn!?i+)7x0@B~R zZz1QdO&IWf36zUYfzLjT^eZ;dJ(Fb^tX#xJGumCT(D_$FvF0p-zc>S7YA*PGi%9o> zO8eyy#&1XJ*LM(^^shM_t=4q_qFLZyC$Oe}3cy4!>g_ zESEGsEge%IS|#4RMYkh7*Wu{A*=kEU`bho8J06#^?L#{{>rIHQv!PR&3(_NmgNJR9 z@76#%=O|PkUPM^#O@tI0(0O+)WJ5lJWF&FZ#d=7JoRC~}KsaOt|D6T=Asc*(9Z$WR zR#t$g&+(C@(c{KqwB90G)$9yoHKG{~3m1D%3;Bn|;1`xaI=zH`|0R$NFM?#~0f^(@ z1s^&Cf@(7OPSYSvItc&o8W2}w!$h}BLYNiBYNdvcfeFOJ z{ocC<`I}cUw#p$I=XU#ax z`}7Q;se8^?_eZ{))ctjDeO2MD>gu9qdU~4fdCv2k^S;lUi#EG|{gfLpEe4XQ=P@>} zT&Q$u>c`m>P4Raz>Wi-h=i;jR#$;EFx)vSxxs>DJ?$!)nF9{R;UH_YAUfx*n>vPdk zf}=s?cS!`JwOIkqVH`NwAaKgBAn{uR zpOu#|Jn47%6%y=xV}>G|U|qBt(qpAiCRL*~;lhq7)sS8!obq5P98#;%Dqjt*&%Yp< zxC4$qrGXu}25i6iL@#dvvuFprju*o9SU!1wAtZ$Ja!1MjN;#Yeo;uztgKL2f>)L zo_kJNwQxK25FP8(7-7~5H-6w9W7XA@sow{!73%c|FYqMzsnlxWpdoyl@cia4%HVcI z1#ab5FmqOr^M7xvAEouAqL~NbNqG1~p0}g(EXzz5srb8WNEYRx#|IYGkGuA(P3b|i6p%6DB+%)iRO%j{0G7-r-Z`oh7QuhW#EDd z)*O5daV*i8Ic7LNg*>tX;+-$a--HWqerM~6((L#nNQe9j&B7jl4G0F~zmi~CAlx^{ zqTR`-L^~e>w}a^Xz<5Zu--bQGQ^&}Bup3p7B~?J4R`$t9HJOYF*T}WsdIx{KT0niP zXm1a?rcY~0+c$plGf|rLaN>3FG-=>cR0Y@cBDkNu14(cMnCa`mOjrjlfMDt7L@+<) zLVBYd-F0e=G8=@_K*Gnry@SuA-oiDKT*FrK`j$9IL!zLdJbGpfSijZqm~<4~58sEV z(`ItNqT##qF}jZb{{Q)jY>KA%PmBNEP3Maq0XUab?SJ`B`S6UpMT^G`9wu12>Y!cd zwL*E!#YCU)X3P?Ld$>bnXZNS$oCseXoA6pN>lH5=rZos;uPjiM^0uCs)Ej=5*~$!l zs~0E^y?|)a88H2~f%RPqhW5K_IT1`pqOH5n13Qsu$6h~@*NHYAvX^kk3t$$egI$*o z*`;c5i3V_yMsOEQwmlnGM|8dk%4Ze~sn-hvKUfu15BI3jLl##9b_3y9`=3L8z7#G6 zM)(=)Fuk%t)Zu&`f~gXI4ZPVo2%#Am9=_0)pN(LnKA6*|<{p{KqERL`fCl`N<0 zbR$1ng>7k%CW4{P1V3rtduO#C?iB{KdZU5YlS(*dy@B||6Y`yJ5$w+acdiI*LJ7FL zYP6`;pm(DIJ)T!UxxEP95v6ENaNA+`4LI#ify?0n!ef6S9C|-E-w-H=>_n^J6fnc0 zzFk7iRe#eaMV(4}Kn1TS31{C9o)Uj@x;+83HGyO8#Na6(Sm3{}d* zg)8RFv%8e_`@o3&x^5Q>)d3fCe(!f6@}i=bUoTtkDD{dIk>2Eo${gumwTp!1tHZb&vvAN8118s4?G~6CxKny#Z|W5lz#D|#WhOY> zHA8Y$2k}`o*x+YiR%e4vXn! zd%p&nhig@4y?(LfQk{AX&ExO=(IoI7TAtSJyO^|a*AXsC^t|J9JzBih!5& zxdL1a8E>KpcYa!p7SAg&<`1iI^dI#?y8h;UpYZ9u58)O58+;Q>VZY)ExKXFUOiF}! zegWEqKF73__rj$QwBq)GKSM&WQ^d*s_L*slruZj>yK4&^Nm2Ve%FK$n`SUsdmTrH) zHsIsY8kf(P4vNXF9F>;ydQs-p%n9k&?~XrmtFF!VT(f)FeM9r@x799tGTylcN5pX> z$BY%U^zngo=}oXRBH=LM2wdZf-)17f?U? zxfUzCs==xVH=4S|Rlc9T?gQ`8#h`)1Gox({NJhp3S$Gk|VY!fO&V-zLIR_;X{ND#= zBEk3}d%*P%f@BUE3%Y#|&T#-Zw~;n}&30J?ws<2Kn|=O#u%`eUZeTh%_b2GXBP z!G`8T5?cc2a)YggUa2wJ>eHKBG#L4ZRS?q1yJnWW+7SP~a@K|q7RT`f18Lu;mIPyE zC!eBaxfY-4v}j8F@El?IF=*hzUgUE`GZ&>EdgU zEsh5>I+Ez%NN_9Z{9QDBZWg1rp%!hl8hBJ`pnP0`ZW=Xc4JKXVT57JBeq*#UH1Bdr zMZIJdZ|!S_J9w z0@xqC4{mWLJol4pT1L3=q8Ko<&wv@aA8fA;;0A6a_&FS$^B}OTW`ONH8{C*Ma9>k@ z)9qkpMnk^m9^~PQx=_9O9H$HqR!mpcbw*8gwTdl-7DtkEYWGU4QDQ zy0M;jq`92aKh}$AK0fWgO8x$6eO15*vv7E$NzkKShkhSS0w1#mtqfXQjR38A3bmNM zj+>0WN6p4AK_4v66h{Zu)CxY!c!N%7vmy6v0|9vs=zXWUVs&&PbGTaHzSqzITW(uZ zG{rwX=-g%0{#&j$)8DMfPs>02Am#SCytMm!Ro5SVw{6)vRw(Ds5G#@t%o$G25i6GVEe2mxEKzAge2bX`Gk zbS*gdaRftqLDKabaKrb29dN`pm&i;%h4x9mVL+`$(4m6x#cBhZQ>=cghy7#1d&y@j zqMxAE!}l0eTPv8r^L9TqTAI;%rUO<}JA(gSG-s5~HBj$m+HaJuH_>_~!c|@9SV4Qb zuOxhv<|T}&=Y_M#7(#1uskdO1-q4R8M{^fwE$)y;qk!hp&Uo}nsC0Gt(|z}7?uk8b zHQvMKFBb^yn((tJnt}$c+l&rZHCH9ST5&tAaP6JU!XKX|r>8zjQeDcuekbJmg%sa_ zzWxHcf8(UXdyhrp^>@=_vfhn2dQ;c_a^Cxq`Kr8QN%`*<}2dS)1>r+h*or8-Z z|1yE_#;p*wAXw6M6ULt@7R)_xT{vn-hCu8e2By%6?XnVed;AJdC(+TIC9}U@(JCH2Sg5tnSTko?LryiiI zsvMKlyxlabg&Aov3VRX$HGtO$W`D49a~rIj?3NX5HV@C|R*X0DcD5eqI;-=#x_ad< z9pCD_T05Nj^0(Wa1X-WS_||M?={nA+db6+-(e%D_UeZ#F_JuWY3%>`4z?0|@^#Gj{ zE8rbbf@WcaOHN6%)#bB2*Msw%2(iyNbP9?G+ioFPk7Zy-T!GKoXYflaMu1u?7)tnJ zd+O`QfAVRfUQXSKJ|Cp56KrTS+44e{f3zxSy}Yg0af4aDwB90}S*EsI_`8AISO~0n!JC%I$bVuK|ZEcuK83@a;*c*IJdLi-spp}$7ZZDOoi*za&50#Dx%olVPYotAxfa>A3BQ_q#x3|vxIFL60j3iiuHjLOvrdW1ZN zxc>q8<>@gtyGr04M7ZmkcsS5JpzSYVpRR?XKnqD$F?v*~G1_7lPHeE+jc(wDeT*9P z*Xsnd$H;7xm1*&y9$Y*R(JeC^2wqPux7e+&tGC}^v?@27EpEs4Cf|9cde*hb2wAQH z0al}MQ=`RYywxJ?Yt{(*S?UBm3CC^wN>8x+A*8`7xb4b?+nOvmFG_}6U^eU*XMpX# z15BF*V7Z z_-GMQ%p|zzHm`x_0yLleuUaIiAa2(Uj@ypFE8{*qcihCX4;DGaL&`J9o6UAZUsMam zmK%ia!(*YGIs!8oacSN_j_OHIPSq#jYf;yTSdkLeER!lq(&vrWa%*e z-8?ZhHAPT|%E@N3{U0+?M=*jvDJ)FP5#V3*QB*|Dw5a%ssYyw-pQUqNI+vv8gjaIX zG6)_`BaMucRBWrx z9+3SvF3pY4uEFp7`#Z*lpNFXP zWiou+)(+j+D(J=J!m^|u^M`sUPQ7xFwXey2VJikzlzA;OjEbv*iFZDj8!uvZRxO;W zlrZ+{}Kov`_V^;uYa>;!i13= zrV)(bpJ8ilizh)<)-lml(|sOg8AnFs+dNNr;mA*}-C4rR39sO$r4t;QNpffvm!C)K z(<&~nuq=i1{KT$ZTAt^huv~-Q7#s>L*FJt-LYue#0tCXEW74$jkYLW+88_p*%`V5b z=-(2mtxj?ktQ}EpRJYVJ-AmDhIZlyWkR)Q^3o<*>{TvZLTJ~)I0xF z!t{!Y_?gs5_1xymUF}fU@e9n(~ceNc*ftV|c!2$YfQKieeo{@S|r3bniEVexwZaeOZ|P zSPXm5O3Y1e$I6^8%4o41wDJLHXAtLlS7TIC3zpV&VW~n*aa5_`I6(YQcMps>ZP0uC z60}qKpzSBL=aO5XIo$+peFzxNY%o6$1H)uDnA5()Uj7R$9h=i&?n{T0NAo+)G{6qNJ>R)kAS;RKrHvgDK(`d{!r;jLRmt*QXHr`D)mA_Ti@?jUl-% zm0MkXi}X3j7)}X0BaD1L{vHfE15x}U`>i*^DY^#6f51!~!3h4Gm@{)ee7wud0{zA2 z4;~4P?mtM=kBq6B5*1NADT7z-Ox{-{kCGfZY`iof!KDQRj}}*Rxuqo>Ug(vF&3f~l zLvi$4zP7{ib4bZ<+D`nAUBTt0C8V`&y7|1_j;tHE$-2Gd;z<8TEm;^dfA--|hfuf0^=OIiMUkg}=aJ$28U z_q4GO+Fzw-71leS}dc0E3R6othJrEo~Dg=K6V zES}`RDf=~M30p9?Ru1xca!)-lF{!=dn__W(s6;4wDisPN%6VxirI~_QAwS#sKg$uG z=`a_|Z)Z_VrY-ybounfe!Jin*=WoKf^IZD<2V8x>fE-h|Td6wXF%=(&Jjoj!A1iez z%qa9M=cOn8gF}b)C{J9)fjl(evzm!EujRZ8{E?6G^wc|DDt-Lk7tRPv~T!{?Xr zGGb%0J3jYFm5=)7nOy5!W}o5ZRGGn*m~z(ffNa{g_j9QypBB=>i{CgUl(l@3QC@$F zSKWAsThp*VUsCQ>mM%yr%@W2(yy#hBxFQsEr(n?SFJbaVA3U#77@0@1KL0OK`%5D zHZ^US-m1jnAthxFp#x`WK-sTebCA3gI?(%%<2bV)kJ8?S|uhD{{5Kde(1Lh z4Cji{Yt_*4$%6Ic3fQN%!sO&bm><52nSoib@yvkjvsaiFA;uC;6P6HT*wa2lyW2fr zlU-BmnpIVIkzeuh2pOZvE0DTH6}ErMtE@XvBoaT#%P(|2vVXsp4xRBYbA^n9Gj;Sq zXN=URAHfKI!@@ahap3TCEstAVmiI$}(S=LT=s`hw7SUlM8~=v_lMHUfccnbR^MB^h zVJ%8>=rE7+^VnI9I}YAypxsSYjZG4_?MN2A-jOM)`%#)M4lPgRCngj$Z+=wP|H-wK zZX=gyg@I@B;KvV&2kqRFI*pG8SJAe)@+sf@xSM%VE%_gr2k$MyJwnLaJgte5176mGN3@^jRUH6A8WzkV7Yi z(4nD9Fan9=<8Ck#`@qOl!$dLwONkohex=ZJ%Yt6IY&b?s_C(S35W@ah9mbprfc~Zf zn06-aZU!A%V z++%$F!D~inmSSP5xMfd@pm}?4R`q3Rx+pxep#DU7m2w4J*s}9(gv|2Fvkn8V;=##2 zwS&_=vNYDGBimVj^RL%F7vH7l&Xt=56sa77CCYg&@zu<)u4hws-^-_7XEz$mIa&nT zn46%R9RX{?1%%Y87FF=l1m(O8j6w`IwZj8+Z9+-IY==M?}m<> zgz)2^LwoZR(D%n-aft%E8wY7SD|)on##T@qee&_~-As%=$%p=-R5;al!TJ3VbDdI6 zUC`KtjeP@DvL3+ppNEEP(l1phC?+RF&|MMs%l^q7(a`mL1s$>;RU~2TUcv|-O;Lgw zCI>Tt;NIxBpdaOdw(TkCORs^x+6$~Z)zIY<{{D$@7_RyWI*azh;L|hES#}Gwt&uQ1 zl8WhG**I3JW~V3@+zVAii8qB{}kDj z3lTkrH)55eB64NRx!KKodBTRhg_%;HqRgVlg+0 zhiqMQK3EoZ_E z-NX-kH6ymVYYWMtRlGEDab9s?PFbC6VS)59@xHKBkP~w(dr;R^su>mA(EY{Qcm?H@ zRHOe@)_~T;`)#l#%;ab}Xv+e@SQh{@cPUtek8gZ12ej|X!1^g2^uq*)ZVv(DND3Td zJ8@N^8SOPNFgc{BchQqB)!Ym9DkJ@aiLkg@jKu|NIK;JLW<(A4z0}Y*NcyPDYX>OX z`ZQVxKMb+_d;1;d2j;^vuoh&@#mLcZA`jM4{{7uAcR@ zt9Mygmufk`uK9RwevP|WB)Q?}oQRaF=H2C7esUFuFRbPe*O0>%mZqeJWrPJdlx0R7 zui$d{!`GU}OE1VP^7OstZt(j$G9wtlUj?h2mQxafil;kGn~C4&!T(n<&e95;Wa(;Q zYT41^RFPL9JLhITTXeN3J?CLriZHT>oprk?E&CpsbN`DkpC+F(nzf5xo32hXUi&j;{U# z7AGGlbx#Jr*Z(o@XWbv3|IFO#tESF5R)X!Zi8WV5R8rS z7$Ka{{#Hel(e z?w=W~R4;fYSA7;PQ?5Kz+0R_WYr)c@UaTxsQ_YKj1c;`+BPwv@$*ZETxcc+2LG+!8?f}i4@+O1&6S=kVGAP& z-V7^D$#ySH&l~1Vl27wEg%_k8f&Z{CKkUzEuq(J3+<#;5yn~v|`aOQ05CVt@=-S1# zyX)H5hVI%C3s|tAsGy*$0=g(DO#wv-Ac&$grGuytLP9|gzK~q&R!S)ggn4N(v&xTL+;TN0XJGxk@WH7r0X@3sT$@p+ zAE;1v@k82n#NV_n)Bl0`AzTBN-)jXXSIWVx3&p_ba5k86JRR(bZAK10lOd)*zX#u6 zs{=m8zfQ+hc3H!`Q%0r~$S9NoDV3flq2}jGDKs*^y7TO9-iIk+%|pvFTe?mamsesL z?-ky!-Vbct8Lvi`VC#X-CGKd=jtAOsP1RZ~(Af|M7CaUJ9n)7}sy!1NrK?b$%_GKe z{d|&2v-5SQdVhkt??=C$ky*P)EnwPp95B2>1PcSCU}cIDY{o0Wmh^To+m{0t-Yo(f z0z`mTUF%M&s&klsD;Z3&ivdeR@m-9eKV8^qwIX*0^$eWYL!3s!4u`oB~6APb1&%KmH&-&%fZsid|+~t45l4O0VbC5z!F=7 z?DMNbR-cf9;{m;>2+{EBbV;{WuDH#f&8`gQv$(MW7CTW?So8+^cf<^421_gtdfTWv zoZ6-_%V_RCo>|{@Cb>nkC!l%6#ELVFntFbep{v5j)?n)H3kNeidBDV53@``s!19=C zV2*1>;8~jSy?xtY9e=-JWai1j0o1-iHL^0L8DPvJfq_*jxXJIEgl!+1Z_ORj`bjdP zvn)ss7Tx86*x=}_-U?(E(DNZvo&EV>4X6RI}~sH|A%mnh346^--qQ?SZN zL?*m`V(Mpx!u@2HuG#X}zswVw(BCBJ=kxtJ1``q9xiI2Y`+}&9jwO%7aFdQ(oIt*w zJ@XIuU;0vhj;@$|g2VI_E>+EOruCBj2uqB6Coy7vi3hgY76DV+Qn2bc z0j#tx1`7^mfN7iJf!^|9V7T%bSaD1Qwq0lgcL~3Kl_pZ}$BR48WQsdZ;bk3X2(q@z z6j7sdp+MmSql8<9W%1=>L8)xK$r4lraCxFgs=UF?0{08*>ligKa4iRzy*QwI_$8Q^ zr~>;%9}s8Wpsw!s0l?q_1>9*FF$y0XT9MMN*%P7~T0He44Pf@;!DL$^nCo8(b|lw< zCykoLac%vk9@WD}VamRxY4s}eBzfIPTw5B|JGl0F*T9OGU4t9oo+pXjeLE7BecSPMoo7Xb#ToBp9S0m4-I%Wq#Q`0| z9l#=oXyd=DD#tL4GdpY+kO| zf`J#Fr{SfiSR{^TF`4HMLqIN!6cF<;8OwG;KUv2U4-LMwo? zEjaHQ@72O9%<(Em*;GcMGGl88HV3JO7KFkD696dT$!czjLaZ zY)jcC!Q~8mYBdv=C}-ebS5ULkULu{h*U(^MZPJAP z{RKIC*C|Om;GV+Z5w>P>WK!4SxSZaN@u|%#g8cA$9xfs16NjykRo^TD@JzY!^Ei$4 z4FIg=bMO^=a?>T-bF#~JF?0DpvvPRuOp3sTP2>2%{wVB;!YIzEaF>x7c*su}5-KAT z&fG_HQ5>x4)6!bD-ngs4*j$&R&fQd?E_+JRcb>HB-wjh41;!4{eU>`BEGTMt-d(K9 z@ODtU{*7Rzj#o(AY4iA&}S=uLBHr2Sb2le ztGE7n4T$O-STkB{AB|J@Z-sg2Nq#RXxPNG2fM(dly>7s8cU}uH%WXvt=5`{^f@=249teF`Z(DmT<6HYopDG8IJrIn{ zWK`DN{m5Q2e|$|Ctg&J5B!<G4+ zqWUVgBtM|4Fe6IN%y?OukBhBfWF}SQUg#I52p7(y+F&=&2r+)GSzxVoKp{=uDJZ+yJ`%<|g zG_=CV&EpOFqWvAz)eDzVhxb?_3+B!n%TI~K@1{?X`)mP$f2ouzd?+HbQeYnxdSqaT$;>yrd|rfRm2)XKAukHLmfpPSz()JEf89q)N`ucv<&~!&1CC0(45q9HZVU6!F^0lilvDi>=A$M2ia^LydPSW_VoTqS^w#cU zajpHP7days55)%~LS2gkwq@AFN%BGWe$DVqLT#G^rMAI^uBh?AwRN3{@9y6gq#j;y zqhUnFHN14NKnJg@( zzJJ|CwnqD4mIm3Hs02ITHGwmIVS;zM5{U2HFH*MVu7B2YaU;b`?`4Dg~zCY9NpU{N< zH-hJFK6FXZdHztdD8ySi!|$db*ymde@zZTJ{bRsPkt+P^WFYkyB@H zBKHD`I$k~$jLY>Lw5xk2IuJ|LONeLBdY2|ykr2sy;2b%q8&*8BG)zE5766@bCLn{kGLjql-`GWT;2aQNzrr_ z&aj~Ge|%2?7_hd6bv2jAk6}qGv4On7d29SDfQd&1Sm4bA%Y21kktYw_$WiNZIpQc- zL;uciG;wjW9cc9+Xh4)y|6Oj7r^nF{5}^lGIAucRdA zQ=UnNz0YxGj@RqsHT$Q$^Rut%OQyol1u1FU|En{$elM7VZr*b6U$)0R^rfy}z8pMr zch}F0j$RS};DPZIH#a>}bo4jyXLHl7$i#m76Z$Iz*E_q|U{TRNnuWJ66rr!!5>Ypu zO3^oO7Nb4fxR@I*4D?S7~FQgVF!#zg%`K8e`hQzLvAq)@{ z7LM(QANR8PTP(KK_@-Z*j%$Es(v6229an7kB(KN4hHe3!ldxd}v%?aGm-r_P&vJ_B z)3py*X}d(JCdCvCtk09STr1?&_&^TQB=xRTaf3^$SYu`%@IiaQx(Z;p1P5lVi3b+W zG9*seZ<-}j+Klm2R_jQW*4?BFYF!KXHJ-&hxj(Gq3k0=yAxD`!g&&+X!F5f+HNy*j z#CL(kzEWVD*^SN@SKoduSDCp|HIuQz;d$=T5yQR7JxEN)!1r(4R2CVHomQ?))uiuZ zs(~4y2Qeq9ku&sett-VUOk!o1shGjQ!#NxDe2vCRM`jn2D^l%ml_qBESK6E^_@vi;icO z%D`VbGAmWlvj={sjjhN1=vCr5%lB2L!R1IKsoMoQAs&V2eG%07h@K0o|E@VIyp4fnI1(1iXf!SC=B zJMEB2udX?6b|UnR%SBpO9cWrk7Z_TO_PJW;&*dVA&t)M;9C8q|V=oZ%BYwypOMhhF zNiXD>jSq6++EbLHd#qMiM2R6bv_wBDf^M9ZCHsMz$303T%4}jI6bsWcYqxO<_#vDE zK^TkzhU7Y)T)8tRPri?lFL9!f-`hq!t(_Gd-1?P=SCifyUzPs(pK4I&uQ&XYz3Yr> zDqGuop9F#^ilWS*j*c@rqv!}?9c&fI<6{R@bX?!eop0Uy-5gKKKtF+MZY0}`_0*PETNbgK%jLXH>&K}ag@)o~WxCd?T#&Atsw;%XT4w}HFfD{wT~!X%z4FW9My&Qcrd$GE9Vv7zWNPU zTL1XD`%eZmZ#GTt-g&tJZ1Zge+!v`}y;&^aF;4?twL{!xk2>8^{=Qg0qPKsZ8#9*Z zjf_?@r5X*iHg$>a`5BHa&EYc=h9sPkMQ~yOpIUZHW0CAfU|*2Xde5LBRpn$ zTWxVi@S<1gPx$!-*ZhogF4bJosL9OK|5^{cuLa_PJAT{&tUPYu)^YRvpRQS?)9cI1 zVzuenhKt97&Qgr*QW&sf4jVPYB~NBfxgrCY!LvrJ^D9=*mSQlR-<4_ z^65}cDhZxFdku=ohryF)uL23V5O_{L3Z7NF1?3EG!*fbLP*K$ns%Tw;nudOur9&vr z-SaMcZWi-MCAHBB^~EbDcNr9rdR1#G+WczES^}%fTYZxAd-mKd=-eHd+QJiltBE_a z@bTfuTYY>%p6y(|S9-ZDFFeL;8gxQ&nR+0r-U&6Wdodf|aSjKsF-{x%e)h{DvulmL zrrC~ZbORxkcCb&O8SGbKf-`2lP(gnj3JK5Wz`IKT@9rF+9{36uSoL;`H|g~^DJ@ec zb6bW~b32CAvpYtVb2>&;^E(Iii#wj%movI9Bg{m+meSB?O=;<|M*Oy-`LS0?TeovK zZEpJx;~F6A+5nSFhJ+B8y_ncTFbjW-cTOK)6z$sd(|O%PI``UNiY2s8?AN^g z9OG6@1njcWfKxpbtXA>>0=5Z2FOG>zdpInPYDfz;`2{c2Vt)RClQNf#B{}39Kf~3g!lJlce`8$|^2}{m%LANjo$%4IS=`@k-29Jvl%V&l<>CTH z3QE|+tov?Xdi+1?4fFV!)ifwwPOQ+~$g}PreA03($3G7~ZeDQ1v2tb9rExxM-6out zTpB!cIt+?Q20~FucPJqp1|`o0voKX!c^*S$y`YLx3{=$cff_m?P)*AV>gr#{Z0+Ll zVWBxIvon}NMTH&86|@%n%8GVZv?m>f(xssB+<>KGWis=QfnqUK=8F&?tvFs+P|f(kp7~vp}2_X`)CQrM5h^w~rm-H1+Rd zOMWnMthnKcrD-q&ukTC8$y-rjVCLwC+^!ML?5Cru*Bf5#GQCrcx6JKk+irXZtT=WN zaGZ7rE9E`GR;{Z*(Tf7TGx}Gfzq`;IkW#kEIhSr&# zr{c~?T!EtEzCc;bW|Fl^tlEoC;J>q$@YSyr|3ZF7!@3sD+8J)?UQ%<>06Nf*Md>^?>DL1~?Hc_qV+ zSlWEX*)agWem-}H;P3ZoK>lRjb!&mLm>8tQ#|yL&iNvLxm~}jh`T7SQ{YlF$qSKO7 zj}h?f|E4=+IhNzE16{+rxBdcRT${O*JYVfFS0`a-rEfyXGf_}lDjdqlCP7)HC@3Qn z4yB|c=6PZ?R8UKR8v5x_NhcO+nxsMlyIjoeY7K|awFjK8UfJw+_6c}f`!Jl2X*edO z9Sudba=~G>d~n9R3R;D9u^aif;jKfTusep-uv>XNz&l*(Be+=(aT+N1U`G$oz(FAr z5ZYG7auLI>N0nc&A0 z4Pcja8`!Jx80?wntNcnYz;5Lsut#MK9M+ovCUL(LuGYT&F}`v3P&DJUU<_k!-!0~h zaBlO628sE?9Mz~w=sgZ8RpZAmCl0I*%NpC9Lh9dFQTN#0JMKA`yj2lAp_vFyC`AAZ zzbbqT?dcZ1*i!6VNHNsC(}D}H8`?~1>$Iq;YYnNdq2EBB%*A!Es3%J$3%khVS{9y? zskQA(yz5`b(T}gQeve6}6_mt}XeRni{}STbv(DFfc#XYvC!48OGtS9km?PMEc0;h^ zBu~2Uj9^*NE0L=BVcn*D`i(YnK|y}u1|7cFi&Do@VYzU5gTaP`Dg1Z>!Ru_>cT7PnlDkS+fC9^NL%*t3xdD9zbC?C z?o}&+l&~;N3km$DsURn~olK;)7m?~0#wVTlPqnT^En=ZhLs98*LBW6T4YC}|@i&9O zMgS_JN-#ZiKp@oV`5IGoGNvqj4W5$>fHG%-p@QNKsG^brRaKJaaWoXlDqe$X%3)Aj zCloWZjKjP`AFhbY9{M@8c<|J{qG6HP)ZexST_>+}@=juN4oG3M^1Y3};CTdHrc30eI+mF&ymDV@9Epma1iAR7woqf6OBtB3glDku2-tH*f5 zDhK%PJsdbzUDp~&uc*6)_R?VOON4p}u=Y$@=<|=}?IcRg7r8p~i#hX?W=d{CHKelJ zgQhv*Qzs*Q#<%#pjq!N746ioOZNTi!``81VW_SW!XL%zp&u+~OoIXeiojO$;Gop?9 z9WY6SM8xly#Gv+(^(FOD56kOgP|c89(PdUhq>F0EYC_ac^skcX1&wnR5IwLD+zs~SX(pz-G#BKj zA)hJ>)90~s!6U$`6}5gm7mM1$2Mk^8b5qtzDxu!L5xsS}j`kbt9s$+W5T-^zO)Vd2X_bm|b|SJ}@h{-GnLuBk zncsCdv%FV4r?g8fi98?>lh?N`;BGg!_wDXgUNP;Q?vX7ktU@~347@vV2Hrh*9gpXj zS;RC!-*W_SX!Qhl$#06w!hV>|#p@N9W5DDpYyU}trPnM$+v+7|?mNRCp7UmhOUT@6 z9g|+n(rcXEz-a`3PWLGkRqg`Em3zTq@h3p=R3{J+eGK*rw*$fBoj~Yh7ubKQ2OJci z$Jvvk;Dp8`P;z^XNt=&BySVqOVru4uGMO)xVoPR(qH{)nO3HsB5P9zzUn;TxXia5X zU`|QDjKYOdcvK?;@QeF_!}2$Pid`1GTJUs3WYzF@p*5qMq8xiiphd_z>w z+z-wcJp^OjPMnL?7^kP(+!{}psnt;~(;M&kO$!!=O`a-G9x!gAJV^cE*+rwdh?32q zkW(9}#kUxw!n+I-`A!41G_H|KiKElXZqljcHybDw35}%{w~-&MiB^_|)|{dKc=crs zQMAgoiG$PZ?Qg*X+ZyHHm%9@A2df$EwGQ2l%g)X`7DOf1uI_Kq2N8;59|m2(Wv(>IRb zbv1*-HH5})8Qh5XifiNajj7|j9M-VnqE8Lp()A(!ybTr8u%cmV7S&Mpd>NEcqd|#t zrSo}wCJ^FJ020Tl=5zO6Tu|DZEkRjtw_b^Ty&)=nZYQO>-?Hez3$yEaule0V-f+A7 zy@LMk33okKM(-%<5bOMTL4}g;jy+Foj21@Ep!;=c5;F!b zb=L-L+nK9ir_@y-<-mY47w$tde0l$9qn6jvu9oJ4yJpr0emZ7wd!Mg0%z%j%=5X-%F8JCVkHH?err-kW+ut&c*S6X9lSAu+$Lu#ogoqy1c$Wq!sxNk!$&WNI$j ze`awn#LC8k{3yAT$CkbH%kf_yYq{0{)XO>8&YvSRYJ8Kq{cmg@4ow_}8j0BX^YNIe zVKPonKN-_CNWk>1?_ws_aX3f!G&VPXBEc@8oXtJ5p2H)ek^^CPT`)ZtuUL`znCI=ijehVBtm*+BkOJyaHJfS27TRwre@IvQUv zbAVJaU`na(vrMH;NZq2&{2E;_ClE<~v(qc*cV7FOf2?xxde0RS`F^v1TIbzWf_+S8b>(QBNp>RX(m_B$wJIRp<$w}RtZ!{D6G0KAbj zzP+HRPm@^Oqn47{yEm?AdVfyYpnM!{YTy5`cO5`cUhVpPOYev@u|SMs`7J?=5s8V| zV?m@uiM;}fiXugdfGoYM^rn=h$g*s&z|s*ALF`5a6-7fY%eKti?`%QM!Q#GZj8Gdm85~Jly9t!am?rnnoP<71TLu<17 zj^Hyt+24#DU6>d?VHO%Ps(12u4~n0ID&D>$>iz+vT7mwfT8W|Krm5j$OL9VomoVZ7 zwsMKDd>|%5425+qh^KIc#{@MEo7@#_Py{Qtqvh zbp-sU{TybGC!5i8k;-^~ic<6bG`;SfJFaTz7ym-B-tiE=(yyL;%*hauQgF0LFZnv( zJU@4IeRdLWd18{#G%J2`NqV?oer%A?I5t3N92Oxm@Cg!W9*Y=Nw6LuQt9CvB?(st^ z1m-&@8ms$g1>=o9;WTG@M@aQdimGU<;6P`?z$^Rk#;&PS_1*XLoc6Rl0U2b56* zH3Q-7Qn)s9AICy2NzD1MKPh_HEH-j{Zg|+Z;bE5^%#pKw3K#uGRj&q2Xa}Mm9mb!X z7&>ZtJ>-vhH-g{JBBp(^Yv$fd>0q#l(BX4Raot`Sj)X1 zNUwi(jK=-_2!Zu#cj)C9Wg|WPzm3~rK60L+A-Le|tk76g;P8-Mo+{y)QoO8?Ia#*1 z^mC8u7doXfm-kxLbx~+sseUQcg+_6d$|OTwu%@!ApcM87Yn`S=O6x0-w zoSJF(;_E4of@{ey{A&m=d^oHZ?hUMt@D@&ECYSj9a%tAvO$m{Y^+Ey~)qF3plzqJ` zmEBy56iyt=!|Zp?NA~PWMmBBA0ygV2!Jdr-WV3Y{*!VpGoU-e}xa@s|x#09nA>h!E za+E7it2l0SEt~k}5((dTw1)L65Y7>4s_sl=b9+3aNdmKT>0xk-$} zejZ}GZv^oU7imV_5E;kh3Fjmi@fT&@o?M=eN4=c4B7?yDF1$oE%RNP`=Hxwq+3WoQ z$zYGJ#*=&P;2e|N4TC?$H1W**Dko+nHBT%~X&qa6rE*NywqOjiIHDIUjp_rdJllcA z;Ucix6OWt-U@CYfKU0pQeKH9n4H!f*N9SO1Lk49{ANE4+fcvbfG8v9?AjgzoDauQy zwEyWWb_avOXlGaBA(q|cwxu!4-?)|E`skFM*|!WEJ!0T}ZAjyQ`&-PeldlnH?|zKi zwJ~L{YZDrQu@f^w!v|*uTz#a54SKAR9Q)jeLFqXSIVQwy*~}}Blncvd55WAQOzRcy z-G|)tF1IDUwx;W9Ip_6GJpIki(!91MYgerMTh6DWp#khRY(R)NubXyI2w4)$gndVJ zaa>c<*SCGrW>{+8*hA4O@@5$o#Douy7XztUA>N zY(x7oKOLrmjR$jq{h2%@I=^S;P0oOM5^Lz2h>DR}!Fl~NvMNW{)Ym?akjBic3OS}p zF;t3YGJIpgJ)uww59&H)*Ns`nm-7}RXZFtZ#XeR&AM{*#_nC)?&537Vr^idg$@3lJ z8Zn~m88xhNE$V|#T__J8qdB#aosYIk_}Ggg+-H zL|~j%GQPU3s{dE0g_pq`|K2xWta~~}sC*17P(0{8so?C+!yNYDD|p0+)qT>$S`a_I zbHv&~WnzN_x?n+a9dCJd!fE%=PypA^B2W)_zNTP!g)TaLY?yod^Oj&2^FVv-H7Ej9N2a!2XXc& zK~nIq<`mR@vPtF+E{UiZG78EX(!#1UX>2j?4D~7_kfbjTg*-rurGCCGoE?o!Y`k=6GV`gj& ze2*VeXeuiF6>>|+As(od78S8@=TPE5@6pH)Om)Qdy@Vt3XS>scNfJ> z)Ft>yW|c$U*+J$O-J{eLw39g{Eo63FpzC?1|Bhbiv`yPT#o+lh-^2tYdV8z4;_;#K zc}j4Fb0XnPyB2!wje1&hAeYpBflYaIj7#pk*h*>6Y^5}1w~)IMTZvsU^`$R8X}5ci z;IlqC5L5eim);oKRC0ZEJuZG?_3dch@^qCY(k zd8GuWzQAhP%9O{+QtVgr&pwH3n1Og8T%lJXzX$s80n z>*f1{U_Ym19=0?tm)3?*%#`$dqL_J~M#W2N@ibC7%Qs~)B%F6#k-KS}rwts@ba}H`ZLJdcFu1IEspcvXp z<)$}L8?g=KyMYb#=3t1e@|X?IVd|h%mo|}}hjDS;XIVKPj#4xJaHORT*b!sLtxBSK z7CAAK%djEBnHzV%0}EH(1E$OBz=H4FfX)IgP@RzpRCJ<%hG8C9ZuJW6brm3Pp(2%w z*F@@G@nX%On_|6)0@17_3g0}ninlVmWz6bMOTPo5t?xia-Nb756JlitM~OhRE1AlCOQq zpQm;qf~R&YctX+k$ZO=(<+qB#nPd9bZjT$rvH9PY)C|})avsFMJTcVthnmzd2Pt(K zexkSrYd-YacV{wkKP~kS@6|kneXI~)J7VS#F^<`A@;O*@v<)oX#{$dtlmpw-?~zN1 zLX8BRV15>E!m==ba0|Yu&z?}$YtN*-I$cfcy3oLA4UzW(P4%VAU0$n^#Lp;(QfhJc zsT@4SRZe#Hnndr*>aFEPXCKl@_=ikl1&W`{hg53qUur?JxplPKuX35_D#b~79me$N zeQ=fBPNhonpJa%cQit&hjN2gxmGV>c@nkBgjlxU~yWpjwtTerkbK3sB4AyB)W*UGX z7Z;_5V#3J|a^;;ia%~>!xoC_}|LPou`8xC*ZXiF$a!b1}a&d3YSLO5_Loswu$@Q@x zZ^cenLJP^fC z7`r#uwWSbidk=(%eVS?Od>^s%>P74#A7Cz(Jy)^u8UT)02QceTbpUI(`@qVD3w}Dt z1Wp&9AifDaop_w!+x&{*%@lm^F*g0RJDc*-jmv!EC5h+d?>DTwLmn#2AxOC>taY;q z@b^r@C!yA!yk;)fXqM|WqZkNzsH8ST|D5lf!bf!dYoF5R9Hv7Dl}?q%uyw#nEr^RowkS6pvd2&`9=fR*(lV7j;-=+4Ch15*;vGpPmYM%Ab{ z0M(gH6hBK)F9d2jc+|^)I(k_{7Y{U1JpFcQ7g)b#5F8H|C?&M;&5Irk?key4=v>k@ zV3%@_w=#eso_X%7SattaF|y-_3GkCeKd}DpBiLp!3hcM=5f5*XT4btd7PdrWjJ+i? z!jeVC*Y1dnA}GSSvBg4DpCqC7#VCP>Po`MgC0DEh`}%hsdV^T+ehB`xp&hK;&)uk?lHOWbe+%XyrS&5=vA*F+RC(102On&oru~WM$dRCr3KwzXnwKg@ zHL>+$#%BnBs-4Uhsq8^TbqVhC;PTRCi8O*Q2`4O-V z1?v+BcDf;veowWMu&<5MqIXB2@Jkz z2If2afPI=+A+SxPk8KsszDySD98MJ}ZS$E#%&q&t_m;!pz(z5$e*+(}w;n?re;!3_ zt%t#`9|yr9CqBkMNTeNlTVxnT70!!b3g^br1@oiHLetC1LhW-2Lbc2JVl7wPpK1;s z!^nQmLCm&8J;2KL1z5kQ2drGn1#oUDmH7TNozUyr#O+FGtEw+(t7*uqX?z~ctm!#V zX7wIT!HuoBdV5kIOXr&eRS69JNMpJo#4&wews?jo=TB|-9HH92;BL%sQQZm$BA#Ge zA|EJTxb{*x=oa4~s6=QOkk8kPC>S%jQ8c_TrSQ|jJi^;m_&ZO3Bv!oGPNM$4r-gMl z19H%*zSO^9pIlRPDmMSjH922gu6;QQZ6w_O3h{ z>izG(zq43oj5T|RgrdgYMuseDQPQH-nrq+U5-F4HODLu7inJ1Gk}W$Sl}ZYgd!v+y za&5EpJI{9}T&d@td!F;0^PK1Ro7Xw-GZ>#4fAI2pFQ3=@#*>1=D=oJQue0-Y&iTTk zMs{Cn@@J@Lzc!m=gYEa>xOd>W;NtJW$14cBnz68K*-5b4bQ{^Wtq577e;mXl9f2fd z2g=Inph-sgQ=tatNZteqnLD7MQjI=;9p*@sgQD^W5SMxl!V=GbC|U;uvHK`*)&Rd~ z5fDW3Kv28^jT#V|TLIEKuRw9jCm@H8fqvu!X!wkP^5%Y!K)+5@eg?b}C=ZL4fRtPt z?6mlbxUXYiw@`YKH7h#7c-eC>Gk6V_=H0M$Yd`Xf*C_ti<4jU)4nsbHMpp_-rVDw- zkMRXuW(j)cd?joP{uAR6{28}pUpHc9*N?2-_7Txr^#o344y)60-`i)VjV!y8F=$yz z>-M1)zjw;L(Z4w><1^({=E#zy+zI7`(g~$Qr4w@kZw(6`%K0J^dwW9RP#H^{+Q5_w z%wq{TCJx~p;(Kv>qMl)05?gTxPQD>VpC6PsSw2cm%pF&X${v-8&H5sncIl(irJUb& zu3mkqm!JQfQgEZyxa>}=!=pQ8*Jk@HPv-HBle|{{llk}AzN7az{lb!p%gx1Ar`h-G zACy#Ous?o6E6$(J)j73Iwm%fD{97%Qc86VCoqV6>Nq?s1DIRCn8KS)ddAa<_1sDGe zOSO)Ij&=g9UY!LSw&Wp}HZ(*(x>0M8NXglIx4T`n$?E|U^Fp%`~`OgbuJOd=+H zR5JX?sBrSJF~!r#BTLfaMpV-iM%B+B`%@?V*r-NY>X=$g>V)jkljBmsXU2rx6W;Ug zi|@gEpYG#}zcD;F>Gt@1Y6(*+`W{0*vVk$z>-0FkOX?txQ}iD=r^tKQptLsL$W!eC z$FKA&X5St%&ARs4=w!wh_4JG(jf^WFb*^7|V^Vni^)_0;3(Jav$L>u<)rlM(i1Ox4 z-_RfL>QBcc&lWeZ>)K5PrBQci%@!B3Yh^BEaK8QwKBv8ZVjXr2Vz=1zA{HjCutK{4$Qq|WpPUXBltOUW{tV-~ zvmJZL;{zdj|7YRYpwHr|VZ-tXVT00fhd)UsL=4I%P(RBiQHSM{qW)BfKk`K;fjTUE z^ze{qD0NUUFnoZ(_MNhIeS}!K)*%}`n~@#+pJM`&-Vze849?B2|7;ddn@~)?Kdu(v zLRUOk#G2!MW}LA9{0J%VR2QE|+MMbi%x>w5vaWzTH{UwvT={5q?c#g$ zn^${m%5J=JD$VV*tGxNtr=C`Gh&?aF&Y5TBD1kQcHUo?Qx{Z_T}IBml&3_y zM$;^(-P_YlD?Y)=?I+K3_9#!zJxzHo&GccKux{a{G;5}Fw3?PPD??GGb zJ<78~V4}@{)jAB&BY%OVx+Ab~(eI$F)C|gtpMi#HFK9ZAfPMfSH1~~x!YWj^YCZ$O z`4538^8on7ihxg~oTEPpLRUaZ0o9-@ScvUf7NV{G0rWKcVAs}hjQgHZ{C@8Veh=>n z9(%hlSlewM5DU{*Agkt}JboNh=f{FB`8*itU4!+e<*;kZ1H^9UBaFlD7L5JgW{jIh zJI>Xm4eRdp2IuD1j&pHs$L@7|jM?Sfg4w?B9SSM>osQaPn-9 z-|{!#xgYyV#WhcFmlQoLs5)6os|#o^)d*G7hemEbL}uIwB=n z2SUQduvD`L-0bN1U)|`0(EW5$NFYNX<`6?XJd7di?LEP}Yu6xV?b>d{*y0T=TlEaI z^vglVuoMi;D!^<*6spWO z^mvSM_IZH~is}=fCVUc2IrUMlx}yEy{qn{$P36s}YN|Vr&>G%5oogLgeym|ag?fEL zGVODQbu;y!Usk7F0kirTW;51e0Zz=+=GIKwEMRjQkx2D z67JI~5}WfY;#&&JF0$*BGxust^_3?5;cKSqq_g;SN=r6Q&N|&==kIMrx2JmS-_-`D z_;kkZQcgU~%R6R3CjYPPoacgz|1_}wa-_voVUtZUvf4Nsv^BFpWx;uvuaF4}@|hs7 zlmkmw)WgP&j}dFjM#RkM0jyrpit4>8P**Jj^@UBKs#Xn}i(0@?>jN0-4S<3E2ULsp zz$)V}D0eXs(>*N2z?KQ>%ZET=Q5(oFXoI;*Z9tN&0-|U!5JifCAb1gk#q+_)x*r@4 zFmO&bEZiz`FNg>f0fBTCNTjns(R~Acj&we107EFsmmw4r%$O4sOcy^A%n%Mc$PkQ( zV2Fhzumn9Ln0!0jCNP#edJ)qtFTi?l8)E1E663PJ2j?347VjU?$G<;zkmwoo7VqrW zh4SYMjFWpO*4_67&e`=T*2|*>7nd|Fo02v(?^5odX?00wXv5v7Ne$&slG#yT^E|Gi zzUu&czBRpeL@V;bka*OYS0t~fTR0EuHEcxcUH;g#W`UerJ!{xAP2cX}b7t&0o^hzI ztmJ4*w#Ui$dHkcF+}He@U86I6L#BK5g^e@L&gj<{qFj6X-gkb=Xy~Y^{a^nIa>2#_ zTi|hcP?jTu86^%`vFbNaUz`l83)4Y;!9`G;e;pR6+6fs{-!h)di7G4WE66srbF$r=z5%LR4)C*T}4f%iyc^4V==Vzm@IKvbXr z1W1LzD-eu6MuYjXJ_vDU5MuW;MB_sll5vL^k`ZAH(W6Hga}tvnbE7UYr2>w#1iTI~ zdA(1t2%Gi|BE}nAV7={A#L>40>k-_C_x!aVA4DA>?ho(dck%1SdH(tl@9xus^YLuM z`FXVCkA}PQB<;-Zpk2`Q)B#mh=wx=(rBO?f`g>LLAi@za{thg!hQ_nYKU&MqW&@5yufcC4C$9Eb}Gab}4Br~8w+;Nm|CSPT~AC6&Q?O$=gY zngu$#iJ-D50p-wCSg3v$G|Bm(t6c@FEnC6asT1q$@Ep5oT{B`vse#oio4|NgJs2&2 z0&A8(2MQW%3|@h?#Q@@HJ&yI*&cwU9vG9JLEIt=|7T$i-zpxG){)M$MV41t7S8FSeFqw$9sQjrlThbAy&qc1aM4xVR;dPXt%d{488&Z#UO z%Uyj4Wn&X;ae9mF-PecN<^B<~*QF2RdvKVKdTd;rO8qS2;naZ(aOvVnIy@|QA$3^) zbmW(X(Elh0nsTptRAy#U@{*I~j|T?}1lZeQw^^7Y znyM?~6(D2YJ|I?oc?Ystba5$^&CREG)@^U!=g19(a9 zz$ch0rBp!{`!mCmAyFml<+Y8dEYbjYaZLW)Xcdz7p+| zSop231BiunJ6LaegY4Y(5wp*E2j{(MY;I51;XAij_L&gf(R^Gyc>*7;?ev(6f`tLK!Y5I=HeNksd*N(bgzO5r5@IA zXhod7-eMhHS~2T3+(yjJ^HA=*32V&iVb|u@i09s6{LYPC$Y#q|h>hi2WXsxa#M5>d zcf^+|NOfisBYl}dVeSk8UmH3uWG9O^)t4z6ww=XeV?2zk((C};1+}27S^<=W4Pd*n z7xCFKgo`=DkWIWwSEQb2N`&Vy#Ul%tGLD3I)k@8UvjYMNVN0SN( zX2J?`7x*}i@I(hph((9e#o0PEIg_q*tY$(bV`E9J96qW`d1q*tGS-|lBvpWV$^FT4BL z0GH?ZF#mVN0|9UN-CUZnKJG7YZr-nPA)!M8iKpla$(JXTPZW%+pT0h-d8u^J;#79u zf{^$!p6JXc0;#!OGFiDjTJ=TGBL3phl1UDoj=JwO>bIT4_1|LpF4JH0_TRi>t0(U< z)l7dsr!Q6bGY)1rd>hsC8AnkuXQi@oa%YC7${ z_enx0Kthq;R#du(iUPWdfQ402P!V(~0wNLt=`EB5LMK#dQbn3nsjI7E0d*}~TyhgQ z_;}3WymrlCW4t&LQSMyvj6lBZi4eYGx;J0i!*&WeS&krEvpcY5)eZ37G>W44Fh#PG zxoTCNv+If)*+#`@S*El)zG_-8PfN&q-`T%M*6P!sBX8c&BMI{o0Y{~b0al8dLL@f32ZxjOk5*#_i>_X@(A0Hv3&5+u-~QEl%D(UtEB z;TcT)(c>>gf&*TNWZc|wbzchHdanJ)Kgf7*@q^isE3}2#dBF8aO6>e*7N{F^8he0PXgl=F<>UR z%~ocEkx?0}{k9dh@B9TF3!N5?iegG1Aw9r3Y^z4=tunx34IS)ko8f!chnV0)Z$x}u zo?%^`9wIN-5ll=72cMJ9Q>Q2J)IyIi#Xa|oVcd4SMETnTjZ$T2m-bt=yY0 z8@z*s^|F11yzKr&f!jtgneH5^(lDNKNfFDav3FwUna+346>W?)73UaMCFhuC8Rxh< zyGcA`WHEo$KHolij=;AAp&+rw4Q|BZjv*u({irK0KMNIvZ&9fGH zCCnw6nJkU+6!x;(D2@)*dqOhAV+a@H`@3kk?=PZ}em{wj10P9JL!L+{hrW_c3x7?d zhCIh7#l4nIN|+*0GuTS>6CB<260Sy06I(C0nZ2aAow2;?{FHS~*O+Bl^Yg`(^$+!$ zTkoyB*>|Pnx8DAby-M95cZq(|eSh)Smw8(Me0nZ^$+e$#>qou%)$Hbf&WC<=KFl+9 zf7HAm^7h&WT{`OejcfBdm5Z~QWE)G{HOq^diL{g)aaw$m_z@p>toaHv5bnbhIGq3Q z$9@3|_%9)NdNCLQhsc1kk~$bJvj*MeUa)%oQCPDf49wQXgM}3hEY>H0g+&gmTAdD7 zR=Hrk?i6g^+7G*S-bQ;}A0gks8C+B{S0*}cM*4gAL5!8nNwBghgLT&Ru-dX5wtaUI z4j#CV4!J$UhJ;Ls2Zc_H#TD?0v=W{wIhid-@|+a$*)xLm-1Q7|{NSueb|g=!A&IlN zHIk=wI*6~F=EaptILH*I9-I;@3uG%*NAom`GdatOPq9oI+9w^l`(F77@7mt!O_hBN z%c236>9O4RlFO_aut@hcZ2X1=W{P(~Tc!y#<@yD_z6m6yk_0>&E#Ol+;HBxHDAx`0 z^3^~jo`MY)Pr=WRDU#X5)6Q<=>L$_o3b7S@BDv$eVoDcZEvb{QoRG^?Ak&#dS`}M8 ztCFQt+%#vJU&>mVnlh`B70pnoNaif9rLYZ>Nw1_6{2xlhAH63Y<#SaeIrx!OO4u+y zCG43@Ud%hStjKYtl&Cj^xX@Qp@l*yOg)*y{k;B#~s$v-yHL{FK>lrIfcFkDSU4Ca< z(>L+$$@&Mn`Q=v$^$mlI2m5cP{6jzeSMSsR+EsV)pRz{3(5VBTJ^x3Y`AKVj&K>#O zYKdx#la4Z3oMf(+J+X_F=5etzohDQczb?1%iwWNQjGlsG~3NIG3pkJt>uqx3 zJNwgU%jO1f+;aBAo+OWbzhRCY855y|u?X2@o@!PqPc4qhl=bxg8MDRV6xeM!1naj z*Qj?_`>1zy{p`B>-l=U>=VqYp{xcFl^Jc+c6Jgv<0 zT-~%bo+hP~r<`2KR!Og5YZlZ_FDa^E7#Eey7^G1rm2+Ze)r5Ug3Gp04Svu1s^Y~jr zQosX=7}8C#*x+BqlS6My(qisQ=Om7*6emqC&Y{j~B~m5{v^0itQrx5*Ic`EGlg`%6 zt6?pr*R%Bs8kmM9O$@W*jv14R{)yFvHTM?flwFmruDzsoq38BtVUFnMtfmjych^7d za`}5!^9Rq~ck#3K?7RF${q$>X`89_Q{#Eb1Isch3mwur3^fr>qL9DK-`iI?23;T^1 z@Nb3i$rW;?q?i~iA`(GQQv+5Ro5Ch5Td=orLH4$uXon*i?btyZJNg1^sQtb;=p+On+juWYLo|1RyBu=Q!3n&x1F#&&yll^}ePYk*%K?(XpiWc<%PfvZS zl$SiBM$enmO{Yw$B*wqQC&rE7X(?k0sqtfqDb!bl*yJ&p1j@J^oj##SOMNY$R`N=* zv~|L`pzb%N{IVXo+@kZc-EG%x?(|-0n6HukW5)eFXLj|>=hR>Rt3EpL<(dEfe1^$~ z-l>nZf}wleeM7<=r~dL9b00@1jE;)x0%tDZUj?BT!r^cq>y>x{ELPKj)y8IEvu-== zboN3Ayn``bzLA*yE|KVfOBC|S7H2)cVPGKFF?DU6On@x4LR*Ufp+cBMLYLq zqx}a;(BYr~Y&hk}^LVO=fA*lA1IJK0eTwTVnY{+9+*5u7u6ee>PXGhJcq(?Fo zkNZ6madYcHo41!Br@iOVVgLKs@Q85P=ne# zb-`NulVD+01U8#nVEf+dC?b6pUvh@IyslAUUPb-f>bAbOZfCpRcwXpz7SY!|63}#JV#leDX}h8xwy_t9 zkJDQ*3yL~#LCs(qbe2qmp4w~JXU2z3+Sg&NW-DVwR7Sw5## zR5hhvTr+KyS1_ranLVwMoG?yIDB&vv=5i&2Q)VUN$P+Tblb*|`B)%aE`H~X%NSZ{tiVN`{!bKdrCl(rXPt@1@7S{7nFUHHG4?_yP zf%6Z&g^N!7S-iA$+AObZSUDl%oOp6ZpTwEE-fyn-{1o$HPu*8_(Ed-p{R4l_^W}f? z=Y_A|Qwce<_quRz(oj=JU{MSiziZ=0q$)2D3t3DH_%}iLFR!Yo0voKifva0EI&!oS z8x!9wT99*7J~!OX6A)VDRqggz_Fe|w>XHFa7YGhntX$M!#Nf(qb z^>fJ#t@z+K(&2#*#e6*nF|MxNXscrda@f;=oDTM(J)V8YKV(=WGHOgRfbSWmgU68%n{{nhr*53t^{QFCx*##8Rp_>P3|-!>k;xW_mnV zB{hsGpB>6jEKi(W(w;YI|HFy#-7P6|D=N~Nrlpxolh(82`?@+@Dr?x~2eE0G-3{cmZ21U)cps70v+FD~^q%#4w1`KdAeFmEsp9A+5 z<6y4b392$Q&>&=kmV6-?YWIP;{t%cM48dxH+hA&N3s##y2aC0@LF=0vu-Ie>)@*+X zyJI<+&Bs=q@9-V0r~4(0n|nXnd!QHX`@R?L_xu3`hF!s>=D$*)SC6WZ^M=HusO_S( z^s^Ejjd!eXogFBjp9%du8#-U}{HnL~>Q~xTz^k{~dkTK6tg%cb1&eK3WdVx_#09On zfPXcFHO$`X&Xuhlk8RTm2c@G@yF~-T>v2KH8*x#wEus;WA4L74JF%XT0)l1HTdeSX3^9c)LNoK7NZ#{#h4SqRqO6@ZmP zEv(;F0}cXBx?AwOc0P0wIs05kTlaOK4Ne`f#<3IDY;6QxlQ>W}@&lcfiC}1z0qgCn zVDEt|NSGOy9?eh=4|pjSMS3Dmix`)$$e3EuSMt`mBWq^;=|r}E6_sUBnLWF@B%5JU zQ!=yuT;Ge}OFhG}1HHrK3oTE>`x;05+FIVaop#(Bc=ccb`UXQ5>v|%@DYH-a@qOF@@aHcba*nBWkHBf8aBc zpAxBY-Y4)5Cr2I*WGnN(Zy8}M52OZL2}Mf$w6{ZM1lg!N{}Q7 z2na(M(#(+4%#d>s7Xb;vDnUu=8rS-!b^qL3-~D^Pt$TT@&UAOx{OGPa_4M>R za)PfaJo9z6MTHS*u6Y@+1=dQ+4PL6k&+q-&THi%MV(ZnZB~q|og1)gx5l{R zidOi3%XqTGH@K8NAS9QV8eg-msi@Bm@9X(r_2u7tL*Ft!nRs4aYkq}IR`|{BmKU_K zV|)i;8}H@~owRM_~mnTDNB0g*WaGV4|;!)9Qx-mQuJ%l{J0g_ ztUGHG6-DzFt+it}S}UL2WRyJ(rsX}itsu=?<~>+eRysQlhXq;wo&P25Kfv@)R10XH102&fQpdsIm)Wn$}Ay5F)zf^+gks^>jQOx4d8W0nrf|zg> zNQyB*Osp4A-o}b)`oU} zPCq01xnP*@D9>fbI<^3hZempU?JChL3hu_TI&N#C4IW;dKx4 z#FK(Tc&%7`DSY@ae79xmM$Xa({@(zf>GC&`Ebo2;8QUZx8=F+j-XV?P>Ovy8IF}JFdr;W?eVd4W z?zQZ0_5}o|i-iP#ZwBj{!S3bN%I5FgLk#j5=JfY{%o!B&m@6cHY?F8RD2Ic8ADhwT z9!$rDfs~E%kg|CmlGiT=Im3sbpp%c3buy8>5gEjk6XA?zK8rUCK}z;F5SL2^ahYV0 zK6e*Pjp#^EqZ~OH_Fz7?W9&J%*H71_&6`yIwxU40{^n$5@VjH=us1^FJ8NgjaVv7< z_!WiH>;d-MRl~7u)Ze3<$W#7RrE?A?1xtoEg8tkoCNvL+j;z3egX?hM=QR-c zaTN}KzW_h)dJOxwb;F?@BOtu*1!$a^LcVUZoR>_837XP$&^z0M6i$_b?5QF+C)NNm z;&mV;RtMsul^`j>05$Ceq@cP0CKm57BmGsRZ@z+@u6-b$5~0CSq1zyGIuRtKQ$WwK z0(ralv&Y|BTiJuWdpU#s$GC(2`nf{< z`?#)q40HRt_7Yt$F$tc|oorXVA900+FK!FI`hwTXcbvn;d6dn`afpCty;<7#Vb&K1 zFe~d3OxK_h85_4Fch`A#TZ;kA)SwkPS`HK3ZAaK{_`cj8cV+blQuO+1%I#Izs^69s z8WI<^$x&a0nqrq#%VJmLN@G{#OYbddSEMf(wo@O);Q5&y)WJA>9kj7{+Pk)N z)-5YzT~hVz3>+0;d3J#{;1_rUdU4XH{M!3l-?J+zwSkamA_xiJfm5fFKu$g%R8^}W#AlW#?bh<~yHRfhlH>jq%qv({ zE}<+MrIKEsjEQ^wQ}nf!y`GLU>>)mLJjFS4s=c(<>~CJX=Ifede|1AKqh>T1?^ z{#4M@r;Sa+APp&Mq#?QUNg#7R1>{weLGFAclGDrpMUzsbW5;?YU2H>^!83$_gtaXR z)VG3_J+wu&P% zQ4c~+R(A;wc3A`;k9ziipjP5lA3Dc1-ww`@E4^GdZjSTbzOlGBC1&aH{n!=Zw5a7{ zsnM?llOvW7r~dZxm&C}$pObIT^Jhmd9xu2(FOnZUeurU`nAamy3{+b6sx1w&(z#~sZL9Jsa}(^s8^f3sM}UH5rS*B z9!l3eT!Z31zP9w4Ygzt+sju}4hse=!ILY$y$41ATTWRz0nmlQ(fZE@@M;7YFzM@(kX<2L72qfBzB*MBw4%g`L}W!>;XnfNvi^9Qxr1h#V0G zGc{+Fm)Q9eHD^qNnmcV+`(VzxrTlS7Pepf1cSUz%Z&`anPibd#M`=%J3%NU}t++dg zS=fHLxp2^(PVV(=%pb8~kRG`<7d>*L7mm0yNu#ceqLItZq;Us&!MICv?u1Qa_PB9# z=A=<|(wu5->NAao)EO=My&1iR^cg)y#;iqs)-wx6)-xMg?6MLi;nn$?#3jwz)J22l z!fEdTD!l;Lpe+^Sp*V-OQpUp@N~gW=M*ey5oY*j&5}XDpp>;ST`T@>LegtvWxiJ46 zNboO#vcNmg7yb*hg+77^e+SNM%h+%cscViP&+8w!y#n8H$(^YNN!c<`k}ZY{ zO65pbyB7JoPjCi!j&dekU*juJUC^OrJ-4VO&A8w?x{KPI+)rWV_ETFP;%mC3q$QQ` zfahDn1AgbJ%9$|ir#2LR%T}&w9IC8s#`lA8UD{L2e9&3nnb=v^n%LgldAqHt<7RWy zBfr|_Ck|!x)7trzDajNpb2srs$56#xT71L<^-esEteyW|p-1 zF-m&9TZ+2<=mmqWjDkLQ25G>FSup6qC>->}IkbuN_#(aFkt>}v>fD$!W=hW+yVQ^| zWmumzuJe^sbDml?XU11ZZk zfUW*C7UBM3OG@y^{jTnBh-&JC;N|YGW(8Xr}Q7VpW3%CBe`pD%pLmXz>q4Ui)TK; z+OZhZG0#JChB-6AH57ej{GjC>n0 zE%zdHQpOVY?H7byJHLlRheY6%v<2|;Z2wPB(G6_i9|#1SI5)BM=P?jHVF%)}*FaeM z3P_zv1S#2gP*BPQg>z|e(|d4JC#5SM=g&cEU1@iDLqbPsV?=uiBdn*aDR!WYk=0Yq zOlU8mhqM$iz41XO_qaEe_Bk;M+uRtWUdQ%=4*#~oZoig-KF{`|?trHJu}h5w!*3`e#VJoTtgdu~#7|Ak3M;iMn#-3MvS zML3V*8nlx-kkC=_`>p!I8IKV6RbDmOS-2p(f(#TtA${2|NL%7BWWX9`lAn=<$QNXI z;xp(8zXQcXEKMpf2+E?5K=D{T1eh+eS4O@SCEs3?_Ou^nv({triF^ezP-P-bxpL&F zJBHcojABl@GlVd&_gmuwKI}>M|G3w~ex0aqHi;Y@*Vw}2Kkd}e>PF(CSs*MP3lg$- zK~Xsod|ii$er~rTy1&4jrznWe(CB$xQ{*?%9d+qF23#xJ-0wSz4Hc6y(xD;X*c? zQ_lbu%>ra>#Xy>-MM&GC3Mpz7fr5S^QZ}Wa^G2-yn=z5PO&5~Ws{;xBd^n+$0!QUi z;K;cJ&~g!gv9Yg=$0#rs8emN9PPeb2he>Y}?# z87xoFh-fcv4Q?%_2QZ3ToaqIfj!ZJ$t+lYlyS=a@u#?OP>nflJF-e22Ers3Q%)&m; zmV!agro2ZMjd=s+^aqocZ4aM1)o09^KfJztr0(IAZClBcD@^heKjy&tG~eX&dek8^B*x=wZ91FXTKl^mA^0-xzCup z%oof}>SOq~u z1X)xBWmQ>al}(gIAV5Mw*a?BKCV&Vk3Q80ew<_X>K+pS|04?q5*Z1`Qp7NaYJIMh) zz>v9f?=v&^jsS&kyTHC5g<$Un4lq%w2dvQ1U5yDZOgO>sb{%)VC1qn&2hFG$)~M%0 zV`3%rupA(`oAu$(9(uFD*Lqkg*!8`9X5iSj$Y0dTLX10TF@y^X8((hkFpS@;lmmX* z9V!`1#l6AcpmiP2(Y6kk5IVHBGUuL6d2XMnps>@otCW|E@Dkk{LidHx{qsM3lQ7;n z{l1G+RV?DxUqjVQNP?FR!}ffopowVV#jJcVe&JwJi?g8dAXS3_bv4=WfKEL; zYSl+D*5pBb^&044d>@~BYHaP%gTqn=luk%Ddx$%K@$)L*h|ltx8VsPI5DXM{2Lc79 zK%iro4xQ|H_^7i3Ush!ITh}l;Z9ACtsR$FXb?0PV!JQ**Oi`2sBT=5*?7Qo;9tqA) zW9?t^jwE?=5=^b&=kl))dX!v!YFZHYTq7&`mExs{H|x>)s*C4F)}UTR@abnud_4MP zTwH~Cb9yawa~BZ;0tOdcN_(-+&G`ZzC)uN)JMlDE|Mo(-NdWQ-mV;GmRKVu#$ARL$ zWbC;N6qIAZ&&mmsGmL6`5`mghI#AplDe0iCeO;LRRHw1H`=p?#{gkMrEe`b$ zkmg1BiMVJp>uzW(t0xlmXDf5X&i?kpGFGI=(3=kKDxeX$29nhofTGF<>PkgGXJ0AyRD!dfql0i!Fen@U&-VN$zHeEs76ZJ=@{gJ2q8D|~@9|8=Q7>oOFLYME(bS$kw*lcR z+SBjiRu`i^sSXZ5r@g8mzk}mSU6qfR{W_)>P<}RA|-E1yL#H>$7nqJ7PNswS@Y1PHH;;Jz8 zAZ_1P%nxg0Hbeai!L7I9w&{Sms zs%8zKVy`y3oiHxw(>i~jcXIyz9~K4$jV*~yAN$tfuo$nRngX`(48S=nHkrv(wc(o$i9uyexgOuKH?=A0VC_V!EY2wBVH&l;)axKQise0 zjC+1UcH@;!c4g7@dRE=T;qZU=k)NGe#NoF54X)14@RU5*_d0vZxT0Bkom0M|*zeVl z!!QqVbDy{K$4y|Ntn5Giv7W2B`adhQmo6hcAFTO$3;1~#9cXGM0-A0N|DXqC`dzZ%n{T&S@(7ijIz2O7kDph;o@vStC$R>NLZk^oU71*q?f2WpDJAjpR; z)5flgp4vk~eNZ+}GG~A9*|B+@th%d0R&Da{JQVx+j-tAl_7eU@iOy#>CLq4qRa%>O zgI&!)oRgFNz$`oN$)1w5hcs^1Bb(eyPgRq`#NWh)4lIug7O#v68d{lj{`rQ6qHaIL zQ*Us%YzY^`Fch5yZRfV8wsTrjyUMCqh>J#@c)8r${DqXK*{@P=Mxz8TgE2yc`Go9g z!$~O@@+3aWZbI%dhM{iC3Ei#~1&i5y!=HDE$jjaZP#&}onO z2GsW~&$?$6=XY~);NjMJ7rmc+nRW8r_l15R*IzyPVSUWu*NXz2AIe@h+Or@v>rJj`e32fItZ!x0e(`^o{f=?cKjm;vz5X@R^Y<*IKm6{wHOLFJDX-8m+S`Br zhBa&F?tsqK|La0t-&5z0-n|M33dYp|>6*SW= zgH}d-XlmR74XIpcK*lhYS`BHGI;c(I0v+8dNFo&g9bz%iQp*L}TG@cOKML+wiv~{g z9DIF=@K`sST{)Al)59)9xjId~oU;0vj4{+BMch)vs>(#3K!}fuN@@}%TD`O`8{r(n zK6HMkIA>5hC#`>5dcxiHtZQO}_L9!<)}mWMRo5QS3lfI*rG!2DE+yj5>iEFNtMk(y zs^q02;F-WmGg6i<$^4v-%&p_HGE{76{R0qk^7*F;R}4A{n!G8pRqO* za_1~2Wr7SRrBfUxi=M9F#p~bpvln zE{1d}8~V_Bgv6lkrTH=UwpOP1km~bz_P$*B#doWNf`0wN>%{GOZtgb-hwONGN2@xV zr9Kzaog8RDVnBWUQmC!V1=^HKK+&my26_$9P@e-$O{<}vJ`-voov(2fkTFe9QcK3T zXb9Ba7Y_@vy0>+emX#n3#pa@lVzBlOAhk$3ESY75#X7 zM(FSl{L*{=k~`xVhN7Mz+Ji?K>dn>NkxkXz=Q;Ue%OL-U3y)Y05ll&U;9;|2g3E#D z_%k-2WTWlI7oK+-UwFxJLO#}MLjI!l#C&(!OT4fCd%`)BPtxxC&++QNFaS-Z0;Kzo ztm|O*#PzVt1-+b#X4Egdp74rDRC@_FZxn+cf4UFCf<7(}bnBb%XfDKA7-ASoX@Cc4 z4Nymu186$6*n1v4NWX*gIybt&Km6k&-_ZB+Cj(#0M<#z-=M(-`-pHW=YUo{pM7>z3 zjNzw_c?z^}$b*G>o!gKupV8uI%nD;}{BZU#e_p`h_IamWI_G&?br6D`2j@p0dHY3- z$H>w+ztPpTFArp7Rsth0OSs_z?y~jXU zR-ZMsk3Y+czUXQk zrKABHa+y}eMWQ_=Wqrho#z9wR)g#m5sv*OyvRA6fd9OCdW)H84NFG@o8Y%w5+p|O3 z#ia^Qw<*KXU3fUOpK5Gb4vCaJK-9jBamsW^(@ugk%@nArmIC&X3xJkRDbT?*yS@%f z!c9#vO>d}I0!bPPfV4jWP&CsZML7oQ>`%aOAr2mK%E7m@s}pAQ`^+8&;-M05GaEx^ z^3A3_CXvr?D_d}Zm2*oYEwOdQrNquJQ!@L$$+&WF0Vcf5*7izmIpl-<6v# zHm=NgWKo{^$g1@669aClSg#^YY*?8kw(el_awQmw@lOeUmWg5-t8NE3RP_ZhGM-R9 z9PUezwd#O@b_=vI7{Iw%Jtp{Aj7Wt!e3A>Y9Fw`|HoiF4d0al>*!VIJOyAp*2O(W^ z5Spsrg!}h$fjPz}Bix7Oo3h1jXb-%X!)@;6l(&f3ZRvsj?-&2PRSY(+9{@jW7y`y- z?_oylTLmw>TT%|@y?8t0n>f1ZO&sE%rZfS@^F`3f<1xY2=ee}2&kJc+|6ytG&{4Ut z=#Q)8Qa^4qcCLfUhG~FkbPa0ihCp?_2uQSufl)Dyi#oWx+!;JWV_1`Y+w#$ zT!J5lp%>hH7x>zW2xnaG$p$#zmhnA&S0==BNIu4AWMz`?yERdM?^cB$d%ZaD*wcj` zPJL3&md$uu!%Cc`b~&`dw1@xU8tH;m;Scq!n_eC4+C0P~r+cvcX`j2l%am)9>|ae~ zBDKuosWZ9rlDs6z|C__9Y{)AxvDDSYEs|UKPfw@0`WM#D|NIQbNj5B z<#%;ruiRU4E`lc;7%rM0c(zs6=Tw!nom~;m)*=t*V48`e(@SvXhHQA?Kt3cHW++x;ITyp)R7fOd z0-{P3&{n(zXlmynMJpCwO=@3@xaHKo1=8^tj&j&DTK-SHwi(`n_H*mmH#`|xH+Q98 z?p~W5FZ?PombWD3a?k3_^nstUbH%%^T^Zb-o&IPyukg;%imQVME3Q7UYAopYY|0)u z)Lhu-SD$;|1x7>e#u)-eWsj43bSwk^-V){Vp9m#x2oJxZe>Ddyu( z5ngYWy3_j!wixd-qc%emssQ7l0%&4`VW{f>!NQ>j=iuCjcXNL%6&n6-MOw`0j?~1_ z?Z?kNlA&1VKppd3NHUIrn);DY%PABzIiKhI-FxS3&*w`Lg8sGood4V9aiKqo#eDmIZT!ji>%R4V zvoxGPMGdiiOmQT>pB0O^2CNC+@6kam&KOs@Q#~BkTh}Hab?@JHc-|(@$3IyL=ORn?HDqZ`J}WX8X_#ii5#tVzajP40^M=``WWWlAH5=n1`EOj~N)6V$# zUp6G?eUx+bX~K-SR}tysjV)r3zS%`&&cA{Ra-S&vZ3cZU7V6qU4RmUyc=Kv;ANyK7$gzfCsuvP#w)jF;l~K#Gv1t+qY_J(SrOu`YDMQ9<46Vf22)n)Xut&Sh5Z?H~%~T zT>H*HYNhi%roU;_|4}dftCl(>6t?v>-z+FiN#8{7Q(EXeEyO<&WGz&5`D)lHqYMU& zFvNE)!pQ!EZ(u7WIIM?yEMS=C;@p98E$fJTw;r*$6^KsiQR5uMHZMb5(@Ml;6(Ae4 za%5>zfh^1#5syRgli!IsTeV^~j3Q)hd>ye_#fYh!2L=XLz{nsK8SADaTUHjbW9Fc! zpsGb}#jQc47M<&b*EE)O3h$n8Ebg<&h`zJ>`_ng9+_>^Y<;Jx~2Xphr<*x`H$)shB ztjkF4T$7dFvo`C>sMM9rfsOfsQMt1GC-l0Kr}jnJodd=H12h$^kE3uPwFkX zf3~-@CAum95$}5HQ{}XT7h8+2PHA>GbYylnw5N5}_kLHNH^~SO?4h}OKF32MJ}&Wc zoTivDx)JH&ZOjOEu?LZz!h(kg073GP1ag^jMdW6+aC{M7E2NJ+gUL)%B6u zuBl*%6X0G%33tCq4fkxLg}K#I1Dwh!zIG+JyTx_P*SQ+^v#-O0ZCmjGyJp;jV5zN1 zBeK#FAY-*uq_#H-l(t2H!qyPjFMAHu6bVmqq=N7z<-j!Q06Mb`G!NB*zRqnh)^A6) zRz1kuVF14v*1sYzVO*{_V?wQ^`0-J4hJvi8{Nelm+I9Tj_0sv>bbrr3IonrJof=?k zi;GaH|MV@j5dV*ZJjZF&MX+JrcF@!HLoQzRSX}g@m8XwQFLQV5$IaNa$i$)q8FMO- zIj0Pnm=XHaRDc{TN(o-pU|geWf}hQZZ`X>sxOQT}9vu`PUK{SlxrO;Tw&8ZxWr$}f zK%O3Lc({KT?R0Se;@A`Y%a8lr5{V3M6bTEhpqZPTK|AHSuvU@*tHt#|ULgQZoNE!u z%p2N}DR{U!Cx2pRPWHoX*_p$evoi)Z<>e2_78DNbC@2_}FDZDUDJ-6}X{mbbf3JG* zbVp@xbaz!-N`Ga`)!v$hjJwsf9!+JvR>c{U8tLCpZ^=q}wX3FN(pp&Y(4yq(;J%2U zR+_%<4KOmjiy|-1h@J}nu+r1<8O7e_0Y-9@XWE0f7Tw6%dK~j`n8wc?n-wjH`&F(e z?$=${F8sRdeCQW3dy{F*+MpXTG;e^3fe`5&%7Y;81H3Wg4QFmATUAG1U-?*Um*9nW z+trsIIeuToxf;JA)`72}vF9Do5B&l<8Xtho{fdqr{X#3g^g%5yYDUtD)S>)w%#`?U z28OkuMKDTNyAxC%m5)qs)rs@f~LauVOH{-EpKz6S`oQP`@NfnGp2#P1<^9m;S6c&!}zb2SeO3N5s zS5Q2zSX}(W!QvaE2a5~GRD?xi?3>kN-rbdb7v}!wRNYiE+)#G4y`>N z4wJYW>F1662u(eJ+#IIxQz4&MT#lLDQkw8-|Ml-b?az&wk&O(RS>eQ=#w~PO5lgcL z3^j^@sZ{~d?oSu@ls!4qU)`5EaP_%Qf5t19p0qdod#P_ZdG^1p@X`GpvpoC-nJ9e( zy+dz-zW*JVSxan9tQRpDEkM_-28P~zGKsTG*RXJI z=bpB44(M~TkVjNI&JDeTX_!TWp2@d}WqARq=|zH?{z(W6tfdVIZ&nigoS%g!ynRK^ zB=gkKHjyxQA=Q(cM`+C)+|e!@;~J+SbLM4aLcfGeH7_Aum3UB5428Yh{XuSH5J;_e zBGM5K?uY_qLWAxin7U2M8I%=LVfWTp*tPu(!PrxbEdH?0N{7sb934ib;mBn z6)iiW9Rg<7Stuv}sa%fWwL(_QOzj%5F>6LSXMf&7KJTd|`;}8q`fG>&%vWw*S6_H_Cj4xaY4iKi zApPHQUxTl>z1Bx$q5LD5sJ;Yq(+|kb?JMqM^_7}*@{8oTvomYFT%J+b>_J3lHi7}c zdIMGy=rJllL-Pu#>!yL4?o~KU&jBq~GMG4IAf|m0QZtPO6~i#lU_`=!BcX8Ma1fZA zB%nK$BM~FQ`Zb2ntOgiIw7=mX{37#&7PHwjMOh8^?heRZEqx~?hAo~d(RPU z3;@-G3?#*QutCBG)~z*!jq6-srwpM*x10urU5T(q zHXdZw`+@Ab0MOV~0J?jMKxSjsGXfwi*hxZ_^s+I%dn_OV=H*{FC&IClIIE2PDfE8lK zgjeUmDniGIZghba64tP0y)B5Z=YX3H`dN34VRem`#1v zkR|Eus>;R;YRez7>#9b~n}rWN?p5`lntPsGZGBUBLsPOKxmsM0ehMAZiU9-DEOa?% zYC}Q6luAz4YlUpV8-w^5p;|yK}{6adQ-{))^D%{iM3qVw9y-6w;ltfJt?rC(5Cx#T!1Z- zE+D(X2M+H^hOHZpg7gMgkl7Fd(i=SpU*ZaD2=+?LCxO)7B-pK41e)w_V7m<=r@$vT z-){svdi)v9@AQ<2&+&0uz=;R6i1WjX{LXezL*j>MKJkN8$BV;wVAZ>&;SKLr#FY%K zw6}M`)`+fJ(4`CUA03ND7K5D3LGbgbrTE7Fyohcy3^KA2uxObcELyG(OT-O9Le33V zN!q}YZx|pZ=?L586G3Xnd04yUC`fF!ht1pkL5rRYNvS=n3(5xNu9rR7TPYl4);Ev4 zvVwOt8KjZeI9)W2c~+oxQ5n(yXR-)L0gI>aOC9emiQ z5&>c1-84bT^gco1>x22ZFAkBjPL~s2OCLWrzQob84%0Z21c$X#K~*Ca4ya!NC-;YV zdi>{Iflg1UY;q>cxD^?(YLNx|F5+4CpyU2O{TF-R85PyGZn@U3DsoZ`h=__HDhL9i zh$I2!m_Q^+P)U-i$T`O%7C9#=a!!�YM}Qk`*NfC74A$;Q7&ebM##M_U+gAc8@pi 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 z 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 literal 0 HcmV?d00001 diff --git a/icons/lit.png b/icons/lit.png new file mode 100644 index 0000000000000000000000000000000000000000..f389f0afb673b17f123d87c711e19ab411d51a4d GIT binary patch literal 5244 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 KF + + ../../icons/a-system.png + images/administrator-splash-en.png + images/administrator-splash-ru.png + images/cat.png + images/cat_g.png + images/doc.png + images/doc_g.png + images/journ.png + images/journ_g.png + images/reg_g.png + images/reg.png + images/user.png + images/users.png + images/metadata.png + images/role.png + images/regs.png + images/report.png + images/report_g.png + + \ No newline at end of file diff --git a/src/admin/atreeitems.cpp b/src/admin/atreeitems.cpp new file mode 100644 index 0000000..d91b055 --- /dev/null +++ b/src/admin/atreeitems.cpp @@ -0,0 +1,157 @@ +/**************************************************************************** +** $Id: atreeitems.cpp,v 1.2 2008/12/05 21:11:54 leader Exp $ +** +** Header file of the Ananas visual tree object +** of Ananas Designer applications +** +** Created : 20031201 +** +** Copyright (C) 2003-2004 Leader InfoTech. All rights reserved. +** Copyright (C) 2003-2005 Grigory Panov , Yoshkar-Ola. +** +** This file is part of the Designer application of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.leaderit.ru/page=ananas or email sales@leaderit.ru +** See http://www.leaderit.ru/gpl/ for GPL licensing information. +** +** Contact org@leaderit.ru if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +//#include +//#include +//#include +#include +#include + +#include "atreeitems.h" + +ananasListViewItem::ananasListViewItem( Q3ListView *parent, aCfg * cfgmd, aCfgItem cfgobj, + const QString &name ) +: Q3ListViewItem( parent ) +{ + obj = cfgobj; + md = cfgmd; + if ( name.isNull() ) setText( 0, md->attr( obj, mda_name ) ); + else setText( 0, name ); + id = md->id(obj); +} + +ananasListViewItem::ananasListViewItem( ananasListViewItem *parent, ananasListViewItem *after, + aCfg * cfgmd, aCfgItem cfgobj, const QString &name ) +: Q3ListViewItem( parent, after ) +{ + obj = cfgobj; + md = cfgmd; + if ( name.isNull() ) setText( 0, md->attr( obj, mda_name ) ); + else setText( 0, name ); + id = md->id(obj); +} + +ananasListViewItem::ananasListViewItem( Q3ListView *parent, Q3ListViewItem *after, aCfg * cfgmd, aCfgItem cfgobj, const QString &name ) +: Q3ListViewItem( parent, after ) +{ + obj = cfgobj; + md = cfgmd; + if ( name.isNull() ) setText( 0, md->attr( obj, mda_name ) ); + else setText( 0, name ); + id = md->id(obj); +} + +void +ananasListViewItem::clearTree() +{ + QListViewItem *item, *nextitem; + + // clear tree + item = firstChild(); + while( item ) + { + nextitem = item->nextSibling(); + delete item; + item = nextitem; + } +} + +/* +void +ananasListViewItem::moveItem ( QListViewItem * after ) +{ +CHECK_POINT + aCfgItem temp = obj, temp2 = ((ananasListViewItem*)after)->obj; + QListViewItem::moveItem( after ); + obj = temp; + ((ananasListViewItem*)after)->obj = temp2; +} +*/ + +ananasListViewItem * +ananasListViewItem::previousSibling() +{ + if ( !this ) return 0; + QListViewItem *parent, *item; + parent = this->parent(); + item = parent->firstChild(); + while ( item ) + if ( (ananasListViewItem *)item->nextSibling() == this ) + return (ananasListViewItem *) item; + else item = item->nextSibling(); + return 0; +} + +ananasListViewItem* +ananasListViewItem::nextSibling() +{ + return (ananasListViewItem *)QListViewItem::nextSibling(); +} + + + + +ananasListViewItem* +ananasListViewItem::getLastChild() +{ + QListViewItem *item, *nextitem; + item = firstChild(); + while( item ) + { + nextitem = item->nextSibling(); + if ( nextitem ) + item = nextitem; + else + return (ananasListViewItem*) item; + } + return 0; +}; + + +ananasTreeView::ananasTreeView ( QWidget *parent, aCfg *cfgmd ) +:Q3ListView ( parent ) +{ + md = cfgmd; + addColumn( "" ); + header()->hide(); + setSorting ( -1 ); + setSelectionMode( Single ); +}; + + +void +ananasTreeView::ContextMenuAdd( QPopupMenu * m ) +{ + //m->insertSeparator(); +}; + + + + diff --git a/src/admin/atreeitems.h b/src/admin/atreeitems.h new file mode 100644 index 0000000..1d8dc15 --- /dev/null +++ b/src/admin/atreeitems.h @@ -0,0 +1,88 @@ +/**************************************************************************** +** $Id: atreeitems.h,v 1.2 2008/12/05 21:11:54 leader Exp $ +** +** Header file of the Ananas visual tree object +** of Ananas Designer applications +** +** Created : 20031201 +** +** Copyright (C) 2003-2004 Leader InfoTech. All rights reserved. +** Copyright (C) 2003-2005 Grigory Panov , Yoshkar-Ola. +** +** This file is part of the Designer application of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.leaderit.ru/page=ananas or email sales@leaderit.ru +** See http://www.leaderit.ru/gpl/ for GPL licensing information. +** +** Contact org@leaderit.ru if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#ifndef ATREEITEMS_H +#define ATREEITEMS_H +#include +//#include +#include +//#include +#include "acfg.h" + +#define QListView Q3ListView +#define QListViewItem Q3ListViewItem +#define QPopupMenu Q3PopupMenu +#define QHeader Q3Header + +class QWidget; + +class ananasListViewItem : public Q3ListViewItem +{ +public: + int id; + aCfgItem obj; + QWidget *editor; + aCfg *md; + + ananasListViewItem( Q3ListView *parent, aCfg * cfgmd, aCfgItem cfgobj, const QString &name = QString::null ); + ananasListViewItem( Q3ListView *parent, Q3ListViewItem *after, aCfg * cfgmd, aCfgItem cfgobj, const QString &name = QString::null ); + ananasListViewItem( ananasListViewItem *parent, ananasListViewItem *after, aCfg * cfgmd, + aCfgItem cfgobj, const QString &name = QString::null ); + + void clearTree(); +// void moveUp (); +// void moveDown (); + + ananasListViewItem *previousSibling(); + ananasListViewItem *nextSibling(); +// ananasListViewItem *getLastChild( QListViewItem * parent ); + ananasListViewItem *getLastChild(); +protected: +// virtual void okRename( int col ); +}; + +class ananasTreeView +: public Q3ListView +{ + Q_OBJECT +public: + aCfg *md; + + ananasTreeView( QWidget *parent, aCfg *cfgmd ); + + void ContextMenuAdd( QPopupMenu * m ); +// void deleteItem(); +// void moveUpItem (); +// void moveDownItem (); +// void renameItem(); +}; + + +#endif diff --git a/src/admin/deditpermissions.cpp b/src/admin/deditpermissions.cpp new file mode 100644 index 0000000..9693997 --- /dev/null +++ b/src/admin/deditpermissions.cpp @@ -0,0 +1,82 @@ +#include "deditpermissions.h" + +#include +#include +#include + +//#include "deditpermissions.ui.h" +/* + * Constructs a dEditPermissions as a child of 'parent', with the + * name 'name' and widget flags set to 'f'. + * + * The dialog will by default be modeless, unless you set 'modal' to + * true to construct a modal dialog. + */ +dEditPermissions::dEditPermissions(QWidget* parent, const char* name, bool modal, Qt::WindowFlags fl) + : QDialog(parent, name, modal, fl) +{ + setupUi(this); + +} + +/* + * Destroys the object and frees any allocated resources + */ +dEditPermissions::~dEditPermissions() +{ + // no need to delete child widgets, Qt does it all for us +} + +/* + * Sets the strings of the subwidgets using the current + * language. + */ +void dEditPermissions::languageChange() +{ + retranslateUi(this); +} + + +void dEditPermissions::setData( int pm ) +{ + int r,i; + r = 1; + QCheckBox *c; + for (i=1;i<=7;i++) + { + c = (QCheckBox*) child( (const char*) QString("checkBox%1").arg(i),"QCheckBox"); + if ( c ) { + c->setChecked( (pm & r ) !=0 ); + } + r = r << 1; + } +} + + +int dEditPermissions::getData() +{ + int r,i, res=0; + r = 1; + QCheckBox *c; + for (i=1;i<=7;i++) + { + c = (QCheckBox*) child( (const char*) QString("checkBox%1").arg(i),"QCheckBox"); + if ( c ) { + if (c->isChecked()) res |= r; + } + r = r << 1; + } + return res; +} + + +void dEditPermissions::setAll( bool v ) +{ + int i; + QCheckBox *c; + for (i=1;i<=7;i++) + { + c = (QCheckBox*) child( (const char*) QString("checkBox%1").arg(i),"QCheckBox"); + if ( c ) c->setChecked( v ); + } +} diff --git a/src/admin/deditpermissions.h b/src/admin/deditpermissions.h new file mode 100644 index 0000000..61274d1 --- /dev/null +++ b/src/admin/deditpermissions.h @@ -0,0 +1,25 @@ +#ifndef DEDITPERMISSIONS_H +#define DEDITPERMISSIONS_H + +#include +//#include + +class dEditPermissions : public QDialog, public Ui::dEditPermissions +{ + Q_OBJECT + +public: + dEditPermissions(QWidget* parent = 0, const char* name = 0, bool modal = false, Qt::WindowFlags fl = 0); + ~dEditPermissions(); + +public slots: + virtual void setData( int pm ); + virtual int getData(); + void setAll( bool b ); + +protected slots: + virtual void languageChange(); + +}; + +#endif // DEDITPERMISSIONS_H diff --git a/src/admin/deditpermissions.ui b/src/admin/deditpermissions.ui new file mode 100644 index 0000000..d7c05d4 --- /dev/null +++ b/src/admin/deditpermissions.ui @@ -0,0 +1,218 @@ + + dEditPermissions + + + + 0 + 0 + 331 + 204 + + + + Edit permissions + + + + + + + 0 + 0 + + + + Permissions + + + + + 10 + 140 + 84 + 23 + + + + turn off + + + + + + 10 + 160 + 84 + 23 + + + + all + + + + + + 10 + 20 + 73 + 23 + + + + view + + + + + + 10 + 40 + 73 + 23 + + + + update + + + + + + 10 + 60 + 73 + 23 + + + + insert + + + + + + 10 + 80 + 73 + 23 + + + + delete + + + + + + 10 + 100 + 73 + 23 + + + + execute + + + + + + 10 + 120 + 73 + 23 + + + + turn on + + + + + + + + + + Ok + + + + + + + Cancel + + + + + + + + + Qt::Vertical + + + QSizePolicy::Expanding + + + + 51 + 114 + + + + + + + + qPixmapFromMimeSource + + + Q3ButtonGroup + Q3GroupBox +

Qt3Support/Q3ButtonGroup
+ 1 + + + + acfg.h + qmap.h + + + + + pushButton1 + clicked() + dEditPermissions + accept() + + + 190 + 30 + + + 20 + 20 + + + + + pushButton2 + clicked() + dEditPermissions + reject() + + + 190 + 67 + + + 20 + 20 + + + + + diff --git a/src/admin/deditrole.cpp b/src/admin/deditrole.cpp new file mode 100644 index 0000000..679bd5c --- /dev/null +++ b/src/admin/deditrole.cpp @@ -0,0 +1,50 @@ +#include "deditrole.h" + +#include +#include +#include + +/* + * Constructs a dEditRole as a child of 'parent', with the + * name 'name' and widget flags set to 'f'. + * + * The dialog will by default be modeless, unless you set 'modal' to + * true to construct a modal dialog. + */ +dEditRole::dEditRole(QWidget* parent, const char* name, bool modal, Qt::WindowFlags fl) + : QDialog(parent, name, modal, fl) +{ + setupUi(this); + +} + +/* + * Destroys the object and frees any allocated resources + */ +dEditRole::~dEditRole() +{ + // no need to delete child widgets, Qt does it all for us +} + +/* + * Sets the strings of the subwidgets using the current + * language. + */ +void dEditRole::languageChange() +{ + retranslateUi(this); +} + + +void +dEditRole::setData( const QString &s ) +{ + lineEdit1->setText(s); +} + + +QString +dEditRole::getData() +{ + return lineEdit1->text(); +} diff --git a/src/admin/deditrole.h b/src/admin/deditrole.h new file mode 100644 index 0000000..2d94e37 --- /dev/null +++ b/src/admin/deditrole.h @@ -0,0 +1,22 @@ +#ifndef DEDITROLE_H +#define DEDITROLE_H + +#include "ui_deditrole.h" + +class dEditRole : public QDialog, public Ui::dEditRole +{ + Q_OBJECT + +public: + dEditRole(QWidget* parent = 0, const char* name = 0, bool modal = false, Qt::WindowFlags fl = 0); + ~dEditRole(); + + virtual void setData( const QString & s ); + virtual QString getData(); + +protected slots: + virtual void languageChange(); + +}; + +#endif // DEDITROLE_H diff --git a/src/admin/deditrole.ui b/src/admin/deditrole.ui new file mode 100644 index 0000000..1283988 --- /dev/null +++ b/src/admin/deditrole.ui @@ -0,0 +1,72 @@ + + + + + dEditRole + + + + 0 + 0 + 394 + 99 + + + + Role name + + + + + + + + Ok + + + + + + + Cancel + + + + + + + + + + + Role name + + + false + + + + + + + + + + + + qPixmapFromMimeSource + + + bOk + clicked() + dEditRole + accept() + + + bCancel + clicked() + dEditRole + reject() + + + diff --git a/src/admin/dedituser.cpp b/src/admin/dedituser.cpp new file mode 100644 index 0000000..8c86bae --- /dev/null +++ b/src/admin/dedituser.cpp @@ -0,0 +1,90 @@ +#include "dedituser.h" + +#include +#include +#include + +/* + * Constructs a dEditUser as a child of 'parent', with the + * name 'name' and widget flags set to 'f'. + * + * The dialog will by default be modeless, unless you set 'modal' to + * true to construct a modal dialog. + */ +dEditUser::dEditUser(QWidget* parent, const char* name, bool modal, Qt::WindowFlags fl) + : QDialog(parent, name, modal, fl) +{ + setupUi(this); + +} + +/* + * Destroys the object and frees any allocated resources + */ +dEditUser::~dEditUser() +{ + // no need to delete child widgets, Qt does it all for us +} + +/* + * Sets the strings of the subwidgets using the current + * language. + */ +void dEditUser::languageChange() +{ + retranslateUi(this); +} + + +bool +dEditUser::check( const QString &login ) +{ + if(usr->sysValue("login").toString()==login) + { + return false; + } + return true; +} + + +aUser * dEditUser::getData() +{ + return usr; + +} + + +void dEditUser::setData( aUser *user, bool isNew ) +{ + usr = user; + newUser = isNew; + //usr->Select(); + if(!isNew) + { + lineEdit1->setText(usr->sysValue("login").toString()); + lineEdit2->setText(usr->sysValue("password").toString()); + lineEdit3->setText(usr->sysValue("fname").toString()); + lineEdit4->setText(usr->sysValue("lname").toString()); +} +} + + +void dEditUser::onOk() +{ + if(check(lineEdit1->text())) + { + if(newUser) + { + usr->New(lineEdit1->text(), lineEdit2->text(),lineEdit3->text(),lineEdit4->text()); + } + else + { + usr->setSysValue("login",lineEdit1->text()); + usr->setSysValue("password",lineEdit2->text()); + usr->setSysValue("fname",lineEdit3->text()); + usr->setSysValue("lname",lineEdit4->text()); + usr->Update(); +} + this->accept(); + } +} diff --git a/src/admin/dedituser.h b/src/admin/dedituser.h new file mode 100644 index 0000000..e7ecd4e --- /dev/null +++ b/src/admin/dedituser.h @@ -0,0 +1,29 @@ +#ifndef DEDITUSER_H +#define DEDITUSER_H +#include "ui_dedituser.h" + +class dEditUser : public QDialog, public Ui::dEditUser +{ + Q_OBJECT + +public: + dEditUser(QWidget* parent = 0, const char* name = 0, bool modal = false, Qt::WindowFlags fl = 0); + ~dEditUser(); + + virtual aUser * getData(); + +public slots: + virtual bool check( const QString & login ); + virtual void setData( aUser * user, bool isNew ); + virtual void onOk(); + +protected slots: + virtual void languageChange(); + +private: + aUser *usr; + bool newUser; + +}; + +#endif // DEDITUSER_H diff --git a/src/admin/dedituser.ui b/src/admin/dedituser.ui new file mode 100644 index 0000000..b7a15f6 --- /dev/null +++ b/src/admin/dedituser.ui @@ -0,0 +1,135 @@ + + + + + dEditUser + + + + 0 + 0 + 414 + 246 + + + + User + + + + + + + + Login + + + false + + + + + + + + + + Password + + + false + + + + + + + QLineEdit::Password + + + + + + + First name + + + false + + + + + + + + + + Last Name + + + false + + + + + + + + + + + + + + Ok + + + + + + + Cancel + + + + + + + + 20 + 141 + + + + QSizePolicy::Expanding + + + Qt::Vertical + + + + + + + + + qPixmapFromMimeSource + + auser.h + mdtree.h + + + + pushButton1 + clicked() + dEditUser + onOk() + + + pushButton2 + clicked() + dEditUser + reject() + + + diff --git a/src/admin/dselectrole.cpp b/src/admin/dselectrole.cpp new file mode 100644 index 0000000..3bfd312 --- /dev/null +++ b/src/admin/dselectrole.cpp @@ -0,0 +1,80 @@ +#include "dselectrole.h" + +#include +#include +#include + +/* + * Constructs a dSelectRole as a child of 'parent', with the + * name 'name' and widget flags set to 'f'. + * + * The dialog will by default be modeless, unless you set 'modal' to + * true to construct a modal dialog. + */ +dSelectRole::dSelectRole(QWidget* parent, const char* name, bool modal, Qt::WindowFlags fl) + : QDialog(parent, name, modal, fl) +{ + setupUi(this); + +} + +/* + * Destroys the object and frees any allocated resources + */ +dSelectRole::~dSelectRole() +{ + // no need to delete child widgets, Qt does it all for us +} + +/* + * Sets the strings of the subwidgets using the current + * language. + */ +void dSelectRole::languageChange() +{ + retranslateUi(this); +} + +void +dSelectRole::setData( aUser *user ) +{ + usr = user; + listBox1->clear(); + listId.clear(); + Q3ValueList list = user->getRoles(false); + Q3ValueList::iterator it; + for ( it = list.begin(); it != list.end(); ++it ) + { + listBox1->insertItem( (*it)->sysValue("name").toString() ); + listId.append((*it)->sysValue("id").toString()); + delete (*it); + } +// delete list; +} + + +void +dSelectRole::onSelect() +{ + if(listBox1->currentItem()!=-1) + { + printf("add role\n"); + + //emit( addRole(listId[listBox1->currentItem()].toULongLong()) ); + roleId = listId[listBox1->currentItem()].toULongLong(); + usr->addRole(roleId); + listBox1->removeItem(listBox1->currentItem()); + accept(); + // new aListViewItem(p_item, + } + else + { + printf("not selected\n"); + } +} + + +Q_ULLONG dSelectRole::getData() +{ + return roleId; +} diff --git a/src/admin/dselectrole.h b/src/admin/dselectrole.h new file mode 100644 index 0000000..63a0652 --- /dev/null +++ b/src/admin/dselectrole.h @@ -0,0 +1,29 @@ +#ifndef DSELECTROLE_H +#define DSELECTROLE_H + +#include "ui_dselectrole.h" + +class dSelectRole : public QDialog, public Ui::dSelectRole +{ + Q_OBJECT + +public: + dSelectRole(QWidget* parent = 0, const char* name = 0, bool modal = false, Qt::WindowFlags fl = 0); + ~dSelectRole(); + +public slots: + virtual void setData( aUser * user ); + virtual void onSelect(); + virtual Q_ULLONG getData(); + +protected slots: + virtual void languageChange(); + +private: + Q_ULLONG roleId; + aUser *usr; + QStringList listId; + +}; + +#endif // DSELECTROLE_H diff --git a/src/admin/dselectrole.ui b/src/admin/dselectrole.ui new file mode 100644 index 0000000..567fbb3 --- /dev/null +++ b/src/admin/dselectrole.ui @@ -0,0 +1,71 @@ + + + + + dSelectRole + + + + 0 + 0 + 445 + 312 + + + + Select role + + + + + + + New Item + + + + + + + + + + Select + + + + + + + + 20 + 201 + + + + QSizePolicy::Expanding + + + Qt::Vertical + + + + + + + + + qPixmapFromMimeSource + + auser.h + arole.h + + + + bSelect + clicked() + dSelectRole + onSelect() + + + diff --git a/src/admin/dselectuser.cpp b/src/admin/dselectuser.cpp new file mode 100644 index 0000000..a1d7917 --- /dev/null +++ b/src/admin/dselectuser.cpp @@ -0,0 +1,89 @@ +#include "dselectuser.h" + +#include +#include +#include + +/* + * Constructs a dSelectUser as a child of 'parent', with the + * name 'name' and widget flags set to 'f'. + * + * The dialog will by default be modeless, unless you set 'modal' to + * true to construct a modal dialog. + */ +dSelectUser::dSelectUser(QWidget* parent, const char* name, bool modal, Qt::WindowFlags fl) + : QDialog(parent, name, modal, fl) +{ + setupUi(this); + +} + +/* + * Destroys the object and frees any allocated resources + */ +dSelectUser::~dSelectUser() +{ + // no need to delete child widgets, Qt does it all for us +} + +/* + * Sets the strings of the subwidgets using the current + * language. + */ +void dSelectUser::languageChange() +{ + retranslateUi(this); +} + +void +dSelectUser::setData( aRole *i ) +{ + Q_ULLONG id = i->sysValue("id").toULongLong(); + listBox1->clear(); + listId.clear(); + role = i; + aUser *user = new aUser(i->db); + user->Select(); + if(user->First()) + { + do + { + if(!user->hasRole(id)) + { + listBox1->insertItem(user->sysValue("login").toString()); + listId.append(user->sysValue("id").toString()); + } + }while(user->Next()); + } + + +} + + +Q_ULLONG +dSelectUser::getData( ) +{ + return userId; +} + + +void dSelectUser::onSelect() +{ + if(listBox1->currentItem()!=-1) + { + printf("add user\n"); + + //emit( addRole(listId[listBox1->currentItem()].toULongLong()) ); + userId = listId[listBox1->currentItem()].toULongLong(); +printf("addUser()\n"); + role->addUser(userId); + printf("user added\n"); + listBox1->removeItem(listBox1->currentItem()); + accept(); + // new aListViewItem(p_item, + } + else + { + printf("not selected\n"); + } +} diff --git a/src/admin/dselectuser.h b/src/admin/dselectuser.h new file mode 100644 index 0000000..e4c7f3d --- /dev/null +++ b/src/admin/dselectuser.h @@ -0,0 +1,31 @@ +#ifndef DSELECTUSER_H +#define DSELECTUSER_H + +#include "ui_dselectuser.h" + +class dSelectUser : public QDialog, public Ui::dSelectUser +{ + Q_OBJECT + +public: + dSelectUser(QWidget* parent = 0, const char* name = 0, bool modal = false, Qt::WindowFlags fl = 0); + ~dSelectUser(); + +public slots: + virtual void setData( aRole * i ); + virtual Q_ULLONG getData(); + +protected slots: + virtual void languageChange(); + +private: + Q_ULLONG userId; + QStringList listId; + aRole *role; + +private slots: + virtual void onSelect(); + +}; + +#endif // DSELECTUSER_H diff --git a/src/admin/dselectuser.ui b/src/admin/dselectuser.ui new file mode 100644 index 0000000..9e7cd99 --- /dev/null +++ b/src/admin/dselectuser.ui @@ -0,0 +1,75 @@ + + + + + dSelectUser + + + + 0 + 0 + 602 + 348 + + + + Select user + + + + + + + New Item + + + + + + + + + + + + Select + + + + + + + + + + 20 + 200 + + + + QSizePolicy::Expanding + + + Qt::Vertical + + + + + + + + + qPixmapFromMimeSource + + mdtree.h + arole.h + + + + bSelect + clicked() + dSelectUser + onSelect() + + + diff --git a/src/admin/images/administrator-splash-en.png b/src/admin/images/administrator-splash-en.png new file mode 100644 index 0000000000000000000000000000000000000000..5f1d49b536fd09ee108ebac8d401723036d5287b GIT binary patch literal 100739 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

;rJJjQ_%{lYj&E3>kL}q}wl@;Z9pf#EL>(z6 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πsy4To=rNe7L}%|+ogzcI>!^!u;sh=Fx3 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 s+R-XZ)}K-6BT4`EgM^gJDwL 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¬M6UK& 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 literal 0 HcmV?d00001 diff --git a/src/admin/images/cat.png b/src/admin/images/cat.png new file mode 100644 index 0000000000000000000000000000000000000000..3c1ae0f5f5bd21107cd4b0840936a705bbbc1f91 GIT binary patch literal 401 zcmV;C0dD?@P)CjQBW(3gGkIg?Y}rt@iyu{tV7@W`;p} z_ZVZwg-5|_qoWBeoP-W9Y?Ps@f9zg~+1Nb<$ud>bl15w#+%_*xNxU z;S6?7Ipk0P5*TB?J-{>T7}NtZ v#*WB(5rYEG*DX!S%Lf>Pdf@+#)Bbr6u%@REt8=nw00000NkvXXu0mjfRRy-l literal 0 HcmV?d00001 diff --git a/src/admin/images/cat_g.png b/src/admin/images/cat_g.png new file mode 100644 index 0000000000000000000000000000000000000000..9e6bc8ea8cbe58ef6d7c91a7ae286084fe8ad5a9 GIT binary patch literal 697 zcmV;q0!ICbP)QbaO!mz6&u=szgc zg%}8JSAwYc2MQHe+NFYE2$WX3P#UNsxJU+-WMLr-q3xnL7cyiHG%zlvlgT8L`b7_1 zE@!y&ocFxyO2vm1xzro5p{Gi$yDFHl4&b%d&!D_(briqCYJd z!Hu-dOIK82b=4VLI~eA6oTr)qy{l=-3Or83*rlsc6J@dA^7|Z#O3zVOSn9TLII#ID0Ej)=i~Kq z4Aok7T=DQdH%$V=FhE=ypPF!Kj<>Hi@$o@Giv|H#+(f=`cL5WVl?N+HE3(-qN#z;E z!`C)1stpc~4p2%#U!V`J=OQ9#t?|W2yBhI?>PD51b|XH=rb!S4k7Cb^$85gaLd_JB zzMudRLa2nki%4k0$=vv6)7on#t*|U>Y(v&J+B{u{fb5SWY8U<*H?Z6N7&R&NPyY~3zMaLwH>1i`q zURtL8wTUtn{)y*u;<5Ol;;2Zw-DZE^9WYYgV}Kji=YrWQvxCwKg%Em4Kb(B=0nnbt fJ#uNaIs@=8gNQgJv}Px200000NkvXXu0mjfz-l^6 literal 0 HcmV?d00001 diff --git a/src/admin/images/doc.png b/src/admin/images/doc.png new file mode 100644 index 0000000000000000000000000000000000000000..61334f2cbf6a35cc5c57c5537af017b3b7addafc GIT binary patch literal 456 zcmV;(0XP1MP)5$d`I0G!X~MYy$NB7);MI2;bhvTR(7;}}8+1HK4;FW`{m zcs!yg3fyitNGZql=ksYW*tGLFXH*o00ai*u2!TA$A%sBJbz{ObO>w{9@zt?X%D8ew z1mE`&h9QC=nB9@p84ovL8m{YNzu$jop6A(tyRKUVFB!3Rtd!aY{1?a5daM?26UUo@ yhqvM1!EM_jNfK*tRaJJK_v?4`-g#`R&-4YJRw>fn=4>7fJ5?(EDy z-#hPo`%O@*IsQlM2gqiFYw5L`3;qS%*L<+ndRG)hRI63CwzkOSay9{fGDklhPHAglZxJsqc0k+m6rR4PV6e%V3dOZzzbaceV#zxot_B?J+ zIp-XMgM;L9IYviEFI`c$=2_9q008x~%Jj^vH~Dj64}hJw?*N#boV*@fuh%{B^vo>3 zUOi&?-V}rq`Mu0YTOeqagLX?i#nxKyqv5+#pd?tsaK_-a^Ia7NZ5h(l3IL1&Ygk-) z4!6e<2mr*OK>ap|8?C7e4;H+7;%#2LVvJ<}(*fKXXY0i-8Vv@NQD8tC>Gksu^JK`d z_IT|YaKGTm%L31~_o$H^Z-v&H!^1-lytz~2>E?TMDA7WY=?85zSWw}G|JrD% z8&s&M{-{#?QVu-u+}s=;ZEObmp?a>kDFh0I0F-IjfxhUMkIQ`cSZKKjmmfPLBN?~4 zvP$Xe0U{&N4bM%(W1}w=H-nT)CC<)d$_ct1rqlPwUG7dUU6VjyXcV5t9&4ikP@zJe eONzyE3jPC1VC6k=Vuw=z0000!lvI6;RN#5=* z4F5rJ!QSPQfg+p*9+AZi4BSE>%y{W;-5;PJdx@v7EBh4|VIe8DExVg;FfcF*c)B=- zRNUG+b#HHrfk5kgeia_m02a{zW=77d3RMf(nS`VioT3C39!@ahh!AF|zBsS!d)oPA zS?h_py>|P5Za(_8>ahA7Zh52cUlll73|ln1PJBL{D)N16g|DkX$88he8{2x9pd7f@cC>|F&Cycgd8n z#9-%7%O6!A^=IC_uG_@-=7B_sA6>G?6Z}%Ip5xvG3%JrG?kO*e@Wl?(fKNE>eg&va4~qg`njxgN@xNAx}l=_ literal 0 HcmV?d00001 diff --git a/src/admin/images/journ_g.png b/src/admin/images/journ_g.png new file mode 100644 index 0000000000000000000000000000000000000000..8739e8d11353d384dfc490f77c79dbceb8ab3255 GIT binary patch literal 671 zcmV;Q0$}}#P)`%nh!%JUniSaD&p8Ml- zzW1E-uIhF}{)c4%ayd1WJ~K0uI$x{psI+<2?S|xXDr~pg1VJ#eqV4T%ipAnU_>FjQ zetteObdpP%pBTq>1@2JHi1t@L#ue+BPoLUje6 zycN5+S3EX0=E@L{`sW?E zJI&kIn^-Ie7%?E=iRbtWPZr3MW%=2%3lM~7lmnido1@PrA3+9=jt#f9#$eEZ zk;`;oBfqoP;lsz8TfD8UEvnTjl}aU9Xt&!eEiTdewu8=UY%k~1%dyx^2 literal 0 HcmV?d00001 diff --git a/src/admin/images/metadata.png b/src/admin/images/metadata.png new file mode 100644 index 0000000000000000000000000000000000000000..b5c894955bd8a55e7a0e3cf2430a8515c4f8df3f GIT binary patch literal 1354 zcmV-Q1-1H#P);5hr@0^`?Tj{pAsOJMlNkpKVR zzlr}D7#6%+=l%ho!2kiog3OVMKUnbpKf?u}W`j@a$_zifMHqfda2s%(e*T{E?Kg&x znZ^w4r=In5?zkfWRNjEkV1NK(L^kxBzIgwCpvmml-h6l$V<7NHfro+V=RXFHH$NE| znHU-Vu`@CJWcbU#GxgL5rq|yZ|NZ;_f#LuE2cNe296&c1Ab{WoOU4~M|2*B!fI$Qy zDRTHVgYcDi49rY_8JL(E8Ccj@7+3_k7~aSO@vUbJzj@dgm@hqNV0!W~@ykxX1;_>i z1P~L9@spX~fMElW@fL`G0S!IynnC>TI|eSnKMd^r{~1_${xLAJ{bKn0^#g~p7D^1itQCQd{%?=&Vt@c*fyMs+U++I~e19SEgG~Zx3j>4by^joh3ak(Q{bAm~ z@Sou$FevmHnHe1z85sq@Uj6lz!TLT6!>NBv4B!9#7eF@{Ab`LI|Ka60|6N_2fr0lw z*tJ}*zcX;~vm9XKXAL|UB?FIr`(;lAm{^$V8Ce+%K>WWz#rpih42R8?0yzGzTMvx% zgFg?3OaRFN1Q4Tmh13tRGmoSQwc8GlKOnZN3UJcp^w1Ab^-&uXK69`r{n~ z&-<$k9N!-@FuaEt{E3yF;e{Y?fZMFs^RXGcLXr^__6OL0F*5xA%gDfZ_ca5a6WYHCkJ%HIlnMG z_yaWl`a1@O|6-yHf1OPY{w*If?Mg_m6#Ze64V*JOT%lVr@ zp6CAq9!{nMtZd8=Sy-9;AADvsIQ#7XJ65rFABuKNMx9~oq=JO7b8Fb!3!aNpREqR1vnTO%OwVeH}Amd7$AU{;aU3DvIm?(z6$>&I1NAsa;!PQ z!1U}L!#@LH;UNoD_7K@?Kr9Y*A<#^Q=fHAc4$!4f-!EV|7n2E60uVr`LE*7U;Qzn> z`#~if5G4ZH2LCx(`hS+&3jDv!k5K3i&9mQu_%PI0D}e>gp+LBK00Bf0vD>Y2VD7*A zpJ5Zws>T2RGv(g=&up>cJY(63{|pa-VkbdPIQE~xXbDQ12M8c0LI#6e4+i=`tofCJ z@!Hh~KtV@_efKsn?7zpru=+Ry!^L}`ASguE2M|Ck1Pulj=8W5KKVZJ{QsMuXUkv|0 z{|x+hD)Iw^@zO$uNykA-CISt`DChwKh-k!YzFdIGY`Fok>Hz`_06+A`+)vkOxc~qF M07*qoM6N<$g1Pf^2mk;8 literal 0 HcmV?d00001 diff --git a/src/admin/images/reg.png b/src/admin/images/reg.png new file mode 100644 index 0000000000000000000000000000000000000000..bab93ceaaf420679b6640b8e3aeaf2893a07ea68 GIT binary patch literal 425 zcmV;a0apHrP)3Vh@8Zr*FkdjdbL`JL!rOv^3UyN)(KfD4LMMVh7nc%Fxp5~Y+ekK-621f|mcdoPzu z09@Av!1sMRosK@>Q^z30vvGQoJW{Q`SXRT~EzRb;G3)iNjAvbiQi{!HgXeiH77J~h z+a61;Rs&!#7|?FFzq=K-@oe^RwsF6IbJ}=5pBtOvIM!y<>69$X^t-&{APCMk9*^&- z*IzB;Fl^Ciy!~iwfYbEJFiw($Fl<@iEX%C9@B7EWUyVnjJIm}`W8HCnUni3Z>-E~$ zR4$i|S>AEpFP!K&iXy$2AXsC;L7@c)DM4u63NGy*An54U zf`ceX+eINz=-?k<-E2n%!BlChQ@f~jqAFB{c^cXG#aI^&wJm8hlc=!!(jlHmzPPUQhtLI8ACMsBGBEK zrz8?D+o*E6yNrx{4D8L%UkKEG6t3%XbaX@{5y}do^^}2u7%y@Hi^X$a!v+dRE8+Vu({}MP^cy%RE z2aIdAXFhQvk)ZPK5&g+gsA_bv#N`K`@x(YCw9wu7G;#mUQ7{@BLVrwf)03SX0kG~p z4%W?#oAbK8y^Z5IB$G+p9}6Iw`_qeXZ5V|DKwVUrzk&+4jHC|f59!Xt#bPmtA)4&> z99$jd{hKu$91t*KKtPKQ)RPYtSh=b7vsS4?pG~Y5=D+I0Y`=sJ=%U%2Y2{kx|Gz0~R;F*e-yNGxfJ6^NDGvv4O z?NOZ8(n^8(rFERD#!-q`2pn;s0j4U@5U;KarfS&zvrGPGseO*yG&lw!*xff=QVN4X z0Y+MJ;COXutHj3FOe@81o=PcZre`Sp%AsNk=QwjY&R86exY?voD6q4m{Yb5DKhxW{ zhTWkXLw;+8Lh!Pr;Vq6h0GO&l?`!h;l5hMEMMzob=Y~;L00000NkvXXu0mjfX$4Pt literal 0 HcmV?d00001 diff --git a/src/admin/images/regs.png b/src/admin/images/regs.png new file mode 100644 index 0000000000000000000000000000000000000000..cbc44196791d624960e64b923d64f8da5301f127 GIT binary patch literal 433 zcmV;i0Z#sjP)I?ZB9zkHqG~sx0`~xo zhNw(iDJ={*tw{ygj3JcLsqv%&>4`AL8Mva#MR7Wv0I1jND5cO^TmAKVjqAG9YU%sl z@Am*Wjsrjt1dPXHGvFd)aNTEX`fm3`tM!tz3d11}5ARlQI=!>jCJHTO>GnR_?b3Ul zP6vSbe9mYz%15#A{lW)5De3p$el(uVy4Ko&J*ipv0v&3u(qBr$T&ReGBSINgT%joX=+*$FYEAb+b=e{J9_f bKiJe4&jYf@?6s&(00000NkvXXu0mjf;Sa%o literal 0 HcmV?d00001 diff --git a/src/admin/images/report.png b/src/admin/images/report.png new file mode 100644 index 0000000000000000000000000000000000000000..0c4bb0c066fce2757147c499a69c38e4b65803ba GIT binary patch literal 636 zcmV-?0)zdDP)g3vw)0+dpeN+l|l z3Z|J-Ns-5bl~N(_lU}daaa}hN9toCGhQLxvq?7=x*K2CES|U6WY~J04v=iXFQYfWZ zuh#%ntJPR|Ixa_TAwt?2kiEWUI2>wC2!Z1`A$aPrK}<8H=JPrEUXQjAe13e?Q4R(J z8jS|acVh0pi7`jmw7Z-Yccm%{o{AE7ZK0fsG$^HFak^dV`=twPTuJMXpEQDRH~uki0000AReK(Ue z?Rs!vn0ekGpXWQ@_nG(g`hCm)ag_in74Mbwe&2fk1^n9Z#TZk#lO&0m%^Zk8T$B6IT^B3=4G}0QQG_?EU3>uVHph0Rm7MCe=_mjKDA7m*EM?nxkN$}~Hbw1zPqtojkgaD(#fQ%$sYm`#N zIz~x_jx<}_TkO{NJO}<|YKk;X3%))4`YXiM1+>u!2F_s4lp2lJ8o)jG{;1P<+9-M) z$1(f+`vvg*?I!o`e@7fiVj(D(Al5M$P|?8uSjUiRRHW!0b!q(8_6p#|#l?#Y4ObVS z1l^wE4Ixk{1fcZD4&p)Fe%j{ypXzRE3I6@qnVl`$JGbx9{QWVaEQkS00)6JOjt7c| zNt(?j&!0=j@h&?|KY0JT^{@Hvn*;*Qz)Q@TeL4m}MGD!IG#YIO{s(y7?%IDqdmsP+ N002ovPDHLkV1hNWh93X` literal 0 HcmV?d00001 diff --git a/src/admin/images/role.png b/src/admin/images/role.png new file mode 100644 index 0000000000000000000000000000000000000000..eb4da7f9e1023c8ea899180ae717a9dd56cdb70b GIT binary patch literal 1507 zcmV<91swW`P)MLDa6m#rTsU(9 z4gp0dEE0kc!Wuv_Gs{wQoG+$%zW?;X!fRQU9aTzQz!7Wy zo0OHw&6{6oInG_{OC@j2vizMw_)id(c1g+4)M{u;i9P*3C(f&jo;Ou%w|Drye=?5a zQ(9|tp2aVQbI!40!-n-z%59l#!(O)zMhF}yLc%!;0I?8wD+sXU`*?O`1@|Ng<3zhE zmCEbmo70?+f9?Kqv0AlNw?1kbmG*s<&O+j%<(P+3^OlrczZHJp_a<7tX& zQDAEnK^6r*c3sR{76W4~$8qlTJgO17Aes(23%`Q4Tsp5W%w~oaSah34nuSqgO%s#Sr&eG9E=wQ zuFi9~#-QLF1h9U;f3Vx_9y7)`Vq>SXZ=35*J{JUHo8!O-z>Gmu6nH;P@n({M5n&U6 zox>rvBnc*y1TkaysL{Yp%gZpvV3{$Tu`FalxOS=JYpoAPQS`HPIS({|e0AUy5q`~c zyxs5PV3r{zLdqC^B*Gm4$^aM4#rSL!;Z2A~1}M3}d2eA;M0X^j=jLOsusa*h=tKw6&y zaCSHx{vOBiP)3{&KIGi{#Ijg<{dy?d1}_RUW@hk=ZG(tV*BZNxfzTSWoMQmsx+H;8 z3MFIkr<8cNTE&3#AtUm&)-zd_eLENoPRfF@5AsIiQQ^9vB*FNJ6OeI?Tx&?i5CGW3 zIZhgbuQ|tA08b5vD8(^4Q3OwGyjL#cE8hnJg;Hw9w(U(}7$#Yk{VC_>=3ZP{S~?=7 zoL=X;Hw({`p;GzJNfHi>$r_e5+UC4OL~O_yo;3z-A_VI;&X^o8B(yiB@EZO!AQ$%8`F&B(~ zk8`xOhDC&&F`lOBSKV&+hdj@Z0e}QR#+WpY<0Ek#zp(1129N;APA@DRPLt$7XKd_M zi?O?p0dTa&$g1IIg}~>o3w$v3}ze$8Rw2|+c&matt3g3pZKK;0QfBj7H2t!5dz*n7K=lKt!av}JpbG5IF3iM zEUU`@A>eSp+Gz}KHU@+XwiR8KW%}vG#rWlF_1iC_Xm7N#a!4t)a_It$Z5{zC_Zl-i z&bjF@1_#I!qUeOy-J?bE-GRa2&=8aTI(4`xjvdu{$q)?y^a1GeT(*Dz{!4lQ5y22i0xSSbp92^M7y%f;m|Cmv zFO^KM=vNQ9Gynhq8FWQhbW?9;ba!ELWdK2BZ(?O2No`?gWm08fWO;GPWjp`?002ov JPDHLkV1lx!sht1- literal 0 HcmV?d00001 diff --git a/src/admin/images/user.png b/src/admin/images/user.png new file mode 100644 index 0000000000000000000000000000000000000000..ccb0df58550e7583d4e1e0282d06425ff6eb19cc GIT binary patch literal 1267 zcmV<9XpHXs58SylY=|3w#ErTzabZl1CMHH*32vZ? zMWGaVDMA4I1885{*S=r($GEt!^wAXRNzR?QcXGeqbI$ji5o~Q8Lhx2falFxINPsMq znOd#zleK&UiKEOwBS@s&W!I1r&gIBY^V& z@EykEv(blnY0q|CUxDi+ZWL_G;G_+`cM9wcBCY|`K;{1uI70B=qdmMc(1jENtcA68 ztrjf}pgr1W@?@=L61Y<<*Oml(x?1>P-%i>cdGCSiKvxS4^}t9kJiQyP%+Wr($TTno ztkmn_-iP48^CLWTbQs33LVhKQyg3c~`(bc9G#FSTKRig|xvLxiegkd+r3Vst4ts`r z(FY%afo`}t4`Bq|S?Fj^I>Xl7kw zNeRu3;JKvB0j+?~dJLNq#8FJS8iDIVSl4(Pd)nG0gK7j(j0Mz2T{k1J)sX8q=81)i zbnCiijlkZ0BpKXTfO3^$t%L5F1&FyLhg}6|lT2IQ&?|{z1#xzu?RzmVoQPY)#<1 zN^O?GHV|(V%gwt!{h^Wb*WmXFhtm_1;a!#|`eO1+@a-v=bN|3c-#4(dn)N|;1EvOk zSFU>91aJg0@5AU3*sEcIeFHypX!sVtj=6-9L<%SrEhBv)iz`{ib1&d|JxF;m41zNg zQ9S=K@FS21BBu`gIP`u3uRIB(E@Xf_N4lYi>k6VM!}xfG z+~pON=aMoS-)K_CM~K_}JNHF?Y32Nfz}EukgvPJn^<^q!g6PA=X-a ztwLuzr>InOOirDgDph7rIKZ3m_`7gGtqKvq$=(<|_+9Y7UPK4GPuRU~RP$ z#pPlYl?!0+)b693z!l)~e-`d~*d=ULUjP6A9dt!lbVF}#ZDnqB07G(RVRU6=Aa`kW dXdqN*WgtgMO;GP-C2jx!002ovPDHLkV1grwLk9o= literal 0 HcmV?d00001 diff --git a/src/admin/images/users.png b/src/admin/images/users.png new file mode 100644 index 0000000000000000000000000000000000000000..211f7a97c86496ca6076242878565a3b3aae4141 GIT binary patch literal 1498 zcmV<01tt24P)f_M=y>KJvM_$L}TJ ze1fnIJO;c7%mI3KW_oUZ_E@P?dmm*iFa{+%|`;4JVu z@JtUd*W7KDnzdVEMqI{QT@ZWKi@4PVIvejZJaNKWUTvwxrR#43`}YIP13&AXz&e|J^iAN`jjtHf}k2P6G z(4V&OW6g!7CQnpyj18tSDj|*&0^eh}RPIlwouO_J{qGo9g3=?C>FiIQDiUjpmapkg zK`{##R=QkRji@!djOIbcinbf$BpDM$($>b@^^)!a6tbfKtDnhar-xEx(>9h6$V4Hf z;>1Xb8!bf`C8$Iah6&ZWZ&Hy6_B(B*los~|WE^3Q=Pi^}gj!<>fz}$OG=o{lryvYt zIvtCv8zFDp3`GB#FuT6iu;M75={;-j6N6mHis>&MPdz!77wIdTF$*`lthXeEGz3y{ zsi|3!uvC|vZ)$GjGmPeo;_{Vc+bZ|XCXpVF+;ACa-xCl?lNs(aUmNbT#;(<4iaFSJ z6??uWQiea|}@7E2R+wHk-?JwsWo+d#s$FoSu4gcfHjYx#8PDbQmyWrLr%X z{LwGxZCSY02t_L}Y_t`AY*_a4)N+G31(^Tr47qZaI2|L4274$)K!8)S?a|`+)Yg^F z4WrFR2LK_2_{RK0pZ~?vFMRiv%9&@2*PEL4T0^YvblDA4sG*Y#%sojde-iIjK&xIy zj2lEjU}Y?@z+ebvNMdAvXVvu*SN_uhaGcar51;=lV3P19)IF2 zqj^Cj4ZCrM#(qSkU}R#N>hdCMf4xNJG^CECFv?&OgI1buH^e{=$l5?*a%%dg&%ONW zH|ZM{ZMRFJ6b8YG=_y`#_AKSe2dM7&G}=B=X|xaw92vo@d$jjAafU362H8!JjU?$@ zbsOIG&Yyt4JHW(P`Pf6Le2LwThXE|h!WhGcH`n>%scBkXOry2W;6NY8$4e|Nud(BG z89i2EdvS&O=GLA_S+4YAH`(mJ2_(Z7O(vQcn9!-J)j2c0-*!+$BEAQK|~Zq*tU%j z0wDw@k*wC5G&>RduE+UzKj7Ryt`deZQpO}nf-xol7J>6X49GiL;sDutqsd@v4`VQv zeLFoM1S*j%f4n6^iE;e^r4%YjND@UHMZ#_Gu)n>w1XKYR2m#IQnqUr6#f@9nE}yge zhRzI>#vH9;V>>BJ2um2iZEd5p5m6*DfReEeyml0afwg)4-MZJR{jmp#faLJU6+j87 z*iQP4u&if{F&QC*_1{_`#BFB;x4kmjXsrz9J)OwE0sjIvfG&rs*#W=;vOqu3*XyTy zX~gcWi{574^D+X0UQoMtTn+aE{HGM$A!^?-J`6a39JG51AK1SE&#b+a9p^Kf0000T zbVXQnLvL+uWo~o;Lvm$dbY)~9cWHEJAXI2&AV*0}Q14_VZU6uP07*qoM6N<$f|BFO At^fc4 literal 0 HcmV?d00001 diff --git a/src/admin/main.cpp b/src/admin/main.cpp new file mode 100644 index 0000000..db9ae79 --- /dev/null +++ b/src/admin/main.cpp @@ -0,0 +1,165 @@ +/**************************************************************************** +** $Id: main.cpp,v 1.4 2008/12/05 21:11:54 leader Exp $ +** +** Main file of Ananas Administrator application +** +** Created : 20040823 +** +** Copyright (C) 2003-2004 Leader InfoTech. All rights reserved. +** Copyright (C) 2003-2005 Grigory Panov , Yoshkar-Ola. +** +** This file is part of the Engine application of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.leaderit.ru/page=ananas or email sales@leaderit.ru +** See http://www.leaderit.ru/gpl/ for GPL licensing information. +** +** Contact org@leaderit.ru if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#include +#include +#include +#include +#include +#include "mainform.h" +#include "ananas.h" + +//QApplication *application = 0; +//MainForm *mainform = 0; +//QTranslator *translator = 0, tr_app(0), tr_lib(0), tr_plugins(0); +QString lang="en", + rcfile="", + username="", + userpassword=""; + +int setTranslator(QString lang) +{ + QString langdir; +#ifdef _Windows + langdir = qApp->applicationDirPath()+"/"; +#else + langdir = "/usr/share/ananas/translations/"; +#endif +// tr_app.load( langdir+"ananas-administrator-"+lang+".qm","."); +// tr_lib.load( langdir+"ananas-lib-"+lang+".qm","."); +// tr_plugins.load( langdir+"ananas-plugins-"+lang+".qm","."); + return 0; +} + +int +parseCommandLine( int argc, char **argv ) +{ + QString param, name, value; + int i; + char *s, locale[50]="en"; + + strncpy( locale, QTextCodec::locale(), sizeof( locale ) ); + s = strchr( locale, '_' ); + if ( s ) { + *s = 0; + } + lang = locale; + setTranslator( lang ); +// printf("locale=%s\n", locale ); + QString str_ru=QString::null, str_en=QString::null; + bool lang_setted = false; + bool help_setted = false; + for ( i=1; iaddLibraryPath( qApp->applicationDirPath() ); + if ( parseCommandLine( argc, argv ) ) return 1; +// qApp->installTranslator( &tr_app ); +// qApp->installTranslator( &tr_lib ); +// qApp->installTranslator( &tr_plugins ); + pixmap = QPixmap(":/images/administrator-splash-"+lang+".png" ); + if ( pixmap.isNull() ) +#ifdef _Windows + pixmap = QPixmap( qApp->applicationDirPath()+"/administrator-splash-"+lang+".png" ); +#else + pixmap = QPixmap( "/usr/share/ananas/administrator/locale/administrator-splash-"+lang+".png" ); +#endif + if ( pixmap.isNull() ) pixmap = QPixmap(":/images/administrator-splash-en.png" ); + QSplashScreen *splash = new QSplashScreen( pixmap ); + if ( ananas_login( rcfile, username, userpassword, 0, AApplication::Administrator ) ){ + splash->show(); + splash->message( QObject::tr("Init application"), Qt::AlignBottom, Qt::white ); + MainForm *w = new MainForm( 0, "MainForm"); + //mainform = w; +// mainformws = mainform->ws; +// mainformwl = mainform->wl; + qApp->setMainWidget( w ); + w->rcfile = rcfile; +// printf( "rcfile = %s\n", rcfile.ascii() ); + w->show(); + ok = w->init(); + splash->clear(); + splash->finish( w ); + delete splash; + if ( ok ) { + a.connect( &a, SIGNAL( lastWindowClosed() ), &a, SLOT( quit() ) ); + rc = a.exec(); + } else { + QMessageBox::critical(0, "error","Error init Ananas engine"); + } + ananas_logout(); + return rc; + } else return 0; +} diff --git a/src/admin/mainform.cpp b/src/admin/mainform.cpp new file mode 100644 index 0000000..c981cad --- /dev/null +++ b/src/admin/mainform.cpp @@ -0,0 +1,131 @@ +#include "mainform.h" + +#include +#include +#include + +/* + * Constructs a MainForm as a child of 'parent', with the + * name 'name' and widget flags set to 'f'. + * + */ +MainForm::MainForm(QWidget* parent, const char* name, Qt::WindowFlags fl) + : QMainWindow(parent, fl) +{ + setupUi(this); + setObjectName( name ); + (void)statusBar(); + init(); +} + +/* + * Destroys the object and frees any allocated resources + */ +MainForm::~MainForm() +{ + // no need to delete child widgets, Qt does it all for us +} + +/* + * Sets the strings of the subwidgets using the current + * language. + */ +void MainForm::languageChange() +{ + retranslateUi(this); +} + +#include "usersform.h" +#include "rolesform.h" + +void MainForm::fileNew() +{ + +} + + +void MainForm::fileOpen() +{ + +} + + +void MainForm::fileSave() +{ + +} + + +void MainForm::fileSaveAs() +{ + +} + + +void MainForm::filePrint() +{ + +} + + +void MainForm::fileExit() +{ + close(); +} + + +/*! + * Users functions. + */ +void MainForm::adminUsers() +{ + + + if( usersForm ) usersForm->show();//->isHidden()) + else { + usersForm = new UsersForm( this ); +// usersForm->init(db); +// usersForm->createTree(); + ws->addSubWindow( usersForm ); + usersForm->show(); + } +} + + + +bool MainForm::init() +{ + ws = new QMdiArea; + setCentralWidget( ws ); + db = aDatabase::database(); +// usersForm = new UsersForm; +// usersForm->hide(); +// rolesForm = new RolesForm; +// rolesForm->init(db); +// rolesForm->createTree(); +// rolesForm->hide(); +// ws->addSubWindow( usersForm ); +// ws->addSubWindow( rolesForm ); + QSqlTableModel *t = new QSqlTableModel( this, *db->db() ); + t->setTable( db_users ); + t->setEditStrategy(QSqlTableModel::OnFieldChange ); + t->select(); + QTableView *dt = new QTableView; + dt->setModel( t ); + ws->addSubWindow( dt ); + dt->show(); + return true; +} + + + +void MainForm::adminRoles() +{ + if ( rolesForm ) rolesForm->show(); + else { + rolesForm = new RolesForm( this ); +// rolesForm->init(db); +// rolesForm->createTree(); + ws->addSubWindow( rolesForm ); + } +} diff --git a/src/admin/mainform.h b/src/admin/mainform.h new file mode 100644 index 0000000..fd0660c --- /dev/null +++ b/src/admin/mainform.h @@ -0,0 +1,41 @@ +#ifndef MAINFORM_H +#define MAINFORM_H + +#include +#include + +#include "ui_mainform.h" + +class MainForm : public QMainWindow, public Ui::MainForm +{ + Q_OBJECT + +public: + MainForm(QWidget* parent = 0, const char* name = 0, Qt::WindowFlags fl = Qt::WType_TopLevel); + ~MainForm(); + + aWindowsList *wl; + QMdiArea *ws; + QString rcfile; + QPointer usersForm; + QPointer rolesForm; + aDatabase *db; + aCfg cfg; + +public slots: + virtual void fileNew(); + virtual void fileOpen(); + virtual void fileSave(); + virtual void fileSaveAs(); + virtual void filePrint(); + virtual void fileExit(); + virtual void adminUsers(); + virtual bool init(); + virtual void adminRoles(); + +protected slots: + virtual void languageChange(); + +}; + +#endif // MAINFORM_H diff --git a/src/admin/mainform.ui b/src/admin/mainform.ui new file mode 100644 index 0000000..926f17c --- /dev/null +++ b/src/admin/mainform.ui @@ -0,0 +1,127 @@ + + + + + MainForm + + + + 0 + 0 + 724 + 599 + + + + Ananas: Administrator + + + a-system.png + + + + + Tools + + + + + + + 0 + 0 + 724 + 28 + + + + + &File + + + + + + + + &Administrator + + + + + + + + + + fileExitAction + + + Exit + + + E&xit + + + + + + + + administratorUsersAction + + + &Users + + + &Users + + + + + administratorRolesAction + + + Roles + + + Roles + + + + + qPixmapFromMimeSource + + ananas.h + qworkspace.h + awindowslist.h + q3vbox.h + usersform.h + + + + fileExitAction + activated() + MainForm + fileExit() + + + administratorUsersAction + activated() + MainForm + adminUsers() + + + fileExitAction + activated() + MainForm + fileExit() + + + administratorRolesAction + activated() + MainForm + adminRoles() + + + diff --git a/src/admin/mdtree.cpp b/src/admin/mdtree.cpp new file mode 100644 index 0000000..62d8ded --- /dev/null +++ b/src/admin/mdtree.cpp @@ -0,0 +1,962 @@ +/**************************************************************************** +** $Id: mdtree.cpp,v 1.3 2008/12/05 21:11:54 leader Exp $ +** +** Code file of the Metadata Tree of Ananas Administrator applications +** +** Created : 20050609 +** +** Copyright (C) 2003-2005 Leader InfoTech. All rights reserved. +** Copyright (C) 2003-2005 Grigory Panov , Yoshkar-Ola. +** +** This file is part of the Designer application of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.leaderit.ru/page=ananas or email sales@leaderit.ru +** See http://www.leaderit.ru/gpl/ for GPL licensing information. +** +** Contact org@leaderit.ru if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#include +#include +//#include +//#include +//#include +//#include +//#include +//#include +//#include +//#include +//#include +//#include +//#include +#include +//#include + +#include "adatabase.h" +#include "mainform.h" +#include "deditpermissions.h" +#include "dselectuser.h" +#include "deditrole.h" +#include "dedituser.h" +#include "dselectrole.h" +//#include "deditcat.h" +//#include "deditireg.h" +//#include "deditareg.h" +//#include "deditjournal.h" +//#include "deditwebform.h" +//#include "deditcolumns.h" +#include "awindowslist.h" + +//#include "acfg.h" +#include "acfgrc.h" + +#include "mdtree.h" +#include "usersform.h" +#include "rolesform.h" + +//extern MainForm *mainform; +//extern QPixmap rcIcon(const char *name); +//extern void set_Icon(QListViewItem *item, const char *name); + + + +aListViewItem::aListViewItem( ananasListViewItem *parent, + ananasListViewItem *after, + aCfg *cfgmd, + aCfgItem cfgobj, + const QString &name, + aUser *usr, + aRole *rl + ): ananasListViewItem( parent, after, cfgmd, cfgobj, name ) +{ + adb = aDatabase::database(); + if(usr) + { +// printf("new user\n"); + user = new aUser(usr->db); + user->Select(usr->sysValue("id").toULongLong()); + } + else + { + user=NULL; + } +// user = usr; + if(rl) + { +// printf("new role\n"); + role = new aRole(rl->db); + role->Select(rl->sysValue("id").toULongLong()); + } + else + { + role=NULL; + } + loadTree(); +} + + + +aListViewItem::aListViewItem(QListView *parent, aCfg *cfgmd, aCfgItem cfgobj, const QString &name ) +: ananasListViewItem( parent, cfgmd, cfgobj, name ) +{ + adb = aDatabase::database(); + role=NULL; + user=NULL; + loadTree(); +} + + +aListViewItem::~aListViewItem() +{ + + if(role) + { +// printf("delete role\n"); + delete role; + role = NULL; + } + if(user) + { +// printf("delete user\n"); + delete user; + user = NULL; + } +} + + +QString +aListViewItem::text( int column ) const +{ + return Q3ListViewItem::text( column ); +// if ( obj.isNull() ) return QObject::tr("Unknown object context"); + if ( !id ) return Q3ListViewItem::text( column ); + switch ( column ) { + case 0: return md->attr( obj, mda_name ); + default: + return ""; + } +} + + + +int +aListViewItem::compare( Q3ListViewItem *i, int col, bool accending ) const +{ + int id1 = 0, id2 = 0; + aListViewItem *ai = (aListViewItem *) i; + id1 = md->order( obj ); + id2 = ai->md->order( ai->obj ); + if ( md == ai->md && md->parent( obj ) == ai->md->parent( ai->obj ) && col ==0 && accending ) { + if ( id1 < id2 ) return -1; + if ( id1 == id2 ) return 0; + return 1; + } + return 1; +} + + + +void +aListViewItem::setup() +{ + Q3ListViewItem::setup(); +} + + + +/*! +Update metadata tree for the object context. +*/ +void +aListViewItem::update() +{ + QString oclass = md->objClass( obj ); + printf("remove !\n"); + if( oclass == md_user ) + { + if(user->First()) + { + setText(0,user->sysValue("login").toString()); + } + } + if( oclass == md_role) + { + if(role->First()) + { + setText(0,role->sysValue("name").toString()); + } + + } + if( oclass == md_rl_user) + { + + } + if( oclass == md_rl_user) + { + + } + if( oclass == md_rl_user) + { + + } + if( oclass == md_rl_user) + { + + } + + +} + + +void +aListViewItem::loadTree() +{ +//printf("load tree\n"); + aListViewItem *item, *nextitem; + QString oclass, ldclass=""; + int i, n; + aCfgItem cobj; + + // clear tree +// item = (aListViewItem *) firstChild(); +// while( item ) { +// nextitem = (aListViewItem *) item->nextSibling(); +// delete item; +// item = nextitem; + // } + if ( !md ) return; + if (id) setRenameEnabled(0, true); + oclass = md->objClass( obj ); +// printf("oclass=`%s'\n",oclass.ascii()); + if ( oclass == md_roles ) + { + loadRoles(this); + + } + if ( oclass == md_role ) + { + cobj = md->find ( mdc_metadata ); +// cobj.setTagName("eqwe"); + new aListViewItem(this, getLastChild(), md, cobj, QObject::tr("Metadata Objects"),NULL,role ); + // cobj.clear(); + cobj = cobj.cloneNode(false).toElement(); + cobj.setTagName( md_rl_users ); // change type to users +// cobj.setTagName("eqwe"); + + aUser *usr = new aUser(adb); + new aListViewItem(this, getLastChild(), md, cobj, QObject::tr("Users"),usr,role); + } + if ( oclass == md_users ) + { + loadUsers(this); + } + if ( oclass == md_user ) + { + loadUsrRoles(this); + } + if ( oclass == md_metadata ) + { + cobj = md->find ( mdc_metadata ); + setPixmap(0, QPixmap(":/images/metadata.png")); + // setOpen(true); + cobj = md->find ( obj, md_catalogues, 0 ); + new aListViewItem( this, getLastChild(), md, cobj, QObject::tr("Catalogues"),NULL,role ); + cobj = md->find ( obj, md_documents, 0 ); + new aListViewItem( this, getLastChild(), md, cobj, QObject::tr("Documents"),NULL,role ); + cobj = md->find ( obj, md_reports, 0 ); + new aListViewItem( this, getLastChild(), md, cobj, QObject::tr("Reports"),NULL,role ); + cobj = md->find ( obj, md_journals, 0 ); + new aListViewItem( this, getLastChild(), md, cobj, QObject::tr("Journals"),NULL,role ); + cobj = md->find ( obj, md_iregisters, 0 ); + new aListViewItem( this, getLastChild(), md, cobj, QObject::tr("Information registers"),NULL,role ); + cobj = md->find ( obj, md_aregisters, 0 ); + new aListViewItem( this, getLastChild(), md, cobj, QObject::tr("Accumulation registers"),NULL,role ); + + } + if ( oclass == md_catalogues ){ + QPixmap pixmap = QPixmap(":/images/cat_g.png"); + if(pixmap.isNull()) printf("image not loaded\n"); + setPixmap(0, pixmap ); + ldclass = md_catalogue; + } + if ( oclass == md_documents ){ + setPixmap(0, QPixmap(":/images/doc_g.png")); + ldclass = md_document; + } + if ( oclass == md_reports ){ + setPixmap(0, QPixmap(":/images/report_g.png")); + ldclass = md_report; + } + if ( oclass == md_journals ){ + setPixmap(0, QPixmap(":/images/journ_g.png")); + ldclass = md_journal; + } + if ( oclass == md_iregisters ){ + setPixmap(0, QPixmap(":/images/reg_g.png")); + ldclass = md_iregister; + } + if ( oclass == md_aregisters ){ + setPixmap(0, QPixmap(":/images/regs_g.png")); + ldclass = md_aregister; + } + if ( oclass == md_rl_users ){ + setPixmap(0, QPixmap(":/images/users.png")); + loadRlUsers(this); + // ldclass = md_rl_user; + } + if ( oclass == md_users ){ + setPixmap(0, QPixmap(":/images/users.png")); + // ldclass = md_rl_user; + } + if ( oclass == md_roles ){ + setPixmap(0, QPixmap(":/images/roles.png")); + // ldclass = md_role; + } + if ( oclass == md_user || oclass == md_rl_user){ + setPixmap(0, QPixmap(":/images/user.png")); + // ldclass = md_document; + } + if ( oclass == md_role || oclass == md_usr_role){ + setPixmap(0, QPixmap(":/images/role.png")); + // ldclass = md_document; + } + if ( !ldclass.isEmpty() ) { + + if(ldclass==md_rl_user) + { + } +// printf("%s\n",(const char *) ldclass.local8Bit() ); + n = md->count( obj, ldclass ); +// printf(" objclass=%s ldclass = %s count = %d\n", (const char *) oclass, (const char *) ldclass, n); + for ( i = 0; ifind( obj, ldclass, i ); + if ( !cobj.isNull() ) { +// printf("%d ok\n", i); +// new aListViewItem( this, md, md->find( obj, ldclass, i ), QString::null ); + new aListViewItem( this, getLastChild(), md, cobj, QString::null, NULL ,role ); + } + } + } + + +// elements +} + + +void +aListViewItem::loadUsrRoles ( aListViewItem *parent ) +{ + QValueList list = user->getRoles(true); + aCfgItem cobj; + //listId.clear(); +// QValueList list = user->getRoles(false); + QValueList::iterator it; + for ( it = list.begin(); it != list.end(); ++it ) + { + cobj = md->find ( mdc_metadata ); + cobj = cobj.cloneNode(false).toElement(); + cobj.setTagName( md_usr_role ); // change type to users + new aListViewItem(parent, getLastChild(), md, cobj, (*it)->sysValue("name").toString(),user,(*it)); +// listBox1->insertItem( (*it)->sysValue("name").toString() ); + delete (*it); + } +} + + + +void +aListViewItem::loadRoles (aListViewItem *parent) +{ + aCfgItem cobj; + if( adb ) + { + role = new aRole( adb ); + + cobj = md->find ( mdc_metadata ); + cobj = cobj.cloneNode(false).toElement(); + cobj.setTagName( md_role ); // change type to users + role->Select(); + if(role->First()) + { +// printf("role first!!!\n"); + do + { +// printf("role next\n"); + new aListViewItem(parent, getLastChild(), md, cobj, role->sysValue("name").toString(),NULL,role); + }while(role->Next()); + } + } +} + + + +void +aListViewItem::loadUsers (aListViewItem *parent) +{ + aCfgItem cobj; + if( adb ) + { + user = new aUser(adb); + + cobj = md->find ( mdc_metadata ); + cobj = cobj.cloneNode(false).toElement(); + cobj.setTagName( md_user ); // change type to role + user->Select(); + if(user->First()) + { +// printf("user first!!!\n"); + do + { +// printf("user next\n"); + new aListViewItem(parent, getLastChild(), md, cobj, user->sysValue("login").toString(),user); + + }while(user->Next()); + } + } +} + + + +void +aListViewItem::loadRlUsers ( aListViewItem *parent ) +{ +//printf("load users!\n"); +// aUser *usr = new aUser(adb); + if(!user) + { + printf("user=NULL\n"); + return; + } + + //user->Select(); + aCfgItem l; + l = md->find( mdc_metadata ); + l = l.cloneNode(false).toElement(); + l.setTagName(md_rl_user); + user->Select(); + if(user->First()) + { +// printf("user first\n"); + do + { + if(role->hasUser(user->sysValue("id").toULongLong())) + { + new aListViewItem(parent, getLastChild(),md, l, user->sysValue("login").toString(),user,role); + } +// printf("user next\n"); + }while (user->Next()); + } +// printf("end\n"); +} + + + +void +aListViewItem::deleteRole () +{ + printf("delete role!\n"); + role->Delete(); +// removeItem(this); +} + + + +void +aListViewItem::deleteUser () +{ + printf("delete user!\n"); + user->Delete(); +// removeItem(this); +} + + + +void +aListViewItem::remove () +{ + QString oclass = md->objClass( obj ); + printf("remove !\n"); + if( oclass == md_usr_role ) + { + user->delRole(role->sysValue("id").toULongLong()); + } + if( oclass == md_rl_user) + { + role->delUser(user->sysValue("id").toULongLong()); + } +// removeItem(this); +} + + +/* +*edit selected object +*/ + + + +void +aListViewItem::editRole( bool isNew) +{ + QString oclass = md->objClass( obj ); + if(oclass == md_role || oclass == md_roles ) + { + dEditRole *e = new dEditRole( qApp->mainWidget()); + // wl->insert( objid, e ); + editor = e; + // QObject::connect( mainform, SIGNAL( tosave() ), editor, SLOT( updateMD() ) ); + if(isNew) + { + printf("new role\n"); + e->setData("New Role"); + } + else + { + printf("edit role `%s'\n",role->sysValue("name").toString().ascii()); + e->setData(role->sysValue("name").toString()); + } + if(e->exec() == QDialog::Accepted) + { + if(isNew) + { + role->New(e->getData()); + aCfgItem l; + l = md->find( mdc_metadata ); + l = l.cloneNode(false).toElement(); + l.setTagName(md_role); + new aListViewItem(this,getLastChild(),md,l,role->sysValue("name").toString(),NULL,role); + role->Select(); + } + else + { + role->setSysValue("name",e->getData()); + role->Update(); + setText(0,e->getData()); + } + } + delete e; + } +} + + + +void +aListViewItem::editPermission() +{ + QString oclass = md->objClass( obj ); + dEditPermissions *e = new dEditPermissions( qApp->mainWidget()); +// wl->insert( objid, e ); + editor = e; + + int role_id, obj_id; + role_id = role->sysValue ( "id" ).toULongLong(); + obj_id = md->id( obj ); + printf("role = %i, obj=%i id=%i\n", role_id, obj_id, id ); + int perm = adb->rolePermission( role_id, obj_id ); + + e->setData ( perm ); + if ( e->exec() == QDialog::Accepted ) + { + perm = e->getData (); + adb->setRolePermission( role_id, obj_id, perm ); + } + delete e; + +// QObject::connect( mainform, SIGNAL( tosave() ), editor, SLOT( updateMD() ) ); +/* QMap m; + m [perm_read] = true; + m [perm_execute] = false; + m [perm_turn_on] = false; + m [perm_turn_off] = false; + m [perm_create] = false; + m [perm_delete] = false; + + e->setData( m ); + if(e->exec() == QDialog::Accepted) + { + e->getData( m ); + //TODO: add logic here! + } + delete e; +*/ +// mainform->addTab(++mainform->lastTabId,e->name()); +// e->parentWidget()->setGeometry(0,0,e->parentWidget()->frameSize().width(), +// e->parentWidget()->frameSize().height()); + +// printf("oclass = %s\n",( const char *) oclass ); + //if ( oclass == md_documents ) newDocument(); +// if ( oclass == md_columns ) newColumn(); +} + + + +void +aListViewItem::editUser(bool isNew) +{ + QString oclass = md->objClass( obj ); + if ( oclass == md_users || oclass == md_user) + { + + dEditUser *e = new dEditUser( qApp->mainWidget() ); + editor = e; + e->setData( user, isNew ); + if(e->exec()==QDialog::Accepted) + { + if(isNew) + { + aCfgItem l; + l = md->find( mdc_metadata ); + l = l.cloneNode(false).toElement(); + l.setTagName(md_user); + new aListViewItem(this,getLastChild(),md,l,user->sysValue("login").toString(),user,NULL); + user->Select(); + } + else + { + update(); + } + } + delete e; + + } +} + + + +void +aListViewItem::addUser() +{ + QString oclass = md->objClass( obj ); + if ( oclass == md_rl_users) + { + + dSelectUser *e = new dSelectUser( qApp->mainWidget() ); + editor = e; + e->setData( role ); + if(e->exec() == QDialog::Accepted) + { + aCfgItem l; + l = md->find( mdc_metadata ); + l = l.cloneNode(false).toElement(); + l.setTagName(md_rl_user); + aUser *usr = new aUser(e->getData(),role->db); + new aListViewItem(this,getLastChild(),md,l,usr->sysValue("login").toString(),usr,role); + delete usr; + usr = NULL; + } + delete e; + + } +} + + + +void +aListViewItem::addRole() +{ + QString oclass = md->objClass( obj ); + if ( oclass == md_user) + { + + dSelectRole *e = new dSelectRole( qApp->mainWidget() ); + editor = e; + e->setData( user ); + if(e->exec() == QDialog::Accepted) + { + aCfgItem l; + l = md->find( mdc_metadata ); + l = l.cloneNode(false).toElement(); + l.setTagName(md_usr_role); + aRole *rl = new aRole(e->getData(),user->db); + new aListViewItem(this,getLastChild(),md,l,rl->sysValue("name").toString(),user,rl); + delete rl; + rl = NULL; + } + delete e; + + } +} + + + +aMetadataTreeView::aMetadataTreeView( QWidget *parent, aCfg *cfgmd ) +:ananasTreeView( parent, cfgmd ) +{ + aListViewItem *conf; + + if ( !md ) return; + +// aCfgItem it = md->find( mdc_metadata ); +// it = it.cloneNode(false).toElement(); +// it.setTagName(md_roles); + +// conf = new aListViewItem( this, md, it, tr(QString("Roles"))); +// conf->setOpen( TRUE ); + connect( this, SIGNAL( contextMenuRequested( Q3ListViewItem*, const QPoint&, int) ), this, SLOT(ContextMenu() ) ); +// connect( this, SIGNAL( returnPressed( QListViewItem* ) ), this, SLOT( itemEdit() ) ); +// connect( this, SIGNAL( doubleClicked( QListViewItem* ) ), this, SLOT( itemEdit() ) ); +// connect( this, SIGNAL( collapsed( QListViewItem* ) ), this, SLOT( on_collapsed( QListViewItem* ) ) ); +} + + +aMetadataTreeView::aMetadataTreeView( UsersForm *parent, aCfg *cfgmd ) +:ananasTreeView( parent, cfgmd ) +{ + aListViewItem *conf; + + if ( !md ) return; + + aCfgItem it = md->find( mdc_metadata ); + it = it.cloneNode(false).toElement(); + it.setTagName(md_users); + + conf = new aListViewItem( this, md, it, tr(QString("Users"))); + conf->setOpen( TRUE ); + connect( this, SIGNAL( contextMenuRequested( Q3ListViewItem*, const QPoint&, int) ), this, SLOT(ContextMenu() ) ); +// connect( this, SIGNAL( doubleClicked( QListViewItem* ) ), this, SLOT( itemEdit() ) ); + connect( this, SIGNAL( collapsed( QListViewItem* ) ), this, SLOT( on_collapsed( QListViewItem* ) ) ); +} + + +aMetadataTreeView::aMetadataTreeView( RolesForm *parent, aCfg *cfgmd ) +:ananasTreeView( parent, cfgmd ) +{ + aListViewItem *conf; + + if ( !md ) return; + + aCfgItem it = md->find( mdc_metadata ); + it = it.cloneNode(false).toElement(); + it.setTagName(md_roles); + + conf = new aListViewItem( this, md, it, tr(QString("Roles"))); + conf->setOpen( TRUE ); + connect( this, SIGNAL( contextMenuRequested( Q3ListViewItem*, const QPoint&, int) ), this, SLOT(ContextMenu() ) ); +// connect( this, SIGNAL( returnPressed( QListViewItem* ) ), this, SLOT( itemEdit() ) ); +// connect( this, SIGNAL( doubleClicked( QListViewItem* ) ), this, SLOT( itemEdit() ) ); + connect( this, SIGNAL( collapsed( Q3ListViewItem* ) ), this, SLOT( on_collapsed( Q3ListViewItem* ) ) ); +} + + + +void +aMetadataTreeView::on_collapsed( Q3ListViewItem * item ) +{ + aListViewItem *i = (aListViewItem *) item; + if ( i ) + { + QString oclass = md->objClass( i->obj ); + if ( oclass == md_roles ) setOpen( i, true ); + } +} + + +void +aMetadataTreeView::ContextMenu() +{ + + QPopupMenu *m=new QPopupMenu( this, "PopupMenu" ); + Q_CHECK_PTR(m); + +/* QLabel *caption = new QLabel( "" + "Context Menu", this ); + caption->setAlignment( Qt::AlignCenter ); + m->insertItem( caption ); + m->insertItem( "&New", this, SLOT( itemNew() ), CTRL+Key_N ); + m->insertItem( "&Rename", this, SLOT( itemRename() ), CTRL+Key_O); + m->insertItem( "&Edit", this, SLOT( itemEdit() ), CTRL+Key_N ); + m->insertItem( "&Delete", this, SLOT( itemDelete() ), CTRL+Key_O );*/ + + aListViewItem *i = (aListViewItem *) selectedItem(); + if(!i) return; + + QLabel *caption = new QLabel( tr("" "Context Menu"), this ); + caption->setAlignment( Qt::AlignCenter ); +// m->insertItem( caption ); + + QString oclass = md->objClass(i->obj); + printf("popup oclass==`%s'\n",oclass.ascii()); + + if(oclass == md_user) + { + + m->insertItem( tr("&Add Role"), this, SLOT( addRole() ), Qt::CTRL+Qt::Key_A ); + } + if(oclass == md_roles) + { + m->insertItem( tr("&New Role"), this, SLOT( newRole() ), Qt::CTRL+Qt::Key_N ); + } + if( oclass == md_role) + { + + m->insertItem( tr("&Edit Role"), this, SLOT( editRole() ), Qt::CTRL+Qt::Key_E ); + m->insertItem( tr("&Delete Role"), this, SLOT( delRole() ), Qt::CTRL+Qt::Key_D ); + } + + if(oclass==md_rl_users) + { + m->insertItem( tr("&Add User"), this, SLOT( addUser() ), Qt::CTRL+Qt::Key_A ); + } + if(oclass==md_users ) + { + m->insertItem( tr("&New User"), this, SLOT( newUser() ), Qt::CTRL+Qt::Key_N ); + } + + if(oclass==md_user) + { + m->insertItem( tr("&Edit User "), this, SLOT( editUser() ), Qt::CTRL+Qt::Key_E ); + m->insertItem( tr("&Delete User"), this, SLOT( delUser() ), Qt::CTRL+Qt::Key_D ); + } + if(oclass==md_usr_role || oclass==md_rl_user) + { + m->insertItem( tr("&Remove"), this, SLOT( itemDelete() ), Qt::CTRL+Qt::Key_R ); + } + if( oclass == md_catalogue + || oclass == md_document + || oclass == md_journal + || oclass == md_aregister + || oclass == md_iregister + || oclass == md_report ) + { + m->insertItem( tr("&Set permissions"), this, SLOT( itemSetPermission() ), Qt::CTRL+Qt::Key_S ); + } + + ContextMenuAdd(m); +// m->insertItem( tr("&New"), this, SLOT( itemNew() ), CTRL+Key_N ); + m->exec( QCursor::pos() ); + delete m; +} + + +/*void +aMetadataTreeView::itemRename() +{ + renameItem(); +} +*/ +void +aMetadataTreeView::newUser() +{ + aListViewItem *i = (aListViewItem *) selectedItem(); + if ( i ) + { + i->editUser(true); + } +} + +void +aMetadataTreeView::newRole() +{ + aListViewItem *i = (aListViewItem *) selectedItem(); + if ( i ) + { + i->editRole(true); + } +} + +void +aMetadataTreeView::editUser() +{ + aListViewItem *i = (aListViewItem *) selectedItem(); + if ( i ) + { + i->editUser(false); +// emit (updateRoles()); + } +} + +void +aMetadataTreeView::editRole() +{ + aListViewItem *i = (aListViewItem *) selectedItem(); + if ( i ) + { + i->editRole(false); + + //emit(updateUsers()); + } +} + +void +aMetadataTreeView::delRole() +{ + aListViewItem *i = (aListViewItem *) selectedItem(); + if ( i ) + { + i->deleteRole(); + delete i; + //emit(updateUsers()); + } +} +void +aMetadataTreeView::delUser() +{ + aListViewItem *i = (aListViewItem *) selectedItem(); + if ( i ) + { + i->deleteUser(); + delete i; + //emit (updateRoles()); + } +} + +void +aMetadataTreeView::addRole() +{ + aListViewItem *i = (aListViewItem *) selectedItem(); + if ( i ) + { + i->addRole(); + //i->update(); + //emit(updateUsers()); + //emit (updateRoles()); + } +} +void +aMetadataTreeView::addUser() +{ + aListViewItem *i = (aListViewItem *) selectedItem(); + if ( i ) + { + i->addUser(); + //i->update(); + //emit (updateRoles()); + } +} + +void +aMetadataTreeView::itemSetPermission() +{ + aListViewItem *i = (aListViewItem *) selectedItem(); + if ( i ) + { + //if ( i->id == 0 ) + i->editPermission(); + } +} + + +void +aMetadataTreeView::itemDelete() +{ + aListViewItem *i = (aListViewItem *) selectedItem(); + if ( i ) + { + i->remove(); + delete i; + } +// deleteItem(); +} + + + diff --git a/src/admin/mdtree.h b/src/admin/mdtree.h new file mode 100644 index 0000000..a5b3b6a --- /dev/null +++ b/src/admin/mdtree.h @@ -0,0 +1,158 @@ +/**************************************************************************** +** $Id: mdtree.h,v 1.3 2008/12/05 21:11:54 leader Exp $ +** +** Header file of the Metadata Tree of Ananas Administrator applications +** +** Created : 20050609 +** +** Copyright (C) 2003-2005 Leader InfoTech. All rights reserved. +** Copyright (C) 2003-2005 Grigory Panov , Yoshkar-Ola. +** +** This file is part of the Designer application of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.leaderit.ru/page=ananas or email sales@leaderit.ru +** See http://www.leaderit.ru/gpl/ for GPL licensing information. +** +** Contact org@leaderit.ru if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#ifndef MDTREE_H +#define MDTREE_H +#include +//#include +//#include +#include "acfg.h" +#include "atreeitems.h" +#include "auser.h" +#include "arole.h" + +#define QIntDict Q3IntDict +#define QValueList Q3ValueList + +//#include "usersform.h" +//#include "rolesform.h" + +//extern aFormDesigner *formdesigner; +//#include "cfg.h" +class QWidget; +class UsersForm; +class RolesForm; + +class aListViewItem : public ananasListViewItem +{ + +public: +/* int id; + aCfgItem obj; + QWidget *editor; + aCfg *md; +*/ + aDatabase *adb; + + aListViewItem( ananasListViewItem *parent, + ananasListViewItem *after, + aCfg * cfgmd, + aCfgItem cfgobj, + const QString &name = QString::null, + aUser *usr = NULL, + aRole *rl = NULL); +// aListViewItem(QListViewItem *parent, aCfg * cfgmd, aCfgItem cfgobj, const QString &name = QString::null ); + aListViewItem( QListView *parent, + aCfg * cfgmd, + aCfgItem obj, + const QString &name = QString::null); + + ~aListViewItem(); + QString text( int column ) const; + + aUser *user; + aRole *role; + + void loadTree(); + void setup(); + void update(); + void deleteUser(); + void deleteRole(); + void editUser(bool isNew); + void editRole(bool isNew); + void addUser(); + void addRole(); + void remove(); + + void editPermission(); +// void newDocument(); +// void newCatalogue(); +// void newJournal(); +// void newIRegister(); +// void newARegister(); +// void newReport(); +// void newForm(); +// void newWebForm(); +// void newTable(); + void newColumn(); + +protected: +// virtual void okRename( int col ); + virtual int compare( Q3ListViewItem *i, int col, bool accending ) const; +private: +// void loadDocument (); +// void loadJournal (); +// void loadIRegister (); +// void loadARegister (); +// void loadCatalogue (); +// void loadReport (); + void loadRoles (aListViewItem *a); + void loadUsers ( aListViewItem *a ); + void loadRlUsers ( aListViewItem *a ); + void loadUsrRoles (aListViewItem *a); +// void loadForms (aListViewItem *parent); +// void loadWebForms (aListViewItem *parent); +// void loadColumns ( aListViewItem *parent ); +}; + + +class aMetadataTreeView : public ananasTreeView +{ + Q_OBJECT +public: +// aCfg *md; + + aMetadataTreeView( QWidget *parent, aCfg *cfgmd ); + aMetadataTreeView( UsersForm *parent, aCfg *cfgmd ); + aMetadataTreeView( RolesForm *parent, aCfg *cfgmd ); + +signals: + void updateUsers(); + void updateRoles(); + +public slots: + void ContextMenu(); + void newUser(); + void editUser(); + void delUser(); + void addUser(); + void newRole(); + void editRole(); + void delRole(); + void addRole(); + + void itemDelete(); + void itemSetPermission(); +private slots: + void on_collapsed( Q3ListViewItem *item ); +private: + QIntDict editors; +}; + +#endif diff --git a/src/admin/rolesform.cpp b/src/admin/rolesform.cpp new file mode 100644 index 0000000..51f0d3c --- /dev/null +++ b/src/admin/rolesform.cpp @@ -0,0 +1,36 @@ +#include "rolesform.h" + +#include +#include +#include + +/* + * Constructs a RolesForm as a child of 'parent', with the + * name 'name' and widget flags set to 'f'. + */ +RolesForm::RolesForm(QWidget* parent, const char* name, Qt::WindowFlags fl) + : QWidget(parent, name, fl) +{ + setupUi(this); + new QVBoxLayout( this ); + mdtree = new aMetadataTreeView( this, &aDatabase::database()->cfg ); // metadata tree creation + mdtree->setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding); + layout()->add( mdtree ); + updateGeometry(); +} + +/* + * Destroys the object and frees any allocated resources + */ +RolesForm::~RolesForm() +{ +} + +/* + * Sets the strings of the subwidgets using the current + * language. + */ +void RolesForm::languageChange() +{ + retranslateUi(this); +} diff --git a/src/admin/rolesform.h b/src/admin/rolesform.h new file mode 100644 index 0000000..b05f0a4 --- /dev/null +++ b/src/admin/rolesform.h @@ -0,0 +1,26 @@ +#ifndef ROLESFORM_H +#define ROLESFORM_H + +#include "ui_rolesform.h" + +class RolesForm : public QWidget, public Ui::RolesForm +{ + Q_OBJECT + +public: + RolesForm(QWidget* parent = 0, const char* name = 0, Qt::WindowFlags fl = 0); + ~RolesForm(); + + QString rcfile; + aMetadataTreeView *mdtree; +// aCfg *cfg; + +signals: + void updateUsers(); + +protected slots: + virtual void languageChange(); + +}; + +#endif // ROLESFORM_H diff --git a/src/admin/rolesform.ui b/src/admin/rolesform.ui new file mode 100644 index 0000000..009b5b3 --- /dev/null +++ b/src/admin/rolesform.ui @@ -0,0 +1,26 @@ + + + + + RolesForm + + + + 0 + 0 + 398 + 400 + + + + Ananas: Roles + + + + + qPixmapFromMimeSource + + mdtree.h + acfg.h + + diff --git a/src/admin/usersform.cpp b/src/admin/usersform.cpp new file mode 100644 index 0000000..c5f36c0 --- /dev/null +++ b/src/admin/usersform.cpp @@ -0,0 +1,39 @@ +#include "usersform.h" + +#include +#include +#include + +/* + * Constructs a UsersForm as a child of 'parent', with the + * name 'name' and widget flags set to 'f'. + */ +UsersForm::UsersForm(QWidget* parent, Qt::WindowFlags fl) + : QWidget(parent, fl) +{ + setupUi(this); + new QVBoxLayout( this ); + mdtree = new aMetadataTreeView( this, &aDatabase::database()->cfg ); // metadata tree creation + mdtree->setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding); + layout()->add( mdtree ); + updateGeometry(); +} + +/* + * Destroys the object and frees any allocated resources + */ +UsersForm::~UsersForm() +{ + +} + +/* + * Sets the strings of the subwidgets using the current + * language. + */ +void UsersForm::languageChange() +{ + retranslateUi(this); +} + + diff --git a/src/admin/usersform.h b/src/admin/usersform.h new file mode 100644 index 0000000..24ebec8 --- /dev/null +++ b/src/admin/usersform.h @@ -0,0 +1,28 @@ +#ifndef USERSFORM_H +#define USERSFORM_H +#include + +#include "ui_usersform.h" + +class UsersForm : public QWidget, public Ui::UsersForm +{ + Q_OBJECT + +public: + UsersForm(QWidget* parent = 0, Qt::WindowFlags fl = 0); + ~UsersForm(); + +signals: + void updateRoles(); + +protected: + aCfg *cfg; + QPointer mdtree; + QString rcfile; + +protected slots: + virtual void languageChange(); + +}; + +#endif // USERSFORM_H diff --git a/src/admin/usersform.ui b/src/admin/usersform.ui new file mode 100644 index 0000000..da45988 --- /dev/null +++ b/src/admin/usersform.ui @@ -0,0 +1,24 @@ + + UsersForm + + + + 0 + 0 + 330 + 291 + + + + Ananas: Users + + + + qPixmapFromMimeSource + + mdtree.h + acfg.h + + + + diff --git a/src/ananas.pri b/src/ananas.pri new file mode 100644 index 0000000..fbf64d0 --- /dev/null +++ b/src/ananas.pri @@ -0,0 +1,24 @@ +#QMAKE_CLEAN += $(TARGET) Makefile +CONFIG += qt warn_on release thread +#LANGUAGE = C++ + +QT += qt3support sql xml +CONFIG += warn_on designer + +unix { + UI_DIR = .ui + MOC_DIR = .moc + OBJECTS_DIR = .obj + INCLUDEPATH +=.ui ../lib ../../lib ../../plugins ../plugins ../lib/.ui ../../lib/.ui +} +win32 { + UI_DIR = tmp\ui + MOC_DIR = tmp\moc + OBJECTS_DIR = obj + debug:CONFIG += console + INCLUDEPATH +=tmp\ui ..\lib ..\..\lib ..\..\plugins ..\lib\tmp\ui ..\..\lib\tmp\ui ..\plugins + INCLUDEPATH += ..\..\plugins +# LIBS += -L..\..\plugins -lananasplugin +} + +INCLUDEPATH +=$(QTDIR)/include/qdataschema diff --git a/src/ananas/ananas.pro b/src/ananas/ananas.pro new file mode 100644 index 0000000..0571384 --- /dev/null +++ b/src/ananas/ananas.pro @@ -0,0 +1,46 @@ +include (../plugins/plugins.pri) +include (../lib/lib.pri) +include (../ananas.pri) +load(qsa) + +TARGET = ananas4 +TEMPLATE = app + +DESTDIR = ../../bin + +INCLUDEPATH += ../lib ../../tmp/ui/ananas ../plugins +LIBS += -L../../lib -lananas4 -L../../lib/designer -lananasplugin4 -lqt4-qdataschema +#-L$(QTDIR)/lib -lqsa1 +#LIBS += -L$(QTDIR)/lib -lqsa1 -L../lib -lananas -L../plugins -lananasplugin # -lqui + +#MOC_DIR = ../../tmp/moc/$$TARGET +#OBJECTS_DIR = ../../tmp/obj/$$TARGET +#UI_DIR = ../../tmp/ui/$$TARGET + + +HEADERS = \ + mainform.h + +SOURCES = \ + main.cpp \ + mainform.cpp + +#FORMS = qadocjournal.ui + +RESOURCE = \ + ananas.qrc + +TRANSLATIONS = \ + ../../translations/ananas-engine-en.ts \ + ../../translations/ananas-engine-ru.ts + +unix { + ananas.path = $(BINDIR) + ananas.files = ananas4 +} +win32{ +# ananas.path =. +# ananas.extra = CALL create_base.bat +} + +#INSTALLS += ananas diff --git a/src/ananas/ananas.qrc b/src/ananas/ananas.qrc new file mode 100644 index 0000000..8e02144 --- /dev/null +++ b/src/ananas/ananas.qrc @@ -0,0 +1,34 @@ + + + images/a-system.png + images/cat.png + images/d_document_turned.png + images/document_turned.png + images/editdelete.png + images/editdelete2.png + images/engine-splash-en.png + images/engine-splash-ru.png + images/field.png + images/field2.png + images/group.png + images/group2.png + images/lib_database.png + images/lib_dbgroup.png + images/msg_error.png + images/msg_fatal.png + images/msg_info.png + images/msg_warning.png + images/object_markdeleted.png + images/t_cat_e.png + images/t_cat_ed.png + images/t_cat_g.png + images/t_cat_gd.png + images/t_doc.png + images/t_doc_d.png + images/t_doc_m.png + images/t_doc_t.png + images/t_doc_tm.png + images/t_doc_to.png + images/t_doc_tom.png + + diff --git a/src/ananas/bkground.jpg b/src/ananas/bkground.jpg new file mode 100644 index 0000000000000000000000000000000000000000..06a9ee84d1c5ac682a3f5a1b5fcca18dca3427f5 GIT binary patch literal 5119 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 J?fvBAe*ngP7CHa` literal 0 HcmV?d00001 diff --git a/src/ananas/images/a-system.png b/src/ananas/images/a-system.png new file mode 100644 index 0000000000000000000000000000000000000000..6638dfffd429826b0f6b152a1255762a855bc285 GIT binary patch literal 1283 zcmV+e1^oJnP)ff z?ml$jF!N^az2|$*`JNw7_vD$s4}OTmU{jdp5sSmLI$*GH8n&7m=Q`Z+FY`mDA1* zE)~V-hdloha5E&YgW6RHmT%lxY#%=S<9bm%3*dnY*Z>{^E2=2aGPCZ5aOq9&Uwbfd zwOJqDc`(6CqBs@569Da@v-)q~+gX~&eib+dS+U_BA`7Mf}=*d2&@bA zMHm{00E|Q!g&+oCoHzy`xSiT<9YhN_C<0LK6JczpdRr%E;+E1UqNuhKYD9eA)m`7z z<6}2*M&;h*XX#a0k031mQP|o5JQE&FT^~!an`f+w*2%;J#j<5fNK!Q_PtuiYlYCjN zF;#9C6VLRjfOTML5@UB&l}^$LW2cFl6i{o`5qqM%0Gyj=8VUwr*#P{e$|BGfnYz9U z?5mlYCux_s-vPy3A&3WVOdj*q#L5a-1on&2n}i6lZ159>5mTN{NOO50^#ma2ynn}d z*?l9+-hV2~cwB_8mF=1}c`}E_Y;e1t3H8xeS;A_0T7*NuV`iE@x<}X=ifmRTY*Zea z51c-q$TAj;S;K^o2?wN>?y?;KN!>lPbQ=O;lhs?UMcWkD_ieqUXPD(kw^OVKz@Mu8 z0}QQ0h8Yp6uOAqQC0MQ%)M8d5qI&2fyZ+XesX;uDD@ma~o>zh@2qA7lJ|GMH3u tjw}qdxxPvOCjQBW(3gGkIg?Y}rt@iyu{tV7@W`;p} z_ZVZwg-5|_qoWBeoP-W9Y?Ps@f9zg~+1Nb<$ud>bl15w#+%_*xNxU z;S6?7Ipk0P5*TB?J-{>T7}NtZ v#*WB(5rYEG*DX!S%Lf>Pdf@+#)Bbr6u%@REt8=nw00000NkvXXu0mjfRRy-l literal 0 HcmV?d00001 diff --git a/src/ananas/images/d_document_turned.png b/src/ananas/images/d_document_turned.png new file mode 100644 index 0000000000000000000000000000000000000000..dd4b1d30dae1cebfea640b53cd3762fc459dd39a GIT binary patch literal 505 zcmV!1BI-OGTSBk?hq}S_J=7N0n+-mY( z0S1GC3oI6k!Um@}ilV$vuZ2p`;c(~z*Xy+;$bq-pEx zQ&g4NY*q&^S&*h_No_$fKpe+B9uGu>>2&%EFIix%C643DQ{}+|PrpHk`<*Py@VuY&>z8#r9&6Rs z1r=a2nGgg4tyT+>pKaD!PNx%_&E_pQsE7%m#u!8dRmJyx;OT#oB(U2eqq%kw literal 0 HcmV?d00001 diff --git a/src/ananas/images/document_turned.png b/src/ananas/images/document_turned.png new file mode 100644 index 0000000000000000000000000000000000000000..101ac7dd9efe91d9ba4e9907466c53da4f13fe2b GIT binary patch literal 384 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

Anp)}|s_^bT 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 literal 0 HcmV?d00001 diff --git a/src/ananas/images/engine-splash-ru.png b/src/ananas/images/engine-splash-ru.png new file mode 100644 index 0000000000000000000000000000000000000000..9d7cf5b3d163aa362a732d3333925367173c7c8f GIT binary patch literal 94298 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 literal 0 HcmV?d00001 diff --git a/src/ananas/images/field.png b/src/ananas/images/field.png new file mode 100644 index 0000000000000000000000000000000000000000..efa2405cf020179a395668c453a0aeac8ae53207 GIT binary patch literal 155 zcmeAS@N?(olHy`uVBq!ia0vp^VnEEr!3HEZELe9NNF{l?IEGZrxjJbh?*Ri2mVOOy z1Ge1;%eeI)NZPa=FIXiqt*Ki>&w06oCg_}PB|)* z+_K@C6vNhQ?)B2Gs}`-=JvAUx^7(Z32k+)LJ}s}WVVp8wWa)$>7b1bSF?hQAxvX>>{nGsA3ck(Gu2m{Ne&F?hQAxvX2BR0pkR}y zi(^Q|oa8;l&-s{j8H9a(WGAt0HUNSvSFZe7KCMw#SGT92SyDnm!p6oXK;+Ghjm)k* zbNjt{c?|CDEN!%H^y7-|&O*b-8IJZPylf0Jw0kbAUp7$zx`x5i)z4*}Q$iB}gz!Xp literal 0 HcmV?d00001 diff --git a/src/ananas/images/group2.png b/src/ananas/images/group2.png new file mode 100644 index 0000000000000000000000000000000000000000..5c6e955ee9aa3c5a138f9e5741a7429dc6202e2e GIT binary patch literal 174 zcmeAS@N?(olHy`uVBq!ia0vp^VnEEp!3HGLe)=8*Ql*|Qjv*GkZzn5q9S#t1xj#+j zoxFm`GrPvFUEc(W0!x(_vpUsSRoB3v?J9##Vpy40iYq}| zP{%;(CW~8>T{LQBBgSSi8W zCw3Ao=(;f>Hd zdWY`_@t$jZ)@VBl?KUerqwHM|95uc&1aI(rycJz4O5AH84|~@GFCRE^t!QXg>|yVE z;5o%RjX?Ms!pD~}IKGT`k1eBr^cVESmV|iEH9q4W?sbrdyjRu(!+Gcy?4DWd_RrwJ z;S|Cj{(!O1Z{yS#_k?)QH9m8A&*A0$m$38TkL*T4FgKb#H(}bpfaZO3Ft{#4zbA#p z-QS4yd2<}k)a-*?s)MYqf^NI7AozaOb`MOir}Bcg)xU!}tAfr?l6ZeUjmY&hTw_U8 zzoan1lQ-km)>f2iYN4&|KuyySc33|{{jM+3=$t`q^9X7!3i>WABK9*dbQc)71)N?1 zeCHRlaO0X$#N%=F_xGc%tqmcfZ0ER zBa6VRqe-Tm%nKeLAIHeZ2qKY)ct~$=FS@$ApjNB#=|UP`5$t>#`1W_;yFdN|2WHbu zSy?k-ECnaGAuZo!|?EMUNEmbF?zioWo2d1Xf$GK$or4mR)q^=&6x1Z&^#$| zEliRhW?WHG0h7rDm&+yc?djY=m7TeR|2Jdy8W1h53w;5%TuH+{{m(w4{!w7Pb&Zb002ov JPDHLkV1mdf@KFE& literal 0 HcmV?d00001 diff --git a/src/ananas/images/lib_dbgroup.png b/src/ananas/images/lib_dbgroup.png new file mode 100644 index 0000000000000000000000000000000000000000..30052901351d9e7bf76d6a5d3e229c1c7f4f5b63 GIT binary patch literal 681 zcmV;a0#^NrP)&zV_?Ao z5*83PzydZjIWo7*mC0P7hIDZfE_3<5-#swH6o9F#hCt|ta3lSv7N(?2IL zy)c3$7$;MJ&(F`%?RJq!Bt{CxokjufbUJ9a+a%)acs$M&j5m$)X|IKa2VBURhC+KI0TMX>AvRR4N6(-#;8IO+Bl- zh83R)tFO#hJGNjwyarojgISZfU%W%TUhh~iy;)|pDlGQ|&-^Q}9IwI}dakHR+-Ecz z!SnoRFjKIoBEM7f%VkAP8q;0c^`*cpfoeg8rK6{cn#5~rwfg_SOu_sNmJSWHrdyA0 z4!=Pz{qU9vreX9LNKH2$&P@hp31;q3!yr5%HO=X-PX=ZQ6pziT`ZN6tYfOW(K6naU P00000NkvXXu0mjfdXp^n literal 0 HcmV?d00001 diff --git a/src/ananas/images/msg_error.png b/src/ananas/images/msg_error.png new file mode 100644 index 0000000000000000000000000000000000000000..901b8b6500ccb748c7460c0921a8a36fcf82f8a0 GIT binary patch literal 964 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 SB>FAThYX&selF{r5}E*FFoEy@ literal 0 HcmV?d00001 diff --git a/src/ananas/images/t_cat_ed.png b/src/ananas/images/t_cat_ed.png new file mode 100644 index 0000000000000000000000000000000000000000..64ddd638ee170e5c963ca1ed2b43c9053f18ad4e GIT binary patch literal 404 zcmeAS@N?(olHy`uVBq!ia0vp^Vj#@H1|*Mc$*~4fY)RhkE)4%caKYZ?lYt_f1s;*b z3=G_YAk0{w5<>&kwWOMp#B@NiT78wLhOMNb#UkcwN$2@THe zc=h^q;E{+8nl|TDfAb%Ut4tG%qnxk(ryD`|y1GdWm1Ze@9A4NX%GR_<8Oko=f-dpa1av seS8~G%E-XL;7?*g!Vk|A0kfDGq~B*{l-vk$0)`)hr>mdKI;Vst0IQgv1ONa4 literal 0 HcmV?d00001 diff --git a/src/ananas/images/t_cat_g.png b/src/ananas/images/t_cat_g.png new file mode 100644 index 0000000000000000000000000000000000000000..99e052e55b68fc0d28d0b8bd2abc89b58ef2297c GIT binary patch literal 329 zcmeAS@N?(olHy`uVBq!ia0vp^Vj#@H1|*Mc$*~4fY)RhkE)4%caKYZ?lYt_f1s;*b z3=G_YAk0{w5<>&kwWOMuNt`{MbXjXhB%*vI^^zGxim!tE#eUUa>->&1wzX=7LX;O6Ja8`LaIc-`C>j66=yb zYI1AF*-e%GKEJWCF){Q$H_y%uN}M8g!aWlwPCS^9o;B+L5PW$4JAD$5s)Xl@doJuh zczCrZC0LaFGI_T^;hJj;gYeo*uU8y&zL6m2WZCg*sl+;`j(~+GAD-qVCMq&>b8{b_ zZ(lF*>-XcA3kyHbU3B90`}gTTet*|Le15*YBvAODfq}svl@twMMh1QXYmX8g So&P`|GI+ZBxvX<>&kwWOMuPT`fBowB@7IV@}4e^Ar-fh6C_w!7?d@;HgDP_ z@#^*Kz#|bGG;PkQ{^maxSDhfb={{Q#(w!i8p6H*TQryl?Ne$Ou^=ekh&WfFHD^z`tsSqEQcVFQBG`Tdd` zCHu|>9G&apGHLEg&93qdk}an%Y*6BCb6)Om{HVvKB>!%?dX9#fgF(+mNrw{wi+GMb zON!a2a4VsPO~7bQXH0L)6$8Q5j)m&qHXKd02$W>G>5!zvmu}_exBuxap$OBY;O04f zh0~H$m#-6kY80{1q~g@wLx-H$#Kgqf?Cbv-eEI%;vjGq|KYnKID!F9;{`n8z-`~#z plu7~m<;URz2R=-mu+W5+p{_PDPdr-lJ}~qcJYD@<);T3K0RTS9pjH3? literal 0 HcmV?d00001 diff --git a/src/ananas/images/t_doc.png b/src/ananas/images/t_doc.png new file mode 100644 index 0000000000000000000000000000000000000000..6b3b0da4956acb903f89405004e7e6753ad944fd GIT binary patch literal 353 zcmeAS@N?(olHy`uVBq!ia0vp^Vj#@H1|*Mc$*~4fY)RhkE)4%caKYZ?lYt_f1s;*b z3=G_YAk0{w5<>&kwWOMul_B}!MD11R*))5S5Q;?~M_jIc|1|=V9K%3 z(1&xPpG5K=NR7N?a`saKL-t#%1i?u5JyYgA_gTe~DWM4fOk|Q} literal 0 HcmV?d00001 diff --git a/src/ananas/images/t_doc_d.png b/src/ananas/images/t_doc_d.png new file mode 100644 index 0000000000000000000000000000000000000000..1eea2f2764fc25ed1587b442c3924cf6dd4f7ea5 GIT binary patch literal 435 zcmV;k0ZjghP)7$_&LBohDt0YFJa zK~#9!?Ub=f#6S>+zdh1K5NrZztgL(i;W{g^_YEYFkS?HgNF8C{;7Yse^{N94!56R+ zgewFeAS5Iq7ABBfcC!Jsb09@#XaE17f7pTlFhpbc1`&oKaU2hFmJa#m(zC~rZP`N8ng zG^H%dNpDqM7=icwn!0Er9sx@!jqRJxM#JmBynT;#(RwUqJrEV>db?4!uM@DCqpA-$ zXQ;D)RX}sVwI1u1kY*`~-&&iWQ)_e<>&kwWOMp#|!No~CpMimq$z0RZD$3bk{D0Rr zvCJRR*=q&(zh#*Hbuaxj{rKBA=Wn(pu3+E2&Rc+m;mYzitJ=F3Nu0Cr6l&nU6Oy@2 zwQEtK_9q*6&06O@HEVj#ZFykPw{q1hHT&~MA5U*#n(P*?rpx-_+mkhQU& zF>#~iw!XbTe(ii!Dd)uTYL}bWPYx3YP8qdG#idI!rA}>P`N6dBf77{D@*Mrq%*HXX RS-=2d@O1TaS?83{1OSoznRfsH literal 0 HcmV?d00001 diff --git a/src/ananas/images/t_doc_t.png b/src/ananas/images/t_doc_t.png new file mode 100644 index 0000000000000000000000000000000000000000..fda5f3ef3f9f6049e148bd8df6a291884615db6b GIT binary patch literal 396 zcmV;70dxL|P)8!de5gI@pu0U1d| zK~#9!?NqUDgD@04M_w{?M6h?tUS;a%Ac5GZlG%DQQT$V#qGo1_)U6*-i5dZNme2$+ z7?H5$Brm7;?w#*h2A;4$TTTN}6hR2l;CP?%=8zis-Fj6IW&jWb0UXEa)GbWSeEBkX zoy$<|`#wC+GuH5_S#1s}cI%Y}@Fs*f5|LRr3`4lC3nD`K_d6(hiKE7sQi`=}8brMS zBGP>sw~>5Yhp^A9UL)fy%b>L$9mlQc;PR3rK~WSBd9R)2DW$CLw)?c>_BICNbCXg& z#PMQElg;g9;n^Iw+}o*aJkJ5(1mN2yIxEgq1Yn&27!G6r00009U77ifz|*30U}96 zK~#9!wUjYV!!Q_yKSx;@atbEYp%>`J#LmPCvZjKuilQu_NO;W&xI!m3SeRRNLSo|p zl|rHi z{{l-XJM-MkV{0s!1BI-OGTSBk?hq}S_J=7N0n+-mY( z0S1GC3oI6k!Um@}ilV$vuZ2p`;c(~z*Xy+;$bq-pEx zQ&g4NY*q&^S&*h_No_$fKpe+B9uGu>>2&%EFIix%C643DQ{}+|PrpHk`<*Py@VuY&>z8#r9&6Rs z1r=a2nGgg4tyT+>pKaD!PNx%_&E_pQsE7%m#u!8dRmJyx;OT#oB(U2eqq%kw literal 0 HcmV?d00001 diff --git a/src/ananas/images/t_doc_tom.png b/src/ananas/images/t_doc_tom.png new file mode 100644 index 0000000000000000000000000000000000000000..32596cd3cc44b16c1fceab9c481d7878f1255bc5 GIT binary patch literal 361 zcmeAS@N?(olHy`uVBq!ia0vp^Vj#@H1|*Mc$*~4fY)RhkE)4%caKYZ?lYt_f1s;*b z3=G_YAk0{w5<>&kwWOMsQtJiPz+VxZ7BPZ!6Kid%1|*k&Cu5NNg6&k9;n z^2Sa*qG)l#hQj5-GgijFU`q2BIl;;FlIb>^jO1;Nvr>y<|2HI;|8_W={DrsbFvq*7 z3DFkwKG`hS;5r{1{A96R@2~gIN;6~_mSlQKw3(N-Z#@0#Vc|E+>C5yyg&tYRt+iZp z_SFjikkF?tPgosXjx9d1sYjzrKycUm_mMAD`yBJH-FmR=m~k6pN5||_6^lF#q+MgL zTRi9eyT?q6KW3V0?(KhD=b14wM`W8vwn%RNo!uMM zweGdSF&k#v3k>o9yADY>-~Vpn%lv_{M$fVQs{Z9KG1r{A6J7#CfWgz%&t;ucLK6Tj CC6R;x literal 0 HcmV?d00001 diff --git a/src/ananas/main.cpp b/src/ananas/main.cpp new file mode 100644 index 0000000..84b0b96 --- /dev/null +++ b/src/ananas/main.cpp @@ -0,0 +1,198 @@ +/**************************************************************************** +** $Id: main.cpp,v 1.5 2008/12/10 21:05:14 leader Exp $ +** +** Main file of Ananas Engine application +** +** Created : 20031201 +** +** Copyright (C) 2003-2004 Leader InfoTech. All rights reserved. +** +** This file is part of the Engine application of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.leaderit.ru/page=ananas or email sales@leaderit.ru +** See http://www.leaderit.ru/gpl/ for GPL licensing information. +** +** Contact org@leaderit.ru if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#include +#include +#include +#include +#include +//Added by qt3to4: +#include +#include +#include "mainform.h" +#include "dselectdb.h" +#include "dlogin.h" +#include "ananas.h" +#include "alog.h" +#include "aextensionfactory.h" + +//QApplication *application = 0; +QTranslator *translator = 0, tr_app(0), tr_lib(0), tr_plugins(0); +QString lang="en", + rcfile="", + username="", + userpassword=""; + +int setTranslator(QString lang) +{ + QString langdir; +#ifdef _Windows + langdir = qApp->applicationDirPath()+"/translations/"; +#else + langdir = "/usr/share/ananas/translations/"; +#endif + tr_app.load( langdir+"ananas-engine-"+lang.lower()+".qm","."); + tr_lib.load( langdir+"ananas-lib-"+lang.lower()+".qm","."); + tr_plugins.load( langdir+"ananas-plugins-"+lang.lower()+".qm","."); + return 0; +} + +int +parseCommandLine( int argc, char **argv ) +{ + QString param, name, value; + int i; + char *s, locale[50]="ru"; + + strncpy( locale, QTextCodec::locale(), sizeof( locale ) ); + s = strchr( locale, '_' ); + if ( s ) { + *s = 0; + } + lang = locale; + setTranslator( lang ); +// printf("locale=%s\n", locale ); + QString str_ru=QString::null, str_en=QString::null; + bool lang_setted = false; + bool help_setted = false; + for ( i=1; iargc(), qApp->argv() ) ) return 1; + qApp->installTranslator( &tr_app ); + qApp->installTranslator( &tr_lib ); + qApp->installTranslator( &tr_plugins ); + //--pixmap = QPixmap::fromMimeSource( "engine-splash-"+lang+".png" ); + pixmap = QPixmap( ":/images/engine-splash-"+lang+".png" ); + if ( pixmap.isNull() ) +#ifdef Q_OS_WIN32 + pixmap = QPixmap( qApp->applicationDirPath()+"/engine-splash-"+lang+".png" ); + qApp->addLibraryPath( qApp->applicationDirPath() ); +#else + pixmap = QPixmap( "/usr/share/ananas/designer/locale/engine-splash-"+lang+".png" ); + qApp->addLibraryPath( "/usr/lib/ananas/" ); +#endif + //--printf("extensions: \n%s\n",( const char *) AExtensionFactory::keys().join("\n") ); +// Test create extension +// AExtension *e = AExtensionFactory::create("AExtTest"); +// if (e) printf("EXT OK\n"); else printf("NO EXT OK\n"); + + if ( pixmap.isNull() ) + //--pixmap = QPixmap::fromMimeSource( "engine-splash-en.png" ); + pixmap = QPixmap( ":/images/engine-splash-en.png" ); + QSplashScreen *splash = new QSplashScreen( pixmap ); + +// printf("Keys:\n%s\n",( const char *) AExtensionFactory::keys().join("\n").toUtf8().data()); + + if ( ananas_login( rcfile, username, userpassword, 0, AApplication::Ananas ) ){ + splash->show(); + splash->message( QObject::tr("Init application"), Qt::AlignBottom, Qt::white ); + MainForm *w = new MainForm( 0, "MainForm"); + mainform = w; + mainformws = mainform->ws; + mainformwl = mainform->wl; + qApp->setMainWidget( w ); + w->rcfile = rcfile; +// printf( "rcfile = %s\n", rcfile.ascii() ); + w->show(); + ok = w->init(); + splash->clear(); + splash->finish( w ); + delete splash; + if ( ok ) { + qApp->connect( qApp, SIGNAL( lastWindowClosed() ), qApp, SLOT( quit() ) ); + rc = qApp->exec(); + ananas_logout( w->engine.db ); + if( w ) delete w; + w=0; + } else { + QMessageBox::critical(0, "error","Error init Ananas engine"); + } + aLog::close(); + return rc; + } + else + { + aLog::close(); + return 0; + } +} diff --git a/src/ananas/mainform.cpp b/src/ananas/mainform.cpp new file mode 100644 index 0000000..9993de2 --- /dev/null +++ b/src/ananas/mainform.cpp @@ -0,0 +1,314 @@ +/**************************************************************************** +** $Id: mainform.cpp,v 1.2 2008/12/06 22:56:39 leader Exp $ +** +** Code file of the Main form of Ananas Engine application +** +** Created : 20031201 +** +** Copyright (C) 2003-2004 Leader InfoTech. All rights reserved. +** +** This file is part of the Engine application of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.leaderit.ru/page=ananas or email sales@leaderit.ru +** See http://www.leaderit.ru/gpl/ for GPL licensing information. +** +** Contact org@leaderit.ru if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +/**************************************************************************** +****************************************************************************/ +#include +#include +#include +#include +#include +#include +#include +#include +//Added by qt3to4: +#include +#include +#include + +#include "mainform.h" + +#include "ananas.h" + +MainForm *mainform=NULL; +QWorkspace *mainformws=NULL; +aWindowsList *mainformwl=NULL; +//extern void messageproc(int n, const char *msg); + +/* + * Constructs a AnanasMainWindow as a child of 'parent', with the + * name 'name' and widget flags set to 'f'. + * + */ +MainForm::MainForm( QWidget* parent, const char* name, Qt::WFlags fl ) + : Q3MainWindow( parent, name, fl ) +{ +// QApopupmenu *popup; + Q3VBox *vb = new Q3VBox(this); + + setIcon( rcIcon("a-system.png")); + vb->setFrameStyle( Q3Frame::StyledPanel | Q3Frame::Sunken ); + ws = new QWorkspace( vb ); + wl = new aWindowsList(); + ws->setScrollBarsEnabled( TRUE ); + setCentralWidget( vb ); + statusBar()->setName("statusbar"); + if ( !name ) setName( "mainwindow" ); + //--engine_settings.insertSearchPath( QSettings::Unix, QString(QDir::homeDirPath())+QString("/.ananas")); + //--engine_settings.insertSearchPath( QSettings::Windows, "/ananasgroup/ananas" ); + +// QStringList lst = settings.entryList("/engine"); + engine_settings.beginGroup("/engine"); + bool maximize = engine_settings.readBoolEntry( "/maximize", 0 ); + int width = engine_settings.readNumEntry( "/geometry/width", 600 ); + int height = engine_settings.readNumEntry( "/geometry/height", 480 ); + int offset_x = engine_settings.readNumEntry( "/geometry/x", 0 ); + int offset_y = engine_settings.readNumEntry( "/geometry/y", 0 ); + engine_settings.endGroup(); + resize( QSize(width, height) );// .expandedTo(minimumSizeHint()) ); + move(offset_x,offset_y); + if(maximize) + { +// setWindowState(windowState() ^ WindowMaximized); + } + rcfile=""; +} + +bool +MainForm::init() +{ + MessagesWindow *msgWindow = new MessagesWindow( this );// , WDestructiveClose ); + moveDockWindow( msgWindow, Qt::DockBottom ); + setMessageHandler( true ); + msgWindow->hide(); + if ( !initEngine() ) return false; + connect( menubar, SIGNAL(activated(int)), &engine, SLOT(on_MenuBar(int)) ); + languageChange(); + engine.project.addObject(menubar); + engine.project.addObject(this); + engine.project.addObject(statusBar()); + languageChange(); + engine.on_systemstart(); + return true; +} + +bool +MainForm::initEngine() +{ + if (rcfile.isEmpty()) return false; + if ( !engine.init( rcfile ) ) return false; + engine.ws = ws; + engine.wl = wl; + connect( &engine, SIGNAL( statusMessage( const QString & ) ), this, SLOT( statusMessage( const QString & ) ) ); + md = engine.md; + if ( !md ) return false; + initMenuBar(); + initStatusBar(); + initActionBar(); + return true; +} + +void +MainForm::initMenuBar() +{ + Q3PopupMenu *m; + m = new Q3PopupMenu(); + windowsMenu = new Q3PopupMenu(); + connect( windowsMenu, SIGNAL( aboutToShow() ), + this, SLOT( windowsMenuAboutToShow() ) ); + m->insertItem(rcIcon("a-system.png"), tr( "About" ), this, SLOT( helpAbout() )); + //windowsMenu->insertItem(rcIcon("a-system.png"), tr( "Windows" ), this, SLOT( windowsMenuAboutToShow() )); + menubar = new AMenuBar( md, this, "menubar"); + InsertMainMenu( tr("&Help"), m ); + InsertMainMenu( tr("&Windows"), windowsMenu ); + menuBar()->show(); +} + +void +MainForm::initStatusBar() +{ +} + +void +MainForm::initActionBar() +{ + aCfgItem obj, item; + + obj = md->find( md->find( mdc_interface ), md_toolbars ); // look for md_toolbars + item = md->firstChild( obj ); + while ( !item.isNull() ) { // foreach md_toolbar + new aToolBar( md, item, &engine, this, md->attr( item, mda_name ) ); // create toolbar + item = md->nextSibling( item ); // next md_toolbar + } +} + +void +MainForm::helpAbout() +{ + QMessageBox::about( this, tr("About Ananas.Engine program"), + tr("

Ananas.Engin %1

is a programm " + "for executing application of accounting automation system

" + "Copyright 2003-2008 Leader Infotech, Valery Grazdankin, " + "Copyright 2003-2008 Project Ananas, Andrey Paskal, Grigory Panov, Andrey Strelnikov
" + "License: GPL

" + "technical support:
" + "lider-infotech@narod.ru
" + "app@linux.ru.net
" + "Web sites:
" + "
http://ananas.lrn.ru
" + "http://www.leaderit.ru" + "
Avalable extensions:

%2


" + ).arg(ananas_libversion()).arg( AExtensionFactory::keys().join(", ") ) ); +} + +void MainForm::InsertMainMenu(QString text, QObject *pop){ + menubar->insertItem(text, (Q3PopupMenu *) pop); + +} + + +void +MainForm::Exit(int code) +{ + + qApp->exit(code); +} +void +MainForm::close() +{ + engine_settings.beginGroup("/engine"); +// engine_settings.writeEntry( "/maximize", windowState()&WindowMaximized ? true: false); + engine_settings.writeEntry( "/geometry/width", width() ); + engine_settings.writeEntry( "/geometry/height", height() ); + engine_settings.writeEntry( "/geometry/x", pos().x() ); + engine_settings.writeEntry( "/geometry/y", pos().y() ); + engine_settings.endGroup(); + printf("exit\n" ); +//MainWindow::close(); +} + +void +MainForm::statusMessage( const QString &msg ) +{ + statusBar()->message( msg ); +} + +void +MainForm::setBackground( const QPixmap &pix ){ + ws->setBackgroundPixmap( pix ); +} + +/* + * Destroys the object and frees any allocated resources + */ +MainForm::~MainForm() +{ + engine.on_systemstop(); + close(); +// printf("Mainform destructor\n"); + if(ws) delete ws; + ws = 0; + if(wl) delete wl; + wl=0; + if(menubar) delete menubar; + menubar=0; +// printf("delete mainform\n"); +// cfg->on_systemstop(); +} + +/* + * Sets the strings of the subwidgets using the current + * language. + */ +void MainForm::languageChange() +{ + setCaption(QString( tr("Ananas")+" "+ananas_libversion() )+": "+md->info( md_info_name ) ); +// setCaption( tr( "Ananas VERSION" ) ); +} + +void MainForm::windowsMenuAboutToShow() +{ + windowsMenu->clear(); + int cascadeId = windowsMenu->insertItem(tr("&Cascade"), ws, SLOT(cascade() ) ); + int tileId = windowsMenu->insertItem(tr("&Tile"), ws, SLOT(tile() ) ); + int horTileId = windowsMenu->insertItem(tr("Tile &horizontal"), this, SLOT(tileHorizontal() ) ); + if ( ws->windowList().isEmpty() ) { + windowsMenu->setItemEnabled( cascadeId, FALSE ); + windowsMenu->setItemEnabled( tileId, FALSE ); + windowsMenu->setItemEnabled( horTileId, FALSE ); + } + windowsMenu->insertSeparator(); + QWidgetList windows = ws->windowList(); + if(windows.count()==0) return; + int i=0, count = windows.count(); + + do + { + int id=0; + if(windows.at(i) && windows.at(i)->isHidden()) + { + ++i; + continue; + } + id = windowsMenu->insertItem(windows.at(i)->caption(), this, SLOT( windowsMenuActivated( int ) ) ); + windowsMenu->setItemParameter( id, i ); + windowsMenu->setItemChecked( id, ws->activeWindow() == windows.at(i) ); + ++i; + }while( i < count ); +} + +void MainForm::tileHorizontal() +{ + // primitive horizontal tiling + QWidgetList windows = ws->windowList(); + int count =0; + for ( int i = 0; i < int(windows.count()); ++i ) + { + QWidget *window = windows.at(i); + if( !window ) continue; + if(!window->isHidden()) count++; + } + if ( !count ) return; + + int heightForEach = ws->height() / count; + int y = 0; + for ( int i = 0; i < windows.count(); ++i ) + { + QWidget *window = windows.at(i); + if ( !window ) continue; + if ( window->isHidden() ) continue; + if ( window->windowState() == Qt::WindowMaximized ) + { + // prevent flicker + window->hide(); + window->showNormal(); + } + int preferredHeight = window->minimumHeight()+window->parentWidget()->baseSize().height(); + int actHeight = QMAX(heightForEach, preferredHeight); + + window->parentWidget()->setGeometry( 0, y, ws->width(), actHeight ); + y += actHeight; + } +} + +void MainForm::windowsMenuActivated( int id ) +{ + QWidget* w = ws->windowList().at( id ); + if ( w ) w->showNormal(); + w->setFocus(); +} diff --git a/src/ananas/mainform.h b/src/ananas/mainform.h new file mode 100644 index 0000000..9f0d7ec --- /dev/null +++ b/src/ananas/mainform.h @@ -0,0 +1,116 @@ +/**************************************************************************** +** $Id: mainform.h,v 1.1 2008/11/05 21:16:26 leader Exp $ +** +** Header file of the Main form of Ananas Engine application +** +** Created : 20031201 +** +** Copyright (C) 2003-2004 Leader InfoTech. All rights reserved. +** +** This file is part of the Engine application of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.leaderit.ru/page=ananas or email sales@leaderit.ru +** See http://www.leaderit.ru/gpl/ for GPL licensing information. +** +** Contact org@leaderit.ru if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +/**************************************************************************** +****************************************************************************/ + +#ifndef ANANASMAINFORM_H +#define ANANASMAINFORM_H +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +//Added by qt3to4: +#include +#include +#include +#include +#include +#include +#include "ananas.h" +#include "amenubar.h" +#include "atoolbar.h" +#include "awindowslist.h" +#include "engine.h" + + +class Q3VBoxLayout; +class Q3HBoxLayout; +class Q3GridLayout; +class QAction; +class Q3ActionGroup; +class Q3ToolBar; +class Q3PopupMenu; + +/*! + * \ru + * Главное окно приложения Ананас, запускаемого пользователем. + * + * \_ru + */ + +class MainForm : public Q3MainWindow { + Q_OBJECT + +public: + MainForm( QWidget* parent = 0, const char* name = 0, Qt::WFlags fl = Qt::WType_TopLevel ); + ~MainForm(); + aEngine engine; + aCfg *md; + + AMenuBar* menubar; + Q3PopupMenu *windowsMenu; + QWorkspace* ws; + aWindowsList* wl; + QString rcfile; + +public slots: + bool init(); + bool initEngine(); + void initMenuBar(); + void initStatusBar(); + void initActionBar(); + void InsertMainMenu(QString text, QObject *pop); + void Exit(int code); + void close(); + void helpAbout(); + void statusMessage( const QString &msg ); + void windowsMenuAboutToShow(); + void windowsMenuActivated( int id ); + void tileHorizontal(); + void setBackground( const QPixmap &pix ); + +protected: + protected slots: + virtual void languageChange(); + +private: + QSettings engine_settings; +}; + +extern MainForm *mainform; +extern QWorkspace *mainformws; +extern aWindowsList *mainformwl; + +#endif // ANANASMAINFORM_H diff --git a/src/ananas/report.sxw b/src/ananas/report.sxw new file mode 100644 index 0000000000000000000000000000000000000000..1fdc4e1064d5088a44626867cd51ad313979d302 GIT binary patch literal 6806 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 literal 0 HcmV?d00001 diff --git a/src/ananas/report.tpl b/src/ananas/report.tpl new file mode 100644 index 0000000..25a88a0 --- /dev/null +++ b/src/ananas/report.tpl @@ -0,0 +1,21 @@ +<#section main#> + +
+Ananas HTTP Server +
+ +<#title#> + +<#endsection#> + +<#section endmain#> +
+ +<#endsection#> + +<#section trow#><#value#>)<#endsection#> + +<#section endrow#> +<#endsection#> + +<#section col#><#value#><#endsection#> diff --git a/src/designer/actiontree.cpp b/src/designer/actiontree.cpp new file mode 100644 index 0000000..f77e77b --- /dev/null +++ b/src/designer/actiontree.cpp @@ -0,0 +1,257 @@ +/**************************************************************************** +** $Id: actiontree.cpp,v 1.1 2008/11/05 21:16:26 leader Exp $ +** +** Code file of the Action Tree of Ananas Designer applications +** +** Created : 20031201 +** +** Copyright (C) 2003-2004 Leader InfoTech. All rights reserved. +** +** This file is part of the Designer application of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.leaderit.ru/page=ananas or email sales@leaderit.ru +** See http://www.leaderit.ru/gpl/ for GPL licensing information. +** +** Contact org@leaderit.ru if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#include +#include +#include +#include +#include +//Added by qt3to4: +#include + +#include "acfg.h" +#include "actiontree.h" +#include "mainform.h" +#include "deditaction.h" +#include "awindowslist.h" + +extern MainForm *mainform; +extern QPixmap ANANAS_EXPORT rcIcon(const char *name); +extern void set_Icon(Q3ListViewItem *item, const char *name); + + +ActionListViewItem::ActionListViewItem( Q3ListView *parent, aCfg * cfgmd, aCfgItem cfgobj, const QString &name ) +: ananasListViewItem( parent, cfgmd, cfgobj, name ) +{ + if (id) setRenameEnabled(0, true); +}; + +ActionListViewItem::ActionListViewItem( ananasListViewItem *parent, ananasListViewItem *after, aCfg * cfgmd, aCfgItem cfgobj, const QString &name ) +: ananasListViewItem( parent, after, cfgmd, cfgobj, name ) +{ + aCfgItem active; + QPixmap pix; + if (id) setRenameEnabled(0, true); + active = md->findChild( obj, md_active_picture, 0 ); + if ( !active.isNull() ) { + pix.loadFromData( md->binary( active ) ); + setPixmap( 0, pix ); + } +}; + +void +ActionListViewItem::loadTree() +{ + QString oclass; + aCfgItem cobj; + + // clear tree + clearTree(); + if ( !md ) return; + setPixmap(0, rcIcon("actions.png")); + cobj = md->firstChild ( obj ); + while ( !cobj.isNull() ) + { + oclass = md->objClass ( cobj ); + if ( oclass == md_actiongroup ) + loadGroup ( this, cobj ); + oclass = md->objClass ( cobj ); + if ( oclass == md_action ) + new ActionListViewItem( this, getLastChild(), md, cobj, QString::null ); + cobj = md->nextSibling ( cobj ); + } +}; + +void +ActionListViewItem::loadGroup( ananasListViewItem * parent, aCfgItem child ) +{ + ActionListViewItem * gparent; + QString oclass; + aCfgItem cobj; + + gparent = new ActionListViewItem( parent, getLastChild(), md, child, QString::null ); + gparent->setPixmap(0, rcIcon("action_g.png")); + cobj = md->firstChild ( gparent->obj ); + while ( !cobj.isNull() ) + { + oclass = md->objClass ( cobj ); + if ( oclass == md_actiongroup ) + loadGroup ( gparent, cobj ); + oclass = md->objClass ( cobj ); + if ( oclass == md_action ) + new ActionListViewItem( gparent, getLastChild(), md, cobj, QString::null ); + cobj = md->nextSibling ( cobj ); + } +}; + +void +ActionListViewItem::newActionGroup () +{ + aCfgItem newobj; + ActionListViewItem *newitem; + QString oclass = md->objClass( obj ); + + if ( oclass == md_actiongroup || oclass == md_actions ) + { + setSelected( FALSE ); + setOpen( TRUE ); + newobj = md->insert( obj, md_actiongroup, QObject::tr("New Action Group") ); + newitem = new ActionListViewItem( this, getLastChild(), md, newobj ); + newitem->setSelected( TRUE ); + newitem->setPixmap(0, rcIcon("action_g.png")); + newitem->edit(); + }; + +} + +void +ActionListViewItem::newAction () +{ + aCfgItem newobj; + ActionListViewItem *newitem; + QString oclass = md->objClass( obj ); + + if ( oclass == md_actiongroup || oclass == md_actions ) + { + setSelected( FALSE ); + setOpen( TRUE ); + newobj = md->insert( obj, md_action, QObject::tr("New Action") ); + newitem = new ActionListViewItem( this, getLastChild(), md, newobj ); + newitem->setSelected( TRUE ); + newitem->edit(); + }; +} + +void +ActionListViewItem::edit () +{ + QWorkspace *ws = mainform->ws; + aWindowsList *wl = mainform->wl; + QString oclass = md->objClass( obj ); + int objid = md->id( obj ); + if ( wl->find( objid ) ) { + wl->get( objid )->setFocus(); + return; + } + + if ( oclass == md_action ) + { + dEditAction * e = new dEditAction ( ws, 0, Qt::WDestructiveClose ); + wl->insert( objid, e ); + editor = e; + QObject::connect( mainform, SIGNAL( tosave() ), editor, SLOT( updateMD() ) ); + e->setData( this ); + e->show(); + //--mainform->addTab(++mainform->lastTabId,e->name()); + mainform->addTab(e); + return; + } +} + +aActionTreeView::aActionTreeView ( QWidget *parent, aCfg *cfgmd ) +: ananasTreeView( parent, cfgmd ) +{ + ActionListViewItem *actions; + aCfgItem item; + item = md->find ( mdc_actions ); + if ( item.isNull() ) + { + item = md->insert( md->find ( mdc_root ), md_actions, QString::null, -1 ); + } + actions = new ActionListViewItem ( this, md, item, QObject::tr ( "Actions" ) ); + actions->loadTree(); + actions->setOpen ( TRUE ); + connect( this, SIGNAL( contextMenuRequested( Q3ListViewItem*, const QPoint&, int) ), this, SLOT(ContextMenu() ) ); + connect( this, SIGNAL( returnPressed( Q3ListViewItem*) ), this, SLOT( itemEdit() ) ); + connect( this, SIGNAL( doubleClicked( Q3ListViewItem*) ), this, SLOT( itemEdit() ) ); +}; + + +void +aActionTreeView::ContextMenu() +{ + Q3PopupMenu *m=new Q3PopupMenu( this, "PopupMenu" ); + Q_CHECK_PTR(m); + + ContextMenuAdd( m ); + m->insertItem( QObject::tr("New &Group"), this, SLOT( itemNewGroup() ), Qt::CTRL+Qt::Key_G ); + m->insertItem( QObject::tr("New &Action"), this, SLOT( itemNewAction() ), Qt::CTRL+Qt::Key_A ); +// m->insertItem( QObject::tr("&Rename"), this, SLOT( itemRename() ), CTRL+Key_R); +// m->insertItem( QObject::tr("&Edit"), this, SLOT( itemEdit() ), CTRL+Key_E ); +// m->insertItem( QObject::tr("&Delete"), this, SLOT( itemDelete() ), CTRL+Key_D ); + m->exec( QCursor::pos() ); + delete m; +}; + +void +aActionTreeView::itemNewGroup() +{ + ActionListViewItem *i = (ActionListViewItem *) selectedItem(); + if ( i ) + i->newActionGroup(); +}; + +void +aActionTreeView::itemNewAction() +{ + ActionListViewItem *i = (ActionListViewItem *) selectedItem(); + if ( i ) + i->newAction(); +}; + +void +aActionTreeView::itemDelete() +{ + deleteItem(); +}; + +void +aActionTreeView::itemMoveUp() +{ + moveUpItem(); + +}; + +void +aActionTreeView::itemMoveDown() +{ + moveDownItem(); +}; + +void +aActionTreeView::itemEdit() +{ + ActionListViewItem *i = (ActionListViewItem *) selectedItem(); + if ( i ) i->edit(); +}; + +void +aActionTreeView::itemRename() +{ + renameItem(); +} diff --git a/src/designer/actiontree.h b/src/designer/actiontree.h new file mode 100644 index 0000000..90abd14 --- /dev/null +++ b/src/designer/actiontree.h @@ -0,0 +1,74 @@ +/**************************************************************************** +** $Id: actiontree.h,v 1.1 2008/11/05 21:16:26 leader Exp $ +** +** Header file of the Action Tree of Ananas Designer applications +** +** Created : 20031201 +** +** Copyright (C) 2003-2004 Leader InfoTech. All rights reserved. +** +** This file is part of the Designer application of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.leaderit.ru/page=ananas or email sales@leaderit.ru +** See http://www.leaderit.ru/gpl/ for GPL licensing information. +** +** Contact org@leaderit.ru if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#ifndef ACTIONTREE_H +#define ACTIONTREE_H +#include +#include +//#include "acfg.h" +#include "atreeitems.h" + +class QWidget; + +class ActionListViewItem : public ananasListViewItem +{ +public: +/* int id; + aCfgItem obj; + QWidget *editor; + aCfg *md; +*/ + ActionListViewItem( Q3ListView *parent, aCfg * cfgmd, aCfgItem cfgobj, const QString &name = QString::null ); + ActionListViewItem( ananasListViewItem *parent, ananasListViewItem *after, aCfg * cfgmd, aCfgItem cfgobj, + const QString &name = QString::null ); + void loadTree(); + void loadGroup ( ananasListViewItem * parent, aCfgItem child ); + void newActionGroup (); + void newAction (); + void edit (); +}; + +class aActionTreeView : public ananasTreeView +{ + Q_OBJECT +public: + + aActionTreeView( QWidget *parent, aCfg *cfgmd ); + +public slots: + void ContextMenu(); + void itemNewGroup(); + void itemNewAction(); + void itemMoveUp(); + void itemMoveDown(); + void itemDelete(); + void itemEdit(); + void itemRename(); + +}; +#endif //ACTIONTREE_H diff --git a/src/designer/aliaseditor.cpp b/src/designer/aliaseditor.cpp new file mode 100644 index 0000000..55f4108 --- /dev/null +++ b/src/designer/aliaseditor.cpp @@ -0,0 +1,88 @@ +/**************************************************************************** +** $Id: aliaseditor.cpp,v 1.1 2008/11/05 21:16:27 leader Exp $ +** +** Code file of the Alias editor of Ananas +** Designer applications +** +** Created : 20031201 +** +** Copyright (C) 2003-2004 Leader InfoTech. All rights reserved. +** +** This file is part of the Designer application of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.leaderit.ru/page=ananas or email sales@leaderit.ru +** See http://www.leaderit.ru/gpl/ for GPL licensing information. +** +** Contact org@leaderit.ru if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#include +#include "aliaseditor.h" +#include "acfg.h" + + +aAliasEditor::aAliasEditor( aCfg *c, aCfgItem o, Q3Table *t ) +{ + ac = c; + obj = o; + tAliases = t; + tAliases->setNumRows( 0 ); + tAliases->setNumCols( 1 ); + tAliases->horizontalHeader()->setLabel( 0, tr("Name") ); +} + +aAliasEditor::~aAliasEditor() +{ +} + +void aAliasEditor::setData() +{ + int i, j, n; + aCfgItem alias, langs, lang; + QString langtag; + + langs = ac->find( ac->find( mdc_root ), md_languages, 0 ); + langCount = ac->count( langs, md_language ); + n = ac->countChild( obj, md_alias ); + tAliases->setNumRows( langCount ); + for ( i = 0; i < langCount; i++ ) { + lang = ac->findChild( langs, md_language, i ); + langtag = ac->attr( lang, mda_tag ); + tAliases->verticalHeader()->setLabel( i, langtag ); + for ( j = 0; j < n; j++) { + alias = ac->findChild( obj, md_alias, j ); + if ( langtag == ac->attr( alias, mda_tag ) ) { + tAliases->setText( i, 0, ac->attr( alias, mda_name ) ); + } + } + } +} + +void aAliasEditor::updateMD() +{ + int i; + aCfgItem alias; + + do { + alias = ac->findChild( obj, md_alias, 0 ) ; + if ( !alias.isNull() ) ac->remove( alias ); + } while ( !alias.isNull() ); + for (i = 0; i < tAliases->numRows(); i++ ) { + if ( tAliases->text( i, 0 ) != "" ) { + alias = ac->insert( obj, md_alias, tAliases->text( i, 0 ), -1 ); + ac->setAttr( alias, mda_tag, tAliases->verticalHeader()->label( i )); + } + } +} + diff --git a/src/designer/aliaseditor.h b/src/designer/aliaseditor.h new file mode 100644 index 0000000..92cd06c --- /dev/null +++ b/src/designer/aliaseditor.h @@ -0,0 +1,54 @@ +/**************************************************************************** +** $Id: aliaseditor.h,v 1.1 2008/11/05 21:16:27 leader Exp $ +** +** Header file of the Alias editor of Ananas +** Designer applications +** +** Created : 20031201 +** +** Copyright (C) 2003-2004 Leader InfoTech. All rights reserved. +** +** This file is part of the Designer application of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.leaderit.ru/page=ananas or email sales@leaderit.ru +** See http://www.leaderit.ru/gpl/ for GPL licensing information. +** +** Contact org@leaderit.ru if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#ifndef ALIASEDITOR_H +#define ALIASEDITOR_H + +#include +#include +#include "acfg.h" + + +class aAliasEditor : public QObject +{ + Q_OBJECT +public: + aCfg *ac; + aCfgItem obj; + Q3Table *tAliases; + int langCount; + + aAliasEditor( aCfg *c, aCfgItem o, Q3Table *tAliases ); + ~aAliasEditor(); + + void setData(); + void updateMD( );//aCfgItem o ); +}; + +#endif diff --git a/src/designer/atreeitems.cpp b/src/designer/atreeitems.cpp new file mode 100644 index 0000000..7915bc9 --- /dev/null +++ b/src/designer/atreeitems.cpp @@ -0,0 +1,274 @@ +/**************************************************************************** +** $Id: atreeitems.cpp,v 1.2 2008/11/08 20:16:35 leader Exp $ +** +** Header file of the Ananas visual tree object +** of Ananas Designer applications +** +** Created : 20031201 +** +** Copyright (C) 2003-2004 Leader InfoTech. All rights reserved. +** +** This file is part of the Designer application of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.leaderit.ru/page=ananas or email sales@leaderit.ru +** See http://www.leaderit.ru/gpl/ for GPL licensing information. +** +** Contact org@leaderit.ru if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#include +#include +#include +#include +#include + +#include "atreeitems.h" +#include "alog.h" + +ananasListViewItem::ananasListViewItem( Q3ListView *parent, aCfg * cfgmd, aCfgItem cfgobj, + const QString &name ) +: Q3ListViewItem( parent ) +{ + obj = cfgobj; + md = cfgmd; + if ( name.isNull() ) setText( 0, md->attr( obj, mda_name ) ); + else setText( 0, name ); + id = md->id(obj); +} + +ananasListViewItem::ananasListViewItem( ananasListViewItem *parent, ananasListViewItem *after, + aCfg * cfgmd, aCfgItem cfgobj, const QString &name ) +: Q3ListViewItem( parent, after ) +{ + obj = cfgobj; + md = cfgmd; + if ( name.isNull() ) setText( 0, md->attr( obj, mda_name ) ); + else setText( 0, name ); + id = md->id(obj); +} + +ananasListViewItem::ananasListViewItem( Q3ListView *parent, Q3ListViewItem *after, aCfg * cfgmd, aCfgItem cfgobj, const QString &name ) +: Q3ListViewItem( parent, after ) +{ + obj = cfgobj; + md = cfgmd; + if ( name.isNull() ) setText( 0, md->attr( obj, mda_name ) ); + else setText( 0, name ); + id = md->id(obj); +} + +void +ananasListViewItem::clearTree() +{ + Q3ListViewItem *item, *nextitem; + + // clear tree + item = firstChild(); + while( item ) + { + nextitem = item->nextSibling(); + delete item; + item = nextitem; + } +} + +/* +void +ananasListViewItem::moveItem ( QListViewItem * after ) +{ +CHECK_POINT + aCfgItem temp = obj, temp2 = ((ananasListViewItem*)after)->obj; + QListViewItem::moveItem( after ); + obj = temp; + ((ananasListViewItem*)after)->obj = temp2; +} +*/ +void +ananasListViewItem::moveUp () +{ + if(!previousSibling()) return; // not previous item! - no changes + aCfgItem item = previousSibling()->obj; + + if ( obj.isNull() ) + { + aLog::print(aLog::Error, QObject::tr(" Ananas List View Item %1 is null").arg(md->attr(obj,mda_name))); + return; + } + if( md->swap( obj, item ) ) + { + previousSibling()->moveItem( this ); + aLog::print(aLog::Debug, QObject::tr("Ananas List View Item swaping")); + } + else + { + aLog::print(aLog::Error, QObject::tr("Ananas List View Item swaping")); + } +} + +void +ananasListViewItem::moveDown () +{ + if(!nextSibling()) return; // not next item! - no changes + aCfgItem item = nextSibling()->obj; + if ( item.isNull() ) + { + aLog::print(aLog::Error, QObject::tr(" Ananas List View Item %1 is null").arg(md->attr(obj,mda_name))); + return; + } + if( md->swap( obj, item ) ) + { + moveItem( nextSibling() ); + aLog::print(aLog::Debug, QObject::tr("Ananas List View Item swaping")); + } + else + { + aLog::print(aLog::Error, QObject::tr("Ananas List View Item swaping")); + } +} + +ananasListViewItem * +ananasListViewItem::previousSibling() // becose QListViewItem not have function previousSibling(); +{ + Q3ListViewItem *parent, *item; + parent = this->parent(); + item = parent->firstChild(); + while ( item ) + if ( (ananasListViewItem *)item->nextSibling() == this ) + return (ananasListViewItem *) item; + else item = item->nextSibling(); + return 0; +} + +ananasListViewItem* +ananasListViewItem::nextSibling() +{ + return (ananasListViewItem *)Q3ListViewItem::nextSibling(); +} + + +void +ananasListViewItem::okRename( int col ) +{ + Q3ListViewItem::okRename( col ); + if ( id && !obj.isNull() && col == 0 ) { + setText( 0, text( 0 ).stripWhiteSpace() ); + md->setAttr( obj, mda_name, text( 0 ) ); + } +} + +/* +ananasListViewItem* +ananasListViewItem::getLastChild( QListViewItem * parent ) +{ + QListViewItem *item, *nextitem; + item = parent->firstChild(); + while( item ) + { + nextitem = item->nextSibling(); + if ( nextitem ) + item = nextitem; + else + return (ananasListViewItem*) item; + } + return 0; +}; +*/ + +ananasListViewItem* +ananasListViewItem::getLastChild() +{ + Q3ListViewItem *item, *nextitem; + item = firstChild(); + while( item ) + { + nextitem = item->nextSibling(); + if ( nextitem ) + item = nextitem; + else + return (ananasListViewItem*) item; + } + return 0; +}; + + +ananasTreeView::ananasTreeView ( QWidget *parent, aCfg *cfgmd ) +:Q3ListView ( parent ) +{ + md = cfgmd; + addColumn( "" ); + header()->hide(); + setSorting ( -1 ); + setSelectionMode( Single ); +}; + + +void +ananasTreeView::ContextMenuAdd( Q3PopupMenu * m ) +{ + //--QLabel *caption = new QLabel( tr("" "Context Menu"), this ); + //--caption->setAlignment( Qt::AlignCenter ); + //--m->insertItem( caption ); + m->insertItem( tr("&Rename"), this, SLOT( itemRename() ), Qt::CTRL+Qt::Key_R); + m->insertItem( tr("&Edit"), this, SLOT( itemEdit() ), Qt::CTRL+Qt::Key_E ); + m->insertItem( tr("&Delete"), this, SLOT( itemDelete() ), Qt::CTRL+Qt::Key_D ); + m->insertItem( tr("&MoveUp"), this, SLOT( itemMoveUp() ), Qt::CTRL+Qt::Key_U ); + m->insertItem( tr("&MoveDown"), this, SLOT( itemMoveDown() ), Qt::CTRL+Qt::Key_M ); + m->insertItem( tr("&SaveItem"), this, SLOT( itemSave() ) ); + m->insertItem( tr("&LoadItem"), this, SLOT( itemLoad() ) ); + m->insertSeparator(); +}; + +void +ananasTreeView::deleteItem() +{ + ananasListViewItem *i = (ananasListViewItem *) selectedItem(); + if ( i ) + { + if ( i->id ) { + md->remove( i->obj ); + delete i; + } + } +}; + +void +ananasTreeView::moveUpItem() +{ + ananasListViewItem *i = (ananasListViewItem *) selectedItem(); + if ( i ) + { + if ( i->id ) { + i->moveUp(); + } + } +} + +void +ananasTreeView::moveDownItem() +{ + ananasListViewItem *i = (ananasListViewItem *) selectedItem(); + if ( i ) + { + if ( i->id ) { + i->moveDown(); + } + } +} + +void +ananasTreeView::renameItem() +{ + if ( selectedItem() ) selectedItem()->startRename( 0 ); +} + diff --git a/src/designer/atreeitems.h b/src/designer/atreeitems.h new file mode 100644 index 0000000..90f7741 --- /dev/null +++ b/src/designer/atreeitems.h @@ -0,0 +1,83 @@ +/**************************************************************************** +** $Id: atreeitems.h,v 1.1 2008/11/05 21:16:27 leader Exp $ +** +** Header file of the Ananas visual tree object +** of Ananas Designer applications +** +** Created : 20031201 +** +** Copyright (C) 2003-2004 Leader InfoTech. All rights reserved. +** +** This file is part of the Designer application of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.leaderit.ru/page=ananas or email sales@leaderit.ru +** See http://www.leaderit.ru/gpl/ for GPL licensing information. +** +** Contact org@leaderit.ru if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#ifndef ATREEITEMS_H +#define ATREEITEMS_H +#include +#include +#include +#include "acfg.h" + +class QWidget; + +class ananasListViewItem : public Q3ListViewItem +{ +public: + int id; + aCfgItem obj; + QWidget *editor; + aCfg *md; + + ananasListViewItem( Q3ListView *parent, aCfg * cfgmd, aCfgItem cfgobj, const QString &name = QString::null ); + ananasListViewItem( Q3ListView *parent, Q3ListViewItem *after, aCfg * cfgmd, aCfgItem cfgobj, const QString &name = QString::null ); + ananasListViewItem( ananasListViewItem *parent, ananasListViewItem *after, aCfg * cfgmd, + aCfgItem cfgobj, const QString &name = QString::null ); + + void clearTree(); + void moveUp (); + void moveDown (); + + ananasListViewItem *previousSibling(); + ananasListViewItem *nextSibling(); +// ananasListViewItem *getLastChild( QListViewItem * parent ); + ananasListViewItem *getLastChild(); +protected: + virtual void okRename( int col ); +}; + +class ananasTreeView +: public Q3ListView +{ + Q_OBJECT +public: + aCfg *md; + + ananasTreeView( QWidget *parent, aCfg *cfgmd ); + + void ContextMenuAdd( Q3PopupMenu * m ); + void deleteItem(); + void moveUpItem (); + void moveDownItem (); + void renameItem(); + void saveItem(); + void loadItem(); +}; + + +#endif diff --git a/src/designer/cfgform.cpp b/src/designer/cfgform.cpp new file mode 100644 index 0000000..78347af --- /dev/null +++ b/src/designer/cfgform.cpp @@ -0,0 +1,860 @@ +#include "cfgform.h" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +//Added by qt3to4: +#include +#include +//#include + +#include "ananas.h" +#include "mainform.h" +#include "deditfield.h" +#include "deditcfg.h" +#include "deditdoc.h" +#include "deditrole.h" +#include "deditreport.h" +#include "deditdialog.h" +#include "deditcat.h" +#include "deditlang.h" +#include "mdtree.h" +#include "actiontree.h" +#include "alog.h" + +/* + * Constructs a CfgForm as a child of 'parent', with the + * name 'name' and widget flags set to 'f'. + * + */ +CfgForm::CfgForm(QWidget* parent, const char* name, Qt::WindowFlags fl) + : Q3MainWindow(parent, name, fl) +{ + setupUi(this); + + (void)statusBar(); +} + +/* + * Destroys the object and frees any allocated resources + */ +CfgForm::~CfgForm() +{ + destroy(); + // no need to delete child widgets, Qt does it all for us +} + +/* + * Sets the strings of the subwidgets using the current + * language. + */ +void CfgForm::languageChange() +{ + retranslateUi(this); +} + +extern MainForm *mainform; + +void +set_Icon(Q3ListViewItem *item, const char *name) +{ + char in[200]; + strcpy(in, name); + strcat(in,".png"); + item->setPixmap(0, rcIcon(in)); +} + + +/*class ObjEditing { + public: + ObjEditing(){item=NULL; widget=NULL;} + ObjEditing(QListViewItem *aitem, QWidget *awidget) {item=aitem;widget=awidget;} + + QListViewItem *item; + QWidget *widget; +}; +*/ +//typedef QValueList ObjEditingList; +//ObjEditingList ObjEdList; + +CfgForm *configform=NULL; + + +void CfgForm::fileNew() +{ + +} + +void CfgForm::fileOpen() +{ + +} + +void CfgForm::fileSave() +{ + +} + +void CfgForm::fileSaveAs() +{ + +} + +void CfgForm::filePrint() +{ + +} + +void CfgForm::fileExit() +{ +} + + +void +CfgForm::init( QString &rcf, bool flagNew ) // flagNew shows if it needs to create new configuration +{ + statusBar()->hide(); + configform=this; + rcfile = rcf; // resource file + setIcon( rcIcon("a-system.png")); + if ( !flagNew ) { // read rcfile + if ( cfg.readrc( rcfile ) ) { + aLog::print(aLog::Error,tr("CfgForm readrc error")); + return; + } + } +// globalCfg = &cfg; + setCaption(tr("Business scheme: ")+cfg.info( mda_name )); +// QWidget *tab_0 = new QWidget( tabWidget, "tab" ); + Q3GridLayout *l = new Q3GridLayout( tabWidget->page(0), 1, 1, 1, 2, "tablayout" ); + mdtree = new aMetadataTreeView( tabWidget->page(0), &cfg ); // metadata tree creation + l->addWidget( mdtree, 0, 0); +// tabWidget->insertTab( tab_0, tr( "Business scheme" ), 0 ); +// tabWidget->setCurrentPage( 0 ); + initLang(); // languages tab initialization + initRoles(); // rights tab initialization + initImageCollection(); // image collection tab initialization + mainform->TBToolbar->setShown( TRUE ); // show edit toolbar + mainform->configSaveAction->setVisible( TRUE ); // show save button + + actiontree = new aActionTreeView ( tabWidget->page(1), &cfg ); // action tree creation + Q3GridLayout *j = new Q3GridLayout( tabWidget->page(1), 1, 1, 1, 2, "atablayout" ); + j->addWidget( actiontree, 0, 0); + + interfacetree = new InterfaceTreeView ( tabWidget->page(2), &cfg ); // interface tree creation + Q3GridLayout *k = new Q3GridLayout( tabWidget->page(2), 1, 1, 1, 2, "itablayout" ); + k->addWidget( interfacetree, 0, 0); + // connection toolbar actions + connect(mainform->objMetadataNewAction, SIGNAL(activated()), mdtree, SLOT( itemNew() ) ); + connect(mainform->objMetadataEditAction, SIGNAL(activated()), mdtree, SLOT( itemEdit() ) ); + connect(mainform->objActionsNewAction, SIGNAL(activated()), actiontree, SLOT( itemNewAction() ) ); + connect(mainform->objActionsNewGroupAction, SIGNAL(activated()), actiontree, SLOT( itemNewGroup() ) ); + connect(mainform->objActionsEditAction, SIGNAL(activated()), actiontree, SLOT( itemEdit() ) ); + connect(mainform->objInterfaceNewCommandAction, SIGNAL(activated()), interfacetree, SLOT( itemNewCommand() ) ); + connect(mainform->objInterfaceNewSubmenuAction, SIGNAL(activated()), interfacetree, SLOT( itemNewSubmenu() ) ); + connect(mainform->objInterfaceNewSeparatorAction, SIGNAL(activated()), interfacetree, SLOT( itemNewSeparator() ) ); + connect(mainform->objInterfaceEditAction, SIGNAL(activated()), interfacetree, SLOT( itemEdit() ) ); + connect(mainform->objImageCollectionAddAction, SIGNAL(activated()), this, SLOT( bAddImage_clicked() ) ); + connect(mainform->objLanguagesNewAction, SIGNAL(activated()), this, SLOT( bAdd_clicked() ) ); + connect(mainform->objLanguagesEditAction, SIGNAL(activated()), this, SLOT( bEdit_clicked() ) ); + connect(mainform->objLanguagesClearAction, SIGNAL(activated()), this, SLOT( bKill_clicked() ) ); + connect(mainform->objRoleNewAction, SIGNAL(activated()), this, SLOT( bAddRole_clicked() ) ); + connect(mainform->objRoleEditAction, SIGNAL(activated()), this, SLOT( bEditRole_clicked() ) ); + connect(mainform->objRoleClearAction, SIGNAL(activated()), this, SLOT( bKillRole_clicked() ) ); +} + +/* + * Image collection initialization + */ +void CfgForm::initImageCollection() +{ + aCfgItem oroot, image_collection, image; + int i, n; + QPixmap pix; + QString name; + + oroot = cfg.find( mdc_root ); // get root + image_collection = cfg.find( oroot, md_image_collection, 0 ); // get image col part + if ( image_collection.isNull() ) cfg.insert( oroot, md_image_collection, QString::null, -1 ); + n = cfg.countChild( image_collection, md_image ); // count images + for ( i = 0; i < n; i++ ) { + image = cfg.findChild( image_collection, md_image, i ); // foreach + name = cfg.attr( image, mda_name ); // get name + pix.loadFromData( cfg.binary( image ) ); // load binary + Q3IconViewItem *item = new Q3IconViewItem( vImageCollection, name, pix ); // create image + item->setRenameEnabled( TRUE ); // set rename enabled + vImageCollection->insertItem( item, 0 ); // insert image + idList.insert( cfg.id( image ), item ); // add image into dict + } + if ( vImageCollection->count() ) bRemoveImage->setEnabled( TRUE ); // enable remove button +} + +/* + * Add image into collection + */ +void CfgForm::bAddImage_clicked() +{ + QPixmap pix; + Q3FileDialog *fd = new Q3FileDialog( "", "Images (*.png *.xpm *.jpg *.jpeg *.bmp)", 0, 0, TRUE ); + QByteArray ba; + QString name; + QStringList names; + aCfgItem image_collection, image; + QFile f; + PixmapPreview *p = new PixmapPreview; + + fd->setContentsPreview( p, p ); + fd->setPreviewMode( Q3FileDialog::Contents ); + fd->setContentsPreviewEnabled( TRUE ); + fd->setCaption( tr("Open image dialog" ) ); + fd->setMode( Q3FileDialog::ExistingFiles ); // tune file dialogue + if ( fd->exec() == QDialog::Accepted ) { // if accepted + names = fd->selectedFiles(); // get selected filenames + QStringList::Iterator it = names.begin(); + while( it != names.end() ) { // trough the names + name = *it; + ++it; + if ( !name.isEmpty() ) { // if not empty + f.setName( name ); + if ( f.open( QIODevice::ReadOnly ) ){ // open r\o mode + ba = f.readAll(); // get binary + f.close(); + pix.loadFromData( ba ); // load pixmap from binary + } else continue; + } + QFileInfo fi( name ); + name = fi.baseName(); + Q3IconViewItem *item = new Q3IconViewItem( vImageCollection, name, pix ); + item->setRenameEnabled( TRUE ); // set rename enabled + vImageCollection->insertItem( item, 0 ); // insert image + image_collection = cfg.findChild( cfg.find( mdc_root ), md_image_collection, 0 ); + image = cfg.insert( image_collection, md_image, name ); // insert image metaitem + cfg.setBinary( image, ba ); // set binary + idList.insert( cfg.id( image ), item ); // add image into dict + } + delete fd; // delete file dialogue + bRemoveImage->setEnabled( TRUE ); // remove button enable + mainform->objTBDeleteAction->setEnabled( TRUE ); // toolbar button enable + } +} + +/* + * Remove image from collection + */ +void CfgForm::bRemoveImage_clicked() +{ + Q3IconViewItem *current; + aCfgItem image_collection, image; + int i, n, id; + + image_collection = cfg.findChild( cfg.find( mdc_root ), md_image_collection, 0 ); + n = cfg.countChild( image_collection, md_image ); // count image in collection + current = vImageCollection->currentItem(); // get current selected image + for ( i = 0; i < n; i++ ) { + image = cfg.findChild( image_collection, md_image, i ); // get metaitem + id = cfg.id( image ); // get id + if ( current == idList.find( id ) ) { // if corresponds + cfg.remove( image ); + idList.remove( id ); // rmove from metadata and from dict + delete current; + break; + } + } + if ( !vImageCollection->count() ) { // if last image removed + bRemoveImage->setEnabled( FALSE ); // disable remove button and toolbar button + mainform->objTBDeleteAction->setEnabled( FALSE ); + } + vImageCollection->sort( TRUE ); // turn image sorting on +} + +/* + * Image rename event handler + */ +void CfgForm::vImageCollection_itemRenamed( Q3IconViewItem *item, const QString &name ) +{ + aCfgItem image_collection, image; + int i, n; + + image_collection = cfg.findChild( cfg.find( mdc_root ), md_image_collection, 0 ); + n = cfg.countChild( image_collection, md_image ); // count images + for ( i = 0; i < n; i++ ) { + image = cfg.findChild( image_collection, md_image, i ); // get timage + if ( item == idList.find( cfg.id( image ) ) ) { // if corresponds + cfg.setAttr( image, mda_name, name ); // rename metaitem + break; + } + } +} + +/* + * Languages initialization + */ +void CfgForm::initLang() +{ + aCfgItem oroot; + aCfgItem lang, obj; + int i, n; + + tLang->setNumRows( 0 ); + oroot = cfg.find( mdc_root ); // get root + if ( oroot.isNull() ) { + aLog::print(aLog::Info,tr("CfgForm metadata root is null")); + } + lang = cfg.findChild( oroot, md_languages, 0 ); // get lang part + if ( lang.isNull() ) { + aLog::print(aLog::Info,tr("CfgForm metadata lang is null")); + } + if ( lang.isNull() ) lang = cfg.insert( oroot, md_languages, QString::null, -1 ); + n = cfg.count( lang, md_language ); // count languages + aLog::print(aLog::Debug,QString(tr("lang = %1")).arg(n)); + for ( i = 0; i < n; i++ ) { // foreach + obj = cfg.find( lang, md_language, i); // get lang + if ( obj.isNull() ) aLog::print(aLog::Debug,QString(tr("CfgForm %1 metadata lang is null")).arg(i)); + tLang->insertRows( tLang->numRows(), 1 ); // insert into table + tLang->setText( tLang->numRows()-1, 0, cfg.attr( obj, mda_tag ) ); + tLang->setText( tLang->numRows()-1, 1, cfg.attr( obj, mda_name ) ); + tLang->setText( tLang->numRows()-1, 2, cfg.attr( obj, mda_trfile ) ); // fill cols + } + if ( !tLang->numRows() ) { // turn buttons off + bDelete->setEnabled( FALSE ); + bEdit->setEnabled( FALSE ); + bKill->setEnabled( FALSE); + mainform->objLanguagesClearAction->setEnabled( FALSE ); + mainform->objLanguagesEditAction->setEnabled( FALSE ); + } +} + +/* + * Roles initialization + */ +void CfgForm::initRoles() +{ + aCfgItem oroot; + aCfgItem role, obj; + int i, n; + QString rd; + + tRole->setNumRows( 0 ); // no rows + oroot = cfg.find( mdc_root ); // get root + role = cfg.find( oroot, md_roles, 0 ); // get role part + if ( role.isNull() ) role = cfg.insert( oroot, md_roles, QString::null, -1 ); + n = cfg.count( role, md_role ); // count roles + for ( i = 0; i < n; i++ ) { + obj = cfg.find( role, md_role, i); // get role + tRole->insertRows( tRole->numRows(), 1 ); // insert this + tRole->setText( tRole->numRows()-1, 0, cfg.attr( obj, mda_name ) ); + rd = cfg.sText( obj, md_description ); + rd.replace( QChar('\n'), " " ); // remove \n symbol for good perception + tRole->setText( tRole->numRows()-1, 1, rd ); // fill cols + } + if ( !tRole->numRows() ) { // turn unneccessary buttons off + bDeleteRole->setEnabled( FALSE ); + bEditRole->setEnabled( FALSE ); + bKillRole->setEnabled( FALSE); + mainform->objRoleClearAction->setEnabled( FALSE ); + mainform->objRoleEditAction->setEnabled( FALSE ); + } +} + +/* + * Destroy configuration form + */ +void CfgForm::destroy() +{ + configform = 0; +// globalCfg = 0; // clear pointers + mainform->cfgform = NULL; + mainform->removeTab(name()); +} + +/* + * Save metadata on disk + */ +void CfgForm::save() +{ +// int i, n; +// aCfgItem oroot, lang, obj; + aDatabase *database = aDatabase::database(); + + if ( cfg.writerc( rcfile ) ) cfg_message(0, tr("Unable to write rc file.")); + else { +// if ( database.init( rcfile ) ){ + database->update(); +// database.done(); +// } + } +} + +/* + * Add new language + */ +void CfgForm::bAdd_clicked() +{ + aCfgItem lang, obj; + + tLang->insertRows( tLang->numRows(), 1 ); // insert new row + tLang->setCurrentCell( tLang->numRows()-1, 0 ); // focus on new role + lang = cfg.find( cfg.find( mdc_root ), md_languages, 0 ); // get lang part + obj = cfg.insert( lang, md_language, tr("New language") ); // insert new metaitem + dEditLang *e = new dEditLang( ws, 0, Qt::WDestructiveClose ); + e->setData( configform, obj ); + e->show(); // create editor, set its data and show this one + bDelete->setEnabled( TRUE ); + bEdit->setEnabled( TRUE ); + bKill->setEnabled( TRUE ); // enable control buttons and toolbar actions + mainform->objLanguagesClearAction->setEnabled( TRUE ); + mainform->objLanguagesEditAction->setEnabled( TRUE ); + mainform->objTBDeleteAction->setEnabled( TRUE ); +} + +/* + * Delete language + */ +void CfgForm::bDelete_clicked() +{ + if ( ! QMessageBox::warning( this, tr("Deleting row"), tr("Delete '%1'?").arg( tLang->text( tLang->currentRow(), 1 ) ), tr("Yes"), tr("No") ) ) { +// request for delete + aCfgItem lang, obj, alias; + int i, n; + + lang = cfg.find( cfg.find( mdc_root ), md_languages, 0 ); // get lang part + n = cfg.count( lang, md_language ); // count langs + for ( i = 0; i < n; i++ ) { + obj = cfg.find( lang, md_language, i ); // foreach lang + if ( cfg.attr( obj, mda_tag ) == tLang->text( tLang->currentRow(), 0 ) ) { + cfg.remove( obj ); // if tags corresponding remove metaitem + break; + } + } + tLang->removeRow( tLang->currentRow() ); // remove row + if ( !tLang->numRows() ) { + bDelete->setEnabled( FALSE ); + bEdit->setEnabled( FALSE ); + bKill->setEnabled( FALSE ); // if last row removed then buttons and actions are disabled + mainform->objLanguagesClearAction->setEnabled( FALSE ); + mainform->objLanguagesEditAction->setEnabled( FALSE ); + mainform->objTBDeleteAction->setEnabled( FALSE ); + } + } +} + +/* + * Language editing + */ +void CfgForm::bEdit_clicked() +{ + aCfgItem obj; + + obj = cfg.find( cfg.find( cfg.find( mdc_root ), md_languages, 0 ), md_language, tLang->currentRow() ); + // get lang metaitem + dEditLang *e = new dEditLang( ws, 0, Qt::WDestructiveClose ); + e->setData( configform, obj ); + e->show(); // create editor, set its data and show this one +} + +/* + * Double-click table event + */ +void CfgForm::tLang_doubleClicked( int, int, int, const QPoint & ) +{ + bEdit_clicked(); // call edit button click event +} + +/* + * Kill dead aliases througout metadata + */ +void CfgForm::bKill_clicked() +{ + aCfgItem oroot, alias; + int i = 0, s, n, ac, killed = 0; + + oroot = cfg.find( mdc_root ); // get root + n = cfg.count( oroot, md_alias ); // count aliases + while ( i < n ) { // foreach + ac = 0; // unset counter + alias = cfg.find( oroot, md_alias, i ); // get alias + for ( s = 0; s < tLang->numRows(); s++ ) // check aliase tag on existing in lang list + if ( cfg.attr( alias, mda_tag ) == tLang->text( s, 0 ) ) ac++; + if ( !ac ) { + cfg.remove( alias ); + killed++; + n--; // if dead then delete this and change counters + } else i++; + } + QMessageBox::warning( this, tr("Clearing dead aliases"), tr("%1 dead aliases killed.").arg( killed ), tr("OK") ); + // information message box +} + +void CfgForm::newObj() +{ +} + + +void CfgForm::listCfg_onItem( Q3ListViewItem * ) +{ + +} + + + +void CfgForm::newField() +{ +} + + + +void CfgForm::newForm() +{ +} + + +void CfgForm::newTable() +{ +} + +/* + * Cofiguration form close event + */ +void CfgForm::closeEvent( QCloseEvent *e ) +{ + + if ( !cfg.modified() ) { // if data didn't modify send event further + Q3MainWindow::closeEvent( e ); + return; + } + switch( QMessageBox::warning( this, tr("Saving changes"), + tr("Save changes %1?").arg( caption() ), + tr("Yes"), tr("No"), tr("Cancel") ) ) { + // request for saving before exit + case 0: // yes + { + mainform->closeChildWindows(); + save(); // save data and send event further + Q3MainWindow::closeEvent( e ); +/* + cancelupdate=0; + if (closeSubWindows()) e->ignore(); + else { + if (mainform) mainform->configSave(); + QMainWindow::closeEvent( e ); + } +*/ + } + break; + case 1: // no +// if (closeSubWindows()) {//e->ignore(); +// } +// else { +//// cancelupdate=1; +// //e->accept(); +// } // send event further + mainform->closeChildWindows(); + Q3MainWindow::closeEvent(e); + break; + default: + e->ignore(); // ignore event by default + break; + mainform->TBToolbar->setShown( FALSE ); + mainform->configSaveAction->setVisible( FALSE ); + mainform->tbMetadata->setShown( FALSE ); + mainform->tbActions->setShown( FALSE ); + mainform->tbInterface->setShown( FALSE ); // disable toolbars anyway + mainform->tbRights->setShown( FALSE ); + mainform->tbLanguages->setShown( FALSE ); + mainform->tbImageCollection->setShown( FALSE ); +// closeSubWindows(); + } + // } else { + // e->accept(); + // } +} + +/* + * Subwindow close event + */ +int +CfgForm::closeSubWindows() +{ + QWidgetList windows = ws->windowList(); // workspace windows list + if ( windows.count() ) { // if there're opened windows + for ( int i = 0; i < int(windows.count()); ++i ) { // foreach + QWidget *window = windows.at( i ); + if (window!=this) { // if not this + if ( window->className() == tr ( "messageswindow" ) ) { + delete window; // if messageswindow remove it + continue; + } + if ( !window->close() ) return 1; // if cannot close return error + else delete window; // else delete window + } + } + } + return 0; +} + + + +/* +int CfgForm::activateExist( QListViewItem *item ) +{ + QWidget *window; + + window=findOpened(item); + if (window) { + window->setFocus(); + return 1; + } + return 0; +} +*/ + +//QWidget * +//CfgForm::findOpened( QListViewItem *item ) +//{ +/* + ObjEditingList::iterator it; + QWidgetList windows = ws->windowList(); + QWidget *window, *res=NULL; + int f; + + if ( windows.count() ) { + it = ObjEdList.begin(); + while ( it != ObjEdList.end()) { + f=0; + for ( int i = 0; i < int(windows.count()); ++i ) { + window = windows.at( i ); + if (window==(*it).widget) { + f=1; break; + } + } + if (!f) { + it=ObjEdList.remove(it); + } else it++; + } + for ( it = ObjEdList.begin(); it != ObjEdList.end(); ++it ) { + if (item==(*it).item) { + res=(*it).widget; + break; + } + } + } + return res; +*/ +// return NULL; +//} + +/* + * When tab switches some actions reconnect to corresponding toolbar buttons and toolbars recombinate + */ +void CfgForm::tabWidget_selected( const QString &tab ) +{ + bool fM, fA, fI, fR, fL, fIC; + + if ( tab == tr("Metadata") ) { + connect(mainform->objTBDeleteAction, SIGNAL(activated()), mdtree, SLOT( itemDelete() ) ); + connect(mainform->objTBRenameAction, SIGNAL(activated()), mdtree, SLOT( itemRename() ) ); + connect(mainform->objTBMoveUpAction, SIGNAL(activated()), mdtree, SLOT( itemMoveUp() ) ); + connect(mainform->objTBMoveDownAction, SIGNAL(activated()), mdtree, SLOT( itemMoveDown() ) ); + fM = TRUE; + } else { + disconnect(mainform->objTBDeleteAction, SIGNAL(activated()), mdtree, SLOT( itemDelete() ) ); + disconnect(mainform->objTBRenameAction, SIGNAL(activated()), mdtree, SLOT( itemRename() ) ); + disconnect(mainform->objTBMoveUpAction, SIGNAL(activated()), mdtree, SLOT( itemMoveUp() ) ); + disconnect(mainform->objTBMoveDownAction, SIGNAL(activated()), mdtree, SLOT( itemMoveDown() ) ); + fM= FALSE; + } + if ( tab == tr("Actions") ) { + connect(mainform->objTBDeleteAction, SIGNAL(activated()), actiontree, SLOT( itemDelete() ) ); + connect(mainform->objTBRenameAction, SIGNAL(activated()), actiontree, SLOT( itemRename() ) ); + connect(mainform->objTBMoveUpAction, SIGNAL(activated()), actiontree, SLOT( itemMoveUp() ) ); + connect(mainform->objTBMoveDownAction, SIGNAL(activated()), actiontree, SLOT( itemMoveDown() ) ); + fA = TRUE; + } else { + disconnect(mainform->objTBDeleteAction, SIGNAL(activated()), actiontree, SLOT( itemDelete() ) ); + disconnect(mainform->objTBRenameAction, SIGNAL(activated()), actiontree, SLOT( itemRename() ) ); + disconnect(mainform->objTBMoveUpAction, SIGNAL(activated()), actiontree, SLOT( itemMoveUp() ) ); + disconnect(mainform->objTBMoveDownAction, SIGNAL(activated()), actiontree, SLOT( itemMoveDown() ) ); + fA = FALSE; + } + if ( tab == tr("Interface") ) { + connect(mainform->objTBDeleteAction, SIGNAL(activated()), interfacetree, SLOT( itemDelete() ) ); + connect(mainform->objTBRenameAction, SIGNAL(activated()), interfacetree, SLOT( itemRename() ) ); + connect(mainform->objTBMoveUpAction, SIGNAL(activated()), interfacetree, SLOT( itemMoveUp() ) ); + connect(mainform->objTBMoveDownAction, SIGNAL(activated()), interfacetree, SLOT( itemMoveDown() ) ); + fI = TRUE; + } else { + disconnect(mainform->objTBDeleteAction, SIGNAL(activated()), interfacetree, SLOT( itemDelete() ) ); + disconnect(mainform->objTBRenameAction, SIGNAL(activated()), interfacetree, SLOT( itemRename() ) ); + disconnect(mainform->objTBMoveUpAction, SIGNAL(activated()), interfacetree, SLOT( itemMoveUp() ) ); + disconnect(mainform->objTBMoveDownAction, SIGNAL(activated()), interfacetree, SLOT( itemMoveDown() ) ); + fI = FALSE; + } + if ( tab == tr("Rights") ) + { + connect(mainform->objTBDeleteAction, SIGNAL(activated()), this, SLOT( bDeleteRole_clicked() ) ); + fR = TRUE; + if ( !tRole->numRows() ) mainform->objTBDeleteAction->setEnabled( FALSE ); + else mainform->objTBDeleteAction->setEnabled( TRUE ); + } else { + disconnect(mainform->objTBDeleteAction, SIGNAL(activated()), this, SLOT( bDeleteRole_clicked() ) ); + fR = FALSE; + } + if ( tab == tr("Languages") ) { + connect(mainform->objTBDeleteAction, SIGNAL(activated()), this, SLOT( bDelete_clicked() ) ); + fL = TRUE; + if ( !tLang->numRows() ) mainform->objTBDeleteAction->setEnabled( FALSE ); + else mainform->objTBDeleteAction->setEnabled( TRUE ); + } else { + disconnect(mainform->objTBDeleteAction, SIGNAL(activated()), this, SLOT( bDelete_clicked() ) ); + fL = FALSE; + } + if ( tab == tr("Image collection") ) { + connect(mainform->objTBDeleteAction, SIGNAL(activated()), this, SLOT( bRemoveImage_clicked() ) ); + fIC = TRUE; + if ( !vImageCollection->count() ) mainform->objTBDeleteAction->setEnabled( FALSE ); + else mainform->objTBDeleteAction->setEnabled( TRUE ); + } else { + disconnect(mainform->objTBDeleteAction, SIGNAL(activated()), this, SLOT( bRemoveImage_clicked() ) ); + fIC = FALSE; + } + if ( tab == tr("Image collection") || tab == tr("Languages") || tab == tr("Rights") ) { + mainform->objTBRenameAction->setVisible( FALSE ); + mainform->objTBMoveUpAction->setVisible( FALSE ); + mainform->objTBMoveDownAction->setVisible( FALSE ); + } else { + mainform->objTBRenameAction->setVisible( TRUE ); + mainform->objTBMoveUpAction->setVisible( TRUE ); + mainform->objTBMoveDownAction->setVisible( TRUE ); + mainform->objTBDeleteAction->setEnabled( TRUE ); + } + mainform->tbMetadata->setShown( fM ); + mainform->tbActions->setShown( fA ); + mainform->tbInterface->setShown( fI ); + mainform->tbRights->setShown( fR ); + mainform->tbLanguages->setShown( fL ); + mainform->tbImageCollection->setShown( fIC ); +} + +/* + * Adds new role + */ +void CfgForm::bAddRole_clicked() +{ + aCfgItem role, obj, roles; + + tRole->insertRows( tRole->numRows(), 1 ); // insert row into table + tRole->setCurrentCell( tRole->numRows()-1, 0 ); // focus on new cell + roles = cfg.find( cfg.find( mdc_root ), md_roles, 0 ); // get role part of configuration + obj = cfg.insert( roles, md_role, tr("New role") ); // insert new role into part + dEditRole *e = new dEditRole( ws, 0, Qt::WDestructiveClose ); + e->setData( configform, obj ); + e->show(); // create role editor, set its data and show this one + bDeleteRole->setEnabled( TRUE ); + bEditRole->setEnabled( TRUE ); + bKillRole->setEnabled( TRUE ); + mainform->objRoleClearAction->setEnabled( TRUE ); + mainform->objRoleEditAction->setEnabled( TRUE ); + mainform->objTBDeleteAction->setEnabled( TRUE ); // enable buttons and actions +} + +/* + * Delete role + */ +void CfgForm::bDeleteRole_clicked() +{ + if ( ! QMessageBox::warning( this, tr("Deleting row"), tr("Delete '%1'?").arg( tRole->text( tRole->currentRow(), 0 ) ), tr("Yes"), tr("No") ) ) { +// request for deleting + aCfgItem roles, obj, role; + int i, n; + + roles = cfg.find( cfg.find( mdc_root ), md_roles, 0 ); // get role part of configuration + n = cfg.count( roles, md_role ); // count roles + for ( i = 0; i < n; i++ ) { // foreach role + obj = cfg.find( roles, md_role, i ); // get this one + if ( cfg.attr( obj, mda_name ) == tRole->text( tRole->currentRow(), 0 ) ) { + cfg.remove( obj ); + break; // if found delete and break the cycle + } + } + tRole->removeRow( tRole->currentRow() ); // remove row from table + if ( !tRole->numRows() ) { // if there're no rows disable buttons and actions + bDeleteRole->setEnabled( FALSE ); + bEditRole->setEnabled( FALSE ); + bKillRole->setEnabled( FALSE ); + mainform->objRoleClearAction->setEnabled( FALSE ); + mainform->objRoleEditAction->setEnabled( FALSE ); + mainform->objTBDeleteAction->setEnabled( FALSE ); + } + } +} + +/* + * Edit curren role + */ +void CfgForm::bEditRole_clicked() +{ + int objid; + aCfgItem obj; + + obj = cfg.find( cfg.find( cfg.find( mdc_root ), md_roles, 0 ), md_role, tRole->currentRow() ); + // get role +/* printf( "name = %s\n", cfg.attr( obj, mda_name ).ascii() ); + objid = cfg.id( obj ); + if ( wl->find( objid ) ) { + wl->get( objid )->setFocus(); + return; + } +*/ + dEditRole *e = new dEditRole( ws, 0, Qt::WDestructiveClose ); + e->setData( configform, obj ); + e->show(); // create role editor, set its data and show this one +} + +/* + * Kill dead roles throughout the configuration + */ +void CfgForm::bKillRole_clicked() +{ + aCfgItem oroot, roles, role; + int i = 0, s, n, ac, killed = 0; + + oroot = cfg.find( mdc_root ); // get configuration root + n = cfg.count( oroot, md_role ); // count roles throughout configuration + while ( i < n ) { // foreach role + ac = 0; // unset counter + role = cfg.find( oroot, md_role, i ); // get this one + for ( s = 0; s < tRole->numRows(); s++ ) // look through role table for correspondence + if ( cfg.attr( role, mda_name ) == tRole->text( s, 0 ) ) ac++; // inc counter + if ( !ac ) { + cfg.remove( role ); + killed++; + n--; // if counter then remove role, inc kill-counter and dec main counter + } else i++; // else inc current role number + } + QMessageBox::warning( this, tr("Clearing dead roles"), tr("%1 dead roles killed.").arg( killed ), tr("OK") ); + // display count of killed roles +} + + +void CfgForm::tRole_doubleClicked( int, int, int, const QPoint & ) +{ + bEditRole_clicked(); // call role edit method +} + diff --git a/src/designer/cfgform.h b/src/designer/cfgform.h new file mode 100644 index 0000000..ad954d4 --- /dev/null +++ b/src/designer/cfgform.h @@ -0,0 +1,71 @@ +#ifndef CFGFORM_H +#define CFGFORM_H + +#include "ui_cfgform.h" + + +class CfgForm : public Q3MainWindow, public Ui::CfgForm +{ + Q_OBJECT + +public: + CfgForm(QWidget* parent = 0, const char* name = 0, Qt::WindowFlags fl = Qt::WType_TopLevel); + ~CfgForm(); + + Q3IntDict idList; + InterfaceTreeView *interfacetree; + aActionTreeView *actiontree; + aCfg cfg; + QWorkspace *ws; + aMetadataTreeView *mdtree; + InterfaceTreeView *toolbartree; + QString rcfile; + aWindowsList *wl; + +public slots: + virtual void fileNew(); + virtual void fileOpen(); + virtual void fileSave(); + virtual void fileSaveAs(); + virtual void filePrint(); + virtual void fileExit(); + virtual void init( QString & rcf, bool flagNew ); + virtual void initImageCollection(); + virtual void bAddImage_clicked(); + virtual void bRemoveImage_clicked(); + virtual void vImageCollection_itemRenamed( Q3IconViewItem * item, const QString & name ); + virtual void initLang(); + virtual void initRoles(); + virtual void save(); + virtual void bAdd_clicked(); + virtual void bDelete_clicked(); + virtual void bEdit_clicked(); + virtual void tLang_doubleClicked( int, int, int, const QPoint & ); + virtual void bKill_clicked(); + virtual void newObj(); + virtual void listCfg_onItem( Q3ListViewItem * ); + virtual void newField(); + virtual void newForm(); + virtual void newTable(); + virtual void tabWidget_selected( const QString & tab ); + virtual void bAddRole_clicked(); + virtual void bDeleteRole_clicked(); + virtual void bEditRole_clicked(); + virtual void bKillRole_clicked(); + virtual void tRole_doubleClicked( int, int, int, const QPoint & ); + +signals: + void wActivate(); + void wDeactivate(); + +protected slots: + virtual void languageChange(); + +private: + void destroy(); + virtual void closeEvent( QCloseEvent * e ); + virtual int closeSubWindows(); + +}; + +#endif // CFGFORM_H diff --git a/src/designer/cfgform.ui b/src/designer/cfgform.ui new file mode 100644 index 0000000..6ec1649 --- /dev/null +++ b/src/designer/cfgform.ui @@ -0,0 +1,775 @@ + + Leader + CfgForm + + + + 0 + 0 + 482 + 412 + + + + + 0 + 0 + + + + CfgForm + + + + + 0 + 0 + 482 + 412 + + + + + + + + 10 + + + + + Metadata + + + + + Actions + + + + + Interface + + + + + Rights + + + + + + 0 + + + 2 + + + true + + + Q3Table::Multi + + + + Role name + + + + + Description + + + + + + + + + + Add + + + + + + + Remove + + + + + + + Edit + + + + + + + Clear dead roles + + + + + + + Qt::Vertical + + + QSizePolicy::Expanding + + + + 21 + 250 + + + + + + + + + + + Languages + + + + + + + + Add + + + + + + + Remove + + + + + + + Edit + + + + + + + Clear dead aliases + + + + + + + Qt::Vertical + + + QSizePolicy::Expanding + + + + 20 + 250 + + + + + + + + + + 0 + + + 3 + + + true + + + Q3Table::Multi + + + + Tag + + + + + Name + + + + + Translation file + + + + + + + + + Image collection + + + + + + 50 + + + 50 + + + false + + + + + + + + + Add + + + + + + + false + + + Remove + + + + + + + + + Qt::Vertical + + + QSizePolicy::Expanding + + + + 20 + 240 + + + + + + + + + + + + + + + + &New + + + New + + + Ctrl+N + + + fileNewAction + + + + + + + + &Open... + + + Open + + + Ctrl+O + + + fileOpenAction + + + + + + + + &Save + + + Save + + + Ctrl+S + + + fileSaveAction + + + + + Save &As... + + + Save As + + + + + + fileSaveAsAction + + + + + + + + &Print... + + + Print + + + Ctrl+P + + + filePrintAction + + + + + E&xit + + + Exit + + + + + + fileExitAction + + + + + + + + + Action + + + objEdit + + + + + + + + Action + + + objNew + + + + + editdelete.png + + + Action + + + objDelete + + + + objGroup + + + + + rcIcon + + + Q3IconView + Q3Frame +
q3iconview.h
+
+ + Q3MainWindow + QWidget +
q3mainwindow.h
+ 1 +
+ + Q3Table + Q3Frame +
q3table.h
+
+
+ + tabWidget + + + acfg.h + qworkspace.h + q3socket.h + q3serversocket.h + acfgrc.h + mdtree.h + actiontree.h + interfacetree.h + pixmappreview.h + awindowslist.h + + + + + fileExitAction + activated() + CfgForm + fileExit() + + + -1 + -1 + + + 20 + 20 + + + + + filePrintAction + activated() + CfgForm + filePrint() + + + -1 + -1 + + + 20 + 20 + + + + + fileSaveAsAction + activated() + CfgForm + fileSaveAs() + + + -1 + -1 + + + 20 + 20 + + + + + fileSaveAction + activated() + CfgForm + fileSave() + + + -1 + -1 + + + 20 + 20 + + + + + fileOpenAction + activated() + CfgForm + fileOpen() + + + -1 + -1 + + + 20 + 20 + + + + + fileNewAction + activated() + CfgForm + fileNew() + + + -1 + -1 + + + 20 + 20 + + + + + bAdd + clicked() + CfgForm + bAdd_clicked() + + + 20 + 20 + + + 20 + 20 + + + + + bDelete + clicked() + CfgForm + bDelete_clicked() + + + 20 + 20 + + + 20 + 20 + + + + + bEdit + clicked() + CfgForm + bEdit_clicked() + + + 20 + 20 + + + 20 + 20 + + + + + tLang + doubleClicked(int,int,int,QPoint) + CfgForm + tLang_doubleClicked(int,int,int,QPoint) + + + 20 + 20 + + + 20 + 20 + + + + + bKill + clicked() + CfgForm + bKill_clicked() + + + 20 + 20 + + + 20 + 20 + + + + + bAddImage + clicked() + CfgForm + bAddImage_clicked() + + + 20 + 20 + + + 20 + 20 + + + + + bRemoveImage + clicked() + CfgForm + bRemoveImage_clicked() + + + 20 + 20 + + + 20 + 20 + + + + + vImageCollection + itemRenamed(Q3IconViewItem*,QString) + CfgForm + vImageCollection_itemRenamed(Q3IconViewItem*,QString) + + + 20 + 20 + + + 20 + 20 + + + + + tabWidget + selected(QString) + CfgForm + tabWidget_selected(QString) + + + 20 + 20 + + + 20 + 20 + + + + + bAddRole + clicked() + CfgForm + bAddRole_clicked() + + + 20 + 20 + + + 20 + 20 + + + + + bEditRole + clicked() + CfgForm + bEditRole_clicked() + + + 20 + 20 + + + 20 + 20 + + + + + tRole + doubleClicked(int,int,int,QPoint) + CfgForm + tRole_doubleClicked(int,int,int,QPoint) + + + 20 + 20 + + + 20 + 20 + + + + + bDeleteRole + clicked() + CfgForm + bDeleteRole_clicked() + + + 20 + 20 + + + 20 + 20 + + + + + bKillRole + clicked() + CfgForm + bKillRole_clicked() + + + 20 + 20 + + + 20 + 20 + + + + +
diff --git a/src/designer/deditaction.cpp b/src/designer/deditaction.cpp new file mode 100644 index 0000000..337b344 --- /dev/null +++ b/src/designer/deditaction.cpp @@ -0,0 +1,366 @@ +#include "deditaction.h" + +#include +#include +#include + +#include +//Added by qt3to4: +#include +#include "acfg.h" +#include +#include +#include + +/* + * Constructs a dEditAction as a child of 'parent', with the + * name 'name' and widget flags set to 'f'. + * + */ +dEditAction::dEditAction(QWidget* parent, const char* name, Qt::WindowFlags fl) + : Q3MainWindow(parent, name, fl) +{ + setupUi(this); + + (void)statusBar(); + init(); +} + +/* + * Destroys the object and frees any allocated resources + */ +dEditAction::~dEditAction() +{ + destroy(); + // no need to delete child widgets, Qt does it all for us +} + +/* + * Sets the strings of the subwidgets using the current + * language. + */ +void dEditAction::languageChange() +{ + retranslateUi(this); +} + +void dEditAction::setData( ActionListViewItem * o ) +{ + item = o; + md = o->md; + obj = o->obj; + aCfgItem active, passive; + QString st; + QPixmap pix, pix1; + static const char *empty[] = { + "1 1 1 1", + ". c None", + "."}; + dp = new QPixmap( empty ); + + aAliasEditor *a = new aAliasEditor( md, obj, tAliases ); + al = a; + al->setData(); // alias table init + + pActive->setPixmap( *dp ); // set empty pixmaps + pPassive->setPixmap( *dp ); + eName->setText( md->attr( obj, mda_name ) ); + setCaption( tr("Action:") + md->attr( obj, mda_name ) ); + eDescription->setText( md->sText( obj, md_description ) ); + eParams->setText( md->sText( obj, md_argument ) ); // set atributes + st = md->attr ( obj, mda_type); + if ( st == "0" ) cbType->setCurrentItem( 0 ); + else if ( st == "1" ) cbType->setCurrentItem( 1 ); + eModule->setText( md->sText( obj, md_sourcecode ) ); + active = md->findChild( obj, md_active_picture, 0 ); + if ( !active.isNull() ) { // set active mode picture if exists + bRemoveActive->setEnabled( TRUE ); + pix.loadFromData( md->binary( active ) ); + pActive->setPixmap( pix ); + setIcon( pix ); + } + passive = md->findChild( obj, md_passive_picture, 0 ); + if ( !passive.isNull() ) { // set passive mode picture if exists + bRemovePassive->setEnabled( TRUE ); + pix1.loadFromData( md->binary( passive ) ); + pPassive->setPixmap( pix1 ); + } + + QStringList tlist = md->ObjectTypes(); + otypes.clear(); + cbObject->clear(); + for ( QStringList::Iterator it = tlist.begin(); it != tlist.end(); ++it ) + { + otypes.append( (*it).section( "\t", 0, 0 ).section(" ", 1, 1 ) ); + cbObject->insertItem( (*it).section("\t", 1, 1 )); + } + QString oid = md->sText( obj, md_objectid ); + uint n = otypes.count(); + for ( uint i = 0; i < n; i++ ) + if ( otypes[i] == oid ) + { + cbObject->setCurrentItem( i ); + break; + } + cbObjectChange(); + n = formslist.count(); + oid = md->sText( obj, md_formid ); + for ( uint i = 0; i < n; i++ ){ + if ( formslist[i] == oid ) + { + cbForm->setCurrentItem( i ); + break; + } + + } + int type = md->sText( obj, md_actiontype ).toInt(); + switch ( type ) + { + case 0 : + cbAction->setCurrentItem(md_action_new); + break; + case 1 : + cbAction->setCurrentItem(md_action_edit); + break; + case 2 : + cbAction->setCurrentItem(md_action_view); + break; + case 3 : + cbAction->setCurrentItem(md_action_execute); + break; + } + + + cbTypeChange(); +} + +void dEditAction::updateMD() +{ + al->updateMD( ); + char sid[50]=""; + int id = 0; + + item->setText( 0, eName->text() ); + md->setAttr( obj, mda_name, eName->text() ); + md->setSText( obj, md_description, eDescription->text() ); + md->setSText( obj, md_argument, eParams->text() ); + if ( cbType->currentItem() == 0 ) + { + md->setAttr( obj, mda_type, "0" ); + id=cbAction->currentItem(); + switch ( id ) + { + case 0 : + sprintf(sid, "%i", md_action_new); + md->setSText( obj, md_actiontype, sid ); + break; + case 1 : + sprintf(sid, "%i", md_action_edit ); + md->setSText( obj, md_actiontype, sid ); + break; + case 2 : + sprintf(sid, "%i", md_action_view); + md->setSText( obj, md_actiontype, sid ); + break; + case 3 : + sprintf(sid, "%i", md_action_execute); + md->setSText( obj, md_actiontype, sid ); + break; + } + id=cbObject->currentItem(); + md->setSText( obj, md_objectid, otypes[id] ); + id=cbForm->currentItem(); + md->setSText( obj, md_formid, formslist[id] ); + } + + if ( cbType->currentItem() == 1 ) + { + md->setAttr( obj, mda_type, "1" ); + md->setSText( obj, md_sourcecode, eModule->text() ); + } +} + + +void dEditAction::init() +{ + + delete statusBar(); + eModule->setInterpreter(new QSInterpreter()); +// tabWidget2->page(1)->hide() ; +// tabWidget2->setTabEnabled ( tabWidget2->page(1), FALSE ); +} + + +void dEditAction::destroy() +{ + updateMD(); + ( (MainForm*)this->topLevelWidget() )->wl->remove( this ); + ( (MainForm*)this->topLevelWidget() )->removeTab(name()); +} + + +void dEditAction::cbTypeChange () +{ +// if ( cbType->currentItem() == 0 ) +// selectStandart(); + // if ( cbType->currentItem() == 1 ) +// selectUser(); +// if ( cbType->currentItem() == 2 ) wStack->raiseWidget( 2 ); + wStack->raiseWidget( cbType->currentItem() ); +} + +void dEditAction::selectStandart() +{ + lAction->show(); + lObject->show(); + lParams->show(); + cbAction->show(); + cbObject->show(); + cbForm->show(); + eParams->show(); +// tabWidget2->page(1)->hide() ; + eModule->hide() ; +// tabWidget2->setTabEnabled ( tabWidget2->page(1), FALSE ); +} + + + +void dEditAction::selectUser() +{ + + lAction->hide(); + lObject->hide(); + lParams->hide(); + cbAction->hide(); + cbObject->hide(); + cbForm->hide(); + eParams->hide(); + eModule->show() ; +// tabWidget2->setTabEnabled ( tabWidget2->page(1), TRUE ); +} + + +void dEditAction::bSetActive_clicked() +{ + QString st; + QPixmap pix; +// QFileDialog *fd = new QFileDialog( "", "Images (*.png *.xpm *.jpg *.jpeg *.bmp)", 0, 0, TRUE ); + QByteArray ba; + QString name; + QFile f; +// PixmapPreview *p = new PixmapPreview; + aCfgItem active; + +// fd->setContentsPreview( p, p ); +// fd->setPreviewMode( QFileDialog::Contents ); +// fd->setContentsPreviewEnabled( TRUE ); // prepair file dialog +// fd->setCaption( tr("Open image dialog" ) ); +// fd->setMode( QFileDialog::ExistingFiles ); + name= Q3FileDialog::getOpenFileName("", "Images (*.png *.xpm *.jpg *.jpeg *.bmp)", this, + tr("Open image dialog"), + tr("Choose an image") ); +// if ( fd->exec() == QDialog::Accepted ) { // if accepted +// name = fd->selectedFile(); // get filename + if ( !name.isEmpty() ) { // if not empty + f.setName( name ); + if ( f.open( QIODevice::ReadOnly ) ){ // open file + ba = f.readAll(); // read data + f.close(); // close file + pix.loadFromData( ba ); // load data into pixmap + active = item->md->findChild( item->obj, md_active_picture, 0 ); + if ( active.isNull() ) active = item->md->insert( item->obj, md_active_picture, QString::null, -1 ); + item->md->setBinary( active, ba ); // save data into cfg + item->setPixmap( 0, pix ); + setIcon( pix ); // put on caption + } + } +// delete fd; // remove filedialog + pActive->setPixmap( pix ); // put on form + bRemoveActive->setEnabled( TRUE ); // enable remove button +// } +} + + +void dEditAction::bSetPassive_clicked() +{ + QString st; + QPixmap pix; + Q3FileDialog *fd = new Q3FileDialog( "", "Images (*.png *.xpm *.jpg *.jpeg *.bmp)", 0, 0, TRUE ); + QByteArray ba; + QString name; + QFile f; + PixmapPreview *p = new PixmapPreview; + aCfgItem passive; + + fd->setContentsPreview( p, p ); + fd->setPreviewMode( Q3FileDialog::Contents ); + fd->setContentsPreviewEnabled( TRUE ); + fd->setCaption( tr("Open image dialog" ) ); + fd->setMode( Q3FileDialog::ExistingFiles ); + if ( fd->exec() == QDialog::Accepted ) { + name = fd->selectedFile(); + if ( !name.isEmpty() ) { + f.setName( name ); + if ( f.open( QIODevice::ReadOnly ) ){ + ba = f.readAll(); + f.close(); + pix.loadFromData( ba ); + passive = item->md->findChild( item->obj, md_passive_picture, 0 ); + if ( passive.isNull() ) passive = item->md->insert( item->obj, md_passive_picture, QString::null, -1 ); + item->md->setBinary( passive, ba ); + } + } + delete fd; + pPassive->setPixmap( pix ); + bRemovePassive->setEnabled( TRUE ); + } +} + + +void dEditAction::bRemoveActive_clicked() +{ + item->md->remove( item->md->findChild( item->obj, md_active_picture, 0 ) ); + bRemoveActive->setEnabled( FALSE ); + pActive->clear(); + item->setPixmap( 0, 0 ); + setIcon( *dp ); + pActive->setPixmap( *dp ); +} + + +void dEditAction::bRemovePassive_clicked() +{ + item->md->remove( item->md->findChild( item->obj, md_passive_picture, 0 ) ); + bRemovePassive->setEnabled( FALSE ); + pPassive->clear(); + pPassive->setPixmap( *dp ); +} + + +void dEditAction::cbObjectChange() +{ + aCfgItem cobj, fobj; + long id = otypes[cbObject->currentItem()].toLong(); + uint n; + cobj=md->find(id); + + cbForm->clear(); + formslist.clear(); + + cbForm->insertItem( QObject::tr("default") ); + formslist.append( "0" ); + if ( md->objClass( cobj ) == md_catalogue ) + { + cbForm->insertItem( QObject::tr("embedded editor") ); + formslist.append( "1" ); + } + n = md->count( cobj, md_form ); + for ( uint i = 0; i < n; i++ ) + { + fobj = md->find( cobj, md_form, i); + if ( fobj.isNull() ) + continue; + cbForm->insertItem( md->attr(fobj, mda_name) ); + formslist.append(md->attr(fobj, mda_id)); + } +} diff --git a/src/designer/deditaction.h b/src/designer/deditaction.h new file mode 100644 index 0000000..d110475 --- /dev/null +++ b/src/designer/deditaction.h @@ -0,0 +1,48 @@ +#ifndef DEDITACTION_H +#define DEDITACTION_H + +#include "ui_deditaction.h" + + +class dEditAction : public Q3MainWindow, public Ui::dEditAction +{ + Q_OBJECT + +public: + dEditAction(QWidget* parent = 0, const char* name = 0, Qt::WindowFlags fl = Qt::WType_TopLevel); + ~dEditAction(); + + ActionListViewItem * item; + aAliasEditor *al; + QStringList otypes; + QStringList formslist; + aCfg * md; + aCfgItem obj; + QPixmap *dp; + +public slots: + virtual void setData( ActionListViewItem * o ); + virtual void updateMD(); + virtual void bSetActive_clicked(); + virtual void bSetPassive_clicked(); + virtual void bRemoveActive_clicked(); + virtual void bRemovePassive_clicked(); + +protected: + virtual void selectStandart(); + virtual void selectUser(); + +protected slots: + virtual void languageChange(); + + virtual void init(); + virtual void destroy(); + + +private slots: + virtual void cbTypeChange(); + virtual void cbObjectChange(); + +}; + +#endif // DEDITACTION_H diff --git a/src/designer/deditaction.ui b/src/designer/deditaction.ui new file mode 100644 index 0000000..9465248 --- /dev/null +++ b/src/designer/deditaction.ui @@ -0,0 +1,663 @@ + + dEditAction + + + + 0 + 0 + 500 + 355 + + + + Action + + + + + 0 + 0 + 500 + 355 + + + + + + + true + + + + + + QTabWidget::Rounded + + + + Common + + + + + + Description: + + + false + + + + + + + + + Name + + + false + + + + + + + Type + + + false + + + + + + + + 0 + 0 + + + + + standart command + + + + + user script + + + + + external script + + + + + + + + true + + + + 0 + 22 + + + + + + + + + + + + + + + Qt::Vertical + + + QSizePolicy::Expanding + + + + 91 + 20 + + + + + + + + Enabled icon + + + + + + + 20 + 24 + + + + ... + + + + + + + true + + + false + + + + + + + false + + + + 20 + 32767 + + + + X + + + + + + + + + + Disabled icon + + + + + + true + + + false + + + + + + + + 0 + 0 + + + + + 20 + 32767 + + + + ... + + + + + + + false + + + + 0 + 0 + + + + + 20 + 32767 + + + + X + + + + + + + + + + + + + Execute + + + + + + + + 0 + 0 + 100 + 30 + + + + + + + + + Qt::Vertical + + + QSizePolicy::Expanding + + + + 21 + 130 + + + + + + + + + + + 0 + 0 + + + + + + + + + + + Action + + + false + + + + + + + Object + + + false + + + + + + + Form + + + false + + + + + + + true + + + + 0 + 22 + + + + + + + + + 0 + 0 + + + + + new + + + + + edit + + + + + view + + + + + execute + + + + + + + + Params + + + false + + + + + + + + + + + + + 0 + 0 + 100 + 30 + + + + + + + true + + + + + + + + + 0 + 0 + 100 + 30 + + + + + + + + + File name + + + false + + + + + + + + + + + 20 + 32767 + + + + ... + + + + + + + + + Qt::Vertical + + + QSizePolicy::Expanding + + + + 20 + 170 + + + + + + + + + + + + + Aliases + + + + + + 0 + + + 2 + + + + Lang + + + + + Name + + + + + + + + + + + + + Action + + + Action + + + Action + + + + + Action_2 + + + Action_2 + + + Action_2 + + + + + rcIcon + + + Q3GroupBox + QGroupBox +
Qt3Support/Q3GroupBox
+ 1 +
+ + Q3MainWindow + QWidget +
q3mainwindow.h
+ 1 +
+ + Q3WidgetStack + Q3WidgetStack +
q3widgetstack.h
+ 1 +
+ + Q3Table + Q3Frame +
q3table.h
+
+ + Q3TextEdit + Q3Frame +
q3textedit.h
+
+ + QSEditor + QWidget +
qseditor.h
+
+
+ + actiontree.h + aliaseditor.h + pixmappreview.h + mainform.h + qseditor.h + + + + + cbType + activated(int) + dEditAction + cbTypeChange() + + + 20 + 20 + + + 20 + 20 + + + + + bSetActive + clicked() + dEditAction + bSetActive_clicked() + + + 20 + 20 + + + 20 + 20 + + + + + bRemoveActive + clicked() + dEditAction + bRemoveActive_clicked() + + + 20 + 20 + + + 20 + 20 + + + + + bSetPassive + clicked() + dEditAction + bSetPassive_clicked() + + + 20 + 20 + + + 20 + 20 + + + + + bRemovePassive + clicked() + dEditAction + bRemovePassive_clicked() + + + 20 + 20 + + + 20 + 20 + + + + + cbObject + activated(int) + dEditAction + cbObjectChange() + + + 20 + 20 + + + 20 + 20 + + + + +
diff --git a/src/designer/deditareg.cpp b/src/designer/deditareg.cpp new file mode 100644 index 0000000..b92b82e --- /dev/null +++ b/src/designer/deditareg.cpp @@ -0,0 +1,76 @@ +#include "deditareg.h" + +#include +#include +#include + +#include +#include "acfg.h" + +/* + * Constructs a dEditAReg as a child of 'parent', with the + * name 'name' and widget flags set to 'f'. + * + */ +dEditAReg::dEditAReg(QWidget* parent, const char* name, Qt::WindowFlags fl) + : Q3MainWindow(parent, name, fl) +{ + setupUi(this); + + (void)statusBar(); + init(); +} + +/* + * Destroys the object and frees any allocated resources + */ +dEditAReg::~dEditAReg() +{ + destroy(); + // no need to delete child widgets, Qt does it all for us +} + +/* + * Sets the strings of the subwidgets using the current + * language. + */ +void dEditAReg::languageChange() +{ + retranslateUi(this); +} + +void dEditAReg::init() +{ + delete statusBar(); +} + +void dEditAReg::destroy() +{ + updateMD(); + ( (MainForm*)this->topLevelWidget() )->wl->remove( this ); + ( (MainForm*)this->topLevelWidget() )->removeTab(name()); +} + +void dEditAReg::setData( aListViewItem *o ) +{ + item = o; + aCfg *md = o->md; + aCfgItem obj = o->obj; + aAliasEditor *a = new aAliasEditor( md, obj, tAliases ); + al = a; + al->setData(); + setCaption( tr("Accumulation register:") + md->attr( obj, mda_name ) ); + eName->setText( md->attr( obj, mda_name ) ); + eDescription->setText( md->sText( obj, md_description ) ); +} + +void dEditAReg::updateMD() +{ + aCfg *md = item->md; + aCfgItem obj = item->obj; + + al->updateMD(); + item->setText( 0, eName->text().stripWhiteSpace() ); + md->setAttr( obj, mda_name, eName->text().stripWhiteSpace()); + md->setSText( obj, md_description, eDescription->text() ); +} diff --git a/src/designer/deditareg.h b/src/designer/deditareg.h new file mode 100644 index 0000000..02fc4db --- /dev/null +++ b/src/designer/deditareg.h @@ -0,0 +1,31 @@ +#ifndef DEDITAREG_H +#define DEDITAREG_H + +#include "ui_deditareg.h" + + +class dEditAReg : public Q3MainWindow, public Ui::dEditAReg +{ + Q_OBJECT + +public: + dEditAReg(QWidget* parent = 0, const char* name = 0, Qt::WindowFlags fl = Qt::WType_TopLevel); + ~dEditAReg(); + + aListViewItem *item; + aAliasEditor *al; + +public slots: + virtual void setData( aListViewItem * o ); + virtual void updateMD(); + +protected slots: + virtual void languageChange(); + +private: + void init(); + void destroy(); + +}; + +#endif // DEDITAREG_H diff --git a/src/designer/deditareg.ui b/src/designer/deditareg.ui new file mode 100644 index 0000000..42e8535 --- /dev/null +++ b/src/designer/deditareg.ui @@ -0,0 +1,123 @@ + + dEditAReg + + + + 0 + 0 + 445 + 317 + + + + Accumulating register + + + + + 0 + 0 + 445 + 317 + + + + + + + + Common + + + + + + + + Name: + + + false + + + + + + + + + + + + Description: + + + false + + + + + + + + + + + Aliases + + + + + + 0 + + + 2 + + + + Lang + + + + + Name + + + + + + + + + + + + + rcIcon + + + Q3MainWindow + QWidget +
q3mainwindow.h
+ 1 +
+ + Q3Table + Q3Frame +
q3table.h
+
+ + Q3TextEdit + Q3Frame +
q3textedit.h
+
+
+ + mdtree.h + aliaseditor.h + mainform.h + + + +
diff --git a/src/designer/deditcat.cpp b/src/designer/deditcat.cpp new file mode 100644 index 0000000..3c99a5e --- /dev/null +++ b/src/designer/deditcat.cpp @@ -0,0 +1,174 @@ +#include "deditcat.h" + +#include +#include +#include + +#include +#include +#include +#include "acfg.h" + +/* + * Constructs a dEditCat as a child of 'parent', with the + * name 'name' and widget flags set to 'f'. + * + */ +dEditCat::dEditCat(QWidget* parent, const char* name, Qt::WindowFlags fl) + : Q3MainWindow(parent, name, fl) +{ + setupUi(this); + + (void)statusBar(); + init(); +} + +/* + * Destroys the object and frees any allocated resources + */ +dEditCat::~dEditCat() +{ + destroy(); + // no need to delete child widgets, Qt does it all for us +} + +/* + * Sets the strings of the subwidgets using the current + * language. + */ +void dEditCat::languageChange() +{ + retranslateUi(this); +} + +void dEditCat::setData( aListViewItem *o ) +{ + long int i; + int fid, fcount, fieldid, stdf; + item = o; + aCfg *md = o->md; + aCfgItem obj = o->obj, sv, g, e, field; + + aAliasEditor *a = new aAliasEditor( md, obj, tAliases ); + al = a; + al->setData(); + aRoleEditor *r = new aRoleEditor( md, obj, tRoles, md_catalogue ); + re = r; + re->setData(); + setCaption( tr("Catalogue:") + md->attr( obj, mda_name ) ); + eName->setText( md->attr( obj, mda_name ) ); + eDescription->setText( md->sText( obj, md_description ) ); + g = md->find( obj, md_group ); // Find group context + e = md->find( obj, md_element ); // Find Element context + sv = md->find( g, md_string_view ); // Group string view +//==================================== + eStrViewFG->setText( md->sText( sv, md_svfunction ) ); + eSvG->insertItem( "[ standart function ]" ); + eSvG->insertItem( "[ user function ]" ); + fid = md->sText( sv, md_fieldid ).toInt(); + stdf = md->attr( sv, mda_stdf ).toInt(); + eSvG->setCurrentItem( 0 ); + for ( i = 0; i < md->count( g, md_field ); i++ ) { + field = md->find( g, md_field, i ); + eSvG->insertItem( QString("%1").arg( md->attr( field, mda_name ) ) ); + fieldid = md->id( field ); + fieldsg.insert( i, new int( fieldid ) ); + if ( fid == fieldid && !stdf ) { + eSvG->setCurrentItem( i + 2 ); + eStrViewFG->setEnabled( FALSE ); + } + } + if ( !fid && !stdf ) { + eStrViewFG->setEnabled( TRUE ); + eSvG->setCurrentItem( 1 ); + } + +//==================================== + sv = md->find( e, md_string_view ); + eStrViewF->setText( md->sText( sv, md_svfunction ) ); + eSv->insertItem( "[ standart function ]" ); + eSv->insertItem( "[ user function ]" ); + fid = md->sText( sv, md_fieldid ).toInt(); + stdf = md->attr( sv, mda_stdf ).toInt(); + eSv->setCurrentItem( 0 ); + for ( i = 0; i < md->count( e, md_field ); i++ ) { + field = md->find( e, md_field, i ); + eSv->insertItem( QString("%1").arg( md->attr( field, mda_name ) ) ); + fieldid = md->id( field ); + fields.insert( i, new int( fieldid ) ); + if ( fid == fieldid && !stdf ) { + eSv->setCurrentItem( i + 2 ); + eStrViewF->setEnabled( FALSE ); + } + } + if ( !fid && !stdf ) { + eStrViewF->setEnabled( TRUE ); + eSv->setCurrentItem( 1 ); + } +} + + +void dEditCat::init() +{ + delete statusBar(); + eStrViewF->setInterpreter( new QSInterpreter() ); + eStrViewF->setEnabled( FALSE ); +} + + +void dEditCat::updateMD() +{ + aCfg *md = item->md; + aCfgItem obj = item->obj, sv, g, e; + + al->updateMD(); + re->updateMD(); + item->setText( 0, eName->text().stripWhiteSpace() ); + md->setAttr( obj, mda_name, eName->text().stripWhiteSpace() ); + md->setSText( obj, md_description, eDescription->text() ); + g = md->find( obj, md_group ); // Find group context + e= md->find( obj, md_element ); // Find Element context + //======== Element view save + sv = md->find( e, md_string_view ); + if ( sv.isNull() ) sv = md->insert( e, md_string_view ); + md->setSText( sv, md_svfunction, eStrViewF->text() ); + if ( eSv->currentItem() == 0 ) md->setAttr( sv, mda_stdf, "1" ); + else { + md->setAttr( sv, mda_stdf, "0" ); + if ( eSv->currentItem() == 1 ) md->setSText( sv, md_fieldid, "0" ); + else md->setSText( sv, md_fieldid, QString("%1").arg( *(fields.find( eSv->currentItem() - 2 ) ) ) ); + } + //======== Group view save + sv = md->find( g, md_string_view ); + if ( sv.isNull() ) sv = md->insert( g, md_string_view ); + md->setSText( sv, md_svfunction, eStrViewFG->text() ); + if ( eSvG->currentItem() == 0 ) md->setAttr( sv, mda_stdf, "1" ); + else { + md->setAttr( sv, mda_stdf, "0" ); + if ( eSvG->currentItem() == 1 ) md->setSText( sv, md_fieldid, "0" ); + else md->setSText( sv, md_fieldid, QString("%1").arg( *(fieldsg.find( eSvG->currentItem() - 2 ) ) ) ); + } + +} + +void dEditCat::destroy() +{ + updateMD(); + ( (MainForm*)this->topLevelWidget() )->wl->remove( this ); + ( (MainForm*)this->topLevelWidget() )->removeTab(name()); +} + + + + +void dEditCat::eSv_activated( int index ) +{ + if ( index == 1 ) eStrViewF->setEnabled( TRUE ); + else eStrViewF->setEnabled( FALSE ); +} + +void dEditCat::eSvG_activated( int index ) +{ + if ( index == 1 ) eStrViewFG->setEnabled( TRUE ); + else eStrViewFG->setEnabled( FALSE ); +} diff --git a/src/designer/deditcat.h b/src/designer/deditcat.h new file mode 100644 index 0000000..6943d7e --- /dev/null +++ b/src/designer/deditcat.h @@ -0,0 +1,38 @@ +#ifndef DEDITCAT_H +#define DEDITCAT_H + +#include "ui_deditcat.h" + + +class dEditCat : public Q3MainWindow, public Ui::dEditCat +{ + Q_OBJECT + +public: + dEditCat(QWidget* parent = 0, const char* name = 0, Qt::WindowFlags fl = Qt::WType_TopLevel); + ~dEditCat(); + + aRoleEditor *re; + Q3IntDict fields, fieldsg; + aAliasEditor *al; + aListViewItem *item; + +public slots: + virtual void setData( aListViewItem * o ); + virtual void updateMD(); + virtual void eSv_activated( int index ); + virtual void eSvG_activated( int index ); + +protected: + int newVariable; + +protected slots: + virtual void languageChange(); + +private: + void init(); + void destroy(); + +}; + +#endif // DEDITCAT_H diff --git a/src/designer/deditcat.ui b/src/designer/deditcat.ui new file mode 100644 index 0000000..f2cf761 --- /dev/null +++ b/src/designer/deditcat.ui @@ -0,0 +1,266 @@ + + dEditCat + + + + 0 + 0 + 465 + 297 + + + + Catalogue + + + + + 0 + 0 + 465 + 297 + + + + + + + + + + + Common + + + + + + + + Name: + + + false + + + + + + + + + + + + Description: + + + false + + + + + + + + + + + Aliases + + + + + + 0 + + + 2 + + + + Lang + + + + + Name + + + + + + + + + Element string view + + + + + + true + + + + + + + + + + + Group string view + + + + + + true + + + + + + + + + + + Access + + + + + + 0 + + + 2 + + + false + + + Q3Table::Multi + + + + Read + + + + + Write + + + + + + + + + + + + + rcIcon + + + Q3MainWindow + QWidget +
q3mainwindow.h
+ 1 +
+ + Q3Table + Q3Frame +
q3table.h
+
+ + Q3TextEdit + Q3Frame +
q3textedit.h
+
+ + QSEditor + QWidget +
qseditor.h
+
+
+ + mdtree.h + aliaseditor.h + mainform.h + roleeditor.h + qseditor.h + qseditor.h + + + + + eSv + activated(int) + dEditCat + eSv_activated(int) + + + 20 + 20 + + + 20 + 20 + + + + + eSv + highlighted(int) + dEditCat + eSv_activated(int) + + + 20 + 20 + + + 20 + 20 + + + + + eSvG + activated(int) + dEditCat + eSvG_activated(int) + + + 20 + 20 + + + 20 + 20 + + + + + eSvG + highlighted(int) + dEditCat + eSvG_activated(int) + + + 20 + 20 + + + 20 + 20 + + + + +
diff --git a/src/designer/deditcfg.cpp b/src/designer/deditcfg.cpp new file mode 100644 index 0000000..223bc1d --- /dev/null +++ b/src/designer/deditcfg.cpp @@ -0,0 +1,171 @@ +#include "deditcfg.h" + +#include +#include +#include + +#include "acfg.h" +#include "qlayout.h" +#include "qsproject.h" +#include "qsscript.h" +//#include "qseditor.h" +#include +#include + +#ifndef QSA_NO_IDE +#include "qsworkbench.h" +#endif + +/* + * Constructs a dEditCfg as a child of 'parent', with the + * name 'name' and widget flags set to 'f'. + * + */ +dEditCfg::dEditCfg(QWidget* parent, const char* name, Qt::WindowFlags fl) + : Q3MainWindow(parent, name, fl) +{ + setupUi(this); + + (void)statusBar(); + init(); +} + +/* + * Destroys the object and frees any allocated resources + */ +dEditCfg::~dEditCfg() +{ + destroy(); + // no need to delete child widgets, Qt does it all for us +} + +/* + * Sets the strings of the subwidgets using the current + * language. + */ +void dEditCfg::languageChange() +{ + retranslateUi(this); +} + +void dEditCfg::init() +{ + delete statusBar(); + + eDBType->clear(); + eDBType->insertItem(trUtf8("Unknown"), 0); + eDBType->insertItem(trUtf8("MySQL"), 1); + eDBType->insertItem(trUtf8("Postgres"), 2); +// QGridLayout *l=new QGridLayout(tabWidget->page(2)); +// eModule=NULL; +// eModule = new QSEditor(tabWidget->page(2), "global module"); +// l->addWidget(eModule, 5, 5, 0); + eModule->setInterpreter(new QSInterpreter()); +} + + + +void dEditCfg::destroy() +{ + updateMD(); + ( (MainForm*)this->topLevelWidget() )->wl->remove( this ); + ( (MainForm*)this->topLevelWidget() )->removeTab(name()); + // item->editor = 0; +} + + +void dEditCfg::setData( aListViewItem *o ) +{ +// int n; +// char to[100]=""; +// cfg_objptr code, remark, context=NULL; +// char *id0; + item = o; + aCfg *md = item->md; + aCfgItem obj = item->obj; + + QString v; +// int rc=0; + + setCaption( tr("Business scheme parameters: ") + md->info( md_info_name ) ); + v = md->rc.value("dbtype"); + eDBType->setCurrentItem(0); + if ( v == "postgres" ) eDBType->setCurrentItem(2); + if ( v == "mysql" ) eDBType->setCurrentItem(1); + + eCfgName->setText( md->rc.value("configfile") ); + eWorkDir->setText( md->rc.value("workdir") ); + eDBHost->setText( md->rc.value("dbhost") ); + eDBName->setText( md->rc.value("dbname") ); + eDBHeader->setText( md->rc.value("dbtitle") ); + eDBPass->setText( md->rc.value("dbpass") ); + eDBUserName->setText( md->rc.value("dbuser") ); + eName->setText( md->info( md_info_name ) ); + eAuthor->setText( md->info( md_info_author ) ); + eDate->setText( md->info( md_info_date ) ); + eDescription->setText( md->info( md_info_remark ) ); + globals = md->find( obj, md_globals, 0 ); + eModule->setText( md->sText( globals, md_sourcecode ) ); + +/* + n=cfgobj_count(context, aot_remark); + if (n) { + id0=cfgobj_idn(context, aot_remark, 1, &remark); + if (remark) eRemark->setText(trUtf8(cfgobj_text(remark))); + } + n=cfgobj_count(context, aot_sourcecode); + if (n) { + id0=cfgobj_idn(context, aot_sourcecode, 1, &code); + if (code) eModule->setText(trUtf8(cfgobj_text(code))); + } +*/ +} + + + +void dEditCfg::updateMD() +{ +// int n; +// char to[100]=""; +// cfg_objptr code, remark, context=NULL; +// char *id; +// cfg_objptr o; + aCfg *md = item->md; + aCfgItem obj = item->obj; + + md->setInfo( md_info_name, eName->text() ); + md->setInfo( md_info_remark, eDescription->text() ); + md->setInfo( md_info_author, eAuthor->text() ); + md->setInfo( md_info_date, eDate->text() ); + md->rc.setValue( "configfile", eCfgName->text().stripWhiteSpace() ); + md->rc.setValue( "workdir", eWorkDir->text().stripWhiteSpace() ); + md->rc.setValue( "dbhost", eDBHost->text().stripWhiteSpace() ); + md->rc.setValue( "dbtitle", eDBHeader->text().stripWhiteSpace() ); + md->rc.setValue( "dbname", eDBName->text().stripWhiteSpace() ); + md->rc.setValue( "dbpass", eDBPass->text().stripWhiteSpace() ); + md->rc.setValue( "dbuser", eDBUserName->text().stripWhiteSpace() ); + if (eDBType->currentItem()==1) md->rc.setValue( "dbtype", "mysql" ); + if (eDBType->currentItem()==2) md->rc.setValue( "dbtype", "postgres" ); + globals = md->find( obj, md_globals, 0 ); + md->setSText( globals, md_sourcecode, eModule->text() ); + +/* + if (cancelupdate) return; + item->setText(0, eName->text()); +// item->setText(1, eID->text()); +// item->setText(2, eType->text()); +// o=cfgobj_find(eID->text()); +// if (o) { +// printf("founded id=%s!\n", cfgobj_attr(o,"id")); + cfg_setinfo("name", eName->text().utf8()); + n=cfgobj_count(context, aot_remark); + if (!n) remark=cfgobj_new(context, aot_remark, trUtf8("Комментарий"), NULL); + else id=cfgobj_idn(context, aot_remark, 1, &remark); + if (remark) cfgobj_settext(remark, eRemark->text().utf8()); + n=cfgobj_count(context, aot_sourcecode); + if (!n) code=cfgobj_new(context, aot_sourcecode, trUtf8("Глобальный модуль"), NULL); + else id=cfgobj_idn(context, aot_sourcecode, 1, &code); + if (code) cfgobj_settext(code, eModule->text().utf8()); + +*/ +} diff --git a/src/designer/deditcfg.h b/src/designer/deditcfg.h new file mode 100644 index 0000000..129d83e --- /dev/null +++ b/src/designer/deditcfg.h @@ -0,0 +1,29 @@ +#ifndef DEDITCFG_H +#define DEDITCFG_H + +#include "ui_deditcfg.h" + + +class dEditCfg : public Q3MainWindow, public Ui::dEditCfg +{ + Q_OBJECT + +public: + dEditCfg(QWidget* parent = 0, const char* name = 0, Qt::WindowFlags fl = Qt::WType_TopLevel); + ~dEditCfg(); + + aListViewItem *item; + aCfgItem globals; + +public slots: + virtual void init(); + virtual void destroy(); + virtual void setData( aListViewItem * o ); + virtual void updateMD(); + +protected slots: + virtual void languageChange(); + +}; + +#endif // DEDITCFG_H diff --git a/src/designer/deditcfg.ui b/src/designer/deditcfg.ui new file mode 100644 index 0000000..6c0d3e7 --- /dev/null +++ b/src/designer/deditcfg.ui @@ -0,0 +1,449 @@ + + dEditCfg + + + + 0 + 0 + 461 + 364 + + + + + 400 + 364 + + + + Business scheme parameters + + + + + 0 + 0 + 461 + 364 + + + + + + + + 10 + + + + + Common + + + + + + + + + 80 + 0 + + + + QFrame::NoFrame + + + QFrame::Plain + + + Name + + + false + + + + + + + + + + + + + + + 80 + 0 + + + + Author + + + false + + + + + + + + + + + + + + + 80 + 0 + + + + Date + + + false + + + + + + + + + + + + + + Description + + + false + + + + + + + + + + + + + User + + + + + + + 160 + 0 + + + + Data base server user + + + false + + + + + + + + + + + + + 160 + 0 + + + + Data base password + + + false + + + + + + + QLineEdit::Password + + + + + + + + + + + + 160 + 0 + + + + + 160 + 32767 + + + + Data base type + + + false + + + + + + + false + + + false + + + + Unknown + + + + + mysql + + + + + postgres + + + + + + + + + + + + + 160 + 0 + + + + Data base server address + + + false + + + + + + + + + + + + + + + 160 + 0 + + + + Data base name + + + false + + + + + + + + + + + + + + + + + 160 + 0 + + + + Data base server port + + + false + + + + + + + + + + + + Qt::Vertical + + + QSizePolicy::Expanding + + + + 130 + 21 + + + + + + + + + + + + + 160 + 0 + + + + Work directory + + + false + + + + + + + + + + + + + + + 160 + 0 + + + + Configuration file name + + + false + + + + + + + + + + + + Qt::Vertical + + + QSizePolicy::Expanding + + + + 20 + 20 + + + + + + + + Data base header + + + false + + + + + + + + + + + Global module + + + + + + + + + + + + + + rcIcon + + + Q3MainWindow + QWidget +
q3mainwindow.h
+ 1 +
+ + Q3TextEdit + Q3Frame +
q3textedit.h
+
+ + QSEditor + QWidget +
qseditor.h
+
+
+ + mdtree.h + acfg.h + qseditor.h + mainform.h + qseditor.h + + + +
diff --git a/src/designer/deditcolumns.cpp b/src/designer/deditcolumns.cpp new file mode 100644 index 0000000..e78c624 --- /dev/null +++ b/src/designer/deditcolumns.cpp @@ -0,0 +1,266 @@ +#include "deditcolumns.h" + +#include +#include +#include + +#include +#include +//Added by qt3to4: +#include +#include +#include "acfg.h" + +/* + * Constructs a dEditColumns as a child of 'parent', with the + * name 'name' and widget flags set to 'f'. + * + */ +dEditColumns::dEditColumns(QWidget* parent, const char* name, Qt::WindowFlags fl) + : Q3MainWindow(parent, name, fl) +{ + setupUi(this); + + (void)statusBar(); + init(); +} + +/* + * Destroys the object and frees any allocated resources + */ +dEditColumns::~dEditColumns() +{ + destroy(); + // no need to delete child widgets, Qt does it all for us +} + +/* + * Sets the strings of the subwidgets using the current + * language. + */ +void dEditColumns::languageChange() +{ + retranslateUi(this); +} + +void dEditColumns::setData( ananasListViewItem * o ) +{ + item = o; + md = o->md; + obj = o->obj; + aCfgItem com_action, apix; + QPixmap pix; + + + usedFields = new ananasTreeView( gbFields, md ); + Q3GridLayout *l = new Q3GridLayout( gbFields ); + l->addWidget( usedFields, 0, 0); + availableFields = new ananasTreeView( frmFields, md ); + l = new Q3GridLayout( frmFields ); + l->addWidget( availableFields, 0, 0); + + aCfgItem cobj, fobj, dobj, pobj, tobj; + + uint n, fCount, tCount, addfields, addtables; + long id; + QString dName, fName; + cobj = md->parent(md->parent(obj)); + setCaption( tr("Column:") + md->attr( cobj, mda_name ) + "." + md->attr( obj, mda_name )); + eName->setText( md->attr( obj, mda_name ) ); + ananasListViewItem *fitem, *ditem, *titem, *tparent, *docs; + QStringList docsId = md->getJournalDocuments(cobj); + docs = new ananasListViewItem( availableFields, availableFields->lastItem(), md, md->find(md->find(mdc_metadata),md_documents,0), QObject::tr("Documents") ); + docs->setPixmap(0, rcIcon("doc_g.png")); + docs->setOpen(true); + n = docsId.count(); + for ( uint i = 0; i < n; i++ ) + { + id = docsId[i].toInt(); + dobj = md->find(id); + if ( dobj.isNull() ) + continue; + ditem = new ananasListViewItem( docs, docs->getLastChild(), md, dobj ); + ditem->setPixmap(0, rcIcon("doc.png")); + tobj = md->find(dobj,md_header,0); + tparent = new ananasListViewItem( ditem, ditem->getLastChild(), md, tobj, QObject::tr("Header") ); + tparent->setPixmap(0, rcIcon("doc_h.png")); + fCount = md->count(tobj,md_field); + for ( uint k = 0; k < fCount; k++ ) + { + fobj = md->find(tobj,md_field,k); + if ( fobj.isNull()) + continue; + fitem = new ananasListViewItem ( tparent, tparent->getLastChild(), md, fobj ); + fitem->setPixmap(0, rcIcon("field.png")); + } + pobj = md->find(ditem->obj, md_tables, 0); + if ( !pobj.isNull() ) + { + tparent = new ananasListViewItem( ditem, ditem->getLastChild(), md, pobj, QObject::tr("Tables") ); + tparent->setPixmap(0, rcIcon("table_g.png")); + addtables = 0; + tCount = md->count(pobj,md_table); + for ( uint j = 0; j < tCount; j++ ) + { + tobj = md->find ( pobj, md_table, j ); + if ( tobj.isNull() ) + continue; + titem = new ananasListViewItem( tparent, tparent->getLastChild(), md, tobj ); + titem->setPixmap(0, rcIcon("table.png")); + fCount = md->count(tobj,md_field); + addfields = 0; + for ( uint k = 0; k < fCount; k++ ) + { + fobj = md->find(tobj,md_field,k); + if ( fobj.isNull()) + continue; + QString sum = md->attr(fobj,mda_sum); + if ( sum != "1" ) + continue; + addfields++; + fitem = new ananasListViewItem ( titem, titem->getLastChild(), md, fobj ); + fitem->setPixmap(0, rcIcon("field.png")); + } + if ( !addfields ) + delete titem; + else + addtables++; + } + if ( !addtables ) + delete tparent; + } + } + fieldsList.clear(); + n = md->count(obj,md_fieldid); + for (uint i = 0; i < n; i++) + { + fobj = md->find( obj, md_fieldid, i ); + if ( fobj.isNull() ) + continue; + id = md->text(fobj).toLong(); + aCfgItem testitem = md->find(id); + if (testitem.isNull()) + md->remove( testitem ); + else + addField( testitem ); + } +} + + +void dEditColumns::updateMD() +{ + aCfgItem field; + item->setText( 0, eName->text().stripWhiteSpace() ); + md->setAttr(obj, mda_name, eName->text().stripWhiteSpace()); + do + { + field = md->findChild( obj, md_fieldid, 0 ); + if ( !field.isNull() ) + md->remove( field ); + } while ( !field.isNull() ); + ananasListViewItem *aitem = (ananasListViewItem *)usedFields->firstChild(); + if (!aitem) + return; + while ( aitem ) + { + field = md->insert( obj, md_fieldid, QString::null, -1 ); + md->setText( field, QString( "%1" ).arg( aitem->id ) ); + aitem = (ananasListViewItem *)aitem->nextSibling(); + } +} + +void dEditColumns::destroy() +{ + updateMD(); + ( (MainForm*)this->topLevelWidget() )->wl->remove( this ); + ( (MainForm*)this->topLevelWidget() )->removeTab(name()); +} + +void dEditColumns::init() +{ + statusBar()->hide(); +} + + +void +dEditColumns::bAddAction_clicked() +{ + ananasListViewItem *cur = (ananasListViewItem *)availableFields->selectedItem(); + if (!cur) + return; + if ( md->objClass( cur->obj ) != md_field ) + return; + eName->setText( md->attr( cur->obj, mda_name ) ); + addField( cur->obj ); +} + + +void dEditColumns::bRemoveAction_clicked() +{ + ananasListViewItem *rmItem = (ananasListViewItem*)usedFields->selectedItem(); + if ( !rmItem ) + return; + aCfgItem cobj = md->find(md->id(rmItem->obj)); + aCfgItem doc, parent = md->parent(cobj); + if ( md->objClass (parent) == md_header ) + doc = md->parent(parent); + else + doc = md->parent(md->parent(parent)); + fieldsList.remove(md->attr(doc,mda_id)); + usedFields->removeItem( rmItem ); +} + + +void dEditColumns::bMoveUp_clicked() +{ + Q3ListViewItem *aitem, *after; + + aitem = usedFields->selectedItem(); + if ( aitem ) + { + after = aitem->itemAbove(); + if ( after ) + after->moveItem( aitem ); + } +} + + +void dEditColumns::bMoveDown_clicked() +{ + Q3ListViewItem *aitem, *after; + aitem = usedFields->selectedItem(); + if ( aitem ) + { + after = aitem->itemBelow(); + if ( after ) + aitem->moveItem( after ); + } +} + + + +void dEditColumns::addField( aCfgItem addItem ) +{ + aCfgItem fparent, parent; + fparent = md->parent(addItem); + QString fName; + if ( md->objClass( fparent ) == md_header ) + { + fName = QObject::tr("header"); + parent = md->parent(fparent); + } + else + { + fName = md->attr( fparent, mda_name ); + parent = md->parent(md->parent(fparent)); + } + QString fId = md->attr( parent, mda_id ); + if ( fieldsList.findIndex(fId) != -1 ) + return; + fName = md->attr(parent,mda_name)+"."+fName+"."+md->attr(addItem,mda_name); + ananasListViewItem *aitem = new ananasListViewItem(usedFields, usedFields->lastItem(), md, addItem,fName ); + aitem->setPixmap(0, rcIcon("field.png")); + aitem->setRenameEnabled(0,false); + fieldsList.append(fId); +} + diff --git a/src/designer/deditcolumns.h b/src/designer/deditcolumns.h new file mode 100644 index 0000000..8e7478c --- /dev/null +++ b/src/designer/deditcolumns.h @@ -0,0 +1,41 @@ +#ifndef DEDITCOLUMNS_H +#define DEDITCOLUMNS_H + +#include "ui_deditcolumns.h" + + +class dEditColumns : public Q3MainWindow, public Ui::dEditColumns +{ + Q_OBJECT + +public: + dEditColumns(QWidget* parent = 0, const char* name = 0, Qt::WindowFlags fl = Qt::WType_TopLevel); + ~dEditColumns(); + +public slots: + virtual void setData( ananasListViewItem * o ); + virtual void updateMD(); + virtual void bAddAction_clicked(); + virtual void bRemoveAction_clicked(); + virtual void bMoveUp_clicked(); + virtual void bMoveDown_clicked(); + +protected slots: + virtual void languageChange(); + +private: + aCfgItem obj; + aCfg *md; + aAliasEditor *al; + ananasListViewItem * item; + ananasTreeView *availableFields; + ananasTreeView *usedFields; + QStringList fieldsList; + + void destroy(); + void init(); + virtual void addField( aCfgItem addItem ); + +}; + +#endif // DEDITCOLUMNS_H diff --git a/src/designer/deditcolumns.ui b/src/designer/deditcolumns.ui new file mode 100644 index 0000000..f618475 --- /dev/null +++ b/src/designer/deditcolumns.ui @@ -0,0 +1,293 @@ + + dEditColumns + + + + 0 + 0 + 495 + 361 + + + + Columns + + + + + 0 + 0 + 495 + 361 + + + + + + + + + Name: + + + false + + + + + + + true + + + + 0 + 22 + + + + + + + + + + + + Qt::Vertical + + + QSizePolicy::Expanding + + + + 20 + 44 + + + + + + + + + 0 + 0 + + + + + + + + + + + + + + + 0 + 0 + + + + + + + + + + + + + + + 0 + 0 + + + + + + + + + + + + + + + 0 + 0 + + + + + + + + + + + + + + Qt::Vertical + + + QSizePolicy::Expanding + + + + 21 + 35 + + + + + + + + + + + 0 + 0 + + + + QFrame::NoFrame + + + QFrame::Plain + + + + + + + + 0 + 0 + + + + Columns + + + 0 + + + 0 + + + + + + + + Action + + + Action + + + + + rcIcon + + + Q3GroupBox + QGroupBox +
Qt3Support/Q3GroupBox
+ 1 +
+ + Q3Frame + QFrame +
Qt3Support/Q3Frame
+ 1 +
+ + Q3MainWindow + QWidget +
q3mainwindow.h
+ 1 +
+
+ + atreeitems.h + aliaseditor.h + mdtree.h + mainform.h + + + + + bAddAction + clicked() + dEditColumns + bAddAction_clicked() + + + 20 + 20 + + + 20 + 20 + + + + + bRemoveAction + clicked() + dEditColumns + bRemoveAction_clicked() + + + 20 + 20 + + + 20 + 20 + + + + + bMoveUp + clicked() + dEditColumns + bMoveUp_clicked() + + + 20 + 20 + + + 20 + 20 + + + + + bMoveDown + clicked() + dEditColumns + bMoveDown_clicked() + + + 20 + 20 + + + 20 + 20 + + + + +
diff --git a/src/designer/deditcommand.cpp b/src/designer/deditcommand.cpp new file mode 100644 index 0000000..5423ecb --- /dev/null +++ b/src/designer/deditcommand.cpp @@ -0,0 +1,241 @@ +#include "deditcommand.h" + +#include +#include +#include + +#include +#include +//Added by qt3to4: +#include +#include "acfg.h" + +//extern aCfg cfg; + +/* + * Constructs a dEditCommand as a child of 'parent', with the + * name 'name' and widget flags set to 'f'. + * + */ +dEditCommand::dEditCommand(QWidget* parent, const char* name, Qt::WindowFlags fl) + : Q3MainWindow(parent, name, fl) +{ + setupUi(this); + + (void)statusBar(); + init(); +} + +/* + * Destroys the object and frees any allocated resources + */ +dEditCommand::~dEditCommand() +{ + destroy(); + // no need to delete child widgets, Qt does it all for us +} + +/* + * Sets the strings of the subwidgets using the current + * language. + */ +void dEditCommand::languageChange() +{ + retranslateUi(this); +} + +void dEditCommand::updateMD() +{ + aCfgItem com_action, apix; + al->updateMD( ); + QPixmap pix; + + item->setText( 0, eName->text().stripWhiteSpace() ); + md->setAttr( obj, mda_name, eName->text().stripWhiteSpace() ); + md->setSText( obj, md_description, eDescription->text() ); + md->setSText( obj, md_menutext, eMenuText->text() ); + + QString sKey = ""; + if ( cbKey-> currentText () != "" ) + { + if ( cbCTRL->isChecked() ) + sKey += md_km_ctrl; + if ( cbALT->isChecked() ) + sKey += md_km_alt; + if ( cbShift->isChecked() ) + sKey += md_km_shift; + sKey += cbKey->currentText (); + } + md->setSText( obj, md_key, sKey ); + + do + { + com_action = md->findChild( obj, md_comaction, 0 ); + if ( !com_action.isNull() ) + md->remove( com_action ); + } while ( !com_action.isNull() ); + ananasListViewItem *aitem = (ananasListViewItem *)vComActions->firstChild(); + if (!aitem) + return; + while ( aitem ) + { + com_action = md->insert( obj, md_comaction, QString::null, -1 ); + md->setText( com_action, QString( "%1" ).arg( aitem->id ) ); + aitem = (ananasListViewItem *)aitem->nextSibling(); + } + aitem = (ananasListViewItem *)vComActions->firstChild(); + apix = md->findChild( md->find( aitem->id ), md_active_picture, 0 ); + if ( apix.isNull() ) + return; + pix.loadFromData( md->binary( apix ) ); + item->setPixmap( 0, pix ); +} + +void dEditCommand::destroy() +{ + updateMD(); + ( (MainForm*)this->topLevelWidget() )->wl->remove( this ); + ( (MainForm*)this->topLevelWidget() )->removeTab(name()); +} + +void dEditCommand::init() +{ + statusBar()->hide(); +} + +void dEditCommand::setData( InterfaceListViewItem * o ) +{ + int i, j, n, k, id; + item = o; + md = o->md; + obj = o->obj; + aCfgItem com_action, apix; + aAliasEditor *a = new aAliasEditor( md, obj, tAliases ); + QPixmap pix; + + vComActions = new ananasTreeView( tabWidget2->page(1), md ); + vComActions->setSorting( -1 ); + // TODO Fixme!!! + //--layout28->addWidget( vComActions, 0, 0 ); + actiontree = new aActionTreeView ( tabWidget2->page(1), md ); + disconnect( actiontree, SIGNAL( contextMenuRequested( Q3ListViewItem*, const QPoint&, int) ), actiontree, SLOT(ContextMenu() ) ); + disconnect( actiontree, SIGNAL( returnPressed( Q3ListViewItem*) ), actiontree, SLOT( itemEdit() ) ); + disconnect( actiontree, SIGNAL( doubleClicked( Q3ListViewItem*) ), actiontree, SLOT( itemEdit() ) ); + // TODO Fixme!!! + //--layout29->addWidget( actiontree, 0, 0 ); + + al = a; + al->setData(); + + setCaption( tr("Command:") + md->attr( obj, mda_name ) ); + eName->setText( md->attr( obj, mda_name ) ); + eMenuText->setText( md->sText( obj, md_menutext ) ); + eDescription->setText( md->sText( obj, md_description ) ); + + QString sKey = md->sText( obj, md_key ); + if ( ( sKey.find (md_km_ctrl) ) >= 0 ) + { + cbCTRL->setChecked ( TRUE ); + sKey.remove(md_km_ctrl); + } + if ( ( sKey.find (md_km_alt) ) >= 0 ) + { + cbALT->setChecked ( TRUE ); + sKey.remove(md_km_alt); + } + if ( ( sKey.find (md_km_shift) ) >= 0 ) + { + cbShift->setChecked ( TRUE ); + sKey.remove(md_km_shift); + } + + + n = cbKey->count(); + for ( i = 0; i < n; i++ ) + if ( sKey == cbKey->text( i ) ) + { + cbKey->setCurrentItem( i ); + break; + } + n = md->countChild( obj, md_comaction ); + k = md->count( md->find ( mdc_actions ), md_action ); + ananasListViewItem *aitem; + aCfgItem actionObj; + for ( i = 0; i < n; i++ ) + { + actionObj = md->find (obj, md_comaction, i); + id = md->text(actionObj).toLong(); + if ( actionObj.isNull() ) + md->remove(actionObj); + com_action = md->find(id); + aitem = new ananasListViewItem (vComActions, vComActions->lastItem(), md, com_action); + aitem->setRenameEnabled( 0, FALSE ); + apix = md->findChild( com_action, md_active_picture, 0 ); + if ( apix.isNull() ) + break; + pix.loadFromData( md->binary( apix ) ); + aitem->setPixmap( 0, pix ); +/* for ( j = 0; j < k; j++) + { + com_action = md->find ( md->find( mdc_actions ), md_action, j ); + if ( md->id(com_action) == id ) + { + aitem = new ananasListViewItem (vComActions, vComActions->lastItem(), md, com_action); + aitem->setRenameEnabled( 0, FALSE ); + apix = md->findChild( com_action, md_active_picture, 0 ); + if ( apix.isNull() ) + break; + pix.loadFromData( md->binary( apix ) ); + aitem->setPixmap( 0, pix ); + } + }*/ + } +} + + +void +dEditCommand::bAddAction_clicked() +{ + aCfgItem apix; + QPixmap pix; + + ananasListViewItem *cur = (ananasListViewItem *)actiontree->selectedItem(); + if (!cur) + return; + if ( md->objClass( cur->obj ) != md_action ) + return; + ananasListViewItem *aitem = new ananasListViewItem(vComActions, vComActions->lastItem(), md, cur->obj ); + apix = md->findChild( md->find( aitem->id ), md_active_picture, 0 ); + pix.loadFromData( md->binary( apix ) ); + aitem->setPixmap( 0, pix ); +} + + +void dEditCommand::bRemoveAction_clicked() +{ + vComActions->removeItem( vComActions->selectedItem() ); +} + + +void dEditCommand::bMoveUp_clicked() +{ + ananasListViewItem *aitem, *after; + + aitem = (ananasListViewItem *) vComActions->selectedItem(); + if ( aitem ) { + after = (ananasListViewItem *)aitem->itemAbove(); + if ( after ) after->moveItem( aitem ); + } + +} + + +void dEditCommand::bMoveDown_clicked() +{ + ananasListViewItem *aitem, *after; + aitem = (ananasListViewItem *)vComActions->selectedItem(); + if ( aitem ) { + after = (ananasListViewItem *)aitem->itemBelow(); + if ( after ) aitem->moveItem( after ); + } +} diff --git a/src/designer/deditcommand.h b/src/designer/deditcommand.h new file mode 100644 index 0000000..3b22e6c --- /dev/null +++ b/src/designer/deditcommand.h @@ -0,0 +1,39 @@ +#ifndef DEDITCOMMAND_H +#define DEDITCOMMAND_H + +#include "ui_deditcommand.h" + + +class dEditCommand : public Q3MainWindow, public Ui::dEditCommand +{ + Q_OBJECT + +public: + dEditCommand(QWidget* parent = 0, const char* name = 0, Qt::WindowFlags fl = Qt::WType_TopLevel); + ~dEditCommand(); + + ananasTreeView *vComActions; + aActionTreeView *actiontree; + InterfaceListViewItem * item; + aAliasEditor *al; + aCfg *md; + aCfgItem obj; + +public slots: + virtual void updateMD(); + virtual void setData( InterfaceListViewItem * o ); + virtual void bAddAction_clicked(); + virtual void bRemoveAction_clicked(); + virtual void bMoveUp_clicked(); + virtual void bMoveDown_clicked(); + +protected slots: + virtual void languageChange(); + +private: + void destroy(); + void init(); + +}; + +#endif // DEDITCOMMAND_H diff --git a/src/designer/deditcommand.ui b/src/designer/deditcommand.ui new file mode 100644 index 0000000..9320388 --- /dev/null +++ b/src/designer/deditcommand.ui @@ -0,0 +1,577 @@ + + dEditCommand + + + + 0 + 0 + 569 + 371 + + + + Command + + + + + 0 + 0 + 569 + 371 + + + + + + + + + + QTabWidget::Rounded + + + + Common + + + + + + + + Description: + + + false + + + + + + + + + + + + + + Hot Key: + + + false + + + + + + + Ctrl + + + + + + + Alt + + + + + + + Shift + + + + + + + + + + + + + 1 + + + + + 2 + + + + + 3 + + + + + 4 + + + + + 5 + + + + + 6 + + + + + 7 + + + + + 8 + + + + + 9 + + + + + 0 + + + + + A + + + + + B + + + + + C + + + + + D + + + + + E + + + + + F + + + + + G + + + + + H + + + + + I + + + + + J + + + + + K + + + + + L + + + + + M + + + + + N + + + + + O + + + + + P + + + + + Q + + + + + R + + + + + S + + + + + T + + + + + U + + + + + V + + + + + W + + + + + X + + + + + Y + + + + + Z + + + + + + + + Qt::Vertical + + + QSizePolicy::Expanding + + + + 71 + 20 + + + + + + + + + + Type: + + + false + + + + + + + Menu text + + + false + + + + + + + + + + true + + + + 0 + 22 + + + + + + + + Qt::Vertical + + + QSizePolicy::Expanding + + + + 360 + 20 + + + + + + + + + + + Name: + + + false + + + + + + + + Actions + + + + + + + + + + + + + Qt::Vertical + + + QSizePolicy::Expanding + + + + 20 + 44 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Qt::Vertical + + + QSizePolicy::Expanding + + + + 21 + 44 + + + + + + + + + + + + + Aliases + + + + + + 0 + + + 2 + + + + Lang + + + + + Name + + + + + + + + + + + + + rcIcon + + + Q3MainWindow + QWidget +
q3mainwindow.h
+ 1 +
+ + Q3Table + Q3Frame +
q3table.h
+
+ + Q3TextEdit + Q3Frame +
q3textedit.h
+
+
+ + interfacetree.h + aliaseditor.h + actiontree.h + mainform.h + + + + + bAddAction + clicked() + dEditCommand + bAddAction_clicked() + + + 20 + 20 + + + 20 + 20 + + + + + bRemoveAction + clicked() + dEditCommand + bRemoveAction_clicked() + + + 20 + 20 + + + 20 + 20 + + + + + bMoveUp + clicked() + dEditCommand + bMoveUp_clicked() + + + 20 + 20 + + + 20 + 20 + + + + + bMoveDown + clicked() + dEditCommand + bMoveDown_clicked() + + + 20 + 20 + + + 20 + 20 + + + + +
diff --git a/src/designer/deditdialog.cpp b/src/designer/deditdialog.cpp new file mode 100644 index 0000000..9580d6a --- /dev/null +++ b/src/designer/deditdialog.cpp @@ -0,0 +1,337 @@ +#include "deditdialog.h" + +#include +#include +#include + +#include "qtextcodec.h" + +#include +#include +#include +#include "acfg.h" +#include "qsproject.h" +#include "qsscript.h" +#include +#include +//--#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "formdesigner.h" +#include "mainform.h" +#include "alog.h" + +//#include "qananastable.h" +//#include + +//extern QApplication *application; + +/* + * Constructs a dEditDialog as a child of 'parent', with the + * name 'name' and widget flags set to 'f'. + * + */ +dEditDialog::dEditDialog(QWidget* parent, const char* name, Qt::WindowFlags fl) + : Q3MainWindow(parent, name, fl) +{ + setupUi(this); + + (void)statusBar(); + init(); +} + +/* + * Destroys the object and frees any allocated resources + */ +dEditDialog::~dEditDialog() +{ + destroy(); + // no need to delete child widgets, Qt does it all for us +} + +/* + * Sets the strings of the subwidgets using the current + * language. + */ +void dEditDialog::languageChange() +{ + retranslateUi(this); +} + +void dEditDialog::init() +{ + delete statusBar(); + eModule->setInterpreter(new QSInterpreter()); +// fd = new aFormDesigner(); +} + + +void dEditDialog::destroy() +{ + updateMD(); + ( (MainForm*)this->topLevelWidget() )->wl->remove( this ); + ( (MainForm*)this->topLevelWidget() )->removeTab(name()); +} + + +void dEditDialog::setData( aListViewItem *o ) +{ + item=NULL; + QString parentClass; + if (o) { + item = o; + aCfg *md = o->md; + aCfgItem obj = o->obj; + aAliasEditor *a = new aAliasEditor( md, obj, tAliases ); + al = a; + al->setData(); + eName->setText( md->attr( obj, mda_name ) ); + eDescription->setText( md->sText( obj, md_description ) ); + eModule->setText( md->sText( obj, md_sourcecode ) ); + eFormFile->setText( QString("inputform_")+QString::number(item->id)+QString(".ui")); + setCaption( tr("Form:") + eName->text() ); + parentClass = md->objClass( md->parent ( md->parent( obj ) ) ); + if ( parentClass == md_document ) { +// cbFormMode->insertItem(QObject::tr("Document")); + } + if ( parentClass == md_catalogue ) { +// cbDefault->insertItem(QObject::tr("selection")); + cbFormMode->clear(); + cbFormMode->insertItem(QObject::tr("Elements list dialog")); + cbFormMode->insertItem(QObject::tr("Element dialog")); + cbFormMode->insertItem(QObject::tr("Group dialog")); + } + else cbSelect->setHidden( true ); + int i = md->sText(obj, md_defaultmod).toInt(); + cbNew->setChecked( (i>>md_form_new)%2 ); + cbView->setChecked( (i>>md_form_view)%2 ); + cbEdit->setChecked( (i>>md_form_edit)%2 ); + cbSelect->setChecked( (i>>md_form_select)%2 ); + i = md->attr( obj, mda_type ).toInt(); + cbFormMode->setCurrentItem( i ); + i = md->attr( obj, mda_readonly ).toInt(); + cbReadOnly->setChecked( i ); + QString ui= md->sText( obj, md_formdesign ); +// bPreview->setDisabled(ui.isEmpty()); + } +} + +//#include "mainform.h" +//#include +//extern MainForm *mainform; + +void dEditDialog::EditForm() +{ + + aCfg *md = item->md; + aCfgItem obj = item->obj, o; + QString ui, s, tpl_name = "inputform.ui.tpl", tpldir; + QFile f( eFormFile->text() ); +// char* arg; +// int rc; + aLog::print(aLog::Debug,tr("dEditDialog edit form")); + //MainForm *mw = (MainForm*) topLevelWidget(); + //printf("end getting pointer to Main form\n"); + QStringList env; +// QProcess proc( this ); + +#ifdef Q_OS_WIN32 + tpldir = qApp->applicationDirPath()+"/templates/"; +#else + tpldir = "/usr/share/ananas/templates/"; +#endif + tpldir = ":/designer/templates/"; + +/* + int rc; + char* arg; + QFile f; + QString s; + const char *ui; + int fc=0; + + if (cfg_rcfile()) { + setenv("ANANASRCFILE",cfg_rcfile(),1); + } else { + cfg_message(1, "Ошибка! Не удалось получить значение для записи в ANANASRCFILE\n"); + } +*/ + + if (!f.exists()) + { + aLog::print(aLog::Debug,tr("dEditDialog form file does not exists")); + ui= md->sText( obj, md_formdesign ); + if (!ui.isEmpty()) + { + + aLog::print(aLog::Debug, tr("dEditDialog create form file from metadata")); + QFile f1(eFormFile->text()); + f1.open(QIODevice::WriteOnly); + f1.writeBlock(ui, strlen(ui)); + f1.close(); + + } + else + { + aLog::print(aLog::Debug, tr("dEditDialog create new form file from template")); + o = md->parent( md->parent( obj ) ); + if ( md->objClass( o ) == md_document ) tpl_name = "inputformdoc.tpl"; + if ( md->objClass( o ) == md_catalogue ) tpl_name = "inputformcat.tpl"; + if ( md->objClass( o ) == md_journal ) tpl_name = "inputformjourn.tpl"; + if ( md->objClass( o ) == md_report ) tpl_name = "inputformrep.tpl"; + QFile fi( tpldir+tpl_name ); + if ( fi.open( QIODevice::ReadOnly )) + { + if(f.open( QIODevice::WriteOnly )) + { + Q3TextStream tso( &f ); + tso.setEncoding( Q3TextStream::UnicodeUTF8 ); + QString form = fi.readAll(); +// printf("obj id = %i\n", md->id( o ) ); + form.replace( QString("$$$id$$$"), QString("%1").arg( md->id( o ) ) ); + form.replace( QString("$$$name$$$"), QString("") ); + form.replace( QString("$$$caption$$$"), md->attr( o, mda_name ) ); + tso << form; //tsi.read(); + fi.close(); + f.close(); + } + else + { + aLog::print(aLog::Error, tr("dEditDialog open file %1 for write").arg(f.name())); + } + } + else + { + aLog::print(aLog::Error,tr("dEditDialog open file %1 for read from templates directory %2").arg(tpl_name).arg(tpldir)); + } +// s=QString("cp inputform.ui.tpl ")+ eFormFile->text(); +// system((const char *)s); + } + } + + if(!QFile(eFormFile->text()).exists()) + { + + aLog::print(aLog::Error, tr("dEditDialog file %1 not exists").arg(eFormFile->text())); + } + formdesigner->fileOpen( eFormFile->text() ); + aLog::print(aLog::Debug, tr("dEditDialog show formdesigner")); + formdesigner->show(); + +// } + + +// +// if (!proc.start()) { +// printf("Error running qt designer\n"); +// } +//CHECK_POINT +/* + if ((rc=fork())==0) { + arg = strdup( (const char *) eFormFile->text() ); + execlp("designer","designer","-client",arg,0); + printf("Error running qt designer: errno=%d\terror=%s\n", + errno,strerror(errno)); + } else if (rc==-1) { + printf("Error while fork: errno=%d\terror=%s\n", + errno,strerror(errno)); + } +*/ +} + + +void dEditDialog::EditModule() +{ +// cfgobj_editcode(objectptr); +} + + +void dEditDialog::updateMD() +{ + + formdesigner->fileSaveAll(); + aCfg *md = item->md; + aCfgItem obj = item->obj; + QString ui; + QFile f(eFormFile->text()); +//if (cancelupdate) return; + al->updateMD(); + item->setText( 0, eName->text().stripWhiteSpace() ); + md->setAttr( obj, mda_name, eName->text().stripWhiteSpace() ); + md->setAttr( obj, mda_type, cbFormMode->currentItem() ); + md->setAttr( obj, mda_readonly, cbReadOnly->isChecked() ); + md->setSText( obj, md_description, eDescription->text() ); + md->setSText( obj, md_sourcecode, eModule->text() ); +// ui.arg(cbDefault->currentItem()); +// md->setSText( obj, md_defaultmod, QString( "%1" ).arg( cbDefault->currentItem() ) ); + int i = (1<isChecked() + \ + (1<isChecked() + \ + (1<isChecked() +\ + (1<isChecked(); + md->setSText( obj, md_defaultmod, QString( "%1" ).arg( i ) ); + if (f.open(QIODevice::ReadOnly)){ + Q3TextStream ts(&f); + ts.setEncoding(Q3TextStream::UnicodeUTF8); + ui=ts.read(); + md->setSText( obj, md_formdesign, ui ); + f.close(); + f.remove(); + } + +} + + + +void dEditDialog::formPreview() +{ +// if ( !QFile::exists(eFormFile->text())) return; + + aCfg *md = item->md; + aCfgItem obj = item->obj; + QString ui, s; + QFile f(eFormFile->text()); + + if (!f.exists()){ + ui= md->sText( obj, md_formdesign ); + if (!ui.isEmpty()) { + f.open(QIODevice::WriteOnly); + f.writeBlock(ui, strlen(ui)); + f.close(); + } else { + return; + QFile fi("inputform.ui.tpl"); + if ( fi.open( QIODevice::ReadOnly ) && f.open( QIODevice::WriteOnly ) ){ + Q3TextStream tsi( &fi ), tso( &f ); + tso << tsi.read(); + fi.close(); + f.close(); + } + } + } + + QIODevice *d; + d= &f; + d->open(QIODevice::ReadOnly); + //--QWidget *form = QWidgetFactory::create(d); + QFormBuilder fb; + QWidget *form = fb.load(d); + d->close(); + if (form) form->show(); + else printf("Error create form\n"); + +} + + + + +int dEditDialog::getDocId() +{ + return docId; +} diff --git a/src/designer/deditdialog.h b/src/designer/deditdialog.h new file mode 100644 index 0000000..8010dce --- /dev/null +++ b/src/designer/deditdialog.h @@ -0,0 +1,38 @@ +#ifndef DEDITDIALOG_H +#define DEDITDIALOG_H + +#include "ui_deditdialog.h" + + +class dEditDialog : public Q3MainWindow, public Ui::dEditDialog +{ + Q_OBJECT + +public: + dEditDialog(QWidget* parent = 0, const char* name = 0, Qt::WindowFlags fl = Qt::WType_TopLevel); + ~dEditDialog(); + + int docId; + aAliasEditor *al; + aFormDesigner *fd; + aListViewItem *item; + + virtual int getDocId(); + +public slots: + virtual void init(); + virtual void destroy(); + virtual void setData( aListViewItem * o ); + virtual void EditForm(); + virtual void EditModule(); + virtual void updateMD(); + +protected slots: + virtual void languageChange(); + +private slots: + virtual void formPreview(); + +}; + +#endif // DEDITDIALOG_H diff --git a/src/designer/deditdialog.ui b/src/designer/deditdialog.ui new file mode 100644 index 0000000..6b1a01d --- /dev/null +++ b/src/designer/deditdialog.ui @@ -0,0 +1,374 @@ + + dEditDialog + + + + 0 + 0 + 436 + 336 + + + + Form + + + + + 0 + 0 + 436 + 336 + + + + + + + 1 + + + + Common + + + + + + + + Description: + + + false + + + + + + + + + + + + + 100 + 0 + + + + Module file + + + false + + + + + + + Form mode: + + + false + + + + + + + + + + + 100 + 0 + + + + Name + + + false + + + + + + + Use for: + + + false + + + + + + + true + + + + + + + + Dialog + + + + + + + + false + + + + + + + + 100 + 0 + + + + Form file + + + false + + + + + + + New + + + + + + + View + + + + + + + Edit + + + + + + + Selection + + + + + + + Qt::Vertical + + + QSizePolicy::Expanding + + + + 30 + 21 + + + + + + + + Read only + + + + + + + + Design + + + + + + QFrame::NoFrame + + + QFrame::Plain + + + + + + + Qt::Vertical + + + QSizePolicy::Expanding + + + + 151 + 171 + + + + + + + + Designer + + + + + + + Preview + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + Module + + + + + + + + + + Aliases + + + + + + 0 + + + 2 + + + + Lang + + + + + Name + + + + + + + + + + + + + rcIcon + + + Q3Frame + QFrame +
Qt3Support/Q3Frame
+ 1 +
+ + Q3MainWindow + QWidget +
q3mainwindow.h
+ 1 +
+ + Q3Table + Q3Frame +
q3table.h
+
+ + Q3TextEdit + Q3Frame +
q3textedit.h
+
+ + QSEditor + QWidget +
qseditor.h
+
+
+ + mdtree.h + formdesigner.h + aliaseditor.h + mainform.h + qseditor.h + + + + + bPreview + clicked() + dEditDialog + formPreview() + + + 20 + 20 + + + 20 + 20 + + + + + pbDesigner + clicked() + dEditDialog + EditForm() + + + 20 + 20 + + + 20 + 20 + + + + +
diff --git a/src/designer/deditdoc.cpp b/src/designer/deditdoc.cpp new file mode 100644 index 0000000..a1a383e --- /dev/null +++ b/src/designer/deditdoc.cpp @@ -0,0 +1,131 @@ +#include "deditdoc.h" + +#include +#include +#include + +#include +#include "acfg.h" +#include +#include + +/* + * Constructs a dEditDoc as a child of 'parent', with the + * name 'name' and widget flags set to 'f'. + * + */ +dEditDoc::dEditDoc(QWidget* parent, const char* name, Qt::WindowFlags fl) + : Q3MainWindow(parent, name, fl) +{ + setupUi(this); + + (void)statusBar(); + init(); +} + +/* + * Destroys the object and frees any allocated resources + */ +dEditDoc::~dEditDoc() +{ + destroy(); + // no need to delete child widgets, Qt does it all for us +} + +/* + * Sets the strings of the subwidgets using the current + * language. + */ +void dEditDoc::languageChange() +{ + retranslateUi(this); +} + +void dEditDoc::init() +{ + delete statusBar(); + eModule->setInterpreter( new QSInterpreter() ); + eStrViewF->setInterpreter( new QSInterpreter() ); + eStrViewF->setEnabled( FALSE ); +} + + +void dEditDoc::destroy() +{ + updateMD(); + item->editor = 0; + ( (MainForm*)this->topLevelWidget() )->wl->remove( this ); + ( (MainForm*)this->topLevelWidget() )->removeTab(name()); +} + + +void dEditDoc::setData( aListViewItem *o ) +{ + long int i; + int fid, fcount, fieldid, stdf; + item = o; + aCfg *md = o->md; + aCfgItem obj = o->obj, sv, field; + + aAliasEditor *a = new aAliasEditor( md, obj, tAliases ); + al = a; + al->setData(); + aRoleEditor *r = new aRoleEditor( md, obj, tRoles, md_document ); + re = r; + re->setData(); + setCaption( tr("Document:") + md->attr( obj, mda_name ) ); + eName->setText( md->attr( obj, mda_name ) ); + eDescription->setText( md->sText( obj, md_description ) ); + eModule->setText( md->sText( obj, md_sourcecode ) ); + sv = md->find( obj, md_string_view ); + eStrViewF->setText( md->sText( sv, md_svfunction ) ); + eSv->insertItem( "[ standart function ]" ); + eSv->insertItem( "[ user function ]" ); + fid = md->sText( sv, md_fieldid ).toInt(); + stdf = md->attr( sv, mda_stdf ).toInt(); + eSv->setCurrentItem( 0 ); + for ( i = 0; i < md->count( obj, md_field ); i++ ) { + field = md->find( obj, md_field, i ); + eSv->insertItem( QString("%1").arg( md->attr( field, mda_name ) ) ); + fieldid = md->id( field ); + fields.insert( i, new int( fieldid ) ); + if ( fid == fieldid && !stdf ) { + eSv->setCurrentItem( i + 2 ); + eStrViewF->setEnabled( FALSE ); + } + } + if ( !fid & !stdf ) { + eStrViewF->setEnabled( TRUE ); + eSv->setCurrentItem( 1 ); + } +} + +void dEditDoc::updateMD() +{ + aCfg *md = item->md; + aCfgItem obj = item->obj, sv; + + al->updateMD(); + re->updateMD(); + item->setText( 0, eName->text().stripWhiteSpace() ); + md->setAttr( obj, mda_name, eName->text().stripWhiteSpace() ); + md->setSText( obj, md_description, eDescription->text() ); + md->setSText( obj, md_sourcecode, eModule->text() ); + sv = md->find( obj, md_string_view ); + if ( sv.isNull() ) sv = md->insert( obj, md_string_view ); + md->setSText( sv, md_svfunction, eStrViewF->text() ); + if ( eSv->currentItem() == 0 ) md->setAttr( sv, mda_stdf, "1" ); + else { + md->setAttr( sv, mda_stdf, "0" ); + if ( eSv->currentItem() == 1 ) md->setSText( sv, md_fieldid, "0" ); + else md->setSText( sv, md_fieldid, QString("%1").arg( *(fields.find( eSv->currentItem() - 2 ) ) ) ); + } +} + + + +void dEditDoc::eSv_activated( int index ) +{ + if ( index == 1 ) eStrViewF->setEnabled( TRUE ); + else eStrViewF->setEnabled( FALSE ); +} diff --git a/src/designer/deditdoc.h b/src/designer/deditdoc.h new file mode 100644 index 0000000..ac1437b --- /dev/null +++ b/src/designer/deditdoc.h @@ -0,0 +1,34 @@ +#ifndef DEDITDOC_H +#define DEDITDOC_H + +#include "ui_deditdoc.h" + + +class dEditDoc : public Q3MainWindow, public Ui::dEditDoc +{ + Q_OBJECT + +public: + dEditDoc(QWidget* parent = 0, const char* name = 0, Qt::WindowFlags fl = Qt::WType_TopLevel); + ~dEditDoc(); + + aListViewItem *item; + aAliasEditor *al; + Q3IntDict fields; + aRoleEditor *re; + +public slots: + virtual void setData( aListViewItem * o ); + virtual void updateMD(); + virtual void eSv_activated( int index ); + +protected slots: + virtual void languageChange(); + + virtual void init(); + virtual void destroy(); + + +}; + +#endif // DEDITDOC_H diff --git a/src/designer/deditdoc.ui b/src/designer/deditdoc.ui new file mode 100644 index 0000000..4444461 --- /dev/null +++ b/src/designer/deditdoc.ui @@ -0,0 +1,225 @@ + + dEditDoc + + + + 0 + 0 + 446 + 322 + + + + Document + + + + + 0 + 0 + 446 + 322 + + + + + + + + + + QTabWidget::Rounded + + + + Common + + + + + + + + Name + + + false + + + + + + + + + + + + Description: + + + false + + + + + + + + + + + Module + + + + + + + + + + Aliases + + + + + + 0 + + + 1 + + + + Name + + + + + + + + + String view + + + + + + + + + false + + + + + + + + Access + + + + + + 0 + + + 2 + + + false + + + Q3Table::Multi + + + + Read + + + + + Write + + + + + + + + + + + + + rcIcon + + + Q3MainWindow + QWidget +
q3mainwindow.h
+ 1 +
+ + Q3Table + Q3Frame +
q3table.h
+
+ + Q3TextEdit + Q3Frame +
q3textedit.h
+
+ + QSEditor + QWidget +
qseditor.h
+
+
+ + mdtree.h + aliaseditor.h + mainform.h + roleeditor.h + qseditor.h + qseditor.h + + + + + eSv + activated(int) + dEditDoc + eSv_activated(int) + + + 20 + 20 + + + 20 + 20 + + + + + eSv + highlighted(int) + dEditDoc + eSv_activated(int) + + + 20 + 20 + + + 20 + 20 + + + + +
diff --git a/src/designer/deditfield.cpp b/src/designer/deditfield.cpp new file mode 100644 index 0000000..cd575de --- /dev/null +++ b/src/designer/deditfield.cpp @@ -0,0 +1,326 @@ +#include "deditfield.h" + +#include +#include +#include + +#include "acfg.h" +#include "acfgrc.h" +#include +#include "alog.h" + +/* +#include +#include +#include +#include +*/ + +/* + * Constructs a dEditField as a child of 'parent', with the + * name 'name' and widget flags set to 'f'. + * + */ +dEditField::dEditField(QWidget* parent, const char* name, Qt::WindowFlags fl) + : Q3MainWindow(parent, name, fl) +{ + setupUi(this); + + (void)statusBar(); + init(); +} + +/* + * Destroys the object and frees any allocated resources + */ +dEditField::~dEditField() +{ + destroy(); + // no need to delete child widgets, Qt does it all for us +} + +/* + * Sets the strings of the subwidgets using the current + * language. + */ +void dEditField::languageChange() +{ + retranslateUi(this); +} + +void +setText(){ + +} + + +void dEditField::destroy() +{ + updateMD(); + ( (MainForm*)this->topLevelWidget() )->wl->remove( this ); + ( (MainForm*)this->topLevelWidget() )->removeTab(name()); +} + + + +void dEditField::init() +{ +// eModule->setInterpreter(new QSInterpreter()); + delete statusBar(); + otypes.clear(); + artypes.clear(); + eType->clear(); + otypes.append(" "); + eType->insertItem(tr("Unknown"), 0); + +} + + +void dEditField::setData( aListViewItem *o ) +{ + item = o; + aCfg *md = o->md; + aCfgItem obj = o->obj; + + QString ts; + char t=' '; + int w=0, d=0, oid, idx=0; + unsigned int i; + + + aAliasEditor *a = new aAliasEditor( md, obj, tAliases ); + al = a; + al->setData(); + // setCaption( tr("Field:") + md->attr( obj, mda_name ) ); + eName->setText( md->attr( obj, mda_name ) ); + nameChanged(); + // eID->setText( md->attr( obj, mda_id ) ); + ts = md->attr( obj, mda_type ); + if(md->objClass(md->parent(obj))==md_element) + { + saldoTextLabel->show(); + comboBox2->show(); +// updateGeometry(); + } + else + { + saldoTextLabel->hide(); + comboBox2->hide(); +// layout()->remove(comboBox2); +// layout()->remove(saldoTextLabel); + +// updateGeometry(); + } + // eType0->setText( ts ); + // eModule->setText( md->sText( obj, md_sourcecode ) ); + eDescription->setText( md->sText( obj, md_description ) ); + + if( md->attr( obj, mda_sort ) == "1" ) efSort->setChecked( true ); + else efSort->setChecked( false ); + if( md->attr( obj, mda_plus ) == "1" ) efPlus->setChecked( true ); + else efPlus->setChecked( false ); + if( md->attr( obj, mda_nz ) == "1" ) efNZ->setChecked( true ); + else efNZ->setChecked( false ); + efSum->setChecked(md->attr( obj, mda_sum ) == "1"); + + QStringList tlist; + if(md->objClass(md->parent(obj))==md_resources) + { + tlist.append("\t"+QObject::tr("Unknown")); + tlist.append("N %d %d\t"+QObject::tr("Numberic")); + } + else + { + tlist = md->types(); + } + otypes.clear(); + + eType->clear(); + for ( QStringList::Iterator it = tlist.begin(); it != tlist.end(); ++it ) { + otypes.append( (*it).section( "\t", 0, 0 ) ); + eType->insertItem( (*it).section("\t", 1, 1 ), idx++ ); + } + + if ( !ts.isEmpty() ) + { + sscanf( ts, "%c %d %d", &t, &w, &d ); + } + else + { + t = 'N'; + w = 10; + } + if ( t=='O' ) { + for( i = 0 ; i < otypes.count(); i++ ) { + if( otypes[i][0] == 'O' ) { + sscanf( (const char *)otypes[ i ], "O %d", &oid ); + if ( oid == w ) { + eType->setCurrentItem( i ); + break; + } + } + } + } else { + if ( t == ' ' ) eType->setCurrentItem( 0 ); + if ( t == 'N' ) + { + eWidth->setMaxValue(20); + eDec->setMaxValue(99); + eType->setCurrentItem( 1 ); + } + if ( t == 'C' ) + { + + eWidth->setMaxValue(254); + eDec->setMaxValue(99); + eType->setCurrentItem( 2 ); + } + if ( t == 'D' ) eType->setCurrentItem( 3 ); + if ( t == 'B' ) eType->setCurrentItem( 4 ); + eWidth->setValue( w ); + eDec->setValue( d ); + } + aCfgItem obj2; + int n, n1,aregid, aregfid; + QString str; + QStringList l_name; + //long oid; + aCfgItem context = md->findChild(md->find(mdc_metadata),md_registers); + comboBox2->clear(); + comboBox2->insertItem(" "); + artypes.clear(); + artypes.append(" "); + n = md->count( context, md_aregister ); +// printf("n=%d name = %s\n",n, md->attr(context,mda_name).ascii()); + for (i=0; ifind( context, md_aregister, i); + if ( !obj.isNull() ) + { + aregid=md->attr(obj,mda_id).toInt(); + str = tr(QString("AccumulationRegister."))+md->attr( obj, mda_name ); + //printf("`%s'\n",str.ascii()); + obj = md->findChild(obj,md_resources); + n1 = md->count( obj, md_field); +// printf("n=%d name = %s\n",n, md->attr(obj,mda_name).ascii()); + for (uint j=0; jfind( obj, md_field, j); + if ( !obj2.isNull() ) + { + aregfid = md->attr(obj2, mda_id).toInt(); + artypes.append(QString(" %1 %2").arg(aregid).arg(aregfid)); + comboBox2->insertItem(str+"."+md->attr( obj2, mda_name )); + if(w==aregid && d==aregfid) comboBox2->setCurrentItem(comboBox2->count()-1); + } + } + } + } + typeSelect( eType->currentItem() ); +} + +void dEditField::updateMD() +{ + QString st; + + aCfg *md = item->md; + aCfgItem obj = item->obj; + + al->updateMD(); + item->setText( 0, eName->text().stripWhiteSpace() ); + md->setAttr( obj, mda_name, eName->text().stripWhiteSpace() ); + md->setSText( obj, md_description, eDescription->text() ); +// md->setSText( obj, md_sourcecode, eModule->text() ); + + if ( md->objClass(md->parent(obj)) == md_resources ) + efSort->setChecked( true ); + if( efSort->isChecked() ) md->setAttr( obj, mda_sort, "1" ); + else md->setAttr( obj, mda_sort, "0" ); + if( efPlus->isChecked() ) md->setAttr( obj, mda_plus, "1" ); + else md->setAttr( obj, mda_plus, "0" ); + if( efNZ->isChecked() ) md->setAttr( obj, mda_nz, "1" ); + else md->setAttr( obj, mda_nz, "0" ); + if( efSum->isChecked() ) + md->setAttr( obj, mda_sum, "1" ); + else + md->setAttr( obj, mda_sum, "0" ); + if(eType->currentItem()==0) + { + st.sprintf(artypes[comboBox2->currentItem()]); + } + else + { + st.sprintf( otypes[ eType->currentItem() ], eWidth->value(), eDec->value() ); + printf("type is %s\n",st.ascii()); + if ( efSort->isChecked() ) + st.append(" I"); + } + //printf("%s\n",st.ascii()); + md->setAttr( obj, mda_type, st ); +} + + +void dEditField::typeSelect( int idx ) +{ + if ( otypes[ idx ][0] == 'N' ) + { + eWidth->setMaxValue(20); + eWidth->show(); + eDec->setMaxValue(99); + eDec->show(); + tWidth->show(); + tDec->show(); + efSum->show(); + comboBox2->setEnabled(false); + } + else + { + if ( otypes[ idx ][0] == 'C' ) + { + eWidth->setMaxValue(254); + eWidth->show(); + eDec->hide(); + tWidth->show(); + tDec->hide(); + efSum->hide(); + efSum->setChecked(false); + comboBox2->setEnabled(false); + } + else + { + if( idx == 0) + { + comboBox2->setEnabled(true); + eWidth->hide(); + eDec->hide(); + tWidth->hide(); + tDec->hide(); + efSum->hide(); + efSum->setChecked(false); + } + else + { + comboBox2->setEnabled(false); + eWidth->hide(); + eDec->hide(); + tWidth->hide(); + tDec->hide(); + efSum->hide(); + efSum->setChecked(false); + // comboBox2->setEnabled(false); + } + } + } +} + + +void dEditField::nameChanged() +{ + setCaption( tr("Field:") + eName->text() ); +} + + +void dEditField::AARegSelect( int i ) +{ + +} diff --git a/src/designer/deditfield.h b/src/designer/deditfield.h new file mode 100644 index 0000000..05eed74 --- /dev/null +++ b/src/designer/deditfield.h @@ -0,0 +1,38 @@ +#ifndef DEDITFIELD_H +#define DEDITFIELD_H + +#include "ui_deditfield.h" + + +class dEditField : public Q3MainWindow, public Ui::dEditField +{ + Q_OBJECT + +public: + dEditField(QWidget* parent = 0, const char* name = 0, Qt::WindowFlags fl = Qt::WType_TopLevel); + ~dEditField(); + + QStringList otypes; + QStringList artypes; + aListViewItem *item; + aAliasEditor *al; + +public slots: + virtual void setData( aListViewItem * o ); + virtual void updateMD(); + virtual void typeSelect( int idx ); + virtual void nameChanged(); + virtual void AARegSelect( int i ); + +protected slots: + virtual void languageChange(); + +private: + QString capt; + + void destroy(); + void init(); + +}; + +#endif // DEDITFIELD_H diff --git a/src/designer/deditfield.ui b/src/designer/deditfield.ui new file mode 100644 index 0000000..94b4872 --- /dev/null +++ b/src/designer/deditfield.ui @@ -0,0 +1,355 @@ + + dEditField + + + + 0 + 0 + 521 + 403 + + + + + 521 + 343 + + + + Field + + + + + 0 + 0 + 521 + 403 + + + + + + + + 10 + + + + + Common + + + + + + + 0 + 0 + + + + Width + + + false + + + + + + + + + 1 + + + 254 + + + 10 + + + + + + + + 0 + 0 + + + + Decimals + + + false + + + + + + + + + + Qt::Vertical + + + QSizePolicy::Expanding + + + + 230 + 20 + + + + + + + + + + + 0 + 0 + + + + + 80 + 0 + + + + + 80 + 32767 + + + + Type + + + false + + + + + + + + 0 + 0 + + + + + 80 + 0 + + + + Name + + + false + + + + + + + + + + Flags + + + + + + Sort + + + + + + + Positive + + + + + + + Not null + + + + + + + Sum + + + + + + + + + + false + + + + + + + + 0 + 0 + + + + Saldo source + + + false + + + + + + + + + + + Description + + + + + + + + + + Aliases + + + + + + 0 + + + 2 + + + + Lang + + + + + Name + + + + + + + + + + + + + rcIcon + + + Q3GroupBox + QGroupBox +
Qt3Support/Q3GroupBox
+ 1 +
+ + Q3MainWindow + QWidget +
q3mainwindow.h
+ 1 +
+ + Q3Table + Q3Frame +
q3table.h
+
+ + Q3TextEdit + Q3Frame +
q3textedit.h
+
+
+ + acfg.h + mdtree.h + qseditor.h + aliaseditor.h + mainform.h + + + + + eType + activated(int) + dEditField + typeSelect(int) + + + 20 + 20 + + + 20 + 20 + + + + + eName + textChanged(QString) + dEditField + nameChanged() + + + 20 + 20 + + + 20 + 20 + + + + + comboBox2 + activated(int) + dEditField + AARegSelect(int) + + + 20 + 20 + + + 20 + 20 + + + + +
diff --git a/src/designer/deditimagecollection.cpp b/src/designer/deditimagecollection.cpp new file mode 100644 index 0000000..2ecebb0 --- /dev/null +++ b/src/designer/deditimagecollection.cpp @@ -0,0 +1,49 @@ +#include "deditimagecollection.h" + +#include +#include +#include + +#include + +/* + * Constructs a dEditImageCollection as a child of 'parent', with the + * name 'name' and widget flags set to 'f'. + * + */ +dEditImageCollection::dEditImageCollection(QWidget* parent, const char* name, Qt::WindowFlags fl) + : Q3MainWindow(parent, name, fl) +{ + setupUi(this); + + (void)statusBar(); + init(); +} + +/* + * Destroys the object and frees any allocated resources + */ +dEditImageCollection::~dEditImageCollection() +{ + // no need to delete child widgets, Qt does it all for us +} + +/* + * Sets the strings of the subwidgets using the current + * language. + */ +void dEditImageCollection::languageChange() +{ + retranslateUi(this); +} + +void dEditImageCollection::init() +{ + delete statusBar(); +} + +void dEditImageCollection::setData( ) +{ + //--obj = o; + +} diff --git a/src/designer/deditimagecollection.h b/src/designer/deditimagecollection.h new file mode 100644 index 0000000..4a58390 --- /dev/null +++ b/src/designer/deditimagecollection.h @@ -0,0 +1,28 @@ +#ifndef DEDITIMAGECOLLECTION_H +#define DEDITIMAGECOLLECTION_H + +#include "ui_deditimagecollection.h" + + +class dEditImageCollection : public Q3MainWindow, public Ui::dEditImageCollection +{ + Q_OBJECT + +public: + dEditImageCollection(QWidget* parent = 0, const char* name = 0, Qt::WindowFlags fl = Qt::WType_TopLevel); + ~dEditImageCollection(); + + aCfgItem obj; + +public slots: + virtual void setData(); + +protected slots: + virtual void languageChange(); + +private: + void init(); + +}; + +#endif // DEDITIMAGECOLLECTION_H diff --git a/src/designer/deditimagecollection.ui b/src/designer/deditimagecollection.ui new file mode 100644 index 0000000..b8c0591 --- /dev/null +++ b/src/designer/deditimagecollection.ui @@ -0,0 +1,84 @@ + + dEditImageCollection + + + + 0 + 0 + 523 + 320 + + + + Image Collection + + + + + 0 + 0 + 523 + 320 + + + + + + + + + Add + + + + + + + Rename + + + + + + + Remove + + + + + + + + + Qt::Vertical + + + QSizePolicy::Expanding + + + + 31 + 81 + + + + + + + + + rcIcon + + + Q3MainWindow + QWidget +
q3mainwindow.h
+ 1 +
+
+ + acfg.h + + + +
diff --git a/src/designer/deditireg.cpp b/src/designer/deditireg.cpp new file mode 100644 index 0000000..f36fd36 --- /dev/null +++ b/src/designer/deditireg.cpp @@ -0,0 +1,85 @@ +#include "deditireg.h" + +#include +#include +#include + +#include +#include "acfg.h" + +/* + * Constructs a dEditIReg as a child of 'parent', with the + * name 'name' and widget flags set to 'f'. + * + */ +dEditIReg::dEditIReg(QWidget* parent, const char* name, Qt::WindowFlags fl) + : Q3MainWindow(parent, name, fl) +{ + setupUi(this); + + (void)statusBar(); + init(); +} + +/* + * Destroys the object and frees any allocated resources + */ +dEditIReg::~dEditIReg() +{ + destroy(); + // no need to delete child widgets, Qt does it all for us +} + +/* + * Sets the strings of the subwidgets using the current + * language. + */ +void dEditIReg::languageChange() +{ + retranslateUi(this); +} + +void dEditIReg::init() +{ + delete statusBar(); +} + +void dEditIReg::destroy() +{ + updateMD(); + ( (MainForm*)this->topLevelWidget() )->wl->remove( this ); + ( (MainForm*)this->topLevelWidget() )->removeTab(name()); +} + +void dEditIReg::setData( aListViewItem *o ) +{ + item = o; + aCfg *md = o->md; + aCfgItem obj = o->obj; + aAliasEditor *a = new aAliasEditor( md, obj, tAliases ); + al = a; + al->setData(); + setCaption( tr("Information register:") + md->attr( obj, mda_name ) ); + eName->setText( md->attr( obj, mda_name ) ); + if(md->attr(obj, mda_no_unconduct)=="1") + { + checkBox1->setChecked(true); + } + else + { + checkBox1->setChecked(false); + } + eDescription->setText( md->sText( obj, md_description ) ); +} + +void dEditIReg::updateMD() +{ + aCfg *md = item->md; + aCfgItem obj = item->obj; + + al->updateMD(); + item->setText( 0, eName->text().stripWhiteSpace() ); + md->setAttr( obj, mda_name, eName->text().stripWhiteSpace() ); + md->setAttr( obj, mda_no_unconduct, checkBox1->isChecked()?"1":"0"); + md->setSText( obj, md_description, eDescription->text() ); +} diff --git a/src/designer/deditireg.h b/src/designer/deditireg.h new file mode 100644 index 0000000..5fe49c8 --- /dev/null +++ b/src/designer/deditireg.h @@ -0,0 +1,31 @@ +#ifndef DEDITIREG_H +#define DEDITIREG_H + +#include "ui_deditireg.h" + + +class dEditIReg : public Q3MainWindow, public Ui::dEditIReg +{ + Q_OBJECT + +public: + dEditIReg(QWidget* parent = 0, const char* name = 0, Qt::WindowFlags fl = Qt::WType_TopLevel); + ~dEditIReg(); + + aListViewItem *item; + aAliasEditor *al; + +public slots: + virtual void setData( aListViewItem * o ); + virtual void updateMD(); + +protected slots: + virtual void languageChange(); + +private: + void init(); + void destroy(); + +}; + +#endif // DEDITIREG_H diff --git a/src/designer/deditireg.ui b/src/designer/deditireg.ui new file mode 100644 index 0000000..05c2538 --- /dev/null +++ b/src/designer/deditireg.ui @@ -0,0 +1,130 @@ + + dEditIReg + + + + 0 + 0 + 447 + 314 + + + + Information register + + + + + 0 + 0 + 447 + 314 + + + + + + + + Common + + + + + + + + Name: + + + false + + + + + + + + + + + + + + + Description: + + + false + + + + + + + Don't delete record in unconduct + + + + + + + + Aliases + + + + + + 0 + + + 2 + + + + Lang + + + + + Name + + + + + + + + + + + + + rcIcon + + + Q3MainWindow + QWidget +
q3mainwindow.h
+ 1 +
+ + Q3Table + Q3Frame +
q3table.h
+
+ + Q3TextEdit + Q3Frame +
q3textedit.h
+
+
+ + mdtree.h + aliaseditor.h + mainform.h + + + +
diff --git a/src/designer/deditjournal.cpp b/src/designer/deditjournal.cpp new file mode 100644 index 0000000..75a4c71 --- /dev/null +++ b/src/designer/deditjournal.cpp @@ -0,0 +1,197 @@ +#include "deditjournal.h" + +#include +#include +#include + +#include +#include "acfg.h" + +/* + * Constructs a dEditJournal as a child of 'parent', with the + * name 'name' and widget flags set to 'f'. + * + */ +dEditJournal::dEditJournal(QWidget* parent, const char* name, Qt::WindowFlags fl) + : Q3MainWindow(parent, name, fl) +{ + setupUi(this); + + (void)statusBar(); + init(); +} + +/* + * Destroys the object and frees any allocated resources + */ +dEditJournal::~dEditJournal() +{ + destroy(); + // no need to delete child widgets, Qt does it all for us +} + +/* + * Sets the strings of the subwidgets using the current + * language. + */ +void dEditJournal::languageChange() +{ + retranslateUi(this); +} + +void dEditJournal::setData( aListViewItem *o ) +{ + item = o; + md = o->md; + obj = o->obj; + aCfgItem cobj, doc, docs; + int i, j, n; + aAliasEditor *a = new aAliasEditor( md, obj, tAliases ); + al = a; + al->setData(); + aRoleEditor *r = new aRoleEditor( md, obj, tRoles, md_journal ); + re = r; + re->setData(); + setCaption( tr("Journal:") + md->attr( obj, mda_name ) ); + eName->setText( md->attr( obj, mda_name ) ); + eDescription->setText( md->sText( obj, md_description ) ); + + i = md->attr ( obj, mda_type ).toInt(); + cbType-> setCurrentItem(i); + + journalDocs = new ananasTreeView( tabWidget18->page(2), md ); + journalDocs->setSorting( -1 ); + // TODO Fix me!!! + //--layout28->addWidget( journalDocs, 0, 0 ); + n = md->count( obj, md_used_doc ); + for ( j = 0; j < n; j++ ) + { + cobj = md->find( obj, md_used_doc, j ); + if ( cobj.isNull() ) + continue; +// did = md->text(cobj).toLong(); + doc = md->find(md->text(cobj).toLong()); + if ( doc.isNull() ) + md->remove(cobj); + else + new ananasListViewItem( journalDocs, journalDocs->lastItem(), md, doc ); + } + + allDocs = new ananasTreeView( tabWidget18->page(2), md ); + allDocs->setSorting( -1 ); + // TODO Fix me!!! + //--layout29->add( allDocs ); + docs = md->find(md->find(mdc_metadata),md_documents,0); + n = md->count( docs, md_document ); + for ( j = 0; j < n; j++ ) + { + cobj = md->find( docs, md_document, j ); + if ( cobj.isNull() ) + return; + // did = md->id(cobj); + doc = md->find(md->id(cobj)); + new ananasListViewItem( allDocs, allDocs->lastItem(), md, doc ); + } + docPage = tabWidget18->page(2); + if ( cbType->currentItem() != 1 ) + typeChange(); +} + + +void dEditJournal::init() +{ + statusBar()->hide(); +} + + +void dEditJournal::updateMD() +{ + aCfgItem doc, docs; + int i; + + al->updateMD(); + re->updateMD(); + item->setText( 0, eName->text().stripWhiteSpace() ); + md->setAttr( obj, mda_name, eName->text().stripWhiteSpace() ); + md->setSText( obj, md_description, eDescription->text() ); + md->setAttr( obj, mda_type, cbType->currentItem() ); + docs = md->find(obj,md_columns,0); + do + { + doc = md->findChild( docs, md_used_doc, 0 ); + if ( !doc.isNull() ) + md->remove( doc ); + } while ( !doc.isNull() ); + if ( cbType->currentItem() != 1 ) + return; + ananasListViewItem *aitem = (ananasListViewItem *)journalDocs->firstChild(); + for ( i = 0; i < journalDocs->childCount(); i++ ) + { + doc = md->insert( docs, md_used_doc, QString::null, -1 ); + md->setText( doc, QString( "%1" ).arg( aitem->id ) ); + aitem = (ananasListViewItem *)aitem->nextSibling(); + } + +} + +void dEditJournal::destroy() +{ + updateMD(); + ( (MainForm*)this->topLevelWidget() )->wl->remove( this ); + ( (MainForm*)this->topLevelWidget() )->removeTab(name()); +} + + + + +void dEditJournal::typeChange() +{ + if ( cbType->currentItem() != 1 ) + tabWidget18->removePage(tabWidget18->page(2)); + else + tabWidget18->insertTab(docPage,QObject::tr("Documents")); +} + + +void dEditJournal::addDoc() +{ + ananasListViewItem *cur = (ananasListViewItem *)allDocs->selectedItem(); + if (!cur) + return; + if ( md->objClass( cur->obj ) != md_document ) + return; + new ananasListViewItem(journalDocs, journalDocs->lastItem(), md, cur->obj ); +} + + +void dEditJournal::removeDoc() +{ + journalDocs->removeItem( journalDocs->selectedItem() ); +} + + +void dEditJournal::moveUp() +{ + ananasListViewItem *aitem, *after; + + aitem = (ananasListViewItem *) journalDocs->selectedItem(); + if ( aitem ) + { + after = (ananasListViewItem *)aitem->itemAbove(); + if ( after ) + after->moveItem( aitem ); + } +} + + +void dEditJournal::moveDown() +{ + ananasListViewItem *aitem, *after; + aitem = (ananasListViewItem *)journalDocs->selectedItem(); + if ( aitem ) + { + after = (ananasListViewItem *)aitem->itemBelow(); + if ( after ) + aitem->moveItem( after ); + } +} diff --git a/src/designer/deditjournal.h b/src/designer/deditjournal.h new file mode 100644 index 0000000..15c4b1a --- /dev/null +++ b/src/designer/deditjournal.h @@ -0,0 +1,44 @@ +#ifndef DEDITJOURNAL_H +#define DEDITJOURNAL_H + +#include "ui_deditjournal.h" + + +class dEditJournal : public Q3MainWindow, public Ui::dEditJournal +{ + Q_OBJECT + +public: + dEditJournal(QWidget* parent = 0, const char* name = 0, Qt::WindowFlags fl = Qt::WType_TopLevel); + ~dEditJournal(); + + aListViewItem *item; + aAliasEditor *al; + ananasTreeView * journalDocs; + ananasTreeView * allDocs; + aCfg *md; + aCfgItem obj; + QWidget * docPage; + aRoleEditor *re; + +public slots: + virtual void setData( aListViewItem * o ); + virtual void updateMD(); + +protected slots: + virtual void languageChange(); + +private: + void init(); + void destroy(); + +private slots: + virtual void typeChange(); + virtual void addDoc(); + virtual void removeDoc(); + virtual void moveUp(); + virtual void moveDown(); + +}; + +#endif // DEDITJOURNAL_H diff --git a/src/designer/deditjournal.ui b/src/designer/deditjournal.ui new file mode 100644 index 0000000..4f02d90 --- /dev/null +++ b/src/designer/deditjournal.ui @@ -0,0 +1,398 @@ + + dEditJournal + + + + 0 + 0 + 503 + 328 + + + + Journal + + + + + 0 + 0 + 503 + 328 + + + + + + + + 0 + 0 + + + + + Common + + + + + + + + Name: + + + false + + + + + + + + + + + + + + + + + Type: + + + false + + + + + + + + Common + + + + + Special + + + + + Othes + + + + + + + + + + Description: + + + false + + + + + + + + Aliases + + + + + + 0 + + + 0 + + + + + + + + Documents + + + + + + + + + + + + + Qt::Vertical + + + QSizePolicy::Expanding + + + + 20 + 40 + + + + + + + + + 0 + 0 + + + + + + + + + + + + + + + 0 + 0 + + + + + + + + + + + + + + + 0 + 0 + + + + + + + + + + + + + + + 0 + 0 + + + + + + + + + + + + + + Qt::Vertical + + + QSizePolicy::Expanding + + + + 20 + 56 + + + + + + + + + + + + + Access + + + + + + 0 + + + 2 + + + false + + + Q3Table::Multi + + + + Read + + + + + Write + + + + + + + + + + + + + Action + + + Action + + + + + Action_2 + + + Action_2 + + + + + rcIcon + + + Q3MainWindow + QWidget +
q3mainwindow.h
+ 1 +
+ + Q3Table + Q3Frame +
q3table.h
+
+ + Q3TextEdit + Q3Frame +
q3textedit.h
+
+
+ + mdtree.h + atreeitems.h + aliaseditor.h + mainform.h + roleeditor.h + + + + + cbType + activated(int) + dEditJournal + typeChange() + + + 20 + 20 + + + 20 + 20 + + + + + bAddDoc + clicked() + dEditJournal + addDoc() + + + 20 + 20 + + + 20 + 20 + + + + + bRemoveDoc + clicked() + dEditJournal + removeDoc() + + + 20 + 20 + + + 20 + 20 + + + + + bMoveUp + clicked() + dEditJournal + moveUp() + + + 20 + 20 + + + 20 + 20 + + + + + bMoveDown + clicked() + dEditJournal + moveDown() + + + 20 + 20 + + + 20 + 20 + + + + +
diff --git a/src/designer/deditlang.cpp b/src/designer/deditlang.cpp new file mode 100644 index 0000000..5d63ef3 --- /dev/null +++ b/src/designer/deditlang.cpp @@ -0,0 +1,78 @@ +#include "deditlang.h" + +#include +#include +#include + +#include "acfg.h" +#include +#include + +/* + * Constructs a dEditLang as a child of 'parent', with the + * name 'name' and widget flags set to 'f'. + * + */ +dEditLang::dEditLang(QWidget* parent, const char* name, Qt::WindowFlags fl) + : Q3MainWindow(parent, name, fl) +{ + setupUi(this); + + (void)statusBar(); + init(); +} + +/* + * Destroys the object and frees any allocated resources + */ +dEditLang::~dEditLang() +{ + destroy(); + // no need to delete child widgets, Qt does it all for us +} + +/* + * Sets the strings of the subwidgets using the current + * language. + */ +void dEditLang::languageChange() +{ + retranslateUi(this); +} + +extern aCfg cfg; + +void dEditLang::setData( CfgForm *c, aCfgItem o ) +{ +// aCfgItem alias; +// int i, n, count; + + cf = c; + obj = o; + + setCaption( tr("Language:") + cf->cfg.attr( obj, mda_name ) ); + eTag->setText( cf->cfg.attr( obj, mda_tag ) ); + eName->setText( cf->cfg.attr( obj, mda_name ) ); + eTrFile->setText( cf->cfg.attr( obj, mda_trfile ) ); +} + +void dEditLang::init() +{ + delete statusBar(); +} + +void dEditLang::destroy() +{ + updateMD(); + ( (MainForm*)this->topLevelWidget() )->removeTab(name()); +} +void +dEditLang::updateMD() +{ + cf->cfg.setAttr( obj, mda_tag, eTag->text() ); + cf->cfg.setAttr( obj, mda_name, eName->text().stripWhiteSpace() ); + cf->cfg.setAttr( obj, mda_trfile, eTrFile->text() ); + cf->initLang(); + ( (MainForm*)this->topLevelWidget() )->wl->remove( this ); +} + diff --git a/src/designer/deditlang.h b/src/designer/deditlang.h new file mode 100644 index 0000000..27c5ec2 --- /dev/null +++ b/src/designer/deditlang.h @@ -0,0 +1,32 @@ +#ifndef DEDITLANG_H +#define DEDITLANG_H + +#include "ui_deditlang.h" + + +class dEditLang : public Q3MainWindow, public Ui::dEditLang +{ + Q_OBJECT + +public: + dEditLang(QWidget* parent = 0, const char* name = 0, Qt::WindowFlags fl = Qt::WType_TopLevel); + ~dEditLang(); + +public slots: + virtual void setData( CfgForm * c, aCfgItem o ); + virtual void updateMD(); + +protected slots: + virtual void languageChange(); + +private: + aCfgItem obj; + int langCount; + CfgForm *cf; + + void init(); + void destroy(); + +}; + +#endif // DEDITLANG_H diff --git a/src/designer/deditlang.ui b/src/designer/deditlang.ui new file mode 100644 index 0000000..11e1753 --- /dev/null +++ b/src/designer/deditlang.ui @@ -0,0 +1,123 @@ + + dEditLang + + + + 0 + 0 + 299 + 185 + + + + Language + + + + + 0 + 0 + 299 + 185 + + + + + + + + Common + + + + + + + + + + Tag: + + + false + + + + + + + Name: + + + false + + + + + + + Translation file: + + + false + + + + + + + + + + + + + + + + + + + + + + + + Qt::Vertical + + + QSizePolicy::Expanding + + + + 21 + 141 + + + + + + + + + + + + + rcIcon + + + Q3MainWindow + QWidget +
q3mainwindow.h
+ 1 +
+
+ + mdtree.h + cfgform.h + mainform.h + + + +
diff --git a/src/designer/deditreport.cpp b/src/designer/deditreport.cpp new file mode 100644 index 0000000..d500557 --- /dev/null +++ b/src/designer/deditreport.cpp @@ -0,0 +1,83 @@ +#include "deditreport.h" + +#include +#include +#include + +#include +#include "acfg.h" +#include +#include + +/* + * Constructs a dEditReport as a child of 'parent', with the + * name 'name' and widget flags set to 'f'. + * + */ +dEditReport::dEditReport(QWidget* parent, const char* name, Qt::WindowFlags fl) + : Q3MainWindow(parent, name, fl) +{ + setupUi(this); + + (void)statusBar(); + init(); +} + +/* + * Destroys the object and frees any allocated resources + */ +dEditReport::~dEditReport() +{ + destroy(); + // no need to delete child widgets, Qt does it all for us +} + +/* + * Sets the strings of the subwidgets using the current + * language. + */ +void dEditReport::languageChange() +{ + retranslateUi(this); +} + +void dEditReport::setData( aListViewItem *o ) +{ + item = o; + aCfg *md = o->md; + aCfgItem obj = o->obj; + aAliasEditor *a = new aAliasEditor( md, obj, tAliases ); + al = a; + al->setData(); + setCaption( tr("Report:") + md->attr( obj, mda_name ) ); + eName->setText( md->attr( obj, mda_name ) ); + eDescription->setText( md->sText( obj, md_description ) ); + eModule->setText( md->sText( obj, md_sourcecode ) ); +} + + +void dEditReport::init() +{ + delete statusBar(); + eModule->setInterpreter(new QSInterpreter()); +} + + +void dEditReport::updateMD() +{ + aCfg *md = item->md; + aCfgItem obj = item->obj; + + al->updateMD(); + item->setText( 0, eName->text().stripWhiteSpace() ); + md->setAttr( obj, mda_name, eName->text().stripWhiteSpace() ); + md->setSText( obj, md_description, eDescription->text() ); + md->setSText( obj, md_sourcecode, eModule->text() ); +} + +void dEditReport::destroy() +{ + updateMD(); + ( (MainForm*)this->topLevelWidget() )->wl->remove( this ); + ( (MainForm*)this->topLevelWidget() )->removeTab(name()); +} diff --git a/src/designer/deditreport.h b/src/designer/deditreport.h new file mode 100644 index 0000000..e4a5103 --- /dev/null +++ b/src/designer/deditreport.h @@ -0,0 +1,31 @@ +#ifndef DEDITREPORT_H +#define DEDITREPORT_H + +#include "ui_deditreport.h" + + +class dEditReport : public Q3MainWindow, public Ui::dEditReport +{ + Q_OBJECT + +public: + dEditReport(QWidget* parent = 0, const char* name = 0, Qt::WindowFlags fl = Qt::WType_TopLevel); + ~dEditReport(); + + aListViewItem *item; + aAliasEditor *al; + +public slots: + virtual void setData( aListViewItem * o ); + virtual void updateMD(); + +protected slots: + virtual void languageChange(); + + virtual void init(); + virtual void destroy(); + + +}; + +#endif // DEDITREPORT_H diff --git a/src/designer/deditreport.ui b/src/designer/deditreport.ui new file mode 100644 index 0000000..646975f --- /dev/null +++ b/src/designer/deditreport.ui @@ -0,0 +1,142 @@ + + dEditReport + + + + 0 + 0 + 447 + 313 + + + + Report + + + + + 0 + 0 + 447 + 313 + + + + + + + + + + + Common + + + + + + + + Name: + + + false + + + + + + + + + + + + Description: + + + false + + + + + + + + + + + Module + + + + + + + + + + Aliases + + + + + + 0 + + + 2 + + + + Lang + + + + + Name + + + + + + + + + + + + + rcIcon + + + Q3MainWindow + QWidget +
q3mainwindow.h
+ 1 +
+ + Q3Table + Q3Frame +
q3table.h
+
+ + Q3TextEdit + Q3Frame +
q3textedit.h
+
+ + QSEditor + QWidget +
qseditor.h
+
+
+ + mdtree.h + aliaseditor.h + mainform.h + qseditor.h + + + +
diff --git a/src/designer/deditrole.cpp b/src/designer/deditrole.cpp new file mode 100644 index 0000000..6c350e9 --- /dev/null +++ b/src/designer/deditrole.cpp @@ -0,0 +1,76 @@ +#include "deditrole.h" + +#include +#include +#include + +#include "acfg.h" +#include +#include + +/* + * Constructs a dEditRole as a child of 'parent', with the + * name 'name' and widget flags set to 'f'. + * + */ +dEditRole::dEditRole(QWidget* parent, const char* name, Qt::WindowFlags fl) + : Q3MainWindow(parent, name, fl) +{ + setupUi(this); + + (void)statusBar(); + init(); +} + +/* + * Destroys the object and frees any allocated resources + */ +dEditRole::~dEditRole() +{ + destroy(); + // no need to delete child widgets, Qt does it all for us +} + +/* + * Sets the strings of the subwidgets using the current + * language. + */ +void dEditRole::languageChange() +{ + retranslateUi(this); +} + +extern aCfg cfg; + +void dEditRole::setData( CfgForm *c, aCfgItem o ) +{ +// aCfgItem alias; +// int i, n, count; + + cf = c; + obj = o; + + setCaption( tr("Role:") + cf->cfg.attr( obj, mda_name ) ); + eName->setText( cf->cfg.attr( obj, mda_name ) ); + eDescription->setText( cf->cfg.sText( obj, md_description ) ); +} + +void dEditRole::init() +{ + delete statusBar(); +} + +void dEditRole::destroy() +{ + updateMD(); + ( (MainForm*)this->topLevelWidget() )->removeTab(name()); +} +void +dEditRole::updateMD() +{ + cf->cfg.setAttr( obj, mda_name, eName->text().stripWhiteSpace() ); + cf->cfg.setSText( obj, md_description, eDescription->text() ); + cf->initRoles(); + ( (MainForm*)this->topLevelWidget() )->wl->remove( this ); +} + diff --git a/src/designer/deditrole.h b/src/designer/deditrole.h new file mode 100644 index 0000000..50d2c7e --- /dev/null +++ b/src/designer/deditrole.h @@ -0,0 +1,32 @@ +#ifndef DEDITROLE_H +#define DEDITROLE_H + +#include "ui_deditrole.h" + + +class dEditRole : public Q3MainWindow, public Ui::dEditRole +{ + Q_OBJECT + +public: + dEditRole(QWidget* parent = 0, const char* name = 0, Qt::WindowFlags fl = Qt::WType_TopLevel); + ~dEditRole(); + +public slots: + virtual void setData( CfgForm * c, aCfgItem o ); + virtual void updateMD(); + +protected slots: + virtual void languageChange(); + +private: + aCfgItem obj; + CfgForm *cf; + int roleCount; + + void init(); + void destroy(); + +}; + +#endif // DEDITROLE_H diff --git a/src/designer/deditrole.ui b/src/designer/deditrole.ui new file mode 100644 index 0000000..0c53f93 --- /dev/null +++ b/src/designer/deditrole.ui @@ -0,0 +1,91 @@ + + dEditRole + + + + 0 + 0 + 365 + 198 + + + + Role + + + + + 0 + 0 + 365 + 198 + + + + + + + + Common + + + + + + Description: + + + false + + + + + + + + + Name: + + + false + + + + + + + + + + + + + + + + + + + + rcIcon + + + Q3MainWindow + QWidget +
q3mainwindow.h
+ 1 +
+ + Q3TextEdit + Q3Frame +
q3textedit.h
+
+
+ + mdtree.h + cfgform.h + mainform.h + + + +
diff --git a/src/designer/dedittoolbar.cpp b/src/designer/dedittoolbar.cpp new file mode 100644 index 0000000..7fe2e26 --- /dev/null +++ b/src/designer/dedittoolbar.cpp @@ -0,0 +1,228 @@ +#include "dedittoolbar.h" + +#include +#include +#include + +#include +#include +//Added by qt3to4: +#include +#include "acfg.h" + +//extern aCfg cfg; + +/* + * Constructs a dEditToolbar as a child of 'parent', with the + * name 'name' and widget flags set to 'f'. + * + */ +dEditToolbar::dEditToolbar(QWidget* parent, const char* name, Qt::WindowFlags fl) + : Q3MainWindow(parent, name, fl) +{ + setupUi(this); + + (void)statusBar(); + init(); +} + +/* + * Destroys the object and frees any allocated resources + */ +dEditToolbar::~dEditToolbar() +{ + destroy(); + // no need to delete child widgets, Qt does it all for us +} + +/* + * Sets the strings of the subwidgets using the current + * language. + */ +void dEditToolbar::languageChange() +{ + retranslateUi(this); +} + +void dEditToolbar::updateMD() +{ + int i; + aCfgItem com_action, apix; + al->updateMD( ); + QPixmap pix; + + item->setText( 0, eName->text().stripWhiteSpace() ); + md->setAttr( obj, mda_name, eName->text().stripWhiteSpace() ); + md->setSText( obj, md_description, eDescription->text() ); +// md->setSText( obj, md_menutext, eMenuText->text() ); + + QString sKey = ""; + if ( cbKey-> currentText () != "" ) + { + if ( cbCTRL->isChecked() ) + sKey += md_km_ctrl; + if ( cbALT->isChecked() ) + sKey += md_km_alt; + if ( cbShift->isChecked() ) + sKey += md_km_shift; + sKey += cbKey->currentText (); + } + md->setSText( obj, md_key, sKey ); + + do + { + com_action = md->findChild( obj, md_comaction, 0 ); + if ( !com_action.isNull() ) + md->remove( com_action ); + } while ( !com_action.isNull() ); + ananasListViewItem *aitem = (ananasListViewItem *)vComActions->firstChild(); + for ( i = 0; i < vComActions->childCount(); i++ ) + { + com_action = md->insert( obj, md_comaction, QString::null, -1 ); + md->setText( com_action, QString( "%1" ).arg( aitem->id ) ); + aitem = (ananasListViewItem *)aitem->nextSibling(); + } + aitem = (ananasListViewItem *)vComActions->firstChild(); + apix = md->findChild( md->find( aitem->id ), md_active_picture, 0 ); + if ( apix.isNull() ) + return; + pix.loadFromData( md->binary( apix ) ); + item->setPixmap( 0, pix ); +} + +void dEditToolbar::destroy() +{ + updateMD(); + ( (MainForm*)this->topLevelWidget() )->wl->remove( this ); + ( (MainForm*)this->topLevelWidget() )->removeTab(name()); +} + +void dEditToolbar::init() +{ + statusBar()->hide(); +} + +void dEditToolbar::setData( InterfaceListViewItem * o ) +{ + int i, j, n, k, id; + item = o; + md = o->md; + obj = o->obj; + aCfgItem com_action, apix; + aAliasEditor *a = new aAliasEditor( md, obj, tAliases ); + QPixmap pix; + + vComActions = new ananasTreeView( tabWidget2->page(1), md ); + vComActions->setSorting( -1 ); + // TODO Fix me!!! + //--layout28->addWidget( vComActions, 0, 0 ); + actiontree = new aActionTreeView ( tabWidget2->page(1), md ); + disconnect( actiontree, SIGNAL( contextMenuRequested( Q3ListViewItem*, const QPoint&, int) ), actiontree, SLOT(ContextMenu() ) ); + disconnect( actiontree, SIGNAL( returnPressed( Q3ListViewItem*) ), actiontree, SLOT( itemEdit() ) ); + disconnect( actiontree, SIGNAL( doubleClicked( Q3ListViewItem*) ), actiontree, SLOT( itemEdit() ) ); + // TODO Fix me!!! + //--layout29->addWidget( actiontree, 0, 0 ); + + al = a; + al->setData(); + + setCaption( tr("Command:") + md->attr( obj, mda_name ) ); + eName->setText( md->attr( obj, mda_name ) ); +// eMenuText->setText( md->sText( obj, md_menutext ) ); + eDescription->setText( md->sText( obj, md_description ) ); + + QString sKey = md->sText( obj, md_key ); + if ( ( sKey.find (md_km_ctrl) ) >= 0 ) + { + cbCTRL->setChecked ( TRUE ); + sKey.remove(md_km_ctrl); + } + if ( ( sKey.find (md_km_alt) ) >= 0 ) + { + cbALT->setChecked ( TRUE ); + sKey.remove(md_km_alt); + } + if ( ( sKey.find (md_km_shift) ) >= 0 ) + { + cbShift->setChecked ( TRUE ); + sKey.remove(md_km_shift); + } + + + n = cbKey->count(); + for ( i = 0; i < n; i++ ) + if ( sKey == cbKey->text( i ) ) + { + cbKey->setCurrentItem( i ); + break; + } + n = md->countChild( obj, md_comaction ); + k = md->count( md->find ( mdc_actions ), md_action ); + ananasListViewItem *aitem; + for ( i = 0; i < n; i++ ) + { + id = md->text(( md->find (obj, md_comaction, i))).toInt(); + for ( j = 0; j < k; j++) + { + com_action = md->find ( md->find( mdc_actions ), md_action, j ); + if ( md->id(com_action) == id ) + { + aitem = new ananasListViewItem (vComActions, vComActions->lastItem(), md, com_action); + aitem->setRenameEnabled( 0, FALSE ); + apix = md->findChild( md->find( aitem->id ), md_active_picture, 0 ); + if ( apix.isNull() ) + break; + pix.loadFromData( md->binary( apix ) ); + aitem->setPixmap( 0, pix ); + } + } + } +} + + +void +dEditToolbar::bAddAction_clicked() +{ + aCfgItem apix; + QPixmap pix; + + ananasListViewItem *cur = (ananasListViewItem *)actiontree->selectedItem(); + if (!cur) + return; + if ( md->objClass( cur->obj ) != md_action ) + return; + ananasListViewItem *aitem = new ananasListViewItem(vComActions, vComActions->lastItem(), md, cur->obj ); + apix = md->findChild( md->find( aitem->id ), md_active_picture, 0 ); + pix.loadFromData( md->binary( apix ) ); + aitem->setPixmap( 0, pix ); +} + + +void dEditToolbar::bRemoveAction_clicked() +{ + vComActions->removeItem( vComActions->selectedItem() ); +} + + +void dEditToolbar::bMoveUp_clicked() +{ + ananasListViewItem *aitem, *after; + + aitem = (ananasListViewItem *) vComActions->selectedItem(); + if ( aitem ) { + after = (ananasListViewItem *)aitem->itemAbove(); + if ( after ) after->moveItem( aitem ); + } + +} + + +void dEditToolbar::bMoveDown_clicked() +{ + ananasListViewItem *aitem, *after; + aitem = (ananasListViewItem *)vComActions->selectedItem(); + if ( aitem ) { + after = (ananasListViewItem *)aitem->itemBelow(); + if ( after ) aitem->moveItem( after ); + } +} diff --git a/src/designer/dedittoolbar.h b/src/designer/dedittoolbar.h new file mode 100644 index 0000000..fb65eab --- /dev/null +++ b/src/designer/dedittoolbar.h @@ -0,0 +1,39 @@ +#ifndef DEDITTOOLBAR_H +#define DEDITTOOLBAR_H + +#include "ui_dedittoolbar.h" + + +class dEditToolbar : public Q3MainWindow, public Ui::dEditToolbar +{ + Q_OBJECT + +public: + dEditToolbar(QWidget* parent = 0, const char* name = 0, Qt::WindowFlags fl = Qt::WType_TopLevel); + ~dEditToolbar(); + + ananasTreeView *vComActions; + aAliasEditor *al; + InterfaceListViewItem *item; + aActionTreeView *actiontree; + aCfg *md; + aCfgItem obj; + +public slots: + virtual void updateMD(); + virtual void setData( InterfaceListViewItem * o ); + virtual void bAddAction_clicked(); + virtual void bRemoveAction_clicked(); + virtual void bMoveUp_clicked(); + virtual void bMoveDown_clicked(); + +protected slots: + virtual void languageChange(); + +private: + void destroy(); + void init(); + +}; + +#endif // DEDITTOOLBAR_H diff --git a/src/designer/dedittoolbar.ui b/src/designer/dedittoolbar.ui new file mode 100644 index 0000000..5726b59 --- /dev/null +++ b/src/designer/dedittoolbar.ui @@ -0,0 +1,503 @@ + + dEditToolbar + + + + 0 + 0 + 570 + 321 + + + + Form1 + + + + + 0 + 0 + 570 + 321 + + + + + + + + + + QTabWidget::Rounded + + + + Common + + + + + + + + Description: + + + false + + + + + + + + + + + + + + Hot Key: + + + false + + + + + + + Ctrl + + + + + + + Alt + + + + + + + Shift + + + + + + + + + + + + + 1 + + + + + 2 + + + + + 3 + + + + + 4 + + + + + 5 + + + + + 6 + + + + + 7 + + + + + 8 + + + + + 9 + + + + + 0 + + + + + A + + + + + B + + + + + C + + + + + D + + + + + E + + + + + F + + + + + G + + + + + H + + + + + I + + + + + J + + + + + K + + + + + L + + + + + M + + + + + N + + + + + O + + + + + P + + + + + Q + + + + + R + + + + + S + + + + + T + + + + + U + + + + + V + + + + + W + + + + + X + + + + + Y + + + + + Z + + + + + + + + Qt::Vertical + + + QSizePolicy::Expanding + + + + 71 + 20 + + + + + + + + + + + + Type: + + + false + + + + + + + + + + Qt::Vertical + + + QSizePolicy::Expanding + + + + 51 + 20 + + + + + + + + Name: + + + false + + + + + + + true + + + + 0 + 22 + + + + + + + + + + + Actions + + + + + + + + + + + + + Qt::Vertical + + + QSizePolicy::Expanding + + + + 20 + 44 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Qt::Vertical + + + QSizePolicy::Expanding + + + + 21 + 44 + + + + + + + + + + + + + Aliases + + + + + + 0 + + + 2 + + + + Lang + + + + + Name + + + + + + + + + + + + + rcIcon + + + Q3MainWindow + QWidget +
q3mainwindow.h
+ 1 +
+ + Q3Table + Q3Frame +
q3table.h
+
+ + Q3TextEdit + Q3Frame +
q3textedit.h
+
+
+ + actiontree.h + interfacetree.h + aliaseditor.h + mainform.h + + + +
diff --git a/src/designer/deditwebform.cpp b/src/designer/deditwebform.cpp new file mode 100644 index 0000000..5339192 --- /dev/null +++ b/src/designer/deditwebform.cpp @@ -0,0 +1,89 @@ +#include "deditwebform.h" + +#include +#include +#include + +#include +#include "acfg.h" +#include +#include + +/* + * Constructs a dEditWebForm as a child of 'parent', with the + * name 'name' and widget flags set to 'f'. + * + */ +dEditWebForm::dEditWebForm(QWidget* parent, const char* name, Qt::WindowFlags fl) + : Q3MainWindow(parent, name, fl) +{ + setupUi(this); + + (void)statusBar(); + init(); +} + +/* + * Destroys the object and frees any allocated resources + */ +dEditWebForm::~dEditWebForm() +{ + destroy(); + // no need to delete child widgets, Qt does it all for us +} + +/* + * Sets the strings of the subwidgets using the current + * language. + */ +void dEditWebForm::languageChange() +{ + retranslateUi(this); +} + +void dEditWebForm::init() +{ + delete statusBar(); + eServerModule->setInterpreter(new QSInterpreter()); + eClientModule->setInterpreter(new QSInterpreter()); +} + +void dEditWebForm::destroy() +{ + updateMD(); + ( (MainForm*)this->topLevelWidget() )->wl->remove( this ); + ( (MainForm*)this->topLevelWidget() )->removeTab(name()); + item->editor = 0; +} + + +void dEditWebForm::setData( aListViewItem *o ) +{ + item = o; + aCfg *md = o->md; + aCfgItem obj = o->obj; + + aAliasEditor *a = new aAliasEditor( md, obj, tAliases ); + al = a; + al->setData(); + setCaption( tr("Web form:") + md->attr( obj, mda_name ) ); + eName->setText( md->attr( obj, mda_name ) ); + eDescription->setText( md->sText( obj, md_description ) ); + eServerModule->setText( md->sText( obj, md_servermodule ) ); + eClientModule->setText( md->sText( obj, md_clientmodule ) ); + eFormSource->setText( md->sText( obj, md_formsource ) ); +} + +void dEditWebForm::updateMD() +{ + aCfg *md = item->md; + aCfgItem obj = item->obj; + + al->updateMD( ); + item->setText( 0, eName->text().stripWhiteSpace() ); + md->setAttr( obj, mda_name, eName->text().stripWhiteSpace() ); + md->setSText( obj, md_description, eDescription->text() ); + md->setSText( obj, md_servermodule, eServerModule->text() ); + md->setSText( obj, md_clientmodule, eClientModule->text() ); + md->setSText( obj, md_formsource, eFormSource->text() ); +} diff --git a/src/designer/deditwebform.h b/src/designer/deditwebform.h new file mode 100644 index 0000000..7a3000e --- /dev/null +++ b/src/designer/deditwebform.h @@ -0,0 +1,31 @@ +#ifndef DEDITWEBFORM_H +#define DEDITWEBFORM_H + +#include "ui_deditwebform.h" + + +class dEditWebForm : public Q3MainWindow, public Ui::dEditWebForm +{ + Q_OBJECT + +public: + dEditWebForm(QWidget* parent = 0, const char* name = 0, Qt::WindowFlags fl = Qt::WType_TopLevel); + ~dEditWebForm(); + + aAliasEditor *al; + aListViewItem *item; + +public slots: + virtual void setData( aListViewItem * o ); + virtual void updateMD(); + +protected slots: + virtual void languageChange(); + +private: + void init(); + void destroy(); + +}; + +#endif // DEDITWEBFORM_H diff --git a/src/designer/deditwebform.ui b/src/designer/deditwebform.ui new file mode 100644 index 0000000..b95aaaa --- /dev/null +++ b/src/designer/deditwebform.ui @@ -0,0 +1,154 @@ + + dEditWebForm + + + + 0 + 0 + 445 + 328 + + + + Web Form + + + + + 0 + 0 + 445 + 328 + + + + + + + + Common + + + + + + Description + + + false + + + + + + + + + + + + Name: + + + false + + + + + + + + + + + + + Form editor + + + + + + Qt::PlainText + + + + + + + + Client module + + + + + + + + + + Server module + + + + + + + + + + Aliases + + + + + + 0 + + + 0 + + + + + + + + + + + + rcIcon + + + Q3MainWindow + QWidget +
q3mainwindow.h
+ 1 +
+ + Q3Table + Q3Frame +
q3table.h
+
+ + Q3TextEdit + Q3Frame +
q3textedit.h
+
+ + QSEditor + QWidget +
qseditor.h
+
+
+ + aliaseditor.h + mdtree.h + mainform.h + qseditor.h + qseditor.h + + + +
diff --git a/src/designer/designer.pro b/src/designer/designer.pro new file mode 100644 index 0000000..ca9006f --- /dev/null +++ b/src/designer/designer.pro @@ -0,0 +1,182 @@ +include(../plugins/plugins.pri) +include(../lib/lib.pri) +TARGET = ananas4-designer +TEMPLATE = app + +CONFIG += designer + +DESTDIR = ../../bin + +INCLUDEPATH += . ./formdesigner ../lib ../../tmp/ui/ananas ../plugins +LIBS += -L../../lib -lananas4 -L../../lib/designer -lananasplugin4 -lqt4-qdataschema +unix { + #LIBS += -L$(QTINC)/QtDesigner + LIBS += -lQtDesignerComponents +# LIBS += -lqt4designer +} +win32{ + LIBS += -lQtDesignerComponents4 +} + +MOC_DIR = ../../tmp/moc/$$TARGET +OBJECTS_DIR = ../../tmp/obj/$$TARGET +UI_DIR = ../../tmp/ui/$$TARGET + +#LIBS += -L../lib -L../plugins -lananas -lananasplugin -lqsa -ldesignercore -lqassistantclient +#LIBS += -L. -L../lib -L../plugins -lananas -lananasplugin -lqsa -lformdesigner -lqassistantclient +#INCLUDEPATH += ../lib ../lib/tmp/ui ../lib/.ui $(QTDIR)/tools/designer/designer ../../qt-headers/tools/designer/designer /usr/lib +#INCLUDEPATH += ../lib ../lib/tmp/ui ../lib/.ui ./formdesigner /usr/lib + +include ( ../ananas.pri ) +load(qsa) + +HEADERS = \ + actiontree.h \ + aliaseditor.h \ + atreeitems.h \ + cfgform.h \ +# cfgform.ui.h \ + deditaction.h \ +# deditaction.ui.h \ + deditareg.h \ +# deditareg.ui.h \ + deditcat.h \ +# deditcat.ui.h \ + deditcfg.h \ +# deditcfg.ui.h \ + deditcolumns.h \ +# deditcolumns.ui.h \ + deditcommand.h \ +# deditcommand.ui.h \ + deditdialog.h \ +# deditdialog.ui.h \ + deditdoc.h \ +# deditdoc.ui.h \ + deditfield.h \ +# deditfield.ui.h \ + deditimagecollection.h \ +# deditimagecollection.ui.h \ + deditireg.h \ +# deditireg.ui.h \ + deditjournal.h \ +# deditjournal.ui.h \ + deditlang.h \ +# deditlang.ui.h \ + deditreport.h \ +# deditreport.ui.h \ + deditrole.h \ +# deditrole.ui.h \ + dedittoolbar.h \ +# dedittoolbar.ui.h \ + deditwebform.h \ +# deditwebform.ui.h \ + formdesigner.h \ + interfacetree.h \ + mainform.h \ +# mainform.ui.h \ + mdtree.h \ + pixmappreview.h \ + roleeditor.h \ + formdesigner/formwindowsettings.h \ + formdesigner/newform.h \ + formdesigner/plugindialog.h \ + formdesigner/qdesigner_actioneditor.h \ + formdesigner/qdesigner_actions.h \ + formdesigner/qdesigner_formwindow.h \ + formdesigner/qdesigner_objectinspector.h \ + formdesigner/qdesigner_pch.h \ + formdesigner/qdesigner_propertyeditor.h \ + formdesigner/qdesigner_resourceeditor.h \ + formdesigner/qdesigner_settings.h \ + formdesigner/qdesigner_signalsloteditor.h \ + formdesigner/qdesigner_toolwindow.h \ + formdesigner/qdesigner_widgetbox.h \ + formdesigner/qdesigner_workbench.h \ + formdesigner/saveformastemplate.h + +SOURCES = \ + actiontree.cpp \ + aliaseditor.cpp \ + atreeitems.cpp \ + cfgform.cpp \ + deditaction.cpp \ + deditareg.cpp \ + deditcat.cpp \ + deditcfg.cpp \ + deditcolumns.cpp \ + deditcommand.cpp \ + deditdialog.cpp \ + deditdoc.cpp \ + deditfield.cpp \ + deditimagecollection.cpp \ + deditireg.cpp \ + deditjournal.cpp \ + deditlang.cpp \ + deditreport.cpp \ + deditrole.cpp \ + dedittoolbar.cpp \ + deditwebform.cpp \ + formdesigner.cpp \ + interfacetree.cpp \ + main.cpp \ + mainform.cpp \ + mdtree.cpp \ + roleeditor.cpp \ + formdesigner/formwindowsettings.cpp \ + formdesigner/newform.cpp \ + formdesigner/plugindialog.cpp \ + formdesigner/qdesigner_actioneditor.cpp \ + formdesigner/qdesigner_actions.cpp \ + formdesigner/qdesigner_formwindow.cpp \ + formdesigner/qdesigner_objectinspector.cpp \ + formdesigner/qdesigner_propertyeditor.cpp \ + formdesigner/qdesigner_resourceeditor.cpp \ + formdesigner/qdesigner_settings.cpp \ + formdesigner/qdesigner_signalsloteditor.cpp \ + formdesigner/qdesigner_toolwindow.cpp \ + formdesigner/qdesigner_widgetbox.cpp \ + formdesigner/qdesigner_workbench.cpp \ + formdesigner/saveformastemplate.cpp + +FORMS = \ + cfgform.ui \ + deditaction.ui \ + deditareg.ui \ + deditcat.ui \ + deditcfg.ui \ + deditcolumns.ui \ + deditcommand.ui \ + deditdialog.ui \ + deditdoc.ui \ + deditfield.ui \ + deditimagecollection.ui \ + deditireg.ui \ + deditjournal.ui \ + deditlang.ui \ + deditreport.ui \ + deditrole.ui \ + dedittoolbar.ui \ + deditwebform.ui \ + mainform.ui \ + formdesigner/formwindowsettings.ui \ + formdesigner/newform.ui \ + formdesigner/plugindialog.ui \ + formdesigner/saveformastemplate.ui + +RESOURCES = \ + designer.qrc +# formdesigner/designer.qrc + +TRANSLATIONS = \ + ../../translations/ananas-designer-en.ts \ + ../../translations/ananas-designer-ru.ts + +unix { + adesigner.path = $(BINDIR) + adesigner.files = ananas-designer +# acfg.path = /etc/ananas +# acfg.files= testwrite.cfg + } + +#INSTALLS += adesigner + diff --git a/src/designer/designer.qrc b/src/designer/designer.qrc new file mode 100644 index 0000000..665da14 --- /dev/null +++ b/src/designer/designer.qrc @@ -0,0 +1,82 @@ + + + images/a-system.png + images/action_g.png + images/actions.png + images/arrow_down.png + images/arrow_left.png + images/arrow_right.png + images/arrow_up.png + images/cat.png + images/cat_g.png + images/columns.png + images/d_editdelete.png + images/designer-splash-en.png + images/designer-splash-ru.png + images/dimensions.png + images/doc.png + images/doc_g.png + images/doc_h.png + images/editcopy.png + images/editcut.png + images/editdelete.png + images/editedit.png + images/editpaste.png + images/editrename.png + images/editsep.png + images/element.png + images/field.png + images/filenew.png + images/fileopen.png + images/filesave.png + images/form.png + images/form_g.png + images/function.png + images/group.png + images/help.png + images/hi22-action-project_open.png + images/hi22-action-run.png + images/information.png + images/journ.png + images/journ_g.png + images/m_menu.png + images/msg_error.png + images/msg_fatal.png + images/msg_info.png + images/msg_warning.png + images/object.png + images/p_menus.png + images/play.png + images/playprev.png + images/print.png + images/project.png + images/qsa.png + images/redo.png + images/reg.png + images/reg_g.png + images/regs.png + images/regs_g.png + images/report.png + images/report_g.png + images/resourses.png + images/script.png + images/scriptnew.png + images/scriptobject.png + images/searchfind.png + images/separator.png + images/submenu.png + images/table.png + images/table_g.png + images/toolbar.png + images/undo.png + images/webform.png + images/webform_g.png + + + templates/inputform.tpl + templates/inputformcat.tpl + templates/inputformdoc.tpl + templates/inputformjourn.tpl + templates/inputformrep.tpl + + diff --git a/src/designer/embed.cpp b/src/designer/embed.cpp new file mode 100644 index 0000000..b5f7cd1 --- /dev/null +++ b/src/designer/embed.cpp @@ -0,0 +1,312 @@ +/********************************************************************** +** Copyright (C) 2000-2003 Trolltech AS. All rights reserved. +** +** This file is part of Qt Designer. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition +** licenses may use this file in accordance with the Qt Commercial License +** Agreement provided with the Software. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for +** information about Qt Commercial License Agreements. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#include "uic.h" +#include +#include +#include +#include +#include +//Added by qt3to4: +#include +#include +#include + +// on embedded, we do not compress image data. Rationale: by mapping +// the ready-only data directly into memory we are both faster and +// more memory efficient +#if defined(Q_WS_QWS) && !defined(QT_NO_IMAGE_COLLECTION_COMPRESSION) +#define QT_NO_IMAGE_COLLECTION_COMPRESSION +#endif + +struct EmbedImage +{ + ~EmbedImage() { delete[] colorTable; } + int width, height, depth; + int numColors; + QRgb* colorTable; + QString name; + QString cname; + bool alpha; +#ifndef QT_NO_IMAGE_COLLECTION_COMPRESSION + ulong compressed; +#endif +}; + +static QString convertToCIdentifier( const char *s ) +{ + QString r = s; + int len = r.length(); + if ( len > 0 && !isalpha( (char)r[0].latin1() ) ) + r[0] = '_'; + for ( int i=1; i> 4) & 15]; + s += hexdigits[v & 15]; + if ( i < (int)len-1 ) + s += ','; + } + if ( s.length() ) + out << (const char*)s; + return len; +} + +static void embedData( Q3TextStream& out, const QRgb* input, int n ) +{ + out << hex; + const QRgb *v = input; + for ( int i=0; i\n"; + out << "#include \n"; + out << "#include \n"; + out << "#include \n"; + out << "\n"; + + Q3PtrList list_image; + list_image.setAutoDelete( TRUE ); + int image_count = 0; + for ( it = images.begin(); it != images.end(); ++it ) { + QImage img; + if ( !img.load( *it ) ) { + fprintf( stderr, "uic: cannot load image file %s\n", (*it).latin1() ); + continue; + } + EmbedImage *e = new EmbedImage; + e->width = img.width(); + e->height = img.height(); + e->depth = img.depth(); + e->numColors = img.numColors(); + e->colorTable = new QRgb[e->numColors]; + e->alpha = img.hasAlphaBuffer(); + memcpy(e->colorTable, img.colorTable(), e->numColors*sizeof(QRgb)); + QFileInfo fi( *it ); + e->name = fi.fileName(); + e->cname = QString("image_%1").arg( image_count++); + list_image.append( e ); + out << "// " << *it << "\n"; + QString s; + if ( e->depth == 1 ) + img = img.convertBitOrder(QImage::BigEndian); + out << s.sprintf( "static const unsigned char %s_data[] = {", + (const char *)e->cname ); +#ifndef QT_NO_IMAGE_COLLECTION_COMPRESSION + e->compressed = +#endif + embedData( out, img.bits(), img.numBytes() ); + out << "\n};\n\n"; + if ( e->numColors ) { + out << s.sprintf( "static const QRgb %s_ctable[] = {", + (const char *)e->cname ); + embedData( out, e->colorTable, e->numColors ); + out << "\n};\n\n"; + } + } + + if ( !list_image.isEmpty() ) { + out << "static struct EmbedImage {\n" + " int width, height, depth;\n" + " const unsigned char *data;\n" +#ifndef QT_NO_IMAGE_COLLECTION_COMPRESSION + " ulong compressed;\n" +#endif + " int numColors;\n" + " const QRgb *colorTable;\n" + " bool alpha;\n" + " const char *name;\n" + "} embed_image_vec[] = {\n"; + EmbedImage *e = list_image.first(); + while ( e ) { + out << " { " + << e->width << ", " + << e->height << ", " + << e->depth << ", " + << "(const unsigned char*)" << e->cname << "_data, " +#ifndef QT_NO_IMAGE_COLLECTION_COMPRESSION + << e->compressed << ", " +#endif + << e->numColors << ", "; + if ( e->numColors ) + out << e->cname << "_ctable, "; + else + out << "0, "; + if ( e->alpha ) + out << "TRUE, "; + else + out << "FALSE, "; + out << "\"" << e->name << "\" },\n"; + e = list_image.next(); + } +#ifndef QT_NO_IMAGE_COLLECTION_COMPRESSION + out << " { 0, 0, 0, 0, 0, 0, 0, 0, 0 }\n};\n"; +#else + out << " { 0, 0, 0, 0, 0, 0, 0, 0 }\n};\n"; +#endif + + out << "\n" + "static QImage uic_findImage( const QString& name )\n" + "{\n" + " for ( int i=0; embed_image_vec[i].data; i++ ) {\n" + " if ( QString::fromUtf8(embed_image_vec[i].name) == name ) {\n" +#ifndef QT_NO_IMAGE_COLLECTION_COMPRESSION + " QByteArray baunzip;\n" + " baunzip = qUncompress( embed_image_vec[i].data, \n" + " embed_image_vec[i].compressed );\n" + " QImage img((uchar*)baunzip.data(),\n" + " embed_image_vec[i].width,\n" + " embed_image_vec[i].height,\n" + " embed_image_vec[i].depth,\n" + " (QRgb*)embed_image_vec[i].colorTable,\n" + " embed_image_vec[i].numColors,\n" + " QImage::BigEndian\n" + " );\n" + " img = img.copy();\n" +#else + " QImage img((uchar*)embed_image_vec[i].data,\n" + " embed_image_vec[i].width,\n" + " embed_image_vec[i].height,\n" + " embed_image_vec[i].depth,\n" + " (QRgb*)embed_image_vec[i].colorTable,\n" + " embed_image_vec[i].numColors,\n" + " QImage::BigEndian\n" + " );\n" +#endif + " if ( embed_image_vec[i].alpha )\n" + " img.setAlphaBuffer(TRUE);\n" + " return img;\n" + " }\n" + " }\n" + " return QImage();\n" + "}\n\n"; + + out << "class MimeSourceFactory_" << cProject << " : public QMimeSourceFactory\n"; + out << "{\n"; + out << "public:\n"; + out << " MimeSourceFactory_" << cProject << "() {}\n"; + out << " ~MimeSourceFactory_" << cProject << "() {}\n"; + out << " const QMimeSource* data( const QString& abs_name ) const {\n"; + out << "\tconst QMimeSource* d = QMimeSourceFactory::data( abs_name );\n"; + out << "\tif ( d || abs_name.isNull() ) return d;\n"; + out << "\tQImage img = uic_findImage( abs_name );\n"; + out << "\tif ( !img.isNull() )\n"; + out << "\t ((QMimeSourceFactory*)this)->setImage( abs_name, img );\n"; + out << "\treturn QMimeSourceFactory::data( abs_name );\n"; + out << " };\n"; + out << "};\n\n"; + + out << "static QMimeSourceFactory* factory = 0;\n"; + out << "\n"; + + out << "void qInitImages_" << cProject << "()\n"; + out << "{\n"; + out << " if ( !factory ) {\n"; + out << "\tfactory = new MimeSourceFactory_" << cProject << ";\n"; + out << "\tQMimeSourceFactory::defaultFactory()->addFactory( factory );\n"; + out << " }\n"; + out << "}\n\n"; + + out << "void qCleanupImages_" << cProject << "()\n"; + out << "{\n"; + out << " if ( factory ) {\n"; + out << "\tQMimeSourceFactory::defaultFactory()->removeFactory( factory );\n"; + out << "\tdelete factory;\n"; + out << "\tfactory = 0;\n"; + out << " }\n"; + out << "}\n\n"; + + out << "class StaticInitImages_" << cProject << "\n"; + out << "{\n"; + out << "public:\n"; + out << " StaticInitImages_" << cProject << "() { qInitImages_" << cProject << "(); }\n"; + out << "#if defined(Q_OS_SCO) || defined(Q_OS_UNIXWARE)\n"; + out << " ~StaticInitImages_" << cProject << "() { }\n"; + out << "#else\n"; + out << " ~StaticInitImages_" << cProject << "() { qCleanupImages_" << cProject << "(); }\n"; + out << "#endif\n"; + out << "};\n\n"; + + out << "static StaticInitImages_" << cProject << " staticImages;\n"; + } +} diff --git a/src/designer/embed.h b/src/designer/embed.h new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/src/designer/embed.h @@ -0,0 +1 @@ + diff --git a/src/designer/formdesigner.cpp b/src/designer/formdesigner.cpp new file mode 100644 index 0000000..bf9c067 --- /dev/null +++ b/src/designer/formdesigner.cpp @@ -0,0 +1,159 @@ +/**************************************************************************** +** $Id: formdesigner.cpp,v 1.2 2008/11/27 20:20:55 leader Exp $ +** +** Code file of the Form designer of Ananas Designer applications +** +** Created : 20031201 +** +** Copyright (C) 2003-2004 Leader InfoTech. All rights reserved. +** +** This file is part of the Designer application of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.leaderit.ru/page=ananas or email sales@leaderit.ru +** See http://www.leaderit.ru/gpl/ for GPL licensing information. +** +** Contact org@leaderit.ru if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#include "formdesigner.h" + +#include +//#include +#include "formdesigner/qdesigner_workbench.h" +#include "formdesigner/qdesigner_formwindow.h" +//#include + +//--aFormDesigner* aFormDesigner::m_designer = 0; + +aFormDesigner::aFormDesigner() +{ + m_workbench = new QDesignerWorkbench(); + setCentralWidget( m_workbench->mainWindow() ); +// resize( ); +/* + designerInterface = QDesignerComponents::createFormEditor( this ); + //new QDesignerFormEditorInterface( 0 ); + + QWidget *w = designerInterface->topLevel(); + if (w) w->show(); + else printf("no designer widget\n"); + + QDesignerWidgetBoxInterface *widgetBox = 0; + widgetBox = designerInterface->widgetBox(); + if ( widgetBox ) widgetBox->show(); +// designerInterface->show(); +*/ +} + + +aFormDesigner::~aFormDesigner() +{ +} + + +/*aFormDesigner* aFormDesigner::designer() +{ + if (!m_designer) + m_designer = new aFormDesigner(); + return m_designer; +}*/ + + +/*QWidget* aFormDesigner::mainWindow() +{ + return m_workbench->mainWindow(); +}*/ + + +void aFormDesigner::fileOpen(const QString& fileName) +{ + //m_guibuilder->openFile(fileName); + m_workbench->readInForm(fileName); +} + + +void aFormDesigner::closeEvent( QCloseEvent *e ) +{ +//CHECK_POINT + fileSaveAll(); + e->accept(); +// deleteLater(); + // ( (MainForm*)this->topLevelWidget() )->removeTab(caption()); +// e->ignore(); +} + + +void aFormDesigner::show() +{ + QMainWindow::show(); +/*CHECK_POINT + MainWindow::show(); +CHECK_POINT +// actioneditor()->hide(); + propertyeditor()->removePage( propertyeditor()->page( 1 ) ); //eventList()->hide(); + objectHierarchy()->parentWidget()->close(); + if(outputWindow() != NULL && outputWindow()->parentWidget()!=NULL) + { + +#ifndef _Windows + outputWindow()->parentWidget()->close(); +#endif + } + workspace()->parentWidget()->parentWidget()->close();*/ + //--mainWindow()->show(); +} + + +void aFormDesigner::hide() +{ + QMainWindow::hide(); + //--fileSaveAll(); + //--fileClose(); + // ( (MainForm*)this->topLevelWidget() )->removeTab(caption()); +} + + +void aFormDesigner::mouseDoubleClickEvent ( QMouseEvent * e ) +{ +//CHECK_POINT + +// MainWindow::mouseDoubleClickEvent ( e ); +} + + +/*GuiBuilderPart *aFormDesigner::guibuilder() const +{ + return m_guibuilder; +}*/ + +QDesignerWorkbench * +aFormDesigner::workbench() +{ + return m_workbench; +} + + +void +aFormDesigner::fileSaveAll() +{ + int i; + QDesignerFormWindow *w; + + for (i=0; i< workbench()->formWindowCount(); i++){ + w = workbench()->formWindow( i ); + workbench()->saveForm(w->editor()); + printf("w=%s\n", w->windowTitle().toUtf8().data()); + } +} + diff --git a/src/designer/formdesigner.h b/src/designer/formdesigner.h new file mode 100644 index 0000000..b3398b5 --- /dev/null +++ b/src/designer/formdesigner.h @@ -0,0 +1,58 @@ +/**************************************************************************** +** $Id: formdesigner.h,v 1.3 2008/11/27 20:20:55 leader Exp $ +** +** Header file of the Form designer of Ananas Designer applications +** +** Created : 20031201 +** +** Copyright (C) 2003-2004 Leader InfoTech. All rights reserved. +** +** This file is part of the Designer application of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.leaderit.ru/page=ananas or email sales@leaderit.ru +** See http://www.leaderit.ru/gpl/ for GPL licensing information. +** +** Contact org@leaderit.ru if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#ifndef FORMDESIGNER_H +#define FORMDESIGNER_H + +#include +#include +#include + + +class QDesignerWorkbench; + +class aFormDesigner : public QMainWindow +{ +public: + aFormDesigner(); + virtual ~aFormDesigner(); + void show(); + void hide(); + void fileOpen(const QString&); + void fileSaveAll(); + QDesignerWorkbench *workbench(); + +protected: + virtual void closeEvent( QCloseEvent *e ); + virtual void mouseDoubleClickEvent ( QMouseEvent * e ); + +private: + QDesignerWorkbench *m_workbench; +}; + +#endif diff --git a/src/designer/formdesigner/designer.qrc b/src/designer/formdesigner/designer.qrc new file mode 100644 index 0000000..11a3b0f --- /dev/null +++ b/src/designer/formdesigner/designer.qrc @@ -0,0 +1,9 @@ + + +images/designer.png +templates/forms/Dialog_with_Buttons_Bottom.ui +templates/forms/Dialog_with_Buttons_Right.ui +templates/forms/Widget.ui +templates/forms/Main_Window.ui + + diff --git a/src/designer/formdesigner/formwindowsettings.cpp b/src/designer/formdesigner/formwindowsettings.cpp new file mode 100644 index 0000000..c9c018a --- /dev/null +++ b/src/designer/formdesigner/formwindowsettings.cpp @@ -0,0 +1,103 @@ +/**************************************************************************** +** +** Copyright (C) 1992-2006 Trolltech ASA. All rights reserved. +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** This file may be used under the terms of the GNU General Public +** License version 2.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of +** this file. Please review the following information to ensure GNU +** General Public Licensing requirements will be met: +** http://www.trolltech.com/products/qt/opensource.html +** +** If you are unsure which license is appropriate for your use, please +** review the following information: +** http://www.trolltech.com/products/qt/licensing.html or contact the +** sales department at sales@trolltech.com. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +****************************************************************************/ + +#include "formwindowsettings.h" +#include +#include + +FormWindowSettings::FormWindowSettings(QDesignerFormWindowInterface *parent) + : QDialog(parent), m_formWindow(parent) +{ + ui.setupUi(this); + + int defaultMargin = INT_MIN, defaultSpacing = INT_MIN; + formWindow()->layoutDefault(&defaultMargin, &defaultSpacing); + + QStyle *style = formWindow()->style(); + ui.defaultMarginSpinBox->setValue(style->pixelMetric(QStyle::PM_DefaultChildMargin, 0)); + ui.defaultSpacingSpinBox->setValue(style->pixelMetric(QStyle::PM_DefaultLayoutSpacing, 0)); + + if (defaultMargin != INT_MIN || defaultMargin != INT_MIN) { + ui.layoutDefaultGroupBox->setChecked(true); + + if (defaultMargin != INT_MIN) + ui.defaultMarginSpinBox->setValue(defaultMargin); + + if (defaultSpacing != INT_MIN) + ui.defaultSpacingSpinBox->setValue(defaultSpacing); + } else { + ui.layoutDefaultGroupBox->setChecked(false); + } + + QString marginFunction, spacingFunction; + formWindow()->layoutFunction(&marginFunction, &spacingFunction); + if (!marginFunction.isEmpty() || !spacingFunction.isEmpty()) { + ui.layoutFunctionGroupBox->setChecked(true); + ui.marginFunctionLineEdit->setText(marginFunction); + ui.spacingFunctionLineEdit->setText(spacingFunction); + } else { + ui.layoutFunctionGroupBox->setChecked(false); + } + + QString pixFunction = formWindow()->pixmapFunction(); + ui.pixmapFunctionGroupBox->setChecked(!pixFunction.isEmpty()); + ui.pixmapFunctionLineEdit->setText(pixFunction); + + ui.authorLineEdit->setText(formWindow()->author()); + + foreach (QString includeHint, formWindow()->includeHints()) { + if (includeHint.isEmpty()) + continue; + + ui.includeHintsTextEdit->append(includeHint); + } +} + +FormWindowSettings::~FormWindowSettings() +{ +} + +QDesignerFormWindowInterface *FormWindowSettings::formWindow() const +{ + return m_formWindow; +} + +void FormWindowSettings::accept() +{ + formWindow()->setAuthor(ui.authorLineEdit->text()); + + if (ui.pixmapFunctionGroupBox->isChecked()) + formWindow()->setPixmapFunction(ui.pixmapFunctionLineEdit->text()); + + if (ui.layoutDefaultGroupBox->isChecked()) + formWindow()->setLayoutDefault(ui.defaultMarginSpinBox->value(), ui.defaultSpacingSpinBox->value()); + + if (ui.layoutFunctionGroupBox->isChecked()) + formWindow()->setLayoutFunction(ui.marginFunctionLineEdit->text(), ui.spacingFunctionLineEdit->text()); + + formWindow()->setIncludeHints(ui.includeHintsTextEdit->toPlainText().split(QLatin1String("\n"))); + + formWindow()->setDirty(true); + + QDialog::accept(); +} diff --git a/src/designer/formdesigner/formwindowsettings.h b/src/designer/formdesigner/formwindowsettings.h new file mode 100644 index 0000000..4d08d3d --- /dev/null +++ b/src/designer/formdesigner/formwindowsettings.h @@ -0,0 +1,48 @@ +/**************************************************************************** +** +** Copyright (C) 1992-2006 Trolltech ASA. All rights reserved. +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** This file may be used under the terms of the GNU General Public +** License version 2.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of +** this file. Please review the following information to ensure GNU +** General Public Licensing requirements will be met: +** http://www.trolltech.com/products/qt/opensource.html +** +** If you are unsure which license is appropriate for your use, please +** review the following information: +** http://www.trolltech.com/products/qt/licensing.html or contact the +** sales department at sales@trolltech.com. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +****************************************************************************/ + +#ifndef FORMWINDOWSETTINGS_H +#define FORMWINDOWSETTINGS_H + +#include "ui_formwindowsettings.h" + +class QDesignerFormWindowInterface; + +class FormWindowSettings: public QDialog +{ + Q_OBJECT +public: + FormWindowSettings(QDesignerFormWindowInterface *formWindow); + virtual ~FormWindowSettings(); + + QDesignerFormWindowInterface *formWindow() const; + + virtual void accept(); + +private: + Ui::FormWindowSettings ui; + QDesignerFormWindowInterface *m_formWindow; +}; + +#endif // FORMWINDOWSETTINGS_H + diff --git a/src/designer/formdesigner/formwindowsettings.ui b/src/designer/formdesigner/formwindowsettings.ui new file mode 100644 index 0000000..18342f5 --- /dev/null +++ b/src/designer/formdesigner/formwindowsettings.ui @@ -0,0 +1,319 @@ + + + ********************************************************************* +** +** Copyright (C) 1992-2006 Trolltech ASA. All rights reserved. +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** This file may be used under the terms of the GNU General Public +** License version 2.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of +** this file. Please review the following information to ensure GNU +** General Public Licensing requirements will be met: +** http://www.trolltech.com/products/qt/opensource.html +** +** If you are unsure which license is appropriate for your use, please +** review the following information: +** http://www.trolltech.com/products/qt/licensing.html or contact the +** sales department at sales@trolltech.com. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +********************************************************************* + + FormWindowSettings + + + + 0 + 0 + 433 + 465 + + + + Form Settings + + + + 8 + + + 6 + + + + + Qt::Vertical + + + + 111 + 115 + + + + + + + + 0 + + + 6 + + + + + &Pixmap Function + + + true + + + + 8 + + + 6 + + + + + + + + + + + + + &Include Hints + + + + 8 + + + 6 + + + + + + + + + + + &Author + + + + 8 + + + 6 + + + + + + + + + + + 0 + + + 6 + + + + + Layout &Default + + + true + + + + 8 + + + 6 + + + + + &Spacing: + + + defaultSpacingSpinBox + + + + + + + &Margin: + + + defaultMarginSpinBox + + + + + + + + + + + + + + + + &Layout Function + + + true + + + + 8 + + + 6 + + + + + + + + + + + Ma&rgin: + + + marginFunctionLineEdit + + + + + + + Spa&cing: + + + spacingFunctionLineEdit + + + + + + + + + + + + Qt::Horizontal + + + + + + + 0 + + + 6 + + + + + Qt::Horizontal + + + + 131 + 31 + + + + + + + + OK + + + true + + + + + + + Cancel + + + + + + + + + + authorLineEdit + defaultMarginSpinBox + defaultSpacingSpinBox + marginFunctionLineEdit + spacingFunctionLineEdit + pixmapFunctionLineEdit + okButton + cancelButton + + + + + okButton + clicked() + FormWindowSettings + accept() + + + 351 + 38 + + + 233 + 29 + + + + + cancelButton + clicked() + FormWindowSettings + reject() + + + 330 + 66 + + + 197 + 125 + + + + + diff --git a/src/designer/formdesigner/images/designer.png b/src/designer/formdesigner/images/designer.png new file mode 100644 index 0000000000000000000000000000000000000000..1014a9cd1a36b71fab0861c3001d22fd77c14962 GIT binary patch literal 14607 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 FV1oa%gxvrD literal 0 HcmV?d00001 diff --git a/src/designer/formdesigner/images/mdi.png b/src/designer/formdesigner/images/mdi.png new file mode 100644 index 0000000000000000000000000000000000000000..5012ab304b7705a035c384e65d5517351837877d GIT binary patch literal 59505 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 z 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 jA{BrQEND-$o5j|9sL;<%2fB-`1Uk0=+( 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 + +#include +#include +#include +#include +#include + +#include + +enum NewForm_CustomRole +{ + TemplateNameRole = Qt::UserRole + 100 +}; + +NewForm::NewForm(QDesignerWorkbench *workbench, QWidget *parentWidget) + : QDialog(parentWidget, +#ifdef Q_WS_MAC + Qt::Tool | +#endif + Qt::WindowTitleHint | Qt::WindowSystemMenuHint), + m_workbench(workbench) +{ + ui.setupUi(this); + ui.treeWidget->setItemDelegate(new qdesigner_internal::SheetDelegate(ui.treeWidget, this)); + ui.treeWidget->header()->hide(); + ui.treeWidget->header()->setStretchLastSection(true); + ui.lblPreview->setBackgroundRole(QPalette::Base); + ui.chkShowOnStartup->setChecked(QDesignerSettings().showNewFormOnStartup()); + + loadFrom(QLatin1String(":/trolltech/designer/templates/forms"), true); + + QDesignerSettings settings; + foreach(QString path, settings.formTemplatePaths()) + loadFrom(path, false); +} + +NewForm::~NewForm() +{ + QDesignerSettings().setShowNewFormOnStartup(ui.chkShowOnStartup->isChecked()); +} + +void NewForm::on_treeWidget_currentItemChanged(QTreeWidgetItem *current, QTreeWidgetItem *) +{ + if (current && current->parent()) { + QIcon icon = formPreviewIcon(current->data(0, TemplateNameRole).toString()); + if (icon.isNull()) { + ui.createButton->setEnabled(false); + ui.lblPreview->setText(tr("Error loading form")); + } else { + ui.createButton->setEnabled(true); + ui.createButton->setDefault(true); + ui.lblPreview->setPixmap(icon.pixmap(QSize(256, 256))); + } + } else { + ui.createButton->setEnabled(false); + ui.lblPreview->setText(tr("Choose a template for a preview")); + } +} + +void NewForm::on_treeWidget_itemActivated(QTreeWidgetItem *item) +{ + if (item->data(0, TemplateNameRole).isValid()) + ui.createButton->animateClick(0); +} + +void NewForm::on_createButton_clicked() +{ + if (QTreeWidgetItem *item = ui.treeWidget->currentItem()) { + close(); + + int maxUntitled = 0; + int totalWindows = m_workbench->formWindowCount(); + // This will cause some problems with i18n, but for now I need the string to be "static" + QRegExp rx(QLatin1String("untitled( (\\d+))?")); + for (int i = 0; i < totalWindows; ++i) { + QString title = m_workbench->formWindow(i)->windowTitle(); + title = title.replace(QLatin1String("[*]"), QLatin1String("")); + if (rx.indexIn(title) != 1) { + if (maxUntitled == 0) + ++maxUntitled; + if (rx.numCaptures() > 1) + maxUntitled = qMax(rx.cap(2).toInt(), maxUntitled); + } + } + + QDesignerFormWindow *formWindow = workbench()->createFormWindow(); + if (QDesignerFormWindowInterface *editor = formWindow->editor()) { + QString formTemplateName = item->data(0, TemplateNameRole).toString(); + QFile f(formTemplateName); + if (f.open(QFile::ReadOnly)) { + editor->setContents(&f); + f.close(); + } else { + editor->setContents(QString()); + } + + if (QWidget *container = editor->mainContainer()) + formWindow->resize(container->size()); + } + QString newTitle = QLatin1String("untitled"); + if (maxUntitled) + newTitle += QLatin1String(" ") + QString::number(maxUntitled + 1); + + newTitle.append(QLatin1String("[*]")); + formWindow->setWindowTitle(newTitle); + formWindow->editor()->setFileName(""); + formWindow->show(); + } +} + +void NewForm::on_closeButton_clicked() +{ + close(); +} + +QDesignerWorkbench *NewForm::workbench() const +{ + return m_workbench; +} + +QIcon NewForm::formPreviewIcon(const QString &fileName) +{ + QIcon result; + + QFile f(fileName); + if (f.open(QFile::ReadOnly)) { + qdesigner_internal::QDesignerFormBuilder formBuilder(workbench()->core(),qdesigner_internal::QDesignerFormBuilder::DisableScripts); + + QWidget *fake = new QWidget(0); + fake->setAttribute(Qt::WA_WState_Visible); + + if (QWidget *widget = formBuilder.load(&f, fake)) { + widget->setParent(fake, 0); + widget->show(); + f.close(); + + QPixmap pix = QPixmap::grabWidget(widget); + QImage image = pix.toImage(); + image = image.scaled(256, 256, Qt::KeepAspectRatio, Qt::SmoothTransformation); + result = QPixmap::fromImage(image); + } + + fake->deleteLater(); + } + + return result; +} + +void NewForm::loadFrom(const QString &path, bool resourceFile) +{ + QDir dir(path); + + if (!dir.exists()) + return; + + // Iterate through the directory and add the templates + QFileInfoList list = dir.entryInfoList(QStringList() << "*.ui", QDir::Files); + + if (list.isEmpty()) + return; + + QChar separator = resourceFile ? QChar(QLatin1Char('/')) + : QChar(QDir::separator()); + QTreeWidgetItem *root = new QTreeWidgetItem(ui.treeWidget); + // Try to get something that is easy to read. + QString visiblePath = path; + int index = visiblePath.lastIndexOf(separator); + if (index != -1) { + // try to find a second slash, just to be a bit better. + int index2 = visiblePath.lastIndexOf(separator, index - 1); + if (index2 != -1) + index = index2; + visiblePath = visiblePath.mid(index + 1); + visiblePath = QDir::convertSeparators(visiblePath); + } + + root->setText(0, visiblePath.replace(QLatin1String("_"), QLatin1String(" "))); + root->setToolTip(0, path); + + foreach(QFileInfo fi, list) { + if (!fi.isFile()) + continue; + + QTreeWidgetItem *item = new QTreeWidgetItem(root); + item->setText(0, fi.baseName().replace(QLatin1String("_"), QLatin1String(" "))); + item->setData(0, TemplateNameRole, fi.absoluteFilePath()); + + QTreeWidgetItem *i = ui.treeWidget->currentItem(); + if (i == 0) { + ui.treeWidget->setCurrentItem(item); + ui.treeWidget->setItemSelected(item, true); + } + } + ui.treeWidget->setItemExpanded(root, true); +} + +void NewForm::on_openButton_clicked() +{ + hide(); + if (m_workbench->actionManager()->openForm()) + close(); + else + show(); +} + +void NewForm::on_treeWidget_itemPressed(QTreeWidgetItem *item) +{ + if (item && !item->parent()) + ui.treeWidget->setItemExpanded(item, !ui.treeWidget->isItemExpanded(item)); +} diff --git a/src/designer/formdesigner/newform.h b/src/designer/formdesigner/newform.h new file mode 100644 index 0000000..bdc9b7f --- /dev/null +++ b/src/designer/formdesigner/newform.h @@ -0,0 +1,59 @@ +/**************************************************************************** +** +** Copyright (C) 1992-2006 Trolltech ASA. All rights reserved. +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** This file may be used under the terms of the GNU General Public +** License version 2.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of +** this file. Please review the following information to ensure GNU +** General Public Licensing requirements will be met: +** http://www.trolltech.com/products/qt/opensource.html +** +** If you are unsure which license is appropriate for your use, please +** review the following information: +** http://www.trolltech.com/products/qt/licensing.html or contact the +** sales department at sales@trolltech.com. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +****************************************************************************/ + +#ifndef NEWFORM_H +#define NEWFORM_H + +#include "ui_newform.h" + +#include + +class QDesignerWorkbench; + +class NewForm: public QDialog +{ + Q_OBJECT +public: + NewForm(QDesignerWorkbench *workbench, QWidget *parentWidget); + virtual ~NewForm(); + + QDesignerWorkbench *workbench() const; + +private slots: + void on_createButton_clicked(); + void on_closeButton_clicked(); + void on_openButton_clicked(); + void on_treeWidget_itemActivated(QTreeWidgetItem *item); + void on_treeWidget_currentItemChanged(QTreeWidgetItem *current, QTreeWidgetItem *); + void on_treeWidget_itemPressed(QTreeWidgetItem *item); + +private: + QIcon formPreviewIcon(const QString &fileName); + void loadFrom(const QString &path, bool resourceFile); + +private: + QDesignerWorkbench *m_workbench; + Ui::NewForm ui; +}; + +#endif // NEWFORM_H diff --git a/src/designer/formdesigner/newform.ui b/src/designer/formdesigner/newform.ui new file mode 100644 index 0000000..b513748 --- /dev/null +++ b/src/designer/formdesigner/newform.ui @@ -0,0 +1,254 @@ + + + ********************************************************************* +** +** Copyright (C) 1992-2006 Trolltech ASA. All rights reserved. +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** This file may be used under the terms of the GNU General Public +** License version 2.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of +** this file. Please review the following information to ensure GNU +** General Public Licensing requirements will be met: +** http://www.trolltech.com/products/qt/opensource.html +** +** If you are unsure which license is appropriate for your use, please +** review the following information: +** http://www.trolltech.com/products/qt/licensing.html or contact the +** sales department at sales@trolltech.com. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +********************************************************************* + + NewForm + + + + 0 + 0 + 494 + 300 + + + + New Form + + + + 9 + + + 6 + + + + + 1 + + + 6 + + + + + + 1 + 1 + 256 + 205 + + + + + 1 + 7 + 0 + 0 + + + + + 128 + 128 + + + + false + + + 1 + + + + 0 + + + + + + + + + 263 + 1 + 212 + 205 + + + + + 7 + 5 + 0 + 0 + + + + 1 + + + Choose a template for a preview + + + Qt::AlignCenter + + + 5 + + + + + + + + + + 9 + 222 + 476 + 3 + + + + QFrame::HLine + + + QFrame::Sunken + + + + + + + 1 + + + 6 + + + + + + 1 + 27 + 103 + 32 + + + + &Open... + + + + + + + + 110 + 27 + 147 + 32 + + + + Qt::Horizontal + + + + 61 + 32 + + + + + + + + false + + + + 263 + 27 + 103 + 32 + + + + C&reate + + + false + + + true + + + + + + + + 372 + 27 + 103 + 32 + + + + &Close + + + false + + + false + + + + + + + + 1 + 1 + 256 + 20 + + + + Show this Dialog on Startup + + + + + + + + + + + diff --git a/src/designer/formdesigner/plugindialog.cpp b/src/designer/formdesigner/plugindialog.cpp new file mode 100644 index 0000000..c57f097 --- /dev/null +++ b/src/designer/formdesigner/plugindialog.cpp @@ -0,0 +1,122 @@ +/**************************************************************************** +** +** Copyright (C) 2005-2006 Trolltech ASA. All rights reserved. +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** This file may be used under the terms of the GNU General Public +** License version 2.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of +** this file. Please review the following information to ensure GNU +** General Public Licensing requirements will be met: +** http://www.trolltech.com/products/qt/opensource.html +** +** If you are unsure which license is appropriate for your use, please +** review the following information: +** http://www.trolltech.com/products/qt/licensing.html or contact the +** sales department at sales@trolltech.com. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +****************************************************************************/ + +#include +#include "private/pluginmanager_p.h" + +#include + +#include "plugindialog.h" + +PluginDialog::PluginDialog(QDesignerFormEditorInterface *core, QWidget *parent) + : QDialog(parent +#ifdef Q_WS_MAC + , Qt::Tool +#endif + ), m_core(core) +{ + ui.setupUi(this); + + ui.message->hide(); + + QStringList headerLabels; + headerLabels << tr("Components"); + + ui.treeWidget->setAlternatingRowColors(false); + ui.treeWidget->setSelectionMode(QAbstractItemView::NoSelection); + ui.treeWidget->setHeaderLabels(headerLabels); + ui.treeWidget->header()->hide(); + + interfaceIcon.addPixmap(style()->standardPixmap(QStyle::SP_DirOpenIcon), + QIcon::Normal, QIcon::On); + interfaceIcon.addPixmap(style()->standardPixmap(QStyle::SP_DirClosedIcon), + QIcon::Normal, QIcon::Off); + featureIcon.addPixmap(style()->standardPixmap(QStyle::SP_FileIcon)); + + setWindowTitle(tr("Plugin Information")); + populateTreeWidget(); +} + +QDesignerFormEditorInterface *PluginDialog::core() const +{ + return m_core; +} + +void PluginDialog::populateTreeWidget() +{ + QStringList fileNames = core()->pluginManager()->registeredPlugins(); + + foreach (QString fileName, fileNames) { + QPluginLoader loader(fileName); + QFileInfo fileInfo(fileName); + + QObject *plugin = loader.instance(); + + QTreeWidgetItem *pluginItem = new QTreeWidgetItem(ui.treeWidget); + pluginItem->setText(0, fileInfo.fileName()); + pluginItem->setIcon(0, style()->standardPixmap(QStyle::SP_DirOpenIcon)); + ui.treeWidget->setItemExpanded(pluginItem, true); + + QFont boldFont = pluginItem->font(0); + boldFont.setBold(true); + pluginItem->setFont(0, boldFont); + + if (plugin != 0) { + QDesignerCustomWidgetCollectionInterface *c = qobject_cast(plugin); + if (c != 0) { + foreach (QDesignerCustomWidgetInterface *p, c->customWidgets()) { + QTreeWidgetItem *item = new QTreeWidgetItem(pluginItem); + item->setText(0, p->name()); + item->setIcon(0, pluginIcon(p->icon())); + item->setToolTip(0, p->toolTip()); + item->setWhatsThis(0, p->whatsThis()); + } + } + + QDesignerCustomWidgetInterface *p = qobject_cast(plugin); + if (p != 0) { + QTreeWidgetItem *item = new QTreeWidgetItem(pluginItem); + item->setText(0, p->name()); + item->setIcon(0, pluginIcon(p->icon())); + item->setToolTip(0, p->toolTip()); + item->setWhatsThis(0, p->whatsThis()); + } + } + } + + if (ui.treeWidget->topLevelItemCount() == 0) { + ui.label->setText(tr("Qt Designer couldn't find any plugins")); + ui.treeWidget->hide(); + } else { + ui.label->setText(tr("Qt Designer found the following plugins")); + } +} + +QIcon PluginDialog::pluginIcon(const QIcon &icon) +{ + if (icon.isNull()) + return QIcon(":/trolltech/formeditor/images/qtlogo.png"); + + return icon; +} + diff --git a/src/designer/formdesigner/plugindialog.h b/src/designer/formdesigner/plugindialog.h new file mode 100644 index 0000000..90e95f9 --- /dev/null +++ b/src/designer/formdesigner/plugindialog.h @@ -0,0 +1,50 @@ +/**************************************************************************** +** +** Copyright (C) 2005-2006 Trolltech ASA. All rights reserved. +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** This file may be used under the terms of the GNU General Public +** License version 2.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of +** this file. Please review the following information to ensure GNU +** General Public Licensing requirements will be met: +** http://www.trolltech.com/products/qt/opensource.html +** +** If you are unsure which license is appropriate for your use, please +** review the following information: +** http://www.trolltech.com/products/qt/licensing.html or contact the +** sales department at sales@trolltech.com. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +****************************************************************************/ + +#ifndef PLUGINDIALOG_H +#define PLUGINDIALOG_H + +#include "ui_plugindialog.h" + +class QDesignerFormEditorInterface; + +class PluginDialog : public QDialog +{ + Q_OBJECT +public: + PluginDialog(QDesignerFormEditorInterface *core, QWidget *parent = 0); + + QDesignerFormEditorInterface *core() const; + +private: + void populateTreeWidget(); + QIcon pluginIcon(const QIcon &icon); + +private: + QDesignerFormEditorInterface *m_core; + Ui::PluginDialog ui; + QIcon interfaceIcon; + QIcon featureIcon; +}; + +#endif diff --git a/src/designer/formdesigner/plugindialog.ui b/src/designer/formdesigner/plugindialog.ui new file mode 100644 index 0000000..be89004 --- /dev/null +++ b/src/designer/formdesigner/plugindialog.ui @@ -0,0 +1,134 @@ + + + ********************************************************************* +** +** Copyright (C) 1992-2006 Trolltech ASA. All rights reserved. +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** This file may be used under the terms of the GNU General Public +** License version 2.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of +** this file. Please review the following information to ensure GNU +** General Public Licensing requirements will be met: +** http://www.trolltech.com/products/qt/opensource.html +** +** If you are unsure which license is appropriate for your use, please +** review the following information: +** http://www.trolltech.com/products/qt/licensing.html or contact the +** sales department at sales@trolltech.com. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +********************************************************************* + + PluginDialog + + + + 0 + 0 + 401 + 331 + + + + Plugin Informations + + + + 8 + + + 6 + + + + + TextLabel + + + true + + + + + + + + + + TextLabel + + + true + + + + + + + 0 + + + 6 + + + + + Qt::Horizontal + + + + 131 + 31 + + + + + + + + OK + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + okButton + clicked() + PluginDialog + accept() + + + 278 + 253 + + + 96 + 254 + + + + + diff --git a/src/designer/formdesigner/private/formscriptrunner_p.h b/src/designer/formdesigner/private/formscriptrunner_p.h new file mode 100644 index 0000000..627ee21 --- /dev/null +++ b/src/designer/formdesigner/private/formscriptrunner_p.h @@ -0,0 +1,87 @@ +/**************************************************************************** +** +** Copyright (C) 1992-2007 Trolltech ASA. All rights reserved. +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** This file may be used under the terms of the GNU General Public +** License version 2.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of +** this file. Please review the following information to ensure GNU +** General Public Licensing requirements will be met: +** http://www.trolltech.com/products/qt/opensource.html +** +** If you are unsure which license is appropriate for your use, please +** review the following information: +** http://www.trolltech.com/products/qt/licensing.html or contact the +** sales department at sales@trolltech.com. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +****************************************************************************/ + +#ifndef FORMSCRIPTRUNNER_H +#define FORMSCRIPTRUNNER_H + +#include +#include +#include +#include + +class QWidget; + +#ifdef QFORMINTERNAL_NAMESPACE +namespace QFormInternal +{ +#endif + +class DomWidget; + +class QDESIGNER_UILIB_EXPORT QFormScriptRunner +{ +public: + QFormScriptRunner(); + ~QFormScriptRunner(); + + typedef QList WidgetList; + + bool run(const DomWidget *domWidget, + const QString &customWidgetScript, + QWidget *widget, const WidgetList &children, + QString *errorMessage); + + struct Error { + QString objectName; + QString script; + QString errorMessage; + }; + typedef QList Errors; + Errors errors() const; + void clearErrors(); + + enum Option { + NoOptions = 0x0, + DisableWarnings = 0x1, + DisableScripts = 02 + }; + Q_DECLARE_FLAGS(Options, Option) + + Options options() const; + void setOptions(Options options); + +private: + class QFormScriptRunnerPrivate; + QFormScriptRunnerPrivate *m_impl; + + QFormScriptRunner(const QFormScriptRunner &); + void operator = (const QFormScriptRunner &); +}; + +Q_DECLARE_OPERATORS_FOR_FLAGS(QFormScriptRunner::Options) + +#ifdef QFORMINTERNAL_NAMESPACE +} +#endif + +#endif // FORMSCRIPTRUNNER_H diff --git a/src/designer/formdesigner/private/pluginmanager_p.h b/src/designer/formdesigner/private/pluginmanager_p.h new file mode 100644 index 0000000..e970b04 --- /dev/null +++ b/src/designer/formdesigner/private/pluginmanager_p.h @@ -0,0 +1,100 @@ +/**************************************************************************** +** +** Copyright (C) 1992-2007 Trolltech ASA. All rights reserved. +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** This file may be used under the terms of the GNU General Public +** License version 2.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of +** this file. Please review the following information to ensure GNU +** General Public Licensing requirements will be met: +** http://www.trolltech.com/products/qt/opensource.html +** +** If you are unsure which license is appropriate for your use, please +** review the following information: +** http://www.trolltech.com/products/qt/licensing.html or contact the +** sales department at sales@trolltech.com. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of Qt Designer. This header +// file may change from version to version without notice, or even be removed. +// +// We mean it. +// + +#ifndef PLUGINMANAGER_H +#define PLUGINMANAGER_H + +#include "shared_global_p.h" + +#include +#include +#include + +class QDesignerFormEditorInterface; +class QDesignerCustomWidgetInterface; + +class QDESIGNER_SHARED_EXPORT QDesignerPluginManager: public QObject +{ + Q_OBJECT +public: + QDesignerPluginManager(QDesignerFormEditorInterface *core); + virtual ~QDesignerPluginManager(); + + QDesignerFormEditorInterface *core() const; + + QObject *instance(const QString &plugin) const; + + QStringList registeredPlugins() const; + + QStringList findPlugins(const QString &path); + + QStringList pluginPaths() const; + void setPluginPaths(const QStringList &plugin_paths); + + QStringList disabledPlugins() const; + void setDisabledPlugins(const QStringList &disabled_plugins); + + QStringList failedPlugins() const; + QString failureReason(const QString &pluginName) const; + + QList instances() const; + QList registeredCustomWidgets() const; + + bool registerNewPlugins(); + +public slots: + bool syncSettings(); + void ensureInitialized(); + +private: + void updateRegisteredPlugins(); + void registerPath(const QString &path); + void registerPlugin(const QString &plugin); + +private: + QDesignerFormEditorInterface *m_core; + QStringList m_pluginPaths; + QStringList m_registeredPlugins; + QStringList m_disabledPlugins; + + typedef QMap FailedPluginMap; + FailedPluginMap m_failedPlugins; + + typedef QList CustomWidgetList; + CustomWidgetList m_customWidgets; + + QStringList defaultPluginPaths() const; +}; + +#endif // PLUGINMANAGER_H diff --git a/src/designer/formdesigner/private/qdesigner_formbuilder_p.h b/src/designer/formdesigner/private/qdesigner_formbuilder_p.h new file mode 100644 index 0000000..028c595 --- /dev/null +++ b/src/designer/formdesigner/private/qdesigner_formbuilder_p.h @@ -0,0 +1,113 @@ +/**************************************************************************** +** +** Copyright (C) 1992-2007 Trolltech ASA. All rights reserved. +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** This file may be used under the terms of the GNU General Public +** License version 2.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of +** this file. Please review the following information to ensure GNU +** General Public Licensing requirements will be met: +** http://www.trolltech.com/products/qt/opensource.html +** +** If you are unsure which license is appropriate for your use, please +** review the following information: +** http://www.trolltech.com/products/qt/licensing.html or contact the +** sales department at sales@trolltech.com. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of Qt Designer. This header +// file may change from version to version without notice, or even be removed. +// +// We mean it. +// + +#ifndef QDESIGNER_FORMBUILDER_H +#define QDESIGNER_FORMBUILDER_H + +#include "shared_global_p.h" + +#include +#include + +#include +#include + +class QDesignerFormEditorInterface; +class QDesignerFormWindowInterface; + +namespace qdesigner_internal { + +// Form builder used for previewing forms +class QDESIGNER_SHARED_EXPORT QDesignerFormBuilder: public QFormBuilder +{ +public: + enum Mode { + // Use container extension to populate containers. Disable scripts. + DisableScripts, + // Use container extension to populate containers as well as scripts + UseScriptAndContainerExtension, + // Experimental: Use scripts to populate the container + UseScriptForContainerExtension + }; + + QDesignerFormBuilder(QDesignerFormEditorInterface *core, Mode mode); + + QWidget *createWidgetFromContents(const QString &contents, QWidget *parentWidget = 0); + + virtual QWidget *createWidget(DomWidget *ui_widget, QWidget *parentWidget = 0) + { return QFormBuilder::create(ui_widget, parentWidget); } + + inline QDesignerFormEditorInterface *core() const + { return m_core; } + + typedef QFormScriptRunner::Errors ScriptErrors; + // Create a preview widget (for integrations) or return 0. The widget has to be embedded into a main window. + // Experimental, depending on script support. + static QWidget *createPreview(const QDesignerFormWindowInterface *fw, const QString &styleName /* ="" */, + ScriptErrors *scriptErrors, QString *errorMessage); + // Convenience that pops up message boxes in case of failures. + static QWidget *createPreview(const QDesignerFormWindowInterface *fw, const QString &styleName = QString()); + +protected: + using QFormBuilder::createDom; + using QFormBuilder::create; + + virtual QWidget *create(DomUI *ui, QWidget *parentWidget); + virtual DomWidget *createDom(QWidget *widget, DomWidget *ui_parentWidget, bool recursive = true); + virtual QWidget *create(DomWidget *ui_widget, QWidget *parentWidget); + virtual QLayout *create(DomLayout *ui_layout, QLayout *layout, QWidget *parentWidget); + + virtual QWidget *createWidget(const QString &widgetName, QWidget *parentWidget, const QString &name); + virtual bool addItem(DomWidget *ui_widget, QWidget *widget, QWidget *parentWidget); + virtual bool addItem(DomLayoutItem *ui_item, QLayoutItem *item, QLayout *layout); + + virtual QIcon nameToIcon(const QString &filePath, const QString &qrcPath); + virtual QPixmap nameToPixmap(const QString &filePath, const QString &qrcPath); + + virtual void applyProperties(QObject *o, const QList &properties); + + virtual void loadExtraInfo(DomWidget *ui_widget, QWidget *widget, QWidget *parentWidget); + +private: + bool addItemContainerExtension(QWidget *widget, QWidget *parentWidget); + QDesignerFormEditorInterface *m_core; + const Mode m_mode; + + typedef QSet WidgetSet; + WidgetSet m_customWidgetsWithScript; +}; + +} // namespace qdesigner_internal + +#endif // QDESIGNER_FORMBUILDER_H diff --git a/src/designer/formdesigner/private/qdesigner_integration_p.h b/src/designer/formdesigner/private/qdesigner_integration_p.h new file mode 100644 index 0000000..3ac94bd --- /dev/null +++ b/src/designer/formdesigner/private/qdesigner_integration_p.h @@ -0,0 +1,96 @@ +/**************************************************************************** +** +** Copyright (C) 1992-2007 Trolltech ASA. All rights reserved. +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** This file may be used under the terms of the GNU General Public +** License version 2.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of +** this file. Please review the following information to ensure GNU +** General Public Licensing requirements will be met: +** http://www.trolltech.com/products/qt/opensource.html +** +** If you are unsure which license is appropriate for your use, please +** review the following information: +** http://www.trolltech.com/products/qt/licensing.html or contact the +** sales department at sales@trolltech.com. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of Qt Designer. This header +// file may change from version to version without notice, or even be removed. +// +// We mean it. +// + +#ifndef QDESIGNER_INTEGRATION_H +#define QDESIGNER_INTEGRATION_H + +#include "shared_global_p.h" +#include "abstractintegration.h" + +#include + +class QDesignerFormEditorInterface; +class QDesignerFormWindowInterface; +class QDesignerFormWindowManagerInterface; + +class QVariant; +class QWidget; + +namespace qdesigner_internal { + +struct Selection; + +class QDESIGNER_SHARED_EXPORT QDesignerIntegration: public QDesignerIntegrationInterface +{ + Q_OBJECT +public: + QDesignerIntegration(QDesignerFormEditorInterface *core, QObject *parent = 0); + virtual ~QDesignerIntegration(); + + virtual QWidget *containerWindow(QWidget *widget) const; + + // Load plugins into widget database and factory. + static void initializePlugins(QDesignerFormEditorInterface *formEditor); + +signals: + void propertyChanged(QDesignerFormWindowInterface *formWindow, const QString &name, const QVariant &value); + +public slots: + virtual void updateProperty(const QString &name, const QVariant &value); + // Additional signals of designer property editor + virtual void updatePropertyComment(const QString &name, const QString &value); + virtual void resetProperty(const QString &name); + virtual void addDynamicProperty(const QString &name, const QVariant &value); + virtual void removeDynamicProperty(const QString &name); + + + virtual void updateActiveFormWindow(QDesignerFormWindowInterface *formWindow); + virtual void setupFormWindow(QDesignerFormWindowInterface *formWindow); + virtual void updateSelection(); + virtual void updateGeometry(); + virtual void activateWidget(QWidget *widget); + + void updateCustomWidgetPlugins(); + +private: + void initialize(); + void getSelection(Selection &s); + QObject *propertyEditorObject(); + + QDesignerFormWindowManagerInterface *m_formWindowManager; +}; + +} // namespace qdesigner_internal + +#endif // QDESIGNER_INTEGRATION_H diff --git a/src/designer/formdesigner/private/qtundo_p.h b/src/designer/formdesigner/private/qtundo_p.h new file mode 100644 index 0000000..0e3e29f --- /dev/null +++ b/src/designer/formdesigner/private/qtundo_p.h @@ -0,0 +1,274 @@ +/**************************************************************************** +** +** Copyright (C) 1992-2006 Trolltech ASA. All rights reserved. +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** This file may be used under the terms of the GNU General Public +** License version 2.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of +** this file. Please review the following information to ensure GNU +** General Public Licensing requirements will be met: +** http://www.trolltech.com/products/qt/opensource.html +** +** If you are unsure which license is appropriate for your use, please +** review the following information: +** http://www.trolltech.com/products/qt/licensing.html or contact the +** sales department at sales@trolltech.com. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of Qt Designer. This header +// file may change from version to version without notice, or even be removed. +// +// We mean it. +// + +#ifndef QTUNDO_H +#define QTUNDO_H + +#include "shared_global_p.h" + +#include +#include +#include +#include +#include + +class QWidget; +class QAction; +class QtUndoStack; + +class QDESIGNER_SHARED_EXPORT QtCommand : public QObject +{ + Q_OBJECT + + friend class QtUndoStack; + + public: + enum Type { Command, MacroBegin, MacroEnd }; + + QtCommand(Type type, const QString &description = QString(), + bool canMerge = false); + QtCommand(const QString &description = QString(), + bool canMerge = true); + + virtual void redo() {}; + virtual void undo() {}; + + QString description() const + { return m_description; } + void setDescription(const QString &s) + { m_description = s; } + bool canMerge() const + { return m_can_merge; } + void setCanMerge(bool b) + { m_can_merge = b; } + Type type() const + { return m_type; } + + bool isMacroBegin() const + { return m_type == MacroBegin; } + bool isMacroEnd() const + { return m_type == MacroEnd; } + bool isCommand() const + { return m_type == Command; } + + protected: + virtual bool mergeMeWith(QtCommand *other); + + private: + void shortenStack(); + + bool m_can_merge; + QString m_description; + Type m_type; +}; + +class QtMultiCommand : public QtCommand +{ +public: + QtMultiCommand(const QString &description = QString()); + QtMultiCommand(const QList &command_list, + const QString &description = QString()); + ~QtMultiCommand(); + virtual void redo(); + virtual void undo(); + + void append(QtCommand *command); + int count() const; + QtCommand *command(int i) const; + +private: + QList m_command_list; +}; + +class QtUndoState; + +class QDESIGNER_SHARED_EXPORT QtUndoStack : public QObject, private QList +{ + Q_OBJECT + + friend class QtUndoManager; + + public: + QtUndoStack(QObject *parent = 0); + void push(QtCommand *command); + bool canUndo() const; + bool canRedo() const; + QString undoDescription() const; + QString redoDescription() const; + QStringList undoList() const; + QStringList redoList() const; + bool isClean() const; + + void setCurrent(); + + QAction *createUndoAction(QObject *parent) const; + QAction *createRedoAction(QObject *parent) const; + + inline int currentIndex() const { return m_current_iter; } + + public slots: + void undo(int count = 1); + void redo(int count = 1); + void clear(); + + void setClean(); + + signals: + void cleanChanged(bool clean); + void commandExecuted(); + + void undoDescriptionChanged(const QString &newDescription); + void redoDescriptionChanged(const QString &newDescription); + void canUndoChanged(bool enabled); + void canRedoChanged(bool enabled); + + private: + typedef int CommandIter; + + void undoMacro(); + void redoMacro(); + CommandIter findMacroBegin(CommandIter it) const; + CommandIter findMacroEnd(CommandIter it) const; + + void beforeChange(QtUndoState &state); + void afterChange(const QtUndoState &state); + + // *m_current_iter == 0 means "one-before-first" + CommandIter m_current_iter; + uint m_num_commands; + int m_macro_nest; + + bool m_have_clean_command; + const QtCommand *m_clean_command; + + QtCommand *commandAt(CommandIter it) const; +}; + +class QDESIGNER_SHARED_EXPORT QtUndoManager : public QObject +{ + Q_OBJECT + + public: + QtUndoManager(); + + QAction *createUndoAction(QObject *parent) const; + QAction *createRedoAction(QObject *parent) const; + + void associateView(QObject *obj, QtUndoStack *stack); + void disassociateView(QObject *obj); + + bool canUndo() const; + bool canRedo() const; + QString undoDescription() const; + QString redoDescription() const; + void setUndoLimit(uint i); + uint undoLimit() const; + QStringList undoList() const; + QStringList redoList() const; + QtUndoStack *currentStack() const; + void setCurrentStack(QtUndoStack *stack); + + static QtUndoManager *manager(); + + public slots: + void undo(int count = 1); + void redo(int count = 1); + + void updateActions(); + + signals: + void changed(); + + void undoDescriptionChanged(const QString &newDescription); + void redoDescriptionChanged(const QString &newDescription); + void canUndoChanged(bool enabled); + void canRedoChanged(bool enabled); + + private slots: + void stackDestroyed(QObject *stack); + void viewDestroyed(QObject *view); + + private: + typedef QMap StackMap; + + StackMap m_stack_map; + QtUndoStack *m_current_stack; + + static QtUndoManager *m_manager; // singleton + static uint m_undo_limit; + + bool m_can_undo, m_can_redo; + QString m_undo_description, m_redo_description; +}; + +class QDESIGNER_SHARED_EXPORT QtUndoListModel: public QAbstractItemModel +{ + Q_OBJECT +public: + QtUndoListModel(QObject *parent = 0); + virtual ~QtUndoListModel(); + + inline int undoIndex() const { return m_undoIndex; } + + virtual int rowCount(const QModelIndex &parent) const; + virtual int columnCount(const QModelIndex &parent) const; + virtual bool hasChildren(const QModelIndex &parent) const + { return rowCount(parent) > 0; } + + virtual QModelIndex parent(const QModelIndex &index) const; + virtual QModelIndex index(int row, int column, const QModelIndex &parent) const; + virtual QVariant data(const QModelIndex &index, int role) const; + +private slots: + void updateItems(); + +private: + QStringList m_items; + int m_undoIndex; +}; + +class QDESIGNER_SHARED_EXPORT QtUndoListView: public QListView +{ + Q_OBJECT +public: + QtUndoListView(QWidget *parent = 0); + virtual ~QtUndoListView(); + virtual void reset(); +private slots: + void undoOrRedo(); +}; + + + +#endif diff --git a/src/designer/formdesigner/private/shared_global_p.h b/src/designer/formdesigner/private/shared_global_p.h new file mode 100644 index 0000000..32fb525 --- /dev/null +++ b/src/designer/formdesigner/private/shared_global_p.h @@ -0,0 +1,58 @@ +/**************************************************************************** +** +** Copyright (C) 1992-2006 Trolltech ASA. All rights reserved. +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** This file may be used under the terms of the GNU General Public +** License version 2.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of +** this file. Please review the following information to ensure GNU +** General Public Licensing requirements will be met: +** http://www.trolltech.com/products/qt/opensource.html +** +** If you are unsure which license is appropriate for your use, please +** review the following information: +** http://www.trolltech.com/products/qt/licensing.html or contact the +** sales department at sales@trolltech.com. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of Qt Designer. This header +// file may change from version to version without notice, or even be removed. +// +// We mean it. +// + +#ifndef SHARED_GLOBAL_H +#define SHARED_GLOBAL_H + +#include + +#ifdef QT_DESIGNER_STATIC +#define QDESIGNER_SHARED_EXTERN +#define QDESIGNER_SHARED_IMPORT +#else +#define QDESIGNER_SHARED_EXTERN Q_DECL_EXPORT +#define QDESIGNER_SHARED_IMPORT Q_DECL_IMPORT +#endif + +#ifndef QT_NO_SHARED_EXPORT +# ifdef QDESIGNER_SHARED_LIBRARY +# define QDESIGNER_SHARED_EXPORT QDESIGNER_SHARED_EXTERN +# else +# define QDESIGNER_SHARED_EXPORT QDESIGNER_SHARED_IMPORT +# endif +#else +# define QDESIGNER_SHARED_EXPORT +#endif + +#endif // SHARED_GLOBAL_H diff --git a/src/designer/formdesigner/private/sheet_delegate_p.h b/src/designer/formdesigner/private/sheet_delegate_p.h new file mode 100644 index 0000000..f260f03 --- /dev/null +++ b/src/designer/formdesigner/private/sheet_delegate_p.h @@ -0,0 +1,63 @@ +/**************************************************************************** +** +** Copyright (C) 1992-2006 Trolltech ASA. All rights reserved. +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** This file may be used under the terms of the GNU General Public +** License version 2.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of +** this file. Please review the following information to ensure GNU +** General Public Licensing requirements will be met: +** http://www.trolltech.com/products/qt/opensource.html +** +** If you are unsure which license is appropriate for your use, please +** review the following information: +** http://www.trolltech.com/products/qt/licensing.html or contact the +** sales department at sales@trolltech.com. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of Qt Designer. This header +// file may change from version to version without notice, or even be removed. +// +// We mean it. +// + + +#ifndef SHEET_DELEGATE_H +#define SHEET_DELEGATE_H + +#include "shared_global_p.h" + +#include +#include + +class QTreeView; + +namespace qdesigner_internal { + +class QDESIGNER_SHARED_EXPORT SheetDelegate: public QItemDelegate +{ + Q_OBJECT +public: + SheetDelegate(QTreeView *view, QWidget *parent); + + virtual void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const; + virtual QSize sizeHint(const QStyleOptionViewItem &opt, const QModelIndex &index) const; + +private: + QTreeView *m_view; +}; + +} // namespace qdesigner_internal + +#endif // SHEET_DELEGATE_H diff --git a/src/designer/formdesigner/qdesigner_actioneditor.cpp b/src/designer/formdesigner/qdesigner_actioneditor.cpp new file mode 100644 index 0000000..fedaaa2 --- /dev/null +++ b/src/designer/formdesigner/qdesigner_actioneditor.cpp @@ -0,0 +1,56 @@ +/**************************************************************************** +** +** Copyright (C) 1992-2006 Trolltech ASA. All rights reserved. +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** This file may be used under the terms of the GNU General Public +** License version 2.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of +** this file. Please review the following information to ensure GNU +** General Public Licensing requirements will be met: +** http://www.trolltech.com/products/qt/opensource.html +** +** If you are unsure which license is appropriate for your use, please +** review the following information: +** http://www.trolltech.com/products/qt/licensing.html or contact the +** sales department at sales@trolltech.com. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +****************************************************************************/ + +//#include "qdesigner.h" +#include "qdesigner_actioneditor.h" +#include "qdesigner_workbench.h" + +#include +#include + +QDesignerActionEditor::QDesignerActionEditor(QDesignerWorkbench *workbench) + : QDesignerToolWindow(workbench) +{ + setObjectName(QLatin1String("ActionEditor")); + QDesignerActionEditorInterface *widget = QDesignerComponents::createActionEditor(workbench->core(), this); + workbench->core()->setActionEditor(widget); + + setCentralWidget(widget); + + setWindowTitle(tr("Action Editor")); +} + +QDesignerActionEditor::~QDesignerActionEditor() +{ +} + +QRect QDesignerActionEditor::geometryHint() const +{ + QRect g = workbench()->availableGeometry(); + int margin = workbench()->marginHint(); + + QSize sz(g.width() * 1/4, g.height() * 1/6); + + return QRect((g.width() - sz.width() - margin), margin, + sz.width(), sz.height()); +} diff --git a/src/designer/formdesigner/qdesigner_actioneditor.h b/src/designer/formdesigner/qdesigner_actioneditor.h new file mode 100644 index 0000000..a940ccf --- /dev/null +++ b/src/designer/formdesigner/qdesigner_actioneditor.h @@ -0,0 +1,41 @@ +/**************************************************************************** +** +** Copyright (C) 1992-2006 Trolltech ASA. All rights reserved. +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** This file may be used under the terms of the GNU General Public +** License version 2.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of +** this file. Please review the following information to ensure GNU +** General Public Licensing requirements will be met: +** http://www.trolltech.com/products/qt/opensource.html +** +** If you are unsure which license is appropriate for your use, please +** review the following information: +** http://www.trolltech.com/products/qt/licensing.html or contact the +** sales department at sales@trolltech.com. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +****************************************************************************/ + +#ifndef QDESIGNER_ACTIONEDITOR_H +#define QDESIGNER_ACTIONEDITOR_H + +#include "qdesigner_toolwindow.h" + +class QDesignerWorkbench; + +class QDesignerActionEditor: public QDesignerToolWindow +{ + Q_OBJECT +public: + QDesignerActionEditor(QDesignerWorkbench *workbench); + virtual ~QDesignerActionEditor(); + + virtual QRect geometryHint() const; +}; + +#endif // QDESIGNER_ACTIONEDITOR_H diff --git a/src/designer/formdesigner/qdesigner_actions.cpp b/src/designer/formdesigner/qdesigner_actions.cpp new file mode 100644 index 0000000..6ff32fd --- /dev/null +++ b/src/designer/formdesigner/qdesigner_actions.cpp @@ -0,0 +1,998 @@ +/**************************************************************************** +** +** Copyright (C) 1992-2006 Trolltech ASA. All rights reserved. +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** This file may be used under the terms of the GNU General Public +** License version 2.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of +** this file. Please review the following information to ensure GNU +** General Public Licensing requirements will be met: +** http://www.trolltech.com/products/qt/opensource.html +** +** If you are unsure which license is appropriate for your use, please +** review the following information: +** http://www.trolltech.com/products/qt/licensing.html or contact the +** sales department at sales@trolltech.com. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +****************************************************************************/ + +//#include "qdesigner.h" +#include "qdesigner_toolwindow.h" +#include "qdesigner_actions.h" +#include "qdesigner_workbench.h" +#include "qdesigner_formwindow.h" +#include "qdesigner_settings.h" +#include "newform.h" +//#include "versiondialog.h" +//#include "oublietteview.h" +#include "saveformastemplate.h" +#include "plugindialog.h" +#include "formwindowsettings.h" + +// sdk +#include +#include "private/qdesigner_formbuilder_p.h" +#include "private/qtundo_p.h" +#include "private/pluginmanager_p.h" + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +QDesignerActions::QDesignerActions(QDesignerWorkbench *workbench) + : QObject(workbench), + m_workbench(workbench), m_assistantClient(0), m_openDirectory(QString()) +{ + Q_ASSERT(m_workbench != 0); + + m_core = m_workbench->core(); + Q_ASSERT(m_core != 0); + + QDesignerFormWindowManagerInterface *formWindowManager = m_core->formWindowManager(); + Q_ASSERT(formWindowManager != 0); + + QDesignerSettings settings; + m_fileActions = new QActionGroup(this); + m_fileActions->setExclusive(false); + + m_recentFilesActions = new QActionGroup(this); + m_recentFilesActions->setExclusive(false); + + m_editActions = new QActionGroup(this); + m_editActions->setExclusive(false); + + m_formActions = new QActionGroup(this); + m_formActions->setExclusive(false); + + m_windowActions = new QActionGroup(this); + m_windowActions->setExclusive(false); + + m_toolActions = new QActionGroup(this); + m_toolActions->setExclusive(true); + + m_helpActions = new QActionGroup(this); + m_helpActions->setExclusive(false); + + +// +// file actions +// + m_newFormAction = new QAction(tr("&New Form..."), this); + m_newFormAction->setShortcut(tr("CTRL+N")); + connect(m_newFormAction, SIGNAL(triggered()), this, SLOT(createForm())); + m_fileActions->addAction(m_newFormAction); + + m_openFormAction = new QAction(tr("&Open Form..."), this); + m_openFormAction->setShortcut(tr("CTRL+O")); + connect(m_openFormAction, SIGNAL(triggered()), this, SLOT(openForm())); + m_fileActions->addAction(m_openFormAction); + + QAction *act; + // Need to insert this into the QAction. + for (int i = 0; i < MaxRecentFiles; ++i) { + act = new QAction(this); + act->setVisible(false); + connect(act, SIGNAL(triggered()), this, SLOT(openRecentForm())); + m_recentFilesActions->addAction(act); + } + updateRecentFileActions(); + + act = new QAction(this); + act->setSeparator(true); + m_recentFilesActions->addAction(act); + + act = new QAction(tr("Clear &Menu"), this); + connect(act, SIGNAL(triggered()), this, SLOT(clearRecentFiles())); + m_recentFilesActions->addAction(act); + + QAction *sep = new QAction(this); + sep->setSeparator(true); + m_fileActions->addAction(sep); + + m_saveFormAction = new QAction(tr("&Save Form"), this); + m_saveFormAction->setShortcut(tr("CTRL+S")); + connect(m_saveFormAction, SIGNAL(triggered()), this, SLOT(saveForm())); + m_fileActions->addAction(m_saveFormAction); + + m_saveFormAsAction = new QAction(tr("Save Form &As..."), this); + connect(m_saveFormAsAction, SIGNAL(triggered()), this, SLOT(saveFormAs())); + m_fileActions->addAction(m_saveFormAsAction); + + m_saveFormAsTemplateAction = new QAction(tr("Save Form As &Template..."), this); + connect(m_saveFormAsTemplateAction, SIGNAL(triggered()), this, SLOT(saveFormAsTemplate())); + m_fileActions->addAction(m_saveFormAsTemplateAction); + + sep = new QAction(this); + sep->setSeparator(true); + m_fileActions->addAction(sep); + + m_closeFormAction = new QAction(tr("&Close Form"), this); + m_closeFormAction->setShortcut(tr("CTRL+W")); + connect(m_closeFormAction, SIGNAL(triggered()), this, SLOT(closeForm())); + m_fileActions->addAction(m_closeFormAction); + + sep = new QAction(this); + sep->setSeparator(true); + m_fileActions->addAction(sep); + + m_quitAction = new QAction(tr("&Quit"), this); + m_quitAction->setShortcut(tr("CTRL+Q")); + connect(m_quitAction, SIGNAL(triggered()), + this, SLOT(shutdown())); + m_fileActions->addAction(m_quitAction); + +// +// edit actions +// + m_undoAction = formWindowManager->actionUndo(); + m_undoAction->setShortcut(tr("CTRL+Z")); + m_editActions->addAction(m_undoAction); + + m_redoAction = formWindowManager->actionRedo(); + m_redoAction->setShortcut(tr("CTRL+SHIFT+Z")); + m_editActions->addAction(m_redoAction); + + sep = new QAction(this); + sep->setSeparator(true); + m_editActions->addAction(sep); + + m_cutAction = formWindowManager->actionCut(); + m_editActions->addAction(m_cutAction); + + m_copyAction = formWindowManager->actionCopy(); + m_editActions->addAction(m_copyAction); + + m_pasteAction = formWindowManager->actionPaste(); + m_editActions->addAction(m_pasteAction); + + m_deleteAction = formWindowManager->actionDelete(); + m_editActions->addAction(m_deleteAction); + + m_selectAllAction = formWindowManager->actionSelectAll(); + m_editActions->addAction(m_selectAllAction); + + sep = new QAction(this); + sep->setSeparator(true); + m_editActions->addAction(sep); + + m_sendToBackAction = formWindowManager->actionLower(); + m_editActions->addAction(m_sendToBackAction); + + m_bringToFrontAction = formWindowManager->actionRaise(); + m_editActions->addAction(m_bringToFrontAction); + +// +// edit mode actions +// + + m_editWidgetsAction = new QAction(tr("Edit Widgets"), this); + m_editWidgetsAction->setCheckable(true); + m_editWidgetsAction->setShortcut(tr("F3")); + m_editWidgetsAction->setIcon(QIcon(m_core->resourceLocation() + QLatin1String("/widgettool.png"))); + connect(formWindowManager, SIGNAL(activeFormWindowChanged(QDesignerFormWindowInterface*)), + this, SLOT(activeFormWindowChanged(QDesignerFormWindowInterface*))); + connect(m_editWidgetsAction, SIGNAL(triggered()), this, SLOT(editWidgetsSlot())); + m_toolActions->addAction(m_editWidgetsAction); + m_editWidgetsAction->setChecked(true); + m_editWidgetsAction->setEnabled(false); + QList builtinPlugins = QPluginLoader::staticInstances(); + builtinPlugins += m_core->pluginManager()->instances(); + foreach (QObject *plugin, builtinPlugins) { + if (QDesignerFormEditorPluginInterface *formEditorPlugin = qobject_cast(plugin)) { + m_toolActions->addAction(formEditorPlugin->action()); + formEditorPlugin->action()->setCheckable(true); + } + } + + m_uiMode = new QActionGroup(this); + m_uiMode->setExclusive(true); + + m_sdiAction = m_uiMode->addAction(tr("Multiple Top-Level Windows")); + m_sdiAction->setCheckable(true); + + m_dockedMdiAction = m_uiMode->addAction(tr("Docked Window")); + m_dockedMdiAction->setCheckable(true); + + switch (settings.uiMode()) { + default: Q_ASSERT(0); break; + + case QDesignerWorkbench::TopLevelMode: + m_sdiAction->setChecked(true); + break; + case QDesignerWorkbench::DockedMode: + m_dockedMdiAction->setChecked(true); + break; + } + + connect(m_uiMode, SIGNAL(triggered(QAction*)), this, SLOT(updateUIMode(QAction*))); + +// +// form actions +// + m_layoutHorizontallyAction = formWindowManager->actionHorizontalLayout(); + m_formActions->addAction(m_layoutHorizontallyAction); + + m_layoutVerticallyAction = formWindowManager->actionVerticalLayout(); + m_formActions->addAction(m_layoutVerticallyAction); + + m_layoutHorizontallyInSplitterAction = formWindowManager->actionSplitHorizontal(); + m_formActions->addAction(m_layoutHorizontallyInSplitterAction); + + m_layoutVerticallyInSplitterAction = formWindowManager->actionSplitVertical(); + m_formActions->addAction(m_layoutVerticallyInSplitterAction); + + m_layoutGridAction = formWindowManager->actionGridLayout(); + m_formActions->addAction(m_layoutGridAction); + + m_breakLayoutAction = formWindowManager->actionBreakLayout(); + m_formActions->addAction(m_breakLayoutAction); + + m_adjustSizeAction = formWindowManager->actionAdjustSize(); + m_formActions->addAction(m_adjustSizeAction); + + sep = new QAction(this); + sep->setSeparator(true); + + m_formActions->addAction(sep); + + m_previewFormAction = new QAction(tr("&Preview"), this); + m_previewFormAction->setShortcut(tr("CTRL+R")); + connect(m_previewFormAction, SIGNAL(triggered()), this, SLOT(previewFormLater())); + m_formActions->addAction(m_previewFormAction); + + m_styleActions = new QActionGroup(this); + m_styleActions->setExclusive(true); + connect(m_styleActions, SIGNAL(triggered(QAction*)), this, SLOT(previewForm(QAction*))); + + QAction *sep2 = new QAction(this); + sep2->setSeparator(true); + m_formActions->addAction(sep2); + + m_formSettings = new QAction(tr("Form &Settings..."), this); + m_formSettings->setEnabled(false); + connect(m_formSettings, SIGNAL(triggered()), this, SLOT(showFormSettings())); + m_formActions->addAction(m_formSettings); + + QStringList availableStyleList = QStyleFactory::keys(); + foreach (QString style, availableStyleList) { + QAction *a = new QAction(this); + a->setText(tr("%1 Style").arg(style)); + a->setObjectName(QLatin1String("__qt_action_style_") + style); + + m_styleActions->addAction(a); + } + +// +// window actions +// + m_minimizeAction = new QAction(tr("&Minimize"), this); + m_minimizeAction->setEnabled(false); + m_minimizeAction->setShortcut(tr("CTRL+M")); + connect(m_minimizeAction, SIGNAL(triggered()), this, SLOT(minimizeForm())); + m_windowActions->addAction(m_minimizeAction); + + sep = new QAction(this); + sep->setSeparator(true); + m_windowActions->addAction(sep); + + m_bringToFrontAction = new QAction(tr("Bring All to Front"), this); + connect(m_bringToFrontAction, SIGNAL(triggered()), this, SLOT(bringAllToFront())); + m_windowActions->addAction(m_bringToFrontAction); + +// +// Help actions +// + + m_mainHelpAction = new QAction(tr("Qt Designer &Help"), this); + connect(m_mainHelpAction, SIGNAL(triggered()), this, SLOT(showDesignerHelp())); + m_mainHelpAction->setShortcut(Qt::CTRL + Qt::Key_Question); + m_helpActions->addAction(m_mainHelpAction); + + sep = new QAction(this); + sep->setSeparator(true); + m_helpActions->addAction(sep); + + m_widgetHelp = new QAction(tr("Current Widget Help"), this); + m_widgetHelp->setShortcut(Qt::Key_F1); + connect(m_widgetHelp, SIGNAL(triggered()), this, SLOT(showWidgetSpecificHelp())); + m_helpActions->addAction(m_widgetHelp); + + sep = new QAction(this); + sep->setSeparator(true); + m_helpActions->addAction(sep); + + m_whatsNewAction = new QAction(tr("What's New in Qt Designer?"), this); + connect(m_whatsNewAction, SIGNAL(triggered()), this, SLOT(showWhatsNew())); + m_helpActions->addAction(m_whatsNewAction); + + // On Mac OS X, the about items are merged in so this separator is redundant. +#ifndef Q_WS_MAC + sep = new QAction(this); + sep->setSeparator(true); + m_helpActions->addAction(sep); + m_aboutPluginsAction = new QAction(tr("About Plugins"), this); +#else + m_aboutPluginsAction = new QAction(tr("Plugin Information"), this); +#endif + connect(m_aboutPluginsAction, SIGNAL(triggered()), this, SLOT(aboutPlugins())); + m_helpActions->addAction(m_aboutPluginsAction); + + m_aboutDesignerAction = new QAction(tr("About Qt Designer"), this); + connect(m_aboutDesignerAction, SIGNAL(triggered()), this, SLOT(aboutDesigner())); + m_helpActions->addAction(m_aboutDesignerAction); + + m_aboutQtAction = new QAction(tr("About Qt"), this); + connect(m_aboutQtAction, SIGNAL(triggered()), qApp, SLOT(aboutQt())); + m_helpActions->addAction(m_aboutQtAction); +// +// connections +// + fixActionContext(); + activeFormWindowChanged(core()->formWindowManager()->activeFormWindow()); +} + +QDesignerActions::~QDesignerActions() +{ +} + +QActionGroup *QDesignerActions::toolActions() const +{ return m_toolActions; } + +QDesignerWorkbench *QDesignerActions::workbench() const +{ return m_workbench; } + +QDesignerFormEditorInterface *QDesignerActions::core() const +{ return m_core; } + +QActionGroup *QDesignerActions::fileActions() const +{ return m_fileActions; } + +QActionGroup *QDesignerActions::editActions() const +{ return m_editActions; } + +QActionGroup *QDesignerActions::formActions() const +{ return m_formActions; } + +QActionGroup *QDesignerActions::windowActions() const +{ return m_windowActions; } + +QActionGroup *QDesignerActions::helpActions() const +{ return m_helpActions; } + +QActionGroup *QDesignerActions::styleActions() const +{ return m_styleActions; } + +QAction *QDesignerActions::newFormAction() const +{ return m_newFormAction; } + +QAction *QDesignerActions::openFormAction() const +{ return m_openFormAction; } + +QAction *QDesignerActions::saveFormAction() const +{ return m_saveFormAction; } + +QAction *QDesignerActions::saveFormAsAction() const +{ return m_saveFormAsAction; } + +QAction *QDesignerActions::saveFormAsTemplateAction() const +{ return m_saveFormAsTemplateAction; } + +QAction *QDesignerActions::closeFormAction() const +{ return m_closeFormAction; } + +QAction *QDesignerActions::quitAction() const +{ return m_quitAction; } + +QAction *QDesignerActions::undoAction() const +{ return m_undoAction; } + +QAction *QDesignerActions::redoAction() const +{ return m_redoAction; } + +QAction *QDesignerActions::cutAction() const +{ return m_cutAction; } + +QAction *QDesignerActions::copyAction() const +{ return m_copyAction; } + +QAction *QDesignerActions::pasteAction() const +{ return m_pasteAction; } + +QAction *QDesignerActions::selectAllAction() const +{ return m_selectAllAction; } + +QAction *QDesignerActions::deleteAction() const +{ return m_deleteAction; } + +QAction *QDesignerActions::sendToBackAction() const +{ return m_sendToBackAction; } + +QAction *QDesignerActions::bringToFrontAction() const +{ return m_bringToFrontAction; } + +QAction *QDesignerActions::mainHelpAction() const +{ return m_mainHelpAction; } + +QAction *QDesignerActions::whatsNewAction() const +{ return m_whatsNewAction; } + +QAction *QDesignerActions::aboutQtAction() const +{ return m_aboutQtAction; } + +QAction *QDesignerActions::aboutDesignerAction() const +{ return m_aboutDesignerAction; } + +QAction *QDesignerActions::layoutHorizontallyAction() const +{ return m_layoutHorizontallyAction; } + +QAction *QDesignerActions::layoutVerticallyAction() const +{ return m_layoutVerticallyAction; } + +QAction *QDesignerActions::layoutHorizontallyInSplitterAction() const +{ return m_layoutHorizontallyInSplitterAction; } + +QAction *QDesignerActions::layoutVerticallyInSplitterAction() const +{ return m_layoutVerticallyInSplitterAction; } + +QAction *QDesignerActions::layoutGridAction() const +{ return m_layoutGridAction; } + +QAction *QDesignerActions::breakLayoutAction() const +{ return m_breakLayoutAction; } + +QAction *QDesignerActions::adjustSizeAction() const +{ return m_adjustSizeAction; } + +QAction *QDesignerActions::previewFormAction() const +{ return m_previewFormAction; } + +QAction *QDesignerActions::formSettings() const +{ return m_formSettings; } + +void QDesignerActions::editWidgetsSlot() +{ + QDesignerFormWindowManagerInterface *formWindowManager = core()->formWindowManager(); + for (int i=0; iformWindowCount(); ++i) { + QDesignerFormWindowInterface *formWindow = formWindowManager->formWindow(i); + formWindow->editWidgets(); + } +} + +void QDesignerActions::createForm() +{ + NewForm *dlg = new NewForm(workbench(), 0); + dlg->setAttribute(Qt::WA_DeleteOnClose); + dlg->setAttribute(Qt::WA_ShowModal); + dlg->show(); +} + +bool QDesignerActions::openForm() +{ + QString fileName = QFileDialog::getOpenFileName( + core()->topLevel(), + tr("Open Form"), m_openDirectory, + tr("Designer UI files (*.ui)"), 0, QFileDialog::DontUseSheet); + + if (!fileName.isEmpty()) { + return readInForm(fileName); + } + return false; +} + +bool QDesignerActions::saveFormAs(QDesignerFormWindowInterface *fw) +{ + QString fileName = fw->fileName().isEmpty() ? QDir::current().absolutePath() + + QLatin1String("/untitled.ui") : fw->fileName(); + QString saveFile = QFileDialog::getSaveFileName(fw, tr("Save form as"), + fileName, + tr("Designer UI files (*.ui)")); + if (saveFile.isEmpty()) + return false; + + if (QFileInfo(saveFile).suffix() != QLatin1String("ui")) + saveFile.append(QLatin1String(".ui")); + + fw->setFileName(saveFile); + return writeOutForm(fw, saveFile); +} + +void QDesignerActions::saveForm() +{ + if (QDesignerFormWindowInterface *fw = core()->formWindowManager()->activeFormWindow()) + saveForm(fw); +} + +bool QDesignerActions::saveForm(QDesignerFormWindowInterface *fw) +{ + bool ret; + if (fw->fileName().isEmpty()) + ret = saveFormAs(fw); + else + ret = writeOutForm(fw, fw->fileName()); + return ret; +} + +void QDesignerActions::closeForm() +{ + if (QDesignerFormWindowInterface *fw = core()->formWindowManager()->activeFormWindow()) + fw->parentWidget()->close(); +} + +void QDesignerActions::saveFormAs() +{ + if (QDesignerFormWindowInterface *fw = core()->formWindowManager()->activeFormWindow()) + saveFormAs(fw); +} + +void QDesignerActions::saveFormAsTemplate() +{ + if (QDesignerFormWindowInterface *fw = core()->formWindowManager()->activeFormWindow()) { + SaveFormAsTemplate dlg(fw, fw->window()); + dlg.exec(); + } +} + +void QDesignerActions::notImplementedYet() +{ + QMessageBox::information(core()->topLevel(), tr("Designer"), tr("Feature not implemented yet!")); +} + +void QDesignerActions::updateUIMode(QAction *act) +{ + QDesignerWorkbench::UIMode mode = QDesignerWorkbench::TopLevelMode; + if (act == m_dockedMdiAction) + mode = QDesignerWorkbench::DockedMode; + + QDesignerSettings settings; + settings.setUIMode(mode); + + m_workbench->setUIMode(QDesignerWorkbench::UIMode(settings.uiMode())); +} + +void QDesignerActions::previewFormLater(QAction *action) +{ + qRegisterMetaType("QAction*"); + QMetaObject::invokeMethod(this, "previewForm", Qt::QueuedConnection, + Q_ARG(QAction*, action)); +} + +void QDesignerActions::previewForm(QAction *action) +{ +//return; + + if (QDesignerFormWindowInterface *fw = core()->formWindowManager()->activeFormWindow()) { + qdesigner_internal::QDesignerFormBuilder builder(core(), qdesigner_internal::QDesignerFormBuilder::DisableScripts); + builder.setWorkingDirectory(fw->absoluteDir()); + + QByteArray bytes = fw->contents().toUtf8(); + QBuffer buffer(&bytes); + + QWidget *widget = builder.load(&buffer, 0); + Q_ASSERT(widget); + + + widget->setParent(fw->window(), Qt::Dialog); + widget->setWindowModality(Qt::ApplicationModal); + widget->setAttribute(Qt::WA_DeleteOnClose, true); + widget->move(fw->mapToGlobal(QPoint(0, 0)) + QPoint(10, 10)); + + QStyle *style = 0; + + if (action != 0 && action->objectName().startsWith(QLatin1String("__qt_action_style_"))) { + QString styleName = action->objectName().mid(QString::fromUtf8("__qt_action_style_").count()); + style = QStyleFactory::create(styleName); + + if (style != 0) { + style->setParent(widget); + widget->setStyle(style); + widget->setPalette(style->standardPalette()); + QList lst = qFindChildren(widget); + foreach (QWidget *w, lst) { + if (w->windowType() == Qt::Popup) + w->setPalette(style->standardPalette()); + w->setStyle(style); + } + } + } + + widget->setWindowTitle(tr("%1 - [Preview]").arg(widget->windowTitle())); + + widget->show(); + } +} + +void QDesignerActions::fixActionContext() +{ + QList actions; + actions += m_fileActions->actions(); + actions += m_editActions->actions(); + actions += m_toolActions->actions(); + actions += m_formActions->actions(); + actions += m_windowActions->actions(); + actions += m_helpActions->actions(); + + foreach (QAction *a, actions) { + a->setShortcutContext(Qt::ApplicationShortcut); + } +} + +bool QDesignerActions::readInForm(const QString &fileName) +{ + // First make sure that we don't have this one open already. + QDesignerFormWindowManagerInterface *formWindowManager = core()->formWindowManager(); + int totalWindows = formWindowManager->formWindowCount(); + for (int i = 0; i < totalWindows; ++i) { + QDesignerFormWindowInterface *w = formWindowManager->formWindow(i); + if (w->fileName() == fileName) { + w->raise(); + formWindowManager->setActiveFormWindow(w); + addRecentFile(fileName); + return true; + } + } + + // Otherwise load it. + QFile f(fileName); + if (!f.open(QFile::ReadOnly)) { + QMessageBox::warning(core()->topLevel(), tr("Read Error"), tr("Couldn't open file: %1\nReason: %2") + .arg(f.fileName()).arg(f.errorString())); + return false; + } + + m_openDirectory = QFileInfo(f).absolutePath(); + + QDesignerFormWindow *formWindow = workbench()->createFormWindow(); + if (QDesignerFormWindowInterface *editor = formWindow->editor()) { + editor->setFileName(fileName); + editor->setContents(&f); + Q_ASSERT(editor->mainContainer() != 0); + formWindow->updateWindowTitle(fileName); + formWindow->resize(editor->mainContainer()->size()); + formWindowManager->setActiveFormWindow(editor); + } + formWindow->show(); + addRecentFile(fileName); + formWindow->editor()->setDirty(false); + return true; +} + +bool QDesignerActions::writeOutForm(QDesignerFormWindowInterface *fw, const QString &saveFile) +{ + Q_ASSERT(fw && !saveFile.isEmpty()); + QFile f(saveFile); + while (!f.open(QFile::WriteOnly)) { + QMessageBox box(tr("Save Form?"), + tr("Could not open file: %1" + "\nReason: %2" + "\nWould you like to retry or change your file?") + .arg(f.fileName()).arg(f.errorString()), + QMessageBox::Warning, + QMessageBox::Yes | QMessageBox::Default, QMessageBox::No, + QMessageBox::Cancel | QMessageBox::Escape, fw, Qt::Sheet); + box.setButtonText(QMessageBox::Yes, tr("Retry")); + box.setButtonText(QMessageBox::No, tr("Select New File")); + switch(box.exec()) { + case QMessageBox::Yes: + break; + case QMessageBox::No: { + QString fileName = QFileDialog::getSaveFileName(fw, tr("Save form as"), + QDir::current().absolutePath(), QLatin1String("*.ui")); + if (fileName.isEmpty()) + return false; + f.setFileName(fileName); + fw->setFileName(fileName); + break; } + case QMessageBox::Cancel: + return false; + } + } + QByteArray utf8Array = fw->contents().toUtf8(); + while (f.write(utf8Array, utf8Array.size()) != utf8Array.size()) { + QMessageBox box(tr("Save Form?"), + tr("Could not write file: %1\nReason:%2\nWould you like to retry?") + .arg(f.fileName()).arg(f.errorString()), + QMessageBox::Warning, + QMessageBox::Yes | QMessageBox::Default, QMessageBox::No, 0, + fw, Qt::Sheet); + box.setButtonText(QMessageBox::Yes, tr("Retry")); + box.setButtonText(QMessageBox::No, tr("Don't Retry")); + switch(box.exec()) { + case QMessageBox::Yes: + f.resize(0); + break; + case QMessageBox::No: + return false; + } + } + addRecentFile(saveFile); + fw->setDirty(false); + fw->parentWidget()->setWindowModified(false); + return true; +} + +void QDesignerActions::shutdown() +{ + + // Follow the idea from the Mac, i.e. send the Application a close event + // and if it's accepted, quit. + /*QCloseEvent ev; + QApplication::sendEvent(qDesigner, &ev); + if (ev.isAccepted()) + qDesigner->quit();*/ +} + +void QDesignerActions::activeFormWindowChanged(QDesignerFormWindowInterface *formWindow) +{ + bool enable = formWindow != 0; + + m_saveFormAction->setEnabled(enable); + m_saveFormAsAction->setEnabled(enable); + m_saveFormAsTemplateAction->setEnabled(enable); + m_closeFormAction->setEnabled(enable); + + m_editWidgetsAction->setEnabled(enable); + m_formSettings->setEnabled(enable); + + m_previewFormAction->setEnabled(enable); + m_styleActions->setEnabled(enable); +} + +void QDesignerActions::updateRecentFileActions() +{ + QDesignerSettings settings; + QStringList files = settings.recentFilesList(); + int originalSize = files.size(); + int numRecentFiles = qMin(files.size(), int(MaxRecentFiles)); + QList recentFilesActs = m_recentFilesActions->actions(); + + for (int i = 0; i < numRecentFiles; ++i) { + QFileInfo fi(files[i]); + // If the file doesn't exist anymore, just remove it from the list so + // people don't get confused. + if (!fi.exists()) { + files.removeAt(i); + --i; + numRecentFiles = qMin(files.size(), int(MaxRecentFiles)); + continue; + } + QString text = fi.fileName(); + recentFilesActs[i]->setText(text); + recentFilesActs[i]->setIconText(files[i]); + recentFilesActs[i]->setVisible(true); + } + + for (int j = numRecentFiles; j < MaxRecentFiles; ++j) + recentFilesActs[j]->setVisible(false); + + // If there's been a change, right it back + if (originalSize != files.size()) + settings.setRecentFilesList(files); +} + +void QDesignerActions::openRecentForm() +{ + if (QAction *action = qobject_cast(sender())) { + if (!readInForm(action->iconText())) + updateRecentFileActions(); // File doesn't exist, remove it from settings + } +} + +void QDesignerActions::clearRecentFiles() +{ + QDesignerSettings settings; + settings.setRecentFilesList(QStringList()); + updateRecentFileActions(); +} + +QActionGroup *QDesignerActions::recentFilesActions() const +{ + return m_recentFilesActions; +} + +void QDesignerActions::addRecentFile(const QString &fileName) +{ + QDesignerSettings settings; + QStringList files = settings.recentFilesList(); + files.removeAll(fileName); + files.prepend(fileName); + while (files.size() > MaxRecentFiles) + files.removeLast(); + + settings.setRecentFilesList(files); + updateRecentFileActions(); +} + +void QDesignerActions::minimizeForm() +{ + if (QDesignerFormWindowInterface *fw = core()->formWindowManager()->activeFormWindow()) { + if (m_workbench->mode() == QDesignerWorkbench::DockedMode) { + // Yuck, I need to get to the QWorkspaceChild::showShaded(), but there is no way + // to do that legally, so I use the QMetaObject as my guide. + QMetaObject::invokeMethod(fw->parentWidget()->parentWidget(), "showShaded"); + } else { + fw->parentWidget()->showMinimized(); + } + } +} + +void QDesignerActions::bringAllToFront() +{ + int i; + for (i = 0; i < m_workbench->formWindowCount(); ++i) + m_workbench->formWindow(i)->raise(); + + for (i = 0; i < m_workbench->toolWindowCount(); ++i) + m_workbench->toolWindow(i)->raise(); +} + +QAction *QDesignerActions::minimizeAction() const +{ + return m_minimizeAction; +} + +QAction *QDesignerActions::bringAllToFront() const +{ + return m_bringToFrontAction; +} + +void QDesignerActions::showDesignerHelp() +{ + showHelp(QLatin1String("designer-manual.html")); +} + +void QDesignerActions::showWhatsNew() +{ + showHelp(QLatin1String("qt4-designer.html")); +} + +void QDesignerActions::showHelp(const QString &url) +{ + /*if (!m_assistantClient) + m_assistantClient + = new QAssistantClient(QLibraryInfo::location(QLibraryInfo::BinariesPath), this); + + QString filePath = QLibraryInfo::location(QLibraryInfo::DocumentationPath) + + QLatin1String("/html/") + url; + + QString cleanFilePath; + int index = filePath.lastIndexOf(QLatin1Char('#')); + if (index != -1) + cleanFilePath = filePath.left(index); + else + cleanFilePath = filePath; + + if (!QFile::exists(cleanFilePath)) { + filePath = QLibraryInfo::location(QLibraryInfo::DocumentationPath) + + QLatin1String("/html/designer-manual.html"); + } + + m_assistantClient->showPage(filePath);*/ +} + +void QDesignerActions::aboutDesigner() +{ + /*VersionDialog mb(core()->topLevel()); + mb.setWindowTitle(tr("About Qt Designer")); + if (mb.exec()) { + OublietteView *oubliette = new OublietteView; + oubliette->setAttribute(Qt::WA_DeleteOnClose); + oubliette->setMinimumSize(800, 600); + oubliette->show(); + }*/ +} + +QActionGroup *QDesignerActions::uiMode() const +{ + return m_uiMode; +} + + +QAction *QDesignerActions::editWidgets() const +{ + return m_editWidgetsAction; +} + +void QDesignerActions::showWidgetSpecificHelp() +{ + QDesignerFormWindowInterface *fw = core()->formWindowManager()->activeFormWindow(); + if (!fw) { + showDesignerHelp(); + return; + } + + QString className; + QString currentPropertyName; + + currentPropertyName = core()->propertyEditor()->currentPropertyName(); + if (!currentPropertyName.isEmpty()) { + QDesignerPropertySheetExtension *ps + = qt_extension(core()->extensionManager(), + core()->propertyEditor()->object()); + if (!ps) + ps = qt_extension(core()->extensionManager(), + fw->cursor()->selectedWidget(0)); + Q_ASSERT(ps); + className = ps->propertyGroup(ps->indexOf(currentPropertyName)); + } else { + QDesignerWidgetDataBaseInterface *db = core()->widgetDataBase(); + QDesignerWidgetDataBaseItemInterface *dbi = db->item(db->indexOfObject(fw->cursor()->selectedWidget(0), true)); + className = dbi->name(); + } + + // ### generalize using the Widget Data Base + if (className == QLatin1String("Line")) + className = QLatin1String("QFrame"); + else if (className == QLatin1String("Spacer")) + className = QLatin1String("QSpacerItem"); + else if (className == QLatin1String("QLayoutWidget")) + className = QLatin1String("QLayout"); + + QString url = className.toLower(); + + // special case + url += QLatin1String(".html"); + + if (!currentPropertyName.isEmpty()) + url += QLatin1Char('#') + currentPropertyName; + + showHelp(url); +} + +QAction *QDesignerActions::widgetHelpAction() const +{ + return m_widgetHelp; +} + +void QDesignerActions::aboutPlugins() +{ + PluginDialog dlg(core(), core()->topLevel()); + dlg.exec(); +} + +void QDesignerActions::showFormSettings() +{ + QDesignerFormWindowInterface *formWindow = core()->formWindowManager()->activeFormWindow(); + QDesignerFormWindow *window = m_workbench->findFormWindow(formWindow); + FormWindowSettings dlg(formWindow); + if (dlg.exec() && window) { + formWindow->setDirty(true); + window->updateChanged(); + } +} diff --git a/src/designer/formdesigner/qdesigner_actions.h b/src/designer/formdesigner/qdesigner_actions.h new file mode 100644 index 0000000..9cbdcee --- /dev/null +++ b/src/designer/formdesigner/qdesigner_actions.h @@ -0,0 +1,223 @@ +/**************************************************************************** +** +** Copyright (C) 1992-2006 Trolltech ASA. All rights reserved. +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** This file may be used under the terms of the GNU General Public +** License version 2.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of +** this file. Please review the following information to ensure GNU +** General Public Licensing requirements will be met: +** http://www.trolltech.com/products/qt/opensource.html +** +** If you are unsure which license is appropriate for your use, please +** review the following information: +** http://www.trolltech.com/products/qt/licensing.html or contact the +** sales department at sales@trolltech.com. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +****************************************************************************/ + +#ifndef QDESIGNER_ACTIONS_H +#define QDESIGNER_ACTIONS_H + +#include +#include +#include + +class QDesignerMainWindow; +class QDesignerWorkbench; + +class QAction; +class QActionGroup; +class QDesignerFormEditorInterface; +class QDesignerFormWindowInterface; +class QAssistantClient; + +class QDesignerActions: public QObject +{ + Q_OBJECT +public: + QDesignerActions(QDesignerWorkbench *mainWindow); + virtual ~QDesignerActions(); + + QDesignerWorkbench *workbench() const; + QDesignerFormEditorInterface *core() const; + + bool saveForm(QDesignerFormWindowInterface *fw); + bool readInForm(const QString &fileName); + bool writeOutForm(QDesignerFormWindowInterface *formWindow, const QString &fileName); + + QActionGroup *fileActions() const; + QActionGroup *recentFilesActions() const; + QActionGroup *editActions() const; + QActionGroup *formActions() const; + QActionGroup *windowActions() const; + QActionGroup *toolActions() const; + QActionGroup *helpActions() const; + QActionGroup *uiMode() const; + QActionGroup *styleActions() const; + +// +// file actions +// + QAction *newFormAction() const; + QAction *openFormAction() const; + QAction *saveFormAction() const; + QAction *saveFormAsAction() const; + QAction *saveFormAsTemplateAction() const; + QAction *closeFormAction() const; + QAction *quitAction() const; + +// +// edit actions +// + QAction *undoAction() const; + QAction *redoAction() const; + QAction *cutAction() const; + QAction *copyAction() const; + QAction *pasteAction() const; + QAction *deleteAction() const; + QAction *selectAllAction() const; + QAction *sendToBackAction() const; + QAction *bringToFrontAction() const; + +// +// edit mode actions +// + QAction *editWidgets() const; + QAction *editConnections() const; + QAction *editTabOrders() const; + QAction *editBuddies() const; + +// +// form actions +// + QAction *layoutHorizontallyAction() const; + QAction *layoutVerticallyAction() const; + QAction *layoutHorizontallyInSplitterAction() const; + QAction *layoutVerticallyInSplitterAction() const; + QAction *layoutGridAction() const; + QAction *breakLayoutAction() const; + QAction *adjustSizeAction() const; + QAction *previewFormAction() const; + QAction *formSettings() const; + +// +// window actions +// + QAction *minimizeAction() const; + QAction *bringAllToFront() const; + +// +// help actions +// + QAction *mainHelpAction() const; + QAction *widgetHelpAction() const; + QAction *whatsNewAction() const; + QAction *aboutQtAction() const; + QAction *aboutDesignerAction() const; + +public slots: + void activeFormWindowChanged(QDesignerFormWindowInterface *formWindow); + void createForm(); + bool openForm(); + +signals: + void useBigIcons(bool); + +private slots: + void saveForm(); + void saveFormAs(); + void saveFormAsTemplate(); + void previewForm(QAction *action = 0); + void previewFormLater(QAction *action = 0); + void notImplementedYet(); + void shutdown(); + void editWidgetsSlot(); + void openRecentForm(); + void clearRecentFiles(); + void closeForm(); + void minimizeForm(); + void bringAllToFront(); + void showDesignerHelp(); + void showWhatsNew(); + void aboutPlugins(); + void aboutDesigner(); + void updateUIMode(QAction *act); + void showWidgetSpecificHelp(); + void showFormSettings(); + +private: + bool saveFormAs(QDesignerFormWindowInterface *fw); + void fixActionContext(); + void updateRecentFileActions(); + void addRecentFile(const QString &fileName); + void showHelp(const QString &help); + +private: + enum { MaxRecentFiles = 10 }; + QDesignerWorkbench *m_workbench; + QDesignerFormEditorInterface *m_core; + QAssistantClient *m_assistantClient; + QString m_openDirectory; + + QActionGroup *m_fileActions; + QActionGroup *m_recentFilesActions; + QActionGroup *m_editActions; + QActionGroup *m_formActions; + QActionGroup *m_windowActions; + QActionGroup *m_toolActions; + QActionGroup *m_helpActions; + QActionGroup *m_uiMode; + QActionGroup *m_styleActions; + + QAction *m_editWidgetsAction; + + QAction *m_newFormAction; + QAction *m_openFormAction; + QAction *m_saveFormAction; + QAction *m_saveFormAsAction; + QAction *m_saveFormAsTemplateAction; + QAction *m_closeFormAction; + + QAction *m_quitAction; + QAction *m_undoAction; + QAction *m_redoAction; + QAction *m_cutAction; + QAction *m_copyAction; + QAction *m_pasteAction; + QAction *m_deleteAction; + QAction *m_sendToBackAction; + QAction *m_bringToFrontAction; + QAction *m_selectAllAction; + + + QAction *m_layoutHorizontallyAction; + QAction *m_layoutVerticallyAction; + QAction *m_layoutHorizontallyInSplitterAction; + QAction *m_layoutVerticallyInSplitterAction; + QAction *m_layoutGridAction; + QAction *m_breakLayoutAction; + QAction *m_adjustSizeAction; + QAction *m_previewFormAction; + QAction *m_formSettings; + + QAction *m_minimizeAction; + QAction *m_bringAllToFrontAction; + + QAction *m_mainHelpAction; + QAction *m_widgetHelp; + QAction *m_whatsNewAction; + QAction *m_aboutQtAction; + QAction *m_aboutPluginsAction; + QAction *m_aboutDesignerAction; + QAction *m_sdiAction; + QAction *m_dockedMdiAction; +}; + +#endif // QDESIGNER_ACTIONS_H + diff --git a/src/designer/formdesigner/qdesigner_formwindow.cpp b/src/designer/formdesigner/qdesigner_formwindow.cpp new file mode 100644 index 0000000..0081f49 --- /dev/null +++ b/src/designer/formdesigner/qdesigner_formwindow.cpp @@ -0,0 +1,180 @@ +/**************************************************************************** +** +** Copyright (C) 1992-2006 Trolltech ASA. All rights reserved. +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** This file may be used under the terms of the GNU General Public +** License version 2.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of +** this file. Please review the following information to ensure GNU +** General Public Licensing requirements will be met: +** http://www.trolltech.com/products/qt/opensource.html +** +** If you are unsure which license is appropriate for your use, please +** review the following information: +** http://www.trolltech.com/products/qt/licensing.html or contact the +** sales department at sales@trolltech.com. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +****************************************************************************/ + +#include "qdesigner_actions.h" +#include "qdesigner_formwindow.h" +#include "qdesigner_workbench.h" +#include "qdesigner_settings.h" + +// sdk +#include + +// shared +#include "private/qtundo_p.h" + +#include +#include +#include +#include + +#include +#include +#include +#include + +QDesignerFormWindow::QDesignerFormWindow(QDesignerFormWindowInterface *editor, QDesignerWorkbench *workbench, QWidget *parent, Qt::WindowFlags flags) + : QMainWindow(parent, flags), + m_editor(editor), + m_workbench(workbench) +{ + Q_ASSERT(workbench); + + if (m_editor) { + m_editor->setParent(this); + } else { + m_editor = workbench->core()->formWindowManager()->createFormWindow(this); + } + + setCentralWidget(m_editor); + + m_action = new QAction(this); + m_action->setCheckable(true); + + connect((QObject*)m_editor->commandHistory(), SIGNAL(commandExecuted()), this, SLOT(updateChanged())); + connect(m_editor, SIGNAL(fileNameChanged(QString)), this, SLOT(updateWindowTitle(QString))); +} + +QDesignerFormWindow::~QDesignerFormWindow() +{ + if (workbench()) + workbench()->removeFormWindow(this); +} + +QAction *QDesignerFormWindow::action() const +{ + return m_action; +} + +void QDesignerFormWindow::changeEvent(QEvent *e) +{ + switch (e->type()) { + case QEvent::ActivationChange: { + if (isActiveWindow()) { + m_action->setChecked(true); + // ### raise(); + } + } break; + case QEvent::WindowTitleChange: + m_action->setText(windowTitle().replace(QLatin1String("[*]"), "")); + break; + case QEvent::WindowIconChange: + m_action->setIcon(windowIcon()); + break; + default: + break; + } + QMainWindow::changeEvent(e); +} + +QRect QDesignerFormWindow::geometryHint() const +{ + return QRect(0, 0, 400, 300); +} + +QDesignerFormWindowInterface *QDesignerFormWindow::editor() const +{ + return m_editor; +} + +QDesignerWorkbench *QDesignerFormWindow::workbench() const +{ + return m_workbench; +} + +void QDesignerFormWindow::updateWindowTitle(const QString &fileName) +{ + QString fn = fileName; + + if (fn.isEmpty()) { + // Try to preserve its "untitled" number. + QRegExp rx(QLatin1String("unnamed( (\\d+))?")); + + if (rx.indexIn(windowTitle()) != -1) { + fn = rx.cap(0); + } else { + fn = QLatin1String("untitled"); + } + } + + if (QWidget *mc = m_editor->mainContainer()) { + setWindowIcon(mc->windowIcon()); + setWindowTitle(tr("%1 - %2[*]").arg(mc->windowTitle()).arg(fn)); + } else { + setWindowTitle(fn); + } +} + +void QDesignerFormWindow::closeEvent(QCloseEvent *ev) +{ + if (m_editor->isDirty()) { +// Сохраняем автоматически + bool ok = workbench()->saveForm(m_editor); + ev->setAccepted(ok); + m_editor->setDirty(!ok); + +/* raise(); + QMessageBox box(tr("Save Form?"), + tr("Do you want to save the changes you made to \"%1\" before closing?") + .arg(m_editor->fileName().isEmpty() ? action()->text() : m_editor->fileName()), + QMessageBox::Information, + QMessageBox::Yes | QMessageBox::Default, QMessageBox::No, + QMessageBox::Cancel | QMessageBox::Escape, m_editor, Qt::Sheet); + box.setButtonText(QMessageBox::Yes, m_editor->fileName().isEmpty() ? tr("Save...") : tr("Save")); + box.setButtonText(QMessageBox::No, tr("Don't Save")); + switch (box.exec()) { + case QMessageBox::Yes: { + bool ok = workbench()->saveForm(m_editor); + ev->setAccepted(ok); + m_editor->setDirty(!ok); + break; + } + case QMessageBox::No: + m_editor->setDirty(false); // Not really necessary, but stops problems if we get close again. + ev->accept(); + break; + case QMessageBox::Cancel: + ev->ignore(); + break; + }*/ + } + + if (m_workbench->core()->formWindowManager()->formWindowCount() == 1 && ev->isAccepted() + && QDesignerSettings().showNewFormOnStartup()) + QTimer::singleShot(200, m_workbench->actionManager(), SLOT(createForm())); // Use timer in case we are quitting. +} + +void QDesignerFormWindow::updateChanged() +{ + setWindowModified(m_editor->isDirty()); + updateWindowTitle(m_editor->fileName()); +} diff --git a/src/designer/formdesigner/qdesigner_formwindow.h b/src/designer/formdesigner/qdesigner_formwindow.h new file mode 100644 index 0000000..61e7af2 --- /dev/null +++ b/src/designer/formdesigner/qdesigner_formwindow.h @@ -0,0 +1,62 @@ +/**************************************************************************** +** +** Copyright (C) 1992-2006 Trolltech ASA. All rights reserved. +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** This file may be used under the terms of the GNU General Public +** License version 2.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of +** this file. Please review the following information to ensure GNU +** General Public Licensing requirements will be met: +** http://www.trolltech.com/products/qt/opensource.html +** +** If you are unsure which license is appropriate for your use, please +** review the following information: +** http://www.trolltech.com/products/qt/licensing.html or contact the +** sales department at sales@trolltech.com. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +****************************************************************************/ + +#ifndef QDESIGNER_FORMWINDOW_H +#define QDESIGNER_FORMWINDOW_H + +#include +#include + +class QDesignerWorkbench; +class QDesignerFormWindowInterface; + +class QDesignerFormWindow: public QMainWindow +{ + Q_OBJECT +public: + QDesignerFormWindow(QDesignerFormWindowInterface *formWindow, QDesignerWorkbench *workbench, + QWidget *parent = 0, Qt::WindowFlags flags = 0); + + virtual ~QDesignerFormWindow(); + + QAction *action() const; + QDesignerWorkbench *workbench() const; + QDesignerFormWindowInterface *editor() const; + + virtual QRect geometryHint() const; + +public slots: + void updateWindowTitle(const QString &fileName); + void updateChanged(); + +protected: + virtual void changeEvent(QEvent *e); + virtual void closeEvent(QCloseEvent *ev); + +private: + QDesignerFormWindowInterface *m_editor; + QPointer m_workbench; + QAction *m_action; +}; + +#endif // QDESIGNER_FORMWINDOW_H diff --git a/src/designer/formdesigner/qdesigner_objectinspector.cpp b/src/designer/formdesigner/qdesigner_objectinspector.cpp new file mode 100644 index 0000000..0a6fa88 --- /dev/null +++ b/src/designer/formdesigner/qdesigner_objectinspector.cpp @@ -0,0 +1,56 @@ +/**************************************************************************** +** +** Copyright (C) 1992-2006 Trolltech ASA. All rights reserved. +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** This file may be used under the terms of the GNU General Public +** License version 2.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of +** this file. Please review the following information to ensure GNU +** General Public Licensing requirements will be met: +** http://www.trolltech.com/products/qt/opensource.html +** +** If you are unsure which license is appropriate for your use, please +** review the following information: +** http://www.trolltech.com/products/qt/licensing.html or contact the +** sales department at sales@trolltech.com. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +****************************************************************************/ + +//#include "qdesigner.h" +#include "qdesigner_objectinspector.h" +#include "qdesigner_workbench.h" + +#include +#include + +QDesignerObjectInspector::QDesignerObjectInspector(QDesignerWorkbench *workbench) + : QDesignerToolWindow(workbench) +{ + setObjectName(QLatin1String("ObjectInspector")); + QDesignerObjectInspectorInterface *widget = QDesignerComponents::createObjectInspector(workbench->core(), this); + workbench->core()->setObjectInspector(widget); + + setCentralWidget(widget); + + setWindowTitle(tr("Object Inspector")); +} + +QDesignerObjectInspector::~QDesignerObjectInspector() +{ +} + +QRect QDesignerObjectInspector::geometryHint() const +{ + QRect g = workbench()->availableGeometry(); + int margin = workbench()->marginHint(); + + QSize sz(g.width() * 1/4, g.height() * 1/6); + + return QRect((g.width() - sz.width() - margin), margin, + sz.width(), sz.height()); +} diff --git a/src/designer/formdesigner/qdesigner_objectinspector.h b/src/designer/formdesigner/qdesigner_objectinspector.h new file mode 100644 index 0000000..f6f50e8 --- /dev/null +++ b/src/designer/formdesigner/qdesigner_objectinspector.h @@ -0,0 +1,41 @@ +/**************************************************************************** +** +** Copyright (C) 1992-2006 Trolltech ASA. All rights reserved. +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** This file may be used under the terms of the GNU General Public +** License version 2.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of +** this file. Please review the following information to ensure GNU +** General Public Licensing requirements will be met: +** http://www.trolltech.com/products/qt/opensource.html +** +** If you are unsure which license is appropriate for your use, please +** review the following information: +** http://www.trolltech.com/products/qt/licensing.html or contact the +** sales department at sales@trolltech.com. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +****************************************************************************/ + +#ifndef QDESIGNER_OBJECTINSPECTOR_H +#define QDESIGNER_OBJECTINSPECTOR_H + +#include "qdesigner_toolwindow.h" + +class QDesignerWorkbench; + +class QDesignerObjectInspector: public QDesignerToolWindow +{ + Q_OBJECT +public: + QDesignerObjectInspector(QDesignerWorkbench *workbench); + virtual ~QDesignerObjectInspector(); + + virtual QRect geometryHint() const; +}; + +#endif // QDESIGNER_OBJECTINSPECTOR_H diff --git a/src/designer/formdesigner/qdesigner_pch.h b/src/designer/formdesigner/qdesigner_pch.h new file mode 100644 index 0000000..397a997 --- /dev/null +++ b/src/designer/formdesigner/qdesigner_pch.h @@ -0,0 +1,41 @@ +/**************************************************************************** +** +** Copyright (C) 1992-2006 Trolltech ASA. All rights reserved. +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** This file may be used under the terms of the GNU General Public +** License version 2.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of +** this file. Please review the following information to ensure GNU +** General Public Licensing requirements will be met: +** http://www.trolltech.com/products/qt/opensource.html +** +** If you are unsure which license is appropriate for your use, please +** review the following information: +** http://www.trolltech.com/products/qt/licensing.html or contact the +** sales department at sales@trolltech.com. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +****************************************************************************/ + +#if defined __cplusplus +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "qdesigner.h" +#include "qdesigner_formwindow.h" +#include "qdesigner_settings.h" +#include "qdesigner_toolwindow.h" +#include "qdesigner_workbench.h" +#endif diff --git a/src/designer/formdesigner/qdesigner_propertyeditor.cpp b/src/designer/formdesigner/qdesigner_propertyeditor.cpp new file mode 100644 index 0000000..dbb4cef --- /dev/null +++ b/src/designer/formdesigner/qdesigner_propertyeditor.cpp @@ -0,0 +1,71 @@ +/**************************************************************************** +** +** Copyright (C) 1992-2006 Trolltech ASA. All rights reserved. +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** This file may be used under the terms of the GNU General Public +** License version 2.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of +** this file. Please review the following information to ensure GNU +** General Public Licensing requirements will be met: +** http://www.trolltech.com/products/qt/opensource.html +** +** If you are unsure which license is appropriate for your use, please +** review the following information: +** http://www.trolltech.com/products/qt/licensing.html or contact the +** sales department at sales@trolltech.com. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +****************************************************************************/ + +//#include "qdesigner.h" +#include "qdesigner_propertyeditor.h" +#include "qdesigner_workbench.h" + +#include + +#include +#include + +QDesignerPropertyEditor::QDesignerPropertyEditor(QDesignerWorkbench *workbench) + : QDesignerToolWindow(workbench) +{ + setObjectName(QLatin1String("PropertyEditor")); + QDesignerPropertyEditorInterface *widget = QDesignerComponents::createPropertyEditor(workbench->core(), this); + workbench->core()->setPropertyEditor(widget); + + setCentralWidget(widget); + + setWindowTitle(tr("Property Editor")); + action()->setShortcut(tr("Ctrl+I")); +} + +QDesignerPropertyEditor::~QDesignerPropertyEditor() +{ +} + +QRect QDesignerPropertyEditor::geometryHint() const +{ + QRect g = workbench()->availableGeometry(); + int margin = workbench()->marginHint(); + int spacing = 40; + + QSize sz(g.width() * 1/4, g.height() * 4/6); + + return QRect((g.width() - sz.width() - margin), (margin + g.height() * 1/6) + spacing, + sz.width(), sz.height()); +} + +void QDesignerPropertyEditor::showEvent(QShowEvent *event) +{ + if (QDesignerPropertyEditorInterface *e = workbench()->core()->propertyEditor()) { + // workaround to update the propertyeditor when it is not visible! + e->setObject(e->object()); // ### remove me + } + + QDesignerToolWindow::showEvent(event); +} + diff --git a/src/designer/formdesigner/qdesigner_propertyeditor.h b/src/designer/formdesigner/qdesigner_propertyeditor.h new file mode 100644 index 0000000..2629ff9 --- /dev/null +++ b/src/designer/formdesigner/qdesigner_propertyeditor.h @@ -0,0 +1,44 @@ +/**************************************************************************** +** +** Copyright (C) 1992-2006 Trolltech ASA. All rights reserved. +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** This file may be used under the terms of the GNU General Public +** License version 2.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of +** this file. Please review the following information to ensure GNU +** General Public Licensing requirements will be met: +** http://www.trolltech.com/products/qt/opensource.html +** +** If you are unsure which license is appropriate for your use, please +** review the following information: +** http://www.trolltech.com/products/qt/licensing.html or contact the +** sales department at sales@trolltech.com. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +****************************************************************************/ + +#ifndef QDESIGNER_PROPERTYEDITOR_H +#define QDESIGNER_PROPERTYEDITOR_H + +#include "qdesigner_toolwindow.h" + +class QDesignerWorkbench; + +class QDesignerPropertyEditor: public QDesignerToolWindow +{ + Q_OBJECT +public: + QDesignerPropertyEditor(QDesignerWorkbench *workbench); + virtual ~QDesignerPropertyEditor(); + + virtual QRect geometryHint() const; + +protected: + virtual void showEvent(QShowEvent *event); +}; + +#endif // QDESIGNER_PROPERTYEDITOR_H diff --git a/src/designer/formdesigner/qdesigner_resourceeditor.cpp b/src/designer/formdesigner/qdesigner_resourceeditor.cpp new file mode 100644 index 0000000..770e59d --- /dev/null +++ b/src/designer/formdesigner/qdesigner_resourceeditor.cpp @@ -0,0 +1,62 @@ +/**************************************************************************** +** +** Copyright (C) 1992-2006 Trolltech ASA. All rights reserved. +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** This file may be used under the terms of the GNU General Public +** License version 2.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of +** this file. Please review the following information to ensure GNU +** General Public Licensing requirements will be met: +** http://www.trolltech.com/products/qt/opensource.html +** +** If you are unsure which license is appropriate for your use, please +** review the following information: +** http://www.trolltech.com/products/qt/licensing.html or contact the +** sales department at sales@trolltech.com. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +****************************************************************************/ + +//#include "qdesigner.h" +#include "qdesigner_workbench.h" +#include "qdesigner_resourceeditor.h" +#include "qdesigner_settings.h" + +#include +#include + +#include + + +QDesignerResourceEditor::QDesignerResourceEditor(QDesignerWorkbench *workbench) + : QDesignerToolWindow(workbench) +{ + setObjectName(QLatin1String("ResourceEditor")); + QWidget *widget = QDesignerComponents::createResourceEditor(workbench->core(), this); + + setCentralWidget(widget); + + setWindowTitle(tr("Resource Editor")); +} + +QDesignerResourceEditor::~QDesignerResourceEditor() +{ +} + +QRect QDesignerResourceEditor::geometryHint() const +{ + QRect g = workbench()->availableGeometry(); + int margin = workbench()->marginHint(); + + QSize sz(g.width() * 1/3, g.height() * 1/6); + QRect r(QPoint(0, 0), sz); + r.moveCenter(g.center()); + r.moveBottom(g.bottom() - margin); + + return r; +} + diff --git a/src/designer/formdesigner/qdesigner_resourceeditor.h b/src/designer/formdesigner/qdesigner_resourceeditor.h new file mode 100644 index 0000000..03b9dce --- /dev/null +++ b/src/designer/formdesigner/qdesigner_resourceeditor.h @@ -0,0 +1,42 @@ +/**************************************************************************** +** +** Copyright (C) 1992-2006 Trolltech ASA. All rights reserved. +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** This file may be used under the terms of the GNU General Public +** License version 2.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of +** this file. Please review the following information to ensure GNU +** General Public Licensing requirements will be met: +** http://www.trolltech.com/products/qt/opensource.html +** +** If you are unsure which license is appropriate for your use, please +** review the following information: +** http://www.trolltech.com/products/qt/licensing.html or contact the +** sales department at sales@trolltech.com. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +****************************************************************************/ + +#ifndef QDESIGNER_RESOURCEEDITOR_H +#define QDESIGNER_RESOURCEEDITOR_H + +#include "qdesigner_toolwindow.h" + +class QDesignerWorkbench; +class QDesignerAbstractFormWindowInterface; + +class QDesignerResourceEditor: public QDesignerToolWindow +{ + Q_OBJECT +public: + QDesignerResourceEditor(QDesignerWorkbench *workbench); + virtual ~QDesignerResourceEditor(); + + virtual QRect geometryHint() const; +}; + +#endif // QDESIGNER_RESOURCEEDITOR_H diff --git a/src/designer/formdesigner/qdesigner_settings.cpp b/src/designer/formdesigner/qdesigner_settings.cpp new file mode 100644 index 0000000..643766b --- /dev/null +++ b/src/designer/formdesigner/qdesigner_settings.cpp @@ -0,0 +1,202 @@ +/**************************************************************************** +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** This file may be used under the terms of the GNU General Public +** License version 2.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of +** this file. Please review the following information to ensure GNU +** General Public Licensing requirements will be met: +** http://www.trolltech.com/products/qt/opensource.html +** +** If you are unsure which license is appropriate for your use, please +** review the following information: +** http://www.trolltech.com/products/qt/licensing.html or contact the +** sales department at sales@trolltech.com. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +****************************************************************************/ + +//#include "qdesigner.h" +#include "qdesigner_settings.h" +#include "qdesigner_widgetbox.h" +#include "qdesigner_workbench.h" +#include "qdesigner_propertyeditor.h" +#include "qdesigner_objectinspector.h" + +#include +#include + +#include +#include +#include + +#include + +QDesignerSettings::QDesignerSettings() + : QSettings() +{ + m_designerPath = QLatin1String("/.designer"); + + QStringList paths = defaultFormTemplatePaths(); + foreach (QString path, paths) { + if (!QDir::current().exists(path)) + QDir::current().mkpath(path); + } +} + +QDesignerSettings::~QDesignerSettings() +{ +} + +QStringList QDesignerSettings::formTemplatePaths() const +{ + return value(QLatin1String("FormTemplatePaths"), + defaultFormTemplatePaths()).toStringList(); +} + +void QDesignerSettings::setFormTemplatePaths(const QStringList &paths) +{ + setValue(QLatin1String("FormTemplatePaths"), paths); +} + +QString QDesignerSettings::defaultUserWidgetBoxXml() const +{ + return QDir::homePath() + m_designerPath + QLatin1String("/widgetbox.xml"); +} + +QStringList QDesignerSettings::defaultFormTemplatePaths() const +{ + QStringList paths; + + QString templatePath = QLatin1String("/templates"); + + paths.append(QDir::homePath() + m_designerPath + templatePath); + paths.append(QApplication::applicationDirPath() + templatePath); + + return paths; +} + +void QDesignerSettings::saveGeometryFor(const QWidget *w) +{ + Q_ASSERT(w && !w->objectName().isEmpty()); + saveGeometryHelper(w, w->objectName()); +} + +void QDesignerSettings::setGeometryFor(QWidget *w, const QRect &fallBack) const +{ + Q_ASSERT(w && !w->objectName().isEmpty()); + setGeometryHelper(w, w->objectName(), + fallBack.isNull() ? QRect(QPoint(0, 0), w->sizeHint()) : fallBack); +} + +void QDesignerSettings::saveGeometryHelper(const QWidget *w, const QString &key) +{ + beginGroup(key); + QPoint pos = w->pos(); + if (!w->isWindow()) // in workspace + pos = w->parentWidget()->pos(); + + setValue(QLatin1String("screen"), QApplication::desktop()->screenNumber(w)); + setValue(QLatin1String("geometry"), QRect(pos, w->size())); + setValue(QLatin1String("visible"), w->isVisible()); + setValue(QLatin1String("maximized"), w->isMaximized()); + endGroup(); +} + +void QDesignerSettings::setGeometryHelper(QWidget *w, const QString &key, + const QRect &fallBack) const +{ +// beginGroup(); + int screen = value(key + QLatin1String("/screen"), 0).toInt(); + QRect g = value(key + QLatin1String("/geometry"), fallBack).toRect(); + QRect screenRect = QApplication::desktop()->availableGeometry(screen); + + // Do geometry in a couple of steps + // 1) Make sure the rect is within the specified geometry + // 2) Make sure the bottom right and top left fit on the screen, move them in. + // 3) Check again and resize. + + if (w->isWindow() && g.intersect(screenRect).isEmpty()) + g = fallBack; + + // Maybe use center? + if (!screenRect.contains(g.bottomRight())) { + g.moveRight(qMax(0 + g.width(), qMin(screenRect.right(), g.right()))); + g.moveBottom(qMax(0 + g.height(), qMin(screenRect.bottom(), g.bottom()))); + } + + if (!screenRect.contains(g.topLeft())) { + g.moveLeft(qMin(screenRect.right() - g.width(), qMax(screenRect.left(), g.left()))); + g.moveTop(qMin(screenRect.bottom() - g.height(), qMax(screenRect.top(), g.top()))); + } + + if (!screenRect.contains(g.bottomRight())) { + g.setRight(qMin(screenRect.right(), g.right())); + g.moveBottom(qMin(screenRect.bottom(), g.bottom())); + } + + if (!screenRect.contains(g.topLeft())) { + g.setLeft(qMax(0, qMin(screenRect.left(), g.left()))); + g.moveTop(qMax(0, qMin(screenRect.top(), g.top()))); + } + + + if (!w->isWindow()) // in workspace + w->parentWidget()->move(g.topLeft()); + else + w->move(g.topLeft()); + + if (value(key + QLatin1String("/maximized"), false).toBool()) { + w->setWindowState(w->windowState() | Qt::WindowMaximized); + } else { + w->resize(g.size()); + } + + if (value(key + QLatin1String("/visible"), true).toBool()) + w->show(); +// endGroup(); +} + +QStringList QDesignerSettings::recentFilesList() const +{ + return value(QLatin1String("recentFilesList")).toStringList(); +} + +void QDesignerSettings::setRecentFilesList(const QStringList &sl) +{ + setValue(QLatin1String("recentFilesList"), sl); +} + +void QDesignerSettings::setShowNewFormOnStartup(bool showIt) +{ + setValue(QLatin1String("newFormDialog/ShowOnStartup"), showIt); +} + +bool QDesignerSettings::showNewFormOnStartup() const +{ + return value(QLatin1String("newFormDialog/ShowOnStartup"), true).toBool(); +} + +void QDesignerSettings::setUIMode(int mode) +{ + setValue(QLatin1String("UI/currentMode"), mode); +} + +int QDesignerSettings::uiMode() const +{ + return value(QLatin1String("UI/currentMode"), QDesignerWorkbench::TopLevelMode).toInt(); +} + +QByteArray QDesignerSettings::mainWindowState() const +{ + return value(QLatin1String("MainWindowState")).toByteArray(); +} + +void QDesignerSettings::setMainWindowState(const QByteArray &mainWindowState) +{ + setValue(QLatin1String("MainWindowState"), mainWindowState); +} + diff --git a/src/designer/formdesigner/qdesigner_settings.h b/src/designer/formdesigner/qdesigner_settings.h new file mode 100644 index 0000000..1416f11 --- /dev/null +++ b/src/designer/formdesigner/qdesigner_settings.h @@ -0,0 +1,66 @@ +/**************************************************************************** +** +** Copyright (C) 1992-2006 Trolltech ASA. All rights reserved. +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** This file may be used under the terms of the GNU General Public +** License version 2.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of +** this file. Please review the following information to ensure GNU +** General Public Licensing requirements will be met: +** http://www.trolltech.com/products/qt/opensource.html +** +** If you are unsure which license is appropriate for your use, please +** review the following information: +** http://www.trolltech.com/products/qt/licensing.html or contact the +** sales department at sales@trolltech.com. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +****************************************************************************/ + +#ifndef QDESIGNER_SETTINGS_H +#define QDESIGNER_SETTINGS_H + +#include +#include + +class QDesignerSettings : public QSettings +{ +public: + QDesignerSettings(); + virtual ~QDesignerSettings(); + + QStringList formTemplatePaths() const; + void setFormTemplatePaths(const QStringList &paths); + + QString defaultUserWidgetBoxXml() const; + + void setGeometryFor(QWidget *w, const QRect &fallBack = QRect()) const; + void saveGeometryFor(const QWidget *w); + + QStringList recentFilesList() const; + void setRecentFilesList(const QStringList &list); + + void setShowNewFormOnStartup(bool showIt); + bool showNewFormOnStartup() const; + + void setUIMode(int mode); + int uiMode() const; + + QByteArray mainWindowState() const; + void setMainWindowState(const QByteArray &mainWindowState); + +private: + QStringList defaultFormTemplatePaths() const; + + void setGeometryHelper(QWidget *w, const QString &key, const QRect &fallBack) const; + void saveGeometryHelper(const QWidget *w, const QString &key); + +private: + QString m_designerPath; +}; + +#endif // QDESIGNER_SETTINGS_H diff --git a/src/designer/formdesigner/qdesigner_signalsloteditor.cpp b/src/designer/formdesigner/qdesigner_signalsloteditor.cpp new file mode 100644 index 0000000..f2df5fe --- /dev/null +++ b/src/designer/formdesigner/qdesigner_signalsloteditor.cpp @@ -0,0 +1,61 @@ +/**************************************************************************** +** +** Copyright (C) 1992-2006 Trolltech ASA. All rights reserved. +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** This file may be used under the terms of the GNU General Public +** License version 2.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of +** this file. Please review the following information to ensure GNU +** General Public Licensing requirements will be met: +** http://www.trolltech.com/products/qt/opensource.html +** +** If you are unsure which license is appropriate for your use, please +** review the following information: +** http://www.trolltech.com/products/qt/licensing.html or contact the +** sales department at sales@trolltech.com. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +****************************************************************************/ + +//#include "qdesigner.h" +#include "qdesigner_signalsloteditor.h" +#include "qdesigner_workbench.h" +#include "qdesigner_settings.h" + +#include +#include + +#include + + +QDesignerSignalSlotEditor::QDesignerSignalSlotEditor(QDesignerWorkbench *workbench) + : QDesignerToolWindow(workbench) +{ + setObjectName(QLatin1String("SignalSlotEditorWindow")); + QWidget *widget = QDesignerComponents::createSignalSlotEditor(workbench->core(), this); + + setCentralWidget(widget); + + setWindowTitle(tr("Signal/Slot Editor")); +} + +QDesignerSignalSlotEditor::~QDesignerSignalSlotEditor() +{ +} + +QRect QDesignerSignalSlotEditor::geometryHint() const +{ + QRect g = workbench()->availableGeometry(); + int margin = workbench()->marginHint(); + + QSize sz(g.width() * 1/3, g.height() * 1/6); + QRect r(QPoint(0, 0), sz); + r.moveCenter(g.center()); + r.moveTop(margin); + + return r; +} diff --git a/src/designer/formdesigner/qdesigner_signalsloteditor.h b/src/designer/formdesigner/qdesigner_signalsloteditor.h new file mode 100644 index 0000000..17bcfa3 --- /dev/null +++ b/src/designer/formdesigner/qdesigner_signalsloteditor.h @@ -0,0 +1,41 @@ +/**************************************************************************** +** +** Copyright (C) 1992-2006 Trolltech ASA. All rights reserved. +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** This file may be used under the terms of the GNU General Public +** License version 2.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of +** this file. Please review the following information to ensure GNU +** General Public Licensing requirements will be met: +** http://www.trolltech.com/products/qt/opensource.html +** +** If you are unsure which license is appropriate for your use, please +** review the following information: +** http://www.trolltech.com/products/qt/licensing.html or contact the +** sales department at sales@trolltech.com. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +****************************************************************************/ + +#ifndef QDESIGNER_SIGNALSLOTEDITOR_H +#define QDESIGNER_SIGNALSLOTEDITOR_H + +#include "qdesigner_toolwindow.h" + +class QDesignerWorkbench; + +class QDesignerSignalSlotEditor: public QDesignerToolWindow +{ + Q_OBJECT +public: + QDesignerSignalSlotEditor(QDesignerWorkbench *workbench); + virtual ~QDesignerSignalSlotEditor(); + + virtual QRect geometryHint() const; +}; + +#endif // QDESIGNER_SIGNALSLOTEDITOR_H diff --git a/src/designer/formdesigner/qdesigner_toolwindow.cpp b/src/designer/formdesigner/qdesigner_toolwindow.cpp new file mode 100644 index 0000000..1fb8d2e --- /dev/null +++ b/src/designer/formdesigner/qdesigner_toolwindow.cpp @@ -0,0 +1,138 @@ +/**************************************************************************** +** +** Copyright (C) 1992-2006 Trolltech ASA. All rights reserved. +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** This file may be used under the terms of the GNU General Public +** License version 2.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of +** this file. Please review the following information to ensure GNU +** General Public Licensing requirements will be met: +** http://www.trolltech.com/products/qt/opensource.html +** +** If you are unsure which license is appropriate for your use, please +** review the following information: +** http://www.trolltech.com/products/qt/licensing.html or contact the +** sales department at sales@trolltech.com. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +****************************************************************************/ + +//#include "qdesigner.h" +#include "qdesigner_toolwindow.h" +#include "qdesigner_settings.h" +#include "qdesigner_workbench.h" + +#include +#include +#include +#include +#include + +QDesignerToolWindow::QDesignerToolWindow(QDesignerWorkbench *workbench, QWidget *parent, Qt::WindowFlags flags) + : QMainWindow(parent, flags), + m_workbench(workbench), + m_saveSettings(false) +{ + Q_ASSERT(workbench != 0); + + m_action = new QAction(this); + m_action->setShortcutContext(Qt::ApplicationShortcut); + m_action->setText(windowTitle()); + m_action->setCheckable(true); + connect(m_action, SIGNAL(triggered(bool)), this, SLOT(showMe(bool))); +} + +QDesignerToolWindow::~QDesignerToolWindow() +{ + if (workbench()) + workbench()->removeToolWindow(this); +} + +void QDesignerToolWindow::showMe(bool v) +{ + QWidget *target = parentWidget() == 0 ? this : parentWidget(); + + if (v) + target->setWindowState(target->windowState() & ~Qt::WindowMinimized); + + target->setVisible(v); +} + +void QDesignerToolWindow::showEvent(QShowEvent *e) +{ + Q_UNUSED(e); + + bool blocked = m_action->blockSignals(true); + m_action->setChecked(true); + m_action->blockSignals(blocked); +} + +void QDesignerToolWindow::hideEvent(QHideEvent *e) +{ + Q_UNUSED(e); + + bool blocked = m_action->blockSignals(true); + m_action->setChecked(false); + m_action->blockSignals(blocked); +} + +QAction *QDesignerToolWindow::action() const +{ + return m_action; +} + +void QDesignerToolWindow::changeEvent(QEvent *e) +{ + switch (e->type()) { + case QEvent::WindowTitleChange: + m_action->setText(windowTitle()); + break; + case QEvent::WindowIconChange: + m_action->setIcon(windowIcon()); + break; + default: + break; + } + QMainWindow::changeEvent(e); +} + +QDesignerWorkbench *QDesignerToolWindow::workbench() const +{ + return m_workbench; +} + +QRect QDesignerToolWindow::geometryHint() const +{ + return QRect(); +} + +void QDesignerToolWindow::closeEvent(QCloseEvent *ev) +{ + if (m_saveSettings) { + ev->setAccepted(workbench()->handleClose()); + /*if (ev->isAccepted() && qDesigner->mainWindow() == this) + QMetaObject::invokeMethod(qDesigner, "quit", Qt::QueuedConnection); // We're going down!*/ + } else { + QMainWindow::closeEvent(ev); + } +} + +bool QDesignerToolWindow::saveSettingsOnClose() const +{ + return m_saveSettings; +} + +void QDesignerToolWindow::setSaveSettingsOnClose(bool save) +{ + m_saveSettings = save; +} + +Qt::DockWidgetArea QDesignerToolWindow::dockWidgetAreaHint() const +{ + return Qt::RightDockWidgetArea; +} + diff --git a/src/designer/formdesigner/qdesigner_toolwindow.h b/src/designer/formdesigner/qdesigner_toolwindow.h new file mode 100644 index 0000000..393e999 --- /dev/null +++ b/src/designer/formdesigner/qdesigner_toolwindow.h @@ -0,0 +1,63 @@ +/**************************************************************************** +** +** Copyright (C) 1992-2006 Trolltech ASA. All rights reserved. +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** This file may be used under the terms of the GNU General Public +** License version 2.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of +** this file. Please review the following information to ensure GNU +** General Public Licensing requirements will be met: +** http://www.trolltech.com/products/qt/opensource.html +** +** If you are unsure which license is appropriate for your use, please +** review the following information: +** http://www.trolltech.com/products/qt/licensing.html or contact the +** sales department at sales@trolltech.com. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +****************************************************************************/ + +#ifndef QDESIGNER_TOOLWINDOW_H +#define QDESIGNER_TOOLWINDOW_H + +#include +#include + +class QDesignerWorkbench; + +class QDesignerToolWindow: public QMainWindow +{ + Q_OBJECT +public: + QDesignerToolWindow(QDesignerWorkbench *workbench, QWidget *parent = 0, Qt::WindowFlags flags = Qt::Window); + virtual ~QDesignerToolWindow(); + + QDesignerWorkbench *workbench() const; + QAction *action() const; + + void setSaveSettingsOnClose(bool save); + bool saveSettingsOnClose() const; + + virtual Qt::DockWidgetArea dockWidgetAreaHint() const; + virtual QRect geometryHint() const; + +private slots: + void showMe(bool); + +protected: + virtual void showEvent(QShowEvent *e); + virtual void hideEvent(QHideEvent *e); + virtual void changeEvent(QEvent *e); + virtual void closeEvent(QCloseEvent *e); + +private: + QDesignerWorkbench *m_workbench; + QAction *m_action; + bool m_saveSettings; +}; + +#endif // QDESIGNER_TOOLWINDOW_H diff --git a/src/designer/formdesigner/qdesigner_widgetbox.cpp b/src/designer/formdesigner/qdesigner_widgetbox.cpp new file mode 100644 index 0000000..eba6c56 --- /dev/null +++ b/src/designer/formdesigner/qdesigner_widgetbox.cpp @@ -0,0 +1,77 @@ +/**************************************************************************** +** +** Copyright (C) 1992-2006 Trolltech ASA. All rights reserved. +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** This file may be used under the terms of the GNU General Public +** License version 2.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of +** this file. Please review the following information to ensure GNU +** General Public Licensing requirements will be met: +** http://www.trolltech.com/products/qt/opensource.html +** +** If you are unsure which license is appropriate for your use, please +** review the following information: +** http://www.trolltech.com/products/qt/licensing.html or contact the +** sales department at sales@trolltech.com. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +****************************************************************************/ + +//#include "qdesigner.h" +#include "qdesigner_widgetbox.h" +#include "qdesigner_workbench.h" +#include "qdesigner_settings.h" + +#include +#include + +#include + +QDesignerWidgetBox::QDesignerWidgetBox(QDesignerWorkbench *workbench) + : QDesignerToolWindow(workbench) +{ + setObjectName(QLatin1String("WidgetBox")); + QDesignerWidgetBoxInterface *widget = QDesignerComponents::createWidgetBox(workbench->core(), this); + widget->setFileName(QLatin1String(":/trolltech/widgetbox/widgetbox.xml")); + widget->load(); + widget->setFileName(QDesignerSettings().defaultUserWidgetBoxXml()); + widget->load(); + +/* int g, w; + for ( g=0; g< widget->categoryCount(); g++){ + printf("cat %i=%s\n", g, widget->category( g ).name().toUtf8().data()); + for ( w=0; w < widget->widgetCount( g ); w++ ){ + printf(" w%i=%s\n", w, widget->widget( g, w ).name().toUtf8().data()); + } + } +*/ + // Удалим лишние группы и объекты + widget->removeCategory( 3 ); + + workbench->core()->setWidgetBox(widget); + + setCentralWidget(widget); + + setWindowTitle(tr("Widget Box")); +} + +QDesignerWidgetBox::~QDesignerWidgetBox() +{ +} + +QRect QDesignerWidgetBox::geometryHint() const +{ + QRect g = workbench()->availableGeometry(); + + return QRect(workbench()->marginHint(), workbench()->marginHint(), + g.width() * 1/6, g.height() * 5/6); +} + +Qt::DockWidgetArea QDesignerWidgetBox::dockWidgetAreaHint() const +{ + return Qt::LeftDockWidgetArea; +} diff --git a/src/designer/formdesigner/qdesigner_widgetbox.h b/src/designer/formdesigner/qdesigner_widgetbox.h new file mode 100644 index 0000000..e6a8697 --- /dev/null +++ b/src/designer/formdesigner/qdesigner_widgetbox.h @@ -0,0 +1,42 @@ +/**************************************************************************** +** +** Copyright (C) 1992-2006 Trolltech ASA. All rights reserved. +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** This file may be used under the terms of the GNU General Public +** License version 2.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of +** this file. Please review the following information to ensure GNU +** General Public Licensing requirements will be met: +** http://www.trolltech.com/products/qt/opensource.html +** +** If you are unsure which license is appropriate for your use, please +** review the following information: +** http://www.trolltech.com/products/qt/licensing.html or contact the +** sales department at sales@trolltech.com. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +****************************************************************************/ + +#ifndef QDESIGNER_WIDGETBOX_H +#define QDESIGNER_WIDGETBOX_H + +#include "qdesigner_toolwindow.h" + +class QDesignerWorkbench; + +class QDesignerWidgetBox: public QDesignerToolWindow +{ + Q_OBJECT +public: + QDesignerWidgetBox(QDesignerWorkbench *workbench); + virtual ~QDesignerWidgetBox(); + + virtual Qt::DockWidgetArea dockWidgetAreaHint() const; + virtual QRect geometryHint() const; +}; + +#endif // QDESIGNER_WIDGETBOX_H diff --git a/src/designer/formdesigner/qdesigner_workbench.cpp b/src/designer/formdesigner/qdesigner_workbench.cpp new file mode 100644 index 0000000..48461f2 --- /dev/null +++ b/src/designer/formdesigner/qdesigner_workbench.cpp @@ -0,0 +1,881 @@ +/**************************************************************************** +** +** Copyright (C) 1992-2006 Trolltech ASA. All rights reserved. +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** This file may be used under the terms of the GNU General Public +** License version 2.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of +** this file. Please review the following information to ensure GNU +** General Public Licensing requirements will be met: +** http://www.trolltech.com/products/qt/opensource.html +** +** If you are unsure which license is appropriate for your use, please +** review the following information: +** http://www.trolltech.com/products/qt/licensing.html or contact the +** sales department at sales@trolltech.com. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +****************************************************************************/ + +//#include "qdesigner.h" +#include "qdesigner_workbench.h" +#include "qdesigner_actions.h" +#include "qdesigner_toolwindow.h" +#include "qdesigner_formwindow.h" +#include "qdesigner_settings.h" +#include "qdesigner_widgetbox.h" +#include "qdesigner_propertyeditor.h" +#include "qdesigner_objectinspector.h" +#include "qdesigner_signalsloteditor.h" +#include "qdesigner_actioneditor.h" +#include "qdesigner_resourceeditor.h" + +#include +#include +#include "private/qdesigner_integration_p.h" +#include "private/pluginmanager_p.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +QDesignerWorkbench::QDesignerWorkbench() + : m_mode(QDesignerWorkbench::NeutralMode), m_workspace(0) +{ + m_initializing = true; + initialize(); + + setUIMode(UIMode(/*QDesignerSettings().uiMode()*/DockedMode)); + m_initializing = false; +} + +QDesignerWorkbench::~QDesignerWorkbench() +{ + if (m_mode == DockedMode) { + Q_ASSERT(m_workspace != 0); + QMainWindow *mw = qobject_cast(m_workspace->window()); + Q_ASSERT(mw != 0); + + QDesignerSettings settings; + settings.setMainWindowState(mw->saveState(2)); + } + + while (!m_toolWindows.isEmpty()) + delete m_toolWindows.takeLast(); +} + +QDesignerWorkbench::UIMode QDesignerWorkbench::mode() const +{ + return m_mode; +} + +void QDesignerWorkbench::addToolWindow(QDesignerToolWindow *toolWindow) +{ + Q_ASSERT(m_toolWindowExtras.contains(toolWindow) == false); + Q_ASSERT(toolWindow->windowTitle().isEmpty() == false); + + m_toolWindows.append(toolWindow); + + if (QAction *action = toolWindow->action()) { + Q_ASSERT(m_toolMenu->actions().isEmpty() == false); + + QList lst = m_toolActions->actions(); + QAction *before = lst.count() ? lst.last() : m_toolMenu->actions().first(); + m_toolMenu->insertAction(before, action); + m_toolActions->addAction(action); + } +} + +void QDesignerWorkbench::addFormWindow(QDesignerFormWindow *formWindow) +{ + Q_ASSERT(m_formWindowExtras.contains(formWindow) == false); + // ### Q_ASSERT(formWindow->windowTitle().isEmpty() == false); + + m_formWindows.append(formWindow); + if (m_windowActions->actions().isEmpty()) + m_windowMenu->addSeparator(); + + if (QAction *action = formWindow->action()) { + m_windowActions->addAction(action); + m_windowMenu->addAction(action); + action->setChecked(true); + } + + m_actionManager->minimizeAction()->setEnabled(true); + m_actionManager->editWidgets()->trigger(); +} + +void QDesignerWorkbench::initialize() +{ + /*QObjectList list = QPluginLoader::staticInstances(); + qDebug() << list.size(); + for (int i=0; iobjectName() << list[i]->metaObject()->className(); + qDebug() << qobject_cast(list[i]); + }*/ + + QDesignerSettings settings; + m_core = QDesignerComponents::createFormEditor(this); + + (void) QDesignerComponents::createTaskMenu(core(), this); + + initializeCorePlugins(); + QDesignerComponents::initializePlugins(core()); + + m_toolActions = new QActionGroup(this); + m_toolActions->setExclusive(false); + + m_windowActions = new QActionGroup(this); + m_windowActions->setExclusive(true); + connect(m_windowActions, SIGNAL(triggered(QAction*)), this, SLOT(formWindowActionTriggered(QAction*))); + + m_actionManager = new QDesignerActions(this); + + m_globalMenuBar = new QMenuBar; + +/* + m_fileMenu = m_globalMenuBar->addMenu(tr("&File")); + foreach (QAction *action, m_actionManager->fileActions()->actions()) { + m_fileMenu->addAction(action); + if (action->text() == QDesignerActions::tr("&Open Form...")) { + QMenu *recentFilesMenu = m_fileMenu->addMenu(tr("&Recent Forms")); + // Pop the "Recent Files" stuff in here. + foreach(QAction *recentAction, m_actionManager->recentFilesActions()->actions()) + recentFilesMenu->addAction(recentAction); + } + } +*/ + m_editMenu = m_globalMenuBar->addMenu(tr("&Edit")); + foreach (QAction *action, m_actionManager->editActions()->actions()) { + m_editMenu->addAction(action); + } + + m_editMenu->addSeparator(); + + foreach (QAction *action, m_actionManager->toolActions()->actions()) { + m_editMenu->addAction(action); + } + + m_editMenu->addSeparator(); + QMenu *menu = m_editMenu->addMenu(tr("User Interface &Mode")); + foreach (QAction *action, m_actionManager->uiMode()->actions()) + menu->addAction(action); + + + m_formMenu = m_globalMenuBar->addMenu(tr("F&orm")); + foreach (QAction *action, m_actionManager->formActions()->actions()) { + m_formMenu->addAction(action); + } + +/* + QMenu *previewSubMenu = new QMenu(tr("Preview in"), m_formMenu); + m_formMenu->insertMenu(m_actionManager->previewFormAction(), previewSubMenu); + + foreach (QAction *action, m_actionManager->styleActions()->actions()) { + previewSubMenu->addAction(action); + } +*/ + m_toolMenu = m_globalMenuBar->addMenu(tr("&Tools")); + + m_toolMenu->addSeparator(); + + m_windowMenu = m_globalMenuBar->addMenu(tr("&Window")); + foreach (QAction *action, m_actionManager->windowActions()->actions()) { + m_windowMenu->addAction(action); + } + +/* + m_helpMenu = m_globalMenuBar->addMenu(tr("&Help")); + foreach (QAction *action, m_actionManager->helpActions()->actions()) { + m_helpMenu->addAction(action); + } +*/ + QDesignerToolWindow *tw = new QDesignerWidgetBox(this); + tw->setObjectName(QLatin1String("qt_designer_widgetbox")); + addToolWindow(tw); + tw = new QDesignerObjectInspector(this); + tw->setObjectName(QLatin1String("qt_designer_objectinspector")); + addToolWindow(tw); + tw = new QDesignerPropertyEditor(this); + tw->setObjectName(QLatin1String("qt_designer_propertyeditor")); + addToolWindow(tw); + tw = new QDesignerSignalSlotEditor(this); + tw->setObjectName(QLatin1String("qt_designer_signalsloteditor")); +// addToolWindow(tw); + tw = new QDesignerResourceEditor(this); + tw->setObjectName(QLatin1String("qt_designer_resourceeditor")); +// addToolWindow(tw); + tw = new QDesignerActionEditor(this); + tw->setObjectName(QLatin1String("qt_designer_actioneditor")); +// addToolWindow(tw); + + m_integration = new qdesigner_internal::QDesignerIntegration(core(), this); + + // create the toolbars + m_editToolBar = new QToolBar; + m_editToolBar->setObjectName(QLatin1String("editToolBar")); + m_editToolBar->setWindowTitle(tr("Edit")); + foreach (QAction *action, m_actionManager->editActions()->actions()) { + if (action->icon().isNull() == false) + m_editToolBar->addAction(action); + } + + m_toolToolBar = new QToolBar; + m_toolToolBar->setObjectName(QLatin1String("toolsToolBar")); + m_toolToolBar->setWindowTitle(tr("Tools")); + foreach (QAction *action, m_actionManager->toolActions()->actions()) { + if (action->icon().isNull() == false) + m_toolToolBar->addAction(action); + } + + m_formToolBar = new QToolBar; + m_formToolBar->setObjectName(QLatin1String("formToolBar")); + m_formToolBar->setWindowTitle(tr("Form")); + foreach (QAction *action, m_actionManager->formActions()->actions()) { + if (action->icon().isNull() == false) + m_formToolBar->addAction(action); + } + + QMenu *toolbarMenu = m_toolMenu->addMenu(tr("Toolbars")); + toolbarMenu->addAction(m_editToolBar->toggleViewAction()); + toolbarMenu->addAction(m_toolToolBar->toggleViewAction()); + toolbarMenu->addAction(m_formToolBar->toggleViewAction()); + + m_geometries.clear(); + + emit initialized(); + + connect(m_core->formWindowManager(), SIGNAL(activeFormWindowChanged(QDesignerFormWindowInterface*)), + this, SLOT(updateWindowMenu(QDesignerFormWindowInterface*))); +} + +Qt::WindowFlags QDesignerWorkbench::magicalWindowFlags(const QWidget *widgetForFlags) const +{ + switch (m_mode) { + case TopLevelMode: { +#ifdef Q_WS_MAC + if (qobject_cast(widgetForFlags)) + return Qt::Tool; +#else + Q_UNUSED(widgetForFlags); +#endif + return Qt::Window; + } + case DockedMode: + Q_ASSERT(m_workspace != 0); + return Qt::Window | Qt::WindowShadeButtonHint | Qt::WindowSystemMenuHint | Qt::WindowTitleHint; + case NeutralMode: + return Qt::Window; + default: + Q_ASSERT(0); + return 0; + } +} + +QWidget *QDesignerWorkbench::magicalParent() const +{ + switch (m_mode) { + case TopLevelMode: + return 0; + case DockedMode: + Q_ASSERT(m_workspace != 0); + return m_workspace; + case NeutralMode: + return 0; + default: + Q_ASSERT(0); + return 0; + } +} + +void QDesignerWorkbench::switchToNeutralMode() +{ + if (m_mode == NeutralMode) { + return; + } else if (m_mode == DockedMode) { + Q_ASSERT(m_workspace != 0); + QMainWindow *mw = qobject_cast(m_workspace->window()); + QDesignerSettings settings; + settings.setMainWindowState(mw->saveState(2)); + } + + QPoint desktopOffset = QPoint(0, 0); + QPoint workspaceOffset = QPoint(0, 0); + if (m_mode == TopLevelMode) + desktopOffset = QApplication::desktop()->availableGeometry().topLeft(); + else if (m_mode == DockedMode) + workspaceOffset = m_workspace->mapToGlobal(QPoint(0, 0)); + m_mode = NeutralMode; + + m_geometries.clear(); + m_visibilities.clear(); + + foreach (QDesignerToolWindow *tw, m_toolWindows) { + m_visibilities.insert(tw, tw->isVisible()); + if (tw->isVisible()) { + // use the actual geometry + QPoint pos = tw->window()->pos(); + if (!tw->isWindow()) { + if (const QWidget *pw = tw->parentWidget()) { + pos = pw->mapTo(tw->window(), QPoint(0, 0)); + pos += tw->window()->pos(); + } + + } + m_geometries.insert(tw, QRect(pos - desktopOffset, tw->size())); + } + tw->setSaveSettingsOnClose(false); + + tw->setParent(0); + } + + foreach (QDesignerFormWindow *fw, m_formWindows) { + if (fw->isVisible()) { + // use the actual geometry + QPoint pos = fw->window()->pos(); + if (!fw->isWindow()) + if (QWidget *p = fw->parentWidget()) + pos = p->pos(); // in workspace + + m_geometries.insert(fw, QRect(pos - desktopOffset + workspaceOffset, + fw->size())); + } + + fw->setParent(0); + } + +#ifndef Q_WS_MAC + m_globalMenuBar->setParent(0); +#endif + m_editToolBar->setParent(0); + m_toolToolBar->setParent(0); + m_formToolBar->setParent(0); + m_core->setTopLevel(0); + /*qDesigner->*/setMainWindow(0); + + if (m_workspace) + delete m_workspace->parentWidget(); + + m_workspace = 0; +} + +void QDesignerWorkbench::switchToDockedMode() +{ + bool wasTopLevel = (m_mode == TopLevelMode); + if (m_mode == DockedMode) + return; + + switchToNeutralMode(); + m_mode = DockedMode; + + QDesignerToolWindow *widgetBoxWrapper = 0; + if (0 != (widgetBoxWrapper = findToolWindow(core()->widgetBox()))) { + widgetBoxWrapper->action()->setEnabled(true); + widgetBoxWrapper->setWindowTitle(tr("Widget Box")); + } + + Q_ASSERT(m_workspace == 0); + + QDesignerSettings settings; + QDesignerToolWindow *mw = new QDesignerToolWindow(this); // Just to have a copy of + mw->setSaveSettingsOnClose(true); + mw->setObjectName(QLatin1String("MDIWindow")); + mw->setWindowTitle(tr("Qt Designer")); + m_workspace = new QWorkspace(mw); + m_workspace->setAcceptDrops(true); + m_workspace->installEventFilter(this); + m_workspace->setScrollBarsEnabled(true); + connect(m_workspace, SIGNAL(windowActivated(QWidget*)), + this, SLOT(activateWorkspaceChildWindow(QWidget*))); + mw->setCentralWidget(m_workspace); + m_core->setTopLevel(mw); + (void) mw->statusBar(); + if (m_geometries.isEmpty()) { + settings.setGeometryFor(mw, qApp->desktop()->availableGeometry(0)); + } else { + if (QDesignerToolWindow *widgetBox = findToolWindow(core()->widgetBox())) { + QRect r = m_geometries.value(widgetBox, QRect(0, 0, 200, 200)); + mw->move(r.topLeft()); + } + mw->setWindowState(mw->windowState() | Qt::WindowMaximized); + } + +#ifndef Q_WS_MAC + mw->setMenuBar(m_globalMenuBar); + m_globalMenuBar->show(); +#endif + mw->addToolBar(m_editToolBar); + mw->addToolBar(m_toolToolBar); + mw->addToolBar(m_formToolBar); + m_editToolBar->show(); + m_toolToolBar->show(); + m_formToolBar->show(); + + /*qDesigner->*/setMainWindow(mw); + + foreach (QDesignerToolWindow *tw, m_toolWindows) { + if (wasTopLevel) + settings.saveGeometryFor(tw); + QDockWidget *dockWidget = magicalDockWidget(tw); + if (dockWidget == 0) { + dockWidget = new QDockWidget(mw); + dockWidget->setObjectName(tw->objectName() + QLatin1String("_dock")); + dockWidget->setWindowTitle(tw->windowTitle()); + mw->addDockWidget(tw->dockWidgetAreaHint(), dockWidget); + } + + dockWidget->setWidget(tw); + } + + foreach (QDesignerToolWindow *tw, m_toolWindows) { + QDockWidget *dockWidget = magicalDockWidget(tw); + tw->setVisible(true); + dockWidget->setVisible(m_visibilities.value(tw, true)); + } + + mw->restoreState(settings.mainWindowState(), 2); + + foreach (QDesignerFormWindow *fw, m_formWindows) + m_workspace->addWindow(fw, magicalWindowFlags(fw))->hide(); + // will be shown in adjustFormPositions + + changeBringToFrontVisiblity(false); + + mw->show(); + + if (!m_initializing) + QMetaObject::invokeMethod(this, "adjustFormPositions", Qt::QueuedConnection); +} + +bool QDesignerWorkbench::eventFilter(QObject *object, QEvent *event) +{ + if (object == m_workspace) { + if (event->type() == QEvent::DragEnter) { + QDragEnterEvent *e = static_cast(event); + if (e->mimeData()->hasFormat("text/uri-list")) { + e->acceptProposedAction(); + return true; + } + } else if (event->type() == QEvent::Drop) { + QDropEvent *e = static_cast(event); + if (!e->mimeData()->hasFormat("text/uri-list")) + return false; + foreach (QUrl url, e->mimeData()->urls()) { + QString fileName = url.toLocalFile(); + if (fileName.endsWith(".ui")) + readInForm(url.toLocalFile()); + else + QMessageBox::critical(m_workspace, tr("Opening Form"), + tr("Cannot open file %1!").arg(fileName)); + } + e->acceptProposedAction(); + return true; + } + } + return false; +} + +void QDesignerWorkbench::adjustFormPositions() +{ + if (m_workspace == 0) + return; + + QPoint workspace_tl = m_workspace->mapToGlobal(QPoint(0, 0)); + + foreach (QDesignerFormWindow *fw, m_formWindows) { + QWidget *frame = fw->parentWidget(); + if (frame == 0) + continue; + QRect g = m_geometries.value(fw, fw->geometryHint()); + frame->move(g.topLeft() - workspace_tl); + fw->resize(g.size()); + frame->show(); + } +} + +void QDesignerWorkbench::changeBringToFrontVisiblity(bool visible) +{ + QAction *btf = m_actionManager->bringToFrontAction(); + QList actionList = m_actionManager->windowActions()->actions(); + btf->setVisible(visible); + QAction *sep = actionList.at(actionList.indexOf(btf) - 1); + if (sep->isSeparator()) + sep->setVisible(visible); +} + +void QDesignerWorkbench::switchToTopLevelMode() +{ + if (m_mode == TopLevelMode) + return; + + // make sure that the widgetbox is visible iff it is different from neutrol. + if (m_mode != NeutralMode) { + if (QDesignerToolWindow *widgetbox_tool = findToolWindow(core()->widgetBox())) { + if (!widgetbox_tool->action()->isChecked()) + widgetbox_tool->action()->trigger(); + } + } + + switchToNeutralMode(); + QPoint desktopOffset = QApplication::desktop()->availableGeometry().topLeft(); + m_mode = TopLevelMode; + + // The widget box is special, it gets the menubar and gets to be the main widget. + + QDesignerToolWindow *widgetBoxWrapper = 0; + if (0 != (widgetBoxWrapper = findToolWindow(core()->widgetBox()))) { + m_core->setTopLevel(widgetBoxWrapper); +#ifndef Q_WS_MAC + widgetBoxWrapper->setMenuBar(m_globalMenuBar); + widgetBoxWrapper->action()->setEnabled(false); + widgetBoxWrapper->setSaveSettingsOnClose(true); + /*qDesigner->*/setMainWindow(widgetBoxWrapper); + widgetBoxWrapper->setWindowTitle(tr("Qt Designer")); +#endif + widgetBoxWrapper->addToolBar(m_editToolBar); + widgetBoxWrapper->addToolBar(m_toolToolBar); + widgetBoxWrapper->addToolBar(m_formToolBar); + + widgetBoxWrapper->insertToolBarBreak(m_formToolBar); + } + + QDesignerSettings settings; + bool found_visible_window = false; + foreach (QDesignerToolWindow *tw, m_toolWindows) { + tw->setParent(magicalParent(), magicalWindowFlags(tw)); + settings.setGeometryFor(tw, tw->geometryHint()); + tw->action()->setChecked(tw->isVisible()); + found_visible_window |= tw->isVisible(); + } + + if (!m_toolWindows.isEmpty() && !found_visible_window) + m_toolWindows.first()->show(); + + changeBringToFrontVisiblity(true); + + foreach (QDesignerFormWindow *fw, m_formWindows) { + fw->setParent(magicalParent(), magicalWindowFlags(fw)); + QRect g = m_geometries.value(fw, fw->geometryHint()); + fw->resize(g.size()); + fw->move(g.topLeft() + desktopOffset); + fw->show(); + } +} + +QDesignerFormWindow *QDesignerWorkbench::createFormWindow() +{ + QDesignerFormWindow *formWindow = new QDesignerFormWindow(/*formWindow=*/ 0, this); + + if (m_workspace) { + m_workspace->addWindow(formWindow, magicalWindowFlags(formWindow)); + } else { + formWindow->setParent(magicalParent(), magicalWindowFlags(formWindow)); + } + + formWindow->setAttribute(Qt::WA_DeleteOnClose, true); + + addFormWindow(formWindow); + + QRect g = formWindow->geometryHint(); + formWindow->resize(g.size()); + formWindow->move(availableGeometry().center() - g.center()); + + if (m_workspace) { + m_workspace->setActiveWindow(formWindow); + } + + return formWindow; +} + +QDesignerFormWindowManagerInterface *QDesignerWorkbench::formWindowManager() const +{ + return m_core->formWindowManager(); +} + +QDesignerFormEditorInterface *QDesignerWorkbench::core() const +{ + return m_core; +} + +int QDesignerWorkbench::toolWindowCount() const +{ + return m_toolWindows.count(); +} + +QDesignerToolWindow *QDesignerWorkbench::toolWindow(int index) const +{ + return m_toolWindows.at(index); +} + +int QDesignerWorkbench::formWindowCount() const +{ + return m_formWindows.count(); +} + +QDesignerFormWindow *QDesignerWorkbench::formWindow(int index) const +{ + return m_formWindows.at(index); +} + +QRect QDesignerWorkbench::availableGeometry() const +{ + if (m_workspace) + return m_workspace->geometry(); + + QDesktopWidget *desktop = QApplication::desktop(); + + QWidget *window = findToolWindow(core()->widgetBox()); + if (window) + return desktop->availableGeometry(desktop->screenNumber(window)); + return desktop->availableGeometry(0); +} + +int QDesignerWorkbench::marginHint() const +{ + return 20; +} + +void QDesignerWorkbench::activateWorkspaceChildWindow(QWidget *widget) +{ + if (QDesignerFormWindow *fw = qobject_cast(widget)) { + core()->formWindowManager()->setActiveFormWindow(fw->editor()); + m_workspace->setActiveWindow(widget); + } +} + +void QDesignerWorkbench::removeToolWindow(QDesignerToolWindow *toolWindow) +{ + int index = m_toolWindows.indexOf(toolWindow); + if (index != -1) { + m_toolWindows.removeAt(index); + m_toolWindowExtras.remove(toolWindow); + } + + if (QAction *action = toolWindow->action()) { + m_toolActions->removeAction(action); + //m_toolMenu->removeAction(action); // FIXME Зависает в этом месте при выходе из программы + } +} + +void QDesignerWorkbench::removeFormWindow(QDesignerFormWindow *formWindow) +{ + int index = m_formWindows.indexOf(formWindow); + if (index != -1) { + m_formWindows.removeAt(index); + m_formWindowExtras.remove(formWindow); + } + + if (QAction *action = formWindow->action()) { + m_windowActions->removeAction(action); + m_windowMenu->removeAction(action); + } + + if (formWindowCount() == 0) { + m_actionManager->minimizeAction()->setEnabled(false); + QList actions = m_windowMenu->actions(); + for (int i = actions.size() - 1; i >= 0; --i) { + QAction *act = actions.at(i); + if (act->isSeparator()) { + delete act; + break; + } + } + } +} + +void QDesignerWorkbench::initializeCorePlugins() +{ + QList plugins = QPluginLoader::staticInstances(); + plugins += core()->pluginManager()->instances(); + + foreach (QObject *plugin, plugins) { + if (QDesignerFormEditorPluginInterface *formEditorPlugin = qobject_cast(plugin)) { + if (!formEditorPlugin->isInitialized()) + formEditorPlugin->initialize(core()); + } + } +} + +void QDesignerWorkbench::saveSettings() const +{ + QDesignerSettings settings; + if (m_mode == DockedMode) { + if (qFindChild(/*qDesigner->*/mainWindow())) { + settings.saveGeometryFor(/*qDesigner->*/mainWindow()); + settings.setValue(/*qDesigner->*/mainWindow()->objectName() + QLatin1String("/visible"), false); + } + } else { + foreach (QDesignerToolWindow *tw, m_toolWindows) { + settings.saveGeometryFor(tw); + } + } +} + +bool QDesignerWorkbench::readInForm(const QString &fileName) const +{ + return m_actionManager->readInForm(fileName); +} + +bool QDesignerWorkbench::writeOutForm(QDesignerFormWindowInterface *formWindow, const QString &fileName) const +{ + return m_actionManager->writeOutForm(formWindow, fileName); +} + +bool QDesignerWorkbench::saveForm(QDesignerFormWindowInterface *frm) +{ + return m_actionManager->saveForm(frm); +} + +QDesignerToolWindow *QDesignerWorkbench::findToolWindow(QWidget *widget) const +{ + foreach (QDesignerToolWindow *toolWindow, m_toolWindows) { + if (toolWindow->centralWidget() == widget) + return toolWindow; + } + + return 0; +} + +QDesignerFormWindow *QDesignerWorkbench::findFormWindow(QWidget *widget) const +{ + foreach (QDesignerFormWindow *formWindow, m_formWindows) { + if (formWindow->centralWidget() == widget) + return formWindow; + } + + return 0; +} + +bool QDesignerWorkbench::handleClose() +{ + QList dirtyForms; + foreach (QDesignerFormWindow *w, m_formWindows) { + if (w->editor()->isDirty()) + dirtyForms << w; + } + + if (dirtyForms.size()) { + if (dirtyForms.size() == 1) { + if (!dirtyForms.at(0)->close()) { + return false; + } + } else { + QMessageBox box(tr("Save Forms?"), + tr("There are %1 forms with unsaved changes." + " Do you want to review these changes before quitting?") + .arg(dirtyForms.size()), + QMessageBox::Warning, + QMessageBox::Yes | QMessageBox::Default, QMessageBox::No, + QMessageBox::Cancel | QMessageBox::Escape, 0); + box.setButtonText(QMessageBox::Yes, tr("Review Changes")); + box.setButtonText(QMessageBox::No, tr("Discard Changes")); + switch (box.exec()) { + case QMessageBox::Cancel: + return false; + case QMessageBox::Yes: + foreach (QDesignerFormWindow *fw, dirtyForms) { + fw->show(); + fw->raise(); + if (!fw->close()) { + return false; + } + } + break; + case QMessageBox::No: + foreach (QDesignerFormWindow *fw, dirtyForms) { + fw->editor()->setDirty(false); + fw->setWindowModified(false); + } + break; + } + } + } + + foreach (QDesignerFormWindow *fw, m_formWindows) + fw->close(); + + saveSettings(); + return true; +} + +QDesignerActions *QDesignerWorkbench::actionManager() const +{ + return m_actionManager; +} + +void QDesignerWorkbench::setUIMode(UIMode mode) +{ + switch (mode) { + case TopLevelMode: + switchToTopLevelMode(); + break; + case DockedMode: + switchToDockedMode(); + break; + + default: Q_ASSERT(0); + } +} + +void QDesignerWorkbench::updateWindowMenu(QDesignerFormWindowInterface *fw) +{ + if (!fw) + return; + if (QDesignerFormWindow *dfw = qobject_cast(fw->parentWidget())) + dfw->action()->setChecked(true); +} + +void QDesignerWorkbench::formWindowActionTriggered(QAction *a) +{ + QWidget *widget = a->parentWidget(); + Q_ASSERT(widget != 0); + + if (m_mode == DockedMode) { + m_workspace->setActiveWindow(widget); + } else { + widget->setWindowState(widget->windowState() & ~Qt::WindowMinimized); + widget->activateWindow(); + widget->raise(); + } +} + +void QDesignerWorkbench::showToolBars() +{ + m_toolToolBar->show(); + m_formToolBar->show(); + m_editToolBar->show(); +} + +void QDesignerWorkbench::closeAllToolWindows() +{ + foreach (QDesignerToolWindow *tw, m_toolWindows) + tw->hide(); +} + +QDockWidget *QDesignerWorkbench::magicalDockWidget(QWidget *widget) const +{ + if (!m_workspace) + return 0; + + QDockWidget *dockWidget = qFindChild(m_workspace->window(), widget->objectName() + QLatin1String("_dock")); + return dockWidget; +} diff --git a/src/designer/formdesigner/qdesigner_workbench.h b/src/designer/formdesigner/qdesigner_workbench.h new file mode 100644 index 0000000..1b922b6 --- /dev/null +++ b/src/designer/formdesigner/qdesigner_workbench.h @@ -0,0 +1,181 @@ +/**************************************************************************** +** +** Copyright (C) 1992-2006 Trolltech ASA. All rights reserved. +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** This file may be used under the terms of the GNU General Public +** License version 2.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of +** this file. Please review the following information to ensure GNU +** General Public Licensing requirements will be met: +** http://www.trolltech.com/products/qt/opensource.html +** +** If you are unsure which license is appropriate for your use, please +** review the following information: +** http://www.trolltech.com/products/qt/licensing.html or contact the +** sales department at sales@trolltech.com. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +****************************************************************************/ + +#ifndef QDESIGNER_WORKBENCH_H +#define QDESIGNER_WORKBENCH_H + +#include +#include +#include +#include +#include + +#include "qdesigner_toolwindow.h" + +class QDesigner; +class QDesignerActions; +//class QDesignerToolWindow; +class QDesignerFormWindow; + +class QAction; +class QActionGroup; +class QDockWidget; +class QMenu; +class QMenuBar; +class QVariant; +class QToolBar; +class QWorkspace; +class QCloseEvent; + +class QDesignerFormEditorInterface; +class QDesignerFormWindowInterface; +class QDesignerFormWindowManagerInterface; + +namespace qdesigner_internal { +class QDesignerIntegration; +} + +class QDesignerWorkbench: public QObject +{ + Q_OBJECT +public: + enum UIMode + { + NeutralMode, + TopLevelMode, + DockedMode + }; + +public: + QDesignerWorkbench(); + virtual ~QDesignerWorkbench(); + + UIMode mode() const; + + QDesignerFormEditorInterface *core() const; + + QDesignerToolWindow *findToolWindow(QWidget *widget) const; + QDesignerFormWindow *findFormWindow(QWidget *widget) const; + + QDesignerFormWindow *createFormWindow(); + + int toolWindowCount() const; + QDesignerToolWindow *toolWindow(int index) const; + + int formWindowCount() const; + QDesignerFormWindow *formWindow(int index) const; + + QDesignerActions *actionManager() const; + + QActionGroup *modeActionGroup() const; + + QRect availableGeometry() const; + int marginHint() const; + + void saveSettings() const; + + bool readInForm(const QString &fileName) const; + bool writeOutForm(QDesignerFormWindowInterface *formWindow, const QString &fileName) const; + bool saveForm(QDesignerFormWindowInterface *fw); + bool handleClose(); + void closeAllToolWindows(); + // + QDesignerToolWindow *mainWindow() const { return m_mainWindow; }; + void setMainWindow(QDesignerToolWindow *tw) { m_mainWindow = tw; }; + +signals: + void modeChanged(UIMode mode); + void initialized(); + +public slots: + void addToolWindow(QDesignerToolWindow *toolWindow); + void addFormWindow(QDesignerFormWindow *formWindow); + void removeToolWindow(QDesignerToolWindow *toolWindow); + void removeFormWindow(QDesignerFormWindow *formWindow); + void setUIMode(UIMode mode); + +// ### private slots: + void switchToNeutralMode(); + void switchToDockedMode(); + void switchToTopLevelMode(); + + void initializeCorePlugins(); + +private slots: + void initialize(); + void activateWorkspaceChildWindow(QWidget *widget); + void updateWindowMenu(QDesignerFormWindowInterface *fw); + void formWindowActionTriggered(QAction *a); + void showToolBars(); + void adjustFormPositions(); + +private: + QWidget *magicalParent() const; + Qt::WindowFlags magicalWindowFlags(const QWidget *widgetForFlags) const; + QDockWidget *magicalDockWidget(QWidget *widget) const; + + QDesignerFormWindowManagerInterface *formWindowManager() const; + void changeBringToFrontVisiblity(bool visible); + + bool eventFilter(QObject *object, QEvent *event); + +private: + QDesignerFormEditorInterface *m_core; + qdesigner_internal::QDesignerIntegration *m_integration; + + QDesignerActions *m_actionManager; + QActionGroup *m_toolActions; + QActionGroup *m_windowActions; + + QMenu *m_fileMenu; + QMenu *m_editMenu; + QMenu *m_formMenu; + QMenu *m_toolMenu; + QMenu *m_windowMenu; + QMenu *m_helpMenu; + + QMenuBar *m_globalMenuBar; + QToolBar *m_toolToolBar; + QToolBar *m_formToolBar; + QToolBar *m_editToolBar; + + UIMode m_mode; + + QList m_toolWindows; + QList m_formWindows; + + QWorkspace *m_workspace; + QHash m_visibilities; + QHash m_geometries; + + class ToolWindowExtra {}; + class FormWindowExtra {}; + + QHash m_toolWindowExtras; + QHash m_formWindowExtras; + bool m_initializing; + // + QPointer m_mainWindow; +}; + +#endif // QDESIGNER_WORKBENCH_H diff --git a/src/designer/formdesigner/qrc_designer.cpp b/src/designer/formdesigner/qrc_designer.cpp new file mode 100644 index 0000000..c4f3c91 --- /dev/null +++ b/src/designer/formdesigner/qrc_designer.cpp @@ -0,0 +1,1198 @@ +/**************************************************************************** +** Resource object code +** +** Created: Sun Oct 26 23:47:57 2008 +** by: The Resource Compiler for Qt version 4.3.0 +** +** WARNING! All changes made in this file will be lost! +*****************************************************************************/ + +#include + +static const unsigned char qt_resource_data[] = { + // /home/user/src/ananas-qt4/src/designer/formdesigner/images/designer.png + 0x0,0x0,0x39,0xf, + 0x89, + 0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0, + 0x0,0x0,0x80,0x0,0x0,0x0,0x80,0x8,0x6,0x0,0x0,0x0,0xc3,0x3e,0x61,0xcb, + 0x0,0x0,0x0,0x9,0x70,0x48,0x59,0x73,0x0,0x0,0xb,0x13,0x0,0x0,0xb,0x13, + 0x1,0x0,0x9a,0x9c,0x18,0x0,0x0,0x38,0xc1,0x49,0x44,0x41,0x54,0x78,0xda,0xed, + 0xbd,0x79,0x9c,0x1d,0x57,0x79,0x26,0xfc,0x9c,0x53,0x75,0xeb,0xde,0xee,0x56,0x4b, + 0xad,0xc5,0x96,0x2c,0x4b,0x5e,0x24,0x6f,0x78,0x1,0xdb,0xb8,0xd,0x76,0x10,0x18, + 0x8c,0x6d,0x30,0x1,0x87,0xc9,0x78,0x98,0x90,0x30,0x81,0x30,0x64,0x42,0x92,0x1, + 0x9b,0x40,0x42,0x48,0x20,0x13,0x96,0xc,0x1f,0x99,0x2f,0x99,0x90,0x5f,0x2,0x18, + 0x92,0xe1,0x73,0x20,0x33,0x59,0x60,0x62,0xc0,0xd8,0xd8,0xec,0x36,0xde,0xb0,0x65, + 0x2d,0x96,0x6d,0x59,0x6a,0xed,0x4b,0x4b,0xea,0x4d,0xdd,0xf7,0xd6,0x76,0x96,0xf7, + 0xfb,0xe3,0x9c,0x53,0x75,0xaa,0xfa,0xb6,0x36,0xb7,0x6c,0xd9,0xb2,0xfc,0x2b,0xd7, + 0xbd,0xbd,0xdc,0xbe,0xb7,0x9e,0xe7,0x7d,0xde,0xf5,0x9c,0x62,0x44,0x84,0xa3,0xf9, + 0xc7,0x18,0x7b,0x39,0x80,0x57,0x0,0xd8,0x9,0x60,0x17,0x80,0x9d,0x44,0x94,0xe1, + 0xa5,0x7f,0x2f,0xc8,0x7f,0xe1,0xd1,0x82,0xbf,0x68,0x59,0xe3,0xb7,0x7e,0xf3,0xb, + 0xb,0x6f,0xda,0xb7,0x45,0xc,0x6d,0x5f,0x27,0x86,0x56,0xdf,0x19,0xf,0x31,0xc6, + 0xf6,0x59,0x42,0xec,0xb4,0x84,0x98,0x7c,0xe9,0xd2,0xbe,0x8,0x9,0x0,0xe0,0x15, + 0x8b,0xce,0xe4,0x37,0xf5,0x2f,0xc,0x96,0xf6,0x2f,0xc,0x96,0x9e,0x33,0xd8,0x5a, + 0x75,0xed,0x7b,0xfb,0x91,0xb4,0xd5,0xd8,0xc8,0x76,0x35,0xb4,0xf3,0x49,0xb1,0x65, + 0xfd,0xf,0x93,0x21,0xc6,0xd8,0x36,0x4b,0x86,0x3,0x96,0x10,0xfb,0x5f,0xba,0xd4, + 0x2f,0x70,0x2,0x30,0xc6,0x6,0x4f,0x3b,0x37,0x7a,0x4b,0x23,0xe2,0x4b,0xeb,0xdf, + 0xeb,0x99,0x13,0x2c,0x58,0x7e,0x51,0xb0,0x60,0xf9,0x45,0xd1,0xe0,0xd5,0x37,0xf7, + 0x15,0x84,0x18,0xd9,0x29,0xf7,0x6c,0xbc,0x3f,0x1d,0x62,0x8c,0x6d,0xad,0xb9,0x8c, + 0x97,0x8,0xf1,0x42,0x22,0x0,0x63,0xac,0x37,0x6a,0xf1,0x1b,0x6,0x96,0xb0,0xeb, + 0x8e,0xe4,0xe7,0x3d,0x42,0xe0,0xb2,0x37,0xf5,0xe2,0xdf,0xe7,0x3a,0x19,0xdb,0x25, + 0x87,0x76,0x3f,0x23,0x87,0x3c,0x42,0xec,0xf7,0x8,0xb1,0xf3,0x25,0x28,0x4e,0x6c, + 0x5,0xb8,0xfc,0xb4,0x73,0xc3,0x55,0x61,0xc8,0x17,0x1c,0xd3,0x1f,0x89,0x78,0xcf, + 0xa9,0x2b,0xa2,0x8b,0x4f,0x5d,0x11,0x5d,0xec,0x8,0x31,0x79,0x40,0xef,0xd9,0x3b, + 0x24,0x87,0x86,0x1e,0x4b,0x87,0x18,0x63,0x43,0x35,0x85,0x78,0x89,0x10,0x27,0xa, + 0x1,0x18,0x63,0x4b,0xa2,0x16,0xbf,0x66,0xce,0x82,0x60,0xd5,0xac,0xfd,0xd1,0x88, + 0xf7,0x2c,0x38,0x9d,0xaf,0x5c,0x70,0x7a,0xb8,0xf2,0xa2,0xd7,0xb6,0xf0,0xb6,0x5b, + 0x7,0x30,0xb6,0x5b,0xe,0xd5,0x8,0xb1,0xff,0xa5,0x4c,0xe3,0xf8,0xff,0x63,0x87, + 0x4b,0x3,0x19,0x63,0x6f,0x5a,0x79,0x79,0xf4,0xc9,0xde,0x79,0xc1,0xa0,0xfb,0xda, + 0x3b,0x3f,0x53,0xa,0x41,0x2b,0xa,0x20,0x15,0x41,0x2a,0x3d,0xab,0x6f,0x6c,0x6a, + 0x54,0xed,0xf1,0x33,0x8d,0xb1,0x61,0xb9,0xbd,0x16,0x58,0xbe,0x94,0x69,0x1c,0x6f, + 0x2,0x30,0xc6,0xce,0x1f,0x38,0x25,0xf8,0xcd,0xe5,0x17,0x47,0x1f,0xf2,0xbf,0xee, + 0x13,0x0,0x0,0x16,0xcc,0x69,0x42,0x28,0xc2,0x54,0x92,0x1f,0xb7,0x37,0xea,0x8, + 0xb1,0x7f,0x9b,0xda,0xb3,0xfe,0x87,0xc9,0xd0,0xb6,0xb5,0xd9,0xb6,0x97,0x52,0xcf, + 0xe3,0xef,0x2,0x5e,0xb1,0x78,0x45,0xe3,0xa6,0xc3,0xbd,0xc8,0x58,0x3b,0xc3,0xf9, + 0xa7,0x2f,0xc0,0xe2,0x81,0x5e,0x74,0xb2,0x1c,0x52,0x69,0x1c,0xec,0xe4,0xc8,0xa5, + 0x42,0x3b,0x11,0x68,0x67,0x2,0x5a,0xd3,0xb3,0x7a,0xa3,0x65,0xea,0x9,0xf8,0x99, + 0x46,0x2d,0xf5,0xdc,0xff,0x52,0xa6,0x31,0x4b,0x4,0x60,0x8c,0xd,0x2e,0x5a,0xd6, + 0xb8,0x26,0xea,0x65,0x2b,0x8f,0xe4,0x85,0x4e,0x9d,0xdb,0xf,0x6,0x60,0x4e,0xb3, + 0x5,0x80,0x30,0xd0,0xdb,0x3,0x30,0x3,0x3a,0x11,0xa1,0x93,0x9,0x4b,0x8c,0xc, + 0xed,0x54,0x20,0xcd,0x15,0xda,0xa9,0x38,0xe6,0x37,0xde,0x2d,0xf5,0x9c,0xda,0xaf, + 0xf6,0xd4,0x32,0xd,0x17,0x43,0xec,0x7f,0x29,0xb0,0x3c,0xa,0x2,0x30,0xc6,0x2, + 0x0,0x97,0x9e,0x72,0x36,0x7f,0xc7,0x91,0xbc,0xc8,0x40,0x5f,0xf,0x38,0xb,0x81, + 0xc2,0x9d,0x90,0x3d,0xcc,0x63,0x6,0xc2,0x9c,0x26,0x37,0xc4,0xe8,0x6b,0x55,0xbe, + 0x37,0xd1,0xc9,0xd1,0x4e,0x73,0x74,0x52,0x81,0x76,0x22,0x8f,0x99,0x14,0x3d,0x73, + 0x82,0x5,0x3d,0x73,0x82,0x5,0x7e,0xa6,0xe1,0x52,0xcf,0x9d,0x4f,0xe5,0x7b,0x5e, + 0xca,0x34,0x8e,0x4e,0x1,0xae,0x5a,0x76,0x61,0xe3,0x2d,0x47,0x9a,0xf6,0x35,0x1b, + 0xd,0x10,0x71,0x4b,0x1e,0x8f,0x4,0x84,0xa,0xd8,0xd5,0x3,0x5,0x21,0xa6,0x93, + 0xc2,0xa8,0xc4,0xb3,0x21,0x45,0x3d,0xf5,0x9c,0x21,0xd3,0x28,0x14,0xe2,0x64,0xcd, + 0x34,0xc2,0x19,0x8a,0x3e,0xd7,0xcc,0x3b,0x25,0xbc,0xfe,0x48,0x5f,0xa4,0x19,0x36, + 0x0,0xf0,0x42,0xee,0xcb,0x7f,0x74,0x8,0x52,0xd8,0xaf,0x11,0x59,0x57,0x51,0x1e, + 0x3,0x7d,0x3d,0x96,0x14,0xe5,0x6b,0xcc,0x6,0x29,0x16,0x9c,0x1e,0x76,0x4d,0x3d, + 0x87,0x37,0x89,0x3d,0xb6,0xa7,0xb1,0xfd,0x64,0x4b,0x3d,0xbb,0x29,0xc0,0xd5,0xa7, + 0x9d,0x1b,0xae,0xe2,0x1c,0x3d,0x47,0xfa,0x22,0x73,0x5a,0x7d,0x0,0x85,0xd3,0xad, + 0xdd,0x8b,0x1,0x7c,0x52,0x30,0xd6,0x85,0x4,0x38,0x84,0x5a,0x30,0x9f,0x14,0xe5, + 0x6b,0x4d,0x74,0x32,0x1c,0xec,0xe4,0x68,0xa7,0xa2,0x88,0x2b,0x8e,0x95,0x10,0xd7, + 0xbe,0xb7,0x7f,0x5a,0xea,0x79,0x32,0x34,0xb9,0xba,0x11,0xe0,0x15,0x73,0x17,0x5, + 0xd7,0x1f,0xd5,0x8b,0xb0,0xb0,0x70,0x1,0x60,0xee,0xd4,0xc5,0xda,0xed,0x63,0x42, + 0x1d,0xf0,0x9a,0x5a,0xd4,0x9,0x41,0x55,0x42,0x55,0x95,0xa2,0xa7,0x78,0x2e,0x95, + 0x46,0x3b,0x15,0x38,0xd8,0xc9,0xad,0x62,0xc8,0xa3,0xaa,0x4f,0x1c,0x45,0x93,0x6b, + 0x27,0x80,0x3,0x2f,0x86,0x4c,0x23,0x9c,0x9d,0x97,0xe1,0x0,0x82,0x8a,0xc4,0x93, + 0x63,0x2,0xa8,0x20,0x5,0xdc,0x57,0xa9,0x8b,0xa5,0x5b,0x55,0xa0,0x1a,0xf8,0x15, + 0xb5,0xa8,0xc5,0x14,0xac,0xa6,0x14,0x8d,0x80,0x63,0x7e,0x5f,0x88,0xf9,0x9e,0xfb, + 0x48,0x85,0x34,0x81,0x66,0x22,0x6c,0xc0,0x79,0xe4,0xae,0x63,0xa6,0x26,0xd7,0xce, + 0x27,0xc5,0x96,0x1d,0x6b,0xb3,0xdd,0x2f,0x86,0x26,0xd7,0xac,0x10,0xa0,0x19,0xb6, + 0x40,0xc4,0xac,0xf9,0x13,0x18,0x63,0x55,0xcb,0x2e,0x80,0x63,0x16,0x3e,0xf2,0xd4, + 0xe2,0xd0,0xa4,0x20,0x2a,0x15,0x84,0x79,0x44,0x71,0xae,0x85,0x99,0x72,0x56,0x55, + 0x29,0xbc,0xa3,0xd5,0xe0,0x58,0x32,0x10,0x1,0x3,0x34,0x2d,0x9e,0x70,0x84,0x38, + 0x52,0xd7,0x51,0x27,0xc4,0x8b,0xa1,0xc9,0x35,0x6b,0x4,0xb0,0xf8,0x5a,0x2b,0xee, + 0xe6,0xcf,0x19,0x18,0x43,0x4d,0xda,0x9d,0x5a,0x1c,0x9a,0x14,0xc,0x5e,0xa0,0x48, + 0xb5,0xd7,0x60,0x35,0xf2,0xb0,0x9a,0x5b,0xa9,0x90,0x42,0x57,0x82,0xcc,0x65,0xb, + 0xcd,0x5f,0x4f,0x73,0x59,0xb8,0xe,0x47,0x8c,0x63,0xc9,0x34,0xe,0xd1,0xe4,0xda, + 0x40,0x44,0x1b,0x5e,0xb4,0x4,0x20,0x70,0xf,0x1c,0xab,0x2,0xf0,0x54,0x60,0x5a, + 0x30,0xe8,0xc9,0xf8,0xc,0x6a,0x41,0x9e,0xc5,0x53,0xcd,0x93,0x4c,0x73,0xb,0x8c, + 0xe,0x1d,0x77,0x30,0xaa,0x12,0x8d,0x4a,0x32,0x30,0x68,0xf4,0x44,0x1c,0xad,0x28, + 0xc2,0xa2,0xb9,0xbd,0xd3,0x54,0xc2,0xc4,0x13,0xf9,0x11,0xc5,0x12,0x33,0x35,0xb9, + 0x9e,0x7e,0x20,0x7b,0x94,0x31,0xf6,0xa9,0x13,0x91,0x4,0xb3,0x43,0x0,0x62,0x55, + 0xc0,0xdd,0xc5,0x2e,0xa4,0x99,0x95,0x2a,0x50,0xc9,0x39,0xa7,0xab,0x85,0x1,0x9d, + 0x15,0x34,0x61,0x96,0x54,0x8c,0xd5,0x82,0x42,0x56,0x9,0x2d,0xa,0x86,0x30,0xf, + 0x7c,0xb2,0xaf,0x67,0xfe,0x86,0xb6,0x3f,0xaf,0x4b,0xa5,0x2a,0x48,0xa4,0x8b,0xdf, + 0xa3,0x5a,0x2a,0xba,0x6c,0xa1,0x8d,0x25,0x72,0x85,0x89,0x38,0xc3,0xc1,0x4e,0x86, + 0x89,0x4e,0x7e,0xc4,0x6e,0x63,0xc1,0xe9,0xe1,0xca,0xb,0xae,0x6,0xbe,0xfd,0x97, + 0xb8,0x8,0xc0,0x8b,0x8f,0x0,0x21,0xf,0x1,0x62,0x6,0xe3,0x12,0xb6,0x2,0x78, + 0x56,0xd3,0xa,0xf2,0x64,0xbe,0xfc,0x25,0xe7,0xcb,0x51,0x95,0x79,0xc6,0xaa,0xca, + 0xe0,0x81,0xce,0xea,0xcf,0x6b,0x59,0x5,0x2b,0xfe,0x1a,0x79,0xe0,0xea,0x82,0x40, + 0x64,0xad,0xbf,0x42,0x4,0x18,0x22,0x50,0x97,0xfa,0x44,0xab,0x11,0x60,0xc9,0x40, + 0x3,0x4b,0x6,0xfa,0x0,0x0,0x52,0x29,0x4c,0x74,0xf2,0x82,0x10,0xcf,0xa6,0xac, + 0xfd,0x82,0x26,0x40,0x6f,0xb3,0xcf,0xa4,0x80,0x84,0x69,0x92,0xcf,0x3c,0xe1,0xad, + 0x9,0xc4,0x34,0x35,0x20,0x46,0x60,0x15,0xec,0x59,0x19,0x3,0x58,0x22,0xb0,0x42, + 0x1c,0x8c,0x22,0x30,0x54,0xdd,0x42,0x55,0x5d,0xaa,0xe9,0xa3,0xb,0x26,0xc9,0xb3, + 0x74,0x82,0x6,0x15,0xa0,0x57,0xe3,0x84,0x6a,0xfc,0x50,0x8b,0x27,0x18,0x21,0xe4, + 0x1,0x16,0xf5,0x37,0xac,0xdb,0x0,0x84,0x52,0x38,0x70,0x30,0x29,0x8,0x91,0x4b, + 0x75,0x72,0x10,0xc0,0x18,0x67,0xd5,0xce,0x19,0xf9,0xd0,0x33,0xd4,0xf4,0xbc,0xb0, + 0x56,0xf2,0xfd,0x79,0x91,0x45,0x58,0xb9,0x77,0x3e,0x9f,0x95,0x64,0xb1,0xdf,0x9d, + 0x7e,0x66,0x1e,0xc7,0x98,0xa7,0x6,0xbe,0xd4,0x33,0x14,0xa0,0x3b,0x5,0x30,0x4, + 0x30,0x67,0x46,0xe5,0x73,0x56,0xa8,0x85,0xae,0xc4,0xe,0xe5,0x7b,0x9d,0x4e,0x8a, + 0x6,0xf,0xb0,0x74,0x7e,0x3,0x4b,0xe7,0x1b,0x82,0x8c,0x4e,0x26,0x78,0x6a,0xd7, + 0x18,0xd4,0xb3,0xec,0x82,0xbe,0x30,0xea,0x0,0xae,0x8,0x54,0x91,0x79,0x56,0x2b, + 0xf4,0x38,0x97,0xe0,0x11,0x83,0x15,0xee,0x1c,0xcc,0xa,0x75,0x1,0x3e,0x73,0x15, + 0x6,0x6,0x10,0x3,0x67,0xe,0x74,0x6,0xc6,0x3c,0x42,0xb8,0xc7,0x4e,0x25,0xe0, + 0x13,0xa7,0xea,0xeb,0xb,0x15,0x60,0x6,0x60,0xd,0x2,0x91,0x2e,0x94,0xc0,0x29, + 0x0,0x81,0xa,0x42,0x80,0x69,0x2f,0x30,0x9d,0xde,0xcb,0x98,0x89,0x14,0xb,0xfb, + 0x43,0xf4,0xf7,0x74,0x30,0xd1,0x49,0x5f,0xfc,0x4,0xa8,0x54,0x7a,0x19,0xf3,0xea, + 0x3f,0xd3,0x74,0xdf,0xe4,0x7,0x8c,0xaa,0xc9,0x80,0x97,0x9,0x30,0xcf,0xab,0x73, + 0xfb,0x98,0x33,0x3,0x7c,0x71,0x2e,0x80,0x67,0x15,0x2,0xb0,0x9a,0xa7,0x61,0xcc, + 0xb7,0xdf,0xba,0xf4,0x13,0x18,0x69,0x10,0xd3,0xd0,0xf6,0x4c,0x64,0x68,0x1,0x72, + 0x84,0xe0,0x96,0x34,0xba,0x4b,0xc9,0x9a,0xe,0x41,0xa,0xe3,0xcb,0xe6,0xb4,0x5a, + 0x2f,0x7e,0x2,0x18,0xc1,0x64,0x75,0x9c,0xa7,0x1,0xf,0xcf,0x42,0x89,0x58,0x45, + 0xb2,0x41,0xc6,0xfa,0x79,0x45,0xee,0x59,0x41,0x2,0x66,0xcf,0x1c,0x1c,0x8c,0x19, + 0x22,0x70,0x17,0x7,0x30,0x86,0x80,0x31,0x4c,0x1c,0xcc,0x30,0xbc,0x3f,0x41,0x92, + 0xa,0x8c,0x4d,0xa4,0x46,0x59,0x98,0x75,0x33,0x1c,0x68,0x35,0x39,0x6,0xe6,0x36, + 0x31,0x6f,0x6e,0x84,0x53,0x17,0xb5,0x10,0x4,0xc,0x9c,0x69,0x68,0x22,0x30,0xa6, + 0xa0,0x89,0x40,0x4c,0x3,0xa4,0xa0,0x99,0x21,0x1,0xa0,0xad,0x8b,0xd3,0x56,0x19, + 0x6a,0xf5,0xd,0x6,0xb0,0x43,0x90,0x82,0x83,0x9f,0x1c,0x95,0x40,0xa2,0x5a,0xc, + 0x30,0xcd,0x15,0x4c,0x27,0x6,0x63,0x2e,0x2c,0x60,0x35,0xe5,0x60,0x85,0x75,0x73, + 0xc6,0x4b,0x2,0x38,0xe0,0x19,0x7,0xb7,0xa0,0x1f,0x18,0x49,0xb0,0x65,0xeb,0x14, + 0x76,0xec,0x6a,0x23,0x17,0xba,0x7c,0x19,0xe6,0x3a,0x90,0xa5,0xef,0x37,0xf1,0x47, + 0x5c,0x58,0xe8,0xc0,0xbc,0x26,0x56,0x9e,0x35,0xf,0x67,0x2e,0x9b,0x83,0xa0,0x11, + 0x80,0x41,0x43,0x93,0xb2,0x65,0x6d,0x6d,0x95,0x40,0xd9,0x4f,0xc1,0xad,0xa,0xe8, + 0xea,0x7,0x21,0x3a,0x24,0x29,0x9a,0x8d,0xd6,0xc9,0x42,0x80,0xe9,0x36,0xcf,0x66, + 0x0,0xde,0x5,0x69,0x64,0x5d,0x4,0xb1,0x32,0xa0,0x43,0x1,0xb7,0xb3,0x78,0x7, + 0xb8,0x3,0x9d,0x23,0xe0,0xc,0xdb,0xb7,0xb5,0xb1,0x76,0xfd,0x38,0x26,0xdb,0xd2, + 0x2,0x1e,0x80,0x21,0xf4,0xb2,0x46,0xaf,0x40,0x44,0xa8,0xf6,0xc,0x2c,0x31,0x26, + 0xc6,0x14,0x1e,0x1d,0x1f,0xc5,0xea,0x35,0x23,0x38,0xfb,0xcc,0xb9,0xb8,0xe8,0x82, + 0xf9,0x68,0xf5,0x44,0xd0,0xd0,0x50,0xa4,0xc0,0xa0,0xa1,0xc0,0x4d,0xaa,0x48,0xda, + 0x16,0xbb,0xf4,0xc,0xcd,0xac,0x6a,0x2c,0xe0,0xbe,0x1a,0x5,0xd1,0xc9,0x91,0x5, + 0x68,0x9a,0x9e,0x82,0xf9,0xa4,0x60,0x95,0xdc,0x1c,0x95,0x68,0x9f,0x51,0x69,0xb6, + 0xcc,0x4a,0x3c,0xb3,0x80,0x57,0x80,0x67,0xc,0xa3,0xa3,0x19,0x1e,0x79,0x64,0xc, + 0x63,0x63,0xc2,0xb8,0x2,0x1e,0xd9,0x40,0x9f,0x81,0xf1,0x2,0xef,0xb2,0x3f,0x40, + 0xf5,0x4a,0x20,0x15,0x19,0x0,0x40,0x60,0xda,0xf8,0xfc,0xa1,0x2d,0x31,0x76,0xee, + 0x4c,0x70,0xfe,0x79,0x3,0xb8,0xf0,0x82,0x1,0x30,0x28,0x28,0x58,0x35,0x20,0x65, + 0xc3,0x45,0xd,0x10,0xb7,0xbf,0xdb,0xc5,0x1d,0x90,0x9f,0x2,0x93,0x57,0x21,0x7d, + 0x91,0x13,0x80,0x6a,0x9f,0xbf,0x5e,0xb,0xaa,0x25,0x1,0x60,0x64,0xc3,0x38,0x97, + 0x1,0xb0,0x32,0xa9,0xb3,0x5e,0x1e,0xdc,0xfb,0x2f,0x60,0xc,0x21,0xe7,0x78,0xfc, + 0xb1,0x71,0xac,0x5f,0x3f,0x5,0xce,0x39,0x38,0x8b,0xc,0x1,0x88,0x5b,0x45,0x61, + 0x45,0xd6,0xc7,0xfc,0xc2,0x52,0xad,0x1e,0x40,0x15,0x1f,0xad,0x8b,0x33,0x48,0x23, + 0xcf,0x8,0xeb,0xd6,0x1f,0xc4,0xee,0xdd,0x9,0xae,0xbc,0x62,0x11,0xfa,0xe7,0x9a, + 0x29,0x27,0x2,0x7,0x41,0x81,0xd9,0x98,0x80,0x48,0xdb,0x17,0xd5,0x95,0xf,0x49, + 0x5d,0x5a,0xdb,0x44,0xfc,0x24,0x73,0x1,0xb5,0xa0,0x9f,0x55,0xeb,0x3e,0xd6,0xdf, + 0x3b,0xd9,0x47,0x25,0xb3,0x67,0x3e,0xf4,0x8c,0x81,0xb3,0x0,0x1,0xe7,0xc8,0x13, + 0x85,0xbb,0xef,0xd9,0x8f,0xf1,0x31,0x85,0x20,0x68,0x15,0xc4,0x28,0x52,0x42,0xaa, + 0xd5,0x1,0xa8,0x56,0x4,0xb2,0xcf,0xa9,0xa8,0x8,0xc2,0x3,0xdf,0x66,0x5,0x16, + 0x5c,0xd,0x8d,0xd1,0x11,0x85,0xbb,0xee,0xda,0x87,0x57,0xbf,0x7a,0x21,0x96,0x9f, + 0xd1,0xe3,0xd1,0x49,0x41,0xd9,0x92,0xb7,0x26,0xd7,0xee,0xf6,0x7d,0x3f,0xab,0xf4, + 0x43,0x18,0x0,0xce,0x1a,0x27,0x9,0x1,0x66,0xc8,0x0,0xa8,0xc8,0xd5,0x7d,0x16, + 0xb0,0xa2,0x58,0x54,0xa4,0x72,0x1e,0x5,0x18,0x63,0xe0,0x8,0xc0,0x19,0x47,0xfb, + 0xa0,0xc0,0x77,0xef,0x18,0x83,0x14,0xc,0x41,0xd0,0xac,0x28,0x3,0x77,0xe4,0xf1, + 0xdd,0x31,0xab,0x4d,0x18,0x79,0xe9,0x26,0xf7,0xdb,0xc8,0x45,0xb1,0xc7,0x94,0x83, + 0xc9,0xba,0x5,0xe,0x65,0x2,0x3f,0xd2,0x78,0xf0,0x81,0x9,0x8c,0x8d,0xa,0xbc, + 0xfc,0xb2,0x79,0x8,0x48,0xd9,0x56,0x93,0x82,0x32,0x14,0xb0,0x61,0x46,0x17,0x17, + 0x30,0xad,0x7,0x72,0x32,0x54,0x2,0x67,0x28,0x76,0xd9,0xc,0xaf,0x8,0xf8,0x8a, + 0x69,0x21,0x2,0x88,0x55,0xa1,0x37,0x96,0xcf,0x11,0xb0,0x0,0x81,0x3,0xff,0x9b, + 0x63,0x50,0x2a,0x44,0x18,0x86,0xe0,0x2c,0x28,0x2,0xc2,0x92,0x38,0x55,0x3f,0x44, + 0x5e,0x27,0x90,0x6a,0xfd,0x3,0x62,0x54,0x93,0x89,0x32,0x53,0x70,0x75,0x4b,0x22, + 0xd,0x66,0x7d,0x3e,0x48,0xe1,0xe9,0x27,0x53,0x64,0x29,0x70,0xc5,0xab,0xe7,0x19, + 0x67,0x41,0xc,0xc,0xaa,0x8c,0x63,0x48,0xa3,0x32,0xfc,0xe2,0x55,0x35,0x9,0xc0, + 0xdc,0xd6,0xfc,0x93,0x23,0x6,0x38,0xa2,0x4d,0x46,0x18,0x2b,0x9b,0x43,0x8c,0x79, + 0x35,0x3b,0x13,0xf4,0x95,0xc1,0x1f,0x47,0x7b,0x52,0xe0,0xce,0x7f,0x1d,0x87,0x94, + 0xd,0x44,0x8d,0x6,0x2,0x16,0x22,0x60,0x41,0x11,0x1c,0x3a,0x2,0xb8,0xf6,0xb2, + 0x3,0x8f,0x6c,0x4,0x4e,0x5d,0xd2,0xb3,0xa2,0x52,0xc8,0x0,0xc6,0x78,0x25,0x23, + 0x71,0x69,0xa3,0xa9,0xfe,0x85,0x80,0xcd,0x2,0x80,0x0,0x5b,0x37,0xb,0xf4,0xf6, + 0xc6,0xb8,0xf0,0x92,0x3e,0x68,0x26,0x6d,0xb1,0x8,0x36,0x45,0xe4,0x25,0xd1,0xca, + 0x28,0xd0,0x73,0x7d,0x74,0x92,0xb8,0x80,0x2e,0xa9,0x5e,0x25,0x16,0x28,0x93,0x7e, + 0x1b,0x9,0x5a,0x1f,0xe9,0xe5,0xfa,0xdc,0x5a,0x3e,0x29,0xc2,0x8f,0xee,0x9a,0x82, + 0xc8,0x1a,0x8,0xc3,0x8,0x1c,0xd,0x6b,0xfd,0x41,0xe1,0xf3,0x4b,0xc5,0xb5,0xd5, + 0x3b,0x22,0x7b,0xd6,0x96,0x8,0xb6,0xba,0x87,0xfa,0x78,0x19,0x3,0xe3,0x96,0x40, + 0x36,0xcb,0xf0,0x9f,0x33,0xab,0xa,0xc,0xa1,0x51,0x1,0x84,0x0,0x4,0x9e,0x78, + 0x3c,0x45,0x6f,0x6f,0x88,0x33,0x56,0xb4,0x40,0x8c,0x81,0x93,0xb2,0x24,0xd0,0x5e, + 0x89,0xb9,0x1c,0x5c,0x20,0xd6,0xed,0x42,0xbc,0x68,0x9,0x60,0x0,0xa8,0xcb,0x2, + 0x63,0xac,0x9a,0xc,0x54,0x52,0x3e,0x78,0x65,0x5c,0x56,0x54,0xf7,0xc2,0x80,0xe1, + 0x47,0x77,0x4f,0x60,0xfc,0x0,0x43,0xd4,0x68,0xa2,0xc1,0x1b,0x8,0x83,0x46,0x21, + 0xff,0x8c,0x95,0x25,0x26,0xd2,0x1a,0x9a,0x18,0xb4,0xd6,0xc5,0xa1,0xb4,0x82,0xd6, + 0xa,0x9a,0x24,0x16,0x2f,0xd,0xb1,0xe4,0xf4,0x26,0x38,0x27,0xcc,0x5f,0xd0,0xc0, + 0xe8,0x88,0x49,0x1d,0xc7,0x47,0x5,0xf6,0xf,0x4b,0x88,0xc,0xe0,0x3c,0x0,0xe7, + 0x1,0x82,0x80,0x83,0x73,0x6e,0x88,0xc9,0x39,0xb8,0x2d,0x16,0x31,0xa6,0x1,0x16, + 0x80,0x18,0xc7,0xea,0x87,0x12,0xcc,0x9b,0x1f,0xa1,0x7f,0x20,0xb0,0xb5,0xcf,0x72, + 0xc8,0x85,0x48,0x57,0x9a,0x5f,0x27,0x3e,0xec,0xb3,0xec,0x2,0x4c,0x39,0x75,0xba, + 0x2c,0x94,0x80,0x31,0x23,0xaf,0x1e,0xf8,0x3e,0x9,0xb8,0xad,0xf4,0x3d,0xbd,0x26, + 0xc6,0xb6,0x67,0x8,0xcd,0xa8,0x85,0x46,0x10,0x21,0xc,0x1a,0x8,0x59,0x58,0x5, + 0x9f,0xc,0xf8,0xa4,0x1,0xa5,0x34,0x94,0x96,0x90,0x4a,0x42,0x29,0x89,0x53,0x97, + 0x72,0xac,0xbc,0xa0,0x85,0x73,0x2e,0xe8,0x31,0x3f,0xe7,0xf5,0x97,0x4f,0x3b,0xa3, + 0x51,0x29,0x23,0xef,0xdb,0x9b,0x61,0xf3,0xc6,0x14,0x9b,0x9f,0xce,0x10,0x6,0xd, + 0x4,0x21,0x10,0x4,0x1,0xc2,0x80,0x81,0xf1,0xc0,0x66,0x22,0x4,0xce,0x43,0x30, + 0xa,0x20,0x64,0x8e,0x87,0x7f,0xd2,0xc6,0xf5,0xbf,0x34,0x0,0xe,0x6d,0x5d,0x4, + 0xb3,0x75,0x5,0x56,0x19,0x7d,0xa7,0x93,0x89,0x0,0x20,0xe7,0x83,0xfd,0xd4,0xe, + 0xc5,0x40,0xa7,0x9,0xf1,0xc,0xf8,0xac,0xfc,0xa1,0x5a,0x3b,0x97,0x21,0x8b,0x15, + 0x7e,0xfe,0xd3,0x1c,0x8d,0xa0,0x7,0x8d,0xa0,0x89,0x30,0x88,0x10,0xf2,0x10,0x1, + 0xf,0x8c,0x9a,0x10,0x8c,0xb4,0x6b,0x5,0xa5,0x8,0x52,0x29,0xe4,0x22,0x87,0x94, + 0x39,0x6,0x16,0x69,0xc,0xae,0x9a,0x83,0xc5,0xa7,0x87,0xd0,0x44,0x10,0x4a,0x96, + 0x59,0xbf,0xd7,0x56,0xe6,0x5e,0x89,0x79,0xd1,0x92,0x8,0xa7,0x9e,0xd6,0xc4,0x65, + 0x83,0xa,0xf,0xdd,0x37,0x89,0xed,0x43,0x39,0xa2,0x46,0x4,0x44,0x1,0xc2,0x80, + 0x83,0x7,0x36,0xe0,0x84,0x6,0x78,0x8,0xf0,0x0,0x93,0xa3,0x31,0x36,0xac,0x8e, + 0x71,0xc1,0xa5,0x2d,0x30,0xa6,0x6d,0xc9,0xd7,0x4a,0x3f,0x95,0x7d,0xce,0x17,0x12, + 0x3,0x66,0xa9,0x1d,0x4c,0x95,0x7e,0x1f,0x98,0xd7,0xd,0x64,0x7e,0x5d,0x88,0x57, + 0x62,0x42,0x5f,0xfa,0x7f,0xfa,0xfd,0xe,0x94,0x88,0xd0,0x6a,0x19,0xf0,0x3,0x1e, + 0x21,0xe0,0x46,0xfa,0x4d,0xdd,0x45,0x43,0x6b,0x18,0xf0,0x85,0x42,0x2e,0x4,0xb2, + 0x3c,0xc3,0xcb,0x2e,0xb,0x30,0xf8,0xda,0xb9,0xd0,0xa4,0x91,0x2b,0x59,0xc4,0x3, + 0x84,0xfa,0x44,0x2,0x2b,0x2,0x48,0xce,0x74,0x51,0x61,0x6c,0xf6,0x72,0xbc,0xe1, + 0xcd,0xb,0xb0,0xe5,0x99,0xe,0x1e,0xfc,0x51,0x82,0x3c,0xe3,0x60,0x91,0x29,0x2d, + 0x23,0x8,0xc0,0x59,0x68,0x49,0xc0,0x11,0x72,0xc2,0xfa,0x47,0xda,0x38,0xf3,0x9c, + 0x26,0xc2,0x5e,0x6e,0x8b,0x43,0xcc,0xc6,0x1f,0x95,0xf1,0x97,0x17,0x8c,0x1b,0x98, + 0x5,0x17,0x60,0x82,0xaf,0xba,0x2a,0x70,0xc6,0x2a,0xc5,0x5f,0x2a,0x82,0x0,0x42, + 0x35,0x7,0x0,0xe,0xec,0xce,0xb1,0x6d,0x23,0xa1,0xb7,0x27,0xb2,0xd2,0x6f,0xe4, + 0x9f,0x73,0x6e,0xad,0x9f,0x8c,0x8f,0x97,0x6,0xfc,0x4c,0xe4,0xc8,0xb2,0xc,0x57, + 0x5f,0xdf,0xc4,0x8a,0xb,0x1b,0xc8,0x95,0x80,0x22,0xd3,0xd9,0x73,0x47,0x1,0x6, + 0x95,0xad,0x62,0xee,0x95,0x99,0x3,0xce,0xa1,0x19,0x21,0xb0,0xd3,0x42,0x67,0x9f, + 0xdb,0x8b,0xf9,0xb,0x1a,0xb8,0xf3,0x5f,0xa6,0x90,0x67,0x1c,0x1c,0x21,0x2,0x16, + 0x82,0x7,0x1,0xc0,0x3,0x80,0x38,0xa2,0x80,0x20,0xb9,0xc2,0xea,0xfb,0x63,0x5c, + 0x75,0x43,0x2f,0x14,0xe3,0xa5,0xa,0xc0,0x94,0xc4,0x5f,0x68,0x6e,0x60,0x56,0x6a, + 0x95,0x85,0xd5,0x15,0xd6,0x67,0x81,0xa8,0xc,0x5e,0x52,0xd7,0xcb,0x12,0x86,0x84, + 0x47,0x7e,0x9c,0x21,0xe4,0x4d,0x84,0xdc,0x82,0xcf,0x23,0x4,0xcc,0xa4,0x7f,0xc, + 0x1c,0x20,0x6,0xad,0x8,0x52,0x2a,0xe4,0x79,0x8e,0x34,0xcd,0xf0,0xea,0xeb,0x42, + 0x9c,0xf5,0xb2,0x10,0x42,0x29,0x8,0xad,0xcc,0x59,0x49,0x8,0xa5,0x20,0x95,0x82, + 0x50,0x1a,0x52,0x29,0x48,0xd2,0x90,0x5a,0x41,0x6a,0x6d,0x49,0x62,0xe,0x13,0x30, + 0x12,0x94,0xd6,0xf6,0x67,0x34,0xe6,0x2d,0xc,0x71,0xe3,0xbf,0xef,0x87,0xd2,0x19, + 0xb2,0x4c,0x40,0x4a,0xd,0xd2,0x1c,0x8c,0x42,0xfb,0xde,0x5a,0x88,0xc2,0x16,0x76, + 0x6f,0x61,0x98,0x18,0x51,0x45,0x3d,0xd2,0xc5,0x26,0x46,0xd,0x50,0x39,0x4e,0xa, + 0x2,0x90,0x67,0x79,0x4,0x9f,0xc,0xba,0x42,0x8a,0x72,0xfe,0x83,0xc0,0x99,0xa9, + 0xce,0xed,0xdb,0x99,0x61,0xcf,0x56,0x66,0x2c,0x3f,0x6c,0x9a,0x80,0x8c,0x37,0x4c, + 0xf0,0xc5,0x2,0x90,0x66,0x50,0x52,0x1b,0xcb,0x4f,0x73,0x24,0x49,0x86,0x57,0xbf, + 0x91,0xe3,0xec,0x97,0x5,0x6,0x70,0x2d,0xcb,0xb3,0x36,0x24,0x90,0xda,0x1c,0x4a, + 0x2b,0xb,0xb4,0x3,0x9e,0xa,0x2,0xb8,0xb4,0x51,0xc3,0x12,0x82,0x14,0x94,0xd6, + 0x18,0x58,0x18,0xe2,0xc6,0xff,0xd0,0xb,0xa5,0x53,0xe4,0x99,0x84,0x52,0xa6,0x9, + 0xc4,0x59,0x88,0x30,0x88,0x6c,0x8c,0xd2,0x83,0x8d,0x8f,0x8b,0x4a,0xc7,0xd3,0xa8, + 0x94,0xb9,0x6,0x4a,0x9b,0x43,0x9f,0xc,0x4,0x20,0xef,0xa2,0x96,0x17,0x57,0x97, + 0xc5,0x19,0x6f,0x14,0x8b,0xd5,0xc6,0x47,0x38,0x7,0x9e,0x5a,0x2d,0xd0,0x8,0x9b, + 0xf6,0x30,0xa,0x10,0x4,0x21,0x2,0x6e,0xac,0x9f,0xac,0xdf,0x17,0x42,0x22,0x4b, + 0x73,0x9c,0x71,0x9e,0xc4,0xd9,0x17,0x5,0x16,0x70,0xb,0xbe,0x92,0xc6,0xda,0x95, + 0x34,0x59,0x81,0xd6,0xc6,0xb2,0x5d,0x7a,0xe8,0xc6,0xbe,0x2c,0xf0,0xce,0x75,0x4d, + 0x8c,0x8,0x3c,0x78,0xcf,0x54,0x45,0x15,0x24,0x29,0xc,0x2c,0xc,0x71,0xe5,0xeb, + 0x2,0xa4,0x49,0x2,0x91,0x4b,0xbb,0xbb,0x49,0x80,0x80,0x47,0x68,0x4,0x4d,0x34, + 0xc2,0x16,0xb6,0x3d,0x9,0xc4,0x53,0xba,0x92,0xf4,0x51,0xcd,0x18,0xa6,0xb9,0xc6, + 0x17,0xaf,0xb,0x50,0x20,0x5b,0x43,0x27,0x6b,0x69,0xe4,0x5d,0xf4,0x6e,0xe3,0x53, + 0xc,0x4,0x52,0x12,0x1b,0x7e,0xae,0x4d,0xce,0xdf,0x68,0x56,0xfd,0x3f,0xe3,0x0, + 0x38,0xb4,0x26,0x48,0x21,0x91,0xa6,0x39,0x34,0x8b,0x31,0x78,0x6d,0xc3,0x4a,0xbc, + 0x1,0x5c,0x28,0x65,0x25,0x5e,0x9a,0xb3,0xb3,0xe6,0x1a,0x19,0xfd,0xc1,0x24,0x6, + 0x0,0x8a,0x70,0xcf,0x3f,0xc5,0x58,0xff,0x90,0xc4,0x13,0x8f,0xc4,0x5,0x91,0x9d, + 0x6a,0xac,0xbc,0x28,0xc2,0xe2,0xe5,0x39,0xe2,0x4e,0x2,0x91,0x2b,0x90,0x66,0x8, + 0x58,0x88,0x46,0xd8,0x44,0xb3,0xd1,0x83,0x46,0xa3,0x17,0x3b,0x37,0xa9,0xf2,0xf5, + 0xec,0x67,0x2e,0x3e,0x3b,0x19,0xf2,0x9d,0x4,0x4,0xa0,0xa2,0xf2,0xa6,0xa1,0xc, + 0x19,0xa0,0xab,0x6e,0xc0,0xeb,0xbe,0x15,0x4a,0xc0,0x80,0x2d,0x4f,0xe6,0x8,0xb9, + 0x9,0xfc,0x1c,0xf8,0x41,0x10,0xda,0xaa,0x1f,0x7,0x29,0x94,0xd2,0xdf,0x49,0xf0, + 0xca,0x6b,0x38,0x82,0x48,0x43,0x68,0x1,0x69,0x25,0xdf,0xc9,0xbd,0xb4,0xc0,0x29, + 0x6d,0xdf,0x3,0x95,0xc3,0x1b,0x6e,0x20,0x84,0x31,0x3b,0xdb,0x23,0x8,0xdf,0xfe, + 0x6a,0x8c,0x78,0xb2,0x81,0x28,0x6c,0xe1,0xc1,0xbb,0x73,0x8c,0xc,0xe7,0xa5,0xa, + 0x68,0x5,0xa5,0x34,0x5e,0xfd,0xc6,0x8,0x53,0x53,0x1d,0xa4,0x49,0x6,0x25,0x34, + 0x38,0x2,0x4,0x41,0x13,0x8d,0xb0,0x7,0xcd,0xb0,0x7,0x5b,0x9f,0xa0,0xca,0x82, + 0x12,0x22,0xef,0x5a,0xd8,0xe3,0x45,0x4f,0x0,0xe5,0xd,0x4c,0x94,0x3e,0xdf,0x90, + 0xa1,0x18,0xad,0x76,0x83,0x95,0x6e,0xb1,0x5,0x23,0x4,0x81,0xc6,0xa6,0x75,0xd2, + 0x0,0xce,0x3,0xdb,0xf,0xe0,0xb6,0xc6,0x6f,0x82,0x3e,0xa5,0x14,0x44,0x2e,0x90, + 0xa6,0x19,0x1a,0xbd,0x6d,0xac,0x7c,0x39,0x87,0x50,0xc2,0x4a,0xbf,0x80,0x54,0x2, + 0x52,0xb,0x23,0xff,0x5a,0x41,0x59,0xe0,0x8d,0xe5,0x9b,0xc7,0xce,0xed,0x70,0x6, + 0x4,0xc,0x68,0x84,0xc0,0x23,0xf7,0x64,0x38,0xb8,0xbf,0x89,0x56,0xd4,0x8b,0x66, + 0xd4,0x83,0x66,0xa3,0xf,0xdf,0xfb,0x3f,0x9,0xd2,0x54,0xda,0x78,0xc0,0xb8,0x97, + 0x9e,0x39,0x1c,0x2b,0x2e,0x12,0x48,0x93,0x14,0x52,0x9a,0x1,0x91,0x90,0x87,0x88, + 0xc2,0x26,0xa2,0x46,0xb,0x53,0xa3,0x4d,0x74,0xe,0x52,0x2d,0x23,0xa2,0x93,0x8b, + 0x0,0x42,0x25,0x26,0xf8,0xd1,0x54,0x89,0x7,0xaa,0x1,0xa0,0x2e,0xa7,0x6b,0xed, + 0x8a,0xde,0x20,0xd4,0xd8,0xb8,0x46,0xba,0x19,0xdf,0x22,0x9f,0x56,0x36,0xda,0x17, + 0x42,0x22,0xcb,0x72,0x24,0x49,0x8a,0x4e,0xa7,0x83,0x97,0xaf,0x82,0xb5,0x7a,0x53, + 0xf9,0xab,0x58,0x3e,0x49,0x68,0x92,0xd0,0x64,0xac,0xdf,0x65,0x1c,0xa6,0x9c,0x6b, + 0x62,0x8d,0x80,0x3,0x21,0x7,0x1e,0xba,0x3b,0xc5,0xa6,0xb5,0xd,0xf4,0xb4,0xfa, + 0xd0,0x6a,0xf6,0xa2,0x15,0xf5,0xa0,0xd5,0xec,0x41,0xde,0x6e,0xe1,0x7,0xff,0xda, + 0x81,0x26,0x65,0x55,0x40,0x42,0x68,0x81,0x2b,0xae,0x89,0xd0,0x6e,0x77,0x90,0x67, + 0x39,0xb4,0x22,0x70,0x16,0x22,0x8,0x8c,0x72,0x44,0x61,0xb,0x3b,0x36,0x2a,0xdb, + 0x55,0x2c,0xfb,0x10,0xa5,0xa,0xd0,0xc9,0x11,0x3,0x10,0x14,0x34,0x54,0xa9,0x6, + 0xc5,0x85,0x50,0xde,0xcc,0x7d,0x39,0x77,0xf,0x68,0xec,0xdc,0x94,0xd9,0x89,0x19, + 0x6b,0xf1,0x36,0xd8,0x53,0x4a,0x43,0xa,0x69,0xa,0x3d,0x69,0x8e,0x38,0x4e,0x20, + 0x75,0x8c,0x73,0x5f,0xd1,0x28,0x22,0xfb,0xc2,0xdf,0x3b,0xd9,0x27,0x55,0xa4,0xa2, + 0xf0,0xe5,0xde,0x1e,0x1,0x63,0x8,0x38,0xc3,0xd0,0xfa,0xc,0x1b,0x1e,0x6c,0xa0, + 0xaf,0xa7,0xf,0xad,0x66,0xf,0xa2,0x46,0xcb,0xc4,0x1e,0x61,0x13,0x51,0xd4,0xc2, + 0xf6,0xa7,0x19,0x1e,0xba,0xb7,0x3,0xa5,0x65,0x71,0xf4,0xf6,0x33,0x2c,0x3b,0xc7, + 0xbc,0xf,0x21,0x25,0x88,0x80,0x80,0x7,0x8,0x82,0x10,0x8d,0x46,0x84,0x7d,0x3b, + 0x6c,0x53,0xaa,0x70,0x85,0x36,0xfe,0xd0,0xa,0x4a,0xcb,0x93,0x24,0x8,0xb4,0x4d, + 0x18,0x22,0x65,0x9a,0x34,0xe8,0x96,0x15,0x94,0xcb,0xb0,0x0,0x8d,0x1d,0x9b,0xf2, + 0x22,0xc7,0x27,0x82,0xf9,0x3d,0xa5,0xa1,0xa4,0x84,0x90,0x12,0x79,0x66,0x8a,0x3d, + 0x49,0x92,0xe0,0x9c,0x4b,0x7d,0x5f,0xef,0xfc,0xbd,0xb4,0xc0,0xab,0x92,0x6c,0x76, + 0xb2,0xc7,0x58,0xbe,0x95,0x7d,0x6e,0xa4,0x7f,0xe7,0xc6,0xc,0xdf,0xfb,0xba,0x46, + 0xab,0xd5,0x87,0x28,0xea,0x41,0x23,0x6c,0x22,0x8,0x4c,0xaa,0x69,0x66,0xff,0x38, + 0x18,0x42,0x3c,0x74,0x77,0x8e,0x1d,0x9b,0x33,0xf3,0x77,0x6c,0x86,0x71,0xee,0xa5, + 0x84,0xa9,0xc9,0x36,0xd2,0x38,0x45,0x9e,0xe7,0x90,0x52,0xdb,0x36,0x76,0x80,0x7d, + 0xdb,0x5c,0x1e,0xa8,0x40,0x70,0x2e,0xc8,0xbc,0xb7,0x5c,0x25,0x27,0x7c,0x2d,0x60, + 0x56,0x8,0x20,0x49,0x14,0x2a,0xa0,0x21,0x6d,0x20,0xa8,0xca,0xb8,0x0,0xe5,0x9c, + 0x3d,0x31,0xd,0x1e,0x68,0xec,0xd9,0x26,0xad,0xbf,0x7,0xc8,0xba,0x10,0xa5,0x34, + 0xa4,0xd4,0x90,0xb9,0x44,0x9e,0xb,0x64,0x69,0x86,0x24,0x4e,0xb1,0xe4,0x4c,0x66, + 0x3,0x3c,0x63,0x95,0x5a,0x5b,0xb9,0x2f,0x2,0x3e,0x55,0xac,0xec,0x31,0x96,0x4f, + 0x8,0xac,0xcf,0xf,0x18,0x70,0x70,0xbf,0xc0,0xdd,0xff,0x20,0xd0,0xd3,0xea,0x35, + 0x8d,0xa6,0x30,0x42,0x10,0x4,0x45,0x9a,0xa9,0x95,0x86,0x52,0x1a,0x5a,0x6a,0x28, + 0xa9,0xb1,0x71,0x4d,0xe2,0x91,0x4d,0x60,0xe9,0xd9,0x1c,0xed,0xf6,0x14,0x3a,0x71, + 0x62,0xa,0x44,0xc2,0xf4,0x23,0x40,0xc,0x59,0x1c,0x60,0x6a,0x5c,0x16,0x9f,0xd5, + 0xbc,0x2f,0x73,0xce,0x65,0x7a,0xc2,0x2b,0xc0,0xac,0xf4,0x2,0xa4,0x4a,0xc1,0x82, + 0x66,0x31,0xd3,0xcf,0xad,0xad,0x33,0x68,0x10,0xb,0x8a,0x51,0x69,0x53,0x9a,0x35, + 0x99,0xf3,0xc8,0x5e,0x93,0x5f,0x93,0x26,0x13,0xf0,0x49,0xd,0x6,0xb3,0xa0,0x52, + 0x8,0x81,0x2c,0xcb,0x11,0xa7,0x29,0xd2,0x34,0xc1,0xd9,0x17,0x47,0xc8,0x95,0x84, + 0x22,0x59,0x48,0xbe,0xd2,0x54,0x99,0xcd,0xe5,0x6e,0x32,0x18,0xa6,0x8b,0x17,0x70, + 0x42,0xc0,0x1,0x52,0x1a,0xff,0xf8,0x97,0x31,0x9a,0xe1,0x7c,0xb4,0x5a,0xbd,0x88, + 0x22,0x93,0x69,0x0,0x1c,0xa4,0xb5,0x9,0x34,0x6d,0x8d,0x21,0x49,0x52,0x9c,0x7a, + 0xa6,0xc4,0x2f,0xdc,0xd4,0x3,0xa5,0x95,0x59,0x28,0xc2,0x2,0xf4,0x34,0x18,0x4e, + 0x39,0x23,0x45,0x7c,0x30,0x46,0xab,0xd9,0x3,0x6a,0x2,0x5a,0x29,0x68,0x65,0xd2, + 0xcb,0xc9,0x51,0x85,0x5,0x73,0xc,0xd1,0x4d,0x1c,0x62,0xea,0x10,0x4a,0xcb,0x13, + 0xbe,0x26,0x3c,0x6b,0x75,0x0,0x63,0x89,0x12,0xe4,0xc9,0xb2,0xc9,0xe,0x6a,0x59, + 0x2,0x34,0x78,0xa8,0xb0,0x6b,0x8b,0x32,0xd6,0x47,0x30,0xc5,0x1a,0xa5,0xa1,0xa4, + 0x82,0x94,0x12,0x42,0x8,0xe3,0x2,0xd2,0xc,0xf3,0x16,0x49,0xb,0x78,0xe9,0xef, + 0x4b,0xe9,0xb7,0xb2,0x4f,0x9e,0xec,0xf3,0x32,0xe2,0xd7,0x42,0xe1,0xeb,0x7f,0x3e, + 0x5,0xc8,0x5e,0x34,0x9b,0xd6,0xf2,0x79,0x68,0x94,0x47,0x9b,0x25,0xde,0x79,0x26, + 0x6c,0xa0,0x19,0x23,0x6c,0x25,0x78,0xf3,0x6f,0x34,0xa0,0xc8,0x64,0x17,0x26,0xdd, + 0x14,0x90,0x4a,0x62,0xe1,0x69,0x2,0x9d,0x4e,0x8c,0x34,0xc9,0xac,0x1b,0x30,0x55, + 0x42,0x22,0x60,0xdf,0x4e,0xa7,0x0,0xd2,0xcc,0xd,0x16,0xa,0x65,0x62,0x0,0xfd, + 0x62,0x57,0x0,0xb2,0x3e,0xdf,0xc6,0xf2,0xe0,0x60,0x66,0x1,0x26,0x71,0x9b,0x9, + 0xc0,0xdb,0x43,0xc8,0x5c,0xe,0x27,0xfb,0x5a,0x19,0xdf,0xaf,0xb5,0x82,0x84,0x89, + 0x5,0xc,0x9,0x4c,0x1c,0x70,0xfa,0xa,0x6d,0xfd,0xbd,0xac,0x82,0xef,0x5a,0xd0, + 0x76,0xc4,0x8b,0x31,0x20,0xe0,0xc,0x21,0x27,0x84,0x9c,0x10,0x45,0x84,0x6f,0xde, + 0xd6,0xc1,0xd8,0x70,0x2f,0xe6,0xcd,0xeb,0x45,0x33,0x6a,0xa2,0xd1,0x68,0x98,0x71, + 0x30,0x2,0x94,0x36,0x29,0x66,0x92,0x24,0xe8,0xb4,0x3b,0xc8,0xe5,0x14,0x7e,0xe9, + 0xb7,0x2,0x84,0x2d,0x53,0x49,0x24,0x3b,0xcf,0xc0,0x58,0x8,0x49,0xc0,0xc2,0xd3, + 0x8,0x4f,0x24,0x9,0xd2,0x2c,0xb3,0xb1,0x83,0xa9,0x51,0x28,0xa9,0x91,0x76,0x54, + 0x19,0x0,0x6a,0x69,0x2a,0x8f,0x5a,0xd9,0xa9,0xa4,0x13,0xbb,0x33,0x34,0x2b,0x4, + 0x10,0x2a,0x41,0xc0,0x2,0xdb,0xf3,0xb7,0x3b,0x86,0x92,0x6,0x43,0x60,0x67,0xeb, + 0x19,0x8,0xb2,0x58,0x31,0xb7,0x69,0x7d,0xe,0xa5,0x94,0x91,0x51,0x2b,0xc3,0x4a, + 0x2a,0x10,0x37,0xa4,0x10,0xc2,0xaa,0x40,0x2e,0xd0,0x37,0x60,0x82,0x2a,0xe7,0xf7, + 0x5d,0x86,0xe1,0xfc,0xbd,0x1,0xc9,0xb5,0x77,0x8d,0xef,0xf,0x43,0xe0,0x5b,0x5f, + 0x9e,0xc4,0xa6,0x35,0x4d,0xc,0xcc,0xeb,0x41,0xb3,0x11,0x21,0xc,0x4d,0x75,0x91, + 0xc8,0x36,0x80,0xa4,0x44,0x9a,0x66,0xe8,0x74,0x62,0x1c,0x3c,0x38,0x81,0x6b,0x7f, + 0x35,0xc3,0xa2,0x65,0x11,0x72,0x29,0x6d,0x31,0x89,0xec,0x50,0x88,0x86,0xd2,0xc0, + 0xdc,0x5,0x84,0x34,0x49,0x91,0xa7,0x19,0x1a,0xa1,0xe9,0x54,0x2a,0x29,0xcd,0xe7, + 0x20,0xab,0x74,0xd6,0xea,0x49,0x2b,0x28,0x22,0x28,0x92,0xe5,0xbe,0x13,0x2f,0x6e, + 0x5,0x30,0xb9,0xb8,0x1b,0xf5,0x36,0xe3,0xda,0xdc,0xc,0x52,0x13,0x7,0x27,0xd, + 0x4d,0x81,0xa7,0x4,0x12,0x52,0x28,0x48,0xa9,0x20,0x85,0x84,0x94,0xa,0x8c,0x29, + 0x70,0x6e,0xca,0xa7,0x22,0x17,0x10,0xb9,0x71,0x3,0x52,0x8,0xdb,0x59,0x94,0x85, + 0x7f,0x75,0x3b,0x7d,0x14,0xeb,0x89,0x58,0x80,0x80,0x1b,0xf9,0xf,0x3,0xc2,0xa3, + 0xf7,0x76,0xb0,0xf6,0x3e,0x8e,0x81,0x79,0x7d,0x68,0x36,0x5b,0x8,0xc3,0x6,0x18, + 0x98,0x9,0xf4,0x28,0x7,0xc8,0xc4,0x19,0x9d,0x76,0x7,0x63,0x63,0x63,0x18,0xbc, + 0x21,0xc1,0xc5,0x57,0xb5,0x90,0x9,0x9,0x45,0xc2,0x10,0x0,0xe6,0xbd,0x72,0x46, + 0xd0,0x9a,0x43,0x2a,0x81,0x38,0x26,0x24,0x69,0x86,0x46,0x23,0x2,0xe7,0x1c,0x79, + 0x2e,0x20,0x72,0x89,0x2d,0xeb,0x53,0x5c,0x72,0x1d,0x83,0x26,0x61,0x7b,0x11,0x46, + 0xad,0xa4,0x4a,0x8a,0x3a,0xc8,0x8b,0x9a,0x0,0x4a,0xb,0x68,0x2e,0x51,0xe,0x6b, + 0x73,0x1b,0xf5,0x73,0x70,0xe2,0x16,0x7c,0x66,0xab,0x83,0xc,0x9a,0x24,0xa4,0x2c, + 0xf,0x21,0xa5,0x1d,0xd8,0xe4,0x86,0x0,0x52,0x22,0x17,0x39,0x84,0x10,0x68,0xf4, + 0xb8,0xdf,0xf1,0xa3,0x7d,0x5d,0x14,0xf6,0x19,0xe3,0xe0,0x5c,0x83,0x33,0x33,0xb0, + 0xb1,0xee,0x67,0x53,0xf8,0xf6,0xdf,0x33,0xc,0xc,0xcc,0x43,0x23,0x6a,0x98,0x68, + 0x9f,0x99,0xc5,0x1c,0x52,0x96,0x79,0x79,0x2e,0x4,0xd2,0x2c,0xc3,0xd2,0x15,0x9, + 0xae,0xfd,0x77,0xbd,0x88,0xf3,0xdc,0x92,0x4c,0x42,0x41,0x15,0xe9,0x9b,0x22,0xd, + 0x5,0x86,0x81,0x53,0x8,0x69,0x9a,0x21,0xcb,0x52,0xa4,0x91,0xc9,0x22,0x72,0x91, + 0x23,0x17,0x2,0x4c,0xa,0x68,0x62,0x50,0x4a,0x98,0xf8,0x81,0x64,0x31,0xa3,0x78, + 0xa2,0xb7,0x85,0x67,0x85,0x0,0xda,0x46,0xbf,0x8c,0xd9,0xa9,0x5d,0x28,0xd3,0x42, + 0x45,0xe0,0x2f,0xc0,0x2,0x91,0x99,0xad,0xd7,0x24,0xad,0xcc,0x1b,0xf0,0x45,0x2e, + 0xec,0x44,0xae,0x25,0x80,0x10,0xc5,0xf7,0x95,0x92,0x20,0x32,0x8b,0x32,0x0,0x5, + 0x14,0xb5,0x4,0x3b,0x51,0xc4,0x61,0x97,0x8f,0x11,0xc6,0xf6,0xa6,0xf8,0xe6,0x17, + 0x12,0xf4,0x34,0x17,0xd8,0x54,0x2f,0x34,0xe0,0x6b,0x82,0x14,0xd5,0x3d,0x7c,0x84, + 0x90,0x50,0x52,0xe1,0xe9,0x35,0x2,0x1b,0xd7,0x29,0x2c,0xbb,0x80,0x17,0x41,0x9c, + 0x9,0x66,0x1,0xed,0x76,0x15,0x21,0x6e,0x26,0x8e,0x72,0x53,0x9d,0x6c,0x46,0x39, + 0x82,0x30,0x40,0x96,0xe5,0xc8,0xf3,0x1c,0x5c,0x8,0x68,0xed,0x14,0x20,0x87,0x56, + 0x76,0xfe,0x40,0x2b,0x90,0x3e,0x3e,0x31,0x0,0x63,0x6c,0x3e,0x80,0x57,0xc2,0xdc, + 0xc4,0xd3,0xfd,0x9b,0x84,0xd9,0x88,0x6a,0xd,0x11,0xc5,0xcf,0x19,0x1,0x40,0x1a, + 0x8a,0x84,0x91,0x7d,0xe7,0x2,0xb4,0x86,0xe6,0x4,0x4d,0xa6,0xa3,0xa7,0x19,0x41, + 0x73,0x4b,0x0,0x25,0x91,0x65,0x99,0x39,0xac,0x4f,0x25,0x22,0x70,0xce,0xa1,0xb5, + 0x42,0x9e,0xe5,0xe6,0xc8,0x73,0x74,0x26,0x85,0x69,0x20,0x93,0x2c,0xad,0x9f,0x91, + 0xb7,0x64,0x1c,0x8,0x38,0x47,0x67,0x3c,0xc3,0xff,0xbc,0x75,0x12,0x1,0xfa,0x11, + 0xf6,0x86,0x36,0xcf,0xb7,0xe0,0xcb,0xe9,0x15,0x39,0x65,0xe3,0x8f,0x46,0x18,0xe1, + 0xb6,0x4f,0x1e,0xc0,0x7f,0xf9,0x74,0xb,0xb,0xcf,0xe0,0x0,0x49,0x0,0xca,0x36, + 0x91,0x6c,0x9d,0x2,0x12,0x7,0xf6,0x66,0xc8,0x52,0x8d,0x2c,0xcd,0x90,0x36,0x52, + 0x4,0x41,0x80,0x34,0x4d,0x91,0xc4,0x9,0x58,0x5f,0x6,0x45,0x1,0x24,0xe5,0x50, + 0xda,0xf4,0x2a,0x94,0xd2,0x86,0xbc,0x1a,0x50,0x6a,0xd6,0xc1,0x5f,0x2,0xe0,0xd2, + 0x7b,0xbe,0xfa,0x77,0x1f,0xbb,0xf6,0xca,0xc1,0x55,0x24,0x25,0x20,0x5,0xe,0x4e, + 0x4c,0x8c,0xfd,0xf8,0x91,0x47,0x1f,0xfd,0xbd,0xcf,0xff,0xf5,0x7d,0x8c,0xb1,0x1f, + 0x3,0x58,0x7d,0x38,0x22,0xcc,0xda,0xea,0x45,0xa5,0x73,0x68,0x12,0xc6,0xa,0x48, + 0x94,0xf5,0x79,0x2d,0xa1,0x21,0x6c,0xad,0x5e,0x82,0xc8,0xf6,0xf0,0x85,0x40,0x9e, + 0x9b,0x6a,0x5f,0x9e,0xe7,0xde,0x61,0xbe,0x2e,0x84,0x30,0xa9,0x96,0x36,0x80,0x80, + 0x19,0x5,0x60,0xac,0x3c,0x38,0xd3,0x66,0xa4,0x4b,0x48,0x7c,0xe9,0xe3,0x63,0xc8, + 0x93,0x6,0x1a,0xd,0x23,0xcf,0xa6,0x42,0x69,0x82,0xbd,0xea,0xeb,0xe7,0xc5,0xeb, + 0x13,0x11,0xc2,0x30,0x84,0x16,0x4d,0xdc,0xfe,0xb9,0x9,0x1b,0x87,0x28,0x70,0xfb, + 0xfa,0xe6,0xef,0x99,0xbf,0xaf,0xad,0xac,0xbb,0xf7,0x9d,0xa6,0x29,0xd2,0x34,0x45, + 0x96,0x65,0x58,0x7e,0xa1,0x82,0x52,0x19,0x94,0xca,0x21,0x75,0x6e,0xce,0x2a,0xb7, + 0xfd,0x91,0xea,0x8e,0x76,0xb3,0x5,0xfe,0x83,0x5f,0xbf,0xfd,0x93,0x3e,0xf8,0x90, + 0x12,0xf3,0x5a,0xad,0x5,0x6f,0xbb,0xfa,0xd5,0xd7,0xaf,0xff,0xfb,0x2f,0x7f,0xec, + 0x1b,0x7f,0xfa,0xf1,0x8f,0x3,0xf8,0x65,0x7b,0xab,0xdf,0xe3,0xdd,0xb,0x30,0xa9, + 0xa0,0xa2,0x12,0x68,0xe3,0xb,0x73,0x28,0x6b,0x15,0x8e,0x18,0x92,0x72,0x9c,0x77, + 0x39,0x9f,0x1,0xfc,0x12,0x78,0x69,0x23,0xec,0x3,0x7b,0x32,0x80,0x99,0x95,0x3a, + 0x6,0x78,0x6d,0xcb,0xbc,0xe6,0x88,0x22,0x8d,0xdb,0x3f,0x3b,0x8a,0xdd,0x43,0xc, + 0x8d,0x46,0xc3,0xaa,0x88,0x2e,0xc0,0x77,0x80,0xd5,0xf,0x29,0xd,0xa0,0x9c,0x73, + 0x34,0x9b,0x4d,0x1c,0xd8,0xd9,0xc0,0x6d,0x1f,0x1f,0x45,0x18,0x98,0x21,0xd5,0x86, + 0x6d,0x1e,0x5,0xdc,0x54,0x16,0x47,0xf6,0x66,0x5,0xa9,0x94,0x52,0xb6,0x80,0x24, + 0x20,0x84,0x80,0x92,0xc2,0x54,0x3b,0x48,0x17,0xa0,0x93,0x6d,0x7e,0x92,0x26,0x90, + 0x9a,0x65,0xf0,0xbf,0x72,0xdb,0x27,0x7,0x2f,0xb8,0x60,0xd0,0x7,0x1f,0x52,0xc2, + 0x3d,0x6f,0x71,0xd6,0xf3,0xb6,0x2b,0x2e,0xbf,0x7e,0xe7,0xff,0x77,0xdb,0x67,0x57, + 0x5d,0x70,0xc1,0x3b,0x18,0x63,0xaf,0x39,0xee,0xa,0xe0,0xaf,0x10,0xad,0x2f,0x16, + 0x25,0x6f,0x74,0x9c,0xec,0xe6,0xd,0xee,0x22,0x2a,0xa5,0x2a,0x80,0x3b,0x69,0x76, + 0x9d,0xc4,0x5d,0x9b,0x73,0x4,0x8c,0x81,0x73,0x33,0xc8,0xe9,0x76,0x7,0x9,0x38, + 0x43,0xd4,0x60,0xf8,0xc7,0xcf,0x8d,0x63,0xcd,0x4f,0x9,0xcd,0xa6,0xc9,0xf3,0xc3, + 0x30,0x4,0xe7,0x36,0xdd,0x53,0xaa,0x20,0x5a,0x92,0x24,0x48,0xd3,0xd4,0x2b,0xe2, + 0x18,0x54,0x82,0x20,0x40,0xb3,0xd9,0x44,0x5f,0x5f,0x1f,0x9e,0x79,0x34,0xc4,0x5d, + 0x5f,0x9d,0x44,0x83,0x7,0x68,0x4,0x21,0x1a,0x41,0x80,0x6,0xf,0x10,0x72,0x8e, + 0x91,0xbd,0xaa,0x78,0x5d,0xa7,0x4,0x8e,0x60,0x51,0x9f,0xb6,0x25,0x65,0xd8,0xda, + 0x86,0x5b,0xbf,0x60,0x1e,0xcf,0xc6,0x4e,0x61,0x3e,0xf8,0xaf,0x5c,0xb9,0x72,0x46, + 0xf0,0xdd,0x73,0x28,0x81,0xc5,0x73,0xe6,0x2c,0xbd,0xf3,0x8f,0x3e,0x72,0xeb,0xcd, + 0x57,0x5d,0xf9,0xf6,0x99,0x48,0x10,0x1e,0x97,0xd0,0xb2,0x58,0x25,0xed,0x2d,0xce, + 0xa2,0x72,0x26,0x28,0x17,0xc0,0xf2,0x73,0x19,0xc6,0xf7,0xca,0x82,0x0,0x4e,0xb6, + 0xdd,0x5,0x76,0x85,0x98,0xdd,0x43,0xb2,0xd8,0x2c,0x22,0x60,0x64,0x7a,0xbb,0x30, + 0x45,0x9f,0xef,0x7f,0x6d,0x12,0xf7,0x7f,0x5b,0xa2,0xb7,0xb7,0x17,0x8d,0x46,0x63, + 0x9a,0xf4,0x3b,0x2b,0x77,0xc4,0x2,0x80,0x30,0xc,0x6d,0x39,0x38,0x28,0x96,0x84, + 0x85,0x61,0x88,0x56,0xab,0x85,0xbe,0xbe,0x3e,0xdc,0x75,0xfb,0x1,0x9c,0x71,0x5e, + 0x13,0xaf,0x78,0x8d,0x59,0x1a,0x1e,0x30,0x8e,0x46,0xc0,0xf0,0xd4,0xea,0xc,0x41, + 0x30,0xaf,0x12,0x3f,0x38,0x2,0x2c,0x39,0x2b,0x80,0x56,0x76,0x26,0x52,0xc3,0xd6, + 0x1a,0xc,0xf8,0x5a,0xd9,0xa5,0x86,0xb3,0x5,0xfe,0x8a,0x95,0x83,0x3a,0x4d,0xc0, + 0x48,0x21,0x98,0xd3,0x57,0x5,0x5f,0xd8,0xb3,0x92,0x20,0x61,0x88,0xd0,0xe2,0xac, + 0xe7,0xef,0xde,0xfb,0xeb,0xef,0x87,0xd2,0x6e,0xc2,0xfa,0xfe,0xe3,0xa3,0x0,0x33, + 0x28,0x41,0x9,0x7c,0x39,0x35,0xa3,0x35,0xb0,0x68,0x29,0x2b,0x2e,0xa0,0xaf,0x0, + 0x4e,0xbe,0x5d,0x94,0xf,0x4,0x58,0x73,0x7f,0x62,0x54,0xc0,0xee,0x14,0xc2,0x19, + 0xc3,0x86,0xfb,0xdb,0xf8,0xd7,0xbf,0xed,0x20,0x8,0x82,0x2,0x4c,0x47,0x20,0x67, + 0xf9,0x69,0x6a,0x66,0x9,0xe,0x1e,0x3c,0x88,0xb1,0xb1,0x51,0x8c,0x8d,0x8d,0x61, + 0x72,0x72,0x12,0x9d,0x4e,0x7,0x69,0x9a,0x42,0x8,0x1,0xad,0x75,0x85,0x4,0xbd, + 0xbd,0x73,0xf0,0xd5,0x3f,0x1b,0xc7,0xf0,0x16,0x85,0x28,0x8,0x11,0x5,0x1,0x44, + 0xae,0xf1,0xd4,0xa3,0xb2,0xa2,0x2c,0xee,0xbd,0xb,0x91,0x63,0xe0,0x14,0xe,0x69, + 0x7b,0x1a,0x86,0x70,0x46,0xf6,0xd,0x1,0xe8,0x59,0xa5,0x81,0xd3,0xc0,0xcf,0x12, + 0xa8,0x24,0x86,0x18,0x19,0xeb,0x62,0xf9,0xe6,0x4c,0xc2,0x3e,0x57,0x46,0x9,0x9a, + 0x9c,0xf5,0x7c,0xe5,0xdd,0xff,0xf1,0xfd,0x67,0x2d,0x1a,0xb8,0xa6,0x1e,0x13,0xf0, + 0xe3,0x83,0x7f,0xf5,0xff,0xe5,0x98,0xb4,0x21,0x80,0x94,0xc0,0x19,0xe7,0x5,0x95, + 0x5a,0x40,0x9d,0x4,0x4e,0x1,0x82,0x20,0xc0,0xc6,0xd5,0x39,0x2,0x6e,0x64,0xdf, + 0xe4,0xfb,0x1c,0x4a,0x96,0x6f,0xbd,0x58,0x37,0x60,0x81,0x71,0xe0,0xc7,0x71,0x8c, + 0xa9,0xa9,0x29,0x4c,0x4c,0x8c,0xe3,0xa3,0x7f,0xdd,0x83,0x4b,0x5e,0x13,0x63,0x7c, + 0x7c,0x1c,0xed,0x76,0x1b,0x49,0x92,0x20,0xcb,0x32,0x48,0x29,0x8b,0xc,0x24,0x8a, + 0x22,0xf4,0xf6,0xf6,0x82,0x64,0x2f,0x3e,0xff,0xd1,0x7d,0x90,0x9,0x43,0x14,0x86, + 0x78,0x6a,0x75,0x7,0x1c,0xa6,0xf8,0xe3,0x2b,0x8c,0x10,0x2,0x61,0x2b,0xc7,0xdc, + 0x85,0xdc,0x2e,0x53,0x23,0x28,0x85,0xd2,0x1d,0x28,0x32,0x18,0xc8,0x63,0x53,0x80, + 0xba,0xec,0x1b,0xf0,0x13,0xe8,0x4e,0x8c,0x7c,0x62,0x1c,0xba,0xd3,0x29,0xc1,0x17, + 0x2,0x50,0x2,0xe4,0x9e,0x2b,0x1,0x8,0x51,0xc6,0x5,0x60,0x3d,0x3f,0xbd,0xe5, + 0x77,0xde,0xf,0xe0,0x15,0x8c,0xb1,0xde,0xe3,0xa7,0x0,0xf0,0x76,0xcd,0x73,0x7d, + 0x80,0xc2,0xfa,0x51,0x8c,0x4c,0x9d,0x77,0x69,0x54,0x4,0x7d,0xee,0xf0,0x65,0xdb, + 0x11,0x20,0xc,0x43,0x3c,0x78,0x77,0x82,0x80,0x73,0x7b,0x18,0xd9,0xbe,0xe2,0xda, + 0x7e,0xbc,0xeb,0xf7,0xe7,0x16,0xbf,0xeb,0x7c,0x7d,0x9a,0xa6,0xa6,0xbe,0xdf,0xe9, + 0x60,0x72,0x72,0x12,0x13,0x7,0x27,0xf0,0xae,0x8f,0xb4,0xb0,0xf8,0xec,0x0,0xff, + 0xf9,0x63,0xb,0xb1,0x70,0x59,0x1b,0x13,0x13,0x13,0x15,0x25,0x70,0x69,0x62,0x10, + 0x4,0x68,0xb5,0x5a,0xe8,0xef,0xef,0x47,0x67,0xbc,0x7,0x7f,0xf1,0xe1,0x7d,0x68, + 0x4,0x1,0x7e,0x78,0xc7,0x14,0x5a,0xad,0x56,0xe1,0x62,0x7c,0x92,0x9d,0x79,0x21, + 0x83,0x54,0xc6,0xea,0x95,0x34,0x4,0x50,0x52,0x43,0x4b,0x7,0xfe,0xb1,0x5,0x81, + 0x55,0xcb,0x5f,0x31,0xa8,0xd3,0x4,0x2a,0x4e,0xa0,0xe3,0x18,0x22,0x89,0xa1,0xdb, + 0x6d,0x74,0xb6,0x6e,0xb3,0xd2,0x2f,0x40,0x4a,0x58,0xd9,0x17,0x16,0x7c,0x5,0x52, + 0xb2,0x54,0x2,0x29,0xb1,0xb8,0xaf,0x77,0xe9,0x3f,0xbf,0xe7,0x9d,0xbf,0x6,0xe0, + 0xf2,0x59,0x27,0x0,0xcd,0xf0,0xc8,0x5f,0x27,0xa0,0xbd,0xf3,0xf9,0x97,0xb7,0xa0, + 0xb4,0x9c,0x6,0xbe,0x53,0x0,0xe7,0x2,0xc2,0x30,0x44,0x16,0x73,0xfc,0xec,0xbb, + 0x1d,0x4,0xde,0x8e,0x61,0x0,0xc3,0xeb,0xff,0xdd,0x3c,0xbc,0xe6,0x17,0xa3,0x4a, + 0x36,0xe1,0x48,0x10,0xc7,0x31,0x3a,0x9d,0xe,0x5e,0x75,0x3,0xc3,0x95,0xd7,0xf7, + 0x22,0x97,0x12,0x99,0x20,0xfc,0xe1,0xdf,0x9c,0x86,0x53,0x96,0x67,0xe8,0x74,0x3a, + 0x88,0xe3,0xb8,0xf8,0x5d,0xa5,0x54,0x91,0x16,0x46,0x51,0x84,0xbe,0xbe,0x3e,0xc, + 0x6d,0x20,0x7c,0xf6,0xf7,0x76,0x60,0xf5,0x8f,0x25,0x9a,0xcd,0xa6,0x2d,0x2a,0xe9, + 0xc2,0xc5,0xe4,0x79,0x6e,0x9,0x60,0x6e,0x57,0x23,0xed,0x4c,0x83,0x52,0xb0,0x44, + 0x20,0x68,0x9,0x48,0x79,0x74,0x5b,0x85,0x14,0xe0,0xdf,0x71,0x87,0xf5,0xf9,0xa9, + 0xb1,0xfc,0xb8,0x3,0xd1,0xe9,0x40,0xb5,0x3b,0xc8,0xe3,0x36,0xda,0x5b,0xb6,0x22, + 0xdd,0xb7,0xdf,0xf3,0xff,0xf6,0x10,0x12,0xa4,0xbc,0x80,0xd0,0x92,0x80,0x94,0xc2, + 0xf5,0x2b,0xce,0x5e,0x75,0xd6,0x82,0xb9,0xd7,0x30,0xc6,0x9a,0xb3,0xaf,0x0,0xf5, + 0x2d,0x74,0x51,0xae,0x90,0xd1,0x6e,0xf1,0x84,0x1d,0x9c,0xcc,0x32,0xe0,0x8a,0x6b, + 0xa2,0xa,0xf8,0xce,0xfa,0x7d,0x5,0xe0,0x9c,0x23,0xc,0x43,0xdc,0xfb,0xcf,0x53, + 0x65,0x26,0x60,0xb,0xce,0x44,0xc0,0x6f,0xfc,0xf1,0x29,0xb8,0xfa,0xc6,0xb0,0xc8, + 0xcb,0x9d,0x2,0xc4,0x71,0x8c,0xb3,0x2f,0x51,0xf8,0xb5,0x8f,0x2c,0x44,0x26,0x25, + 0x52,0x29,0x91,0x49,0x1,0x1e,0x31,0xbc,0xe7,0x63,0xf3,0x41,0x3c,0x46,0x1c,0xc7, + 0x5,0x9,0xba,0xc5,0x3,0x73,0xe6,0xcc,0xc1,0x13,0xf,0x71,0xf4,0xf7,0xcf,0x43, + 0x14,0x45,0x45,0xc,0xe0,0x2b,0xce,0x5,0x83,0x2d,0x48,0xa9,0x6c,0x3b,0xdb,0x80, + 0xaf,0x3d,0xf0,0x95,0x34,0x81,0xe1,0xd1,0x82,0xff,0xd0,0x43,0xf,0x7d,0x72,0xf0, + 0x92,0x8b,0x7,0x75,0x16,0x43,0x25,0xb1,0x1,0x3f,0xe9,0x40,0xc5,0x6d,0x88,0xb8, + 0xd,0xd5,0xee,0x40,0xc4,0x6d,0xec,0x7f,0xf8,0x11,0xa8,0x38,0xae,0xc6,0x0,0x4a, + 0x56,0xc1,0x97,0x6,0x7c,0x13,0x14,0xa2,0xe7,0x8f,0xdf,0xb0,0xea,0xa,0x0,0x17, + 0x3f,0x27,0x31,0x40,0x25,0xf8,0xf3,0x56,0xcf,0x8,0x49,0x78,0xe5,0xeb,0x9b,0x5d, + 0x5d,0x80,0xb3,0x46,0x27,0xcb,0x61,0x18,0x62,0xe7,0x26,0x85,0x9f,0xdd,0xd9,0x2e, + 0x52,0x42,0x66,0x5a,0x81,0x90,0xa,0xf8,0x8d,0x3f,0x5e,0x84,0xab,0x6f,0xc,0x8a, + 0x54,0x2f,0x4d,0x53,0xf4,0x2f,0x12,0x78,0xdf,0xa7,0x16,0x22,0x57,0x12,0x99,0x94, + 0xc8,0x95,0x44,0xae,0x14,0x72,0xa5,0x70,0xda,0xd9,0xd,0x7c,0xec,0x4b,0xb,0xa, + 0x12,0xb8,0x82,0x8e,0x1f,0xf,0x84,0x61,0x88,0x9e,0x9e,0x1e,0xcc,0x9d,0x3b,0x17, + 0xbd,0xbd,0xbd,0x8,0xc3,0xd0,0xc6,0x2f,0x65,0x6d,0x61,0xd1,0x72,0x8d,0xfe,0x85, + 0xc,0x52,0x12,0xa4,0x20,0xb,0xba,0x19,0x6e,0x51,0x2,0x76,0x2d,0x23,0x41,0x8a, + 0x23,0x53,0x80,0xa,0xf8,0x83,0x83,0x83,0x2a,0xcf,0x4a,0xd9,0x8f,0x63,0xa8,0x76, + 0x6c,0x15,0xc0,0x9c,0x45,0x1c,0x23,0x1e,0x1d,0xc7,0x96,0xef,0xdc,0x55,0x5,0x5f, + 0x78,0xd2,0xaf,0x3c,0x42,0x58,0x76,0xbe,0xf1,0x8c,0x33,0x6,0x1,0x5c,0x78,0x9c, + 0x63,0x80,0x72,0x95,0xae,0xf6,0xd7,0xb,0xda,0x43,0x11,0xe1,0xb2,0xd7,0xf5,0x16, + 0x17,0xb3,0xa8,0xfc,0x75,0xc9,0x4,0xc2,0x30,0x44,0xa3,0xd1,0xc0,0x37,0x6e,0x1b, + 0x47,0xda,0xa1,0x62,0xd7,0x50,0x77,0x55,0xa5,0x4,0x6e,0xfe,0xaf,0xb,0xb0,0x74, + 0x5,0x21,0x4d,0x53,0x4,0x51,0x8e,0xdf,0xfc,0xcc,0x7c,0x34,0x7a,0x8,0xb9,0x94, + 0xc5,0xba,0xc1,0x5c,0xda,0xf5,0x83,0x5a,0x61,0xf1,0x19,0x4d,0xfc,0xca,0x2d,0x73, + 0x10,0xc7,0x71,0xa5,0x46,0xe0,0xc8,0xe7,0x2,0xd0,0x46,0xa3,0x51,0x14,0x98,0xfc, + 0x20,0x33,0xcb,0x32,0xbc,0xf2,0xf5,0x91,0x1,0x5f,0x9a,0x51,0x36,0x25,0x6d,0x1c, + 0x20,0xdc,0x2a,0x66,0xf3,0x58,0xab,0xc3,0x13,0x60,0x1a,0xf8,0xca,0x2c,0x55,0xd3, + 0x9d,0x18,0x22,0xee,0x40,0xb5,0xdb,0x10,0x9d,0x29,0x63,0xf9,0x9d,0x36,0x44,0x1c, + 0x23,0xef,0xc4,0xc8,0x93,0x18,0x7,0x47,0x47,0xb1,0xf9,0x8e,0xef,0x98,0x80,0x4f, + 0x88,0xc2,0xe7,0x97,0x96,0xaf,0xe0,0x49,0x13,0x16,0xf7,0xf5,0x2c,0x5,0x70,0xea, + 0xac,0x13,0x80,0xa6,0x15,0x2,0x50,0xc,0x84,0x54,0x49,0x60,0x2a,0x66,0x3c,0xc, + 0x70,0xcd,0x2f,0x4d,0x57,0x1,0x3f,0x13,0xe0,0x9c,0x17,0x2a,0x30,0xbe,0x1f,0xf8, + 0xda,0x5f,0x1c,0xb0,0xeb,0xf6,0xbd,0x85,0x99,0x0,0x9a,0xbd,0x1c,0x7f,0xf8,0xe5, + 0x25,0x58,0x7e,0x1e,0xc3,0xcd,0xb7,0xf4,0x63,0xc9,0xd9,0xa1,0x5d,0x35,0x64,0x16, + 0x87,0xa,0x55,0x2e,0x12,0x75,0xc7,0x6b,0x6e,0x9c,0x87,0x5f,0xfd,0x50,0x5f,0x11, + 0xc,0xfa,0xae,0xc0,0x77,0x43,0x2e,0xf7,0x77,0xd5,0xbf,0x3c,0xcf,0x91,0x24,0x9, + 0x2e,0x7a,0x55,0xcb,0x82,0x6f,0x82,0x3f,0xa3,0xc2,0x86,0x4,0x32,0x37,0xe0,0xcb, + 0x9c,0xa0,0xf,0xa3,0x0,0xb6,0xb1,0x53,0x1,0x5f,0x8,0x1,0x31,0xa7,0xdf,0xc8, + 0x7e,0xc7,0xfa,0xfe,0xb8,0xb4,0xfc,0x3c,0x8e,0x91,0x27,0x9,0xf2,0x34,0x85,0x88, + 0x13,0xec,0xde,0xbe,0xb,0x8f,0x7e,0xf5,0x6b,0x10,0xed,0xa9,0x8a,0xcf,0xf7,0x2d, + 0x1f,0x4a,0x81,0x54,0xb5,0x39,0x71,0x9c,0x15,0xa0,0xac,0x8,0x4c,0x5b,0x3c,0x49, + 0x1a,0x42,0x6a,0xac,0x7a,0x6b,0x5f,0xa5,0xc,0xec,0x48,0x50,0x8f,0x3,0x1a,0x8d, + 0x6,0x9a,0xcd,0x26,0x7e,0x7a,0x67,0x8c,0xfb,0xbe,0x33,0x59,0x54,0x5,0xfd,0xbd, + 0x8,0x79,0x83,0xe3,0x63,0xff,0x6b,0x29,0xae,0xb8,0xbe,0xcf,0xcc,0xe4,0x91,0xf9, + 0x3b,0xaa,0xb2,0x38,0xb4,0xfa,0x3e,0xde,0xf4,0x8e,0x45,0xf8,0x85,0x1b,0x1b,0xe8, + 0x74,0x3a,0x48,0x92,0x64,0x9a,0x1a,0x95,0xf9,0xbe,0xa8,0xf4,0x1,0x6,0xaf,0x6d, + 0x62,0x60,0x51,0x60,0xfd,0xbe,0xb6,0xd6,0x6e,0xa2,0x7f,0x67,0xf9,0x32,0x37,0x44, + 0x90,0x87,0x48,0x3,0xad,0xe5,0xbf,0xea,0x9e,0xbb,0xbf,0xf1,0x31,0x7,0x7e,0xe1, + 0x66,0x7a,0x7a,0x21,0x7b,0xe7,0x40,0x74,0xda,0x50,0x71,0x7,0xa2,0x6d,0xc1,0x4f, + 0xaa,0xe0,0x9b,0xa6,0x5a,0x8a,0xe1,0x91,0x31,0x7c,0xff,0xb6,0xaf,0x61,0x6c,0x68, + 0x93,0x4d,0xff,0x1c,0xf8,0x12,0x90,0x36,0x2b,0x30,0xe5,0xca,0xe3,0x58,0x9,0xf4, + 0xef,0x18,0xe3,0x6a,0x0,0x76,0x73,0x45,0xb3,0xea,0x86,0x21,0x20,0x56,0x2c,0xde, + 0x3c,0xfb,0xe2,0x16,0xce,0xbf,0x8c,0x63,0xf3,0xba,0xbc,0xd8,0xf,0xc0,0x29,0x87, + 0xb,0xba,0x9c,0xa,0x44,0x51,0x4,0xad,0x35,0xbe,0xf4,0xa7,0x23,0x20,0x2,0x56, + 0xfd,0x62,0xbf,0xd9,0xa9,0xab,0x58,0x1,0xe4,0xd6,0x84,0x50,0xd7,0xbd,0xb,0xfd, + 0xad,0xe3,0xfd,0x25,0xdc,0x1f,0xf8,0xd4,0x32,0xec,0xdf,0xb3,0x5,0x9b,0xd7,0xc6, + 0x85,0xaf,0xf7,0x6f,0x66,0xe5,0xdc,0x91,0xd6,0xba,0xe8,0x62,0x5e,0xfb,0xf6,0x45, + 0xd6,0xfa,0x8d,0xfb,0xd5,0x56,0xfe,0x2b,0xe0,0x1b,0xff,0x6f,0x86,0x47,0xf,0x15, + 0xed,0xdf,0xf3,0x95,0x4f,0x5e,0xf9,0xda,0x6b,0x6,0x7d,0x17,0x63,0x6,0x63,0x33, + 0x88,0x73,0xce,0x45,0xb0,0x61,0x3d,0xe4,0x34,0xcb,0x4f,0x20,0x92,0xb4,0xe8,0xa8, + 0xa6,0x22,0x47,0x96,0xe7,0x48,0x73,0x81,0xff,0xfb,0x4f,0xdf,0xc6,0x99,0xad,0x26, + 0x6,0x6f,0x7c,0x3,0xe6,0x9e,0xb6,0x4,0x90,0x66,0x44,0xcd,0x2c,0xbe,0xd0,0xf8, + 0xe1,0xd0,0xf6,0xfb,0x0,0xac,0x3d,0x2e,0x4,0x28,0x36,0xea,0x74,0xed,0x54,0xef, + 0x82,0x6b,0xeb,0xa,0x94,0x26,0x28,0x66,0x2c,0x33,0xcd,0x3,0xfc,0xf2,0xfb,0xe7, + 0xe2,0x53,0xef,0x1d,0xad,0x54,0xf4,0x1c,0x9,0xdc,0xd9,0x57,0x2,0xa5,0x14,0xbe, + 0xf8,0xdf,0xf6,0x83,0x88,0xf0,0xda,0xb7,0xce,0x5,0x38,0x3,0x69,0xb7,0x7d,0xbc, + 0x1d,0x13,0xb3,0x2b,0x90,0xfc,0xd7,0x73,0xae,0xc3,0x6c,0x14,0xe1,0xdd,0x7e,0x86, + 0x2,0xfc,0xc9,0x5f,0xaf,0xc0,0x1f,0xfc,0xfa,0x10,0x26,0xf6,0xc9,0x69,0x44,0x74, + 0xef,0xc3,0x2f,0x36,0x9,0x41,0x45,0xaa,0x67,0x80,0x7,0x64,0x8e,0x2a,0xf8,0x39, + 0x41,0x66,0x4,0x29,0xa6,0x2b,0x40,0x5,0xfc,0xcb,0xce,0x19,0x54,0x76,0xb5,0x93, + 0xf,0x7e,0x96,0x65,0x48,0xe7,0xe,0x20,0x58,0xb0,0x10,0x6c,0xff,0x7e,0x3,0x7c, + 0x62,0x80,0xaf,0x80,0x9f,0x97,0xe0,0xa7,0x42,0x20,0x93,0x2,0x6b,0x26,0x52,0x3c, + 0x7c,0xfb,0xbf,0xe0,0x4c,0x1e,0xe0,0xbc,0xfe,0x6,0x6,0x96,0x9e,0x6,0x95,0xa5, + 0xf8,0xf9,0xde,0xbd,0x3f,0x7f,0xdf,0x81,0xce,0x9f,0x1,0x78,0xec,0xb8,0xf6,0x2, + 0x9c,0x39,0x16,0x37,0x60,0xb1,0xa0,0x98,0xd9,0x0,0xd,0x45,0xdc,0xca,0xb3,0xc2, + 0x8a,0x4b,0x7a,0x71,0xc1,0x2b,0x27,0xb0,0x69,0x4d,0x5e,0xd4,0xe7,0x5d,0x6,0xe0, + 0xaa,0x6f,0x0,0xcc,0x3e,0xc1,0x96,0x4,0x5a,0x6b,0xfc,0xed,0x27,0x86,0xb1,0x6d, + 0x63,0x82,0xff,0xf4,0xe1,0xc5,0xd6,0x99,0xe9,0xca,0x6,0xcd,0x8c,0xdc,0xde,0x7f, + 0x28,0x76,0x8,0x9,0xec,0xee,0x20,0x26,0x9d,0xe4,0xf6,0x4e,0x24,0xc0,0xc3,0x3f, + 0x19,0xc7,0xfe,0x3d,0x2,0x1,0x8c,0xaf,0x77,0x3b,0x93,0xf8,0xe0,0xbb,0x32,0x30, + 0x0,0x7c,0xee,0x96,0x1d,0xf8,0xe8,0x6d,0xa7,0x43,0x31,0x82,0xb2,0x7e,0x5f,0x49, + 0x40,0x38,0xd9,0xb7,0xe0,0x8b,0x8c,0xa0,0x6b,0x4,0x28,0xc1,0xff,0xf2,0x27,0xaf, + 0xbc,0x6c,0xe5,0x20,0x28,0x87,0x52,0x12,0xb9,0xae,0x82,0x9f,0x65,0x26,0xa5,0x4d, + 0x2f,0x1f,0xc4,0xdc,0x27,0xd6,0x43,0x24,0x9,0x44,0x9a,0x22,0x4f,0x92,0x2,0xfc, + 0xcc,0x82,0x9f,0x59,0xf0,0x53,0x29,0x90,0x4a,0x13,0xf0,0x66,0x52,0x61,0x8d,0x16, + 0x78,0xb8,0xd3,0x41,0xb2,0x77,0x1c,0xc3,0x44,0x3f,0xbf,0x97,0xe8,0x13,0x76,0x60, + 0x64,0xfc,0xb8,0xc5,0x0,0xd3,0x62,0x1,0xcf,0x92,0x5c,0x6,0x60,0x46,0xa6,0xcc, + 0x80,0x66,0x26,0x34,0x7e,0xeb,0x53,0xa7,0xa0,0xd1,0x92,0x5d,0x5b,0xc3,0x2e,0x32, + 0xaf,0x2b,0x41,0x14,0x45,0xf8,0xee,0xd7,0xf,0xe2,0xc3,0x37,0xf,0x61,0xe3,0xea, + 0x4,0xa1,0xed,0xdc,0x85,0x3c,0x28,0x3a,0x79,0x8d,0x20,0x40,0xc4,0x39,0x1a,0x1, + 0x37,0x5f,0xb,0xcc,0xcf,0x4,0x76,0x2f,0xe2,0xb1,0x7d,0x39,0xfe,0xec,0xf7,0x9e, + 0xc1,0x67,0x6f,0xdd,0x85,0xb4,0x53,0xa6,0x7a,0x7e,0x9f,0xa2,0x5e,0xa5,0x64,0x8c, + 0x21,0x8d,0x9,0x7f,0xf3,0x87,0xbb,0x11,0x4f,0xaa,0x22,0xe8,0xab,0x83,0x2f,0x73, + 0xa3,0xa,0x7e,0x1a,0x58,0xb5,0xfc,0x73,0x7,0x41,0x2,0xd0,0x2,0x94,0x8d,0x79, + 0xe0,0xa7,0xb6,0x98,0x65,0xea,0x19,0x53,0x42,0x60,0xdb,0xd5,0xab,0x90,0xa,0x81, + 0xdc,0xf9,0xfc,0x2c,0xb3,0x56,0x6f,0x2c,0x3f,0x11,0x8e,0x0,0x6,0xf8,0x44,0x2a, + 0xc4,0x4a,0x23,0x53,0xa,0x9,0x11,0xf6,0x11,0x3d,0x71,0x2f,0xd1,0x67,0x2c,0xf8, + 0xc3,0xc7,0x3d,0x8,0x74,0xbb,0x87,0xc1,0xeb,0x3,0x68,0x94,0x19,0x80,0x22,0xed, + 0x45,0xe4,0xa,0x7d,0xf3,0x43,0xdc,0xfc,0xdb,0xfd,0x33,0xce,0x6,0xb8,0x8b,0x5f, + 0x57,0x82,0x28,0x8a,0xb0,0x7b,0x48,0xe3,0x4f,0xde,0xb3,0x3,0x9f,0xfa,0xcf,0xdb, + 0xb0,0xfe,0x81,0x4e,0x9,0x76,0x18,0x20,0xa,0x2,0x44,0x61,0x58,0x34,0x76,0xa2, + 0x20,0x44,0x83,0x87,0xd8,0xbb,0x35,0xc5,0x6d,0x9f,0xd9,0x8e,0xf7,0x5e,0xf7,0x24, + 0xee,0xff,0x6e,0x82,0x28,0x6a,0x16,0xb3,0x4,0x7e,0x8b,0xba,0xdb,0xe1,0xe6,0x8, + 0xf6,0x6e,0x15,0xb8,0xfb,0xf6,0xf1,0x2,0x74,0x25,0xc,0xe8,0x86,0x8,0x80,0x70, + 0xa,0x20,0xdd,0x6,0xa9,0x55,0xd9,0x7,0xe5,0x80,0xce,0x1,0x9d,0x81,0xe5,0x43, + 0xa5,0xa4,0xa7,0xa6,0x7d,0xed,0x4a,0xda,0x71,0xa7,0x83,0xf1,0x9e,0x5e,0x3c,0x3d, + 0xf8,0x6a,0xc4,0xc2,0x4c,0x53,0xa5,0x99,0x3,0x3f,0x2f,0x64,0xdf,0x14,0xbb,0x24, + 0x52,0xa9,0x90,0x2a,0x8d,0x4c,0x6b,0x24,0x44,0x18,0xd3,0xb4,0xe7,0x1,0xa2,0x7f, + 0x2,0xb0,0xd6,0x7,0xff,0xf8,0xb9,0x0,0x54,0x3,0xaf,0x22,0x16,0x28,0xea,0x2, + 0x1a,0x4a,0x33,0x4,0x4c,0x43,0x32,0x6,0xae,0xcc,0xf8,0xf5,0x1b,0x6e,0x1e,0xc0, + 0xc3,0xdf,0xef,0xe0,0xe9,0xc7,0xf2,0x4a,0x1c,0xe0,0x7c,0xb2,0x2f,0xcb,0x7e,0x95, + 0xd0,0x91,0xe2,0xa9,0xc7,0x72,0x6c,0xf8,0xf9,0x6e,0xf4,0xcd,0x3,0xce,0xb9,0xb8, + 0x89,0xf3,0x2f,0xeb,0x43,0xd8,0x0,0xce,0xb9,0xa4,0x17,0xdb,0x9e,0x4e,0x10,0x4f, + 0x69,0xec,0xd8,0x9c,0x62,0xd7,0x50,0x8a,0x1d,0x9b,0xa4,0x5d,0xe4,0x19,0x21,0x6c, + 0x84,0x95,0xd,0xa9,0xfc,0x72,0xb4,0x6b,0x34,0xf9,0x6d,0x60,0x3f,0x4d,0x7d,0xea, + 0xe1,0x4,0x2f,0x7f,0x7d,0xb,0xac,0x69,0xc0,0x96,0x1e,0xf8,0x5,0x31,0xca,0x3a, + 0x80,0x95,0xfd,0x73,0x6,0xa1,0x73,0x18,0x2,0x64,0x90,0x2a,0x46,0x3e,0xf2,0x39, + 0xa8,0x9e,0x3f,0x45,0xaa,0xce,0xb7,0xe0,0xc7,0x68,0xb7,0x3b,0xe8,0x74,0x3a,0x45, + 0x5f,0x63,0x2a,0x6a,0x62,0xcf,0x85,0x2f,0xc3,0xb9,0xf,0x3d,0xc,0x95,0x67,0xd6, + 0xe7,0xcb,0xd2,0xf2,0x95,0x42,0xaa,0x14,0x12,0xa5,0x91,0x6a,0x85,0x94,0x8,0x63, + 0x44,0x7b,0x7e,0x2,0xfa,0x42,0x1b,0xf8,0x16,0x11,0x6d,0x7b,0x6e,0xe6,0x1,0x6a, + 0xc1,0x60,0xb1,0x81,0x92,0x5b,0x32,0x66,0xd3,0x33,0x49,0xc,0x4c,0x33,0x48,0xc6, + 0xc0,0x94,0x2,0xcb,0x81,0x5b,0xff,0xf2,0x34,0x7c,0xf4,0xe6,0x1d,0x18,0x1b,0xce, + 0x8a,0x7c,0xdc,0x59,0x7c,0x9d,0x4,0xae,0x50,0xe4,0x82,0x47,0x57,0xac,0x49,0xdb, + 0x1a,0xeb,0x1e,0x10,0x58,0x73,0xff,0x98,0xfd,0xd9,0x11,0xdf,0xff,0x9a,0xce,0x9f, + 0x1d,0xed,0x76,0x87,0x3,0xdb,0x55,0x3,0xfd,0x5a,0x80,0x7f,0xf8,0xf3,0x5,0x5a, + 0x6b,0x5c,0xf5,0xd6,0x39,0x88,0x7a,0x19,0xe2,0x44,0x41,0x66,0xda,0x58,0x7d,0x6a, + 0x5d,0x82,0x25,0x81,0x8d,0x47,0x5f,0xfe,0x57,0x9f,0xbd,0xe5,0x9c,0x2a,0xf8,0x39, + 0xa4,0x8a,0x91,0x8e,0x7c,0xe,0xc8,0x27,0x30,0x27,0xfb,0x34,0xe,0x84,0xb7,0x21, + 0xb6,0x8b,0x55,0x3a,0x9d,0xe,0x3a,0xed,0xe,0xda,0xed,0x29,0x4c,0x4d,0x4d,0xe1, + 0xe0,0xc1,0x83,0x18,0xf,0x22,0x3c,0x75,0xee,0xb9,0xb8,0x78,0xdd,0x7a,0xcc,0xab, + 0x80,0x6f,0x2c,0x3f,0xd1,0xa,0xa9,0xd6,0x6,0x7c,0xad,0xf7,0xfc,0x4,0x70,0xe0, + 0xaf,0x7b,0xee,0x6,0x42,0x6a,0x2c,0x70,0x77,0xe0,0xd2,0x76,0x67,0x4d,0x46,0x0, + 0xd3,0x66,0xd1,0x98,0xdb,0x4e,0xde,0xad,0x1b,0x6a,0x84,0x21,0x7e,0xff,0xaf,0x97, + 0xe0,0xe3,0xef,0xda,0x8d,0x2c,0x36,0x20,0xf8,0x3d,0x7f,0x9f,0x4,0x3e,0xa8,0xe, + 0x58,0xa7,0x6,0x75,0xf0,0xe0,0x65,0x4,0xfe,0xeb,0xf8,0x84,0xf2,0xd3,0xbd,0xba, + 0xa5,0x77,0x6b,0x3d,0x9f,0x7e,0x4e,0x3,0x2f,0x7b,0x75,0xf,0x3a,0xb1,0x34,0xc0, + 0xe7,0x4,0x91,0xe9,0x4a,0x3c,0x20,0x32,0xc2,0xc4,0xb0,0x8c,0xfe,0xe8,0x43,0xbf, + 0xfe,0x86,0xdf,0x7d,0xef,0x4d,0x57,0x19,0x9f,0x6f,0x8,0xa0,0x40,0x5,0xf8,0xa4, + 0x34,0xb8,0x1c,0xc6,0xbc,0xf4,0x2f,0x70,0x20,0x79,0x57,0x5,0xfc,0x83,0x93,0x93, + 0x76,0xa6,0x61,0x1c,0x13,0x13,0xe3,0x18,0x9d,0x6c,0x63,0x7d,0xdf,0x1c,0x2c,0xc9, + 0x5,0x2e,0x4d,0x33,0xf4,0x38,0xf0,0x95,0x7,0x3e,0xd1,0x61,0xc1,0x3f,0xee,0x4, + 0x28,0x55,0x0,0x76,0x63,0x8,0xb3,0x64,0xcc,0xdc,0x62,0xc6,0xd4,0x4,0x98,0x36, + 0x7b,0xf2,0x32,0x7b,0x2f,0x1,0xc6,0x14,0x16,0x2e,0x6f,0xe2,0x53,0xff,0xb0,0xc, + 0x7f,0xfc,0x6b,0x3b,0x91,0xc5,0xa6,0x43,0xa7,0x94,0xaa,0x28,0x41,0xe5,0xef,0xd4, + 0xc8,0xe0,0x48,0xe0,0x83,0xdf,0xed,0x67,0x7c,0xd0,0xfd,0xe7,0x3e,0xf8,0xab,0x6e, + 0x9c,0x87,0xad,0xcf,0xb4,0xb1,0x7d,0x63,0x5e,0xf9,0xbd,0x46,0x93,0x70,0xdd,0x3b, + 0xe7,0x21,0x4f,0x35,0xf2,0xcc,0xdc,0x71,0x24,0x4f,0x6d,0xe4,0x9f,0x97,0xe7,0xd1, + 0x5d,0x12,0x37,0x5e,0x7d,0x7d,0xeb,0x93,0x1f,0x79,0xf7,0x55,0xd0,0xc2,0x58,0x3e, + 0xe5,0x50,0xbc,0x17,0xe9,0xc8,0x5f,0x15,0xe0,0x93,0x24,0x90,0xd2,0x58,0xa0,0x7e, + 0x80,0xfe,0xbc,0x89,0x7d,0x9d,0xd7,0xa1,0xdd,0x69,0x63,0xb2,0xe,0xfe,0xe8,0x28, + 0xf6,0xef,0xdf,0x8f,0x4e,0xa7,0x83,0x27,0xb4,0xc2,0x6a,0x1e,0x40,0x43,0x22,0x22, + 0xc2,0x80,0xd6,0x18,0x23,0xc2,0x88,0xd6,0x7b,0x8,0xf8,0x2,0xe,0x3,0xfe,0x73, + 0x12,0x3,0xf8,0x77,0xec,0x98,0xee,0xa,0x34,0x14,0x99,0x7b,0x33,0xba,0x5d,0x45, + 0x1d,0xb4,0x8b,0x96,0x37,0xf1,0xe9,0xaf,0x2d,0xc3,0x1f,0xfd,0xea,0x4e,0xa4,0x1d, + 0x5d,0x14,0x83,0x7c,0x57,0xe0,0xc0,0xac,0x5b,0x68,0x3d,0x7f,0xef,0x76,0xae,0x3f, + 0xae,0x4b,0xbc,0xd6,0x1a,0xab,0xde,0x3c,0x80,0x77,0xdd,0xba,0x14,0xed,0xa9,0xc, + 0x7f,0xf0,0x2b,0xcf,0x20,0x6e,0x97,0xaa,0xb2,0xea,0x97,0x6,0x10,0xf5,0x31,0x74, + 0x62,0x85,0x3c,0xd5,0x55,0xcb,0x77,0xe0,0xef,0x94,0x78,0xd3,0xab,0xae,0xc3,0xe7, + 0x3e,0x72,0x6b,0x54,0x80,0xaf,0x33,0x28,0xde,0x87,0x74,0xe4,0xf3,0xa0,0xce,0x13, + 0x15,0xf0,0xcd,0x41,0x58,0x11,0x7c,0xf,0x5b,0xd3,0x7e,0x4c,0x1e,0x5c,0x62,0xc1, + 0x1f,0xc3,0xc4,0xc4,0x4,0x46,0x47,0x47,0x70,0x60,0xff,0x81,0xa2,0x74,0x9d,0x67, + 0xb9,0x59,0x40,0x23,0x25,0xa6,0x94,0xc2,0x1,0xad,0xa1,0x89,0xf6,0xe0,0x8,0xc1, + 0x3f,0xee,0x69,0xa0,0x9f,0x11,0xc0,0xeb,0xc,0xea,0x62,0x30,0x84,0xec,0x32,0x6a, + 0x32,0xd9,0x80,0xd2,0x66,0xaf,0x3f,0x7b,0x2c,0x5c,0xde,0xc4,0xff,0xfb,0x7f,0xcf, + 0xc2,0x19,0xe7,0xf1,0x4a,0x29,0xb6,0x5b,0xf7,0xb0,0x3e,0x55,0x54,0xf,0xd8,0xfc, + 0x26,0x53,0x7d,0x18,0xb5,0x5e,0xee,0x95,0x4a,0xe2,0x3d,0x1f,0x3d,0xd,0xef,0xbc, + 0x75,0x9,0xda,0x49,0xe,0x41,0x84,0xdf,0xf9,0xf4,0xe9,0x88,0x5a,0x86,0x20,0xa7, + 0x9f,0x13,0xe1,0xa2,0xab,0x7a,0x91,0xa6,0xa,0x59,0xaa,0xac,0x2,0xe8,0x22,0xea, + 0xf7,0xc1,0xff,0x1f,0x1f,0xfd,0x10,0xfc,0x80,0xcf,0x80,0xff,0x57,0xa0,0xce,0x7a, + 0x90,0x9c,0xe,0x3e,0x49,0x8d,0x50,0xa7,0x78,0xfd,0xc2,0xff,0x8d,0x45,0xec,0x7b, + 0x18,0x1f,0x1b,0xb7,0xe0,0x8f,0x62,0x64,0x64,0xc,0x6d,0xd7,0xb7,0xc8,0xb3,0x62, + 0xf5,0x54,0xd1,0x46,0x3f,0x4a,0xf0,0x9f,0x1b,0x5,0xa8,0x5,0x84,0xe5,0x56,0xf2, + 0xe5,0x46,0x8a,0x4a,0x97,0x6b,0xfd,0xa,0x99,0xb6,0x7b,0x6,0xf5,0x2d,0x8,0xf1, + 0x89,0xff,0x75,0x16,0xbe,0xf9,0xc5,0xfd,0xf8,0xb7,0xbf,0x1b,0x2b,0x14,0xc0,0x77, + 0x5,0x8c,0xcd,0xdc,0x6b,0xe9,0x66,0xe9,0x33,0x59,0x3e,0x11,0x61,0xc1,0xe2,0x10, + 0xbf,0xfb,0x99,0xb3,0x70,0xea,0x19,0xd,0x74,0x52,0x1,0x91,0x6b,0x88,0x5c,0xa3, + 0x67,0x41,0x88,0xb7,0xff,0xe6,0x22,0xfc,0xeb,0x17,0xf6,0xe3,0xda,0xff,0x38,0x80, + 0x38,0x55,0x48,0x13,0x85,0x2c,0xf1,0xc1,0x37,0x2a,0x50,0x5,0xdf,0xf9,0x7c,0x61, + 0xc0,0x3f,0xf0,0x57,0xa0,0xf8,0x9,0x3,0xbe,0x3,0xdd,0x3,0x9f,0x14,0x1,0x4a, + 0xa3,0x1,0x89,0xb7,0xad,0x58,0x8d,0x30,0xd9,0x83,0x7f,0xd8,0xbc,0xc,0xa3,0xa3, + 0xa3,0x98,0x9a,0x9a,0x2a,0xba,0x96,0x22,0xf7,0xfb,0x26,0xa,0x5a,0x1f,0x3d,0xf8, + 0xcf,0x19,0x1,0xa6,0xbb,0x2,0x17,0x14,0x96,0x37,0x71,0xb2,0xf9,0xa1,0xb7,0xd9, + 0xb2,0x4,0x51,0x60,0xa6,0x74,0x9a,0x1,0x7e,0xe5,0x43,0x4b,0x30,0xf8,0x86,0x7e, + 0xfc,0xcf,0xdf,0xdf,0x85,0xfd,0xbb,0x64,0x25,0x88,0x9b,0x89,0x4,0x47,0x23,0xfd, + 0x8c,0x11,0xde,0xfa,0x9e,0x53,0xf0,0xfa,0xb7,0x2f,0x40,0xd0,0x4,0xe2,0x54,0x20, + 0xcf,0x35,0x72,0x4b,0x0,0x91,0x11,0x16,0x9f,0x13,0xe1,0xd7,0x3f,0xb1,0x4,0x1a, + 0x84,0x34,0x91,0x48,0x9d,0xf5,0xa7,0x1a,0x22,0x35,0x96,0x3f,0x52,0x7,0x9f,0xb2, + 0xd2,0xe7,0x3b,0xf0,0xb,0xe0,0xbb,0x83,0xef,0x7f,0xff,0x4d,0xe7,0xee,0xc6,0xd2, + 0x68,0x4,0xff,0xfd,0x1b,0x73,0x70,0x20,0x95,0xc8,0xf2,0x1c,0x22,0xaf,0x59,0xfe, + 0x31,0x82,0xff,0x9c,0x12,0xa0,0xb8,0xa7,0x13,0xb3,0x5,0x5b,0x1b,0xf,0x14,0x24, + 0xd0,0x1a,0x60,0xf5,0x7a,0x81,0x59,0x5a,0xa6,0x88,0xa0,0x34,0xc7,0x59,0x97,0xf4, + 0xe0,0x6f,0xee,0x3d,0x1f,0xf7,0x7d,0x6b,0x1c,0xff,0xfb,0xf3,0xc3,0x18,0xde,0x21, + 0x8e,0x88,0x0,0x87,0x52,0x2,0x80,0xf0,0xba,0x9b,0x16,0xe0,0xc6,0xff,0x74,0xa, + 0xfa,0x17,0x70,0x64,0xb9,0xb5,0xec,0x4c,0x23,0xcb,0x35,0x64,0xee,0x59,0x78,0x6e, + 0xa,0x57,0x59,0xa6,0xcd,0x32,0xb1,0xc4,0x3c,0x76,0xdf,0x2b,0x2d,0xff,0x56,0x5b, + 0xe0,0x71,0x1,0x5f,0xdd,0xf2,0xa7,0xcb,0x7e,0x37,0xf0,0x49,0x99,0x1d,0x34,0x2e, + 0x59,0x1a,0xe3,0xeb,0xbf,0xd3,0xc1,0x57,0xbe,0xdd,0x83,0xdb,0x7e,0x22,0x91,0xd8, + 0x8d,0x34,0x94,0xd2,0x0,0xf4,0x31,0x83,0xff,0xdc,0x2a,0xc0,0x34,0x12,0x68,0x73, + 0xdf,0x3f,0x9f,0x4,0x30,0x1b,0x44,0xb8,0xb2,0x9,0x91,0xe9,0x22,0x6,0x44,0xd0, + 0x3a,0x80,0xe2,0x1a,0x4a,0x73,0x5c,0x75,0xe3,0x0,0x56,0xbd,0x6d,0x3e,0x1e,0xfd, + 0xe1,0x41,0x3c,0xf2,0x83,0x83,0x78,0xe0,0xee,0x83,0x68,0x1f,0x94,0x87,0x24,0x40, + 0x85,0x4,0x20,0xac,0xbc,0xa8,0x17,0xaf,0x79,0xcb,0x7c,0xfc,0xc2,0x9b,0x7,0xc0, + 0x22,0x86,0x3c,0x97,0x88,0x33,0x81,0x3c,0x57,0xc8,0x72,0x65,0xa2,0x7a,0xeb,0xdb, + 0xd,0x9,0x8c,0x7f,0x77,0x16,0xef,0xbe,0x2f,0x52,0x5d,0xf8,0xfc,0x1b,0xa6,0xc9, + 0x7e,0x69,0xf9,0x3a,0x7e,0xc2,0x74,0xe5,0x2a,0x41,0x5f,0xf5,0x8c,0xda,0xd7,0xa0, + 0xed,0x63,0x4d,0xd8,0xbd,0x2b,0xc2,0x6b,0x75,0x7,0xab,0xae,0x36,0x53,0x47,0xd0, + 0x84,0xf1,0x84,0xf6,0x7c,0xe0,0x31,0x7c,0x61,0x38,0x3d,0x36,0xf0,0x9f,0x73,0x2, + 0xd4,0x49,0xe0,0xee,0xc6,0xe9,0x48,0x40,0x64,0x9e,0x12,0xb4,0xdd,0x52,0x90,0x95, + 0x1,0x23,0x23,0x4,0x4e,0xd,0x88,0x20,0x34,0xc3,0xcb,0x57,0xf5,0xe3,0xd2,0xd7, + 0xcd,0xc5,0x6f,0x7f,0xe6,0xc,0x6c,0x78,0xa4,0x8d,0xad,0x4f,0xc5,0x38,0xb0,0x3b, + 0xc7,0xe6,0xf5,0x89,0xd9,0x2a,0x86,0x9b,0x45,0x28,0x20,0xa0,0x6f,0x6e,0x80,0xb3, + 0xce,0x6f,0xe1,0x8c,0xb,0x7a,0x71,0xc1,0xe5,0x7d,0x68,0xf6,0x32,0x8,0xa1,0x91, + 0xe7,0xa,0x69,0xa6,0x4b,0xe0,0x73,0x85,0x2c,0xd5,0x10,0xc2,0x44,0xf6,0x79,0x11, + 0xd8,0x19,0x4b,0x37,0x11,0x3f,0x21,0xf3,0x52,0xbe,0x91,0x5d,0xc2,0x3,0x3f,0xaf, + 0x81,0xff,0xf9,0xc3,0x80,0xaf,0x1,0x67,0xfd,0xd2,0xde,0xd,0xc5,0x7,0x5f,0x11, + 0x76,0xef,0x8e,0xd0,0x79,0x2c,0x5,0x29,0xd3,0x5a,0x26,0x45,0x98,0x48,0x9f,0x3d, + 0xf8,0xcf,0xb,0x1,0x7c,0x12,0x18,0x4b,0xd7,0x66,0x23,0x6,0x70,0x73,0x8b,0x17, + 0x4d,0x45,0x65,0x88,0xdc,0x86,0x53,0x64,0xf6,0xf6,0x2f,0xb2,0x6,0x6e,0x17,0x88, + 0x70,0xe,0xae,0x19,0x84,0x62,0x38,0xe7,0xb2,0x1e,0x9c,0x7b,0x79,0x6f,0x71,0x83, + 0x2a,0x66,0x8b,0x4e,0x6e,0xb5,0x8e,0x22,0xb3,0x1d,0x8d,0x54,0x66,0x84,0x2b,0xce, + 0x34,0x84,0x50,0x10,0x82,0x90,0xb,0xeb,0xcb,0x73,0x85,0x3c,0xf7,0xa5,0xdf,0x59, + 0xbd,0x9,0xf0,0x84,0x2d,0xec,0x8,0xef,0xf9,0xe8,0x2e,0x81,0x1b,0xae,0xbc,0xe, + 0xff,0xe3,0xf,0x6e,0xed,0xa,0x3e,0xd5,0xc1,0xd7,0x75,0x99,0xa7,0xd2,0xf2,0xbb, + 0x80,0xbf,0x6b,0x77,0x84,0xd8,0x7,0x5f,0xce,0x1e,0xf8,0xcf,0x1b,0x1,0xea,0x24, + 0x60,0xb6,0x49,0x64,0xf6,0x15,0x73,0xb7,0x74,0xd4,0xa6,0x95,0xac,0xed,0x7e,0x43, + 0x76,0x93,0x7,0xce,0xcd,0x59,0x31,0x6,0x6e,0x3b,0x73,0xe5,0x9d,0x40,0x58,0x71, + 0x7b,0x7a,0x86,0x72,0xe7,0x6e,0xb2,0x46,0x66,0x8,0xa0,0x21,0x85,0x19,0xe3,0xaa, + 0x10,0x40,0x10,0x44,0xae,0x8c,0xe5,0xe7,0x64,0x83,0xbf,0x32,0xad,0x73,0xa,0x20, + 0x3c,0x45,0x18,0xdd,0xa5,0x70,0x7d,0x1,0xbe,0x28,0x8,0xa0,0x82,0xc3,0x59,0x3e, + 0x55,0x2d,0xdf,0x97,0x7d,0x8f,0x8,0x5,0xf8,0xd2,0xe,0x95,0xe8,0x2,0xfc,0x2f, + 0xe,0xa7,0xf8,0xf6,0xb3,0x5,0xff,0x79,0x25,0xc0,0x74,0x25,0xf0,0xee,0xfc,0x4c, + 0xce,0x25,0x58,0xe0,0xb,0x90,0x9,0x9c,0x18,0x34,0xab,0x2,0xef,0x6e,0x3c,0x55, + 0xdc,0x9e,0xe,0xde,0x48,0xba,0x26,0x3b,0x8,0x43,0x76,0x45,0xf,0x15,0x73,0x7c, + 0x22,0xd7,0x10,0xc2,0xde,0x82,0xc6,0x3e,0xce,0x9d,0xa5,0xbb,0x52,0x6e,0x41,0x4, + 0x5d,0x92,0x41,0x0,0xa3,0xbb,0x14,0x6e,0x18,0x7c,0x23,0xfe,0xdc,0x7,0x9f,0xe, + 0x7,0x7e,0x1d,0xec,0x2e,0x3e,0x5f,0x1b,0x9f,0x5f,0xb7,0x7c,0x68,0xc2,0x58,0x4c, + 0x7b,0x3f,0xb8,0x1a,0xb7,0xd,0xa7,0xf8,0xe,0x80,0x75,0xb3,0x81,0xc1,0xf3,0x4a, + 0x80,0xe9,0x31,0x81,0x7f,0xb,0xd6,0x72,0x9a,0x88,0x79,0x53,0x41,0xda,0x1e,0x66, + 0xb2,0x7,0xde,0xad,0xe7,0x50,0x74,0x1d,0x99,0xbd,0x73,0xa7,0x73,0x1,0x6e,0xd5, + 0xae,0x94,0x1a,0x5a,0xc1,0x10,0x40,0x11,0x84,0x23,0x82,0xd4,0x36,0x1e,0x20,0xab, + 0xc,0x66,0xc6,0x4f,0xb8,0xc3,0x76,0xf8,0xdc,0xd4,0xcf,0xc8,0x4e,0x89,0x1b,0xae, + 0x7c,0x23,0xfe,0xfc,0xf7,0xab,0x96,0xaf,0x49,0x21,0x1d,0x35,0xe0,0x93,0x9c,0x1e, + 0xd4,0x4d,0x3,0xdf,0xf7,0xf9,0x15,0xcb,0x6f,0x94,0xe0,0x4b,0xf3,0x7b,0x63,0x9, + 0xd,0x7f,0xf0,0x31,0x7c,0x65,0x5f,0x86,0x3b,0x1,0xac,0x9f,0xad,0xeb,0xff,0xbc, + 0x13,0xc0,0xaf,0x16,0xba,0x5b,0xbc,0x12,0xc8,0xde,0x65,0x9c,0x55,0x5d,0x85,0x23, + 0x1,0xe0,0xdd,0xe8,0xd1,0x2f,0x9,0xa3,0xb8,0x9d,0xbc,0xb9,0xb7,0xa0,0x21,0x81, + 0x59,0xa9,0x63,0x17,0x6d,0x68,0x3,0xb2,0x19,0xe3,0xaa,0x2,0x2d,0xad,0xfc,0xbb, + 0x71,0x2e,0xbf,0xa5,0x2b,0xec,0xd7,0x46,0x76,0x4a,0xbc,0x69,0xf0,0x8d,0xf8,0x5c, + 0x1,0x7e,0x6,0x68,0x1,0x4d,0xa,0xc9,0xd8,0x97,0xa0,0x93,0x67,0x4a,0xf0,0xbb, + 0x54,0xf9,0x48,0xcf,0x0,0xbe,0x8d,0xf6,0x77,0xed,0x6a,0x20,0x5e,0x9d,0x95,0xb2, + 0x6f,0xc0,0xdf,0xf7,0x81,0xc7,0xf0,0xd5,0xfd,0x19,0xee,0x2,0xf0,0x44,0xd9,0xd2, + 0x60,0x20,0x7a,0x76,0x3b,0x10,0x9d,0x10,0x4,0x98,0x49,0xd,0x1c,0x11,0xca,0x3a, + 0x92,0xed,0x26,0x7a,0x64,0x70,0x4d,0x26,0xb8,0x7b,0x4,0x52,0x75,0x5d,0xa2,0xd6, + 0xb0,0xab,0x76,0xcd,0x4e,0xe4,0x46,0x1,0xc,0x1,0x84,0x37,0xc8,0xe9,0xe6,0xfa, + 0x2b,0xc3,0x9d,0xd2,0x8e,0x7b,0x9,0x82,0xca,0x9,0x23,0x3b,0x24,0x6e,0x28,0xc0, + 0x77,0xc3,0x1c,0x47,0x8,0x7e,0x21,0xf3,0xb5,0x80,0xaf,0x2,0x7e,0x84,0x78,0x75, + 0xe9,0xf3,0x49,0x11,0x46,0x13,0xda,0xff,0x81,0xc7,0xf0,0xf5,0x3,0x19,0xee,0x1, + 0xf0,0x24,0x66,0xf9,0x86,0x64,0x27,0x14,0x1,0xea,0x6a,0x50,0x25,0x82,0xbd,0x1, + 0xa5,0x53,0x5,0x8f,0xc,0x40,0xb9,0xfc,0xaa,0xe0,0x81,0x36,0xf,0xb4,0x25,0x81, + 0x92,0x76,0xb3,0x6,0xab,0x4,0xbe,0x3b,0x50,0x56,0x6a,0xa5,0x1d,0xee,0x54,0x5d, + 0x8e,0x91,0x5d,0x12,0xd7,0x5f,0x79,0x1d,0x3e,0xf7,0xe1,0x5b,0x3c,0xd9,0x3f,0x6, + 0xf0,0xe5,0x21,0xc0,0xaf,0xa5,0x7a,0x23,0x31,0x8d,0x7c,0xe0,0x31,0xfc,0xf3,0x48, + 0x8e,0xef,0x5b,0xf0,0x67,0xfd,0xdf,0x9,0x47,0x80,0xae,0x44,0x40,0x19,0x28,0x3a, + 0x55,0x28,0x63,0x3,0xe6,0x6e,0xe0,0x59,0xfc,0x62,0xb9,0x14,0x1d,0xe5,0x3a,0x7d, + 0x32,0x1b,0x3e,0x6a,0x65,0xa7,0x92,0x95,0x55,0x84,0x72,0x5,0x55,0xb1,0x96,0xaf, + 0x5c,0xe1,0x63,0x48,0x31,0xb2,0x53,0xe0,0xba,0x57,0x3a,0xf0,0x7d,0xcb,0x97,0x48, + 0xc6,0x6e,0x83,0x8e,0x9f,0x29,0xb,0x39,0x3e,0xf8,0xb2,0x4,0x18,0xf5,0xe7,0xba, + 0x8b,0xe5,0x7b,0xe0,0x1f,0x88,0x69,0xf4,0x83,0x8f,0xe1,0x9b,0x23,0x39,0x7e,0x64, + 0xc1,0x27,0xef,0x78,0xf1,0x13,0xa0,0x42,0x84,0x2e,0xaa,0x50,0xba,0x5,0x2a,0xef, + 0x48,0xe7,0xee,0xde,0x49,0xcc,0x58,0x99,0x73,0x1,0xe4,0xb2,0x0,0x5b,0x54,0x92, + 0x86,0x18,0xca,0x6e,0xdf,0xa2,0x25,0x95,0xcb,0xbb,0xa5,0x37,0xe5,0xab,0x8,0x23, + 0x3b,0x4,0xde,0x78,0xf9,0x75,0xf8,0x7f,0x7e,0xcf,0x7,0xdf,0xdc,0x5e,0x66,0x3a, + 0xf8,0x55,0x5f,0x3f,0xcd,0xf2,0xb,0x32,0x78,0xd1,0xbe,0x2f,0xfb,0xd2,0x6c,0x2b, + 0xb3,0xaf,0x4d,0x63,0xb7,0x3c,0x8e,0x6f,0x8d,0x1a,0xf0,0x37,0xc0,0xed,0x8f,0x57, + 0x25,0x0,0x3d,0x5b,0xff,0xff,0x82,0x20,0xc0,0x4c,0xad,0x65,0x7f,0x45,0x50,0x79, + 0xef,0x46,0x37,0x81,0xac,0xad,0x1b,0xb0,0x2b,0x93,0xed,0x46,0x4d,0x64,0x37,0x70, + 0xd0,0xf6,0xb6,0x6e,0xe5,0x2e,0x1e,0xc6,0xfa,0xdd,0xd9,0xa9,0xc1,0xf8,0x5e,0x85, + 0x97,0x2d,0xbd,0xc4,0x3,0x3f,0xf3,0x2c,0xff,0xcb,0x87,0x6,0xdf,0xf,0xf8,0x54, + 0xd,0x7c,0xe5,0xa5,0x7a,0xbe,0xcf,0x2f,0xc1,0xbf,0x63,0x34,0xc7,0xf,0x6d,0xc0, + 0x27,0x0,0xc8,0x19,0x48,0x80,0x93,0x8a,0x0,0x5d,0x95,0xc1,0x23,0x6,0x79,0xf7, + 0xa8,0x2c,0xc0,0x77,0xcf,0x6d,0xbf,0x89,0xdc,0xa1,0xcc,0x2,0x4e,0xd2,0x2e,0x50, + 0xf4,0xf,0x6b,0xfd,0x3b,0x15,0xfd,0xd3,0x7f,0xbb,0x95,0x95,0x96,0x2f,0xad,0xcf, + 0xff,0x72,0x17,0xd9,0xa7,0x43,0xe7,0xf9,0xba,0x7b,0xc0,0xa7,0x25,0xd9,0xb8,0x60, + 0x1a,0xf8,0xeb,0x1,0x64,0x0,0xf2,0xe7,0x9a,0x0,0x6b,0xa7,0xc6,0xd4,0x7d,0xfd, + 0xb,0x82,0x55,0x2f,0x64,0x46,0x50,0x37,0x42,0x68,0x14,0x7b,0x14,0xb9,0xaf,0x69, + 0x45,0x45,0x96,0x30,0xba,0x4b,0xea,0xe1,0x2d,0x42,0x1f,0xd8,0x2a,0xd5,0xc4,0x3e, + 0x45,0x57,0x5d,0xf9,0xda,0x70,0xf9,0x92,0xf9,0x61,0x29,0xfb,0x87,0xb0,0xfc,0x5a, + 0xb5,0x6f,0x5a,0xd,0xc0,0xa9,0x81,0x26,0x6c,0x9d,0xea,0x85,0x78,0xac,0x6d,0x15, + 0xc3,0x7c,0x6f,0x7f,0x87,0x46,0x6f,0x79,0x1c,0xff,0xe6,0x81,0x9f,0xda,0x23,0xb7, + 0x2a,0xe0,0x13,0x0,0xb3,0x21,0xff,0x33,0x11,0xe0,0xb1,0x3d,0x1b,0xe5,0x3d,0xe7, + 0xbe,0x2a,0xb8,0x82,0x73,0xf4,0xbc,0xe0,0x94,0xc1,0x5f,0x17,0xe8,0x9e,0xeb,0xf2, + 0xeb,0x5,0x9,0x14,0x70,0x60,0x87,0xd4,0xbb,0x9f,0x14,0x6a,0xf7,0x26,0xa1,0x86, + 0x37,0xe5,0x32,0x4f,0xc9,0xed,0x47,0xab,0x0,0x4,0x97,0x5f,0x76,0x59,0x2f,0xc0, + 0x43,0x57,0xe4,0xf1,0xc1,0x27,0xa5,0x4d,0xa5,0x4f,0x1e,0x81,0xe5,0x6b,0x6d,0xfd, + 0xbe,0x1,0x3f,0xbb,0xaf,0x63,0x9e,0x5b,0xe5,0xd8,0x1f,0xd3,0xc8,0x2d,0xab,0xf1, + 0x8d,0x51,0x13,0xed,0x6f,0xb0,0x96,0x9f,0x79,0xe0,0xfb,0xa,0xa0,0x8f,0xab,0x2, + 0x10,0xd1,0x38,0x63,0xec,0xc7,0x7,0xf,0xc8,0x2b,0xe6,0x2f,0xe,0x6f,0x3a,0xf1, + 0x1,0x3f,0x2,0x15,0xb0,0x3f,0xb7,0xf3,0x89,0x5c,0x6d,0x7b,0x22,0x97,0x3b,0xd7, + 0xe5,0x72,0xe7,0x53,0xb9,0xbb,0xa8,0xd2,0x5e,0x64,0x51,0x7b,0x85,0xfe,0xf7,0xff, + 0xf6,0xfb,0x23,0xdd,0x98,0x84,0x66,0xd,0x64,0xc3,0x9f,0x86,0x8e,0x37,0x1a,0x80, + 0xfd,0x74,0x4f,0x1f,0x89,0xec,0xd7,0xc0,0x4f,0xca,0xca,0xe0,0x48,0x4c,0x7,0x6e, + 0x59,0x8d,0xff,0x33,0x92,0xe3,0x5e,0xb,0xbe,0xf0,0xe,0xe9,0x81,0xaf,0x66,0x1b, + 0xfc,0x43,0xc5,0x0,0xf,0xee,0x7a,0x52,0xdc,0xd9,0xbf,0x90,0xaf,0xa,0x43,0xbe, + 0xe0,0x85,0x20,0xff,0x95,0xd5,0xc0,0x4,0xa4,0x53,0x9a,0xb6,0xae,0xcd,0xe4,0xde, + 0xcd,0x52,0x6f,0x5d,0x9b,0x89,0xed,0x6b,0x73,0xe1,0x59,0x94,0xb0,0x16,0x86,0x19, + 0xfc,0x6a,0x70,0xf9,0xe5,0x97,0xcd,0x5d,0xbe,0xfc,0x74,0x2e,0xd5,0x62,0x88,0xad, + 0xef,0xb3,0x96,0x4f,0x33,0x94,0x78,0x75,0xa5,0xc1,0xe3,0xc0,0x2f,0x8,0xa1,0x9, + 0x5b,0xa6,0x7a,0x91,0xdf,0x6f,0xc1,0xb7,0xb7,0xca,0x19,0x89,0x69,0xff,0x7,0x1f, + 0xc7,0xd7,0x47,0x72,0xdc,0x6d,0xc1,0xaf,0x3,0xae,0xba,0x59,0xfe,0x6c,0xc9,0xff, + 0x8c,0x4,0x20,0x22,0xc5,0x18,0x5b,0x33,0xba,0x4b,0x7d,0x6b,0xf1,0x59,0xfc,0xdd, + 0x2f,0x4,0xe9,0xcf,0x2c,0xe0,0xdb,0xd6,0xe4,0x72,0xcb,0x63,0x99,0xd8,0xbd,0x49, + 0xb8,0xe0,0x29,0xf3,0xe,0x5d,0xbb,0xa0,0xa8,0x59,0x95,0x4b,0x2e,0xe6,0xbd,0xe7, + 0x3d,0xef,0x8e,0xb4,0x92,0xd0,0x62,0x2,0x7a,0xea,0x81,0xc2,0xda,0x71,0xc8,0x9e, + 0x7e,0x35,0xef,0xf7,0x65,0x3f,0xbf,0xaf,0x3,0x96,0xe8,0x22,0xda,0x1f,0x8d,0x69, + 0xf8,0x96,0xc7,0x71,0xfb,0x81,0xb2,0xbc,0x5b,0x7,0x5b,0xd7,0x80,0xa7,0xd9,0x4a, + 0xfd,0x8e,0x28,0xb,0x20,0xa2,0x9f,0x33,0xc6,0xee,0x9a,0x7f,0x6a,0xb8,0x2a,0xea, + 0x65,0x2b,0x4f,0x34,0xc0,0xc7,0xf7,0x29,0xbd,0x6d,0x75,0x26,0xb7,0xae,0xcd,0xe5, + 0x9e,0x8d,0xb9,0xd8,0xbd,0x51,0xe4,0xd6,0xc2,0x53,0xf,0x70,0xe5,0xc9,0xbc,0xee, + 0x72,0x81,0xeb,0x8e,0x23,0x85,0xd9,0x72,0xfd,0xf4,0x5f,0x7c,0xcb,0x9b,0xce,0xd2, + 0x5a,0x42,0xe5,0x63,0xd3,0x80,0xee,0x6,0xfe,0xf4,0x49,0x9e,0xaa,0xec,0xfb,0xe0, + 0x8f,0xc5,0x34,0x7c,0xcb,0x6a,0xfc,0xbd,0xad,0xed,0xaf,0x9b,0x1,0x6c,0x5d,0x2f, + 0xfe,0xcc,0x36,0xf8,0x47,0x92,0x6,0xae,0xdd,0xb7,0x45,0xdc,0xb1,0xfc,0xe2,0xe8, + 0x43,0xcf,0x37,0xe0,0xc3,0x9b,0x84,0xda,0xbb,0x59,0xa8,0xad,0x6b,0x73,0x31,0xf4, + 0x68,0x96,0x8f,0xed,0x91,0xc2,0x3,0xda,0x81,0x2e,0x3d,0x9f,0xae,0x6b,0x92,0xaa, + 0xbb,0xc8,0x69,0x6,0x20,0x1,0x30,0x5,0x60,0xdc,0x3e,0x1e,0x78,0xef,0x7b,0x7f, + 0x63,0xe5,0xa9,0xa7,0x2e,0xea,0x51,0x52,0x40,0xf1,0x45,0x20,0xbe,0x8,0xa4,0x86, + 0x81,0x69,0x25,0x5e,0x9a,0x6,0x3e,0x79,0x1,0xdf,0x96,0xc9,0x9e,0x42,0xf6,0x1d, + 0xf8,0xe3,0xa6,0xa5,0xeb,0xba,0x7a,0xeb,0x66,0x0,0x1c,0xc7,0x1b,0xf8,0x23,0x22, + 0x0,0x11,0x6d,0x64,0x8c,0xdd,0xbb,0xf0,0xa0,0x5a,0xd5,0x3b,0x2f,0x18,0x7c,0xae, + 0x1,0xdf,0xba,0x36,0x97,0x5b,0x1f,0xcf,0xc5,0xe6,0x9f,0xa7,0x79,0xd2,0xd6,0xce, + 0x7f,0xa7,0x16,0xa8,0xcc,0x3,0x5b,0x75,0x9,0x9c,0xba,0x5,0x50,0x8e,0x2c,0xb1, + 0x5,0xdd,0xbd,0xa6,0x7f,0x5e,0x74,0xd3,0x2f,0xbe,0xf9,0x54,0x25,0x85,0xb9,0x3, + 0x88,0x14,0x50,0x8b,0xff,0x4,0xe1,0xd6,0x5b,0x41,0xaa,0xd3,0xa5,0xad,0xdb,0x1d, + 0xfc,0xad,0x93,0x9e,0xcf,0xb7,0xbf,0x33,0x9e,0xd0,0xde,0xf,0xac,0xc6,0x6d,0xfb, + 0xb2,0xa2,0x9f,0x4f,0x33,0x81,0x7e,0xbc,0x81,0x3f,0x9a,0x42,0xd0,0x9a,0xe1,0x21, + 0x71,0xef,0x59,0x97,0x6,0x17,0x1f,0xcf,0xb4,0x70,0xeb,0xda,0x5c,0x6e,0x5b,0x93, + 0xc9,0xbd,0xcf,0x48,0xe9,0x1,0x9e,0x79,0x80,0xe7,0x35,0xb,0x97,0xde,0xd7,0xea, + 0x91,0xb3,0xff,0x38,0xf3,0x2c,0x3d,0xf7,0x8e,0x7a,0x50,0xe8,0x8e,0x39,0xaf,0xba, + 0x6a,0x70,0xb9,0x52,0x8e,0x0,0x39,0x64,0x78,0xe,0xf2,0xd3,0x3e,0x81,0xe6,0xf6, + 0x8f,0x3,0x2a,0xe9,0x12,0xf1,0xd7,0xc1,0xef,0x41,0xe6,0x83,0x6f,0x7,0x38,0x3f, + 0xf8,0x38,0x6e,0xdb,0x97,0xe1,0x5b,0x28,0x87,0x39,0x68,0x5a,0xc5,0x9b,0x9e,0xdb, + 0x1b,0xcc,0x1c,0x96,0x0,0x44,0x34,0xcc,0x18,0xbb,0xab,0x3d,0xa6,0xae,0x98,0xbb, + 0x28,0xb8,0x7e,0xb6,0xfe,0xf0,0xb6,0x35,0xb9,0xd8,0xba,0x36,0x93,0x43,0x8f,0x65, + 0x62,0xe8,0xd1,0xcc,0x81,0xe2,0x83,0x25,0x6a,0x60,0x77,0x3,0x2c,0xf7,0x88,0xe0, + 0x7f,0xcd,0xbd,0x8e,0xa8,0x1,0x3e,0x13,0xe8,0xee,0xf5,0x4f,0xfb,0xc0,0xef,0xfe, + 0xd6,0x99,0x51,0x23,0x68,0x2a,0x25,0xa0,0x44,0x6,0xa9,0x72,0xc8,0x3c,0x83,0xe4, + 0xe7,0x23,0x3b,0xf5,0xc3,0x98,0xb3,0xe3,0xbf,0x3,0x2a,0xeb,0xe,0xbe,0x22,0x6c, + 0x69,0x1b,0xcb,0x2f,0x7c,0xbe,0x2a,0xc0,0xff,0xd2,0x70,0x8a,0x3b,0x6c,0x91,0xe7, + 0x79,0x3,0xfc,0x58,0x4b,0xc1,0xab,0xf7,0x6e,0x92,0xf7,0xf5,0xe,0xb0,0x2b,0x8e, + 0x25,0x2d,0xcc,0x62,0x52,0xdb,0xd7,0xa7,0xf1,0xf6,0x35,0x22,0x7b,0xe6,0x91,0x54, + 0xec,0x7a,0x4a,0xf8,0xf9,0xb7,0xb3,0x72,0xd5,0x5,0xf0,0x3a,0xd8,0xdd,0x24,0x5b, + 0xd4,0x2c,0x7b,0xa6,0x9f,0x99,0x49,0x29,0x94,0xa7,0x2c,0x97,0xbd,0xfd,0x97,0x6f, + 0x7a,0x59,0x1,0xbe,0x14,0x90,0x22,0x33,0x2a,0x20,0x53,0xe4,0xfc,0x7c,0x24,0xa7, + 0xfc,0x17,0x2c,0xdc,0xf3,0x37,0x60,0x4a,0x55,0x66,0xf7,0x49,0x13,0xb6,0xb4,0x7b, + 0xaa,0xd1,0xbe,0x22,0x8c,0xc7,0xb4,0xe7,0x83,0x6b,0xf0,0xc5,0xe1,0xd4,0x58,0xfe, + 0xf3,0xd,0xf8,0x31,0x11,0x80,0x88,0x62,0xc6,0xd8,0xf7,0x26,0x86,0xe9,0xe2,0x45, + 0xcb,0xf0,0x8e,0xc3,0xfd,0x7c,0x7b,0x5c,0xb7,0xc7,0x76,0x8a,0x83,0xdb,0xd6,0xe4, + 0x13,0x4f,0x3d,0x90,0x76,0xb6,0xad,0xcb,0x5d,0x44,0xe,0x7b,0x26,0x94,0xeb,0x12, + 0xb5,0xe7,0xa7,0x67,0x2,0xfc,0x50,0x20,0xe7,0x87,0x51,0x87,0x43,0xc5,0x6,0x7e, + 0x8c,0x10,0x2c,0x5b,0xb6,0xf4,0xec,0x4b,0x2e,0x3a,0xff,0x3c,0x3,0x7e,0xe,0x77, + 0x96,0x32,0x45,0x2e,0x32,0x48,0x91,0x41,0xe0,0x2,0xec,0x19,0x78,0x27,0x4e,0xdb, + 0x7f,0xbb,0x9d,0xb,0xb0,0x96,0x9f,0xcd,0x41,0x7e,0xdf,0x54,0x3d,0xe0,0xdb,0xf3, + 0xc1,0x35,0x47,0x36,0xbd,0xcb,0xe,0xb5,0xbe,0xed,0xc8,0x30,0xa2,0xe3,0xa9,0x0, + 0x2e,0x2d,0xbc,0x73,0xde,0xa9,0xcd,0x55,0x0,0x96,0xfa,0xdf,0x8b,0x27,0xd5,0xc4, + 0xbe,0x2d,0x72,0xfb,0xb6,0xf5,0x62,0xf7,0x86,0x1f,0x25,0xfb,0x76,0x3f,0x9d,0x8f, + 0xd7,0x4a,0x98,0x1,0x80,0x7e,0x0,0xbd,0x0,0x5a,0xf6,0xef,0x72,0x2f,0xfa,0x55, + 0x33,0x48,0xf9,0xe1,0xc0,0xee,0x26,0xe7,0x75,0xd7,0x51,0x7,0x5b,0xd6,0x48,0xe7, + 0xb2,0x82,0xf3,0xdf,0xf7,0xbe,0x77,0x9f,0xab,0x44,0xe,0xa9,0x4,0xa4,0xaa,0x83, + 0x9f,0x42,0xe4,0x9,0x84,0xc8,0x20,0xe8,0x42,0x6c,0xea,0xff,0x35,0xf4,0x74,0xbe, + 0x3,0xe4,0x19,0xe,0xb0,0xf3,0xa0,0x37,0xad,0x45,0x6f,0x35,0xe0,0xab,0x80,0x5f, + 0x3,0xb8,0xe,0x36,0x9b,0xe1,0x3c,0x53,0xc7,0xa3,0x5e,0xff,0x24,0xf7,0xfa,0x47, + 0x4b,0x84,0xa3,0xed,0x6,0xae,0x1d,0xd9,0xae,0xef,0x98,0x1a,0x55,0x37,0xed,0xdb, + 0x22,0x86,0xf6,0x6d,0x53,0x7b,0xd7,0xff,0x20,0xd9,0xba,0x7d,0x5d,0xb6,0x7,0xc0, + 0x3e,0x0,0xa3,0x36,0x8f,0xe6,0x0,0xe6,0x1,0x98,0xeb,0x9d,0x73,0x1b,0x7d,0x37, + 0xed,0xdf,0x75,0x5b,0x7,0xd4,0xad,0xbf,0x9b,0xac,0xcb,0x2e,0x8a,0x30,0x13,0xd8, + 0x72,0x86,0x8a,0x9a,0xee,0x52,0x52,0xf5,0x53,0xc2,0x95,0xd7,0xbf,0xf1,0x75,0x97, + 0x4a,0x99,0x19,0xf0,0x73,0x3,0xbe,0x74,0x96,0x9f,0x27,0x10,0x79,0x6,0x21,0x52, + 0x88,0x2c,0x86,0x90,0x4b,0x31,0xc1,0xde,0x5,0xc1,0x62,0xa4,0x32,0x85,0x38,0x73, + 0x5,0x54,0xf3,0x27,0xc9,0xe4,0x9a,0x9d,0x43,0x43,0x4f,0xd3,0x86,0xbf,0xdd,0x8c, + 0xef,0xc2,0xec,0xc5,0xb7,0x81,0x31,0x16,0xd6,0xc0,0xe5,0x28,0xf7,0xc4,0x80,0xf7, + 0x98,0x1d,0x2,0xf0,0x23,0x3a,0x18,0x63,0xec,0x68,0x48,0x10,0x1e,0xa5,0xcc,0xac, + 0x63,0x8c,0x7d,0xf1,0xcf,0xde,0x3a,0xfc,0x20,0x80,0x5d,0x16,0xf0,0x3d,0x16,0xd8, + 0xc8,0x5a,0x77,0x2f,0x80,0x3e,0xcf,0xc2,0xc9,0x2,0x94,0x0,0xe8,0xb1,0x3f,0x17, + 0xd4,0x8,0x70,0x38,0x9f,0x2f,0xbb,0xf8,0xf2,0xba,0x75,0x77,0x2b,0xa1,0xaa,0x2e, + 0x45,0x16,0xdd,0xa5,0xc8,0xd2,0x7f,0xc6,0xb2,0x65,0x17,0xcd,0x9f,0x3b,0x67,0x45, + 0x1,0xbe,0x48,0x21,0x65,0x86,0x5c,0x64,0x10,0x79,0x6c,0x2c,0xdf,0x82,0x9f,0xe7, + 0x29,0x84,0x48,0x20,0x44,0x8c,0x76,0x32,0x95,0x6c,0xd9,0xb4,0x6f,0xc3,0xda,0x27, + 0xb7,0x6d,0xf8,0xd6,0x5d,0xdb,0x1f,0x7,0xb0,0x1b,0xc0,0x16,0x0,0x4f,0xdb,0x6b, + 0xe0,0xae,0x45,0xfd,0xe8,0x46,0x84,0x3a,0xd8,0xda,0xbb,0x46,0x74,0x88,0x4a,0xa1, + 0x9e,0xa1,0x23,0x32,0xeb,0xa,0x0,0xeb,0xcb,0xd6,0x59,0xbf,0xe5,0x3e,0x4c,0xe0, + 0x81,0xe4,0x7f,0x28,0x67,0x75,0x2e,0xb2,0x6f,0x2,0x68,0x78,0xfe,0x9f,0x66,0xf0, + 0xff,0x72,0x86,0xa6,0x88,0x98,0x41,0xce,0xe5,0x61,0x2e,0x4e,0xb7,0x8b,0xea,0x5f, + 0xec,0xb3,0x2f,0xbf,0xe4,0x92,0xb,0xef,0xb9,0xe7,0x27,0x78,0xcb,0x5b,0x5e,0x6b, + 0x2c,0xbf,0x2,0x7e,0x6a,0xac,0x3f,0xb3,0x8f,0x45,0x82,0x67,0x86,0x76,0x3d,0xb9, + 0x6e,0xdd,0xd0,0x93,0x77,0xfd,0x60,0xdd,0x53,0xa3,0xa3,0x53,0x6b,0x1,0x6c,0xb7, + 0x87,0x73,0x6f,0xa7,0xd8,0xeb,0xe2,0x3e,0x6f,0xe8,0x5d,0x2b,0xee,0x19,0x8,0xf3, + 0x62,0x21,0x5d,0x73,0x89,0xea,0x10,0xaa,0x26,0xbb,0x90,0xa6,0x88,0x27,0x8e,0x54, + 0x5,0x9e,0xed,0x40,0x88,0xbb,0xa0,0xcc,0xbe,0xa1,0x3a,0x9b,0xb5,0x97,0x8b,0x3b, + 0x95,0xf0,0xe5,0x90,0x6a,0x1f,0x48,0xce,0x20,0xe9,0xea,0x30,0x4d,0x12,0x75,0x18, + 0xb,0xef,0x26,0xa5,0xfe,0x67,0x78,0xd9,0xf2,0xe5,0xcb,0xae,0x58,0xb7,0xf6,0x69, + 0x2c,0x98,0xdf,0x8b,0xcb,0x2e,0x3b,0x17,0xb9,0xf3,0xf9,0x79,0x6a,0xac,0x3f,0x8b, + 0xb1,0x65,0xc7,0xee,0xad,0xf,0x3d,0xfc,0xc4,0xda,0x6f,0xdf,0xf5,0xf0,0x33,0x23, + 0x23,0x53,0xcf,0x58,0x15,0xdc,0x63,0xff,0x5e,0x3,0xc0,0x59,0xde,0x67,0x6c,0xd8, + 0x23,0xb4,0x47,0xd0,0xc5,0xe2,0xeb,0x80,0x77,0x53,0x3f,0x3f,0x9d,0xe5,0xf6,0xec, + 0xf7,0x30,0x98,0xa7,0x26,0x45,0x79,0xfb,0x48,0x49,0xf0,0xac,0x8,0x40,0x44,0x64, + 0x63,0x8f,0x3a,0x9,0xe0,0x45,0xfc,0xee,0x43,0xb8,0xb,0x12,0x1c,0xe2,0x2,0xa8, + 0x2e,0xec,0x57,0x33,0x4,0x6d,0x75,0x59,0x9f,0xc9,0x2f,0x76,0xb,0x9a,0xe0,0x59, + 0xe0,0x69,0x17,0x9c,0x77,0xde,0x2b,0x9b,0xcd,0x68,0xe9,0xc1,0xc9,0x49,0xfc,0xfd, + 0xed,0xff,0x86,0x95,0x3f,0x5d,0x84,0x77,0xdc,0x7c,0x2d,0x7a,0x7a,0x22,0xec,0xd9, + 0x33,0xbc,0xef,0x67,0xf,0xad,0x7d,0xe2,0xbb,0x77,0xff,0x6c,0xcb,0x33,0x9b,0xf7, + 0x6c,0x6,0xb0,0xd3,0xc6,0x3b,0xdc,0x82,0x7d,0x8e,0x55,0xb6,0xc8,0x53,0xb8,0xc8, + 0xfb,0xac,0x3e,0xf0,0xbe,0xd1,0x48,0xcf,0x38,0x44,0xad,0x6,0xe2,0x97,0xb7,0x51, + 0x23,0x76,0x60,0xcf,0x3e,0xe0,0xec,0x58,0xdb,0xc4,0xb3,0x35,0x12,0x46,0x5d,0xfc, + 0x90,0xef,0xdf,0xb3,0x2e,0x56,0x80,0x5a,0x16,0xa0,0xba,0xd4,0xec,0x9f,0x2d,0xe0, + 0xd4,0x85,0xb0,0xbe,0xc5,0x34,0x0,0x5c,0x7e,0xe9,0x85,0x97,0x5c,0x99,0x67,0xb9, + 0xdd,0x7a,0x35,0xc3,0x4f,0x1f,0x58,0x37,0xf9,0x8f,0xff,0x72,0xd7,0xd6,0x25,0x4b, + 0x16,0x6c,0x18,0x1a,0xda,0x39,0xc,0x60,0x2f,0x80,0x9,0xfb,0x7e,0xe6,0x1,0x58, + 0x6c,0xe3,0x1d,0x7,0xba,0x23,0x40,0xe4,0x49,0x7e,0x30,0xc3,0xe7,0x14,0x35,0xc0, + 0x53,0xaf,0x3c,0xed,0xc7,0x4d,0x8e,0x20,0x41,0xcd,0x6d,0x74,0xb,0x1e,0x51,0x23, + 0x2,0x3b,0x52,0x15,0x78,0xd6,0x4,0xa8,0xa9,0x40,0x9d,0x14,0xaa,0xcb,0x87,0x60, + 0xde,0x1b,0xa5,0xda,0xc5,0xa9,0xcb,0xf8,0xb3,0x6,0xbc,0x5b,0xca,0x6d,0x3f,0xb7, + 0xb,0x5a,0x2f,0x3e,0x75,0xd1,0x82,0xb,0xe3,0x38,0xce,0xb6,0xed,0xd8,0xb1,0xe9, + 0xe9,0xcd,0x9b,0xb7,0x1f,0x9c,0x9c,0x1c,0x1,0x30,0x39,0x34,0xd4,0x19,0xb3,0xaf, + 0xb9,0x8,0xc0,0xb2,0x1a,0xe8,0x3e,0xe0,0x61,0xd,0x24,0xd4,0x14,0x4e,0xd6,0x80, + 0x4f,0x6a,0xa9,0xb0,0xb2,0xaf,0x23,0xba,0xbc,0xd6,0x4c,0x19,0xc2,0x8c,0x25,0x85, + 0xa3,0x51,0x83,0x59,0x51,0x80,0x1a,0x9,0xa8,0xb,0xeb,0xf9,0x51,0x44,0xbc,0xb3, + 0xd,0x78,0xb7,0xb,0xe4,0x82,0xb3,0x3e,0x0,0x3b,0xee,0x7b,0xf8,0xa1,0x7,0x1f, + 0x5f,0xbf,0x7e,0x8f,0x6d,0x10,0x25,0xf6,0x7b,0x73,0xac,0xbc,0xf7,0x74,0x1,0xde, + 0x97,0xf7,0xa0,0xcb,0x67,0xf2,0x55,0xcd,0xf7,0xe5,0xac,0x6,0xf6,0xa1,0xb2,0x81, + 0x13,0xaa,0x14,0x7c,0x34,0x24,0x80,0x67,0xcd,0xbc,0x16,0xa4,0xe0,0x10,0x4,0x38, + 0x54,0xb0,0xf6,0x6c,0x0,0xef,0x56,0x6d,0x73,0x24,0x8,0x1,0x6c,0x7e,0x7c,0xfd, + 0xfa,0x6f,0xda,0xf7,0xbc,0x18,0xc0,0x42,0x0,0xf3,0x6d,0xe1,0x6a,0x8e,0x5,0xdd, + 0x27,0x40,0xe0,0x59,0x2f,0xab,0x65,0x34,0xbe,0x7c,0xc3,0xab,0x78,0x1e,0xae,0x8, + 0x44,0xc7,0x92,0xc2,0x9d,0x50,0x4,0xe8,0x42,0x2,0xaa,0xa5,0x39,0x6c,0x6,0x2, + 0x60,0x86,0xc8,0x7c,0xd6,0xbb,0x64,0xde,0xfb,0xab,0xc7,0x27,0x43,0x16,0xf8,0x96, + 0x27,0xcb,0xae,0xa9,0xd4,0xf2,0x2c,0xbf,0xe5,0x45,0xf9,0xc1,0xc,0xb2,0xef,0xe7, + 0xeb,0x7e,0xea,0xaa,0xba,0xc4,0x3b,0xca,0xcb,0xf1,0x8f,0xd4,0xdd,0x1d,0x49,0x3c, + 0xf6,0xfc,0x10,0x60,0x6,0x12,0x1c,0xaa,0xbc,0x39,0xd3,0x48,0xe7,0xf1,0xec,0x92, + 0x91,0x27,0xcd,0x1d,0xcf,0x57,0x27,0xb6,0x8a,0xe9,0x2c,0xbf,0xcf,0x2b,0x5d,0xb7, + 0x6a,0x44,0xf0,0x63,0x80,0x7a,0x9a,0x17,0x78,0x9f,0xc5,0x7,0xdd,0x77,0x5,0xf9, + 0xc,0x45,0x2c,0x7d,0x88,0x34,0x96,0xe,0x37,0x3f,0x50,0x37,0x9c,0xe3,0x9e,0x6, + 0x1e,0x49,0x63,0xa2,0x46,0x86,0x59,0x6f,0x66,0x1c,0x23,0x1,0xa4,0x67,0x6d,0xae, + 0x4a,0x39,0xe1,0x81,0xdc,0xea,0x22,0xfd,0x2d,0x2f,0xe2,0xef,0x46,0x86,0x46,0x4d, + 0x1d,0x78,0xad,0xdf,0x41,0xb5,0x3a,0x47,0xee,0x65,0x0,0x59,0xad,0xec,0x5d,0x27, + 0xc5,0x91,0xa6,0xb6,0xcf,0xaf,0xb,0x78,0x9e,0x81,0x3d,0x9a,0xf7,0xe3,0x54,0xca, + 0x59,0x60,0xea,0x49,0x7a,0xe8,0x9d,0xc3,0x5a,0x51,0xa7,0xe1,0x59,0xbe,0x9f,0xf3, + 0xb7,0xec,0xe3,0x66,0x97,0x2,0x50,0x3d,0xc0,0x9b,0xa9,0xfa,0x59,0x1f,0x6f,0x13, + 0xb5,0x86,0x9a,0xef,0x2e,0xe8,0x10,0xd6,0x7f,0x62,0x11,0xe0,0x44,0xfd,0x47,0x54, + 0xdc,0xcf,0x53,0x7b,0xb5,0x1,0x56,0xb,0x5a,0x59,0xcd,0x9a,0x3,0xaf,0xac,0xdb, + 0xf0,0x88,0xd2,0xf0,0xce,0x51,0xed,0x6b,0x7e,0xd0,0xc8,0xbb,0x4,0x8d,0xdd,0x2a, + 0xa1,0xdd,0x1a,0x5f,0xaa,0x4b,0xba,0x3c,0x23,0xf0,0xcf,0x55,0x29,0xf8,0xc5,0x42, + 0x86,0x69,0x41,0x56,0x2d,0x63,0xe8,0xd6,0xb5,0xe3,0x35,0x62,0x4,0x5d,0x48,0x12, + 0x74,0xe9,0x1,0x4,0xb5,0xec,0x1,0xb5,0xf4,0xb7,0x1e,0x28,0xce,0x54,0x21,0x3d, + 0x54,0xbf,0xe3,0xc8,0x33,0xa3,0x13,0x4c,0xa1,0x5f,0x30,0xff,0x3c,0xd5,0xa8,0x93, + 0x24,0xf0,0x4a,0xcd,0xbc,0xb,0x59,0xd8,0x21,0xea,0x22,0xf5,0x5a,0x2,0x75,0x29, + 0x8c,0xcd,0x4,0xfc,0x31,0x2d,0x1c,0xf9,0xff,0x1,0x1f,0xdc,0x76,0xde,0x36,0x49, + 0xe6,0xd2,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82, + // /home/user/src/ananas-qt4/src/designer/formdesigner/templates/forms/Dialog_with_Buttons_Bottom.ui + 0x0,0x0,0x2,0x72, + 0x0, + 0x0,0x8,0xb0,0x78,0x9c,0xb5,0x55,0x4d,0x8f,0xd3,0x30,0x10,0xbd,0x23,0xf1,0x1f, + 0xa2,0x9e,0xe0,0x42,0xda,0xa6,0xfb,0x29,0x37,0x87,0x85,0x43,0x25,0x90,0x60,0x25, + 0x24,0xce,0x5e,0x77,0x48,0xcc,0x26,0x76,0xe4,0x38,0x34,0xd9,0x5f,0x8f,0xbf,0x93, + 0xb8,0xad,0x56,0xb0,0xcb,0x29,0x33,0xcf,0xe3,0x37,0x33,0xcf,0xf6,0x4,0x75,0x34, + 0xf9,0xd,0xa2,0xa5,0x9c,0x6d,0x17,0x9b,0xf,0xcb,0x45,0x92,0xbf,0x7d,0x93,0x20, + 0xdc,0xc9,0x92,0x8b,0x1c,0xa5,0xce,0xd0,0x18,0xe1,0x75,0xd,0x4c,0x2a,0xd0,0x5b, + 0x1a,0x85,0xbe,0xe1,0x42,0xd6,0x98,0x8,0xae,0x56,0xa6,0x9e,0xd9,0x53,0xe1,0xb6, + 0xcd,0x3f,0x51,0x5c,0xf1,0x42,0xed,0x33,0x9e,0xc6,0xf,0x74,0x5f,0x80,0x4c,0xc, + 0xb0,0x5d,0xdc,0xdb,0x80,0x45,0xc2,0x70,0xd,0xdb,0x85,0xf7,0x74,0x64,0x82,0x1a, + 0xc1,0x1b,0x10,0x72,0x70,0x8b,0x5,0xf0,0x1a,0xa4,0x18,0xdc,0x72,0x82,0x4,0x10, + 0x69,0xcd,0x4,0xf5,0xf9,0x12,0xa5,0xbd,0xf7,0x6,0xed,0xd,0xde,0x53,0x29,0x65, + 0x99,0x6f,0x96,0xa,0xb3,0xa6,0xc3,0x4b,0xa0,0x45,0x29,0xf3,0x4c,0x2f,0x38,0xdb, + 0x12,0xa7,0x81,0x19,0xa5,0xbe,0x88,0x93,0x25,0x1d,0x28,0xdb,0xf3,0xc3,0x77,0x2a, + 0x2b,0x8,0x55,0xb5,0x52,0x50,0x56,0x84,0xce,0x9d,0x7b,0x8a,0x2c,0x92,0xe2,0x87, + 0x71,0xbd,0x14,0x15,0x1e,0x78,0x27,0x3d,0xe6,0xb8,0x9f,0x51,0x64,0x26,0x89,0xd6, + 0x64,0x3d,0x11,0x45,0xab,0xb2,0xbe,0x98,0xe8,0xe2,0x85,0xc9,0x2e,0x56,0x73,0x61, + 0x46,0x65,0xb2,0xb9,0x30,0x53,0x65,0xe2,0x6e,0x12,0x64,0x2b,0xe,0xed,0xec,0xee, + 0x78,0xff,0xc5,0x40,0x63,0x79,0x51,0xfd,0x35,0x16,0x5,0x65,0x61,0x39,0x41,0xac, + 0xab,0x1f,0x40,0xe8,0xc3,0x73,0x96,0x4f,0x3b,0x4f,0x75,0x44,0xd4,0x36,0x98,0x28, + 0x95,0x8f,0x99,0x2e,0x9f,0x65,0xa2,0x12,0xea,0xb0,0x4b,0xf3,0x84,0xd8,0xe3,0x34, + 0x5c,0x50,0x75,0xf9,0xb1,0x54,0x4f,0x66,0x4c,0xa5,0xc2,0x40,0xe5,0xc8,0xef,0xe5, + 0xed,0xed,0x4e,0x45,0x3c,0x71,0x15,0x52,0xa9,0x7,0xa1,0xc1,0xc0,0x14,0xe7,0x3d, + 0xd1,0x3,0x7d,0x82,0x1d,0x65,0x72,0xc6,0xac,0xc1,0xd1,0xf5,0x27,0xb6,0xca,0xe2, + 0x13,0x9b,0x1e,0xda,0x2a,0x3a,0x34,0x93,0x7e,0x46,0x74,0x5c,0x8d,0xa,0x98,0xb6, + 0x8e,0xd2,0x89,0x2c,0x73,0x89,0xa2,0x4b,0xfb,0xad,0x6b,0xcb,0xbb,0x4e,0x4a,0xad, + 0x88,0x13,0xe9,0xd1,0xfb,0x67,0x5b,0x95,0xd0,0x47,0x6d,0xda,0x47,0xf2,0xf5,0xf3, + 0xec,0xbd,0x9c,0x2b,0xd5,0x96,0xf0,0xa,0xa5,0x12,0xcc,0x8,0x54,0xff,0x5c,0xee, + 0x47,0xb3,0xfd,0x65,0x25,0xa3,0xd4,0x3e,0x1b,0x37,0x20,0xc6,0xb8,0x99,0xdd,0xd0, + 0xbe,0xc6,0xcd,0xcf,0x8e,0x11,0x7d,0xf7,0xd4,0xb4,0x8d,0x0,0x1d,0x23,0xa0,0xe5, + 0x9d,0x20,0xd0,0xa6,0x6e,0x66,0x33,0x6,0x66,0xb5,0xb5,0xdc,0x23,0xe0,0x7,0x15, + 0xb0,0xbd,0x3a,0x71,0x7f,0x5e,0xaa,0xf,0xb,0xb8,0x55,0x5a,0x30,0x5c,0xe5,0xa4, + 0xa2,0xe4,0x11,0xf6,0xef,0xde,0xeb,0x2b,0x64,0x90,0x30,0x7b,0x81,0xaa,0xdf,0x47, + 0x98,0x73,0x1,0x70,0xdb,0x2b,0x2e,0x73,0x4c,0x8,0x34,0xd2,0xec,0xd5,0xae,0x5d, + 0x29,0xd5,0x1d,0x6f,0xc3,0x8,0x56,0x4e,0x22,0x87,0x46,0xdf,0x7f,0x53,0x7d,0x85, + 0x1f,0xa0,0x9a,0xbc,0x63,0x35,0xc3,0xae,0xae,0xe3,0x21,0x96,0x4d,0x86,0x7b,0xaa, + 0x29,0x4e,0xd0,0xed,0xa1,0x95,0x94,0x99,0xb7,0x7a,0xcc,0x79,0x73,0x19,0x53,0x6e, + 0x4e,0x53,0x5a,0xdb,0x29,0x98,0x46,0x12,0x9e,0x95,0x74,0x7a,0xaf,0xfe,0x83,0xac, + 0x2,0x7e,0xa9,0xac,0x2f,0x94,0x35,0xbb,0xbc,0x79,0x75,0x59,0x57,0x57,0x31,0xe7, + 0xf5,0xfa,0xef,0x75,0x9d,0xfa,0x3a,0x2,0xa5,0x1d,0x55,0x9f,0x3f,0x70,0x8d,0x7e, + 0x64, + // /home/user/src/ananas-qt4/src/designer/formdesigner/templates/forms/Dialog_with_Buttons_Right.ui + 0x0,0x0,0x2,0x78, + 0x0, + 0x0,0x8,0xab,0x78,0x9c,0xb5,0x55,0x4d,0x6f,0xd4,0x30,0x10,0xbd,0x23,0xf1,0x1f, + 0xac,0x3d,0xc1,0x85,0xec,0x57,0x77,0x69,0xe5,0xcd,0xa1,0x70,0x40,0x2,0x9,0x2a, + 0x55,0xe5,0xec,0x7a,0x87,0xc4,0x34,0xb1,0x23,0xc7,0x61,0x13,0x7e,0x3d,0xb6,0x63, + 0x7b,0x9d,0x8f,0xaa,0x2a,0x85,0x53,0x66,0xde,0xd8,0xe3,0x37,0x6f,0xec,0x9,0x6e, + 0x18,0xfa,0x5,0xb2,0x66,0x82,0x1f,0x16,0xdb,0x77,0xcb,0x5,0x4a,0x5f,0xbf,0x42, + 0x98,0x34,0x2a,0x17,0x32,0xc5,0x89,0x33,0xc,0x46,0x45,0x59,0x2,0x57,0x1a,0xf4, + 0x96,0x41,0xa1,0xad,0x84,0x54,0x25,0xa1,0x52,0xe8,0x48,0xec,0xd9,0x3d,0x5,0xa9, + 0xeb,0xf4,0x23,0x23,0x85,0xc8,0xf4,0x3e,0xeb,0x19,0xfc,0xc4,0x8e,0x19,0x28,0x64, + 0x81,0xc3,0xe2,0xa6,0x5f,0xb0,0x40,0x9c,0x94,0x70,0x58,0x78,0xcf,0xac,0x44,0xb8, + 0x92,0xa2,0x2,0xa9,0x3a,0x17,0xcc,0x40,0x94,0xa0,0x64,0xe7,0xc2,0x8,0x4b,0xa0, + 0xaa,0x37,0x11,0x6e,0xd3,0x25,0x4e,0x5a,0xef,0x75,0xc6,0xeb,0xbc,0xa7,0x8f,0x54, + 0x79,0xba,0x5d,0x6a,0xac,0x37,0x1d,0x9e,0x3,0xcb,0x72,0x95,0x6e,0x4c,0xc0,0xd9, + 0x7d,0xe2,0x24,0x64,0xc6,0x89,0x27,0x31,0x4b,0xe9,0xc4,0xf8,0x51,0x9c,0x6e,0x99, + 0x2a,0x20,0xb0,0xaa,0x95,0x64,0x3c,0xb,0x95,0x3b,0x77,0x2e,0xd9,0x48,0x8a,0xef, + 0xd6,0xf5,0x52,0x14,0xa4,0x13,0x8d,0xf2,0x98,0xcb,0xfd,0x84,0x22,0x3,0x49,0x8c, + 0x26,0xb6,0xb4,0x36,0x0,0x5d,0xba,0x8e,0x74,0xf1,0xc2,0xec,0xf7,0x43,0x5d,0x82, + 0x30,0xab,0xe5,0x6e,0x28,0x4c,0xac,0xcc,0xb8,0x1a,0x84,0x7b,0xc6,0xa1,0x9c,0xbb, + 0x6b,0xd1,0x7e,0xb1,0xd0,0x99,0xde,0x88,0x7f,0x49,0x64,0xc6,0x78,0x8,0x23,0xcc, + 0x9b,0xf2,0x1e,0xa4,0x69,0x9e,0xb3,0xfc,0xb1,0xc3,0xa3,0x26,0x89,0xea,0x8a,0x50, + 0xad,0xf2,0x34,0xd3,0xee,0xc9,0x4c,0x4c,0x41,0x19,0xb,0x12,0x77,0xe4,0x5b,0x53, + 0xe7,0xd7,0x8d,0x52,0x82,0xfb,0xae,0x88,0x7,0xef,0xfb,0x3d,0x13,0x2e,0xa,0x5a, + 0x15,0x85,0xc3,0x85,0xf8,0xfa,0x79,0x70,0x19,0x66,0xd9,0x20,0xdb,0x9,0x4d,0x21, + 0xd0,0x8d,0xe8,0x3d,0x93,0x2a,0x25,0x9c,0x42,0xf1,0xd7,0x74,0x3f,0xd8,0xed,0xff, + 0x94,0xb2,0xe9,0x52,0xe8,0xc4,0x94,0x89,0x90,0x4c,0x8f,0x16,0xa2,0xd8,0x80,0xaf, + 0x9e,0x33,0xba,0x83,0xe9,0x8d,0xba,0xba,0xba,0xd3,0x8b,0x19,0x25,0x9a,0x94,0x85, + 0x1e,0xa7,0x34,0xbd,0x1f,0xec,0x37,0x7c,0x62,0x7c,0x54,0xa8,0x6,0xcf,0xae,0x7f, + 0xd,0xeb,0xd1,0x94,0x88,0x1f,0xc4,0x76,0x34,0x28,0xfa,0xd3,0x7,0x79,0xe6,0xf4, + 0x19,0xd4,0x1d,0xeb,0x83,0x93,0xfe,0xcd,0xb8,0xe9,0x70,0xd6,0x71,0x60,0x57,0xac, + 0x2d,0x49,0xf5,0xa3,0xe1,0xd4,0x48,0xa3,0x47,0xed,0x8,0x30,0x6b,0x24,0xd4,0xa2, + 0x91,0x14,0xea,0xc4,0xd,0x6c,0xce,0xc1,0x46,0xeb,0x3e,0xf7,0x19,0xf0,0x53,0xa, + 0xf8,0x51,0x73,0xf2,0xf7,0x59,0x93,0xec,0x1,0x17,0x65,0x19,0x27,0x45,0x4a,0xb, + 0x46,0x1f,0xe0,0xf8,0xe6,0xad,0x29,0xd2,0x22,0x61,0xf0,0x2,0xd3,0xff,0x8e,0x30, + 0xe4,0x2,0xe0,0xb6,0x17,0x42,0xa5,0x84,0x52,0xa8,0x94,0xdd,0x6b,0xdc,0x3e,0x92, + 0xeb,0x26,0xd4,0x61,0xfe,0x6a,0x7,0xa9,0xae,0x32,0xd,0xb2,0xec,0xb,0x72,0xf, + 0x45,0xf4,0x88,0xf5,0x0,0xbb,0x58,0xd,0x7,0xd8,0xe6,0x7d,0x34,0xd8,0x13,0x93, + 0x61,0x26,0xdb,0x11,0x6a,0xc5,0xb8,0xbd,0x49,0xd3,0x94,0xeb,0xcd,0x66,0x34,0x13, + 0x2f,0xe7,0x53,0xf6,0xb6,0x13,0x30,0x19,0x29,0xf8,0xa8,0xa2,0xf1,0xb3,0xfb,0xf, + 0xaa,0x4a,0xf8,0xa9,0x4f,0x7d,0xa9,0xaa,0x9b,0xd1,0x6f,0x61,0xb7,0x7b,0xa9,0xaa, + 0xab,0xcb,0xfd,0x30,0xe5,0x6a,0x7d,0xf1,0x7c,0x59,0x63,0xdf,0xac,0xc0,0x49,0xc3, + 0xf4,0xe7,0xf,0xe0,0x1d,0x7c,0xd5, + // /home/user/src/ananas-qt4/src/designer/formdesigner/templates/forms/Main_Window.ui + 0x0,0x0,0x2,0xc7, + 0x3c, + 0x75,0x69,0x20,0x76,0x65,0x72,0x73,0x69,0x6f,0x6e,0x3d,0x22,0x34,0x2e,0x30,0x22, + 0x20,0x3e,0xd,0xa,0x20,0x3c,0x61,0x75,0x74,0x68,0x6f,0x72,0x3e,0x3c,0x2f,0x61, + 0x75,0x74,0x68,0x6f,0x72,0x3e,0xd,0xa,0x20,0x3c,0x63,0x6f,0x6d,0x6d,0x65,0x6e, + 0x74,0x3e,0x3c,0x2f,0x63,0x6f,0x6d,0x6d,0x65,0x6e,0x74,0x3e,0xd,0xa,0x20,0x3c, + 0x65,0x78,0x70,0x6f,0x72,0x74,0x6d,0x61,0x63,0x72,0x6f,0x3e,0x3c,0x2f,0x65,0x78, + 0x70,0x6f,0x72,0x74,0x6d,0x61,0x63,0x72,0x6f,0x3e,0xd,0xa,0x20,0x3c,0x63,0x6c, + 0x61,0x73,0x73,0x3e,0x4d,0x61,0x69,0x6e,0x57,0x69,0x6e,0x64,0x6f,0x77,0x3c,0x2f, + 0x63,0x6c,0x61,0x73,0x73,0x3e,0xd,0xa,0x20,0x3c,0x77,0x69,0x64,0x67,0x65,0x74, + 0x20,0x63,0x6c,0x61,0x73,0x73,0x3d,0x22,0x51,0x4d,0x61,0x69,0x6e,0x57,0x69,0x6e, + 0x64,0x6f,0x77,0x22,0x20,0x6e,0x61,0x6d,0x65,0x3d,0x22,0x4d,0x61,0x69,0x6e,0x57, + 0x69,0x6e,0x64,0x6f,0x77,0x22,0x20,0x3e,0xd,0xa,0x20,0x20,0x3c,0x70,0x72,0x6f, + 0x70,0x65,0x72,0x74,0x79,0x20,0x6e,0x61,0x6d,0x65,0x3d,0x22,0x6f,0x62,0x6a,0x65, + 0x63,0x74,0x4e,0x61,0x6d,0x65,0x22,0x20,0x3e,0xd,0xa,0x20,0x20,0x20,0x3c,0x73, + 0x74,0x72,0x69,0x6e,0x67,0x20,0x6e,0x6f,0x74,0x72,0x3d,0x22,0x74,0x72,0x75,0x65, + 0x22,0x20,0x3e,0x4d,0x61,0x69,0x6e,0x57,0x69,0x6e,0x64,0x6f,0x77,0x3c,0x2f,0x73, + 0x74,0x72,0x69,0x6e,0x67,0x3e,0xd,0xa,0x20,0x20,0x3c,0x2f,0x70,0x72,0x6f,0x70, + 0x65,0x72,0x74,0x79,0x3e,0xd,0xa,0x20,0x20,0x3c,0x70,0x72,0x6f,0x70,0x65,0x72, + 0x74,0x79,0x20,0x6e,0x61,0x6d,0x65,0x3d,0x22,0x67,0x65,0x6f,0x6d,0x65,0x74,0x72, + 0x79,0x22,0x20,0x3e,0xd,0xa,0x20,0x20,0x20,0x3c,0x72,0x65,0x63,0x74,0x3e,0xd, + 0xa,0x20,0x20,0x20,0x20,0x3c,0x78,0x3e,0x30,0x3c,0x2f,0x78,0x3e,0xd,0xa,0x20, + 0x20,0x20,0x20,0x3c,0x79,0x3e,0x30,0x3c,0x2f,0x79,0x3e,0xd,0xa,0x20,0x20,0x20, + 0x20,0x3c,0x77,0x69,0x64,0x74,0x68,0x3e,0x38,0x30,0x30,0x3c,0x2f,0x77,0x69,0x64, + 0x74,0x68,0x3e,0xd,0xa,0x20,0x20,0x20,0x20,0x3c,0x68,0x65,0x69,0x67,0x68,0x74, + 0x3e,0x36,0x30,0x30,0x3c,0x2f,0x68,0x65,0x69,0x67,0x68,0x74,0x3e,0xd,0xa,0x20, + 0x20,0x20,0x3c,0x2f,0x72,0x65,0x63,0x74,0x3e,0xd,0xa,0x20,0x20,0x3c,0x2f,0x70, + 0x72,0x6f,0x70,0x65,0x72,0x74,0x79,0x3e,0xd,0xa,0x20,0x20,0x3c,0x70,0x72,0x6f, + 0x70,0x65,0x72,0x74,0x79,0x20,0x6e,0x61,0x6d,0x65,0x3d,0x22,0x77,0x69,0x6e,0x64, + 0x6f,0x77,0x54,0x69,0x74,0x6c,0x65,0x22,0x20,0x3e,0xd,0xa,0x20,0x20,0x20,0x3c, + 0x73,0x74,0x72,0x69,0x6e,0x67,0x3e,0x4d,0x61,0x69,0x6e,0x57,0x69,0x6e,0x64,0x6f, + 0x77,0x3c,0x2f,0x73,0x74,0x72,0x69,0x6e,0x67,0x3e,0xd,0xa,0x20,0x20,0x3c,0x2f, + 0x70,0x72,0x6f,0x70,0x65,0x72,0x74,0x79,0x3e,0xd,0xa,0x20,0x20,0x3c,0x77,0x69, + 0x64,0x67,0x65,0x74,0x20,0x63,0x6c,0x61,0x73,0x73,0x3d,0x22,0x51,0x4d,0x65,0x6e, + 0x75,0x42,0x61,0x72,0x22,0x20,0x6e,0x61,0x6d,0x65,0x3d,0x22,0x6d,0x65,0x6e,0x75, + 0x62,0x61,0x72,0x22,0x20,0x2f,0x3e,0xd,0xa,0x20,0x20,0x3c,0x77,0x69,0x64,0x67, + 0x65,0x74,0x20,0x63,0x6c,0x61,0x73,0x73,0x3d,0x22,0x51,0x57,0x69,0x64,0x67,0x65, + 0x74,0x22,0x20,0x6e,0x61,0x6d,0x65,0x3d,0x22,0x63,0x65,0x6e,0x74,0x72,0x61,0x6c, + 0x77,0x69,0x64,0x67,0x65,0x74,0x22,0x20,0x2f,0x3e,0xd,0xa,0x20,0x20,0x3c,0x77, + 0x69,0x64,0x67,0x65,0x74,0x20,0x63,0x6c,0x61,0x73,0x73,0x3d,0x22,0x51,0x53,0x74, + 0x61,0x74,0x75,0x73,0x42,0x61,0x72,0x22,0x20,0x6e,0x61,0x6d,0x65,0x3d,0x22,0x73, + 0x74,0x61,0x74,0x75,0x73,0x62,0x61,0x72,0x22,0x20,0x2f,0x3e,0xd,0xa,0x20,0x3c, + 0x2f,0x77,0x69,0x64,0x67,0x65,0x74,0x3e,0xd,0xa,0x20,0x3c,0x70,0x69,0x78,0x6d, + 0x61,0x70,0x66,0x75,0x6e,0x63,0x74,0x69,0x6f,0x6e,0x3e,0x3c,0x2f,0x70,0x69,0x78, + 0x6d,0x61,0x70,0x66,0x75,0x6e,0x63,0x74,0x69,0x6f,0x6e,0x3e,0xd,0xa,0x20,0x3c, + 0x63,0x6f,0x6e,0x6e,0x65,0x63,0x74,0x69,0x6f,0x6e,0x73,0x2f,0x3e,0xd,0xa,0x3c, + 0x2f,0x75,0x69,0x3e,0xd,0xa, + // /home/user/src/ananas-qt4/src/designer/formdesigner/templates/forms/Widget.ui + 0x0,0x0,0x2,0x18, + 0x3c, + 0x75,0x69,0x20,0x76,0x65,0x72,0x73,0x69,0x6f,0x6e,0x3d,0x22,0x34,0x2e,0x30,0x22, + 0x20,0x3e,0xd,0xa,0x20,0x3c,0x61,0x75,0x74,0x68,0x6f,0x72,0x3e,0x3c,0x2f,0x61, + 0x75,0x74,0x68,0x6f,0x72,0x3e,0xd,0xa,0x20,0x3c,0x63,0x6f,0x6d,0x6d,0x65,0x6e, + 0x74,0x3e,0x3c,0x2f,0x63,0x6f,0x6d,0x6d,0x65,0x6e,0x74,0x3e,0xd,0xa,0x20,0x3c, + 0x65,0x78,0x70,0x6f,0x72,0x74,0x6d,0x61,0x63,0x72,0x6f,0x3e,0x3c,0x2f,0x65,0x78, + 0x70,0x6f,0x72,0x74,0x6d,0x61,0x63,0x72,0x6f,0x3e,0xd,0xa,0x20,0x3c,0x63,0x6c, + 0x61,0x73,0x73,0x3e,0x46,0x6f,0x72,0x6d,0x3c,0x2f,0x63,0x6c,0x61,0x73,0x73,0x3e, + 0xd,0xa,0x20,0x3c,0x77,0x69,0x64,0x67,0x65,0x74,0x20,0x63,0x6c,0x61,0x73,0x73, + 0x3d,0x22,0x51,0x57,0x69,0x64,0x67,0x65,0x74,0x22,0x20,0x6e,0x61,0x6d,0x65,0x3d, + 0x22,0x46,0x6f,0x72,0x6d,0x22,0x20,0x3e,0xd,0xa,0x20,0x20,0x3c,0x70,0x72,0x6f, + 0x70,0x65,0x72,0x74,0x79,0x20,0x6e,0x61,0x6d,0x65,0x3d,0x22,0x6f,0x62,0x6a,0x65, + 0x63,0x74,0x4e,0x61,0x6d,0x65,0x22,0x20,0x3e,0xd,0xa,0x20,0x20,0x20,0x3c,0x73, + 0x74,0x72,0x69,0x6e,0x67,0x20,0x6e,0x6f,0x74,0x72,0x3d,0x22,0x74,0x72,0x75,0x65, + 0x22,0x20,0x3e,0x46,0x6f,0x72,0x6d,0x3c,0x2f,0x73,0x74,0x72,0x69,0x6e,0x67,0x3e, + 0xd,0xa,0x20,0x20,0x3c,0x2f,0x70,0x72,0x6f,0x70,0x65,0x72,0x74,0x79,0x3e,0xd, + 0xa,0x20,0x20,0x3c,0x70,0x72,0x6f,0x70,0x65,0x72,0x74,0x79,0x20,0x6e,0x61,0x6d, + 0x65,0x3d,0x22,0x67,0x65,0x6f,0x6d,0x65,0x74,0x72,0x79,0x22,0x20,0x3e,0xd,0xa, + 0x20,0x20,0x20,0x3c,0x72,0x65,0x63,0x74,0x3e,0xd,0xa,0x20,0x20,0x20,0x20,0x3c, + 0x78,0x3e,0x30,0x3c,0x2f,0x78,0x3e,0xd,0xa,0x20,0x20,0x20,0x20,0x3c,0x79,0x3e, + 0x30,0x3c,0x2f,0x79,0x3e,0xd,0xa,0x20,0x20,0x20,0x20,0x3c,0x77,0x69,0x64,0x74, + 0x68,0x3e,0x34,0x30,0x30,0x3c,0x2f,0x77,0x69,0x64,0x74,0x68,0x3e,0xd,0xa,0x20, + 0x20,0x20,0x20,0x3c,0x68,0x65,0x69,0x67,0x68,0x74,0x3e,0x33,0x30,0x30,0x3c,0x2f, + 0x68,0x65,0x69,0x67,0x68,0x74,0x3e,0xd,0xa,0x20,0x20,0x20,0x3c,0x2f,0x72,0x65, + 0x63,0x74,0x3e,0xd,0xa,0x20,0x20,0x3c,0x2f,0x70,0x72,0x6f,0x70,0x65,0x72,0x74, + 0x79,0x3e,0xd,0xa,0x20,0x20,0x3c,0x70,0x72,0x6f,0x70,0x65,0x72,0x74,0x79,0x20, + 0x6e,0x61,0x6d,0x65,0x3d,0x22,0x77,0x69,0x6e,0x64,0x6f,0x77,0x54,0x69,0x74,0x6c, + 0x65,0x22,0x20,0x3e,0xd,0xa,0x20,0x20,0x20,0x3c,0x73,0x74,0x72,0x69,0x6e,0x67, + 0x3e,0x46,0x6f,0x72,0x6d,0x3c,0x2f,0x73,0x74,0x72,0x69,0x6e,0x67,0x3e,0xd,0xa, + 0x20,0x20,0x3c,0x2f,0x70,0x72,0x6f,0x70,0x65,0x72,0x74,0x79,0x3e,0xd,0xa,0x20, + 0x3c,0x2f,0x77,0x69,0x64,0x67,0x65,0x74,0x3e,0xd,0xa,0x20,0x3c,0x70,0x69,0x78, + 0x6d,0x61,0x70,0x66,0x75,0x6e,0x63,0x74,0x69,0x6f,0x6e,0x3e,0x3c,0x2f,0x70,0x69, + 0x78,0x6d,0x61,0x70,0x66,0x75,0x6e,0x63,0x74,0x69,0x6f,0x6e,0x3e,0xd,0xa,0x20, + 0x3c,0x63,0x6f,0x6e,0x6e,0x65,0x63,0x74,0x69,0x6f,0x6e,0x73,0x2f,0x3e,0xd,0xa, + 0x3c,0x2f,0x75,0x69,0x3e,0xd,0xa, + +}; + +static const unsigned char qt_resource_name[] = { + // trolltech + 0x0,0x9, + 0x6,0x33,0x5c,0xb8, + 0x0,0x74, + 0x0,0x72,0x0,0x6f,0x0,0x6c,0x0,0x6c,0x0,0x74,0x0,0x65,0x0,0x63,0x0,0x68, + // designer + 0x0,0x8, + 0xc,0x9f,0xe9,0x82, + 0x0,0x64, + 0x0,0x65,0x0,0x73,0x0,0x69,0x0,0x67,0x0,0x6e,0x0,0x65,0x0,0x72, + // templates + 0x0,0x9, + 0x4,0x72,0x7f,0x43, + 0x0,0x74, + 0x0,0x65,0x0,0x6d,0x0,0x70,0x0,0x6c,0x0,0x61,0x0,0x74,0x0,0x65,0x0,0x73, + // images + 0x0,0x6, + 0x7,0x3,0x7d,0xc3, + 0x0,0x69, + 0x0,0x6d,0x0,0x61,0x0,0x67,0x0,0x65,0x0,0x73, + // designer.png + 0x0,0xc, + 0x9,0x9c,0x68,0x87, + 0x0,0x64, + 0x0,0x65,0x0,0x73,0x0,0x69,0x0,0x67,0x0,0x6e,0x0,0x65,0x0,0x72,0x0,0x2e,0x0,0x70,0x0,0x6e,0x0,0x67, + // forms + 0x0,0x5, + 0x0,0x6d,0x69,0x43, + 0x0,0x66, + 0x0,0x6f,0x0,0x72,0x0,0x6d,0x0,0x73, + // Dialog_with_Buttons_Bottom.ui + 0x0,0x1d, + 0x5,0xfa,0x5f,0xf9, + 0x0,0x44, + 0x0,0x69,0x0,0x61,0x0,0x6c,0x0,0x6f,0x0,0x67,0x0,0x5f,0x0,0x77,0x0,0x69,0x0,0x74,0x0,0x68,0x0,0x5f,0x0,0x42,0x0,0x75,0x0,0x74,0x0,0x74,0x0,0x6f, + 0x0,0x6e,0x0,0x73,0x0,0x5f,0x0,0x42,0x0,0x6f,0x0,0x74,0x0,0x74,0x0,0x6f,0x0,0x6d,0x0,0x2e,0x0,0x75,0x0,0x69, + // Dialog_with_Buttons_Right.ui + 0x0,0x1c, + 0xb,0x3b,0x86,0x39, + 0x0,0x44, + 0x0,0x69,0x0,0x61,0x0,0x6c,0x0,0x6f,0x0,0x67,0x0,0x5f,0x0,0x77,0x0,0x69,0x0,0x74,0x0,0x68,0x0,0x5f,0x0,0x42,0x0,0x75,0x0,0x74,0x0,0x74,0x0,0x6f, + 0x0,0x6e,0x0,0x73,0x0,0x5f,0x0,0x52,0x0,0x69,0x0,0x67,0x0,0x68,0x0,0x74,0x0,0x2e,0x0,0x75,0x0,0x69, + // Main_Window.ui + 0x0,0xe, + 0x4,0xbe,0x2a,0xd9, + 0x0,0x4d, + 0x0,0x61,0x0,0x69,0x0,0x6e,0x0,0x5f,0x0,0x57,0x0,0x69,0x0,0x6e,0x0,0x64,0x0,0x6f,0x0,0x77,0x0,0x2e,0x0,0x75,0x0,0x69, + // Widget.ui + 0x0,0x9, + 0xa,0xdc,0xce,0x59, + 0x0,0x57, + 0x0,0x69,0x0,0x64,0x0,0x67,0x0,0x65,0x0,0x74,0x0,0x2e,0x0,0x75,0x0,0x69, + +}; + +static const unsigned char qt_resource_struct[] = { + // : + 0x0,0x0,0x0,0x0,0x0,0x2,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1, + // :/trolltech + 0x0,0x0,0x0,0x0,0x0,0x2,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x2, + // :/trolltech/designer + 0x0,0x0,0x0,0x18,0x0,0x2,0x0,0x0,0x0,0x2,0x0,0x0,0x0,0x3, + // :/trolltech/designer/templates + 0x0,0x0,0x0,0x2e,0x0,0x2,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x6, + // :/trolltech/designer/images + 0x0,0x0,0x0,0x46,0x0,0x2,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x5, + // :/trolltech/designer/images/designer.png + 0x0,0x0,0x0,0x58,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x0, + // :/trolltech/designer/templates/forms + 0x0,0x0,0x0,0x76,0x0,0x2,0x0,0x0,0x0,0x4,0x0,0x0,0x0,0x7, + // :/trolltech/designer/templates/forms/Main_Window.ui + 0x0,0x0,0x1,0x4,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x3e,0x5, + // :/trolltech/designer/templates/forms/Dialog_with_Buttons_Bottom.ui + 0x0,0x0,0x0,0x86,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x0,0x39,0x13, + // :/trolltech/designer/templates/forms/Widget.ui + 0x0,0x0,0x1,0x26,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x40,0xd0, + // :/trolltech/designer/templates/forms/Dialog_with_Buttons_Right.ui + 0x0,0x0,0x0,0xc6,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x0,0x3b,0x89, + +}; + +int qInitResources_designer() +{ + extern bool qRegisterResourceData(int, const unsigned char *, const unsigned char *, const unsigned char *); + qRegisterResourceData(0x01, qt_resource_struct, qt_resource_name, qt_resource_data); + return 1; +} +Q_CONSTRUCTOR_FUNCTION(qInitResources_designer) +int qCleanupResources_designer() +{ + extern bool qUnregisterResourceData(int, const unsigned char *, const unsigned char *, const unsigned char *); + qUnregisterResourceData(0x01, qt_resource_struct, qt_resource_name, qt_resource_data); + return 1; +} +Q_DESTRUCTOR_FUNCTION(qCleanupResources_designer) diff --git a/src/designer/formdesigner/qtdesigner.pri b/src/designer/formdesigner/qtdesigner.pri new file mode 100644 index 0000000..f0a1d3e --- /dev/null +++ b/src/designer/formdesigner/qtdesigner.pri @@ -0,0 +1,44 @@ +###################################################################### +# Automatically generated by qmake (2.00a) ?? 20. ??? 19:33:50 2006 +###################################################################### + +DEPENDPATH += . +INCLUDEPATH += . + +# Input +HEADERS += formwindowsettings.h \ + newform.h \ + plugindialog.h \ + qdesigner_actioneditor.h \ + qdesigner_actions.h \ + qdesigner_formwindow.h \ + qdesigner_objectinspector.h \ + qdesigner_pch.h \ + qdesigner_propertyeditor.h \ + qdesigner_resourceeditor.h \ + qdesigner_settings.h \ + qdesigner_signalsloteditor.h \ + qdesigner_toolwindow.h \ + qdesigner_widgetbox.h \ + qdesigner_workbench.h \ + saveformastemplate.h +FORMS += formwindowsettings.ui \ + newform.ui \ + plugindialog.ui \ + saveformastemplate.ui +SOURCES += formwindowsettings.cpp \ + newform.cpp \ + plugindialog.cpp \ + qdesigner_actioneditor.cpp \ + qdesigner_actions.cpp \ + qdesigner_formwindow.cpp \ + qdesigner_objectinspector.cpp \ + qdesigner_propertyeditor.cpp \ + qdesigner_resourceeditor.cpp \ + qdesigner_settings.cpp \ + qdesigner_signalsloteditor.cpp \ + qdesigner_toolwindow.cpp \ + qdesigner_widgetbox.cpp \ + qdesigner_workbench.cpp \ + saveformastemplate.cpp +RESOURCES += designer.qrc diff --git a/src/designer/formdesigner/qtdesigner.pro b/src/designer/formdesigner/qtdesigner.pro new file mode 100644 index 0000000..680e3da --- /dev/null +++ b/src/designer/formdesigner/qtdesigner.pro @@ -0,0 +1,15 @@ +include ( qtdesigner.pri ) +include ( ../../ananas.pri ) + +TEMPLATE = lib +TARGET = qt4designer + +INCLUDEPATH += + +DEFINES += + +LIBS += -lQtDesignerComponents + + +DESTDIR = ../../../lib +DLLDESTDIR = ../../../bin diff --git a/src/designer/formdesigner/saveformastemplate.cpp b/src/designer/formdesigner/saveformastemplate.cpp new file mode 100644 index 0000000..3cfec23 --- /dev/null +++ b/src/designer/formdesigner/saveformastemplate.cpp @@ -0,0 +1,128 @@ +/**************************************************************************** +** +** Copyright (C) 1992-2006 Trolltech ASA. All rights reserved. +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** This file may be used under the terms of the GNU General Public +** License version 2.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of +** this file. Please review the following information to ensure GNU +** General Public Licensing requirements will be met: +** http://www.trolltech.com/products/qt/opensource.html +** +** If you are unsure which license is appropriate for your use, please +** review the following information: +** http://www.trolltech.com/products/qt/licensing.html or contact the +** sales department at sales@trolltech.com. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +****************************************************************************/ + +#include "saveformastemplate.h" +#include "qdesigner_settings.h" + +#include +#include +#include + +#include + +SaveFormAsTemplate::SaveFormAsTemplate(QDesignerFormWindowInterface *formWindow, QWidget *parent) + : QDialog(parent, Qt::Sheet), + m_formWindow(formWindow) +{ + ui.setupUi(this); + + ui.templateNameEdit->setText(formWindow->mainContainer()->objectName()); + ui.templateNameEdit->selectAll(); + + ui.templateNameEdit->setFocus(); + + QDesignerSettings settings; + QStringList paths = settings.formTemplatePaths(); + ui.categoryCombo->addItems(paths); + ui.categoryCombo->addItem(tr("Add path...")); + m_addPathIndex = ui.categoryCombo->count() - 1; + connect(ui.templateNameEdit, SIGNAL(textChanged(QString)), + this, SLOT(updateOKButton(QString))); + connect(ui.categoryCombo, SIGNAL(activated(int)), this, SLOT(checkToAddPath(int))); +} + +SaveFormAsTemplate::~SaveFormAsTemplate() +{ +} + +void SaveFormAsTemplate::on_okButton_clicked() +{ + QString templateFileName = ui.categoryCombo->currentText() + QLatin1Char('/') + ui.templateNameEdit->text(); + if (!templateFileName.endsWith(QLatin1String(".ui"))) + templateFileName.append(QLatin1String(".ui")); + QFile file(templateFileName); + + if (file.exists()) { + if (QMessageBox::information(m_formWindow, tr("Template Exists"), + tr("A template with the name %1 already exits\n" + "Do you want overwrite the template?").arg(ui.templateNameEdit->text()), + tr("Overwrite Template"), tr("Cancel"), QString(), 1, 1) == 1) { + return; + } + } + + while (!file.open(QFile::WriteOnly)) { + if (QMessageBox::information(m_formWindow, tr("Open Error"), + tr("There was an error opening template %1 for writing. Reason: %2").arg(ui.templateNameEdit->text()).arg(file.errorString()), + tr("Try again"), tr("Cancel"), QString(), 0, 1) == 1) { + return; + } + } + + QByteArray ba = m_formWindow->contents().toUtf8(); + while (file.write(ba) != ba.size()) { + if (QMessageBox::information(m_formWindow, tr("Write Error"), + tr("There was an error writing the template %1 to disk. Reason: %2").arg(ui.templateNameEdit->text()).arg(file.errorString()), + tr("Try again"), tr("Cancel"), QString(), 0, 1) == 1) { + file.close(); + file.remove(); + return; + } + file.reset(); + } + // update the list of places too... + QStringList sl; + for (int i = 0; i < m_addPathIndex; ++i) + sl << ui.categoryCombo->itemText(i); + + QDesignerSettings().setFormTemplatePaths(sl); + + accept(); +} + +void SaveFormAsTemplate::on_cancelButton_clicked() +{ + reject(); +} + +void SaveFormAsTemplate::updateOKButton(const QString &str) +{ + ui.okButton->setEnabled(!str.isEmpty()); +} + +void SaveFormAsTemplate::checkToAddPath(int itemIndex) +{ + if (itemIndex != m_addPathIndex) + return; + + QString dir = QFileDialog::getExistingDirectory(this, + tr("Pick a directory to save templates in")); + if (dir.isEmpty()) { + ui.categoryCombo->setCurrentIndex(0); + return; + } + + ui.categoryCombo->insertItem(m_addPathIndex, dir); + ui.categoryCombo->setCurrentIndex(m_addPathIndex); + ++m_addPathIndex; +} diff --git a/src/designer/formdesigner/saveformastemplate.h b/src/designer/formdesigner/saveformastemplate.h new file mode 100644 index 0000000..45d0b57 --- /dev/null +++ b/src/designer/formdesigner/saveformastemplate.h @@ -0,0 +1,50 @@ +/**************************************************************************** +** +** Copyright (C) 1992-2006 Trolltech ASA. All rights reserved. +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** This file may be used under the terms of the GNU General Public +** License version 2.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of +** this file. Please review the following information to ensure GNU +** General Public Licensing requirements will be met: +** http://www.trolltech.com/products/qt/opensource.html +** +** If you are unsure which license is appropriate for your use, please +** review the following information: +** http://www.trolltech.com/products/qt/licensing.html or contact the +** sales department at sales@trolltech.com. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +****************************************************************************/ + +#ifndef SAVEFORMASTEMPLATE_H +#define SAVEFORMASTEMPLATE_H + +#include "ui_saveformastemplate.h" + +class QDesignerFormWindowInterface; + +class SaveFormAsTemplate: public QDialog +{ + Q_OBJECT +public: + SaveFormAsTemplate(QDesignerFormWindowInterface *formWindow, QWidget *parent = 0); + virtual ~SaveFormAsTemplate(); + +private slots: + void on_okButton_clicked(); + void on_cancelButton_clicked(); + void updateOKButton(const QString &str); + void checkToAddPath(int itemIndex); + +private: + Ui::SaveFormAsTemplate ui; + QDesignerFormWindowInterface *m_formWindow; + int m_addPathIndex; +}; + +#endif // SAVEFORMASTEMPLATE_H diff --git a/src/designer/formdesigner/saveformastemplate.ui b/src/designer/formdesigner/saveformastemplate.ui new file mode 100644 index 0000000..5b30435 --- /dev/null +++ b/src/designer/formdesigner/saveformastemplate.ui @@ -0,0 +1,248 @@ + + + ********************************************************************* +** +** Copyright (C) 1992-2006 Trolltech ASA. All rights reserved. +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** This file may be used under the terms of the GNU General Public +** License version 2.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of +** this file. Please review the following information to ensure GNU +** General Public Licensing requirements will be met: +** http://www.trolltech.com/products/qt/opensource.html +** +** If you are unsure which license is appropriate for your use, please +** review the following information: +** http://www.trolltech.com/products/qt/licensing.html or contact the +** sales department at sales@trolltech.com. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +********************************************************************* + + SaveFormAsTemplate + + + + 0 + 0 + 391 + 149 + + + + Save Form As Template... + + + + 9 + + + 6 + + + + + 1 + + + 6 + + + + + + 67 + 1 + 285 + 22 + + + + + + + QLineEdit::Normal + + + + + + + + 67 + 29 + 285 + 26 + + + + + + + + + 1 + 29 + 60 + 26 + + + + QFrame::NoFrame + + + QFrame::Plain + + + &Category: + + + Qt::AutoText + + + categoryCombo + + + + + + + + 1 + 1 + 60 + 22 + + + + QFrame::NoFrame + + + QFrame::Plain + + + &Name: + + + Qt::AutoText + + + templateNameEdit + + + + + + + + + + 9 + 71 + 373 + 20 + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + 9 + 97 + 373 + 3 + + + + QFrame::HLine + + + QFrame::Sunken + + + + + + + 1 + + + 6 + + + + + + 1 + 1 + 197 + 32 + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 204 + 1 + 81 + 32 + + + + OK + + + true + + + + + + + + 291 + 1 + 81 + 32 + + + + Cancel + + + + + + + + + + + diff --git a/src/designer/formdesigner/templates/forms/Dialog_with_Buttons_Bottom.ui b/src/designer/formdesigner/templates/forms/Dialog_with_Buttons_Bottom.ui new file mode 100644 index 0000000..d7e4572 --- /dev/null +++ b/src/designer/formdesigner/templates/forms/Dialog_with_Buttons_Bottom.ui @@ -0,0 +1,100 @@ + + + + + Dialog + + + + 0 + 0 + 400 + 300 + + + + Dialog + + + + + 20 + 250 + 351 + 33 + + + + + 0 + + + 6 + + + + + Qt::Horizontal + + + + 131 + 31 + + + + + + + + OK + + + + + + + Cancel + + + + + + + + + + + okButton + clicked() + Dialog + accept() + + + 278 + 253 + + + 96 + 254 + + + + + cancelButton + clicked() + Dialog + reject() + + + 369 + 253 + + + 179 + 282 + + + + + diff --git a/src/designer/formdesigner/templates/forms/Dialog_with_Buttons_Right.ui b/src/designer/formdesigner/templates/forms/Dialog_with_Buttons_Right.ui new file mode 100644 index 0000000..00e2ca7 --- /dev/null +++ b/src/designer/formdesigner/templates/forms/Dialog_with_Buttons_Right.ui @@ -0,0 +1,100 @@ + + + + + Dialog + + + + 0 + 0 + 400 + 300 + + + + Dialog + + + + + 300 + 20 + 77 + 106 + + + + + 0 + + + 6 + + + + + OK + + + + + + + Cancel + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + + okButton + clicked() + Dialog + accept() + + + 351 + 38 + + + 233 + 29 + + + + + cancelButton + clicked() + Dialog + reject() + + + 330 + 66 + + + 197 + 125 + + + + + diff --git a/src/designer/formdesigner/templates/forms/Main_Window.ui b/src/designer/formdesigner/templates/forms/Main_Window.ui new file mode 100644 index 0000000..8b85924 --- /dev/null +++ b/src/designer/formdesigner/templates/forms/Main_Window.ui @@ -0,0 +1,27 @@ + + + + + MainWindow + + + MainWindow + + + + 0 + 0 + 800 + 600 + + + + MainWindow + + + + + + + + diff --git a/src/designer/formdesigner/templates/forms/Widget.ui b/src/designer/formdesigner/templates/forms/Widget.ui new file mode 100644 index 0000000..c8f4991 --- /dev/null +++ b/src/designer/formdesigner/templates/forms/Widget.ui @@ -0,0 +1,24 @@ + + + + + Form + + + Form + + + + 0 + 0 + 400 + 300 + + + + Form + + + + + diff --git a/src/designer/images/a-system.png b/src/designer/images/a-system.png new file mode 100644 index 0000000000000000000000000000000000000000..6638dfffd429826b0f6b152a1255762a855bc285 GIT binary patch literal 1283 zcmV+e1^oJnP)ff z?ml$jF!N^az2|$*`JNw7_vD$s4}OTmU{jdp5sSmLI$*GH8n&7m=Q`Z+FY`mDA1* zE)~V-hdloha5E&YgW6RHmT%lxY#%=S<9bm%3*dnY*Z>{^E2=2aGPCZ5aOq9&Uwbfd zwOJqDc`(6CqBs@569Da@v-)q~+gX~&eib+dS+U_BA`7Mf}=*d2&@bA zMHm{00E|Q!g&+oCoHzy`xSiT<9YhN_C<0LK6JczpdRr%E;+E1UqNuhKYD9eA)m`7z z<6}2*M&;h*XX#a0k031mQP|o5JQE&FT^~!an`f+w*2%;J#j<5fNK!Q_PtuiYlYCjN zF;#9C6VLRjfOTML5@UB&l}^$LW2cFl6i{o`5qqM%0Gyj=8VUwr*#P{e$|BGfnYz9U z?5mlYCux_s-vPy3A&3WVOdj*q#L5a-1on&2n}i6lZ159>5mTN{NOO50^#ma2ynn}d z*?l9+-hV2~cwB_8mF=1}c`}E_Y;e1t3H8xeS;A_0T7*NuV`iE@x<}X=ifmRTY*Zea z51c-q$TAj;S;K^o2?wN>?y?;KN!>lPbQ=O;lhs?UMcWkD_ieqUXPD(kw^OVKz@Mu8 z0}QQ0h8Yp6uOAqQC0MQ%)M8d5qI&2fyZ+XesX;uDD@ma~o>zh@2qA7lJ|GMH3u tjw}qdxxPvOAx zqN;!wR$PWc6eY^@RHdfO1y4g!p4UvkufknaadUJOq1B^8^O~g4{p?B=9W$F(uFhxC z=N}y8&+hH*XN_Gl74v|82{qx*!TS`>8$EY;7PZCKfK`1 zgGUe=%%6a}&&vNsF{$tSrF*Kl2~C2N(?bXi!~(-$;g_i=Eg)B?CU>`D70ItRAcm*g zZ{dCejRrv9(%653zL~!#*U^91fS`1tM^hXVmC76go#(t7Lp z7Io_EzT92Xyqf0K`woZgE?2`VwAQJX7))po5v;X1aad!KP-q{u`O)dBh2Y~apV4cZ zNGxbTgcK^NcM(Z7jLzNP9eU@z*(!?BI_mSf^%WNyoYvH9;KV@;HWY{@U0(|}vJ+{n3%9E(dU z9w+Jd`&?d{Y|y91Z5)puHj?#?^(?hUBcv{g(~}bifDJ8XXz2BV4E!G!><)u0@GG1E O0000{afxdM)&v!eB~v{!_-V-=?2yS*?}#>_eCNPVTaReP`FG_hsJqAR#rYdhG4S74Dq zr3)C$3~t#vt?{t)cr**V?``V$gzCNJ5bEP+2bqfL$)MMNoQAe)AA_I7|D7Pmz#njj VS_X+9W-I^z002ovPDHLkV1oRIcS8UG literal 0 HcmV?d00001 diff --git a/src/designer/images/arrow_down.png b/src/designer/images/arrow_down.png new file mode 100644 index 0000000000000000000000000000000000000000..3269deca1310ebc8ef07009eae35f786c367e029 GIT binary patch literal 595 zcmV-Z0<8UsP)wKswybMAHqDkuLI$Xqp&U4v;LQslq!6PSYDhF1ZV(pb#KjmwBRV345MsuU zF$Pq#@?bovmvZqh`}looYv#r?o|x#tCa+`PebRoPrwRb&Z&3b^FkK}A2|FZ4RM{|U z-=AaOesiO=9tF0+Uk)3^RyMlU#UTyy+dE6(6-@IP@&I z?5B!r!6_OT9*x1Wg6ONWqOHd5SA5LY@ZnfTWgoNC93eo@&8uL)`^{bHHxE|L0Oj zx{z-3=SRkR>BTp0c;hPbT-qOoVk9pkFKn-yt;_WMLY*iRT1Yv#C(CjST$I#Ma`<=Dgt zjvZeom-|GyQi#ZLQ5O?c7&J7$c5d;Eg^cXU3d<{tSh)RoJzWD)xh)z0*%fA%FBK~f z9#4Oyys?Joz*h(tTkHIU15d5nZEE)Q#-kU{3};nBEkGhB;<@mCEJ(f8cSR1k{b3f* zb9Qa`QkCcwmLRtM>a}oQ^_`}|W>%K80!+SthnyH4xeQ(cetd(%DwsBFTw9B4kwgGg z{yHndfct>yQ>U?e53xH_7&OIG;2@APv&P@NnFW&az^%7$z&S<-2BOD#G;2;J(0lI(#Kt~L1;nee^F|m!YSreZE4u|s~*@~y_{7fbJfETuB83@d* b(v0&PpYt?NkNL`h00000NkvXXu0mjfQk66( literal 0 HcmV?d00001 diff --git a/src/designer/images/arrow_right.png b/src/designer/images/arrow_right.png new file mode 100644 index 0000000000000000000000000000000000000000..37f489c8f4419e7876694952e57c0f2fa71b7f43 GIT binary patch literal 667 zcmV;M0%ZM(P)2|m@NUzWz9iM5ix#Ao{l{QQ z$0cPY4NG#8)b;~2`zrz2OILQ-hK(3-66gTbD*j)rI5Ti?3xj7xs)HxM0U*^XbGNG8 zJCdxK0760kUO0MAq`P$k;IRl{plE012D}xq!-Ik>Zc{IEfGMjO;z* zSDC}W8{oIaVBzYMDwR3%g{c@2oT6QVz=536zZ-^5i`*l7U8`{s7?)IsCp>m8DmfH{ z4pJUge|L}qx;o*=F>(2-$ZX;va4K#~0vsq(=wU&8cM!00KqzC+J~(k+bfy^xHWP&; ztqA-jIWNWJd_~UNA_wI%^!5UgyWJkK6gJB^^xg(q0W5p&VxE^uFgFV?Cyj*#9s~14 zcb?4Hc`ND}d(biz|6D3TArH?djG1Y2z-?d=s5Q4jMks59Dw*l`JiM5InQ5K@w}8(+ z<7!jzx35!t`qA_+o-0xeny5-wT@{Ru6i7SYN!5wr*l zTD6dZ2%=57kQQw+p%zg&_%Tk7&d1wg?j7$8GowKsI2^c~_jjK6Iq!Xs%#7U_j$Il% z220v2spG$bC0$6gc&mw4w<2juQkNvJX^@#UoxtVJWZcGYAGfMXGX?)={_QI`EP9G zmvMp8P_bNDksKKC@|p4eb+z(ZZ*E>3j?upF6X_+0C&~(=Q0G9D*TtWZ&BDn(v6-{c zkMH;l+?Q0WReTTLw-94vf+hj%LR)4(LK2yE0Ueg(V*+JJOdXAi&9 zvt_WVp-xp7)DQdsR)8X4wO|ACKo-iEEf2nF9)DRt>hYFGZjz2~URa ztS(dzye-K&AZKQq;RnBIBMDShz`+{&?JFqgI>XTbYPkmq)D8rToCMB~-yX$pSNR-ipt>t$B})`2x(J=!apffZQn phgR3wRtl=902D0(({4Sce*s;94;xbBBN6}r002ovPDHLkV1fg>HvIqq literal 0 HcmV?d00001 diff --git a/src/designer/images/cat.png b/src/designer/images/cat.png new file mode 100644 index 0000000000000000000000000000000000000000..3c1ae0f5f5bd21107cd4b0840936a705bbbc1f91 GIT binary patch literal 401 zcmV;C0dD?@P)CjQBW(3gGkIg?Y}rt@iyu{tV7@W`;p} z_ZVZwg-5|_qoWBeoP-W9Y?Ps@f9zg~+1Nb<$ud>bl15w#+%_*xNxU z;S6?7Ipk0P5*TB?J-{>T7}NtZ v#*WB(5rYEG*DX!S%Lf>Pdf@+#)Bbr6u%@REt8=nw00000NkvXXu0mjfRRy-l literal 0 HcmV?d00001 diff --git a/src/designer/images/cat_g.png b/src/designer/images/cat_g.png new file mode 100644 index 0000000000000000000000000000000000000000..9e6bc8ea8cbe58ef6d7c91a7ae286084fe8ad5a9 GIT binary patch literal 697 zcmV;q0!ICbP)QbaO!mz6&u=szgc zg%}8JSAwYc2MQHe+NFYE2$WX3P#UNsxJU+-WMLr-q3xnL7cyiHG%zlvlgT8L`b7_1 zE@!y&ocFxyO2vm1xzro5p{Gi$yDFHl4&b%d&!D_(briqCYJd z!Hu-dOIK82b=4VLI~eA6oTr)qy{l=-3Or83*rlsc6J@dA^7|Z#O3zVOSn9TLII#ID0Ej)=i~Kq z4Aok7T=DQdH%$V=FhE=ypPF!Kj<>Hi@$o@Giv|H#+(f=`cL5WVl?N+HE3(-qN#z;E z!`C)1stpc~4p2%#U!V`J=OQ9#t?|W2yBhI?>PD51b|XH=rb!S4k7Cb^$85gaLd_JB zzMudRLa2nki%4k0$=vv6)7on#t*|U>Y(v&J+B{u{fb5SWY8U<*H?Z6N7&R&NPyY~3zMaLwH>1i`q zURtL8wTUtn{)y*u;<5Ol;;2Zw-DZE^9WYYgV}Kji=YrWQvxCwKg%Em4Kb(B=0nnbt fJ#uNaIs@=8gNQgJv}Px200000NkvXXu0mjfz-l^6 literal 0 HcmV?d00001 diff --git a/src/designer/images/columns.png b/src/designer/images/columns.png new file mode 100644 index 0000000000000000000000000000000000000000..52d6fda2ebbb3c4f9b9e9449eb3290a4ad55594b GIT binary patch literal 208 zcmeAS@N?(olHy`uVBq!ia0vp^Vj#@H1|*Mc$*~4foCO|{#S9GGLLkg|>2BR0pkR}y zi(^Q|oa8;l&-s{j8H9a(WGAt0HUNSvSFZe7KCMw#SGT92SyDnm!p6oXK;+Ghjm)k* zbNjt{c?|CDEN!%H^y7-|&O*b-8IJZPylf0Jw0kbAUp7$zx`x5i)z4*}Q$iB}gz!Xp literal 0 HcmV?d00001 diff --git a/src/designer/images/d_editdelete.png b/src/designer/images/d_editdelete.png new file mode 100644 index 0000000000000000000000000000000000000000..7fc2c40d4321bf88e8baf0e39df22eca73248086 GIT binary patch literal 1297 zcmV+s1@8KZP)r;W8O9MCg*Fy-Jl5Gz^^iXa}h zE{iaTE;P_ma3OB|0Dg?Fy3)mb3s(gdwSp2-hskiP*GY4Eley%*oy9RZt?dKv?#Yk$ z^84o@N-6BG_4V~yqtPh3-R?16*F~P^tkdZT98v9dTX!6Xce~wV zqy#^C@T)F-8Goold9t1!_8uGr4>Bu6X+NsqT5+A|WK3 znwrXN+b*=Sv4pO!u7WY9U%!4G&1N$&P4g6hIoEaTWv}bHb;ofgYin!Zoa;Ak+(4_< z>M5oEm`o;fK@gZkDODYRb#)b#Qlx2$JkP-x!`9XoeBZys7~8chivoac+oQF$HDpi+rJ(CNu3o*0X0!Q5*Y(qk zvENE4r4&&Vfl`XeWP&tJapue!*=n_3*J`y{qLf0r-9F|x4!w5m+Mx$hN%$iosxj!C-)oA3v@LAw1*f_rmkMMF71kSFS+Ubr3=-xTa~idGjXb z=jV~8=^k-J3ky7oqI73x=K_FtmoHyF1RoBE5JEr*fzfDG zLHG9dFc=IF1i>RA#22O1S0O}N>DF$yO#pMXTJ2P`*?d#Nk1EbNk|aSGh6uwDK@dFR zocE=a0b^_zKvL<}>2wOqvM6J0*YmvP7cX95c6JtqVL&N$U7(*C_==b}Ng%F=P z=l#;0PN(y~#{jUoxjD8hi|V@m0|4gd=V6-WA+V-tn3~ zx3`BZ%PP2G7|=BBfQmv0ynXw&3P!o>1CQr8&gB06`;|gjmVq%=!DnV>Fg-neBz${& zyGkg4B#5F20I;;Q1jG1Ge?mxg??qAI!-o&p+1a^J6veJlMtWss zMMP1g$8iiwX|>ZhjuFQ(`u+Z6DP;;^V`*s#x~@Yh1wsfo=NJx$XfzrUz&p?L77YM+ z|Ni|f0J^-qT&a}jIg%tn9LJ^npM?W4nZkJ7=~K6+r32y zsaKKqeg97Y-BzoG;c!?*x0IiA-Y+%uJZ~Am>sG6U(P)G$%gUfUlv0ieA;tbkQ{VUh z0`Tg@i4!u8W3AWgJrF{Ckx~Xih~0X`A$CXm1l#)p)Q_HfbZQBJo zYM72jBU4JL7e&GL56E9@eSN(aMUi2eW=+#HF+Dw9l)e7~tgULJG_&CL00000NkvXX Hu0mjf-a25y literal 0 HcmV?d00001 diff --git a/src/designer/images/designer-splash-en.png b/src/designer/images/designer-splash-en.png new file mode 100644 index 0000000000000000000000000000000000000000..0bd473944a09f65102241a66e540ec0d4c8292bb GIT binary patch literal 94291 zcmX_n2Q-^u8+Pnbn-Y6gX|)ooL8!fIw`Nhqs6B&NwfCx7L~5@ZwMPkxShcFCy`_o< zsj4dd^MBv}{Yl>Qp1jF9dEVz<*LB@@5)Jh=X{kA=0RRB4ww9VP06>&MIK(K430Lgr zeRBvWDsL?dKLFqs^Zz}F00l@O06?whqN-|W_|nVY%kQO^H=nkuDxbHnmy?UTBLEPz zT=X>1JnMp0apS^~-c;r5NmHJCBtSs0j&hX2qLd*MU>C!{q%<6xKyAu$n-QsHG88pW ztyPq;T`bb+teli!nQUSO`N6wd)fN_vJ3hWzyz0Rsv45u!)ASLHOv11COI-o7#<5Vj zue|97T0>*K5yZE(Hc9yy_9s3%lMMp^CnSiVaR2v@{}MHN0f+(K^AClXMz;P%cN+?u z0r*}6HU*flw}>)~0izF}jj{knfq?fDa3BF85K>jN6ph^r! zq1;^5w{9KZu`lTb?IbJylic#!Ob-7=`1EEa_ypinpp;+VUlx7sW9J#rV4Q}XAXNc- zUSI`pMq*!Gr-{yPOEp=E-A+0+PwX@l&>KN?8NXKJAIsThI(Q{<%A0#ll@&+}sEae` z*Ken2n{e+B|3O5YOlST%0H73(e~`j)>otJESxN$N0RUw6U8XDDCjw07mG1xmJ>P&< z)!A&i7)k&@tvK@Ddu0lm0hYRcI^+O%Pd^*69l4qkjZi<7L4|xbf{VHYn5)eGtY7Xc zY1?}ej$+1wEr!+sFoYJn$z&CI=*>oM3q*Yc_QX+zb=p-#HR&W$LCh zql%6Jf4nP@Rc+9ECz$DSD9B!}DZ^Z&PWT5u4?pUT&0RX?7g<_DbYq#j`qcb)G9`8)38bn zlNQ6B8mcd>@8)Z`O+M7fG)x%>8mAjh8@(t)zqpS21EXz@i`6KO(<*xg>%g$5^0Q(j z98b+v7JN-f4#nKw=-EGSzC6+mAiLrW5D(FPs_IwkROj^Csc7G4l86q|w0R=Cgw&bh zpQ4=#c|h{u@q?xX*LtV=@cKu~!OQ4n`(xi@*5kuv9NfD|sYtBoT+T!80#4N}({0op z+r0vx{;oI&J475%osXZ>9jwi2o_qW(J7@cjTfoioJ_1Qm%4D#+gCVe!PZ_XpZf{&V zXHR0bsu?FIjoZ`lRT2UoEthpmaCV0 zQTN7F(G+2NZn{{fyPywg>^W?&O+vn3xQB`5pM|=iW+$O-r!se=%$Djo%j9LJBjIInl-|U?Tv6WL) zaQriMK%$6IBz_zGHXdDx7T8cg3x+R*=Z91LMP14NnYd2>-M57}V?EU;vn3iJ+9T?X z&Eqj+0|hKkmL*Eh?npY4qE5+=FoELJdkdz`Z9wk78u z&?jMCo(0CVxM|7_hH$USOWlJ{?UV_dn(hgmye{ndY?omyqW2_fAAUD#ed_Pye<8L| zw`+0b+?#fqUX#)#zv9~N8{k~$>Tc`~J1Xpq=&bFG42u7)ewxSR&n!fBoVYvmbx0v` z$B!86ULc9wEqIpe4{O+4E$w34KbV?81wt*PEiytOv2U32njh~)^Qjn$0}b}7JoUJl z&teK=4b;)4sij6u9i2MR%>5$MoL`VN`7qT#FXId};223N1LOOM*X)^Hf_ObswT1P% z=_Q|~2eR47Y-E`+txIm}{Y6lRNQZ&b{rg$8yNG>{an7vx@rzx-OF#U|ZTDE+*|JvS z217blUGeJsLC=BDgF3Z(wJg6#ZaCe1zZAR`#Twe1@!qiWeaqL*AdAyYfj;#Qtb)l; z*#aMet&O`Kf?Q5MhfTbkXwJPh+%`8hIdesFHsRUu)3OV8 z+b+k!1m~JJ|J?M|J+_<|b>4N=4Zq)Obnb7P>A#o{Jx6#fFR$x#j2|Cr9hM(@)?HZi zHR|-bD$mcvozT{Eo~G_`zVOgl_b&-{Jx`l#ogAMek+zdQe*USwZsn{*rtDX6(JSi- z)9d z(}NcDI6A6$)J^ukx%jQmnx8c11vLay(~Ed{IcYh1&m5+*wyK(|n5W0XP5&Vd{oY|W zuD7qAOq>7xdUESBdAhFwQG@rzy{l=I8xb7g?U_O-oL2s=pIQmSb>g}=MtXVkMgA(? z7~*IDz(%TO3@#M0p*MfUFJkalcRs(BB%n=FXJtKQ0H7%?^vWoU@SYE*WvmAP1m6Jw zBBB9+%YTIP0RR980RZ1^0RXu-005g;=8Its0Fk4&wwm&@pyi`$m-mhq0X%W_3dl=j z$dBLa6D9ZF)qa?v^?$^%M#~@+Nlr>ds!hh8t;QITAjK`T2fCBo4&35J>e5qNQpc+B zN75|k>Z+9M83~iF6cfoLMDlfWJT;gHaG1DOvu`wkgYZZLBJk{B>M7vA%s&?Jq4han z)^}UT5Qnzm>qN0!QQFnR2RF-wU{bH?q9VWxaBfCM z#vhS>Y4VIwK2wF2k{VAA5Il3suBj%JKzz1q3OL0=;CqN;3V-H;B`gIexoWdWi^e^7 z^A4+T!y?c)PFSnVlDgQjCtnJVDTR`eH0%h@pKj>UpD>{qW`$!*#>=(&0lK%PCtFoN#J09 z+|>{#LtM#1ZA0OhL#9xZpPE{{YDqTTpf`}5>%h_tTZg^01Il4fT(_SMEu~d}Fwpiz zSV-^viKHl|EzpD!IBCifJ%NG;x-U(1buv7S+2F`KcZz0U;MjID!>$}{pE9sN{%=?AUWxYd7a1^)WF}`*<%oxW&H7;j_jMHQ9LxgsknCe_!pm} zV1;{uu-+URS6DgVv8g_EyRI#z2}Bdk_bp`YA{BS#!J}4{N<_6jtq2q2e}AOeVnd6`M=15D_FeAsgKw28b#*B_!?Qrb#g{#;$~O6m2Qi?!&=I|qK~Z4;glHkohpa7($Z!q+BT zD)f5lw7UU$KgZa5QS)`K@z3iS_yZU;4Tk;REEdgo0$qc1yW4sQlF|AV7|Ew* zWNxBrVv=$yk_1ivgU?52*g1^zueq#OGf@DAAmUju2l z6p#~nbQG3CHjAI?i09p^hntuXGN=MfcOwvm)m{RY4TAjj7vQfT*+KPoIh9-1i#zgK z1|LD2Rw5=8k*83X`uf^hm*r9sZ#lBa#_Z+=b))h&CKYn!ldm@E$L9^LdEo8!-nHOf z)MTe0e8py>^xFz+-eVRk} zD<09H{2IheR(NV_$MI0g@5ccXT_<5)z&J=+R?Iv+%*ThQLr)EX;)E4c>SYe$gXW|P z^&-t4(3C;n`dc?j-y-fiOz>N4AMa8=wC~%vtDPy7=ofDXtgYQfjx<5JTRc2n9v^JHPCx%fr^laP^QFPuq6s^{=DB#-=J#;A3XM~L zohDFE2z3{axRQ%&+b-QJwD^RawiadD`<@0j{vfUqwKl&t@Ukph9CtGf|Iq*U!TNv? zhX>iEFCkn3I=78QtG?K#v;=gb6|HP|>TaX3qIZ@}<4f>iMkdGM8=@7VeLt>vwqE4M zPQ@-Rn#B+Dr?ug(tgAj6wt6(J96PsIY?#5X8A6`c2Bwh>sJYF-mw|`KJI#7!vBljD z^zky3#IRtj+-`4zmvc+L@!8+MpDhcqmjNph7^uN7g~wdaEWSg2wVA3=iq^O3yLt6C zG&GFc0hinLGSzgJ+K;zDM*;Ez1-il*plwnLSiqHI5k9%MX9tV}(J;0$%VIkh+QsCd zzCa27A<&!ldWN6AKjz_sUA&~1Tg5Vk*Pdo@YhHCEcM6iAjm#gP06sa^;AqcZ%U)%s##g zi%?P}Qt+MHfyiL|tpn9qmn&Vm8$wzWlI=YhNW(TdJXS8QLlqxk++_+64-eZt%0yHU zFWW4&MJJkD7k*rXV7|J`sOGaPxv#VXp5_=Ev8Wpj$-Zb@bhOwe`Az2?*~CICLi(PN zJs~o@D~Cp8zT;uOGDIlI%%4Jn*-6^4LQar ztfK`hX(WTdG`_omaoumKYEBf}S<7I)w;Ct>lu`^S~yL^E_+ z7HeX{O-BLK0N&NBt4!s>v zSi5=2o#ESdK_@#*H`g(1OwBFzjC3l7k8-?OEu1HA%c z)z%7UQDOgjLpED!q5w|@fD_GPG=q>dANz~2zLn$J+Jb2;0!2Sas2fFo1Z&i*C~#^r z{8HMuFsDU+3L=#5yorkJv+v()J)Za6hd{4)2x#HI;L=Da$Mp*BoD#Yb=$T<+(&ph@ zkMGfPo4+7|5q<0vn@B4CdK`elmUt#b6Edcz5lb9@8Xd;mh{e%D!|00?Z8+=x&`Jc; znS;dAalpzkt1wlRt>W9kLf87jO666N7|KD0S(imPB%wSTz!JKlnUb2oA_I&giU(l1 z{-#Okosw^gY6xptFIL~#`8ohjo;&h}K(MUIvAC-U9>WW=zDkeh<=5P`d86zNCvb@uf1 zbap0`ick_mcl_nZ1{u7M{(JA!Ht1<2XAHvvH3nLLshWOxRpJ+gU+yXqDOmF)B#VVV z+uOtjY0ug{RvHe^pf4Wgg>4A3daNv5T!S0eJv$(}Gb0g;QQ%($cMZAtL8c7K*9A=J zRn2ub1b!f-2PN-LtA{?qM;9T`+pb*2NC@`*5A&Z=dhvFI9W{R;a4(7Y;Lnyfko)mX zQpOd*wz~bYRHi6DI--B>GKbwi2BIk_+hqw(mL91Ph3F@(eiMUuZXG=l ztySok=BO4$iA#f(S zVujOK>%~-FxRBTz4;ZT6tWrfwG_S9pl*?maO zyX`o@t-eUV%3~$YF38t6inITI+78|C`vPQQY@w0$L@F3$ z%d#W(g`Xw(jPqyw=x(UJ$EB!3xf$@Di`558ZX}=_XP}0^(w^6VYyC{8xHmL^$pV)RldMenWq2iu8TGW zU`jJ@*c;NG#rC4MA>c?=me7EohEa@s+>ZMSs|^FYIEv^AsPy_6Z`8FB9Oix}d_z4El6J!JgG3ALth3e9T2xT_UVa979i&W(OQ^{$i<0MVjL@^a+6~ zTfG`$Ht5IjjS^xO_UU+~V+2+rHnHXz@4#cBK)1z+Q&N!EW&%zFqdTY#3ES8CcGy1h zBQ1)X+a~DJJBc`ttcpB_n`PN3^5Z|BeZCl!eidv(6!hi41*oxiyRs&3!16HrGsawd zs7_kP1y&qk_ulyB8)6^28VO)`rx6z!AyzUpVwsE{GM3oV7;6+%`fv#jj${cYaLc+R z^xLg99G>WJ0+c%*>8hxim|UXYVrBain$o3cR6*Mq-hnGp2}*nSRiQukW|D}$FeH#f z#2xqtL%3>db>>)ZXF;b4Hek9Dn>aZwrFb>lPou!mD!tqb=m zayU}#(7Z7vD*bUe>N7z{n)CpQZS9Q4D3)6j14YsFpQUIsdI&$Q!ndt%!BTEBjR#Cc zevQKzaf!o{l56j+gIMH^1jrr(c{OtEp3$k)Nb5ai@r>r{r@%ZC(`EuGdk3lf5Y%R} zB6=LfMMP#93NYo04aty)a>P?8Zz2dOd5}Gs-o4{F=-bR^qENe4PQMXBz>#GMHOr z%z6Ljvm_r%*km%e__{LR`7{srpO~BWPg^EANwYGNEecXt=PV9+oOm#ZOCp0W9RZirGi5smsU8mpz z8{O@<1An5FdRC5SJODrGyvEEGmCm2(P(2*Gyp-)Z^6he8`Q;69upkcxQ%j9vw?1l$ zD2qzJohG6!mF7~GN6OKqwzNoU`E9NaQkOEryR6c5^Tj429EwvsN(uF0nPR=CwzgS}WFdmSm@al9UL+~PljmIre>q2_>8Ae7 zqpSas6u-fMcPs6;w@0(IGP9d7z~_te=jQ>vHg1!6C zN`;Yj2-M0l5aYwO(di>NAu;ocKo8Pyt87c@DL*0klkgMH(xi!JG``sLP3)$DI03l; zEvX7wI-)(VRT4NKc}Bb=FQv_;DzYG;{En6LFy1(R8$M(!#O{RH#3Xj%Y3mzeK~ic^ z!9M~5sV2HZFG@nkE_!Ey`uOO*$T9?r?^^hCc4n-DAQT`Jd2tD!9f>L6GdN$jSxohB zN+6{*4r1n0K){m!k)KR*DLOYrblMiwP&C9Fz?4Z_WkUmD1kfoXPO0y9H}j?r0Tp%; zoo_C=o0`n;?NxxucNsx?0A|2nd7ZY;0Uw6@wkyW)TqZe95MsXf9xL79BJ#;>Wa|pr zOuLtz9EuU$2ce1-h&(@nURTiP1L1o^(V7^p-@HFWqZ2?~^MLk#2o+0(dbzNpfYuhPGK&xCHz7_=Jbk9g%oc7t5>O zvy~~_!bIF`{{mFg$_3 zo%qtc^S^!4P${ew{XPJ@SQw?|j3b(mJB!mKUoInMXHiQo1#}cU+LEgL}l1IW_+BEjmt=Fc}Xk^%J7S8=q z3whU2QJ#y=eCV}Uye-e-5G{<`=#u>TqiH_?E5OYNk4aDGK29iA-cq+sS?S*<2r5Y4 z0chs0N*5(hOwO!noFuO{MFUAN-8zhPHzHLNYAFUN2zQ{qK9?>92wJWlXmn}I- z?HJ5A0`>6krK$2|)7X&u=E5}GMB52veA9S>3k8tFXcVa5C{Y2=W@kBqp2fVPR5OxS zf-{?>T!zwpVXm*r8ry{wO!CIgw68o6nj=8Da02BHkbf3>3Z9as6sAl!x~p;Lb}ZIs zhBBN@F`|X8V-olQjcz#PaC8#!V4giVI2fJdbmIbXhI5CDJ8bb)JESNxMZyrFTZW<| zLb~ zCY$mzgG?Ds;(KOwQZWWnISk-81fFXbsgyLR97(?^50X*w7sBu@rcGKbE-r#VJT!U3 zmk|YY=FZ=ElxT@pWqN2w{fs_vhtwJFMHhC7$3jl@cGX81L8AQs2G1JZV_1VFOC~UiuU7EyRhfHn39wfADx#!mW9;Ek+>H zgtD2pe4m5eZ*WE)Th2gee-N}#Tj*z-*F#YiNhV6QHEn1#S|gEVHK|mje zCTEb|D%F0c6uXq@tfX#CsN#rA#Pj&iWcH)&9vv$WJQrmjy`A<+;ky@iHS%fHXrIw{ zmO)6B9eC=@H3HZLkbZPlZ9i4OA*LN9y1Kig)aC3jtJ&}VQ6@h0f)pCu|mwj8zbMip|(mSf=@W-k^jRq1mNNs-nXG8 znq&W)TWu&#nGiJjq?VG;G zpGpH1g6nZ(TRyWoX#$jg9yqtKYrPB_G#nyOeA^lQs=4PKo{Y2e^S52)s;z9>IV|t{ zFho9xswPk#R`uET2NHgUW*N8mo+?SQdD3j1I!Gu#20$iXDh+nY*;Cj8wiA^EZ5kK# z=8!1VdZ$mcUpPSkyk&398LUb4O5m49VlWF60F+Wnzi!!+4Wqxe{^alIf62hC&8lpP zv^Z zD;gbl>9}UdN-(MA+}rJC5{#c?nrumhZg+}S0{PR_6Vl+CXxd-+=U%9f6y*H;xj?61nm$soPdZIa%u9s?<9@KjdIx-6@|zDTQIMV;1H`9Ha2pB zhB__^K$t`35DLpn*T!I_)2X17NjhY;$~z_C@R9GO(iL&6O?DE|Z{-QN`$Nrb0>RI| zERl+l`)2-}Oo-VUR#`0NLgH?hWPZv zU54ZXX&<*`>&Z{bS%P2RYfLzq)l4E`r+}ldB0$wR+8Gj0DyhfFcd#+hX+JT#3^T(s zB@4PJzG*)P>NjCAru0%jqF+WcYg0x#g|TFwU<9$R{*x3gmTr05aV3LjuF&u)?N4jM zzG~&!7|ZA^xhX8sA=^gGEzJW`9!3+plfxK>yu3WUx#DTSz_G}D3X}^I7cBM+ZRpm| zw{+l7O%TLXlZT1dND`Rlq>82q`^l-PRVtF)eN7_?Dc$E_>`9 z#@8xQtjaf(HKonT#t$n?eunj#iVb2M*mTt(2q<B0BG}TmDQ&{QtTrw>`)_{zitw^u`FT*pE z2ZNI(EnLEyGHD;jtDloUPF3l5YLVrl1F}YW!do>T<~@PYL^*T5#4s@g5KSK7THw@Vu2exew~;ab*fJ91IFcLqmGdDz>K4TZ29+9Rw;V^G z%%G_Qh?AWN9_scyQTc=80e9D|aMGK$I*+S%6CK)WmcII4L-4~S>lK0qKEaoP`PR~s z)!-JdJc;$28a{^~BXlU!N7anRyXtB)6M!Kv#j#=mIFOWONAj@Lgp*4F!%~BvcBX^H z`b95TDCR}(`PR%u*hp8u=U>Z^OY~y92ZO`A`MSgJcGWGqYDSrkqSdl`FmU!TUS-OW zg&$S>afW_St7ZVdzHZ~grEVlb>gVa*kS=gP=26kU4sF=Rq!Xb&I9gC`ft}c&s$?us zE1kS-MB_p?n4_TS!{EHk3W6S}yb-9D;x_>_U|MJo58j>qCc4c*d)`wCO*)7xN%#NO2lJH}~}DImDOrB!YehobCz#RKMmfv-w4-{Px!U z_YnvF1&&LEB1LCo7|wVR1tac=a(M2RYDxlS%pS{lx>-F0xWf|Nzo4ui8PMMJBtZ8D z?8)46qR~!Q%Jb#@rW(fcdH=)C0>3oB+{#%8rplUDQ*llq9n|zGZE`U{*0@MN4{Nt6 zN1(>w$**7bDRCtVviWaO`i%|aP=oES&Yvo440fecC52g4f>DoY(8dcFS%$tbH)-?Ilyf2iT$aXhK^}2hS0Wr?e}ca6DTnKBzs%0tlRc@3sfDd9w&#V_!=S1AzLE0@tjCOMz-BNCZFU(kCk*ZX|Ak1_# zNN>^=?t8e9kMncO0T0^0meepFuVhb9W4UwHyLO!27KMM`Fdy8z2W5!5t=_hQi`slO zb3?6a!*X%h{Yb;b!_eesT**k++6Bp97AAN$P*eJM6En4y^v{GeJ%fap0dMYGVDE;6 z4*m?vYNm5yQXlUV0=3po`FQucs8;!a3A?7PVv<@ZhR8#QrWKTih<|92+oAx*E;IUb5Q8yogLK%jm>`PDuF zUFyq!UMU`hIC;GEfaz`{vMOiU*vtlt(HI*v0}E-(fz(+~cw45kbJo~UM|<+lHz0Q~ z@|I|C!(pMub58dTi6jS$?`sWph7i7+ajgG;@W$TPlNZ z+jxRgiu&SW&caQoBBMaq_4(B|5%+>+*(@O=pfBcY{qro&N5oUsEMzE6Yv=Nxr6RHY zDd6zM)AQ~%&vQ_#oydmgt4q|~M5$SZkzcz*9}tq0evkFSrgtz}0s&$=GJ||qiu0B% zv2u^a3o!F-r%_YD9xvT} zt~`ll_aJM{sbQ0fji4PgSYSF2?$P?ARD>q#pYqj27mvj41&$$sX55G7x@}0)f|h9B zgbUDVR60T`wd*#3nBh}|e}sIz7BNLOzCMb(#DGF~1F)(0$DLFR5H3o(Zut|Buf% zeD-_#HC{7qJs&vU$W^w`Kq$f=uHx=j#POX(E1`3A#@=BSW4odC!&u_|J^;2CmLS_#hMp%#&*66x|WVAO4oRW{;0}B zS?p#U zo*R7jZ(3n59eeI|dJJs&bTnMRe--C@Tr- zb~FY38I+KCsv)*WsUa}KD8K749(GkC0@xt^^fLQgxu51m9E^y}dPrYNC;33r(GM#&aAf?*d?;<+Mxoi8mHOI`P42orM>Am?aq|)v~ zF7y#xrA% zFycd#G_Dn>KNkbOd#6G)(36++dg=XxSNpsV5}^D&@`1aq!=bzo3OrP{aI8fV_w(69 z)}y5?gSSyjX^&Nwz z$Cn_d_gwFoy?gF#9fDnI*W-Z#13nCf_tn>GP=fOv=3KHJ10)V6Ufk@RKj~B8FSxa( zfKRb{sGd1GKmGyn6onjJ`m~Dd4P}7We`J^po1L|J@ERW`OOu0JkvdnHMj>^-yt;u+ z&hKT4Kx9w7)_1j4kj#u=;m^-ds91h+-6i<_xNQKD6_V#u- ziZJ6QmKQ$$aO3a6t4-!THQ%-~uZ?{dLJ4bP-rgyk{Z=uoyzgz~!sb@<=- zt$~iFrar5=umApc{fK8aMMS|yZMW;yVJ=iYD>?R!)AR!-H#XGbqV&7k$+D{nLd|9V z=wQ)m6>Ol$KHaF;aXHqP$2j?M=GB=t_^sr0$V;n@yyV!xfc+v=(&gVj`SWbJ=F;kw zc96zf6iVw-=4t{@3iAXO*ny1cl4FCu*Nla%xAdHTtor+JlRUgWZZJ|xG4i(lQR8EoGh zEdKn=a)Mou02Zwu8UN8{lH3n0>VEZ)Xx!lNTuyIJKJW(!lT_NDAz|CJnaDp9Ij!;6 z*kqpYF!u!H@sfYVUA#QQ1cH)wwzof8Uj3XiXf%B{G4bRlZ;m4Z!j%Gcc6R=zH(~^6 z7B(7IhPo4$n1}In0)K!cLIH7!Ve=VPkFWr|A7-+UZYCmFKg6XI0NjkuU919?|H# z36rk7#CuAMS}?o^^<;g|bN+cY!CBAAKYFnv64kp4`gwJ|@BQ@-m86EIkzCPPUd0-7 ztXd6tqShBN1@yx}V3ZnnF2eAY2m?=#`e(y$k_5!{=A_Q!N<=19QFynvY%dUuSS~!2 zM;)4G!BDOY$?v>g=b;<7#8>y0?-~i!%`4mHP53JY)`a6H%<_n!Dl2mJMc_}e5HV*O z7-3GBJ}Udeg#tT$^mgdx>ONxOg8Emcv9JDAzR>9zGzB&;aeox8v&%fJwiMuIcArN* z4eU%KI}&4yy5PU}CFE_h=}`cFZHg{hK;r7!vrinqI_dP3b^b*Nqkz3~e_4ViBmUYM z)pcOiyJSV^V2=E zN(49OrugVs2sqKSr?n1nFv`UTM(nPMC-|%Wi zmML|uc@j|x9t=7uK@w5FufrSL;<7$=mz2T#HllwskND&|epsVR#R2vk8XKD^Epm(A zzV+%@nRh)WL<~h_-%{N~bM>LUgb%vWYjt!g_h-x7Kf6iQ!rv1z(H$O#tvrHa&lekT zW3m|Y1rujPrlbE3#!5$;rsvRB+~ClzSMdUxR4SG9Qew;K3vY~DqA`PbK2m z39c`b`ZNhSQG0!{iuk;2+b5328@k!0pu4*{)vtYPc7lA&jPW^aTgscCnwIyhSQ3P` z)Y=ww#%FEdi*3p3C?VxV6PNMIryb^<@1~(<4BQDE0xR(LL&^`y2|oJBmG(POMJz7) zaPjGD$Izxxq-5cwFwNkSdo5vZ@_Tot-`vHA%9jZBc+%CL(R{G{Q8iAjLTYD`WURgMKtrZM6HI?2hC!a{&!6txxr`Va}zDQk_eq~kP zLELoq?c*(gXLgXGrj#B239E12i#FkxE~QD;g4EqpGPKL0@^_vw_tA=#Av$w-W^BtT8bSyX9}Grskru@_VA_6B_|X7lZ=RhItDFL zp9+f?P_bP#2-IQTzSqh$fK}V$W9+`GwvfX~Aza zJyJB8)vx-8Y6UL~DIeXtdFm2|FKx5YX^O^>q9yl$;9%`t=rY5o9*lzcaIY<=g8~O0&!?ku8Y0A)a7cuYM+ANiUoOKCRs9@^Pt%Oll!b>d- zb(NKf(!U%_e0Bc0D$p^95w522`oR;yJ)qrd28Wb4y1Vvvcx3F>+|%=Y$w%cp+U@y3EUz#$M}{&hF_Dd%cwL#HgXnK{X!Bf__4*EQ= zhionRoN?|g2MdQDi^rv-aV3xQe-kp4z3wM$yNlI|rRb%aHoJpGx4Dq@-P&4w*jq4D z)C1P1rD;u5_|c2K1DBhP>mzafbozHWOjo^!-SPAjKrap+QhP*^MT)RwqaSQ9CzG0`3Ka0UyTvc+^?c zuib@T{AGJQ$IaU=s56lXgpE*61oJQ^LfP^q-EN2b!YA8yYYyEMXj_s8L3Q8kLbig_YP) zC_$@xL^A}WSLGSOH{6ur@~{86pJOv5R~EwJMaH|g%JRQS>2yRyIe5rSJ+_;R)hG5i8>ipMi(-x(D=JP!uO-9-fv|7kZAQ!!1J zpanV%V@6fkDfTt`Ct_`_Q6p52Evk@-(fk=avSszBknn(N)i zmv`c|VzroS8vF`rx%VEuVQ4rEVo6-m-IYx*RX0JQ6n${(v3^C_LZoaewi3VHWoT7r zrJk3%0;P;}cUflBUaGd<(OGcgAr*?LxmP8vJywEGD|o8DmT zNoe0~6{-?s%L_Q8KqkIRlo}-@M9Myl*hKIcJ*J^QuK2=0`uWX`Hv}6x(v>3c>SCGg zuy*P-Jt1y<`yOfHJ^^9MN-3vfYEw>7y$Y-O3zws+&z@uL6Sut$}w%*>0=Rh_kM&0qSkSRVt#nUv&Ez)!e0k; z*im0Qy0jSHT(3_#$xtSUSgExv2}~cKOBZk;tj*Ng4|PO6P$PC_>CwT; zR@J|(e}W`Vnk)?3M)RJnCYU z`paiwca!mW)@DYa$7%f!akmeZO_-M(&L}KBN!Ck>#pNjJNB@VU^A2b8ecQO&wO5I~ zM_a8?YVTNWQB-ZJC~EJ$R}fUqnyo#G+Iws4ReNu-V+TQg&-Z=vr^Deu?%dCHUFUgz zE~3vZFDBZ9P9A+CI0It~LYg|C+Na~LB_U9dV=~d7-1KHRUP^%XO~>MnB`Dh&>JDUv zsP6DvNezbUX08=x-OVe-Tm&GUA(@Z+f_)hLws{61TeTIoK^JRT@*TwDW{u1NcioC) zn?N1PT&}Y@e&pnLixy1=2eS9laN~JnMHlGXXWccU~r^!{jNW%9dCWy&Q?V+tu0L(doGZ9zJ9Su>35ag!sUhF@! zHC#mYf)qG4A>5Zb*{GTyrYRuV7`rpW1ykJD8=0h`uVE^yNZQS8cnHg}?*f9^!-kKV zFpPVbqBDu95d${&x$6BJ*4J_aj)!g7-=*Smz|T92pTuVKZWYg!?Y@7+{x}Dl9IMx@ zzm#cjh!||g+6=*zY-N&fJ-sIk!T7_*qO<15BJ>M0sF6s87Lx%i)i68@%Jy?AZaxMoE$DjN9Br7w&GVn^oFE`0rJ_&ehLjsUPVt<^xZM;`+%|bIERg!cRr1Z3g{TpC%ibjQ;!6RAm=++~J38 z{VF;Uhp+lsqn3B*hLCTr*#q`XU}YpDV6_9eHNQ;B4Xf4i(7J*(I@$!16Kf3$jnu6W zvPz95CaR8#Ii`QKwR)jiGGQw?=)gjN!3533IeEPx&6@QpP6g{lz!p#Jz4NEs&?mqL zO#p_4?Pf&DnEjLY(I4ijUsbS3QT#xhA50vNGwIod0c{WZfvY!Xlgzl5OSavLsPO$N zm@VofYwsIKhZDE`BAXB9oKQ988Z)^9>lmZuJ0%^ZaaU*GwX`*fPsKfwsCy<7DxnW> z2C!Y;2!wxh8dLCI{(+zC@rcubNl=O^mH~HPW<`6T@cTP;0 zN!_*%i_N%y=@4nj5@Xo%Q#ZR_iJHrVWsJOxw$QnJLu^g9!!T@O4mBGV*jahlS-X&H zQ`642WK&H;R9>}^N_zXaCm$lc^`DJR@>Kd$nnEGrW?-sAWY&zh8s!)z%6}atK9)E= zm;-;Xk~tkntUMhxJ^ceVdaA7>8f$0VB9!$3m6&K)18B5%9SBJclF&0rR?bu{T5TJt zFf)EC_~Ln48U(n?HMY9U6cf_a|5|kCA3o@!6R%rV(Y#Ga=ZBsxlbaPvr-f|=OM$)F-c7UXuQ?fgHsMsDsDm3f zG+Ez|lIz0X6#q+k!auLl?R+yX703wp$S11g>guCWNx8`E^Uy%28{z zTg?yr9><)PbMMB*CYCjKwRVJ!{cU^jNs#NwXHz~=y3M%t2mfqKNi}^ku>4&+{p5WB zOfOLMM07?g+VL}5@Lj{HWTg#MU;)I*Nr;)_`Xu7@P_G};-C=y-Gmb&v(%BQ>bYpMF zLcH6u86kJ03b&`rE{yq#_v|}@GC_4xC_1Emc{7!?XDyS(MCDGly_p9eUdqp(kd$UtXcl z-kK6XzHgpOe>GCDU=nb6ujA7&xmd2N;~{>Te!KIp^)=z(_tb(C+u@Qp(OFor8BdfE z2sd9Mzaj!csoKgdf5JkR7$qq+jqoi+`>+1Z+-v@2V*neTT)lkgxG;T4M(^|8smX0Y zaC1{seuXrx%A7v$$Zc3$o43MZuSEm8eRS@h*DMsP{~o@ke-|*MQe2fegeOM!1Xmf^ zjx=>r<;BFE?=GR@i(I`~*+AUrWM{R$9F&4}!J!Jxkr(H{ctnob;R!A%LAuxqs+~>Nym2K<%*f4d#_%%wF`%7LYRhhR zPyepd(a9zK_~vbX?Mtb#7pdo|0jH_Vv7(>ZM#c0A9m7*qF;GtGhsZB2!l*Xmm)_rb z51mj~dzY66_?zCXh$H?B*zV?ub3q-VeT76C#;8*;YnxoiHWU}+cKHkWGSilikDj%e z-%rJC8^K`V{4%pfO`ArsYLWQOe2*DTpI=@28~t}&E=^E9L!&kqWD*biV3ZacGk%rp zjviRy&l-7DwI4|HV{*T1rM-H!e!AB8e$lG}XcFCiGaYX4ABx(v%A64~Tl>ZIqmNQv zoi$MI$E2915QMQ>GxB$sb$Z0#Dn6A!g~)=suZx8hWw|_cuc1w)Uo#5HCV#T$Uc-n+`3(yjLKy>DG zqyD4J)X%0)Kly?%Unyn2TBWhsKWDL9`W7L_vheY_u(iFT-(nW?LmqR-b+7CBrm=o* z%5HSOwf|;Apu`J;!pw($B*8i#^>cVgg*I?#2G5to03%mLlKfvSB~1`u-zK%3H!(f} z0;CY89YJfP@5x$l5=EPrmu+7!Uipi>{=0RjAa(_8?5D|+V+j;-J+t2~VmF~=UBUG- zIb#X9A)jy_GhLhCX}y2RZ(qeb1W2k?n+&HM)vKkYPCfn96D?T338efRdyYH^gR#p2 zha7Yh^bT_g&LbA`eS2VFz^6@#E(TXVb?eC}c`#1Q5T1_GB5IJ63_oJ=9&X zA5R>!SL+*weEE~=ulPzz&iJAu&bW`~F#6MEH!!?6E-t8YXqD;1%^LN10SD76(p-o9 zDF{UIZ5;10CDd>V@l#P-N9Q|-xfb#0l%KS6F=Wm9Ln*Blj~odR$F%0gXS)EUSZc38 zpdC~vv`;m|K;gcZ!Y8vvg&6jwuL1rK+wz6_($cIto%Ds8n!B0uzn4RmX{9&O#0-6s z(Y)lgbZYt1XAfm?Q+YMw<6%C6%pRVca%-BtFVY%eClOsAr&kOzEKBNMX!fDg?7ezekX@@++BvI3LsFjv>`R-^uRRosunevf*Vq zx36-pE$*zP`vK2SQJwanewobK!vWk>s}GZn{Y`W?)K^rkroPGhe4yGczc!N|hR+{P zc5C*n??z<1CaF3yw7Jns&mO|IaW^pXURtb0r5qvQsmTQ%AlL9)d<%1KHyAJ*kL)Qd zz0%}}(o4UM2_F`e&ba9~f7`JY$Z62GnRX+sKh)yDLI?b*LvT~f924@t2EM4am7{n1 z(eu#A^{iIZ=QrL=6sM&WI>JADiDI+N#(Pfw)DloTs0oohF0h+S%N=iFjAs+%;vuL! z_nbAnD*%%|Bf>g70wf!j@HBDl@}yC9J;za2X;3VCR?XQ@oS=$o@#vGa{`M}$M;8(NWaZP{e6mu7Yo8GtHMd*{{Bcz#W%a&f>vg4aQyk?{Xo~ zdAdAQ`?irwMI!h%;0Ps@gV%8~Fs1}fG(Th@Kjko!lO2t!$g8nDb434&ft!8@(KPQCr)8TyCDB59k3|L)=~Qu^pj_No5t*OsFO!-5aPda@r} zDgKD=`F5e7tkb_k23YW=#@N3qV@?H_=FPOv+jUmp#y_5?3;?{wy1KgN zNTU7FZ;ea`&U2l4#i0lk@_1R{L%3tEa=L&A>dJo2wBMXOTt^3IMsy0yN*Wd+@rUe7 z&HUFodFpw0#ygUFBoI{l@i+{y5!sdl(fm0y1Zr-P=wTcw5s3&A!H#9RSrDCn%(5VA zO~Z|gsl_YM%_b>0=iG?7|9#Cc$cgj;uh;^Juy%uFD`l+|!l~4mJKmNA_k$By{$(OH zIk+iV?eAgde9{K;XZcjB-IGbGd$%S5*ZMar+|4!HR~vMQ3#f`P@u=C)8o}Kh{cv6G z3Z7C?lAZGsEr9gkKZ=@v$FF3%Y8Gp!;}X}bj_}~c2d78#Dirk((0CvNPxN6+v{i8` z-4m_LOglzOn)|3`M1ziwm{sf^h<+n&yUB>Rd+fd=;Bvx`j670B8=lDzt30^Ilcq~( z@j5o;~Az0ssujs7Egm z9&=>N$NaLwQPPF#@wdY~h_geB`a@^mMttC5bU(Qogm)s-T8FAQcA?qBJ9}zcyJ2+3 zwn(_gV!P0$_GOlB=0Uw-y-6wpjl~@B01u3X98dy+Be@G#XbYmuowkG_w3lun+po`~VPJHHZ0|?3YgqARI#ycvWz1>5FZ^YJnfL`N< z_lF@r3Gl4F`@VH|$I$DxX5VPck-a%=yY$$Arm8BTc*Y%YTzMrAZBr1uT7$6C{vTNa zdLXM$=7NvWO%91wlf0hSv?I-GNRy)N6Zj(1Ro8XWx%S?yvz)E^FFceb=oym{T%{B= zP{AY2wyc!)xXs|bEQ@MHFXbnW1i)wuy0Wr5+Znlo#qMR~pxn`A-DRRXHqW>ycTg3G zw)nu|1jB$k_KtH(nLw7$U~aImX3*~wmHy@uWXxZ?wi##MTa#m?`(pi&<*qjg{`8`w z8EozQVU^L}%=7(pV`E~?uy!$O>}s2{z#GHuj@vA5WebsjNU32_&(V)MQ8W?#Hf^cZ zX(M_m;Wl7CNn}$(Kr+P*G>T(g|LTvNX9{F;J2pPh?!Eynz`YM>mQN-yNqspi6eI6H zQ{-d;=BeXmW1zu57mF|Wouz%8RZMfTFxq4uK1wlQ_H$&%%vB2nJhY(tcN_P3=p6(h zB%4JGtO8qQ&E0~fnFWn!>?{FOcl&I>?K3|lgEqPrzG3-i&lP4*huCB`hf*`6cO9jW zH|Z)AS>$!2Qo{uCPtlB(J^}>?2fq-{;m|tkjU9uU=8p&NfW`YZl<$7Qv0g`;+&@Z% zi7;@obg=Xd6^;f4Qy(vp9D$`g8GOr|hj@&u)+a(BRD50cs1+n)P<@CiYLPZ-lCp5kB#^f%vLxMSqORuyVgXPA=AT z!1;h;!B_f=68Ni7_UiMG%{1G{Ft>|8C#R5Q7;ERJlh6nfNu~yZQtm>pc)CcH6ghr5 z)!K@Km>9yXsGusPF&vBi{e6P@m$%J8a>I**lt~h>c>sc>f^)(Vx9Xv{e90h)NwLe0 z>uf1!tj84SMcD86S(ljlBvpGYx)Z~GTQZ~5*sq3>fm=Bby(<(zRgA|_z-=uHC z8RepmiyoDAJ#4*IPjcDW;KPe>$Dp~m?fzpGY3Shh6`vUH$H6FT`-=tJOI1m3IAp2{ z9SX3Ert2ZHoaUox!LHjVF17m`$wt)87@lcOus1^tuep{W>r&s!P*d8HWR@gqD}!%! z8;ql=IAweEBz*qJPN%7Y((L+Tc*z*-*ruZ=0eZ#1bK9<4n)a^M6UuYi3LCFtD1m@9 ze|~TY814S1oNy@4g)OXhMTyS69ZwXAAMrfZJ@aBNkB%^_HL9pLEKjPhuc`m>ZqDV$ zFxP_>dY+p(d=cnL6eZQV3jSoTtzI6@lv=f;*~g@i-ik>~0@oKRr1ff8@-u$ft8IoZ z6?r^U;`Q}aGq03%lABs3hv5^X_wzERV-LqNT)A)Al&8p!qSPUUU>kjyWz_0uND$s5 zLQHCGNusP7(JCkz2ljcZlc}HA`$TRBe}nu{_Y7i$_zLo9{e7O>`3R!2;$TA$WDY=s zoXVRn?q%N$fMyqTfR`{#gl#t{KFAb16Z;dh9eeFgXWhCdKyVn&#__|teByL7KlSXIgxlfu z_K$92*#i^s4Q)j|<<@+&a|&Op>H9k)oZ6Z8bRQ>BZT#v*u|EXp7_<1YzoMJ)QoOQ1(mvzS*+J7Y_CekTP_Ba<} zUB7zX;yIBp6!yoM2HlpkVHrBZfQr+n*s3WxNUxT>ZqInvDoI+TU1gw{bB$*z*Fg|R zpJw$#MLPk0g_2%CrnsWI5a@p3Q2p)6y?)XqM-y&um|b{&^$k8b&zr8Ex9kvT(P?AL zxiaVJWAYjLG+efrL!R-^tWN;)Wjx!gJ1@}y2t8dstMgXq3uTn2lOCAFF`VojeqY*m zEsdgwJsY2!g4A(yNgpd}Y>Y!d(FM^5tm0+4+Lx`MPvidu-XX{7V$neHeQ)B}V4~l= zH-%V`IRD$G*t$4hs%3vbxNdl0Se8-P((Zs*UhF{lH=ySNPl^I>5qIot&20OCK4P0I z=0~k5PgQ3>SO2qH#!meWMTTWzsl{S0DG_uMIYocEMQq-E^!iTQ(bbmfJb>;Yo0bP*hA}zvd}6`2{S@1C@XHUkm=Hy~MEqV>jt{$!B1r05Ew7QsCulrC zl3+ktGt7ahQ7k{!Den9Rz>55|=GUs-Z&sRlypJ`5xAE6{4Vy`q3I~(3(`wfP))w0q zt^5wT9uV{@+!Hq%Z;BL7>f&pZ=t`|WWZ3|dPsncNu{b)77x)+&ff^?S1$5X!A^Lh!|)5X^3&Z(hYWfTE)pl@Yv_&pws z5t4KwW8Ms;%mIZqA66G{B>iuJE3DNoHE)k`JH1+n-HxWO!MjBdJ0rHe^#b5yJ`*k^ z#(WyKDs*|{{i65s)!5RVcHrhJ>Mzg-+3{77f-_afr@_8n&vQ@od}E_F>SGsPFW7;B ztNB&UkEeh?0qV*W!Hb{mATpgrub4pii`F)jMSapn)9)?nxf(@L(gLEvf7S4S1MY;) z2q$u73hBgPRr)vp>Jc)K)tsBdr-glI4vBHTLgp=dYf?S3jGS!^L`yGerxyYi!=K8S zg3R74K`u&6A9Zv9;d%F$LZ^F@Ya+fA+3BPHzWX2ne(E>BK8lO?YL9p@*KkWcM(ku&Zrg~9><0?td$=TT%!1|FL52|BNqnihv80EP#N6xH|ZE_G6 zhssG3lCk&70u08|e`4m)Gk>nIt9vtXwZeJb$x4>f`}e)Cqrusv4eC-FUfCO&(s%x= zm)jbC&!o=sg%j)z+g9^d5NDDVgNsEXNZ$?~x5;ZuV9u|fgi;3o8`3jND%|IfC>MhM6EHR?+OuU(N&)m;qB1Fde)Ij=2RbF)LmFfm{ z%*nPXnxIjtvuDFQR5srReenV|E^Nj%CViP*v+d+ee1h-4HrI3I^arS_a*Gu1XH-4B z=Xbn+yPKvM*cQ|w<2d}rHdW(%slsaj@<7_`)9#cI$@3gS|-fL_B(F z2#t@x*nKcDmI*uBU-&Yg&&!oqfXLVrs`?mVrl%89Rgai;H+Gi34mbjG65LjSS2CzF z$2%B28x@s9|FVLfO*Rern*NPNtfnXlcCeevjO z)P3e3&|cWpuiia0d!P3%^xUIJqjNEmbwhkA>OA6-EvJ#xT5141>RYh7Ns6V@JL6eS zRlwH@@JbjArk1ODV>UrA0Z7I#G_5ms_2XVb_F$%f3*c1j?|-$UU~(T>4}J7Xu8)M0 zqVH7MNe6@_mNCMDibaGfJ{q>>m=E2NRv(eigpd)f(?`<;VRdQB<`axCbb2^FKN;=p z&nRpHJg~ro%x^VtzoaOar`shM5tl|-#l67o{MMQ!^7=l(xL{qC{HL*rNr)(B7V{EE zEl0Vqe_+3B`dH6Us>#3j@k*wvNk;m)G%~KS2wn;RN$TX_wX@0GrY6KW2>Vi7X_M;z z+8OEcgCj)6-S`PMQz7iVQbpb&7Yk#_^RYif|0w)ZwiooLS6v2El|=XAq0$ zRz=d9_ojK_Su7?9!>py8j)CYRadsd4e0OJLZ|tFbwZN1U{D}NNmVB&w zZlTNI5*4_XSNV{blMx#$F*@Ho14u#$%gILGw=wo00$Wlu9zRnzWBNW)EAiGB5rFjz zi#LW1rgw6R$o9K4uarcJDN<3`zfLF)pgxTuS|(`8FI>Jxr(&&tpyJ>#pO!*cXTF!E{5hP=d^QI1M@9jOsiT2!@)4=ow5&*<;?K7@EJWT6bXZ*r%6k|%Z`Pdkc!Z2|Up{iM2e_%J0QQTp_rnyM zthFovfp>-m2xPO5or|n^0bFC{i8yy-<3Z+v^`g17B#GnIjCA*r8RdVK|8b@z8s@TjDmY}U~7B_ z53VeDe*5|fiW8ivu8PmpCm4NSlZd!>MZ*XKQ5{DRl0G9<3QINipRs$HHCG3hG7_Jm z%9^!$!?AnimNANc9w`o{zT29&)5VJG&?iVFb2)zJ*N1)FPxFW-O5hyaO#IL-u1x&7p z5{EP0(Myl=mrS*~slxMCkk7eyyFXPABHPB51^Y^l9G22(6mJHf1Nk>11;?gL0cxDC z&rQ(o_c+0$u6+1@aEr;^BAJKfvAa$r*~GSMj{oLOs>yBlTho9W2Uow$q}{M$4lOVV zfxc4$4b9i4q!^qSV8E+n1ox&=RG6KHHUVwpuZ%gQB3W7mJFOzC3G3LVG2T(NCy&fEg~fmzMovh&I7XOfp&y@WEwsh3%G{Q^@;KfHY-Py=k_m!IhYp zND0vkCLu^7S#rC;dXf6p0wQ~HO23{FT#W?}L4pNXFu8Z|wI%b`DY2TVS-|oL@J;e>Y z+5W?$)RnipyUbuxZQk;GwN8WY{_>d`#U9G9p)AUvU``@ryq#2)Hr3KaTo>Ag*0?{} zE0RWUob$1AGGx8|EgTqzdpi0+FsSYT+Am!IY;dYPLvwIIS&iQbUH3xwd>Ya+HGQ=@ z7SJXb*>f^uc$chuk>NO_>`5ED+-u`bJW)B|7 zRe4v`3yL>~HL7&WTfDcnd!CUu?MMbUZScIb=mwt zXp~IGUoBj3Y1UFv1fV7EjHohX@cgsc=Z;dL*mG>SJI)5ZI_JGTiOjyOM=n1k1|G(% zcwFuuRQg@TnED-`cQzTY1q@Rvu&n_4x2$P!zw3^-+}JQfxwC+x~-V345Zy=KVT zDsMnAr}7__X5yL9U_FK)RtU*Iv3;nM$l74u83EP*a|C;xt$noKm}Lrgx?JeWoc2T6P1DJIM_<)XE5LS;$rSM#-w2e>U#n`(3_J(f zKRK2kiMOpLl8pibkqU&pjsR;ezma>Ew1?b~@{{T--?qhpW{*TwEyf-F9h6T~W^a`U zku9tEXp`&hk*c;F%fBR?;J4arAE_>n5I5tbcO}d>TN-yp3Kw*m0f&Fd!Anh!bIdGZ zR#2vhh$@pePZX2jhks44FY<2I=3=k^^xWOj?Y$uX(Gv_^w`o3XzMgA1l-d{}2Gv+T zZH`l(Q1kYBI2+}2yKsByP19h?Es%}?7zr8C}D zZ~r4v-~peEAoyS(H0|nUGBZj`YiCHOjsGK&Z=$jhug0ka#&8*M{BX~s0T5?EMZR|FM>oYY|aR6Xfc}SuT7{)j#zfAA>`tbo^)L<5v4jVNyl!Ritj&v7r~49Pwlvy@Q;hC(* ze9CNO21r^k~H7G@4Tc1Jm%F7r25u*1L%R%+&Q2nJ-3z}54Kc?-|1!ZHps zed;$qlr{MZka6!khuIy017dYp#EER(CWw$@fS4d z<22e^(0*drr8_t~z-}{i+4kbC{gHxna9uqjOMsV%5?Ef4XG9gkC_&Uu z@S>kV)6J^T#Grtiy9ST+wvZO8={U6RrNZzeB>Y#uAV7fj4=^#XZAY%&k%JlF;7R3U z{yQbon71SfeQE028iT-{7`sGhs{fXjhWPa~*aKvzPXSkdy6FB6Uxr9=c3v4=4;zya zI{vy{ZKruuG&%6~$&>Js0~cxJ(Mz9G-9S8>WwkN$2FFk@UK&DgAiI{?zrBRa10Xsc zx3|qZna!imEZgsWr7z$QGl3_bXc4rH!W2`SZs3c?t$1`wZ~bOXRqhEH8k_tHhajZ&rwPVy zf(n9O{>CCrYpN#-Th>k%=3*4~o=z`WLLNc!EE!~{i<_W7bo0ItzKOPW!Ii;qg{{eI z$^v7|e(H6?pRJNaJw9y_xY9{U%#4rX#n~N5Z#RO7lxvwI{`o--1=FqKPfq%ubm|I$ppR@6RX8Yde4BWk2ATck?flo|EzWf7$}h<3{m=T(cW}c zE!j8lF7V#!q01D-r-Ubko4h(M=Q=8-(OWeul$`WzY;&ZnGQG0A09u|7o2$1}{8hj) zI$+@DZ&)y;Ne*R3kCoSb4q$1Da-m-CRIZH|gG^=& zCAMU=q)cmKzV3}%%e352RJ%PL03XmPv68uE^rrLG>0$aSO6xl}KI#73=E8152(U4O z{Xh}-5C2^xwrXV9Z-fC04DxsKKO`1g9|&0IAQt{^5P4ryQ^TPOpuq_AK1Fs5=URcx z9pC=~FJMOEB*-M4k8@(BM#DhGirzJ+7RV}ps_;eYzdf5)R5 zU4`hptl}}p6HLkn*aAT_STqXNQF;_1l(Jo?-o?(3cW4uPG|Mo`Aq?_#~?faRIeCZlctu|8XxN()ae;q_( zzLm-OZ-!)s~Z0MC;xG7N+TBQ;^S%My+{XB zfIZ+{5VOjhgb~4@usY>fC10Tm(R#zplD2l{8u>+c$vDKH+q$U5BP#Q4{>Hxz%k$)I zfQ$Qc?#0>nd=6Hy&V0T5n}oU;W8`6th7%L6oL-9W*rW{|tg1t%W3=qc6{L`bXL%P- z_FF-6>21XUmF76Ir=hmvOmg3MzMjmQVpL!r@Oa|p9RSY}AO8X>db}&3Nye4K;A~BJ zzJ`)k@{ObG4T>iF`%BewtB4JuFoWwIsu{v)f=dsoAj22B$bUc4!-Shls>O4y)_({< z0s!5Rw_#Y9+)@JIxsy2ukOX%|BI zPl@A0mjDj=r!&U%M-x6ak1MdKBF{Dqt?8>7Ge4&Sa>t#EuX$SS;)#p!19q8Ob}UcJ^-c7BqZ0SwFHsjS0Ux zxPIP^A@MT#v%CEjYTv22AU|-E4?Q1v$9!+9EGsV6++RuQ8HDl49*%mgmUkn0dscZL zQ+YNTvb%mLX#U%E%_3FV-}$^Bw=ge;VG=O3dNMLx00Q6N44!H&x>a~Kk~rz<+=LuG z`@w>dsffQRZC=MY9(t|J^!nd@D#C=k&ExlLuT>s_sb)|0oA&KY0Jp+BomYNHI#2~+ z$TC-UubF7vw}r+G+DY$=()DEQXu4x+;}U0px;c5Z|LL-2PkzEu{HX}HX1jf{oV|5-Ve_#(w2vyr4Fwv7E8-}}HJjVPY zZ$%^?OaA>+&9=AnS=6`*RywNx14a&h>;g;Fuf!eAA0DFQ1ym8d@@Ud+8F244h7bFx zD*vA#kGxqrBQ=&8;AiDUCCg+*sTr(e(}C=dyL3Gefmx1zk-)@h!Hw2R0C zp~+L?PS8tHjm((z!s60}^XrW~jr+CuhkibEVgpwGsx!R=s}WU#fJt`E%@V38$Lm=0 z_Q}q670ahgi2{pR{oHixx3%0~Ara1l^Htqs6eCfi5cMEc!{_@32xL52wMXLPx7ud* z8>k+M(?9LcMyo%1WR=g9w^DN@#-;wN(x_Qmh zi|WGWs(EFu@0n40Z zE*TJ7GYCsq%j9X}SvW()S^B_PBwLj+F)_eGh@zYT@u6xU=RPVH;lR2bMx$ga>Y~@r zjn5hvc1AG3H}z;@H8f78c=8hk$A%zKQrz@aF=8xNkpRlZ&PaySaW)*-dyvcXGa9Q8 z*t_wyuA65bAb%Sf8w1;4TYt z4N~kc80Io+Dq6&44J#J@46RIp52*U}EHRn_Hd)h%x*8?i- zGN304J@f@~&cHe%WN_foX2<;cr*7NPRF!Z#P4)P}V#Y9T6l+SYzO~DAXm<1C@nuP$x1X@*?dl^Tg#78~wg>uHd zY5BP0JpS%^&dt0A#ROLFY?KQS5n8lMgOkH~hE90c;1>E^G&DUKjwHzAEC$Pjs(e;* zE2ye!W{cS$o$cCV>62fx9u93Ulh6EQ{#>2BIN~ce%%}4YTz1czd6OGlSPJa3aV(F` z1zFZ41KfRs0p`JA9Rk;_ZjMvN+RWE@nd_-RmuRH@t}X;WV6U43R{zcJPU437F3L~hSQ|JBy>?O|qhi$TG))ra!w{Z-Ti zbnaC|X_xGBxA;NYIlBhFQg6UrCHg3}Oo?H#0IK4#3_OhFW@T#Lyi_leTa(lPQW)71 zx5<*6wtxBmn31`w^^9{2Tv}|z2VInz4!E4Gn2{2ii6Qd(UrtzWX(c$N*aIw!$lHOrl z*Cp1MCRS>CbGzTQ{(MjOWRy+yr*D@e-*rFA5$LObkWVjsY}1^fvt8Gd-Ub$s2#oXnNXQ*YtSCHrdnTwK~J8w209OD^q%I?+%+oA7b z{gu<2e#Fz&dK>)lLw>I}Kg`t>;@k%+%q{n7zr_448w)^er%IIfus~)H0AzO}$7(kK z$XXF{*DrN`A9H=*fes`g$`E)N=1A1hz9Q{)f*}(TXDQUT3~X>v_-7h;e|d0VOSKcU zpT~rki!qmxr!>NoAD&{K(|-N^wMe3y%1x%g_g0qJTJdl96`Dp!mT5!M^44 ze&=x5cjt%d4Q$Bt_QKH;9Ahpt8kIl8hTr+(lUAwB1>Pb8wSt%BIpLF9*C@K{ZeL&i z+{eoD+lw8+QJIaZtdps+vfbZel)bC(h)B@Ctkoa` z&co}!1|`g!tJ}Az8=1B&k1~)H^4Mw4RoA*pZJg$jEcCDi3A7@zW-Nx+S8oVS^A{c4 zrc*c<9S+XV%gnB4u2RWwlcj-G3eO=sguq zsXK&DmX0p``?;htFWv>?-E~zFo-Ey03;gsowfBM;?Idgz`|&E1fB%!ia<(Ffwhj$4eoKN^T_**qR4)X7vh`jw)BMETAD#qUs*NcOmu(vTe?|!N2 z0#6s(jAMkwF|Q&Wml_2|GcbDc5WYO;Qs=|3c%*~)aHVA6OThPiU>&7}=a!PV`yYAh zP!Ve;6_%i1$=uYW)x0M^io({E6JiygxBCq5bsNmHzRpH?-)x_iH>6)SuN;vmYVv;( z^Mvl*NG=?S7aT@PKTNC!9J_K(9Dr9eBZQ7ni(@kJg5D>?ubg$%M@KzcWNrW6^nBKp ztL172k^uy{5|!-)!y(WrjW%6KFQ_DmA2z$d_tp~~K(4safcPExu(i@Uy;;elMOL#zuB=_4He?hP|x<>AKm8ADSae{ zEjOOB8^VJ_Hz(B4e!&S#tC@KP1Fh6IAM`JDrv0&xjEND%=TXhRo_(+iJS;-yiw#{AEZ2Y3+=HtCb&t9m_ggqT8bJk6$ z>xrOFO^qzw&#VE%#5ltSTpe4=ldBQ;{iv#`N`P2^C0}3dw=o+){Mq**QDb!E*_ag# zjpbxoJ72zq%ozf`mvgIuKB)gn0_LNb2Gi%_P~7yeN-=bA?#Gh-^2z5NinBIeGg=Z_ zHoYAh)9AP#;xl%9U0*uq;S0jO1mbn|Qg#iCEc~PT1+`=!{noGoDbTPc>-1lx2BU4x zysv7>#)-MZc%m_ji6u!GutC{80pt?^d#LvhnM2TzC^ympnh+9|r=7M?S1fV_OSZh} zTOA#s6Of%JHwmUAykKNp`1H@*kA#XaqwvSb7nZ5dqc|U}7$|~yNU>5T3?QE|MJaca z820GMFhie%Rj!@hKZ5rQ1^>Qjm&q96cfqV;3UmHB9D3(>_#D`24yNujr;7Q%?Zd4T!8w`Nzoh)utpXnxdwbdCRYGtx(e}^9iVQ^p;CV9FXG7cfsQs0; z+l|~+gqmh?y}SD|Qfgey{on_E4r+P-y5fx(3O2apbn4W zfv&#JYJJzMWWwMGp0@TcqXJLMGBn!W_f@ueG%de2ka&l$Rm$$7bp~8qfVJ<&lr#4% z!3k^A4;J&yb!2{CN=CEv(*L{!-4|$jNZ`qER1#kx@OF!K6DdX7a~6+2SfQ(^ zINY}EnBP6Be;)m-LQQkZUq%!z%01?WG;Okt?jY+}Dqnj*gh2Q1=RMm<}9E7Ea(yu3WE)3ge#L;G3|fx4!+BB$_HwM~s2_$p4* z#?MQl29;l8YV~9w&{sX{YfFDn8;ZLM%5A?hD>l?T_&z>a&1pQNFxV89 zxFNCTfq_!y;~>E^VtDfS!|Me8kT{vwcA;Uxc*ExmI5WT!x_P^}Gn4TYGI_n+(eq}W zf8H-wZe!tBq%U{-Z`{B~Rk2Lqu6+A4=DT03XUDCVDGNu}H{QOYdbU^vjby)O>g^2+ z#LXl4uZCKXrT4*cG9+Tn1l9a4#((A;0kRSDbNZ~iT0TMwy%>3!(pm0j;ZevQ-C(%B zv>t_Q8+NdJ-B#CL#~?jxK%`{loSmJ$;}~#iDLzy0lY869&8S(sd{*(?VWnN{^@7S?-QL(ALN9|G6jJ<+b z6?@gLlA1AU7gZw^wW<1^?{yshJn|c1(-{6x${AuUE-@F!dIuG^`Wv4kuMSI-|yOD zcRJh~JqC`ZV_pMBKQ&Aimv?_puLIPT^){p`KN!JT)Zo9aWA4thXpg%CgE0yN6cpty z=)Dd%)9$6mYTRGGwzFDlSllH|U}f9c4V|QtBulJ-;Y~zr-qW6;tg#r=X8@{o@Yj8}Z|s9D{N<`b>oIXef_Kac$P=SHC}C!VedM3k|n7%!$8kG8ib@>*%~#5_shtB7To-C(S82=)P*x znVXqq!e_1P&)C2vH2&sOK^cJo$kWZg=NW zq;FEGwO(V*o>SmbQckTKsY@qTX&bLzZO~4OOYW4WM< zo-^fwo0vPdze?}Q!Zz6ObTAih1$u%!JRIOkGfS-&0d{7q1E~SOnety!`i}=o1p5SP znrtU30*Rdi9Kk?9kI$_$djY|;9T=>1clKN{t(`Ac^a!p7DGtW9C<~mdwyp*^Hjc!1 z1l&C}|AaoR`RzfCx|L%mIHXLBHkoNd4d6PyMP%>MUCAs?G!JVH)PXb_+sZlCA)(`M7kg6SY45n|*%ixwIPZ=U(7-*X>0rS9VQy*pK@ME0&-P_~Bg?k6f9*lsdM~!dzki%5|d|64}nzeYp+Dy?`D3 zpP+XCcL6@4`D1C~=Vj?~mwAMFF<&mthvQ3t?PW*621kDEdkV<;)rU+p>07Zk%MxGw zE1MY!-01p|X|%K}0n%Ri;*8NNzum>t)tYrcC9y7|7w;W1)n5}u@9HnNr55JdHX5gc zfJwEklHB{e;kf`8^(7a>%-`;U^e{nMan520tb|GigK zri75-SDS`4T?CU)UIgvNIPi3A8gK?41d-eNxMQ+G@99X^pTwTABqT+m!X2%%pX&>= zyaG62O>>j2VP?|8qbOe70r?~bGr`2PD7}-e-i!9;1J`*;Lou?>(4N$3RqnD=iHo?P z?R(ts-t?oqT+q$-bJ70HQN=uHH2_c0G)K$UKqDop16{ppmt-70IpHULC`a@Kl$tIa zo_}$p>m;mXX?X!HFKdFl*uM}})qp!rIOToR{bCZR(4ZUs&I0NUksrT;ygTXwC7)P} zbJ=C=#YO|hx$`d1ODk2=I7x%Iznb*<|G1$l`GmX%9G1|!*bq8~wF*?zL*^M(-60Q! zpL8eU7m+M)HJHfNu!8aZD|OG+F)j9V+3)0tRBihOH>J{12a;l>XX`SFIW4uKPo5}3 zsPF3rj1&K#sqW&W-Jw5fX6DtI|0j4ik1_gJZ7UK)ywN5pS!2Ro&!sHZ|@wrCEQkIHrwLyrkBnv%teR)$piL8tKw-Q25m%oak^*hx5Ud2 zzRcrN=P{Op)stcF?T-GniCxFIx|A0Mf#aQPC%?N3Z};B@!tF(qtl_dypxK;JZa#k= zkpDL4`7~d=?tEZ$@sNiF^_geR_;xwgvDV=GAz|{HwmR%jM97+xQ!Tg1m>?r%u-;5X zwIsUimBoAOj|c>!Sxc+c`=H(Rvq@B9ntc(H69Of0{_lEh#bEvz1KWJf! zQBsA>H+IaWl{quW&)3c(`PI{u(Sl`2l7UZ=y=oZG#u3PiN$`|6TJRJ(+Q>Wa&4)%J zrgFcu)M!?VOg05|lZ)jxVW#-1`QvL{OcAgr(VI7#6h-ta)QUOVBR-~zIxg@e75gQ- ziZ><(x|zi=$qtK|<`uwcdPOY_j4p%affh2$MHzoPnPh-GbiT9knbW2MP)-Gfd3E!( zjyls!ZzwEt%Ujab+|by-5pI|Xfdgn>p+w1vGpP^3mcHiF$y5^$z_m10B7A7!+O@;< z@(_;(NLmTZi?X)v30iKf-OkvXF$=mSngmj{qtk@usFuXpb`*#t8BjN4TSUf$NCOtW zjo7}*S7P%qX7G05rBTJC*JkdD=U4*<&N~5i#`y=L&(+oEZw=7jP|m`DaoLLNg^MXK zng=~87?0AxfRQ}ibr48(HIEqNSZWCcFZqhAB${j6t+`&l(~)Vn7+`Jyb%sa7>@Ob= z!vKk5otO@I$yI%L*VZ`LN3?-=SWp9C9Ihl|;r<0)l7UdbAf*PmFV6Xu%$zpAjc4LH z#>-op%EOcojp_oAVVWpm+x|N9vi0-xO*WnR6)*%gz}RHTMLKsVVd!8^X1F0I&z26c zec!tlnt{MtV2l)tfk~)N_JPmacITiqFsV!PqK{-LiqjA|&t-X=&-p{8cxRbWm zJ-CvY`qHt&&;9^Fte~XVhHrqUw%qL&t zh(e44^Q-Jm77v~ zW3pu@$Atk*ffO3Ku01NOuqdVaDN7$}y)^Fr-P61qhQeTSJh@j!V0!)40Pb4#=i)| zP3LP5d?<$zn?`n3w2CiDH&Hc_y{#^8uOn5`tv>hlwzybgYR)99k>aWhORG+B;fY2t9|kN2F~vxF)MVLZ zfU2xj>gUIWOOZ_$6BF;auTOx<7LMyYG>yqUiFcaN8d51JcH^|Z1>m~32Esi=QNfbaspYpFVI<1f&<>o zThCDxMFV4n9u#3GlAFX7jpjmno4+%E(~R8k1AJTTU>z3TlK(vEe_ge}5)G=&=XIez zt${zpzt{+k2oHM)r%EQH!AbEYFore3CMm6;wb2s>q3=GOREi!@zp1hm%->QVM*zH+NiMl$bUGGOQU3{ zNZVKY`oisu{R^nh7@3)w85w&eb}nx6idZZM{cx7@43=poAC^lJgtD@~$k*)K^?#&E z-u-wD5i^RlVi7D{27#!u&9c*>*dn*|skfgG0^9MeJk+Nx^zrR;knMu7#LSr3M zkJyX{YWZm%u!&4}174_|MSR5l_~x<-=`02~NyytLD#_PGGxe1<*mAe9lXhLehsVCDwE{^2^k958QO=vdH5$Cu%p2IiwPA$yy8irn9QEfCSfQPD0Mn$- zI{FV=XlOc#LCUew+rX*6Ul%2Pf)+-j&butCXX8qY=F52_d7a|f)G^B^%bIU@ZZy;0 z>rn3nynz=WV6eSdhukqyNUrPr*gL0g%|>3I6<4T`R-+K9yut)ZINoz$k`FzG5>6iL zJb+RM=nTS4zPBvxiYw|UrP3)`(E)zz++|8r9bB$jdDx2!=OqZn{?!N3T;$TqYjN@T z%`#Y%MZFsxVsn`}GXnvGigdWnH0Oi-q3tbzz9|DM30x(6y-aADmB3+gHv!B<3_^u( zjsdqULFo)SR;R($$UoxA3MQXlH`U1M{PaGs%VAPXRe56^c`zsWdQCs$yHB=V`R1kU zWaEJW+yHK`pi=_-a;I}RZzcHYz_~dd#aoM==0%U9yp~!{x+cN97r+x?rB5VfdEuO5 z%}Ke%f>)`OkUag0@cpBB-20`zsWPe}3w;MRYWJ;{>>F_dEbHeTZwh;7(H0=7w?jbq35ySU~B!MNw4f9wgCMKYxlA|$-l9H5MTwAM{B1X_1 ztl8$zC^hny-s??d6w#5R^w~}LDMa6bR9KeXNq0Z{_wSYRvu2$wN8oEOUKsKY@*<%m zwxk4EW8g%MpWopFfQfHhF|n|Kfnq1%Ed5~cvjDt#Z|R9UlXK6Yo@SF;z<+I1n1~=! zc1dr*KE&^5n04LHb&$VamOsbWOgmT~_5?EXZlB2!FW#_aGQC>6o1Syk)A-Gu%VG5cSlD@m9VC(zct9c($dn~+sJy9VGj&`;NxQ4VrQ(XYnSs& zT(hTV&DGGqV4<8vX~p$vz=>hEWml~dMjtw>52eB{MfO|#UO9JcJ@e`8T!~((qsQl4 zb1R3XfnYlNs%fX;+JF1ntr+-3>Go4!%p<9`DB1z_%na2pRTVw6#1D}A|DWsK)Cz($7 zbqmYcD;7F(hF-VPAcy&?oNwClvqlPnp=oOW3f^QeQk2kG)24HzaMqwqYKdsHITfbT z?O9&cq&xobnW7)~!D25v;2XtB@`><6VSm4s;G}o{$1DZj_>u+Z=*Wm?vyRQ<`6a|ZRIto)v6@y?7&MPrDA!snu zgwuR;0U`<}>Aay?Q4fo@lYp>y)XjUJc<)0qp#@nmlO_|F0r$~IAs?*iTI|}Rt+VXR zp&K0`7>5qmjygAZOI@z_N?YBbf14%WM75NFxfq2I7;@-C*ii?p$84RGnAWlonZOaP zCiy;{>?KZcAaTpg=x_x>AGpJ=oelUs@EP`4_UU{BANP3@ZJlOUzTFJCt1K0`+(1h2 z%La-szkoRX|KYl}zU(RN9-o*%@%l0f#HWGB6i@rC>X!gE!K<8a)oP5-KJhBgk0GYa z=V!s}5WqpOv1SH5;30+f{0PE;G2W(t30Hyiru)3a{Xb#d|145xxFEpi8Eaj|6UccS|xbdv!HdLL|cH1~&tV z5hECfM^1QDgdtk{uhF8LV-m9bO#F`xdg{q-vtl zKV3ZWav0Kmz$==1g@2bJx)z3jF+gY2?OQ=b3g)_!jVA zs%c_Lb=b_!pz?0fTy2FCt|1G!y-B9Ltw|=N0^`cy(qN>hqi}k9v-F&vJjTwr&H&3o zWHv8G`aHQ2G&0@vsb*0S_^+P~p|ieAXz%Whxt66inYKFndW8??N`*efWln+gt^I3o7*ew9tetNVi z-Gf4yvnZ!Bg8RC%j716@u!>qF(BV4039fwIg$7Z<;Qh@$jBnlCK5P=Y>-$@isNF#F{8P8PnKoIi>!ojGn79O@JmfF?NCzLp}n+YFYk2jqPKw`eESN5i4XJzG8PbD=s&Z`eu zfJciBhZD#qjF||NHwD9q*Kv5%^T?&{H3kCa2&G4#UR@F+PJ{3MY@x+NvZuMSKe}rl z=mfB?xMn$iAQ9hDB#y8O4So7@(f8k{#eK3F$?(WX7M9+hDt1Fw)Ia2kjD)EQ=%N}k z&aNcSNd{bWsH1hJ*t56W7r@?`TON7b%#CVzs-xmeeUWip;vcN7$O-T`y;6%xPx`;wnZ$WP;(OM*75JfDK(c`8flJppEK4UU_k z{53!p#_fw_bQk^}3N)QVh$}$`%4LZc${fWn1H1M2hn6|J9*nirym+DfW8-*FZby%g zD*itCvE8e}(qTx@C`{d2nRp4+B~FY1Q`VLhkgou^=@s9#U~QJvRt~kK&1^w6NGwjL z_PuAeYh1M2b~eo;b+JJ@V?$y`7$VBjD)s#@9l=b2v))wr;nss47DCY8CYMgGUcE$c zQUaTLT7)CZ#E1c2!tPlB0w&yE@Sglf+|s=r=*Pm@d}~2>4rbzc9q8lEr+af=l3OTJ zuOF$|>+w%F>A!3W6$^v>ekYOJ!c#ojHBc-RP#*F!`^mPQ%g9R-ToRU#36tVv^G^%4 zB1X`N)BSbR%Cvj`Vq&d2SEg6XaJ)gp{?bMk1j#~0WK52K1eRJPER&OyV*}hjsJT*P zCr%PG&F6PpJUVCNiZ*~K7K&%NXIy>ma7nM3XWR8hK6%gYQMlu_kF{#+eH(dejWfQt&f!a`K~xvHX*%1Jrg#o3S)F zB_CZ$3Gk+=$U}f-6{gr(tM*Q7b}!m&pT4PagXk-=mx;v>!K7?Hd*aEDIPJbZx1x}w zz;E(Hr2Hf3Of=|R=fuKs}`XH{kklv_uzl-L|7yb4D6{&O4m&x#QbZKHizKS8eq>NXytvOa=J@Xr*aUO-+2N)0IDeq}No;q4L%iLn$ z+2WAp5+S-L8ouohL|ibA_EebtQ2AHAqTmL~15-|QI1Vo(%T%6$8q4Q zB#RbK;6@+kfGj)e01K-Uu9?db;Ed$XO9J2j%&)|MpSl=vcw<;^v4!_Tffqjg@>!IE zLzu+K-{;|UKd9fb9XnUgveo=@j!5zI@MtjN1+MxVC2m}g0?)62wsXuLFXcl``@Mb% z8Dq(5d6Bt?S~9KlFp=;s8=}b4@Eh1$r)GPsaa()%^&~p3j-+ zEQ?)scqFEi#k@jE8ww=JY)C>67OyhB7$YWb9YvjRtC2KZs{TOToKGd3eTG&E6w?0+7m0Qx^ZZ!;1fKew5hz;0#*zQrDoFsmHUQI}j-IipP1QHoB+>A!Ic z0oK5&1Feht!<&@A$M2Q*m2xb}(pc|rI?Kss8>MBZi(de%uC6hT+R%+|Z3b2$9DR@9 zW}ky{bnD~s>Bsy171$n%E6%8DmQIB`99UicbEjRg61TM)_$ zGLl>Rtw+_n)$?{j+;!MDAbbB$Q|sK`7PP(m$s|ZT#q=^eEELSpymUZo8I)R4?pO6| zNRJ)o;~QULBZ`--CV;(38tLG+%7=}hOYg;uaJ~gxmF7W@E|XebG*I$B6QLuI@nap; z{e~=R(&&yBBLTl{HaQEBo;Z<#Rz3%|E)6opWTOaXW)={!5gStewq_eXom(?u?P_hZ z=j8P9>c@&auD2nfKyvd1M^|DCBO{;v7B@J~EDRD^^t?~%o5-V*|6Wq=@iDLZPx1Y~mah=##(G<1pCzG$reM1~Wu zyI!&phE@6-5lM9jQCoIwZZr2HZ*v=0qgIeu;l`tSch9usCMp+bwTAiVr&krvd6O9+ z73{wcFTcKHzz;9!U9Ur<_Rj()X&>Vh?_4T$rCT*{aO!BVeR3>NZ05&Xe#BYXH~+}>@2H!YnAm+7X>~t&&b1Xb6w~d$J6t*Dyy7!V$T zA{C-8`PfAEo}31H1b7+_R-9brO{UeP%qrm_XB`{DY>V_O?_>gJ&sj4l7q7VL2cmEQXM^jTWtHhGSSeOdXMmu@sOCGNQ5ix-8p|< z+RMmJ*|FF!3`nc4KyfjjNB${$=k^pW0b(l9?_BZvawXvxRyJfqwvFf~4wdgsv* z+k28^l`3}$(z+w(K_?_#1gZgKEE`+e8p#|OWyt|q$14{mm(-1Q>qb`KVv1U zn1V-%-(o9v^jT<7+dF=;ZX}JesnJm;d*A-rim1Q+)tc_&*kGXt8SI4;4;DMMPT4S ztbcp)UqaA4N~JicZ#3@%ke<^)SB{SdHmpS?0)p3utpN4*zRd@lko#HgZ8qwDPgy>9 z)D1N2$omqpTbopeWoEtSf9CUPqrl?{(IVF@;bWs!n!DsT=M>y=cE(`Il&9-Lf`S}R z?gwd;^~Hp7oXE*BgbB!to6n2z8Tvhop#2iAJ;(Z4yW1SugDXHNLq76CHEqOJE?jF! z4M*nv&fXz$?gGU!vmL{9(|-rC0b;AcyNvuUOQX@E$pcv!NAXT`d2-AWDNf;NcYQul zZs!^|5TPt^bfdsu79`gobFm`AdqO-;>&_a+Y0X{1yk6${B+qrv7us|`JX+z&-C+B~ zy+5DwdP0l3H^l3(quwhB4>&?Nb#%#ffJ^PfOo4X@ZYbHWMg*kszz=}W*m+krdXh!ozcLO?IxQafTwGifr+7&+ zNj;h|+E8W5?(Xh3sP+yBKr)Co;M!7rmYWn}{y_P&)c$>7UyPmzdsT7?QC$+;Y3!BN z+Y{WjHhh2wPMUlCZ*xtY#mbOCHmrn3fEfCu-%ak}vOo$IH?uO%)eP{x^*E67osJar zM4EVqD4*z^g9-ljmofMIGu_Z*&8XSBT!1=lv7Vjd05E z?pv=b;?MSt&y;=m3+NxSf@&{;z6j6S#XMFq4FsH3W{&J6iWlP%1bMO1rj|xOQSZm) z%t`*HCQ2{9B-Z4iG*vq5r;ll)@^2+nA9-3$n=EJbtF@D-KmE(2!a6PVSL{`u&9fBu zg6-kqVL)0lNFLh%kF$E)yF7ZUE&+IS~y1!X8p_;FcV7o=m5yuqlUlc!ZC02yw4Pu%L{1#lzYN`Rm{f zz@Uscg zK~~_e9!d6+-|?S!$e&_z5u&igN-Sr5+L@$vU9mOY&h$F8QVUPU=0#mO*Xxu37`k_B zBg&|L-CgAa$G*6MF{PG!fE4j0H?Ud#G70vbptbiSm$CJR?(CUn1m45k1}m!xZ}Ub& zqCXPzSCU?3Aw92|KRiC62*WF){P4b2Ki{~F_EE~%vqnO-z!C`r@!a=xOpzCw7@}e;_hlo=qzmEohI-*rv6h8G>{}i zn1iNz*&C~tYykk-N{v0TD(3lAcGoSuS{ z-zZhPe-wXBuD5Zqx%oz1uMM|+VdOSasmg>WFtLtZlK%2%Ph|I~)Q3jitzIN{@x3u# zit#)GVdufvK(jBGEZM@Dn`WEgZZcNP5@?84=qOegw`%^O!b;X)NEB!63k`^|lCyve zAd&TYsA8X@nH-=I9PzB{WejjvfqK-pEL?r-2*#=X$Rqt5P{mk3TfYV}Ohu~ZdmVLJ zoKzHKB#i0hZ7wBr45vrcba)hoE03HizgX(^g(oQd?serv>)kqWmGtTlhE8u6+pZT` z9`2u|eWJ}tXLwX+MxMD5^o;VQl+;hM?bGmvb@B0X^(;R}k=|@G4Or9*{p^3tXq3_0 z6mD{Dl;@7$=`}@|9-%@Eo+3-7nvXbbWBOcIdr2pY*VTIqfEXyQS>wn92 z`)Kk{7T1H)k&)wx?W(Qk_tiOql@%iKKvb+(hAaI@Jb5y4-F?RbTA8eG2{$^PzWaeK zoLUWy^Wzp5mEC_{@)5QmGVF|V@@_NjX1!JI$}sdB4RQ7vzEN~?b!ZtGIpcd$bk)9J z)>jC&Rr-tbc(c^YJXOKHUa~@!29>HMNbP&kqi-mrH!a1=jJ!{IWg_BHlbm{}d2Ehf(5~w@(Z57)#!txc_ zIK$#81u91t#R^O~9a+x(bM4k84jyZE)X-G#;)2uL`oL)mZ}Ws1-*oR2BvPX$4YX_j zLfP4&GpS1HW8Xato4E~~lgBB&Re}hL=7?d_k$i=(cl;N$B>p@qgNsR>(wLXVkBc&y9*ie*tYGn`?5*URdO$I-{ju*9^pPp{kjQ*=hT#A%df?lu2OI90VX{-UXP zQur2M1Se6OkNy2%yve=y3K0WqYusN~T{WV-ldkD%yJ91L`ICF8h4e+FY`?JwWu`nW zacueTq|3VZI+|RV7$Q|Trn6NaJ&9JuoxO-$;LV%ZZgDBK!S^0 z!Wx=u(V(>oO8s3h%3xrf;--oYx?*6m~ZF#O4z%fE=bZ|cios+dd6qzD59I<6J4TRs^y^*KR6?2E{j_ngEo9OCXp*b|U`-UyMKm(x8tlcvxh?MDzx4D{I4FM+|DS^V} z9rO7;wO+o+xUhVA?g-B@^V^uFtm!~)HVHMwdBMa501G-s%@+bhmB?<5M$tsMGVb_k z)E=S=ScyiXz@#tH@du*(@p)k>GMXc`8~)TbhS10IArUMN@WqxSS24jvNr=|l#tEe< zMiV3g*74hKRj2co1j9Jp_909lN9vo{P>^*wR}_ko7x#}RQ6^q`ze}-M`FpP5wYPr+ z{avdce{W%qhA|2lR8LgwDq^T1m~6xpSQnbSxx9Ap*+!i4-ai=JCnO}#;cYMTWh%FBFn7l*g6h# zWmzCEf&r4=&C!v8`AhgOM-xK~`RhNaXBDr5Yp^S>tudJ1JDH{d6WgJ`($|mEdGufN zT!hI;L*D^%-ySW(I274|x&vw4%8=ued)d zJ%ZtrO4a`_2*9Z3RVS18Wo(6!KpG*;MM$0jK~ugZLAaC~5hX4ql#1RVhlhRKE43NlUST1*bgR{EMo3j+p6)ga}ny0r@&t6}ROz1;(q4zBk0(b}|a4M!xb=V*O z=n;hs(0`+SyZ}e_1NYf^$)LMPhg!&*SYIR=$mTj%R&Os_C&oV?ePu7a`+P`c9;#r= z^~XL{`R;t}pBDzCiXxMj4a?)7VnLq1U-BWer8c_!C7Q=97Euc@u_Lx}qyXsv`C zl9ZD)WQ0G53o zeDi-AoCd{oHFC+G8HYXrDEq6oFA@QHrV~8*5c^O{Q2doop`V<^m74!aZV!uYoD>&o z4qSzlQe_)B@-G3zWT%AQPF5;K3gKwl3xAUn+Q>&z^I)cp&z@ydPz-`dKA7Ae(ZGg*kSoD{9tJ5-n$r|ubpQg z_aDpCK*3BEINRL5@}2|50V#F+40CkkAO>xaz zclUF!4y0e{GTF`r1x5RsfHWKN=<5i zW!l|@%%AM@KKKZ#L3Y8+2%H+us_`S$gEHJQPpo0s^=+h!dd>41aFLYHs0!LDNw<`Pmh zdnPE24I>4cRDIAq_`3~rRlUl)fB=K}Ek_ZNM7jADR3f;R2Q3AmLVGqkmt*U!jShV3 z>(JYUp#`$uvK0FVNx6u)&3@D<68>yty2Y*`MQ}MDkl?`JsoMvL;|QytH+%zvir|4s zFY^cT{(IaK5~E2+QKst5_O$#m&_qfC}#_5r{RTbKqrKe64*XbEqH?7LLk{Doc1IWHdW?p zU4382k9Gik&q={=Kux;0VVoHUhINdcOo9^*M3LAg*f&rrcnoU-Tqg?B+%L^8hVx^* zZ!RG&#uMjV z*;a4yNYc-WwIDygYN6z-Id>0an}nVs`Pem()#1Kj*gg)I0vUtM200OZM+*bPH?4HL zg#(|P+kgL=4>Bhy33^R~^EEjC);aPZG8AA+RKa0G?vprt;UvXh)Y-`;ae-#{t3o`t z>W>K*PoZ`M2`hF2Iu1e{qJt7pAxb$;oky&sVj87u^Fci^KY7;2zCc6Q-yg7%ev#}4H|K#sCK~c=^167o#`LpB?^Vrs| z1D9sIIBYyD{yI{1Lwp?N(o^W#y6)3S2Y9tUQ^owpxiOjd&n$;RJL?L!GwT9dR$6PE zpmv5(0Ii9Y99Y-JoQhlcTdabYz};N&ss-C@-kIfaM1ljP^s%BTrUTLlgR5_Ej|?dW zzVcl=Mcmm)g&be{c?2=Kiq4%(tid(LH89iO&*N>(wKl}b2Qm;Y@irep+s1%jo`!hR_8t4eHmyd3DTyMfH~A)QHcGhHS z2>dBSEk^q^fv^3B$1ct$9!G#;Ndxz21|DVZ8n4Ic-+{BS!MXJ`5;_-&Xd-$E`CzXFG8+>xPhLIVBtb{ad{1UOoN3Rd0&tQH!d(J!M7J3o26gouE(-`UDuGB z5P?Xeh0W{xk7imd|7N;fZ8%wW`t3LL9XH&yPpn+G-uc`P30MT)V(mgLr4H2zX+D@h zGq8(rPPl=uWVAIe+2$^Q&3|io(Xqb=#g1lJwUZVEO)t7OKMeH?yuGgBvWGM}wjR1Q zGk>b-1-lG4&?dAaT&nkiLhl+6{e}TaBy-@mowG#<20#oyp~Su`1bj&T>7~LjHNlpa z^~$*r(ZX%5*SE)9*UQxw&14Zxur9(k;jCx#1wlVkP2EB} zJ57=b{Q5)wjQquWD&8I7eO&Qx1_sT6{}M@hKJ5wz5MT}1=wmAi@dDb*Z@bDG z-}^uxs*aI-{crObg1-Bg$a>)=743Z8LYBZqp1>mmLuHq&hkuk}MdMGqh z+{=Wob>-j6>(dzKL!Si1G3fvXe0a5uvAix{xCqkvbKXjOa6a`>D|z+e^APQ4cR+>s z=dTqwpmH87qzO%p>lH8l5&j%6^oQZ_=CPlY1uqThk1|?P{P&q+Vb+TZIFVI@tg!x0 zGA72R*y&gN>24kxMcmBzxM`lHQ!0I{dmjhcz3g6i|JvA)8=ESPUETG{L~q$Q>Ns=$ zRwf>aEXC0K1_Y4I=ZQ)ZyyaT=&j#pW=AVQ7fl(=?krkj(Wnu)C$NbG)b%&RlJ*GF+;JrZk6PI07)U57WH=hm)G3vaUS{=9>*U#tnp9@$Z5 z0$Mt|R+ANj>I_6K65fL~zxy?D+x}#}E)M3SAj#Go`!9cuKGsV?NzAPU$T&YAtM{C0 zQ1kIQnasxo23{=rn3nBcxP@H!_8e;6?T%zTN2nMM(o8AtyImuaRSbVxb-%iH3O$Is z_{mAA+}ib)R%|{wezUPwVb<^$!_dthVjnao=P`=F9b`%%8WVd(MA; zq_v}ezpgNUvw18C!3Zt`@x1WvUFh$RZoy9CjBvJKO4G7{?U%u+bziNzng4AFjEDYI ze)Z9=70xMuzHz?!eDnLk_;>;E>8|KGyiu5c`WO~>3b6E!VnQ5lzQ1|K#+2IU8?tTs z@7l8Gy72F_yAAoLi+-!Yfq|P+0%HG{n>riVsubT}$Kw{<^!BpmkXh;!Rtb2pzV+*dxeSSDgdkPbvK>A4P(-^ov-AEqEC zZ+;CfT?hC1$!V`YUlp*TS!&TqP)?!pxNmD=(Q+PN!i6s3O-KWkd{_cQs_Sx({hZXC?#IFM&e(Z-txRfbyctV9sFY6KhhPb8V zCtxQP(8{Bw>e0fOrnhTnb)kReTI-mUHS}mHQ(>7*Z*#mP+5UumExlNozl$rpY-#O2 zSbzGr&vNd}OVHsWpu4nGv*M(`+Vb`TvtL-DkK(8}P~yefjclRW{*a`0EHT{zrc; z*|yn=V|};OuGjvGZL_iI#=d9EiH-dU0bFZW4qs;RpA`gZ&ML*QnNr>vhI;?MAj{Dl z5>)sfO=lez<@ZH{A43uskDhtb{- zi=X$=hzl-bb08`?3XNGZm}6>~k5lbuP}#KJr%Lw&4Zf%g6xU2e=GhJ4@NZ{_Ni#Fw zZ;5k(%Kja}ODTLJuYXmlj89)l@gnq0+YFX2hnGZl&kS~&%Q)Dbnq zLUE_3{+;j;3+wDZg{7rcvA>b^tQ4tbZLU^uq{x#bd!COIA#}5#qxahC64OAQ9s4La zwdLLQ4|cp<9Feqb?6Hs7PmG={PJuq<@_-R{;9QYZal#}SF?&%-7iQpd#S=W`glo4& z2u+gsx>RZbppS*8w%R6O6wi&*$lMK8b2#(PmRR~M-1!&F9#P|L&&3Bj>9l>@a|_!s ze=)#6s^-Fg|F;Vmb2^w8@F z`VhklnP%_1+ptK&DiwTyx)&&)IU_(F-u&L{y#NI+SEPRlM?Ml^uPG&hxQsGPFhsd& zbFBa7^V-$T^t#*4d^Nl!wRlf(-82^A%ek>GMdQ7#fNX}aBPz>x zMI4UxL@M?#P>8jDN0z<%a9+p|#~X1W#GZzNny;a^=*}4gRw{*oh?eP}9j2@F5j`mX zym4!hHbK3|2X};DO9G9@C zTe<3Ayl0p>5kr{O@$jK9yHhw<&5&+x(i zHa`qbvU4bri<8Qc0S$#u{pzMie_W0)*QyPMI)gyh>8#G?=@5_96DTJ*2iyNz_-`JG za0UPP=W5@5^!^FKMi9>WvV@d0B)b1LKGXNk*WcCse8nPTu6*WLbm?TrV3f#8{Csxz ze!}p&D`4wD#NXGqePNO7IRE{l;KXp&91HF9Q>3#ylV(Nx;h<(OYMJ(5q16&F(m4%P zW5g{d(uG=>K6%%GW^dUVxT-J}Dx}zrvKD;2K{6RVAcqFCtoyWE#Pm5%qEknmgT}x= zpR1(1A3mkhWv52vbjSTdIF=32>;yofiEt$SAd%Vi(F=DOkQ&StCJSVz2I}t zjYhHH@W?)yIOwoEQ6oZ!`R$5Ukf@`_>;thfXVo+R?3BKT;jSeUqmXXTx!od7GV(5E>Ng&Pv>ZqF=h%?>sSiBNtzzSDF!Bvd- zZP?P)%O&UA?xz9wo3IpxpKWc-&={#+@zZw!+X1(<4ni?vGf-^`G2c^MWakI;q0_tCsLzSC$C^D1g(dy_9G5jLtKfxv1B|>vpKqhj`(q=DV`TFOqFJYW4S0onb zXoOpj5?p`2h22!zVvUtR`=4wF}m^VJ<%I zXr({}DEz!(p}xdgZgFz=$RrlZdAG{-MEtU|)WQGcorBN3hwk*>rY-;Lb*a@$c^nOW zaJw~V7a6PV6ID7tH{~VP_mJ|2RQN94BoT=FQe)BTRyg?GpAdkvdu%U5AUa$x{12hm zcKSi~s%uQe4jM!Q6@{IpW zug#R-yngfiqNBE{CFP|RZaT6mld!cI=`!7hkzk2^G_Cf2GsL~&U1`)*i6=6xycJZx zr}5%f!vglUBcmIGiCoXMBCU%;EuSh!x=Mw5*`w|{P_VCDs2{XiIxat7?X%>3RPwmfC+x?BZZ!yk1v6~C9n z>+F6uY(W*97giWzYwZ_OKN%lwSX8l25LwyioOq!21u8U_c*zq~PF-8{K`mty)-^O_ zHfzm?OD~zIVNd#ptmv5mk1mctD1Q|wR*EwgLfOg>Zh*Qss>eixhU=?5c0rt2;LWC& zA|gXC0+LS2-1SKIAgv_*1kX%6G(%Vv@`n-6-Sox$UXmh7c#PgRQlT-!&^pJ)buVE4 z@S19(y>`a^-e`e$c&qe+AUaWKgbs0HjPbN5WxePv9$q6(?e55p8SCQh!U0)@z=9C9 z@&6N&bLsj#dyw1O!wZWnFDT!&N+p3J%&am5WaIjrI<*xMQ@k*JE<4?r*nrXMyeSMd z4V-9hD2dZ5`+kllv z;H{tK4?{3JGammyDxs+QgtR#z`W?~`1`YqwgVX8 z*Ivz%bzD|t`s?Uv+Uh3B?_6Y(c`2?R@>T4J-JSB_Be`M^s1c$Fc~Dii?ar(zT1?w_ zXdtn_a^{y!JMw5tso-}KDLAyE9mdcC*kg%VpGZbO-9vW zKZU*!k01}*rx2y^KY#3j zvWqx0Zp(Q$Nukgr_4o(oX#4fl!TVwBHvjv}ON97Y;r$KRBM$CBs?nT6hOa7(=klYQ z8y@OGPmUPm)0C)RP@3BU2XAn_9whLeZ@5F18)jytfAYGoQ~OD0`4~IbeIChMR-Ruz zP{M&&^lsBkD&B%3t^7_ld#leqb6U96W)jP7%6D1aN7FysvN)e@4zF?RiK1?gtof`P z2%=UQhw?aj>e&%;c@wr=LlH*lug`|B>+9Ljg=4${grbn~9~8EgNQjUy&tGvM(_Z(^;L%bJSz zUZ0!OCV|Rz6APg?vwQlWzeg9F{hw$9*gg}g;2TlruVS#7)RezqSkMmuO%a-a?*mqh zv7~X!?n=_Q=e_IWgYqRm!)A8*-YM-knhT4ZLK&YXP;(nS<#U6ha`f`059srACciu^ zuI304Qw++yOx42v@d;l>WlJ_7>n8y=X3T5iq6*KBtOr^2=#meEzNWVU2Kjemcv((S zm0e-^qgrXVd3R9Zi3A9qM!vO7H1}R`74|zFw1*b7gzu*D}Ot2G{NoM z4bc#;wP26x^Z&Q7bRvq%nQ@V_)kjhO@4x~k@q)!Y1J1~JmN=1)VYY4e3s?Py@2*vX zSKIH?Sg!xo*-Y&D&$&>98mA_irF5@&^^C}jlQ_bFI z&Ml%`^0I0JE+z5N{nG0_eY8sA$3#tT@~g=K#9;FMbTnSKVb!DK#&G+3Uhm@NniF%( z8F=@-AzeK={J>BCFQZiB^)(CbS%>0xyVO(2B$LM?_qipFEM#z@z_y@X& zs$C@K7ZhiIiyB2?1B~-IE9Y9SO_AEW};q9_J+`gY__?H!)V{?s1F&g}@I3 zEN>=R#MZEPdP4paKj0V!o?IYn9v*YM`(4-IcN~ve+ED#TXs^O)(z^D%;&RHct!hr> zCYu1<>Sjb|cKSVU%@i(xn|l|gVp?x!mcsE>9qEc_@87;V5cgb-SibaB$e-f=np+&j^EAFDU3j`$%J_T5_7^OpSFKHP%SvRR?Xqp@g{TVs>zmrVy^&_Epr6= zh;Qy!#C>mf3Io_>TW8w#T`K(RsHuI;hE$Ne{Y8sza9DSidf{&KuD9gaH1A#M6OQ7N zpS%kO2lv$p!_w0>tn#m5hU*h&yI=ix8`d|6L*{<*z~1Lg)PA?(9hzvEKV73WY`It#RdUG^sKtH=13N zz)0(r`7 zP(IipRn|N1<`t2yf4%2-s12Hq2g7LnE9|(QJo$-3tJhpEa{49TN)vTS8&GqAGVIu! z_Z{*+USGE;P>aYB!Ht0$5IQ{}sOzIO^ndm%PjLbwt1+~(nOJc5m4#@{Iq|1$2JT!GXW#Oozr_tM^0Go1|vsvloW`Mo#7n{(lWBl)`VOI%uG~ zNTd}KK)MYKIAaZcRlsDQBKA1~XMQg?^L9XK_d3I_<9K=5F#z?nJ%A=uC1b1O!soa5 zUN~0LhCx%c1z@@?`8nx#lT?Y0zJ|4w5GK`y|I#fZeMxy3+xaA1(DRk$4aO##zQ*C> z)z(O8vG7mNIb67BzE#weTe@~xZ7a}#iFf|U%Nb=K=7-16vHm)WRDJ$lB%YJdwOG*d z`cCXKGnROST)2sm5Jl)K>L*i^*!dI1*fGJrALQiDfYFJUa@hQ}gr&6w9<%g^K-@<( zB2xl9lzg9)!rt;E&>v8LYK>ff57vTYT5u9@Mr+QpN9Hif;xiQQMs99ZbI8w}b*=~h z@X*gxgR%CGY|UT&@#$d)dkbxfqB!alc^s+93u4Dvj@27%3_9-1nKN$#jc+F(aha}F z=`|gj6~`CsG#l78Y-|iIjqT`(iHqOgZvF3a-+lujx~aIU6W5qQ?Y!)5^(5fr(>h-xKg(>uB?GIoVN? z?=b8*uj^ojK*C~0>q%K1{(Rw1SW&jU8B%98=6%==%2tD68q&`aTWKRIwwVN(!jN&V2QUiW>#z|{FIf>{X)f$4Lf67zR ziH|vB|L(0qz*S%db9KX(KZLzMkI9$M)P@Jw^W8FugbdmQomlIykK`pULziCoF7scG zySIpDj;;yr10)iUUJ|bzPfAeepNy)Z{I@B826E z-0uzhXQ?d@?8XK{zCASlyMOVBG=j%A4su^a=Wx)B;I1hvJAmorz z$m6xOJrjg~pT}*-(#>MW;pN(d{ZJ<8?i^gSKzcymQ_Ga;_zgIZr&b$05B5F{# z;^O?D9X#)L3Dz!S1OBR^s;wADH((CJ)3x%DE%EEzimP#2zZ{l(L)z;v>rHy?_?+#e zO-G2>?-R8id%y3xjOAw>x-7Jr$~2hbq9$Q#8t_IPI0S@XW^|m4-p^&CK>b+~H)ng3 zI&)jGRza7n@Vv}_V`KBr1rhkjA;0#~DY-gqx zGE^{ccNXJudll>Vk5=^J&t?~G5?%Px?PhGa;DPVf{hK8rlB)&5_HkZyb!JGD3Uo(fY6&+HFt1>ZprZR&K= z6>&uQOPvH&&8=B>Z{UUdO9M0#2`U$HViLVXfA+Sba~gVU=IL$SU)aWtq`Ym5+`W zFcB}_`4bHu;lA-%u&dwz=YO4DSqYxTA}@XyH%KpkIRp&)R*(@Zp7S@xg+l2}@v^tS zXYPxY0;2iNLCg8~gET9hV|%2$ASGyCj+YvoHTD}L8R5?=G%Wi1 zb_LpYV#Thv!90$6>86ul(E0@!3HL2s_Qu-$&X6Gvo!`^=sjP6)YBloso$&Lkrp%V( zAc9u!fB@I4<87b|N6?~}_~RqM7uI?d-Eni+mHAAF3&1>{DM#Vc8mjbpL0&ZeKlN2>7 zn3N{4p_Uov-$9JnQICnux6&aHr^XI)ZK2jm4OdBmCiS>2%+|xuLC{)mJx8Gg*o zq0jLYyBpA!=@G;oj)Rx&O3$Nb!*pL{UH-k0H!FDK<5$R-a$TD-O36TBwm=iuMEI?in_taJ*?_cnMQckO51)u2w>4(=W)i8wi*6x@y+^pC6X z&@5GQutv`J^fi;tllEENbt|=A&sp4DECtwcJL2aOTP4X~tut>lZLPn~L>yekD2X1+ zn5AZf-`$=R(q1d?H@i37Gz+w@&`zFlUEcQ%s&aCg3ZKQsE?t&r-Wl32To+Rbh#mC` zur*6FOw`Vs>ytsEx8|Vq0uF-?cS(93oDP1w|9wD+L&bnHhyp})LP1j-Q#%(K+1L9k@qp5; z=-+!bZ5ewv_2o8(yW@IYhpD|;uSq}mI(_RgA%YU^6$iG2bY^kL=g&XRDrPDsOX`BC5^_|!*_V< zDVg?ZU|RB)n1@7cVEMaZVVAO*5t9MhCt0K_&bpMWe6%Z*?#JtHG~8;&7yslvf5yKh zGh!k6y~jd5TMuq11l+Cyv8SM$8ED7-FTJh(r$N0Pm302D>5qarURVa1aU&l-Gj8w( zPg%(~Lx@O7P~6se&8T&T1!x@LES>3#-xMp|-PVk@JMah{iBxeE?{=CTJq`<7a!5sa z*LhouaVaX+QV9$eX5evg@|WLyDNhry=SXF0axc5s&P6q_Yuj;d^GxF z_T!2fIdSMk&ruz>uV-DgnK&9vEH ze&X6rH5XRAn8zgD8p{hLrl22EYY68Fa{;q`KXqHp^&v@L`aQUtX03@ZR_|2R}xnZm)uYYa%LFw+1 z`3Zn^iY^i80V-6CG59Y(OIO6KnbZ`MMjb~P{>tzdMx8r=6L>~<`UkgOYdIxsq*Ugs z$ZJWUj|X`szp`2=Zn=qp;Ge2_${JCle3Z>nKWAHj+%c&FVtEl7o77&@b8v%@AU>eM zOY-z#>O{k*kC%Xc9%-k;4ZNj`Ldx~FQv7-2i4!P80tJ4`L17MM_8jI?19r`WC}>em%(pki9cd-e;IRcfu;n$&sC8Ah(UD{u0YCrvgoqCrMxm9cy0KU%G`ckYAFP|l{0{I=tI1L8+yM4h(iRr;1+U`sJa3Pt`o#UKJ2DBvD*V@|!i+EH>@U;~ykbSJx9JC8Lo`uC zDCd(Jai8i1Z?G?d&-EwIZ=!wx=QZMg!le170Hc<&liR^vLzFnsK3nX%5kYrcMtd@^ zC!4KE*PKS(7LdrjIverz=Clof%C&BRi5*2;fx${tMngZ(kke_J0FZ@{gia;0uif2w zcrDUuSJVh{p0qC7)0_ZuZ{_&OFU)s z%L1rbejt!2d%qev77+lUp?4p1d+zk+Q`3(Lji85=eR&_hKO9HDz$XoHE@q1ka;c$n zY>~lF@l^1Je#{Ri0k_0(V8q*rNnBct#1XQ=zQA{j@A=(d~f zznDb;EM4dtR$(E)bGhu*FYI8Ynsbn<=-VW1fL_Wl)1({nVvhruNzYsBWqi2FYv{3T}3iACn9Aw^VNENPS9^_Yw>Gqr|XQC4GTF% zxhylh?~wRQ4S%o4c!%%&ZUz%$jD5Sp#BVReZ?wHm$6q5biD2ERiu+QBR@D7c#M+W= zDyoN<%ixS{ZvH8(MhYKs*hA*P9}V`pno&jD7M%*ssGe!=ZzUyuOD+KA8}qzxpc-^S zyn4CW=Ff*z0k%S04e{#;-VRi{YLpB(k0j_ZwxQxtZ#{_ZG%M09O!{`&gh|8!!L1zkw~Oq zjMu=NdX`Mk13uzA^%$y{w&X( zWXx}A>yGhQSX4ARrwI7=60zXf<1-g`xw#BRlo>=EDPcK#F})uO*h}rDmZ`GrR}(6( z{Kr36*UT&cEQ6qIJ+G~<2Am{+ZqK>bCR9a7W5`LaZ(u-0TWU?w_&dws9=|q+X`8(r z|0KuNs|B~V0z}T3dCecEZy_P&P>0tq*cT$*RMr>l-@q0`VilD} zVMv{_NN!M}Pw=)`@pf^)9ICf_4{G)5c*c~`E#qzS&MUC>(h9UWHr@1flQPY6tfWkama zF)ft)4mJ1|OzDKLFYM=cT$0%#&dPNA0KGcNf#@A0S<_{Y;kQ)tAvYiJ%I{i`N~6ozQRZHj?YI2g*kcD z+tJd{RDYNqu1yw>aRI{II1;(dJ@>R(1C=DeuFic*$PJzcuj&`ss*p~5qt`j*QELyn z?CW&GEkcd^Z$3*=+fn~BC!a{j-@oUi?3VlYjY3WRt`Nz3{IDVA-XnB%yabyGY8K5H z^+OT~$|K<4YxK$?ka`c=^UJ5cVuocJA)SFoIi?1#qmq28e|udY5ktn;Fw7Eim0`sy z&b)b^hCpysCH%&R)n})Xzcw_l+RW!l4 zTUYfzj#BAKT4*pm_f)$SII^n^@6$Jp19G-T&@uz}<`)e>`ZS_PnR@8h4Tg zP8o%lkKFLIIeWM#>@O~h3kNgrcXBm$?>m>pV6SI(C#x}F$koQ8-OuTLZ(n|uA36@s z>M*EinEzGnJ9Io$Jy6|RV*NXNmKQ#iXBAgK!DqzAI=@Gm?N9Fg+4Esnc%=|7@Uy*; z&ENGV-)ww81v(x2E7niBGcS4mcV4Sua$v)(kh``#d{dv?E` zjIv!W01uCk(TdK_x1yS?TL$;dpn(KiQD-G3TNp7>!B7_UkEKEYbyxIq&mor}jT7Wv zUUBT787SGW*DOQ|2?}Nbf9}PKQs z?f4rkK5clZkVF(%nP*tUtTmVC?rJ2#ov1Ceqv@Yz^r6hmcFNb+3&_y5xqgMR3%+@i zE2$Tui>akL8HgHepi4V~rhfLs|J#RE>-st{nOHI8Z>OoGKfW+W;s;8Mi4r33nL(uO$4nt&gzZ@|ZEQdADU-|Ag@BfG9fE5;os(58+lB9;4 zlZOH|f}gl0rFKQvly!Q+C$p=M#d^5*X_WOrRM{UNI!lqlW>~tO56r`hlTU!Xp8D#R z{gg0R_cxiN_8-w7jE3~~%;`+u_RqXOZrI}X?B@=?`xfEP&=5IFkM|<9Vi$yhr3uU^ ziHml)m)(Hd9+c`N7!&kL97b6%O52&CV*pdlkEh4cW^n+B{jmKHD*W>d|6eaZ&DY8Hy5wt&tht zx{?>T`K6r@_3fCv;vbGNUT+pVxS$%{ZL)7DvFfmHjXqNX505#EqUNc{4Q zO{@bn1)D0g-Miw}z| zi=QOH{oMQE+z>a|eVAm6cXcu}-Skr-sWO-tU$=;%d_hH##1Ac_a*SHtS{48+gGFG1 zLMj+$M&^a*>^x-)9eOi3Cf7}wnXB`3zaaj{GMe5pz8USIe)99~98d0NicbxKA1p51 zK44YMM-Bqx2h{q(LEay?_q zGF5v9rY|7)G*DrqVdrB`P`qC*Z{-ygjh^fuoumh+f%*bz!@wA`;ga#B|J?uqYreqr z-;EDkIcOtf25fSkfi1rJtWS{S{S^$hZ+n3^UB2JID%EtZr2NBFvaJRj7>x^dTK&^t zNsRe9qsK<%AvGPyol4T~q;4O!Bqjq)j7DS_OYNg9hHPH;gi8u^q1z9nh-AHJ=MdbG z^9M(anT1>NOspH-l{k!)Q!|m1C&#ae!l$YNkCBvW6saA!Fnls_rpC2hkQ!$eDjrUc&b?`z&&$Jnrcp zD+&iLOc4flTJ@hN z%yR>aR2K5w0_R_htYfO1vQQzP$x~At*mueyViyqQ{(aI6|FB2=lG>`I8OlZ)Ml zD9=$Gs-mZ-hejN)%^mU@zv}D2SQtPoMV|k4#po*HC>=k8$nv|Tr?~1+h6<76>o*9B z8+NVHePie|=cl0H$oP2mHmWC>_JiXW9hej)dp@|W{!vUEM}$%57L(OA4j3r=tWph{oF71Fbt7?oh0{xz+60|LmI;FA2TX&d7>%1uh<~mcqdOg^7GyU( z-qlQuMh}&AA0Xox!gvaAP5WBd_T|Er8mFX|@}#L|rp=_Hngzs|L_q{#UEI{KBO&@T z3dm`<4{aGBEi6)t*Z65oF^%G^Yua$=Iz^j>E6K(AIXAF;?OogeH`g05b{{zV)6xOS3usSskBxlb@WO2dGbP*hcdd7MWA4P><3?j(N%|s`4p*KeA-*CCyzPt zJuujU;??6AJcjtI`@Ub^~oj4ezN zkGsaW@#oJ4p8&|{r$j)ElnZcoH`ks9P){3l?+4D7eQGUbvM+cCT!^x1(d0Jt9eEiU2w`BrE$-A-QawkiLF-kYtX`Ay*noOydHBw`7lo zkC72mM#f~tbx+8VCe?IUQ64@}-Qb0RX<{!^76AO^j^i@FyLs@2VW@h;SvIF!kN2Gb zD>sWD+|H26-`fis6?|LCfoczr9curf!c0cfAx^ot!SBlSzC-fnvFQWD)b z^~s4L_8G9UPSsKIW!2VW-Ew{HgIHN$O@hTIEcc zCsrc4Ke;&Tt1D(0zz`(EACfg$QR=L~Z7cS1$m8%HB?2206!YZ|bTcEZ9%VdM=zr@( z)QXG9^Uxq}%-SHu>083a9>g+(Ojb3_IL4Xo2R#n641Fa<6mC&LwcbZq5Pq@Wmva{v z7SH8?4 zyOUezxW2Vqfba!kK5qF)^T3y^RSZ{$Ut7{$H9Sj2AZ1x?Ru4 z*5?i`yvQl5mG`pzgM?r1KT7@MDh&Nf$wnzB4c_E3jor=Rw9hneUxai&I0$tX3{KITBZA;6sZ0tUdHiI?AsZ)Th?O_5wey>x%Ujq9ceppTEDCS=i4;m{#DH(t2$(@Hv?wjR`xC~N0_e8 zKYhEnRunw(Kb@;R69e3%gRn08m`{1nF=XIy00K#Q^%MG!B$Pf@>ThW`9Qh_da0kvs zzK?;E-&;pq@K%ipy+8t!;PC{WpKAO7RzsjFf#nNLi7s5MgkqOdty-P3kPysG!B|ngVBbeb5zBo!3;4RC$_TND_Y6DBW=Oa&?vRu2`3=q%{`7jbg)8OZho8{vc-^ z-Ti+%XGX1NMwnSj9;h3HDzm}*ul^2%ZM?bV>{%Y(BtjS|R-Gga7>f2$76ltPwiDIg z{X06eI3&;~$8=&8cn@Da4C7@hRrZhY8TeB5bW)7i*}AvLm(`WwlRPGRG_Lj@sHlSen6JShr=YTnvWIlzwOP^Z&qPlG;z z_fnq_f%u+B3Ds==-7Wa4{y~uFJr1r*mDacPbfV{h9Y0?7*8L#<{oj5xZUCpQh=kx{ z3~`rmM17v=xF219Cv}=r6ra~$jgcbdPwGOyg`nz%@#a$Alz>G~1vuB)&d zG8H%J43d!l1z#;j>^mK`%u1hR#0gZK(y((zyU4M^za4E8?Ty zQdnzgLM5omI7n;FCStyrQPl8T@nuoV=MD11J+Zu>!{K`e2ei+hs}M6K8nFlde1aVU zP(1`4jg1mIiBBN8ErTOgpFZ|RE z;X$F7)D=C%>?XJhQM@n^Bng<-p$9+^={$xRG}bAdU5h@OvIP<+ghWr(4F(#%4!y9` z6C@0`-bNq)7ekvR^|toA`$IUr?e|_U3th^G!g zP9V%GB=ZCR!}bU0ul>XS;@=|PJeIE4d0;YfJVMJ>kq}fVeD(<3GK(55rubsER7i|x zLr6?mR!6o@K&*;D@5hhBxcucB>=^#R+J{dbd_s#^B~JM?gmX!izgXt#IkzpxPgeW? ziAWn>n>Y6Q%=32SeJUy><{4yW+FHP?mbfOkS8th`TRS|tEyZW0^L)PEu0n%-vt>n# zP$-1*efA7DzKP0g`D}!4o}IIU0|7Qp5a&Mh%x>I9?t(RuaMGs<(A!ySVY8! zlF0s+Jm2QKygbgYcl$WQ`~~!MWbcQmK1;yCMe_facLlQgGf_Pdd_b<_gS~dse>%P@ z$T`$o%`r2T){DjQ@8X6q;MHqoaSAR}+k$m4F&YhE<(fv{ik*J zj-|qvG+%im7JARJL3B?c|D#xJcd~ozcqKF|$0|p|? zVx<{Mdej?Le)kR?S^P(&lJ)V*&?b>hGD~Huw-bQbhZ-j{TImZUZ6ul@%$f>>J_fjQ z17MjTLw6+Bufx-4ZFX%23>D~mj|qNQJ)ZkMWerr`lfK*o3;H?<=HXQI%S7opy3zvi zsmn5-VNxZV0n1pf`WAnw%Mu&qY%w2TN61uSUk?@ko;Xgx&y9(NVlyhDDko^;4;tOrR0*}E#p^Vbq`r~m+}nb1 zbsciZ`b4dtDjWbB8W||3k6wG?Pq?wLaVMq}2CH+923v$|z7HL3etk@)hL9qx@@Ub2 zA@;~<;MpXJ5G9=!t?Nvnt(B#+Hs&8%{;NvnjdA&pN8IA{3j8OT*eu2M3#&DK6JCg&`KUq=Tkvs zC8UA}-k9h&eA<;1pf4M%{-HYI5Mey|`DyBB^^3q@%!v6yAZz4ZJDRoJiOO>|Si zXatvCZgTFRBm%XEz3HlVDz+pF4|uHS`4dUrnuYs{aO7E-=<^UwE#|wwb`|p_($wW3 zb<@A_7A+Y9)!833U1|@Ud%3(H&Q0Yl|L>q6jWUDhLsb}M*;L_hyK8{W@=tmOck|I| z-Su8iQGnZ|n)9R(76+doEFj^zn=X~pT`Sz9CrG5)H8Bezi?J75x2F(>m1lz>ZSP{W zfkd)gdq`$3R*O!VlqolPQM=sK>_d+yG8h*a4dm}NXU-f2rCL`<0xwJE_f}uAI3tI< zJrE;VghM0CVfbAV+n9JOE||;`H+vc@RWu z0jo|g>1&doG{L|BUExHnD^!u))xVmjOXXe%UBoe#*^Kk1E3xxXsSaBU;ta#Io{w;T zp;5^sPAQ1_!F-S*D}P^cteYni?zV#l;tAKg2Dw)Qoa;khx!4=fh+<3)B8rMr8eA2NR$K**-JdB#hD~DD@WbBW z3CKOf(o^$Nanu&%BXnn}RSQ~0l}raP0T>PxNlO0rzeUt?e!M35>!i6nEr$h2yP>ts z<&inx*{o7iylHTk8q>lhgYNMka`>+h9;y$vi)jl3@Gz$EdB9+^F>XLxI>5#%rp7&ZI8? zZK-gdo+Iz3Uy;FH(41Z2kl4YT{!+ObyFRx^82lPZSt>i8=r|=S7eU`)!P9@}?f+YS%(@7AfTT4gizouh6Ha>ygo@J2SA}bo$!kxHva%EDL z^^EjDZk=G1P$@=Nqx0&&r|Sd6^T#8u`1(j&*lQT9MPH$gW5$WPkM;PLzbjY+^OVJr z#Cn}EU^(&Vn;;Hbqct5d+yFylw!yJWLLlX&YakM}!b~#NbKz%A_?=^&_Zz`D4yK*se_A@GgfG#r^vhxh;6Myx6d z2FRj#WQn^PyW(+!lL`P>;Ju1q+RFl@mG<8Sdom_Y6_#wCY^Hc~^b-WB)M=D;J|uKp z_2WaoC2gN4 z17__?iDa#D%J#3fM@g*haxs)9j}{K|_G>dHOz@r;&2fMo-Ttt5mR|pYjHVzWs@6BSN#5BKNUkR10DeUGLl;cO9;-2BXhe>ydM#FVlW9 z*1@~f1bKJ!`6W4#3}`{&5*Y8QRRk9jB}6sXFehO+A?WM+`ZFyHoWo0kIKf_7uxlZ! zrwlJG0&!-s5~xkwMo*M&J{`ylbQy7j9#Y<}vSxp&He^awi5)u&O;T_H{}5YSwM3=4 zJhpEQVCnt+{oUQM&n2nYTrKi2$X5mep4P5iH8mQOuT%cF!nl4vdhzo&FS2>sORGS}g%e5K+#{su`QmTKklPQQE;g#q3?$>9WE(ZGEBH@?e z^V)I4r~DW{_fM|{a-(_}3>-_;m|is=IJ_z_(4e3A@HgYF>t z(401xkUCf+&(kT_4!&1iaWK^^f4`0;9$<#?Fgl^!RR&;w0x>*vcWj-Mo-x|#Ajk&T z;tSX3aw(Coi40LK6_2Z!LfqHsUSo1cjZsMM)#E$@JtXI6ivxQJbYLkg)Pf(w7 zt!?}keNSO^TPW(&WTrg_Y(L%8m5S+VEM6K%a{rN8oO|-$udTMKg!HY(#z42=m_G5( z;0I3*%qwrT?Tt|HdakrhlK;T7x5`-KaBf4yJfo>wXkW4Rq|;b9a5z|4;dzo3Z{%p9 zdx|7762z7~q#=HDe&8Zc=~VaNz`vK{OH75oPzF3Rdv5?%wXWwKTQ|G!ON<%XBBy5p zV-zn&ogH(5tLp6UD8k9$@87?36cj++%mjmyzQ~Z^NHEzbZjD1)nQvZ%!> zs-VZ?ol#9B?U-Nc{ae%I_C&!{(|p|C^=R=nDxB^mFR2&?8MJwy5|K}Y zuTP64tPQ7JrJ#mLu*BZHi+GPc!Ys|g8)aOR+icUELta?7=eSK%b=WUl>K{Um^hwYg z(U+^$Xwgz86SbWBAUN+h0eP=oT}TQ`@5Btj@QUXAWpyxvc9}i7R)JafYzw?DK@?p< zx;H<@;tsN+cJ>_ZB3>GD5mK-GRE(HN%v|C6U)*8Aw7_C=*Y_hN(Vn!++CWFggZ{IM zKT~XE`Fr*hhb-&ym?ud_H?2Q}0=`5emPCcra1%Jw&xZ1chRQx6VP?cA*C@CX6&0;N z{`unvUK({^Wx;+iO81JBHhwl`fed4WEPG*dPK?QBeC?w}%A(n4TEd@OFeuv}Kp4?D7r(Md6WOYcoKahky-EC)^=RB%_el-!xDj-Z}RwY6Q+o z>?2{fW(|VE|GvJF$&$)^NBU=yc8^sdRrF;jbPhtL%I=joU>5R39kCm%;3(xZtGD{D z-753In(7mp2JdL!zON9T3r?pU(l{$3VerphTv}ATv7AJw?QmSt}feQo5N0OtO? z`a6otVTwVFD)YeEkTp)W6yy_ZMTOJCU0P`}lZnQMcnwITT9sUz$bA115{g2k^u}TO zU(sM#r~B#NLEwo>GbC$FO=O$({`OA}BaNm@p03>k1`^Vs?Kdiqb zPx8^zhlhvF&EooFTU%RW*H*&;M#e5?w92nxqq6dFX0J+Iua%~Fs1y$;f{c0AuCLl9P@|2uR_c)SZXdQ&q==14D5Zf9*roZa_4!r3Z z6=r|Z{ZN|ED0?#Fkt?Z_j=xONMW#V?dH0J^LAOSSNQSk9w?Dj#PtHG$5ezFhx9fB2 zbIZF?u6g=zxfWrTjHt{db<}Ax)2pZ>Go)y{YE_Wpj}nwLf7@AWEKE*LK7EXlrd{ks z8l|iz(T`Tm@GbExg*;|Uv_g!EV@-KM0WW(Rx(P5XX zqCsSxqX!%rLth$P*$|RNx#Uv%6ClA48GpllAH>Xvt#uNMMYh4s0s|3JEFOo#V63kFB z$WDlI?zwozvO_Bnfgsp8L@>%295pG*7$vexR*?I=6rpaeby64Ll|fe`NTruhN@<|g zVFxH)P81+!K(Kl8XdKn(G;MojXDGHJ1$%hFVwKV=cLz;*29gCvYceWQS_Iip@GN_A z2*?Ti3&aEVNTgx1sia=Yq_BNL!KWlntB9QIz{+mjqQVngw{|i|tGFC1 zEU*cw6?;#A|2z^)9i`;Opg&3r=>LU3u+?rwABxd_u^|lc3`47mLMbru@^VE~EK2ha zkqFP<5~9Y5t|H?7m00`m4Fi&`^Z5Jn8@-q(@T31-4bUFtd9H~Td*IN0+|`>;P+^~C z4Th98h~o7fAf#ou)0T>vLS*ODG!X`Dq#nY9`Q=ZQutl|)S%%BYFnAv!f@qUk)zPOT z42!m`6wzEJs;~2gde=_AegEE!D>R0_5sG{8y3#1WvlZB_sbbUDMKqYf_n0=UyMQnU zO74soTc$$HPFiUvO`P@u8?oxl43+&leB!YdcurLA7^^GV*|mxfWbNaeBEugC;x%Cw zT2L1wvq$y+E9Z>$UNorv=@v^kIiPX61-3V#oD&9e1YU{>irA)Jk^?%Wa@qpV@zG(f zI+3I}dRxv&1flHJk2b7?Hh}z1*#e_*K})`D6IzA;`V~X!g3!irn!8rMhF_XP730|r zaLD4E0Ak6q!HrecSeKUB*VbWQv`A4ijCGE6kPVIBYFb$B5!?&E<|C!{rf{dcCw#Xr zl%(^8%|bSOz>J3!!0G}jpl@+&yvO^Ff;8McO!0T)nzriATa9Ticnura+Zc4MNA=Py zcmYn?Zoy++@GVD9W85#=4M`pbkEmyI+LJ5EJIL|zZ7B6{>-wtSg8Gur&Dm39emI4A zXPB%!*O!@Z`Czx;(jJQCE7(gBMYm{hRY-0cwqHh2E1cOuBttl|?=4JqBppx?#CnxQ z&Lqj)Ak=Y>_xx8sNro5ODC^!BfalW09mGS(VKo&>#Sg`M0@b>FBuI;puwccf$^n4q zt_36&aBt)R84G{F1$*w%51bQDD^5_TFi_<^q0)oX zvlgL#C7drZ1DGK20bXZx!t8bl2j1O1rr$vx`B$ojD#LoaEURnvg8sVAq*)ur_&+kw z8A&J0mTNN}T5H-k=78bJi!H*In$TDM*hR0QbqNmmBh2qWB$aUaPJsl`~P_BC+b|Fx%i(d|9uM)~zWk_XyDDaWD&Os_aO&NnuS7BQqRR-8KZIdeW# zkq6r$Z}oMO^dM-ns^=61YA<Jpo4ap?UIw&}hi0Cu9pVSzZwT^SRkb#h zn>=AWz`}u#62~pAKhEkVE(DbdC8*J%IZS@;`?UeS&y$pIw5z~>P`?fOCIc$iidAv< zxyvhl6^|md1m!itLrT%3voTNMDKLzY$#Jk&qA$Iml7kY3*&=0O_E1$kl&?B^9hmWW zr2&dwv+jb65)J^{sSZx1jsNaU7GMi)PYL`mR@-b0ybBzePd2O#o~Uf!nHEsQ4`*E= zf5IPs>c)xsSQLKRh;o#1rp=jfeKY1@d_-lyhztuwJN1^nKa|`O0PCGZGvi0I7N%KD zzf&u!j|5oSpPE*-{1!u(5_BXs(o<- zuBs;_GNy~J6Qt{`2!puQGo0pPZ4N|glsj`tWf`8yvUK3~NjdE)j2ug>C$1(LRHb82aCfk-jhx1>~POm2dBu9TfphA?W8t}i1kPm9UpOvvk6MM3~AM(VPcJJAH*`1aVl-V z(8njo6rw>Q!&AIR$q~UJBMXP+H8w$?}T6F z9Fy>|b!F%$nN<^~VH<5^s0Oj)C|K~92F{M^Sf+!2s}`0MrnEN|D-K>0?$)Fg)&@3} z^NU{3lhT`bV%*o#xQ+OV%SrP^~YJZm9`KXMaT6@n0}k`xPmkt&0-C{Sf+0 zAr0vzmQOKseHph z!TZg>PrT*|cuv$CIkj`B5P~)f|E)8}#2FNts#l>!mt@K3I_ieEQuOioPLxOh;?{p} z=7G1MG5yY;lZlAft~bQ>)$uYR90xsmn!Tc0ZnPD7`P?`)77COlejR44EI*!Q{XuYi z11~SRi>#cY+Gmo;qLft)iW6$G*ewND1{0u3p1et{@S12^ z@Cs*>-QVX=dcImD?^rEohIoW#oZlCES5sE{;XUn$t^`|FIM3kX>{c;l&Cf=mHr~#y zbIT3bqhEY__fBtKs@I+krVtb;tiU3%T=#j5eY z4nq%!Ajp4x{aVY4F`ofqTxL8#aoiNpt-_qXYsH7(NkuWAryEn_@3QEPm2euS{O!yaS7Tsw`!3jUTZJ$4OzSo`Lr zUG){mhB}J?&_SxQ&lOPd@bt7>dpu~OIS=;LNFpsTgH$p{_>EZ3l(Y?)9Ug=Qe7%}Q zGaj>A4mz4$O(J$Qbq&XImoN{lsbf-|Dca&LWh9)~@U3qkd9YBUG|_koh>^f?JHe-O zNn2JK79Sy6CQ91A5I*}J4aS3pkf{wD0Owc-UtXQ&oH~C-3P+f9rQr`9{>K7_A^=n0 z6IMtI2_Ni*hi7_KbQ148n)^d6la|}_q{5!dqzgc(|9d?JEca?N{Ks7jUQ@NlafIZV zR_}Y{i6no4#Nh=y^dEL-(s;H#rs@3YGFr`M+EFopjhTK)PL;_@KT#I(R-?U0SMdll zqIyS{I7u9qn)@z7^aGF|&r!zRMMH4=S+b5V{Zdwl@Z@g-K^WNTz%Kyr)oVM`zZJ;!af}`nAb+6hYhQO^ zNsqO-*6I`AGF-%5#)BSyYC8cuuG`Uh_JylMuJ`Sk^_j<+{yS;XsKykHXVTO$C|uAo zVAuTlmFP@YqyDcTngjeHa~{$R>rTTu?O>9VuW=_?6>P7jO@|C;17d$KTCt=B2-rPJ z4ux68x;2aNeHE$~UytzPi7-2wS2x)^f0}q#L^tbPwb96S``8TO2PSv z)3uW}C>SQM(tE8zWS{HQ-X87wQZRB1q4)skpTD6!kI*9QlQ<@%LXR_&pbGVh;8WVi zm*SHT#Kpm39o38!P&q$1U_}c9D1S`zhVv(`(6_n1Q~9%o!?JWKNhNkYrm%U6L|Im| zesel~09Ujc^45npA)oBQ)d*oMTJ^um^r6Vln=B}cB)(-7A>Mwij$iCD_>-1-yjR*9 zdmdWSK)KqfOMk?`UA7YKQp{ro=`y2Q?Lt*!n}qvi30W*P6} zi3P~|HR8Od=Xx!4O(mi1xJAIX001L`ZxS5{>yE(`l*GyIsoDH|kj!_2*Smf_1vC2~ z7E6)04u!p@QjFRGg@1spHq3ZyOJ7dX#X=m)UWLPUi&NE~w9Pu~PaHNE7yI%Z|6UiJ zneMX?e(EnJQE)JxsE=5tV|9{LR&nifW(==ESl~EwT*;q;62}bxk~xG~nVGP}?WZb8 z4fpy6==?BL4w^7YQ1XQ>un8CPN z0_m5r;xT?#uC#9mUty-jULocCPry5Fwhcv8Ki~Lljrk?WI8HCTy@olk#T1$mL`NZi3UU1^edmb$3>$ki=&>I#yXOKy zr})1H>OyHP81rzakx+Paiz%hpryoMP;bpMt^o0E3;%22XZs?w4@LXriw(k3SQkbC( z8YVm;#R3pvQAJ6Lw1%{{vVGR21XebR>W{EXzr<~(o=X2Lf2|&EAH8o8owAJgan^|J zp}*^%*A}is0^0keAmO0CbYTk+h2{rC?IAK%-G!GnC|f`Ab2R?)&nHXMpUV0ROj;&=R*6bB?i2hewq+baO zuhtxcS@lD|9+zB0Y2~W7)&_!!ZR=46x(vV4t;tXy3!4H`DN<>k$RB8B_GT^8fG+(` zRO!?A>%*BLZv3BH!9)Yu9v53%7Qn`)LaRJ|icFb2fs35*)4~lyRvK>#IE%>a9}3vH zNh9dtwHh?EUjMM{K>LI_jJYB1@L3va=Lg5psIv0htlo_hWH185`qj3;-@mT?3r5`s z3P+;1DeS**W%XO&??=^1-9=ic0v=R-SvER?s)$`3P#`BIQQiNvxeb3zRgCucS#ou~ zyXzp2Cm9u9@!(l;05_+5N+06>(k)_>Oy-h|m## z{9uRlsUIrwVvqiSGPNrG(X1Ux4XIr^0)`Jfri>P82ivDUTC|NmU>SyvgQL%e?B0Y+ zD@*)~Pqb+5r1!@l=JBQB(&cSH5?%EGEKI_efQzQJ;BNsHeInCd>P(TORbKu24{WQo zWMSZ!OYa5s2-51+`Gs1x`+h%V=h3T&A`RSR1_c74mkWyHKhPV2WQ0g&Xpt1%x=^b-!LBKH^Du~Ao_qf18 zI3MH;G%AQtxZC+?M0RdWX=~m6yY<{D`xYIDW!9RS0O_w{`ECt$I*-tbu}9%5#+XUS9}RGNgL z#fUo!Fm^Z56YT`coGF`kZ~+r-Cyq@v>e?t#LB{Gc@MUX}Q zBL;N*iDiHad3#x*DXB!ijPLo309JE7#oCpV(VSF6h6Y`Iz14YyghX)(I@5@uL) zvQI=%A1k5rChTfS#%M!g=nU+1xCZh>L`DV8=umlLTjnCHqtfQ!igzRknIGbw%9E0Y zcz~(7sit=IsHt->X|wf2-LJ>LOvnq*1-Hk+I7N~$lcO|EQY^524OFDyzY4;>z^j{G z&zgkJ(laO=kV{3pc@H6FPqaxf*5_!k-ZUi~|Nf7r@2UquYcY&q~t=H^K!_VV@R31E^bR ziF0b+ZXb9xHbEe8%HG{3Hi_ys7-8axX0UXr&C>KNb^&5~`Xh)+=u3Ph7` z(X1xI8UyVu^*ECEhnnbMG&{-}O!+S~&|4L38j5FtrJAl>+*%)b>jXs6#8WUSCl zOyAMO+Nh8SZ9_MNEt9;S=SgsBk7tjW2#$C?-6HL#T*6HGnrt@Guu7O~c z)(h}YxKHqPue%rsf|+qv#ZmhYO5q%rA9!`5o|?g5_m?Qc%Vo7)k*-}a}mv{=vhScY*0ly+!?RR z{!o7mp`_|lF|ooao27aa$M!XFwSOfpaU-X-X(mI)v~c>liVagovKAyevc901eH-bA zl1_U{A%tfpFQ5yDm+b|jM?ui4ljuYf$o}!`k!=l6%(Pzd5wTg=Jv=kzEn%t z9jrsxQ6E(+wN{1L@?8(6_dS5p)=mzQmyxITxwK=MnE@l5m8!!axNcRdwgdNlrV9+*Xyrd zfMDO|{+VWDtnCOn)ImwHQCA@#t@)=+m~czzQcbtYw_bxPdiC(3+odyNBYffcB=QKs zq!AJ^kdm=`M1S_Rc}B8|p{xuAzA^gtkUfmQVzqSzK5r;4!0pwC0iJ|$t0v&hkguwv z1Kv)SHTdGGi}SY%w}^&R#-a{2AUN};YS95ZT8c91xC@L}vAqRTNWQ9GDEdSsG~wdl zP1YLc@;j|n#3{ec+TwTv_Zm-?XZ;qKz@=eMr>m3n6I{^>x>DK-z5%deEt<1!r?IRC zm~8^%eE?eVr_w1p^-=DL9V;|7phe7mD*fMh2p~#G->8fi8xVmMG_56pkJHzPCSVj_ zV9SV;s|?GS@Kv*ELp5{b#}xI96tJ?GvbMFOt}6U+;O6voqx>xW6;V16VjeHZp)mly zM@3nBDIzOB7+JoeuF_M z!a5f(&;-tJ^U(9%DCdjB<-(lTfaumC2%h+Wb3)zEee z35s}Qa~%Y9vpbD zl2npIcrlBH#2(efyQ+Z*9au0t+xT{^QGM!o3n9o|o zy@tSSVt~b!ibTUJ-Mxlh@}OMYepBQ0pv4paDJFiao?u}TWos2NUCP@JpTm-zL!82l zbEv}439K>$ly7y{wKFy7EW6hYbz0#}Ianc`MKzI>1MMa4dM_J{T9+)|lH$ZyC>#mb zLx0M#?3?k_9&-UT#LrD$S7(`5=8XbF5{(X>yT65Q#+nRqdi&XS}keIRvwR|@1 z>2aAeRp6^S_8=N|qa1e2d)WVdAM6L)KK1N0R;w(58shV@Ke{055vU3XrQ4ugAkTkK zV3N=c+oYuijXOK?{2>t|rBKt?M?SoU{bHh`9hkX^l#yAHv+d30Q~$oVLDtT#Xi^Phb$5NjcHEIl&l=U)JN60I znRwVH0=}y~Y9%}Ebd1)@VN92z#$+l@lBVsxlOO|vQY^x+A$mVBI2!wif!tFYjExMx zqeWK0lhWbF>crOIux(vC!E;7XCr8j2Mwp{?>envr#Oiu$SZDS*4hIAKipDeCx#Q8$ zi^xTuu}5qpjSB2!L(0_D)RIC|q*q&~KH486SvR2vZu{Aw1p*>rU7Rvvw^q56lf|{; ztFM{X&XnA1g6wfh8lKK;Hu}!t13W6x&Tq;OlaDsn*Ylr}h|=E4wEkc&4!imJlYI=S z8<>3qa;}k978JC0cTKvd)G!fI(KPyt1C@C@RNO(L)uF<|LU31%j-paN!gT5T;$fiQ zT+FQ zo|5EIs+^~ZoN7cOa{nGC5=o&kjCv87o%fXKLsQMq_);f#g_jMVP1|i7>N&WxnP+CQ zCk_KdpQscR&n3$GW+lGoqqnrdx^92@}=4e zM1{k*YL8svTMa>m>}=8^=AelA1x)~%e^?b)^vAWD_NBVjE+u)z>TuN8P-I zzGhxG)jr$^1>ZJRL*;+rt}_tf_`(T1J=s&osyqWv^XhQEG9_MEVz#)r@T9Yu1EJe{T*So_)23gk6FR&j($K+2%*w+v7m+JW59r1e*5eGn~e?b2BY2l2o$O%41V)1ieJ0Ln(@)4s>cFZ|j zT>yZ;Lu)*^!?)tc|8@Zo0m01QuI0yXt+sjTE=`%GU`4~4YPW>^e0(}gDIDV<#X`}U z-1x1t((mxDVk!MXX|3p#mbwpUaaD{uSR4{}m=DgkY351!0_AnMXU+j`n)4_p+^d?e z3%M=+>U8^*)yjk`yHGT+2?FM~SY+yQ%YaTpEcoFQWNK{<$kqzQf`bAB7Z0phW3IF{ zc)y}Biclv{8KVcj9NYF@l}kwfB5XspuTyr`ngrO}HmqauWv zru1h`J+W^XpcSUBsbE75msr9+_DgxF{CyEzWmtY_2FbNq>41_e{oueW64O$ANk_EL zGsSphZo~Pwo`(cqmF?itV-!kCERbb{rkrDzx$ZK0tIj;M3(D>D+fUKqX(;cpOexFt z2xxw)sz_-q!}#0EooJs~zSZXh+3L6NOdFi}G)cj_J6>vd&FQk_wGM-Y;|AYdsaSC_ z>y2S~(Cc8_a}=lb>uffeag_wVBjp}@i`WPIq1qbG!~Y&Hls0JY&vHs!Irdx)yt}%F z3J<%jcv%x==D>m=c za>P@3?kF4)KXA=>{89mU3|D-l1gyCh&YqVhC4gq0#= zBz}(g?fVzT4pNf82 zp(?3G?3y`6?7;~dnL8qAeEV}Sd7pT(#aRf|M#DPn0V;h!Vq>2xsFJgvE%JR;u;dBr zbDZburhJprdq@{*>{8I*bgLt7?+okmKIIPcI!1;;18Hbzlw%ADkjjwTy)zj;K@5rE zSGenjX)SFUeB_BE)?IAxQ(x0)!kA3CvbRqU=)D`ky+pDYX@@^FlzuKag2(ER!hxRn zi0?OCUU%zF;XOlJiy?a3^siq%E@~$DlzR>HQBU(WI&Q4qj4XOuUS1uYcmeP&KS@WY z+@4{AYl82%tBv*jL^*5Rdor>?Z7#{F7lEm^DZdM6Y{Q_;Xy~-Bx~bqXYO`j4_WOV< z%T`xtS%)vU(^$R~nf(OVf9xXOKK-;LB19omJu{EOgl&3ydz&LpA8pxlPjbGNTijsM zOd6Lz%}u4_8FtS#9MoW+9Jgtb<%yC@sWyDh!by2((+ufhR3IExAd&&Xv0C<9U%wtxD0J)`!_YkTdDkb?W>#w& z_{yQz6PiL;>Gsv5e8~n>@IR5k>#!8iP?ASDRGq6H`h8#q(CTL*Vq$&o-r1G53s>3E zE2t0%u7Ej?bgHh&$e(u1KN<1P@f?WwOr&XSmcS8{go_WyZ#ugcg&Lh!DU=soyj@&U zEM9|gd~ELf<;$1k(NcJ4Pxs+-Pr)Y6yZc*yZm22V&TNK>;Zk#UbJEq6`qti@$939Y>FZJb83buWrYb06y6~;~PX6 zB^BGgZhU>==8{*RT-o9)j}#IFf^Rv*PBKR!NyY;(7>3!!XR;Zq9q^X+z&HVw9y6xo z07x5f^~Bk*roQ``xrpaZfRJ_qw%u~ zsV`C5?PeownpeO9P_phM_^fc|%@j%q{S#U0Q>&c|0C#3j?1KH3plhTxn@&Rb-h^!u zqcU`;i(X3ZnN}zG3B6L23-OvK|ToBi++iCS>S{KFZJp`O~X+W2J8uVsba2AC49kB-8-pwxT>+9P5Bm37~r4$c$%WAjU{(cpkDC2^VoCvSllfG;5B#cJ;H*I}QacijhmRFv`CjMtAY8 zX7T-`n}vq|-CmV?B}7@Eiqc{TOP4rgfCE=fi94f@^91Wn~NrnH){ z;e@JOiDh{6RXY(f5l~rP7HtU?&R|b`eDb|BKXd*NlAz7^I7=~VuJi$A^lE*bY7Rr1 zOhR>)2I&^o!-1y9~T;~?*a|79LnKr8mi^#e(Vhdq#8?vxdsO}#3+fC{b{$}wCJrpq|{a&-;WlR z3aJJ`2i}lta}1B~T#~56I!znE@GL2-ETX~#)4qE0ij(Z}3p-o77QgwR)^EmmUd2VY zR26#ue6aNlEd1Za>`vpID+*gjvnS4Y-ujNk4H#8H2=e6%ZhhWYtJ{B$4vTq zdJfZCO)jQZ>1_yC#4BVvB{$ZQ-sQ1GxB?48Ami$)7pTZ}p~q=gxfRD#o)xk5QIr+& z`1i28rop(nQNkC#r0%bk7Y@&;ZTCIMWV~i&h`wnGv;=%MZcVtxqZAGtF8`@?i=AL< zDN4?9JbQ=jYe6JqP~}CHygz@Kx4-N1Y5>FSj<#gX4EWab zYPP;m!tZ1JwKuSw)*FFAe0tkyOlL?yrkEPBf}(2<7j&WL+S@JB z5gp+J8{l?TJD1nZBH%DLhUYJ)8AfYWKoKldee(O)ujdOR5dz}qw({)R3yi_YYWT~j zGl;lXYIAp>9SG6*(Sw1ZAJF&yj$?jx$O1{@x&QTlx+^5t~t z#!%^HOre!_s8= zTWTvgMC-cMzrTH(cEE{-HN5CM!+q^O*&h_~Q@|UfgNA4i!K(ap-=mvk?cUw_(+;v? zph--ffNIxjQudV2f*e2nwv+v8EZvi7PasU`O4OY_!JMz)P-MO7x@+fj2 zR%)F7al^d1+khyljg9D22UcJ5sl)y~UmS##QTG?cS9`*&jMMh&2=;NR~Vb`Vr*kulIUzmJZ}y`G=KG~cb)t>K*T z6d6dS>zyT0eJMm4rHgXd(m|E~B9Z`q`VCT!A)lE9uWo~lX6nWG9-)d4!6Pk!>UJ;q$_6m&Mj!0X%4Cp11F(L9I^3otO zYKo3V-F||G{ubVZ%T2(h=lcHU1|;HLkPerG{vvirZ}|x`!!jMNz$c`KPnSZ9x1(wQ zDNmC=9znBB2jJ00gA8hYmQcR!Z&67|EeMQA-n+6y2x^t{yY6&sY_*wG%Q0<9W}nY* zi0?RCo{5`=-8iZ5s0Ux>76-p~X>6O#`!U?#{nn0L7m;T4eMC<7-$z~5bJX;XXm~Mn zvCWyJi%hOmW6j3R*qFFqN*J%$gP1ner|5=NgFZVcY?oYpQ3~raFPtFmbid_ z6rP4*Fe;o~T~(A6W5Q43GbdAE6YR8*N#Q>cNfW@@_EpH;Xd9yn@U_A&4o;-UsG#4G zDU?fzle+2z}I3S#$PP-fm5z?bN;V&WKMtE)5MM=Ht3GnP1lhZq?vVK%!k>pf#OrD@>an zv3s-tkv)1nxxa*&JjHA=j)&oi=i*1N$2j|+THgITG|92}-cM>k08;8}YUR8ptC79$ zJ3r)Q;$>2H&U0Y&n|+!6HN=czX9Ns@wHiJJu^pioW=&4eGp_qV!X7+m zB2=@SNl>%;=7-VF1?vRU)ND;7gB=vw`;=|1Bw1oj0#BmR^C!x>G3#- zI6z-$0g>gqngykgtsTSa)=t;o+f>27)tN%(M6LW|lYMT2&e^@6kke4&=r(d!^@`$3 zGLdYS^~}snZ9I4KgX2i8l!nk~G*9L=>Nj^?x@(-S7!9ISscl)fk{iwgU-P}z-T6<9 z?l^Of%N#gC+D|eyIF0ULFb=ga_opNb4w;7QAM}5euzp?m{-w{7okbz6IsOHqA)dC{ z@Rd)jS+4r`d-Sn30t{pGBTGZ6Smi8hw)=_!8;PN{No5QB9#f7;@ua`!_H*!^pHnj1 zVQDN#Yh>@#1B#|SW(^zPoJ##ieZVyWy+JoJRdX3U?P zH)k$$V-2T^20Yw9&3ODcEDkOq>Wh@yN0Glv=48c@Cq}OHgBcHJoKR9TWU8sDHm%Hi zW7oGv5CtzVC}`vX&iA##v7Lt)Tg&!}29=dC(VV(=i)gE}(UO3@w)wslU+4x#acB`= z@CWXC@s#L}tEi#^yvpy;GaP-(ub{un|9FkN>m4Ih4XW*IA&xDBa?puex`lxWOOtdDb(}HlgpE}C)fvlIE_Rm zn5zRd!qixVqk>qXvwdB;RQ!}UGJRw2D)V^hzs_gGYM^t{B=S*)vdrn@01@s5b<%9j zT}CeGFW!~xV)V5BJ?RU2+SXnIyUUpd9i5Mtt~AVOya7^X7pXx* z|2&$vR=YCuT<46tV^LXp2z4E27W0+(Zjms`%4J&R{P;}bESye6koJu0t5;xN25wUG z7~E@A=mUZgRoH1QRAiYSqw|b)k_Fd5YyWsSd?h%y4uJN6flPELBc0Ftq39!cgA?UO zN=}K=GBA-zfKb7;3><`4?Zg6qYJ+&#?_WBfEn;w&jB2fCpLEwVjMZRJ___Su*c$#i zGHxpKRuJ-6Cd8w#Nlb`Jdc{hBsPcS0XKYP}X8bc+GjJI&-OV)~1qxvVUU z8pGjhqn&zg#Rn`Rn5X=LdnX!-kQrW>6-9h{<|$wFQoU-n7{pZlzCE`!VyxORYZ$Ow zdhy!M{CY@o92Ydt zQW9ahM7oHzrAZX7j(wz_1CMjd)s?Y(h)my`;!|DxSKK?Sef4>#%mH<5OC0A{@8y*T~ zkDiRiSMTnw`bEq$5j{^c;!3`2>mbG%LRk%ztLUM%`K>o-Z7^@EkbWlk?1&NMHe8J^ zcjo0a(V~WtVS_*w^jX5>&_m0?@{jX87CTF+&fbr!)?OjjB{5o_o+l5t_XW}rsr)@V z75teL@+<6@biCHJbuufQf6_d_eivBV1N#~cVwv@}L(eWWX#y>-cOGbKNF|1pq?3~g zZO-`p52wk&Kd^jgz(SVRSp4xrLS2tY;CW#MOE9kO?b;ee4yG21b3QGzV|)akg!&>n zLjtg5es>f6RzE}ol;#1V!2tn~bHRkFZM|x8LF6`SWr=`~ZdiId|+AJS}@XwUOr+`Kf*>8UOeynGA>mw5wNIBa_kjr`qp} zJ`COcbD6BfEum+H4Uz)Q$%AHCOi$3E_-VB0RAri{=eNojh8vaq6tA{@M8fQ^?tTFn z?4wqHwA-f1(sS@8MyM)7j}S;Mv2vl5Cs<~&!zb!S<~;BQ5AbmKM~{5^jo~@TW{+7E z(cO{C2$ah5iCZQ$9Hn+kU}aD3ebtT29zJ-jyLbK>OW3{vcs-~xY8H=9Pw`ixQB~(J zKxc!;Wc0WNYEYjtJ>=#T_sK^Dr`YRn<89LbNt|nmEorhpW2`oxl%c+V`4RE&bdtdXWUF(D6-EySF>k{Y3+RwtV>xYU{|9P1l>- z^ZosO+g45N`T#!BmdpLrhzpY?z{y$kfbiL!m^7ipZLAkCjzgun@pbVCbbxWEpd^S_F! za}uO5d>R)f@t8)A#EDWdJQ@by0eg;72@{7fg=A+x%ClU=SmrM*Nn+{_x^yqLi zZ6+rboUDq+NeM3pH(h~f;UAO+R5TiS@mqQOwt=4vvana%0HQhF^uaICnCp=Sga~`^ z8N}Ry_qyZa4Lqgpd4QKIWL>>69J@%Twss`o}lCxaN#O< z(z+9s#f*uOdtvI02=3*|mf}wrbT`LkU&@(-2@e287{G0h)0&A7`g7UwklsJseeXs8 z_W2*N$TIJovOn7N4%7p8W}sYcVdYZM;wG7x*o`Kqi+NI2igF_!&9aZDti(&Qjp$lq z6gQ4NmQ?{VllvW5SxZu^459*SY}j%DiS_&F#jlzs&O@&aJG8p+`t1g(97$>NqsVtv z`w@gjAB*@;)L%KS;h$!|gvaXX?LDeOz(q|BZb==sFdqhF-FWhWJla{BtdiUMSA0Wf zSc@sLb{WM|OEVK~US%=51AG{=bIISw5A7+j;~`f$6X`MS233-fY80%vst%glR2yG{ zRmEs0o?jR#kBkyXBUi+5?jsV1o_N7SBtNVXmdMAk_N3lWge=OIwN2v%@$S+8wR9ei zQ2&1%ml+~*M#w1JWhKcdTW96yteh1YIbS=QGEQV&R%CR9PWC1#Bje1@*5b%GWRI-h zJHPH9@HzK+zuvFc^YwT=UpvE%&lK5(Oz65Cem-HfyGC`SPQ9tHj630N zf8-xc%O!WA5M>$PZM?Xa&~Z{cf+HzR^($ed+F#KkbKcwk?4X@YxlPXRS7BCU*m$p zw2OQ?nT#xU`DTc9_e9=oVaRPz(E}@2si+QEpW=_`viWaq^`0{!JpWu&5aq|w=Ma{; z?)O~($~nf?@2@g>kn#BY<65qghb9od@$vs3)JL)z))GF1;n)tPfieek2l#NLKS#K# z9H$_1S3UN-m?9XKka{t1eL@Odq1Z6(uq~&w3RsfQsZvIicFTl z+e)xs7Q}gu1rct9HWcsKY{kn+Q&A_kC6yiVWZQ_=`sT$fhP8*vG(4Eg86vwN7K<6G zSz6*#TxLL75|SGU%ybjsB%aheAVdtp{L17ov0^kZOm8ze6P0CGeit%%ms438U zj!O%nseC1p91T3q%gwYNpi4{lgCw>vvHU)pC*F4 z=D6wE@SOOrbbyTqTA20Fq(oq7KtQVsvl4O4g@N_Y zpS6&d8yd!)@0^JWw`+dV_?vgobD%yNf8;gf+D`hIW(y}93~8bH4;@eQ0ZuN7WsC5# zWGY_w0~*W%iJ$NH-%L$t<$6{>bvS~s+&}Lo&s~Gkd?b63Q5%NQ69Tg=Mu;R6XTsq3 zA3wtRs-a`Ll=Qnx4Z>1SZcHzH^?0#)A4L+tguVW!E1myubx|YXHX(DO6>lh*>1_^)VNz zr9#Do{q{8fGQ>C4)lK=<)w39g&T(OO{dN_D@$D?fAm)M=|MNVh0e~Nkl4@*N8&X?l zV6O;UT;^lO&V@k88kfeJxVvW0S53Iy0tFSo1W&L4Em)=0IouQ? zOyDOJGJZDsy;bB=;r9%ZHp~1vDb+jdJe8pT}Jr%auT?tWd;&ar#Y%*!cmh!|;Wqo8Iu1G9=Z zZO?!aylX5XMafjRhuF#5=}A=4?H-3~YinCuU`rG0bzAAzt4=U~*Y_??@n>(I!*3Z0 zh}-xyCZ9gT%i_E?P;`;DgHpl~qhI)RN2j;0a zCsosJ3*>NaPW^NbBA=$-$|uvoIdk2Zowpww*NpGXo70*Ft7YmP6@;^nx|%KAch)0!#bg*BDYLMi_N|IgDXAGo8YtV{5g=hhg?#a-5uD*{W@ z;HgLH=}|xCep@m$$T-}&cjHqzE??^WZo7%f3wi=!GADF)r@&^+=hE2+0LyN$bWx}I zWMQ~uw-G9QgHk&*^`hz%8LpljTV3-b_a8qQTDcp^$ZX%u`XBG?{Bl?nRI`1a2wAT@ z!^o&vZTRSHIR8Zq?~WAEAyUaB6XM{%T^|Rim|YbT^+?#0{Gj&X{B-dJp|7V*Lg0>A z3<0#j8HojN-vyCrRVBf}aLCaV!hwf)x(>Yc+h1Gz86N~${axlevU$<_ zgR+!|OwT?@SUQOwH5Q_X44u|%U5vmY;PBeosL^4M7&Ys&ig2mS!AUpum-LqQRLFdd z@e4H>zVzqt@ZDO$ z=g*pa{a_cy=Ki~H@QStd^@>tbE=7q7n~?W?@9VmZ+Lz9}e9K)iKrLBxnDR$_?8%#?tIO?L1tUJF&$D(Fd&ftL1+;~; zby8nzr%I?Y2IlQ-&XOn2xy!$AX#uWHz+7CuFCVz*s}hs0>Nm|Q>#@O|27S-l4vB(1 z!f-h;p+@MXbt|$fM{peQMMNTnQ7nSP{bI;Kn4C>5>WMP+3e%C;)2D4!P?m>zv$VKH ztf(}1f_B!b6~l5X(RNqV*E1M Hl_1jl5`Lf02zts0{ZPEzc6nKVivzPok7AO<|zoGYX^Jv2Nj$Kcq6^dUR%|RO$swmv*ktI!>9C z1Ye}K*h1Zp5U(p}iTyFcVg#_XL?|j6j`C@}bmu#E)?@dfH)mCC+cDCCDCxF_PeSi4 z1T<4`-H0BTthwjmf0cjNw<%J*;nwJX?%tH$`5dDWb?d#J2LQDuOu8A~sNt(uyTHKW z9Z6F1CHr;yBPa)^IGCogf9ZxNk8R(~)ccHN_dy0Vv!&@ySF6_yvM~t+CeAtJ>k|&^ zPIi8PY0&pT7)%;xczB75_GSw~S>ITC6Bxh9=`*PRypc0t`;q@wei;AjIodZhlLY|B zNRzY%cdb5=A0fzb|Jzns%W-QceOprl^FUeWZ;V6A z{`HfQ)*FXKwt-SkI9&hg>Z^5+jM4BIC(BvCb#vS#}IoOC8HhgySCRRQkobxpN z8}xi%wAt!zU`IbdiKbRSUK>{o=_Y+vL$3ShG2C-+AW5x$H5J!Wrri)SiaMo41_0!% z#9cI@*QbR4{{1^xooHDKli^?#cAlhSxXM?=G8|@(Zp7Q7{LYM{`9X*CLWz|IZn}&9 z0S9_3T>&s?{m#E2j?^BK(SLbaZ&yS`2(_1^*%;YG@3Ah7e@3gwl=`;KbSF&CPLB^KD{S@Znhh)s`9^c*X)Wx~%b~i4T$QEM^5EwQu82NkH)2M@PCDa=;4; zHzN{5knLlO?eJD0H9EE22J8jcMs%*A^&WdGig?EF{Diy}cQ7sUJ8T$?-`o8uM`9H9 zNB2F`Ev8Q;J5&;Qg1FuvR*xoc3;AGhXF%)t$(zpiusjr$rpT8WnW2v5cNuN~CaHG8gcjQ)DtD&-LfXGl+w!7C!)&{)(R_dXOO>jv@8;>rdiH3)BmsvdLaE_C{s6u0y*Q^K=~=|<0rvOw_obz zrnp2j@*brwz(pC0#~(0zniPAHJxaNN7B{*~G}mv^jx(eH)>16|z~`&Se$OXrK}{qV z7ww<=KKO?Rp%bq40E-ui!UrSDPv*Oqv*7|fls@!kMa56!GCsS=6FD>8l}j$a6Jqr&p* zKn8)kN^Qo?*kmprYFIgc)2!(1?CS{~yrRPbpIzU4#At-|q5ubX41K@h!N=crzR{Zg z9vgw@>{#UIy|Z&A|lP^#iwU)#A@u36{M-Q`A{HB(3~*rVBX>J zr52ezk5*5b_sJaykpAqxBblcAh`$!{JJQVJeF3FSMJ^Y_mt0i6UYAZ=B|g-ZxlO<- z>FVWkEA;F61El?70oGR>fqX*|A55@y*;f;1?$N2E#T*^TOD^Pc-^ZKr{p{+ds1n+% z{`eIEyBcHH^bO~bVMY6djzU+dWvmX~fBPhnI*oBHkS`rXNS^O3xa)WJ{@tao8#+8V zHIW3_#n7X&6Vovt{}AOINqv?#i}fT78Kr!_dKnRX0HRUhm>%msoC!_C1D)OeW{PI> zq*?9!rg?cGC;AF0_$NE(=uHJK`r92GHGu1jV}AqAk!9J~H#ZuBa?Zf}C$NTUHx!km zEBznj9WRd3I0qK3uzQH@ql3qq+DW*V@xbi}kQ(o>gHqg#Ao4NbS?9gRQe*Rg9u&2m z>fkTW4F$uIkHJtBCRzX{qTs0rf{H|^s~n*+OoRAh2Ro(u^xxfdHLXe(MI9~y!ztaa zMkOs)>k*dMJ+AYZ{`j!6E+66L=~~roU#|3QUu|k-wC@}vT`??Q+B*(dI(FEtZ*6JN zpdUsCu}awn)M%P2O5NST|2UgOq%9ZFy@ z$&)c07kI9jv*-~w{Su0UYf*pEDAwj`JjeYvEKJ2Cy8G(x2Rl1jmyOJL(j&~2*b-kP z5YxZQjs6!F#~Ow3oud!`q@pjo=63qNYX*)W5F?;H(gOvVa59()6L?nTnl7*y(z3rX zrwd__wT+!nJ1;EvZQ4Cii4a(jw+9IL2vC$vPutd5P?dv)5a@M{X#UiPa+#>Q`|`yn zJr7@oDr9*|CdPj}2369}^X+VT%~jCA;NTjr;Ts z<KvZ%*hEx}M)Axv?~hfSUU7{ypW2b|{Rn1vUS{{%+H^QV}}tN2X!Jl*w8AesBXL)@yo7H(=@9@(Vp& z|8jn{XPwPOIGpp+azHa9_2uuC&P#(&F8KtjossgZjtG zCjos6xJd)8gUBp6qyu#1G?eR|)Nh>80>>i;((3s}C%t-(?$TzF1fT=MsJR}|0MkU$ zwnFbCY$GZ+y5bHS`rQ7(fnweH%IWFTqX7#n86$}(AVz9Ri>KYkYx8=`Usb;AsXVK& zMh@?^waGYR-dqym(N&t;Uwt`Dx($7Cl(PURiX~LvFIhd~8*B?cIsSG)^YunOxyoB* zfmMX+S&Wv9t>OB#yHtpqT;{hQKMvgQbTuRauQ}R}vPn{B2@!&0N%AULh#R^5vRuqN zf^UY6z$)aeW$R zh1EuLc(PBHebGsmD1HtJZ!e$&P0Z;k8P?LY>z=pmS-!IE`!dZw{z73wzUbRv8C6=$ zWRN%BH}54g0LnPK+jqHVS@>&IDWDNweZj&r*>=u`*saV0Wefea|LTQRTcvv~)#s}; zU8!mzD+I3a0Lquzf_gF!`4>{$+|$u*pWf+M&X$s@ThZgUloDhFBB&|>D|~%Wj63W} zMGTxy75*=&$DTbOf|xf#a?)bfK zrXBv3U3ZAm9xtIT&h@}Qxksya z`CVi%zo+<-X&e1hkKjE)B;rJ3lv)_6zxgS>#oUnLY+$P?K_wu?*}$r-M&8XC`Unf1ZXE&f&i>w9>5D+mhW4HcW(hGD^{Ofm$;f;~=U~#30jzinB zx5B88S2LT(t6EgvR;l(7vr|E&s1~_F!dzC(VUa!~bvPI=UGXiZV~QG8ka7Nb?U{N; zk62Gxy=hdhK~eAp&vfaOGQ&&xd2AT_a}Pa-oSJ-)u|6fx2_`>{bZBnh2t{I#M9d5* ztUx&)EzgrcYe2KM2LQug<(t68^4s%4iTemvomgQ&)B)E;+H`dZ{Kn!USSlT09gla3 z*gretcsX&$I{l#=EOIcr{Qs(}DZ#R7wS2-gqk!XFB`~E4J^6id6NV{`r4F|>mqVuM z3sph!f7_ku?Uw}3Xg=ppWK-A4H!V&HH}>AW9ruGQ?Mq{A<(34K%O??A42HnY+;$%1 z1po!vv*cH?#mMh&2c)@cbjW%*cK}w?gL(&_=4)OH>C# z)FBJ&v&|mdx0RJkOvF*I_+{8>K?XhhEjJ?g?^?N%TD_ICn(*|RwdH^8 zvUP=t_kc2lW}aByJr7AywewzVFoKbLp7|gn9r%~pxSp5T0M%mD*2ms7|Y z@CklzRg4`^abWKB;J)#qJ4j}6l!VI8!HR(91JYEWd%=5hZr@G*{lI1;P69sM4y+z< zpK>$%giuq%KG_8*Zee{EO?b9IIG|_|g+oqe2z2FgPo<$EG-hUXHAEKd`nlaynrXm3 zM&j2e4mrIla2U&~ddJO35NQ;EacZW?yLA#J25y8NH@w9Ge85160L9~QU)_Ln?5!AV zhuwGC6(`x}#B_I(4G>O`kAgS7;uap*o3m-dgPXHSjnTw<($bJf9Pv-UQ8dv{R!8`S zEO17F`ulOPcDS{ih{PZvtR7!YMnI}HvFxUB$aByUb+V#IxNgLmp(CGGS^Fa1$|9otv8rTZr4ft~ha{zh$8`mf_ zmVT*GWo`jEAZ-u(APxsk4o}?V(2eo+&?;lj?%!H@M?50?ru$O4*=H!OtnZ)cZ_?WzUa2 zy2Tw|34JtGK*BCSx!xOuOLO<{osuLB(H{l4pZt-8_4L%d$f0={Tf`HM`_$$0A4sZk_m7%B7 zY06EOQwYY{nM8Aka8FVVIp!a7DNYMO6)aIu8zmum({>NwzxwY#qzTU|K$!F3H@?>T zUBf>C}-9Kl-l~c(5@KtO28)vmLVqt98WNj?i z@7q%v8`XA3a=2EXTi85R3%=#0T7?yfo#|QACkVh?#O){e@Ly_IAdtMGVv>;l3sQ|! z20+;hoP{`f8MQ}CNfw7H*moN)UrJ*l-FoEU5K*^$=Tw0T6#G)1LNC7ZIaUIOkv9M% zMcdeVUu3d_Ik)ywf_W-<%h3-e5R_mjC;V`{>NZUIUy_B%kHan%<_5khaIT#=#INs} z5`yxbtq|zagV(x0YEcjda88^$23FgvQK97#FTm?51j9B;;434?e37f0JJ0l;DEk)sRF`@lzCqpOZsow@(P9n^Y-93DecC=_ToSm}X9t^TJTJMR% zAcAh}oz6&YeHL_KjSz@9i1<11_*2J&_m&##agzmazsSa6t4p~u-#KIC`>`T8+$d+v zS%`JpZeR9;j(_1~D|HLC zZbRCXVwJ8uD;EmU5{v5QE?uT-z0zj)%(cHTSGThgPOvu0K9B_S-8@Kl6m{%aQH%#KN17C)-qK i6HZg~6W-Xq2kiJpCVceFo|P literal 0 HcmV?d00001 diff --git a/src/designer/images/designer-splash-ru.png b/src/designer/images/designer-splash-ru.png new file mode 100644 index 0000000000000000000000000000000000000000..8c449ea7dd6615d898585f68c50ad099967ec1d6 GIT binary patch literal 94921 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
T=|&y5@3Bfp4EiI=1!*spPLNiV4f`T`o^B{ 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

6BqB%VaZh|cw92n(z0 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

%ZPRbnh6e&CW0x3 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 literal 0 HcmV?d00001 diff --git a/src/designer/images/doc.png b/src/designer/images/doc.png new file mode 100644 index 0000000000000000000000000000000000000000..61334f2cbf6a35cc5c57c5537af017b3b7addafc GIT binary patch literal 456 zcmV;(0XP1MP)5$d`I0G!X~MYy$NB7);MI2;bhvTR(7;}}8+1HK4;FW`{m zcs!yg3fyitNGZql=ksYW*tGLFXH*o00ai*u2!TA$A%sBJbz{ObO>w{9@zt?X%D8ew z1mE`&h9QC=nB9@p84ovL8m{YNzu$jop6A(tyRKUVFB!3Rtd!aY{1?a5daM?26UUo@ yhqvM1!EM_jNfK*tRaJJK_v?4`-g#`R&-4YJRw>fn=4>7fJ5?(EDy z-#hPo`%O@*IsQlM2gqiFYw5L`3;qS%*L<+ndRG)hRI63CwzkOSay9{fGDklhPHAglZxJsqc0k+m6rR4PV6e%V3dOZzzbaceV#zxot_B?J+ zIp-XMgM;L9IYviEFI`c$=2_9q008x~%Jj^vH~Dj64}hJw?*N#boV*@fuh%{B^vo>3 zUOi&?-V}rq`Mu0YTOeqagLX?i#nxKyqv5+#pd?tsaK_-a^Ia7NZ5h(l3IL1&Ygk-) z4!6e<2mr*OK>ap|8?C7e4;H+7;%#2LVvJ<}(*fKXXY0i-8Vv@NQD8tC>Gksu^JK`d z_IT|YaKGTm%L31~_o$H^Z-v&H!^1-lytz~2>E?TMDA7WY=?85zSWw}G|JrD% z8&s&M{-{#?QVu-u+}s=;ZEObmp?a>kDFh0I0F-IjfxhUMkIQ`cSZKKjmmfPLBN?~4 zvP$Xe0U{&N4bM%(W1}w=H-nT)CC<)d$_ct1rqlPwUG7dUU6VjyXcV5t9&4ikP@zJe eONzyE3jPC1VC6k=Vuw=z0000p;J2fF9bR|6ccE+K#-8uW zi@2`qf1gYy0fw=B^Gwswyxdz?=QEv?(q?F1_x*n{QLQ1); zM?ClxaOd=>lrjdGfd3AJ9=Gv$%=7c}LNY*v#R76P8fn0u7uTJNf3|s60Q|q~Hx8mw UfY(mgL;wH)07*qoM6N<$g0E0J!TS#K;~oGBKlw zg(m>1122G>c?LFwgoF_4%)&(4g{ne;73?PQ-_s$!RtQcp>L(pp_Pzf3`;M=DMO7)1 zhzL*xtn64Rn5IAq#6Y5|i5ak%uj=yhauftX;oxvMlm8L0!!GOVF zz~kd1p64+djR=B(IGz|gI5^<^{QPsL)A+9_8?NP7S>G%7z z+ieaH5Al7UUav=|)A@aIanT0uUmbgGZB4JPuJrWuG`}`eOTZ`d@~Qw)6csw2j=j0L zNs=UNZ*Oyae9Xea0+mVy*LCT3y8!QjdjqZ*K+*C`lF2G+G#c#h@6+q`P*rw!cX1pC z+qSvAy*1O{05xkCkf!Ne#~T|P`L&~?Beu4-CUL9P>9kcqo`9n$%H2(?)oO8ec9x%; z*skkh+cwQ+lQ0aQ+*1ndI1Y~E#a5!W<9utP)v-eX9JSzhU!!U=McFhIPPAHOz z9mg?I6cGf$%dMEVr$)L5RsQ1&-<*4TCuaUQ#3pRVr$k(nI2Eg z`3Br%WuPuF%E6xJ;rl)h4-cgsXTU!2(>ybS`{wV~1bkkvF7RUtoC3*oD-z&KRv&fqwtTQ@amF@pb?J0000?Ueuk18_-1K~#9!oz-7xm317)@z-;9rpD0Hsl!PiJ9Vt-hBwiLg*080 zqAmi9vtm^1PA|piDv(JEl953dV_>W(C}~hctR#`mLq%Q`V_IhnH_A<#C;!zv$L-h6 z?~KC|6Ce2TJn%fvo6qm}{d~UPB!mExB&i7@%q2;(7RzuUgiv;uR}w;yBuN^pu?uT) z6Q}Wg2;s_I!_kPhFou8$e2gctB!r-P#ea^X6u+;m65hvBSc2V{iZ5p{65;)5!|KJ* zTrL+1g+eG43gO(jb76FJH01O7kj-WT9ud`k5utxY*c%waI6jE*W!2EJv9VAn6vD{J zNEjL#3IhWJp{=bg;5aso&a1FoV^;|BuyQil|2*K>^tnu-2Q&Us= z`}>_bb?PME!_Atgv>r`ZgH5=CpK%W!i-m2?<#I3I2Kocu#Uy5Gq603*`^E@=D60Gi zEzQl%>vrtevFU%HZ{sX}$JM0D$E#uyJ0ti4Zfx7OZ9`*YqdS0(M(7pXOjkS?Lb#M9 zNpG~uYgpIZ-0W_kA%u`#u+TGo~ysN9r z#KeT&-d^+b^Ex{_oj-rxp+kqhiS`=AjcRZ@Ns<)q$96m)opCAJ=6YXW-}afAnI)Gm zUsfy@?b)-(`t|E=*|J4_eSQ1Befvt$Q74ilDOKQUtU^0p#Df^dFKED{2m=EH^D*j| zCMPF1wzRaUtE;nf=T50q>gm0E_f~{1z|#@hg=U<ORW_S_psA@zk|Z*jj7%nz z9UL6IFYast-o#u?*~wUlN*nw!p8JZb&bAEC;Oiqtj)XI3&V=FN;gHYg!{Nh+1HQyl zNo+DlW6{!4alm)z!|@Qp+#*{pjYqiq;K73(n>TM(E|=BT*2?Ge4jee}In?2$sO}FG zV|Uwit0sR7`Hi4f1m&W002ovPDHLkV1nFR=q>;N literal 0 HcmV?d00001 diff --git a/src/designer/images/editdelete.png b/src/designer/images/editdelete.png new file mode 100644 index 0000000000000000000000000000000000000000..feb32422d1a570aa2b055d47f6dcd09b5990304b GIT binary patch literal 953 zcmV;q14jIbP)*!rTb!n;5J_9^v4C!?OaDl8^UZ#p;FR$P20R!NShpK4=+YJHtamhnfe-2$Eh`l70ch)yqD z$l2fbbT~w#2nBNB0C>LMG!Kk{QSSRxVTc9+8b$mK{0Q8F@?&s-=Nj-VFgdVfNhd!! zkhX9#gO))+6-Dd-KLOtWpVyMtfLjfC26zJ4-LeX}_6Ln;+=T_4#YHqtDc9DHpg#kv zz!$abZQwTWPXl& z3%47Is^%hsRUdb8k;!yQ5y!_OJ`23u{=9F87#lR_AtwbG#lBCTresO-K*SDk-Yf=O zI%FFTCOV-yp91e*Mx(0mLR{uV5Y1InYz(>Ha_FDN#{rcHsEgj6xQXC$#Z^Em< z_pML&toi`MuPr49z;)mkYir(||MLWw{hbL-N#lkJhZP^;=PG@Q>@*rHPI@?eWw4q-r*mWO1xdloGfz=>+H3WEq97qet!n PEoSg^^>bP0l+XkKLar^H^z<}lhMBRmv%|*52Ai9k0G|WbfscXA%=9q0;-OdHm^-t4arQ+%S^t_= ztHspR6nlGnsOJAnPEOKnHhKB{1dFe~F#GA3#JV>R|V_j!A6g2lzfN9OL$ z*^@Yf-`YKZX`l}51L;vcYWgi37|v0UccAvc3<%h`%6T6W@ZOqGt59- z4y!tF5+DNoz9WwJ+1lC~e7?QC&CJXU-ENmK4A-M5dJFgwXp2ZP@S_!B&X0xMi9(v? z`;w+9Ns^Ex32B?^rGYkXEJu9Xdj&k!W=l1Y*U_}BTC>4mI3KAI3J3>Vf96l5O2`+MexbnXH>DNDA zYE}*B9QfsnftgasE*$X~#SehjZf@>;R2vS6lZ^ddM$vH{j!c!^-YC1fyL398CsK^> z$5r41;LCEYJY`%1E{K`oPlO@gsp`P6uYK|JKLbqoZg$d-`@W;4zHJ)t5AX}{ZTSRo z#g6)r5_s6#=mgO4WA#x$0eT+(r##7F>L;!GRSiArtn?ElK=Lmsv$U(uP><380000< KMNUMnLSTabzpr`# literal 0 HcmV?d00001 diff --git a/src/designer/images/editrename.png b/src/designer/images/editrename.png new file mode 100644 index 0000000000000000000000000000000000000000..1204738dcdf76d33dcab0c5fcb12fc0ecac8ec48 GIT binary patch literal 343 zcmeAS@N?(olHy`uVBq!ia0vp^Vj#@H1|*Mc$*~4fY)RhkE)4%caKYZ?lYt_f1s;*b z3=G^tAk28_ZrvZCAbW|YuPgf%RtYYBsbBXUB7j0qJY5_^D(1YMbddLu0gr2Z_Ypy{ z7i>BL-xkbmV3lZO+~jeT>A+qe2Iei&8yqaJtkb!Ch*2@5Q$Nz{(U0f9tv?(OnYb)o zY2NL#d>M@|^tS40DH#9EDB3615H#s4Lm^91=Pdz^%+y!&Ppn;aX6|!82hH*+S608D zDBU#e+_dnn;&5ZGTxG+qHmi#o_XJ86)C0T*~8n8P0=bi6;nWWlI?Q~O&HUjcL9fuL*A k56*~8{1bIRUj6~2%H^=EXIB@c0R7A0>FVdQ&MBb@0N=KV1poj5 literal 0 HcmV?d00001 diff --git a/src/designer/images/editsep.png b/src/designer/images/editsep.png new file mode 100644 index 0000000000000000000000000000000000000000..d3111989fc17e7cd5e4cf208cc7f157d833a4ba0 GIT binary patch literal 196 zcmeAS@N?(olHy`uVBq!ia0vp^Vj#@H1|*Mc$*~4fY)RhkE)4%caKYZ?lYt_f1s;*b z3=G^tAk28_ZrvZCAbW|YuPgf%R!KH>NvV~ruYp2=o-U3d6?5L6G2}a-z~dYk{59_5 z*$Mg6=B$}}szGVRjL+))*Rnl|zCXX6#>OzA<=*cbD#z!i%2BR0pkR}y zi(^Q|oa8;l&-s{j8H9a(WGAt0HUNSvSFZe7KCMw#SGT92SyDnm!p6oXK;+Ghjm)k* zbNjt{c?|CDEN!%H^y7-|&O*b-8IJZPylf0Jw0kbAUp7$zx`x5i)z4*}Q$iB}gz!Xp literal 0 HcmV?d00001 diff --git a/src/designer/images/field.png b/src/designer/images/field.png new file mode 100644 index 0000000000000000000000000000000000000000..265c4ccf90faab5e00dcf145437d25986537b879 GIT binary patch literal 231 zcmeAS@N?(olHy`uVBq!ia0vp^Vj#@H1|*Mc$*~4fEa{HEjtmSN`?>!lvI6;RN#5=* z4F5rJ!QSPQfg+p*9+AZi4BSE>%y{W;-5;PJdx@v7EBh4|VIe6+!HwpdfkG*sE{-7; zx87da$lGAR<8m?oh>%>fS#io4k;ntNQO8cOWjgl;a0z4{xE@t?^ya25*Je&^^(?&c zFgvV4VB7KIF{kvLB@~vHNL`6)pD~khLh-)%)>VsE)kn)Y^n47B__N#c591GpV-X@V Tb*$7u?qcwC^>bP0l+XkKHq%c* literal 0 HcmV?d00001 diff --git a/src/designer/images/filenew.png b/src/designer/images/filenew.png new file mode 100644 index 0000000000000000000000000000000000000000..8159fa007dcfc49d36f2cae312d4e19dc04e720d GIT binary patch literal 454 zcmV;%0XhDOP)AV-2k0HVL$|J6d6jyX-oMRq0o{h8CMl;+L~Yf4rGxR_~s>(Nr;)TL_}C9Rzrb^zHWh;=_kj=n2({g#{GUr zQ4|nD1SMaMiOxB1?wkWNBTZ9eSq38FIp>q$_oDXTUO%7D&|1&JN5R%w4{WW4wH5$S z*ELS3(=2>7b;d(*uQ4;~x&{CokH<-Puw!OM6h+wWcDUVcueHPB0Hu@%p9H@buuqaC z38a+B^Bh|1*LvHw9)pIRM?@^8^uWd#D5X$U6_irwy6%;*EK6K27kqVWjPb4b%707*qoM6N<$f?6=YtN;K2 literal 0 HcmV?d00001 diff --git a/src/designer/images/fileopen.png b/src/designer/images/fileopen.png new file mode 100644 index 0000000000000000000000000000000000000000..8f5e7f3d62b5a5eca68bfff317588e2bc664d0f8 GIT binary patch literal 850 zcmV-Y1FigtP)ra#xl52BO};I!8X;J*$K`f-8HGY=#QN%w=XaEKH3{NJ59EjDt z8>{{Hcr*wf92|)6`?9>e+!SyUtf_FRR1(*9#dTdNl}fU-v~(h%SvMkrs?sxu)}+&E zdV70oeMc$9>gpgoxUS3I-rmWRCn75VpSFtFvcZ=9 z08#<@gge4K&Hll_{eH&A#^~(qWMg9k&+{Ys0`Vy1E$A8Rbu7<^L!Tx!3> z(|1ou-0Nq2eEf9b!>T{$cQ9VH+TipXYznvk1c2vxl*{GjO9+U6SlHnC$TZveZH%di z8DlX)Cr1!~&CShItw2OpL_`7c59u5)MyA=x?_fPs!lvI6;RN#5=* z4F5rJ!QSPQfg+p*9+AZi4BSE>%y{W;-5;PJdx@v7EBh4|VIgtW88U1285kI~JzX3_ zDsCnJ`TyUZ*_YwU0|7R+w*MiA6#xJK-!A>fexvEb`rD1q{y%BBx;p%SzV(Ga_m>`d zX@6wxf5{mMdf{8c(ki|@RJ>_d4d}8qH+4Umec3w zSPHL}604c@kA3l15;pWj3dP{b7bAG(YD9qf;(AIr@O{BAQ^Y=~f zmh>K6ZG6pmPwmHPD$Y-)JdxP*>&^%1Ki`fq%IsQKc{ppe z3U@`z11{?)9#5Y>O-)EmO-%rT9UGsE9d6~FE&&8i4?~4TS1%WsQQ5O)l@DXk=gaNy T@14sBh9rZhtDnm{r-UW|4b8Vq literal 0 HcmV?d00001 diff --git a/src/designer/images/form.png b/src/designer/images/form.png new file mode 100644 index 0000000000000000000000000000000000000000..d4e263cf0ae11176284dfc0a168ea458f5e13329 GIT binary patch literal 477 zcmV<30V4j1P)m}4L~v+0 z92(lC(OnuE0;h|RXcTg45Tf8j49)_V2wOxnFj~5%PEYR-{c-4R_wKvj_j`}`eWwhE zHnWHbKsGBb`q|m~)Iv@BAQE{91)iQ7iUS7Fb)9%TPAYYYrmeBCFvrTuBC*&!?RJkw z)8d)+x{K#t7zQV7ySQ>!>ocr+YK-tnY{r~L}bFWhlq}093!GT<&RH;FL=`0 zs|pd_7Z_qZf=>4KD<>keFqZEb2c5od_ti7s={y6_YPcsObSf;%!Zb|)a=HDfch%~( z0}nJ-Rn^zJSUh2Sd&|=}5DYkWeo?Jn2Lh+Szd0OUp^X3Yl1cSX?q%nqpGABEhE2D_ T6X_@Q00000NkvXXu0mjf3i8ZS literal 0 HcmV?d00001 diff --git a/src/designer/images/form_g.png b/src/designer/images/form_g.png new file mode 100644 index 0000000000000000000000000000000000000000..99cfdcb305bb94452554836648089c70225ead4a GIT binary patch literal 755 zcmVNRnO&`1cKH|K1Bl0Cb?S!E-_RJ1{=(<`+Ey@`Olh7lKq8SK7z{Er z^onTo99>-<^z@v-??1-IhQ;dYCZFC+)QMaKZl%+VkB>7oHO1oMVm&dy?(QzSt}`|k z=HbJS3=f}WWu?g8-Vgfv0(>}s3jF@I#F0qYHO;K1mCJ5}6@L@CTn^LBY94Val{&IW zX4wQFUn~GHGd<(2`Dz>QYg$u*N!KM7i?!S&dM#R4*9lL$e|DtVMEk^WK;2aMzau_O z+aTPIs#UZkJ|MFJ9qo`cuDe4lmLQdSN-UP(&dnPDJbL`3HE}JqVHoU8CkR{^gp!5z zEsv%Jy|vnW1Y!%rFbMPyg0#R<1ayU)jyHNx4Q(XK=;&yBVgQr^M{)J`b2vSKKmZ{8 z0{LAbIu2S#u8epSbarZPop9~R8-@YOBD0)@lLNebF^7!}3Z#;tz*1IS9lst&M`z;h zM4MaT6WmLgJWFRNY!?thfTO?xt7M^+LQ09PY@{VoB}IBR&3iMWH4ulxVXvNBm`8*n zC`Tcx&fru@9feY=>R2UbKAWtquQm5Lo6S}ZL(@pke&IoK3AP7U@3TT`%19afBk^gW|TNTL>f)0Z4UV2X>{-ujhID&Lk8HRlsWhd67ui zD{{FUORtwGY~~TV@H|&lkCj~^-rrGft32ox1BaVp7H lHUP3Dv9>MN*7Dv{{SE2%RXc>(30(jH002ovPDHLkV1m@kQm6m` literal 0 HcmV?d00001 diff --git a/src/designer/images/function.png b/src/designer/images/function.png new file mode 100644 index 0000000000000000000000000000000000000000..c286f9a07b18e491939bc79de95361dbd0290eb2 GIT binary patch literal 814 zcmV+}1JV46P)qjVLc^55k2|RL(r2?v$AyNL)b7^nlaG%5<@{OLh=u?9CKrmQ7!J=-R|!0uLt9@ z&AWN+2R}HR^E)5TIp4$Y%McMx5)8v|0PYn{4-t`EFhfL!6M!ASI>+fpB$@6K3JG^It6QYcS+?fPA48VHbC5q>#obmq`r7*Ny6^< zcm>PzlBKiLRNLNO1ps@Ci}c3hVSJ$w+O5{2^Bjhh_>J#tUjQIk46fAPN))T()6>|S znUP;_Z6O$sbNP^L>OdRkWEqKQ1hOasz;gf(ior*I2q_8|j2B*8QWX3Qhp_(Ei`4!; z{={PdumQkDM9aD`)j+39WwU^){`lm1HdL;=vG~9EMMRH{{tAfM?6Jh8ftq4)@@61_ zKrB}Jn3)VdL?W8guB9-d?(7u~1809q}A@r014xwWVC*6wA^;Yb%{S sbO>FSD3^?$=Nb03a^84SGc_820sO(_&v6m*+yDRo07*qoM6N<$f;W(FYXATM literal 0 HcmV?d00001 diff --git a/src/designer/images/group.png b/src/designer/images/group.png new file mode 100644 index 0000000000000000000000000000000000000000..52d6fda2ebbb3c4f9b9e9449eb3290a4ad55594b GIT binary patch literal 208 zcmeAS@N?(olHy`uVBq!ia0vp^Vj#@H1|*Mc$*~4foCO|{#S9GGLLkg|>2BR0pkR}y zi(^Q|oa8;l&-s{j8H9a(WGAt0HUNSvSFZe7KCMw#SGT92SyDnm!p6oXK;+Ghjm)k* zbNjt{c?|CDEN!%H^y7-|&O*b-8IJZPylf0Jw0kbAUp7$zx`x5i)z4*}Q$iB}gz!Xp literal 0 HcmV?d00001 diff --git a/src/designer/images/help.png b/src/designer/images/help.png new file mode 100644 index 0000000000000000000000000000000000000000..f57e722e302bfde76a34f13a49354170b8b745e5 GIT binary patch literal 1605 zcmV-L2DEL?eL;6;zSTq6toD)8NFhlh{r& zw#S}~Js!`D=W*|yxepd8Ra0>`-|GA6=q%0=K@jl&B!t)l3<7(BexMt;C#9U0QeM(p zk6V^?=~FKcfW&9PLWn-#aIAxoSQ4VG5RF4qOhO>3+hCO>n>i@1m~SSN$+yPF#^#2H zhy72(9{>v>4nz{1OLW1$=bvU^|1gjB^^miO`baIRGchj zdzo@I$Ks7D(-&N7Yl)YJhKAk+>ZeYf@1ZmI z`iWA?lR}6+u?|M|J^wUA&wYo6Yg4fbT)p}sUF{F^+%pHLSryK{JI2EDERXNp&8vrg zN`=Ab7!zxtwtp<7)!$7{vkS(Td6t)O0_j|#TAT@re;<6 z)#)Gew|~9C@BaJ?06MqyU|SBJAAm0agQl3lm%iGI<2VDhZO0|BH`)r1?Rb)kQ)JUx zqgY)b(G@U$<+r^0!#&)}{DW$($f4oy0kE1&qfC#$_X!Yy#`Y{8ef%MO-`@qaYM?(F zhql&E%C$8Lf5Cky^bVp(mgioQeOumw)SW8oJRh0Il&noY{i3RWXe!z&YDgXhs4NdR!+qrVVq z)##8ym?y8r1~1 zQdgLnpTI~I2{$zn3daaF#WBNCv<}nL+Qs~p8aJ=ARswcEe3)n?LAh4q%F^$NZcPvh#Zf9uIAqe(x{aBM z4d$nF=fmOfjbgD_kpRhL@~zbMfW_$=zUv@lfYKTzLu}?Gd!Blcm%n*}XP$bIN+E=4 z#L=pWkYVt-_8v;9R?hu(5~bAna=Bb`U3XIgjE#-WdDZyAsq-$&^9`hgfB+C6^!*Ef zL`nm#OyZFcpYPmGHQm8GfBJy+tbN+^yt#V4o^u?h^uO8^Cr_R<&zw2)Ei+Mld*5&e zUwO70qe+rpD3ZQgrm*hP))A%mkv4Yj>?N*yn7_8kKmR_(de%NIgt(Z`=hK#DrCry} ze$vOIqoeZX&6}Z#iHTjMQt9aS{_rbLe0dvvU+AEttA%)?8M`XkShdJ3mbi62%k3Na z3x;95?|I%_sZ`3=YPC!{oz4Q~2Nq;>bW~4HPMU>6Au&5U`-10r1D@yYQcCp#al!A(tYs0b_DSf>+pF5i$cF&I1?LVs`JcF^N~)z%u)G z=Y8*+@4Yu;l7%EE10v8&kw_SZ9ciX)yx*X?+eG(A00jh(5+it3$bu6YXlbkO+ko#n zRyLoJ?xw80StF82NcU1C6867zAObQEQ5=}y@jf`0AiW^POy+@@bT19eQA};VmJ5QS z409$~NbE!3aU*J6*`7<1<$sdDydS^R>Wu_4Qh%*8{L6-Q9<~(|r8Uz~e!|sRIS8wqhsG6JlakUaTMp z=1SR`uXwz;%G-K4u|z^HGz04_s)}5@72Q}#dRH>pB>uAZS!AX z#%Cdd&Z%QW1cyTaSKJ`BYrzM*ebVOh*Jj22QeY8bd1;x}!9Eg8sP0JmH-`_5%OI^* z3u|p9Uza9tYH}){n4IW^tyD|V{$4{fxvs;WTH5Wt48|D#0$hCQly{Rv7ytkO07*qo IM6N<$g3N(l0RR91 literal 0 HcmV?d00001 diff --git a/src/designer/images/hi22-action-run.png b/src/designer/images/hi22-action-run.png new file mode 100644 index 0000000000000000000000000000000000000000..70271dbd9b6346146f358b8db257bbdd1f9723ed GIT binary patch literal 810 zcmV+_1J(SAP)6g3o%WIjbbHf#0Wyx#!VW@NFp$MNQef-NCOe<@kQA<5oX0w8K?=Zj;nD(JrX$JvbvxVn-Bx!>0 z_*51v{mBah9!u_xq+-Hmh@Q&sOD9W|Po2iS>|$Bg02G1x$2xg$CKxv`?p~&v^te1p zkLS5a5%18Wa-%W={pGHRf{1n;X8uXs^Rf#S0Wb8h%Qma`R+(s5L_vh-d(@shW9Hlp z&h8H0VF+nLa@59md|thHPUUKaR@lNW+f;8Z^82l)wArq2o0YpOrhn0(w7Gumx_R{A zk+E(2c$+D0s<*19x?Js#AAj=913}Z%)8_T7m*&phm63fsE`F@Xc_RjzQJgAKvdd`2 o$QBzH|3^nFZR}IF`R6~#pU(HCiIP9Wga7~l07*qoM6N<$f(P$(o&W#< literal 0 HcmV?d00001 diff --git a/src/designer/images/information.png b/src/designer/images/information.png new file mode 100644 index 0000000000000000000000000000000000000000..06a942b7f2d8b01113d980515fb2db0395dfb0c8 GIT binary patch literal 678 zcmV;X0$KfuP)hC3I7B48YR}& ze#z8Sud~_&J_E3{^i8=laU!uTnao3qML)U@xttFu0$GNJ-pcIk^!4PHB{dcf?@1sa zA|etBi9pGs0znA|gHrFiN^97Pqa*0<2Ggw0yaXQHz7?aRY0>pFE-tpoW>qI@0*2!s z0G`_sClcGTu<(SFli$ED(C=h2z)#0F-2GlJQYcWj-!AdYj4qLgT9L{FpPE+Hh_tF= z6NmvC5Cl4auRzktmC*0xo1>-Vw6_Zb1Lt_Xf3c<213U)&z$K6c+JHw+tU26@HSLw6 zY0%R%E``EVAOySya?XweXMHoYR0lGd_ewY%sECAt4?y(Bq*p4w4J^xY{lUREVi;wm zbaizxKfj{5#Ov#ul1}>oFwN#Y%;yzGMq&ax7>0qa>y0Z;r+q{s*PnLj$FW!#7{fl) zTGaITdc44vB)}k0*1o1`Y;El-S1LA516u(qjYsx5whS+T4WJe9;PH4+Rh4-Bi#sqb z@!8ove*Zq_=e-mP_bC=zC|@?M*cuK27UdDoSf@M<9{R+3f7R;B?eerT#@7BOH!#*l1VVlKHyme@pmAJrm4i^b9L{Fy2O3IG5A M07*qoM6N<$g5l>j0RR91 literal 0 HcmV?d00001 diff --git a/src/designer/images/journ.png b/src/designer/images/journ.png new file mode 100644 index 0000000000000000000000000000000000000000..4d9210947518713512de1104971ee205c3db6288 GIT binary patch literal 403 zcmeAS@N?(olHy`uVBq!ia0vp^Vj#@H1|*Mc$*~4fEa{HEjtmSN`?>!lvI6;RN#5=* z4F5rJ!QSPQfg+p*9+AZi4BSE>%y{W;-5;PJdx@v7EBh4|VIe8DExVg;FfcF*c)B=- zRNUG+b#HHrfk5kgeia_m02a{zW=77d3RMf(nS`VioT3C39!@ahh!AF|zBsS!d)oPA zS?h_py>|P5Za(_8>ahA7Zh52cUlll73|ln1PJBL{D)N16g|DkX$88he8{2x9pd7f@cC>|F&Cycgd8n z#9-%7%O6!A^=IC_uG_@-=7B_sA6>G?6Z}%Ip5xvG3%JrG?kO*e@Wl?(fKNE>eg&va4~qg`njxgN@xNAx}l=_ literal 0 HcmV?d00001 diff --git a/src/designer/images/journ_g.png b/src/designer/images/journ_g.png new file mode 100644 index 0000000000000000000000000000000000000000..8739e8d11353d384dfc490f77c79dbceb8ab3255 GIT binary patch literal 671 zcmV;Q0$}}#P)`%nh!%JUniSaD&p8Ml- zzW1E-uIhF}{)c4%ayd1WJ~K0uI$x{psI+<2?S|xXDr~pg1VJ#eqV4T%ipAnU_>FjQ zetteObdpP%pBTq>1@2JHi1t@L#ue+BPoLUje6 zycN5+S3EX0=E@L{`sW?E zJI&kIn^-Ie7%?E=iRbtWPZr3MW%=2%3lM~7lmnido1@PrA3+9=jt#f9#$eEZ zk;`;oBfqoP;lsz8TfD8UEvnTjl}aU9Xt&!eEiTdewu8=UY%k~1%dyx^2 literal 0 HcmV?d00001 diff --git a/src/designer/images/m_menu.png b/src/designer/images/m_menu.png new file mode 100644 index 0000000000000000000000000000000000000000..ba6a690f7db4f3025fc55afbea87f8a1ead90f86 GIT binary patch literal 264 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 W5a^*er-JJM00002BR0px`l2 z7srr_IajAT@--_6xXSY$Y?=H;L(Vb(^6DL*IpmH`_ED1Fm9aJH;3YBfe=V#Je}6LO zSuFHXX5neY5C`Un)m_KLK6>rnw%zFl`|}M!ANJV97j;%l3-Y-fqLL9B%JAZCqaho^ z^O!G(f7XPZ+TPG>*qF)Paqyc>e&_9Ny;8f^c{^=7z)%{?{yR}(Uz6Iw{SBKAJoni1 zu4CVRwq?sCCpUyty9vKZT|9*bA Y0DZ*Z>FVdQ&MBb@0H!~62><{9 literal 0 HcmV?d00001 diff --git a/src/designer/images/play.png b/src/designer/images/play.png new file mode 100644 index 0000000000000000000000000000000000000000..dfc0048c7d18ddf106d122ac68aa9e36745ed3e3 GIT binary patch literal 742 zcmV_!B4 zE`K9S3+$?7sUs)wWZNo+O*S7QB;qp84G)q?Bw&XlzsX-Hi}Js6rYbfK^~kZt+Umx_t#$0eXNKpbH`Vs%T>& zr9_De0UP5YezWC5g*q&6_TH0SJ*Q;2tL?uERJTF^WSlIS)>U?1 zIKhF--8AiQ2Y3uD0T+R2JuULMLJRl^=zj8*BDr>r&PyjbeC-Uect=A8JYYi)5Q!K> zA_hUjPjSt`*&QH${WQmJoulR8uDS{cDWz*Q18{DiaQy2Jg~B?qSY%V1 zI{5+xS!B=IBj_Db=KB+Fi+sRS4>%k)Xl`!$CvYWK!k$QBPb{#Mu&}>clrjZ3eFu08 z_`TqeQB(2HWruXaBAuA$$EZnqd=4j_chir6J|GPgfJ%*47{n@n6qmC_Qe!5IV7Tuph7$)CRIZ$qP1uL}i$gUBvn_gEf-G9Gb!!PLfY8Zv@O&yTSt&x?ujz zB}RVCK^#%a+|R@UQ8n=0pgPUB~0q!{;Gz z9_R*+0{iM6M%52QR|){`1Mk$2s88Ygmb!T%L=e~kbSg!81#Spf3+z+Ch(^b literal 0 HcmV?d00001 diff --git a/src/designer/images/playprev.png b/src/designer/images/playprev.png new file mode 100644 index 0000000000000000000000000000000000000000..d2a72b43d1bad0d1b206de6713f924117869a01c GIT binary patch literal 868 zcmV-q1DpJbP)Tmx{!*+g$qF(L4+0s2h@dvE(9BK1Z&2ZD!NeG#-{U2TbovGJuZ3^^4gj@ z{qW$v;eO|T=id7xBK+$GYy||6%(MRiT(`7X{9C+}!GHpsfD3Tzv6>dRtVH}Lt3+-c zk{4C^Hn73C9Kfg^?*r}t!%C@9U`*20mD&p2URSY*<9jx+zH|=sw?TIkjlCY=3uFP& z4w+lN8sIX}2kZq30FP42P)cnBZrAQy&Xd!dSYN7Os2RrM;PXOZ0TZQw8GzKhY?Xzz z_2ON+Qqqe78~}X!n;n2uF7`=Xb-9GDY?OhA+eDsJNnLfhy~i4y2gok}N6BvpO396= zEI!d7`DLqe7ARXXN9t%7?zi>Ha439kC%g;r>DoDx(bvB$ zz_{hf;3I)n9wi2tN`_L*ayuDqe#3|Qv-C!$EbtxpA)1~6A2s7Nb`6qChEf!{oQ#-F zL@uA9H*70#9Y_IVM)ssUw}V2jlj)S|xA>xj;_bWe%wItJgS!Bi^tQbUq-z#@9Hb!4GjMZ#1+})XeeF}I67=W4tp33ppq(x6GMo-M7I~=0NjFRfg051ZM zfgXMIMgf`JiabZ=e#ElqjGA|mFJ0&z0jXOW0R zNkpQ=13?m@2!kCtfrArwg$=A+(C&XmJQSg=DM&mRW+3rfKwDU$8=X?aG|>7c zOn;)|uYeOnC=ZZ@D=V|J;eyWH4L}7@l9d%kuDs693XgUGa0Ym;7vhf`+T4l=N+~xm u8jmT}D@cR5DP ztvauYjsHn8&u|fR(H(bUysl8IEVqvNO5ik0>27xEM4h$Zbs&*tc1HvF|wd&4O)mf5Q^6Qk6q^>QDNPuAA z9@uNkczj8kWvCYP9&|Z+aa1y{nGSXyBSBDJUzK7>+yXFMFycFB^tDeviAj=6&;kLH z-wE&Dp3p8qQ}&+h5q3guiwP6n@EVI{%$QR-W$<^O5AK9C%TbhcYH8(jog;B8|9Y z0;&Y}J5bvYXuB-KUQNo4h2rZb6%dtAMM1?c3Sc!wQ3_S;pNTKG)OJ&Ew;D(Nq@p)x z++_NHDfu*OjM7Fx^X3LwFk5-xJY#P>R2{W{>K@$Q>a)Q-OHa09tkt+6L!GVaDC!w8 zC=f*v&tD#tjP2A`=?0_#XMh~URCJ5-8!#0=<2h>irv)M~JRZ`CI<59*cN6>d2cN&4 zq17T7OtaPeHL2fdFW!w?hQ~wVIBo&>mQJ&D_T|$VskOcUi>+NhNQHuGUd}lsei(E3 f?2uls=O3Ye<>Gvn%R+N&00000NkvXXu0mjfQ9xUj literal 0 HcmV?d00001 diff --git a/src/designer/images/project.png b/src/designer/images/project.png new file mode 100644 index 0000000000000000000000000000000000000000..1837c0a1418e4a27eeb65e79946dcc2de6302489 GIT binary patch literal 1368 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 literal 0 HcmV?d00001 diff --git a/src/designer/images/redo.png b/src/designer/images/redo.png new file mode 100644 index 0000000000000000000000000000000000000000..05cbcdf20e060789803f7e1e544816bec1261511 GIT binary patch literal 667 zcmV;M0%ZM(P)A7#`Z-n#<~mNDRnh=E=K_5fP% zTO`K`_%J*g5hU>)c*UN?y1D1}|puoi)WHC;9Kh!d5o zu?jG8joN4u!7JdU0t&h5si6|^@qgvIZU8@kx(l=$ZyV4B;6Ct>=c?GZpaq4l>G~-H zuWRs4HdWlY+Be(+BH%O7rKGMo7&V8N$hrmA2poKar1TvLKtzedmP*=1Eo!7sS0rF&#f zGVpr}@^h+nO}vDzqbZteLO-=+GfAI;w=B05bJ^lsx3a*Ofxd`LMP!yw^bGuVE?e^H zXoE%M%*LYUePEMoP+O~I)q2)krXO2nzZD*aR14KC)cD^yr5`VVZUF7zd%$*Q8@{L{ z19NqaPUy#{fa_YO%ZwZ60o#8RA1LeP7mWny{RP`7#ZJN6QA+>-002ovPDHLkV1l_O BBxC>p literal 0 HcmV?d00001 diff --git a/src/designer/images/reg.png b/src/designer/images/reg.png new file mode 100644 index 0000000000000000000000000000000000000000..bab93ceaaf420679b6640b8e3aeaf2893a07ea68 GIT binary patch literal 425 zcmV;a0apHrP)3Vh@8Zr*FkdjdbL`JL!rOv^3UyN)(KfD4LMMVh7nc%Fxp5~Y+ekK-621f|mcdoPzu z09@Av!1sMRosK@>Q^z30vvGQoJW{Q`SXRT~EzRb;G3)iNjAvbiQi{!HgXeiH77J~h z+a61;Rs&!#7|?FFzq=K-@oe^RwsF6IbJ}=5pBtOvIM!y<>69$X^t-&{APCMk9*^&- z*IzB;Fl^Ciy!~iwfYbEJFiw($Fl<@iEX%C9@B7EWUyVnjJIm}`W8HCnUni3Z>-E~$ zR4$i|S>AEpFP!K&iXy$2AXsC;L7@c)DM4u63NGy*An54U zf`ceX+eINz=-?k<-E2n%!BlChQ@f~jqAFB{c^cXG#aI^&wJm8hlc=!!(jlHmzPPUQhtLI8ACMsBGBEK zrz8?D+o*E6yNrx{4D8L%UkKEG6t3%XbaX@{5y}do^^}2u7%y@Hi^X$a!v+dRE8+Vu({}MP^cy%RE z2aIdAXFhQvk)ZPK5&g+gsA_bv#N`K`@x(YCw9wu7G;#mUQ7{@BLVrwf)03SX0kG~p z4%W?#oAbK8y^Z5IB$G+p9}6Iw`_qeXZ5V|DKwVUrzk&+4jHC|f59!Xt#bPmtA)4&> z99$jd{hKu$91t*KKtPKQ)RPYtSh=b7vsS4?pG~Y5=D+I0Y`=sJ=%U%2Y2{kx|Gz0~R;F*e-yNGxfJ6^NDGvv4O z?NOZ8(n^8(rFERD#!-q`2pn;s0j4U@5U;KarfS&zvrGPGseO*yG&lw!*xff=QVN4X z0Y+MJ;COXutHj3FOe@81o=PcZre`Sp%AsNk=QwjY&R86exY?voD6q4m{Yb5DKhxW{ zhTWkXLw;+8Lh!Pr;Vq6h0GO&l?`!h;l5hMEMMzob=Y~;L00000NkvXXu0mjfX$4Pt literal 0 HcmV?d00001 diff --git a/src/designer/images/regs.png b/src/designer/images/regs.png new file mode 100644 index 0000000000000000000000000000000000000000..cbc44196791d624960e64b923d64f8da5301f127 GIT binary patch literal 433 zcmV;i0Z#sjP)I?ZB9zkHqG~sx0`~xo zhNw(iDJ={*tw{ygj3JcLsqv%&>4`AL8Mva#MR7Wv0I1jND5cO^TmAKVjqAG9YU%sl z@Am*Wjsrjt1dPXHGvFd)aNTEX`fm3`tM!tz3d11}5ARlQI=!>jCJHTO>GnR_?b3Ul zP6vSbe9mYz%15#A{lW)5De3p$el(uVy4Ko&J*ipv0v&3u(qBr$T&ReGBSINgT%joX=+*$FYEAb+b=e{J9_f bKiJe4&jYf@?6s&(00000NkvXXu0mjf;Sa%o literal 0 HcmV?d00001 diff --git a/src/designer/images/regs_g.png b/src/designer/images/regs_g.png new file mode 100644 index 0000000000000000000000000000000000000000..20b41fd653f33a267ab8acdd5d234ced9f044f16 GIT binary patch literal 739 zcmV<90v!E`P)xd=HFj9_pFyX=l6@b$29lbA>^`oglz z%$-?Y+kB-`Argtu)8qI1^z;;fa5xOW>gp=VWHKnw!Wbfvmu=Oxenx-) z>yA`~!USVuAKT{A=^Jh10EJ|;mu~O(z`&(zgM)(rtgo*#H8s_VVmp!O`eHnrWpwo2 ze-ke)-Dw*K#__DMov?^^Nxr}TG)Q)Qd`zuYqfnRtnv8dMce@)CZ#DNDXCk`>8<0CKW2EmB+*`SD6l-b@RP`EJ+z!n^?Dx`OLU zvw4o=(D$=1z+oj4$lfA2Hq;GN%N>YXWlb)h2W@X&t7#x(pl*0Fvjn$CP$&S@O@;nz zP~qmIlaD9Ke8>bJTadWL4uAw8U()2i7kIH_c)zlNhX)3<(O|$fcE>nMl)2|~&BTdr z`wJHr7lu|yHI@pelF$S$Qp7GGO#yEz|T83}AycKHY(yCa@l8w)wP($OG zxXVmEw7bGFK^;GHl9*ML*N+?>YyE;zh^wC8MLE0 z`g25auYB=5?xLY_2*FWRb4w{S8U<+6#DV9J%Liq)zUG<~FY{DNF*`F$=~n?2Rd@~N zroq^Fe&X{YrBaE*LpwlfUG_7*e{V#F?+yp06$*pTlDdEMj0b>rGg3vw)0+dpeN+l|l z3Z|J-Ns-5bl~N(_lU}daaa}hN9toCGhQLxvq?7=x*K2CES|U6WY~J04v=iXFQYfWZ zuh#%ntJPR|Ixa_TAwt?2kiEWUI2>wC2!Z1`A$aPrK}<8H=JPrEUXQjAe13e?Q4R(J z8jS|acVh0pi7`jmw7Z-Yccm%{o{AE7ZK0fsG$^HFak^dV`=twPTuJMXpEQDRH~uki0000AReK(Ue z?Rs!vn0ekGpXWQ@_nG(g`hCm)ag_in74Mbwe&2fk1^n9Z#TZk#lO&0m%^Zk8T$B6IT^B3=4G}0QQG_?EU3>uVHph0Rm7MCe=_mjKDA7m*EM?nxkN$}~Hbw1zPqtojkgaD(#fQ%$sYm`#N zIz~x_jx<}_TkO{NJO}<|YKk;X3%))4`YXiM1+>u!2F_s4lp2lJ8o)jG{;1P<+9-M) z$1(f+`vvg*?I!o`e@7fiVj(D(Al5M$P|?8uSjUiRRHW!0b!q(8_6p#|#l?#Y4ObVS z1l^wE4Ixk{1fcZD4&p)Fe%j{ypXzRE3I6@qnVl`$JGbx9{QWVaEQkS00)6JOjt7c| zNt(?j&!0=j@h&?|KY0JT^{@Hvn*;*Qz)Q@TeL4m}MGD!IG#YIO{s(y7?%IDqdmsP+ N002ovPDHLkV1hNWh93X` literal 0 HcmV?d00001 diff --git a/src/designer/images/resourses.png b/src/designer/images/resourses.png new file mode 100644 index 0000000000000000000000000000000000000000..52d6fda2ebbb3c4f9b9e9449eb3290a4ad55594b GIT binary patch literal 208 zcmeAS@N?(olHy`uVBq!ia0vp^Vj#@H1|*Mc$*~4foCO|{#S9GGLLkg|>2BR0pkR}y zi(^Q|oa8;l&-s{j8H9a(WGAt0HUNSvSFZe7KCMw#SGT92SyDnm!p6oXK;+Ghjm)k* zbNjt{c?|CDEN!%H^y7-|&O*b-8IJZPylf0Jw0kbAUp7$zx`x5i)z4*}Q$iB}gz!Xp literal 0 HcmV?d00001 diff --git a/src/designer/images/script.png b/src/designer/images/script.png new file mode 100644 index 0000000000000000000000000000000000000000..3b461323b2d68e4e988bdd5bbc1f3aedc01a0b35 GIT binary patch literal 951 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 literal 0 HcmV?d00001 diff --git a/src/designer/images/separator.png b/src/designer/images/separator.png new file mode 100644 index 0000000000000000000000000000000000000000..ed6f3697c9c7f8b54ee4c00236d0f9e4ef8ecd5e GIT binary patch literal 157 zcmeAS@N?(olHy`uVBq!ia0vp^Vj#@H1|*Mc$*~4foCO|{#S9GGf*{OTpAtV2DCqC$ z;uumf=k1k^yax<8TrR#pQEfO&@@>SawZTh#IbD_hG5EjWI(DzUYn{;6hi&(ZzXxAr z>FBtUe71*EK~r?vmjl^rLnIzl2lxETq1Pi+02Kf@M@4OmC{@ejrx14J%wX@oMX=0>!A;Xd4PDo5 zYF2##k7N>2I7jNeFJTzW3=yRn-1mLd(6(*XaR?y`uIoAmt15W(;h1lbSHWmaC)O-*$X@#_L4nn$NC9;8a#t_cDGd6_$=1 qXK&tJO&8?Z5B>C}lA^!+=luZJ;d4fT5{E$m0000!lvI6;RN#5=* z4F5rJ!QSPQfg+p*9+AZi4BSE>%y{W;-5;PJdx@v7EBh4|VIf)8q|dHPfkO43E{-7; zx86=s-Uaxq(AgrmU@#~b(4Dr)3}-75DB zDoalMwEvOJf>lp8JM%XOh8s3qvtpQ2eDIx}yI$vzAn9vg%OU+rQ{n5oWi wYu$2=G`P)q$gGRCt{2l(B15Q54317b2V#1moo3(1L>maj0AWg3KBu54Q{s zj%_Ew$%2EMij!tEP~t-f)hs$`1cwwX=S?t!cT)xA1 zzw_OXd#@P|N1Q}u0Ltayzo}O$RWlI=C=?1aghrz=(>sdOIEQ71!_mn)u2!ovgdhlJ zdO;Adwe}`0@KCGQP92{*p5r+4_r{}Tj9KWgwp}~6pX%5c!_VzI zRDx#8|YwK&1_Fj8&6qS01`<1u&$l^uFX27e57+j8d8=0_`+RwknbK}oVCP8P2o02evzz|wAaC&GUKh8acD8H1{&00000NkvXX Hu0mjfl`;iB literal 0 HcmV?d00001 diff --git a/src/designer/images/toolbar.png b/src/designer/images/toolbar.png new file mode 100644 index 0000000000000000000000000000000000000000..b47aa63d3ef1156d22263a53542e2367d3c76fb3 GIT binary patch literal 234 zcmeAS@N?(olHy`uVBq!ia0vp^Vj#@H1|*Mc$*~4foCO|{#S9GGLLkg|>2BR0px_)& z7srr_Id88zaxp9Nv_70}q)_41|2QzFs>jmJf6~#Me~~>m^mb+Ih^Q$X(XmqzG%eqv zB~@x!2biaGCo);E<>mN>;bZ2Ag+8qz&4+)w-QkIc5w@J2}t+_Pd e#=m#xtr>4Uj_h-}+wlwNP6kg`KbLh*2~7aDWmom-)8|tAsCgO82~@Pm-)Un`A~I*E?A=Q$ANy%0#p=|J5Xij6%YZh zCi&J8=Jv5}D*ZM}Rh-~EDlIgupaKvlXQ!p=61=%QFX4dxb*^uLz5`tW&lMDan>Z0R zxAy0)4RpQ3(=Mp(u8Stv`zwk!<8ce>UVjBVc0je(q-L$%Zc>7*fVqKw088M$18QSY z?CF{n-j>;?Xs13r>?Oy9WZYrNpb;~Y^Ey?9U zz=Kh0Lp74;PR+i@tF&VK^Sw26pL7cz!0i|RU^cZTG;p*400000NkvXXu0mjftFgb- literal 0 HcmV?d00001 diff --git a/src/designer/images/webform.png b/src/designer/images/webform.png new file mode 100644 index 0000000000000000000000000000000000000000..781874acd93c8fe082f689f9003a8121872bc3ba GIT binary patch literal 550 zcmV+>0@?kEP)8!P zbP=A1_MN(f=b`0t(gNS#pKL2Mj1LltTYy**%d$x(A>k)X(09Y>(+I*#L@xvnBOie92rD&aUz!`Qa%AAzo}O5EIC18{h7*topr zqAe}_!Z(#dL}EW+EE}y`5d=gLMl+{r4|crnJfVdeoTL?mGPf{2N2?;>K> z+i%{6NN~_PtP2q{64=4G0S(U9&xy!i7)y7?aj)`?SX*0d zJ1Z1U>+o1(UDqS6cXsxeo0|8vT~(<()(>Z9CVPT^0!6#W0pjdt!~g&Q07*qoM6N<$f_gsjQvd(} literal 0 HcmV?d00001 diff --git a/src/designer/images/webform_g.png b/src/designer/images/webform_g.png new file mode 100644 index 0000000000000000000000000000000000000000..91c0e213ad38fb94dfe9e521cf85d7cefae92d07 GIT binary patch literal 756 zcmV{KUswW26-Q7jkb;ibm zOijIKc=$A{s|EJ}ARt*&T8w(r4e_6t}e}~6R!R8hGBp*Nv~w!_yEtJ&0}GK0;wb@FqK(XN3TZF(V4hC z(dMu42<{|OJV~a>Z|4z0fUUp=vuL7}LQ09HETkz>MaA^v>H4=~pEwu{y7m0x0wNGX z*$Po{2D?IPE0j_d$I3bVvAT&39%nKc05nY_{_+#|;>%b?6H5qm4_L|q8)UKUzojhr zp^!yMVYARE+;lktA@D$9TXIYYBoYBgRkZ`FT<5;#c=I+zAP^{nl}ZjB9XLOKqJ=_1 zcc-)2EX%K!$#3Qmx^O*L6_1rwCf>hfVR3=2!WIDTL*FbeUKntCPxZPp2?UC=m)PZG mDGLBul$hHl>+3mpReuAVOjSMFAX%aS0000 +#include +#include +#include +#include +//Added by qt3to4: +#include + +#include "acfg.h" +#include "interfacetree.h" +#include "mainform.h" +#include "deditcommand.h" +#include "dedittoolbar.h" +#include "awindowslist.h" + +extern MainForm *mainform; +extern QPixmap rcIcon(const char *name); +extern void set_Icon(Q3ListViewItem *item, const char *name); + +InterfaceListViewItem::InterfaceListViewItem( Q3ListView *parent, aCfg * cfgmd, aCfgItem cfgobj, const QString &name ) +: ananasListViewItem( parent, cfgmd, cfgobj, name ) +{ + id = md->id(obj); + if ( ( id ) && ( md->objClass(obj) != md_separator ) ) setRenameEnabled(0, true); + aCfgItem comaction, active; + QPixmap pix; + int idd; + + comaction = md->findChild( obj, md_comaction, 0 ); + idd = md->text( comaction ).toInt(); + active = md->findChild( md->find( idd ), md_active_picture, 0 ); + pix.loadFromData( md->binary( active ) ); + setPixmap( 0, pix ); + pix = 0; +}; + +InterfaceListViewItem::InterfaceListViewItem( ananasListViewItem *parent, ananasListViewItem + *after, aCfg * cfgmd, aCfgItem cfgobj, const QString &name ) +: ananasListViewItem( parent, after, cfgmd, cfgobj, name ) +{ + id = md->id( obj ); + if ( ( id ) && ( md->objClass(obj) != md_separator ) ) setRenameEnabled(0, true); + + aCfgItem comaction, active; + int idd; + QPixmap pix; + + comaction = md->findChild( obj, md_comaction, 0 ); + idd = md->text( comaction ).toInt(); + active = md->findChild( md->find( idd ), md_active_picture, 0 ); + pix.loadFromData( md->binary( active ) ); + setPixmap( 0, pix ); + pix = 0; +}; + +void +InterfaceListViewItem::loadTree() +{ + QString oclass; + aCfgItem cobj; + + clearTree(); + + if ( !md ) return; + cobj = md->firstChild ( obj ); + while ( !cobj.isNull() ) + { + oclass = md->objClass ( cobj ); + if ( oclass == md_submenu || oclass == md_popupmenu || oclass == md_toolbar ) + { + loadSubmenu ( this, getLastChild(), cobj ); + } + oclass = md->objClass ( cobj ); + if ( oclass == md_command ) + { + loadCommand ( this, getLastChild(), cobj ); + } + oclass = md->objClass ( cobj ); + if ( oclass == md_separator ) + { + loadSeparator ( this, getLastChild(), cobj ); + } + cobj = md->nextSibling ( cobj ); + } +}; + +void +InterfaceListViewItem::loadSubmenu ( ananasListViewItem * parent, ananasListViewItem *after, aCfgItem child ) +{ + InterfaceListViewItem * mparent; + QString oclass; + aCfgItem cobj; + + mparent = new InterfaceListViewItem( parent, after, md, child, QString::null ); + mparent->setPixmap(0, rcIcon("submenu.png")); + cobj = md->firstChild ( mparent->obj ); + while ( !cobj.isNull() ) + { + oclass = md->objClass ( cobj ); + if ( oclass == md_submenu || oclass == md_toolbar ) + { + loadSubmenu ( mparent, mparent->getLastChild(), cobj ); + } + oclass = md->objClass ( cobj ); + if ( oclass == md_command ) + { + loadCommand ( mparent, mparent->getLastChild(), cobj ); + } + oclass = md->objClass ( cobj ); + if ( oclass == md_separator ) + { + loadSeparator ( mparent, mparent->getLastChild(), cobj ); + } + cobj = md->nextSibling ( cobj ); + } +}; + +void +InterfaceListViewItem::loadCommand ( ananasListViewItem * parent, ananasListViewItem *after, aCfgItem child ) +{ + new InterfaceListViewItem( parent, after, md, child, QString::null ); +}; + +void +InterfaceListViewItem::loadSeparator ( ananasListViewItem * parent, ananasListViewItem *after, aCfgItem child ) +{ + InterfaceListViewItem *newitem; + newitem = new InterfaceListViewItem( parent, after, md,child,QObject::tr("-------------------") ); + newitem->setPixmap(0, rcIcon("separator.png")); + +}; + +void +InterfaceListViewItem::newCommand () +{ + aCfgItem newobj; + InterfaceListViewItem *newitem;//, *par; + QString oclass = md->objClass( obj ); + +/* par = (InterfaceListViewItem *)this->parent(); + if ( par->text( 0 ) != QObject::tr("Interface") ) obj = md->findChild( obj, md_toolbars ); +*/ if ( oclass == md_popupmenu || oclass == md_submenu || + oclass == md_mainmenu || oclass == md_toolbar ) + { + setSelected( FALSE ); + setOpen( TRUE ); + newobj = md->insert( obj, md_command, QObject::tr("New Command") ); + newitem = new InterfaceListViewItem( this, getLastChild(), md, newobj ); +// newitem->setSelected( TRUE ); + newitem->edit(); + }; +} + +void +InterfaceListViewItem::newSubmenu () +{ + aCfgItem newobj; + InterfaceListViewItem *newitem; + QString oclass = md->objClass( obj ); + + if ( oclass == md_submenu || oclass == md_mainmenu || + oclass == md_toolbars || oclass == md_popupmenus || oclass == md_popupmenu ) + { + setSelected( FALSE ); + setOpen( TRUE ); + if ( oclass == md_popupmenus ) newobj = md->insert( obj, md_popupmenu, QObject::tr("New Popup menu") ); + else + if ( oclass == md_toolbars ) newobj = md->insert( obj, md_toolbar, QObject::tr("New tool bar") ); + else + newobj = md->insert( obj, md_submenu, QObject::tr("New Submenu") ); + newitem = new InterfaceListViewItem( this, getLastChild(), md, newobj ); + newitem->setPixmap(0, rcIcon("submenu.png")); +// newitem->setSelected( TRUE ); + }; + +} + +void +InterfaceListViewItem::newSeparator () +{ + aCfgItem newobj; + InterfaceListViewItem *newitem; + QString oclass = md->objClass( obj ); + + if ( oclass == md_submenu || oclass == md_mainmenu || oclass == md_popupmenu ) + { + setSelected( FALSE ); + setOpen( TRUE ); + newobj = md->insert( obj, md_separator ); + newitem = new InterfaceListViewItem( this, getLastChild(), md, newobj, QObject::tr("-------------------") ); + newitem->setPixmap(0, rcIcon("separator.png")); +// newitem->setSelected( TRUE ); + + }; +} + +void +InterfaceListViewItem::edit () +{ + QWorkspace *ws = mainform->ws; + aWindowsList *wl = mainform->wl; + QString oclass = md->objClass( obj ); + int objid = md->id( obj ); + if ( wl->find( objid ) ) { + wl->get( objid )->setFocus(); + return; + } + + if ( oclass == md_command ) + { + dEditCommand * e = new dEditCommand ( ws, 0, Qt::WDestructiveClose ); + wl->insert( objid, e ); + editor = e; + QObject::connect( mainform, SIGNAL( tosave() ), editor, SLOT( updateMD() ) ); + e->setData( this ); + e->show(); + //--mainform->addTab(++mainform->lastTabId,e->name()); + mainform->addTab(e); + return; + } +} + + +InterfaceTreeView::InterfaceTreeView ( QWidget *parent, aCfg *cfgmd ) +: ananasTreeView ( parent, cfgmd ) +{ + InterfaceListViewItem *mainmenu, *toolbars, *popups; + aCfgItem iface, item; + iface = md->find ( mdc_interface ); + if ( iface.isNull() ) iface = md->insert( md->find ( mdc_root ), md_interface, QString::null, -1 ); + item = md->find ( iface, md_toolbars ); + if ( item.isNull() ) item = md->insert( iface, md_toolbars, QString::null, -1 ); + toolbars = new InterfaceListViewItem ( this, md, item, QObject::tr ( "Toolbars" ) ); + toolbars->setPixmap(0, rcIcon("toolbar.png")); + toolbars->loadTree(); + toolbars->setOpen ( TRUE ); + item = md->find ( iface, md_mainmenu ); + if ( item.isNull() ) item = md->insert( iface, md_mainmenu, QString::null, -1 ); + mainmenu = new InterfaceListViewItem ( this, md, item, QObject::tr ( "Main menu" ) ); + mainmenu->setPixmap(0, rcIcon("m_menu.png")); + mainmenu->loadTree(); + mainmenu->setOpen ( TRUE ); + item = md->find ( iface, md_popupmenus ); + if ( item.isNull() ) item = md->insert( iface, md_popupmenus, QString::null, -1 ); + popups = new InterfaceListViewItem ( this, md, item, QObject::tr ( "Popup menus" ) ); + popups->setPixmap(0, rcIcon("p_menus.png")); + popups->loadTree(); + popups->setOpen ( TRUE ); + connect( this, SIGNAL( contextMenuRequested( Q3ListViewItem*, const QPoint&, int) ), this, SLOT(ContextMenu() ) ); + connect( this, SIGNAL( returnPressed( Q3ListViewItem*) ), this, SLOT( itemEdit() ) ); + connect( this, SIGNAL( doubleClicked( Q3ListViewItem*) ), this, SLOT( itemEdit() ) ); +}; + + +void +InterfaceTreeView::ContextMenu() +{ + Q3PopupMenu *m=new Q3PopupMenu( this, "PopupMenu" ); + Q_CHECK_PTR(m); + +/* QLabel *caption = new QLabel( "" "Context Menu", this ); + caption->setAlignment( Qt::AlignCenter ); + m->insertItem( caption ); + m->insertItem( tr("&Rename"), this, SLOT( itemRename() ), CTRL+Key_R); + m->insertItem( tr("&Edit"), this, SLOT( itemEdit() ), CTRL+Key_E ); + m->insertItem( tr("&Delete"), this, SLOT( itemDelete() ), CTRL+Key_D ); + m->insertItem( tr("&MoveUp"), this, SLOT( itemMoveUp() ), CTRL+Key_U ); + m->insertItem( tr("&MoveDown"), this, SLOT( itemMoveDown() ), CTRL+Key_M ); +*/ + ananasTreeView::ContextMenuAdd( m ); + m->insertItem( tr("&New Submenu"), this, SLOT( itemNewSubmenu() ), Qt::CTRL+Qt::Key_N ); + m->insertItem( tr("New &Command"), this, SLOT( itemNewCommand() ), Qt::CTRL+Qt::Key_C ); + m->insertItem( tr("New &Separator"), this, SLOT( itemNewSeparator() ), Qt::CTRL+Qt::Key_S ); + m->exec( QCursor::pos() ); + delete m; +}; + +void +InterfaceTreeView::itemNewSubmenu() +{ + InterfaceListViewItem *i = (InterfaceListViewItem *) selectedItem(); + if ( i ) + i->newSubmenu(); +}; + +void +InterfaceTreeView::itemNewCommand() +{ + InterfaceListViewItem *i = (InterfaceListViewItem *) selectedItem(); + if ( i ) + i->newCommand(); +}; + +void +InterfaceTreeView::itemNewSeparator() +{ + InterfaceListViewItem *i = (InterfaceListViewItem *) selectedItem(); + if ( i ) + i->newSeparator(); +}; + +void +InterfaceTreeView::itemDelete() +{ + deleteItem(); +}; + +void +InterfaceTreeView::itemMoveUp() +{ + moveUpItem(); +}; + +void +InterfaceTreeView::itemMoveDown() +{ + moveDownItem(); +}; + +void +InterfaceTreeView::itemEdit() +{ + InterfaceListViewItem *i = (InterfaceListViewItem *) selectedItem(); + if ( i ) i->edit(); +}; +void +InterfaceTreeView::itemRename() +{ + renameItem(); +} + diff --git a/src/designer/interfacetree.h b/src/designer/interfacetree.h new file mode 100644 index 0000000..f9e452c --- /dev/null +++ b/src/designer/interfacetree.h @@ -0,0 +1,74 @@ +/**************************************************************************** +** $Id: interfacetree.h,v 1.1 2008/11/05 21:16:27 leader Exp $ +** +** Header file of the Interface Tree of Ananas Designer applications +** +** Created : 20031201 +** +** Copyright (C) 2003-2004 Leader InfoTech. All rights reserved. +** +** This file is part of the Designer application of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.leaderit.ru/page=ananas or email sales@leaderit.ru +** See http://www.leaderit.ru/gpl/ for GPL licensing information. +** +** Contact org@leaderit.ru if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#ifndef INTERFACETREE_H +#define INTERFACETREE_H +#include +#include +//#include "acfg.h" +#include "atreeitems.h" + +class QWidget; + +class InterfaceListViewItem : public ananasListViewItem +{ +public: + InterfaceListViewItem( Q3ListView *parent, aCfg * cfgmd, aCfgItem cfgobj, const QString &name = QString::null ); + InterfaceListViewItem( ananasListViewItem *parent, ananasListViewItem *after, aCfg * cfgmd, aCfgItem cfgobj, + const QString &name = QString::null ); + void loadTree(); + void newCommand (); + void newSubmenu (); + void newSeparator (); + void edit (); +private: + void loadSubmenu ( ananasListViewItem * parent, ananasListViewItem *after, aCfgItem child ); + void loadCommand ( ananasListViewItem * parent, ananasListViewItem *after, aCfgItem child ); + void loadSeparator ( ananasListViewItem * parent, ananasListViewItem *after, aCfgItem child); +}; + +class InterfaceTreeView : public ananasTreeView +{ + Q_OBJECT +public: + InterfaceTreeView( QWidget *parent, aCfg *cfgmd ); + +public slots: + void ContextMenu(); + void itemNewSubmenu(); + void itemNewCommand(); + void itemNewSeparator(); + void itemDelete(); + void itemEdit(); + void itemMoveUp (); + void itemMoveDown (); + void itemRename(); + +}; + +#endif //INTERFACETREE_H diff --git a/src/designer/main.cpp b/src/designer/main.cpp new file mode 100644 index 0000000..97c73fe --- /dev/null +++ b/src/designer/main.cpp @@ -0,0 +1,195 @@ +/**************************************************************************** +** $Id: main.cpp,v 1.5 2008/12/05 21:11:54 leader Exp $ +** +** Main file of Ananas Designer application +** +** Created : 20031201 +** +** Copyright (C) 2003-2004 Leader InfoTech. All rights reserved. +** +** This file is part of the Designer application of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.leaderit.ru/page=ananas or email sales@leaderit.ru +** See http://www.leaderit.ru/gpl/ for GPL licensing information. +** +** Contact org@leaderit.ru if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#include +#include +#include +#include +//Added by qt3to4: +#include +#include +#include "alog.h" +#include "ananas.h" +#include "mainform.h" +#include "dselectdb.h" +#include "formdesigner.h" + +MainForm *mainform = 0; +aWindowsList *mainformwl = 0; +QWorkspace *mainformws = 0; +//QApplication *application = 0; +QTranslator *translator = 0, tr_app(0), tr_lib(0), tr_plugins(0); +aFormDesigner *formdesigner = 0; +QString lang="en", + rcfile="", + username="", + userpassword=""; + + +int setTranslator(QString lang) +{ + QString langdir; +#ifdef Q_OS_WIN32 + langdir = qApp->applicationDirPath()+"/translations/"; +#else + langdir = "/usr/share/ananas4/translations/"; +#endif + tr_app.load( langdir+"ananas-designer-"+lang+".qm","."); + tr_lib.load( langdir+"ananas-lib-"+lang+".qm","."); + tr_plugins.load( langdir+"ananas-plugins-"+lang+".qm","."); + return 0; +} + +int +parseCommandLine( int argc, char **argv ) +{ + QString param, name, value; + int i; + char *s, locale[50]="en"; + + strncpy( locale, QTextCodec::locale(), sizeof( locale ) ); + s = strchr( locale, '_' ); + if ( s ) { + *s = 0; + } + lang = locale; + setTranslator( lang ); +// printf("locale=%s\n", locale ); + QString str_ru=QString::null, str_en=QString::null; + bool lang_setted = false; + bool help_setted = false; + for ( i=1; iws; + mainformwl = mainform->wl; +// application = &app; +// dSelectDB dselectdb; + int rc; + QPixmap pixmap; + + if ( parseCommandLine( argc, argv ) ) return 1; + qApp->installTranslator( &tr_lib ); + qApp->installTranslator( &tr_plugins ); + qApp->installTranslator( &tr_app ); + pixmap = QPixmap( ":/images/designer-splash-"+lang+".png" ); + if ( pixmap.isNull() ) +#ifdef Q_OS_WIN32 + pixmap = QPixmap( qApp->applicationDirPath()+"/designer-splash-"+lang+".png" ); + qApp->addLibraryPath( qApp->applicationDirPath() ); +#else + pixmap = QPixmap( "/usr/share/ananas4/designer/locale/designer-splash-"+lang+".png" ); +// qApp->addLibraryPath( "/usr/lib/ananas4/" ); + qApp->setLibraryPaths( QStringList() <<"/usr/lib/ananas4/" ); +#endif + foreach (QString path, app.libraryPaths()) + printf("%s\n", path.toUtf8().data()); + + if ( pixmap.isNull() ) + pixmap = QPixmap( ":/images/designer-splash-en.png" ); + QSplashScreen *splash = new QSplashScreen( pixmap ); + if ( ananas_login( rcfile, username, userpassword, 0, AApplication::Designer ) ){ + splash->show(); + splash->message( QObject::tr("Init application"), Qt::AlignBottom, Qt::white ); + w->rcfile = rcfile; + qApp->setMainWidget( w ); + splash->message( QObject::tr("Init forms designer"), Qt::AlignBottom, Qt::white ); + formdesigner = new aFormDesigner(); + + //--formdesigner->reparent( mainformws, 0, QPoint( 5, 5 ), false ); +// mainformws->addWindow(formdesigner); + formdesigner->setCaption( QObject::tr("Dialog forms designer") ); + formdesigner->hide(); + w->show(); + splash->clear(); + splash->finish( w ); + delete splash; + qApp->connect( qApp, SIGNAL( lastWindowClosed() ), qApp, SLOT( quit() ) ); + mainform->configOpen(); +// QTextCodec::setCodecForCStrings( QTextCodec::codecForName("UTF8") ); + + rc = app.exec(); + if( w ) delete w; + w=0; + aLog::close(); + ananas_logout(); + return rc; + } + aLog::close(); + return 0; +} diff --git a/src/designer/mainform.cpp b/src/designer/mainform.cpp new file mode 100644 index 0000000..ab3be19 --- /dev/null +++ b/src/designer/mainform.cpp @@ -0,0 +1,496 @@ +#include "mainform.h" + +#include +#include +#include + +#include "qtoolbutton.h" + +#include +#include +#include "q3filedialog.h" +#include "qstatusbar.h" +#include "qmessagebox.h" +#include +//Added by qt3to4: +#include +#include +#include + +#include "ananas.h" +//#include "adatabase.h" +//#include "acfgrc.h" +#include "cfgform.h" +//#include "messageswindow.h" +#include "dselectdb.h" +#include "alog.h" + +//#include "qananastable.h" + +extern CfgForm *configform; +//extern QApplication *application; +extern void messageproc(int n, const char *msg); + +/* + * Constructs a MainForm as a child of 'parent', with the + * name 'name' and widget flags set to 'f'. + * + */ +MainForm::MainForm(QWidget* parent, const char* name, Qt::WindowFlags fl) + : Q3MainWindow(parent, name, fl) +{ + setupUi(this); + + (void)statusBar(); + init(); +} + +/* + * Destroys the object and frees any allocated resources + */ +MainForm::~MainForm() +{ + // no need to delete child widgets, Qt does it all for us +} + +/* + * Sets the strings of the subwidgets using the current + * language. + */ +void MainForm::languageChange() +{ + retranslateUi(this); +} + +void MainForm::filePrint() +{ + +} + +void MainForm::fileExit() +{ +// cfg_done(); +} + +void MainForm::editUndo() +{ + +} + +void MainForm::editRedo() +{ + +} + +void MainForm::editCut() +{ + +} + +void MainForm::editCopy() +{ + +} + +void MainForm::editPaste() +{ + +} + +void MainForm::editFind() +{ + +} + +void MainForm::helpIndex() +{ + +} + +void MainForm::helpContents() +{ + +} + +void MainForm::helpAbout() +{ + QMessageBox::about( this, tr("About Ananas.Designer"), + tr("

Ananas.Designer %1

is a programm
" + "for adjusting accounting automation system

" + "Copyright 2003-2006 Leader Infotech, Valery Grazdankin
" + "Copyright 2003-2006 Project Ananas, Andrey Paskal, Grigory Panov, Andrey Strelnikov
" + "License: GPL

" + "technical support:
" + "lider-infotech@narod.ru
" + "app@linux.ru.net
" + "Web sites:
" + "
http://ananas.lrn.ru
" + "http://www.leaderit.ru" + "

Avalable extensions:
%2").arg(ananas_libversion()).arg( ""/*--AExtensionFactory::keys().join(", ")*/) ); +} + + +void MainForm::init() +{ + + + setName("ananas-designer_mainwindow"); + rcfile=""; + windowsMenu = new Q3PopupMenu( this ); + windowsMenu->setCheckable( TRUE ); + connect( windowsMenu, SIGNAL( aboutToShow() ), + this, SLOT( windowsMenuAboutToShow() ) ); + menuBar()->insertItem( tr("&Windows"), windowsMenu ); + + menuBar()->insertSeparator(); + Q3PopupMenu * help = new Q3PopupMenu( this ); + menuBar()->insertItem( tr("&Help"), help ); + + help->insertItem( tr("&About"), this, SLOT(helpAbout()), Qt::Key_F1); + // help->insertItem( tr("&Test"), this, SLOT(helpTest())); + // help->insertItem( "About &Qt", this, SLOT(aboutQt())); + help->insertSeparator(); + // help->insertItem( trUtf8("Что &это"), this, SLOT(whatsThis()), SHIFT+Key_F1); + + + //--designer_settings.insertSearchPath( QSettings::Unix, QString(QDir::homeDirPath())+QString("/.ananas")); + //--designer_settings.insertSearchPath( QSettings::Windows, "/ananasgroup/ananas" ); + +// QStringList lst = settings.entryList("/engine"); + QSettings designer_settings; + designer_settings.beginGroup("/designer"); + bool maximize = designer_settings.readBoolEntry( "/maximize", 0 ); + int width = designer_settings.readNumEntry( "/geometry/width", 600 ); + int height = designer_settings.readNumEntry( "/geometry/height", 480 ); + int offset_x = designer_settings.readNumEntry( "/geometry/x", 0 ); + int offset_y = designer_settings.readNumEntry( "/geometry/y", 0 ); + designer_settings.endGroup(); + resize( QSize(width, height) );// .expandedTo(minimumSizeHint()) ); + move(offset_x,offset_y); + if(maximize) + { +// setWindowState(windowState() ^ WindowMaximized); + } + + setIcon( rcIcon("a-system.png")); + setCaption(tr("Ananas: Designer")); + Q3VBox* vb = new Q3VBox( this ); + vb->setFrameStyle( Q3Frame::StyledPanel | Q3Frame::Sunken ); + ws = new QWorkspace( vb ); + wl = new aWindowsList(); + ws->setScrollBarsEnabled( TRUE ); + setCentralWidget( vb ); + cfgform=NULL; + + MessagesWindow *msgWindow = new MessagesWindow( this ); // , WDestructiveClose ); + moveDockWindow( msgWindow, Qt::DockBottom ); + setMessageHandler( TRUE ); + msgWindow->hide(); + tbMetadata->setShown( FALSE ); + tbActions->setShown( FALSE ); + tbInterface->setShown( FALSE ); + tbRights->setShown( FALSE ); + tbLanguages->setShown( FALSE ); + tbImageCollection->setShown( FALSE ); + TBToolbar->setShown( FALSE ); + tbTabs->setShown( FALSE ); + lastTabId = 0; + configSaveAction->setVisible( FALSE ); +} + +void MainForm::configNew() +{ + CfgForm *cf = cfgForm(); + if (cf) + { + if ( !cf->close() ) return; // close configuration form if opened + } + cf = new CfgForm(ws, 0, Qt::WDestructiveClose); // create new cfgform + if ( cf ) + { + cf->init( rcfile, TRUE ); // initialization NEW configuration + connectSignals( cf ); + cf->ws=ws; + cf->show(); + ((QWidget*)cf->parent())->move(0,0); + //--addTab(++lastTabId,cf->name()); + addTab(cf); + } +} + +void MainForm::configOpen() +{ + CfgForm *cf = cfgForm(); + if ( cf ) + { + if ( !cf->close() ) return; + } + if ( rcfile.isEmpty()) return; + cf = new CfgForm( ws, 0, Qt::WDestructiveClose); + if ( cf ) + { + cf->init( rcfile, FALSE ); // initialization configuration + connectSignals( cf ); + cf->ws=ws; + cf->show(); + ((QWidget*)cf->parent())->move(0,0); + //--addTab(++lastTabId,cf->name()); + addTab(cf); + } +} + +void MainForm::configSave() +{ + emit tosave(); + CfgForm *cf = cfgForm(); + if ( cf ) cf->save(); // get configuration form and save its data +} + +void MainForm::configSaveAs() +{ +} + + + +void MainForm::fileOpen() +{ + +} + +void MainForm::fileSave() +{ + +} + +void MainForm::fileSaveAs() +{ + +} + +void MainForm::fileNew() +{ + +} + +void MainForm::windowsMenuActivated( int id ) +{ + QWidget* w = ws->windowList().at( id ); + if ( w ) w->showNormal(); + w->setFocus(); +} + + +void MainForm::windowsMenuAboutToShow() +{ + windowsMenu->clear(); + int cascadeId = windowsMenu->insertItem(tr("&Cascade"), ws, SLOT(cascade() ) ); + int tileId = windowsMenu->insertItem(tr("&Tile"), ws, SLOT(tile() ) ); + int horTileId = windowsMenu->insertItem(tr("Tile &horizontal"), this, SLOT(tileHorizontal() ) ); + if ( ws->windowList().isEmpty() ) { + windowsMenu->setItemEnabled( cascadeId, FALSE ); + windowsMenu->setItemEnabled( tileId, FALSE ); + windowsMenu->setItemEnabled( horTileId, FALSE ); + } + windowsMenu->insertSeparator(); + QWidgetList windows = ws->windowList(); + for ( int i = 0; i < int( windows.count() ); ++i ) { + int id = windowsMenu->insertItem(windows.at(i)->caption(), this, SLOT( windowsMenuActivated( int ) ) ); + windowsMenu->setItemParameter( id, i ); + windowsMenu->setItemChecked( id, ws->activeWindow() == windows.at(i) ); + } +} + +void MainForm::tileHorizontal() +{ + // primitive horizontal tiling + QWidgetList windows = ws->windowList(); + if ( !windows.count() ) + return; + + int heightForEach = ws->height() / windows.count(); + int y = 0; + for ( int i = 0; i < int(windows.count()); ++i ) { + QWidget *window = windows.at(i); + if ( window->windowState() == Qt::WindowMaximized ) { + // prevent flicker + window->hide(); + window->showNormal(); + } + int preferredHeight = window->minimumHeight()+window->parentWidget()->baseSize().height(); + int actHeight = QMAX(heightForEach, preferredHeight); + + window->parentWidget()->setGeometry( 0, y, ws->width(), actHeight ); + y += actHeight; + } +} + + +void MainForm::closeEvent( QCloseEvent *e ) +{ + if (configform) + { + if (!configform->close()) + { + e->ignore(); + return; + } + } + + QSettings designer_settings; + designer_settings.beginGroup("/designer"); +// designer_settings.writeEntry( "/maximize", windowState()&WindowMaximized ? true: false); + designer_settings.writeEntry( "/geometry/width", width() ); + designer_settings.writeEntry( "/geometry/height", height() ); + designer_settings.writeEntry( "/geometry/x", pos().x() ); + designer_settings.writeEntry( "/geometry/y", pos().y() ); + designer_settings.endGroup(); + //aLog::print(aLog::Debug,"exit"); + Q3MainWindow::closeEvent( e ); +} + + +void MainForm::connectSignals( CfgForm *cf ) +{ + connect(objNewFormAction, SIGNAL(activated()), cf, SLOT(newForm())); + connect(objNewTableAction, SIGNAL(activated()), cf, SLOT(newTable())); + connect(objNewFieldAction, SIGNAL(activated()), cf, SLOT(newField())); + connect(objRenameAction, SIGNAL(activated()), cf->mdtree, SLOT(itemRename())); + connect(objNewObjAction, SIGNAL(activated()), cf->mdtree, SLOT(itemNew())); + connect(objEditAction, SIGNAL(activated()), cf->mdtree, SLOT(itemEdit())); + connect(objDeleteAction, SIGNAL(activated()), cf->mdtree, SLOT(itemDelete())); +} + + +void MainForm::getMd( aCfg **md ) +{ + CfgForm *cf = cfgForm(); + if ( !cf ) return; + *md = &cf->cfg; +} + +/*! +Get current configuration form +*/ +CfgForm * +MainForm::cfgForm() +{ + CfgForm *res = 0; + QWidgetList windows = ws->windowList(); + for ( int i = 0; i < int( windows.count() ); ++i ) { + if ( strcmp( windows.at(i)->className(),"CfgForm") == 0 ){ + res = ( CfgForm *) windows.at(i); + break; + } + } + return res; +} + + +QWidget * +MainForm::activeWindow() +{ + return ws->activeWindow(); +} + + +int MainForm::getId() +{ + return lastFormId; +} + + +void MainForm::addTab(int uid, const QString& winName ) +{ + QWidgetList windows = ws->windowList(); + QToolButton* bt; + + QString S = winName; + for ( int i = 0; i < int( windows.count() ); i++ ) { + if( !strcmp(windows.at(i)->name(), S.ascii())) + { + windows.at(i)->setName(QString(windows.at(i)->name()+QString("_%1").arg(uid))); + //ixmap pixmap(*windows.at(i)->icon()); + bt = new QToolButton(QIcon(), + windows.at(i)->caption(), + "", + windows.at(i), + SLOT(setFocus( )), + tbTabs, + windows.at(i)->name() ); + + bt->setUsesTextLabel ( true ); +// bt->setAutoRaise ( true ); + // aLog::print(aLog::Debug, QString("button name = %1").arg(bt->name())); + break; + + } +/* if( windows.at(i)->isShown() and !strcmp(windows.at(i)->name(),"designer_mainwindow")) + { + + bt = new QToolButton(QIconSet(), + windows.at(i)->caption(), + "", + windows.at(i), + SLOT(setFocus( )), + tbTabs, + windows.at(i)->name() ); + + bt->setUsesTextLabel ( true ); +// bt->setAutoRaise ( true ); + printf("button name = %s\n",bt->name()); + break; + } + */ + } + // } +// if(windows.count()>1) + if(tbTabs->queryList ("QToolButton").size() > 0) + { + // tbTabs->show(); + + tbTabs->setShown( true ); + } + else + { + // tbTabs->hide(); + tbTabs->setShown( false ); + } +} + + +void MainForm::removeTab(const QString &winName ) +{ +// int ind = winName.findRev("_"); +// printf("winName = %s\n",winName.ascii()); +// QString str = winName; +// str = str.remove(ind,winName.length()-ind); + QObject *button = tbTabs->child( winName ); + if(button) + { + +// printf("deletes tab\n"); + delete button; + button = NULL; + } + +} + + +void MainForm::closeChildWindows() +{ + + QWidgetList windows = ws->windowList(); + for ( int i = 0; i < int( windows.count() ); i++ ) + { + if( windows.at(i)->className() != "CfgForm") + { + windows.at(i)->close(); + } + } +} + + +void MainForm::fileNewAction_activated() +{ + +} diff --git a/src/designer/mainform.h b/src/designer/mainform.h new file mode 100644 index 0000000..aa0937b --- /dev/null +++ b/src/designer/mainform.h @@ -0,0 +1,80 @@ +#ifndef MAINFORM_H +#define MAINFORM_H + +#include "ui_mainform.h" + + +class MainForm : public Q3MainWindow, public Ui::MainForm +{ + Q_OBJECT + +public: + MainForm(QWidget* parent = 0, const char* name = 0, Qt::WindowFlags fl = Qt::WType_TopLevel); + ~MainForm(); + + QLabel *msg; + QWorkspace *ws; + CfgForm *cfgform; + QString rcfile; + aCfg *md; + int lastFormId; + int lastTabId; + aWindowsList *wl; + //--QSettings designer_settings; + + virtual CfgForm * cfgForm(); + virtual QWidget * activeWindow(); + +public slots: + virtual void filePrint(); + virtual void fileExit(); + virtual void editUndo(); + virtual void editRedo(); + virtual void editCut(); + virtual void editCopy(); + virtual void editPaste(); + virtual void editFind(); + virtual void helpIndex(); + virtual void helpContents(); + virtual void helpAbout(); + virtual void init(); + virtual void configNew(); + virtual void configOpen(); + virtual void configSave(); + virtual void configSaveAs(); + virtual void fileOpen(); + virtual void fileSave(); + virtual void fileSaveAs(); + virtual void fileNew(); + virtual void connectSignals( CfgForm * cf ); + virtual void getMd( aCfg * * md ); + virtual int getId(); + virtual void addTab( int uid, const QString & winName ); + // -- Help for add to workspace + virtual void addTab(QWidget* window) { + ws->addWindow(window); + window->show(); + addTab(++lastTabId, window->objectName()); + }; + virtual void removeTab( const QString & winName ); + virtual void closeChildWindows(); + virtual void fileNewAction_activated(); + +signals: + void tosave(); + +protected slots: + virtual void languageChange(); + +private: + Q3PopupMenu *windowsMenu; + +private slots: + virtual void windowsMenuActivated( int id ); + virtual void windowsMenuAboutToShow(); + virtual void tileHorizontal(); + virtual void closeEvent( QCloseEvent * e ); + +}; + +#endif // MAINFORM_H diff --git a/src/designer/mainform.ui b/src/designer/mainform.ui new file mode 100644 index 0000000..bc8ef5e --- /dev/null +++ b/src/designer/mainform.ui @@ -0,0 +1,1391 @@ + + MainForm + + + + 0 + 0 + 677 + 570 + + + + + 0 + 0 + + + + + + + Ananas: Designer + + + + + 0 + 54 + 677 + 516 + + + + + + + 0 + 0 + 105 + 30 + + + + + + + + + + + + + 105 + 0 + 135 + 30 + + + + + + + + + + + + + + 240 + 0 + 75 + 30 + + + + + + + + + + + + 315 + 0 + 105 + 30 + + + + + + + + + + + + + 420 + 0 + 105 + 30 + + + + + + + + + + + + + 525 + 0 + 105 + 30 + + + + + + + + + + + + + 630 + 0 + 45 + 30 + + + + + + + + + + + 0 + 30 + 135 + 30 + + + + + + + + + + + + + + 0 + 60 + 19 + 16 + + + + true + + + true + + + Tabs + + + + + true + + + + 0 + 0 + 677 + 21 + + + + false + + + + &File + + + + + + + + + + + + &Edit + + + + + + + + + + + + + Configuration + + + + + + + + + Object + + + + + + + + + + + + + + + + + + + + + &New + + + &New + + + Ctrl+N + + + fileNewAction + + + + + + + + &Open... + + + &Open... + + + Ctrl+O + + + fileOpenAction + + + + + + + + &Save + + + &Save + + + actFileSave + + + Ctrl+S + + + fileSaveAction + + + + + Save &as... + + + Save &as... + + + + + + fileSaveAsAction + + + + + false + + + + + + &Print + + + &Print + + + Ctrl+P + + + filePrintAction + + + + + E&xit + + + E&xit + + + + + + fileExitAction + + + + + false + + + + + + Undo + + + Undo + + + Ctrl+Z + + + editUndoAction + + + + + false + + + + + + Redo + + + Redo + + + Ctrl+Y + + + editRedoAction + + + + + false + + + + + + Cut + + + Cut + + + Вырезать + + + Ctrl+X + + + editCutAction + + + + + false + + + + + + Copy + + + Copy + + + Копировать + + + Ctrl+C + + + editCopyAction + + + + + false + + + + + + Paste + + + Paste + + + Вставить + + + Ctrl+V + + + editPasteAction + + + + + false + + + + + + Find + + + Find + + + Ctrl+F + + + editFindAction + + + + + &Содержание... + + + Содержание + + + + + + helpContentsAction + + + + + &Индекс... + + + Индекс + + + + + + helpIndexAction + + + + + &О программе + + + О программе + + + + + + helpAboutAction + + + + + new item + + + new item + + + new_itemAction + + + + + new item + + + new item + + + new_itemAction_2 + + + + + Image Collection + + + Image Collection + + + configurationnew_itemAction + + + + + + :/images/filenew.png + + + New + + + New + + + Create new configuration + + + configNewAction + + + + + false + + + :/images/hi22-action-project_open.png + + + &Open + + + &Open + + + Open configuration + + + Open configuration + + + configOpenAction + + + + + :/images/filesave.png + + + Save + + + Save + + + Save configuration + + + Ctrl+S + + + configSaveAction + + + + + Создать/обновить БД + + + Создать/обновить БД + + + config_DBCreateAction + + + + configGroup + + + + + + Новая кнопка + + + Новая кнопка + + + NewButtonAction + + + + + Новый атрибут + + + Новый атрибут + + + NewAttributeAction + + + + + Новое поле + + + Новое поле + + + NewFieldAction + + + + formGroup + + + + + + :/images/form.png + + + New form + + + New form + + + objNewFormAction + + + + + Delete + + + Delete + + + objDeleteAction + + + + + :/images/field.png + + + New field + + + New field + + + objNewFieldAction + + + + + :/images/editrename.png + + + Rename + + + Rename + + + objRenameAction + + + + + Edit + + + Edit + + + objEditAction + + + + + :/images/table.png + + + New table + + + New table + + + objNewTableAction + + + + + :/images/object.png + + + New in group + + + New in group + + + objNewObjAction + + + + + :/images/editdelete.png + + + Delete + + + Delete + + + objTBDeleteAction + + + + + :/images/doc.png + + + New + + + New + + + objMetadataNewAction + + + + + :/images/editrename.png + + + Rename + + + Rename + + + objTBRenameAction + + + + + :/images/arrow_up.png + + + Move Up + + + Move Up + + + objTBMoveUpAction + + + + + :/images/arrow_down.png + + + Move Down + + + Move Down + + + objTBMoveDownAction + + + + + :/images/editedit.png + + + Edit + + + Edit + + + objMetadataEditAction + + + + + :/images/function.png + + + New Group + + + New Group + + + objActionsNewGroupAction + + + + + :/images/filenew.png + + + New + + + New + + + objActionsNewAction + + + + + :/images/editedit.png + + + Action + + + Action + + + objActionsEditAction + + + + + :/images/report_g.png + + + New Submenu + + + New Submenu + + + objInterfaceNewSubmenuAction + + + + + :/images/report.png + + + New Command + + + New Command + + + objInterfaceNewCommandAction + + + + + :/images/editsep.png + + + New Separator + + + New Separator + + + objInterfaceNewSeparatorAction + + + + + :/images/editedit.png + + + Edit + + + Edit + + + objInterfaceEditAction + + + + + :/images/editrename.png + + + Rename + + + Rename + + + objInterfaceRenameAction + + + + + :/images/filenew.png + + + New + + + New + + + objLanguagesNewAction + + + + + :/images/editedit.png + + + Edit + + + Edit + + + objLanguagesEditAction + + + + + :/images/editcut.png + + + Clear dead aliases + + + Clear dead aliases + + + objLanguagesClearAction + + + + + :/images/filenew.png + + + Add + + + Add + + + objImageCollectionAddAction + + + + + :/images/doc.png + + + Add new role + + + Add new role + + + objRoleNewAction + + + + + :/images/editcut.png + + + Clear dead roles + + + Clear dead roles + + + objRoleClearAction + + + + + :/images/editedit.png + + + Edit role + + + Edit role + + + objRoleEditAction + + + + objectGroup + + + + + qPixmapFromMimeSource + + + Q3ToolBar + Q3Frame +
q3listview.h
+
+ + Q3MainWindow + QWidget +
q3mainwindow.h
+ 1 +
+
+ + qworkspace.h + q3vbox.h + cfgform.h + q3popupmenu.h + awindowslist.h + qsettings.h + + + + + + + fileSaveAsAction + activated() + MainForm + fileSaveAs() + + + -1 + -1 + + + 20 + 20 + + + + + filePrintAction + activated() + MainForm + filePrint() + + + -1 + -1 + + + 20 + 20 + + + + + fileExitAction + activated() + MainForm + close() + + + -1 + -1 + + + 20 + 20 + + + + + editUndoAction + activated() + MainForm + editUndo() + + + -1 + -1 + + + 20 + 20 + + + + + editRedoAction + activated() + MainForm + editRedo() + + + -1 + -1 + + + 20 + 20 + + + + + editCutAction + activated() + MainForm + editCut() + + + -1 + -1 + + + 20 + 20 + + + + + editCopyAction + activated() + MainForm + editCopy() + + + -1 + -1 + + + 20 + 20 + + + + + editPasteAction + activated() + MainForm + editPaste() + + + -1 + -1 + + + 20 + 20 + + + + + editFindAction + activated() + MainForm + editFind() + + + -1 + -1 + + + 20 + 20 + + + + + helpIndexAction + activated() + MainForm + helpIndex() + + + -1 + -1 + + + 20 + 20 + + + + + helpContentsAction + activated() + MainForm + helpContents() + + + -1 + -1 + + + 20 + 20 + + + + + helpAboutAction + activated() + MainForm + helpAbout() + + + -1 + -1 + + + 20 + 20 + + + + + configNewAction + activated() + MainForm + configNew() + + + -1 + -1 + + + 20 + 20 + + + + + configOpenAction + activated() + MainForm + configOpen() + + + -1 + -1 + + + 20 + 20 + + + + + configSaveAction + activated() + MainForm + configSave() + + + -1 + -1 + + + 20 + 20 + + + + + objTBDeleteAction + activated() + MainForm + fileOpen() + + + -1 + -1 + + + 20 + 20 + + + + + fileNewAction + activated() + MainForm + configNew() + + + -1 + -1 + + + 20 + 20 + + + + + fileOpenAction + activated() + MainForm + configOpen() + + + -1 + -1 + + + 20 + 20 + + + + + fileSaveAction + activated() + MainForm + configSave() + + + -1 + -1 + + + 20 + 20 + + + + +
diff --git a/src/designer/mdtree.cpp b/src/designer/mdtree.cpp new file mode 100644 index 0000000..3650a1d --- /dev/null +++ b/src/designer/mdtree.cpp @@ -0,0 +1,1190 @@ +/**************************************************************************** +** $Id: mdtree.cpp,v 1.1 2008/11/05 21:16:27 leader Exp $ +** +** Code file of the Metadata Tree of Ananas Designer applications +** +** Created : 20031201 +** +** Copyright (C) 2003-2004 Leader InfoTech. All rights reserved. +** +** This file is part of the Designer application of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.leaderit.ru/page=ananas or email sales@leaderit.ru +** See http://www.leaderit.ru/gpl/ for GPL licensing information. +** +** Contact org@leaderit.ru if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "adatabase.h" +#include "mainform.h" +#include "deditfield.h" +#include "deditcfg.h" +#include "deditdoc.h" +#include "deditreport.h" +#include "deditdialog.h" +#include "deditcat.h" +#include "deditireg.h" +#include "deditareg.h" +#include "deditjournal.h" +#include "deditwebform.h" +#include "deditcolumns.h" +#include "awindowslist.h" + +//#include "acfg.h" +#include "acfgrc.h" + +#include "mdtree.h" + +extern MainForm *mainform; +extern QPixmap rcIcon(const char *name); +//extern void set_Icon(QListViewItem *item, const char *name); + + + +aListViewItem::aListViewItem(ananasListViewItem *parent, ananasListViewItem *after, aCfg *cfgmd, aCfgItem cfgobj, const QString &name ) +: ananasListViewItem( parent, after, cfgmd, cfgobj, name ) +{ + loadTree(); +} + + + +aListViewItem::aListViewItem(Q3ListView *parent, aCfg *cfgmd, aCfgItem cfgobj, const QString &name ) +: ananasListViewItem( parent, cfgmd, cfgobj, name ) +{ + loadTree(); +} + + +aListViewItem::~aListViewItem() +{ + +} + + +QString +aListViewItem::text( int column ) const +{ + return Q3ListViewItem::text( column ); +// if ( obj.isNull() ) return QObject::tr("Unknown object context"); + if ( !id ) return Q3ListViewItem::text( column ); + switch ( column ) { + case 0: return md->attr( obj, mda_name ); + default: + return ""; + } +} + +int +aListViewItem::compare( Q3ListViewItem *i, int col, bool accending ) const +{ + int id1 = 0, id2 = 0; + aListViewItem *ai = (aListViewItem *) i; + id1 = md->order( obj ); + id2 = ai->md->order( ai->obj ); + if ( md == ai->md && md->parent( obj ) == ai->md->parent( ai->obj ) && col ==0 && accending ) { + if ( id1 < id2 ) return -1; + if ( id1 == id2 ) return 0; + return 1; + } + return 1; +} + + +void +aListViewItem::setup() +{ + Q3ListViewItem::setup(); +} + + +/*! +Update metadata tree for the object context. +*/ +void +aListViewItem::update() +{ + +} + + +void +aListViewItem::loadTree() +{ + aListViewItem *item, *nextitem; + QString oclass, ldclass=""; + int i, n; + aCfgItem cobj; + + // clear tree + item = (aListViewItem *) firstChild(); + while( item ) { + nextitem = (aListViewItem *) item->nextSibling(); + delete item; + item = nextitem; + } + if ( !md ) return; + if (id) setRenameEnabled(0, true); + oclass = md->objClass( obj ); + if ( oclass == md_metadata ){ + cobj = md->find ( mdc_metadata ); + setPixmap(0, rcIcon("project.png")); + setOpen(true); + cobj = md->find ( obj, md_catalogues, 0 ); + if ( cobj.isNull() ) + { + cobj = md->insert( obj, md_catalogues, QString::null, -1 ); + } + new aListViewItem( this, getLastChild(), md, cobj, QObject::tr("Catalogues") ); + cobj = md->find ( obj, md_documents, 0 ); + if ( cobj.isNull() ) + { + cobj = md->insert( obj, md_documents, QString::null, -1 ); + } + new aListViewItem( this, getLastChild(), md, cobj, QObject::tr("Documents") ); + cobj = md->find ( obj, md_reports, 0 ); + if ( cobj.isNull() ) + { + cobj = md->insert( obj, md_reports, QString::null, -1 ); + } + new aListViewItem( this, getLastChild(), md, cobj, QObject::tr("Reports") ); + cobj = md->find ( obj, md_journals, 0 ); + if ( cobj.isNull() ) + { + cobj = md->insert( obj, md_journals, QString::null, -1 ); + } + new aListViewItem( this, getLastChild(), md, cobj, QObject::tr("Journals") ); + cobj = md->find ( obj, md_registers, 0 ); + if ( cobj.isNull() ) + { + cobj = md->insert( obj, md_registers, QString::null, -1 ); + } + cobj = md->find ( obj, md_iregisters, 0 ); + if ( cobj.isNull() ) + { + cobj = md->insert( md->find (obj, md_registers, 0 ), md_iregisters, QString::null, -1 ); + } + new aListViewItem( this, getLastChild(), md, cobj, QObject::tr("Information registers") ); + cobj = md->find ( obj, md_aregisters, 0 ); + if ( cobj.isNull() ) + { + cobj = md->insert( md->find (obj, md_registers, 0 ), md_aregisters, QString::null, -1 ); + } + new aListViewItem( this, getLastChild(), md, cobj, QObject::tr("Accumulation registers") ); + } + if ( oclass == md_catalogues ){ + setPixmap(0, rcIcon("cat_g.png") ); + ldclass = md_catalogue; + } + if ( oclass == md_documents ){ + setPixmap(0, rcIcon("doc_g.png")); + ldclass = md_document; + } + if ( oclass == md_reports ){ + setPixmap(0, rcIcon("report_g.png")); + ldclass = md_report; + } + if ( oclass == md_journals ){ + setPixmap(0, rcIcon("journ_g.png")); + ldclass = md_journal; + } + if ( oclass == md_iregisters ){ + setPixmap(0, rcIcon("reg_g.png")); + ldclass = md_iregister; + } + if ( oclass == md_aregisters ){ + setPixmap(0, rcIcon("regs_g.png")); + ldclass = md_aregister; + } + if ( !ldclass.isEmpty() ) { +// printf("%s\n",(const char *) md->toString().local8Bit() ); + n = md->count( obj, ldclass ); +// printf(" objclass=%s ldclass = %s count = %d\n", (const char *) oclass, (const char *) ldclass, n); + for ( i = 0; ifind( obj, ldclass, i ); + if ( !cobj.isNull() ) { +// printf("%d ok\n", i); +// new aListViewItem( this, md, md->find( obj, ldclass, i ), QString::null ); + new aListViewItem( this, getLastChild(), md, cobj, QString::null ); + } + } + } + + if ( oclass == md_tables ){ + setPixmap(0, rcIcon("table_g.png")); + return; + } + if ( oclass == md_forms ){ + setPixmap(0, rcIcon("form_g.png")); + return; + } + if ( oclass == md_form ){ + setPixmap(0, rcIcon("form.png")); + return; + } + if ( oclass == md_webforms ){ + setPixmap(0, rcIcon("webform_g.png")); + return; + } + if ( oclass == md_webform ){ + setPixmap(0, rcIcon("webform.png")); + return; + } + if ( oclass == md_table ) + { + setPixmap(0, rcIcon("table.png")); + return; + } + +// elements + if ( oclass == md_catalogue ){ + setPixmap(0, rcIcon("cat.png")); + loadCatalogue (); + return; + } + if ( oclass == md_document ){ + setPixmap(0, rcIcon("doc.png")); + loadDocument (); + return; + } + if ( oclass == md_aregister ){ + setPixmap(0, rcIcon("regs.png")); + loadARegister (); + return; + } + if ( oclass == md_iregister ){ + setPixmap(0, rcIcon("reg.png")); + loadIRegister (); + return; + } + if ( oclass == md_journal ){ + setPixmap(0, rcIcon("journ.png")); + loadJournal (); + return; + } + if ( oclass == md_report ){ + setPixmap(0, rcIcon("report.png")); + loadReport (); + return; + } + if ( oclass == md_field ){ + setPixmap(0, rcIcon("field.png")); + return; + } + if ( oclass == md_header ) + { + setPixmap(0, rcIcon("doc_h.png")); + return; + } + if ( oclass == md_element) + { + setPixmap(0, rcIcon("element.png")); + return; + } + if( oclass == md_columns ) + { + setPixmap(0, rcIcon("columns.png")); + return; + } + if ( oclass == md_resources ) + { + setPixmap(0, rcIcon("resourses.png")); + return; + } + if ( oclass == md_dimensions ) + { + setPixmap(0, rcIcon("dimensions.png")); + return; + } + if ( oclass == md_information ) + { + setPixmap(0, rcIcon("information.png")); + return; + } + if (oclass == md_group) + { + setPixmap(0, rcIcon("group.png")); + return; + } +} + +void +aListViewItem::loadDocument () +{ + int n, i; + aCfgItem cobj; + aListViewItem *tparent, *fparent; + + fparent = new aListViewItem( this, getLastChild(), md, md->find(obj, md_header, 0), QObject::tr("Header") ); + loadFields ( fparent ); + + tparent = new aListViewItem( this, getLastChild(), md, md->find(obj, md_tables, 0), QObject::tr("Tables") ); + n = md->count ( obj, md_table ); + for ( i = 0; i < n; i++ ) + { + cobj = md->find( obj, md_table, i ); + if ( !cobj.isNull() ) + { + fparent = new aListViewItem( tparent, tparent->getLastChild(), md, cobj, QString::null ); + loadFields ( fparent ); + } + } + loadForms ( this ); + loadWebForms ( this ); +} + +/*void +aListViewItem::loadTable () +{ + int n, i; + QString ldclass; + aCfgItem cobj; + +}*/ + +void +aListViewItem::loadFields (aListViewItem *parent) +{ + int n, i; + aCfgItem cobj; + + n = md->count ( parent->obj, md_field ); + for ( i = 0; i < n; i++ ) + { + cobj = md->find( parent->obj, md_field, i ); + if ( !cobj.isNull() ) + { + new aListViewItem( parent, parent->getLastChild(), md, cobj, QString::null ); + } + } +} + +void +aListViewItem::loadForms (aListViewItem *parent) +{ + int n, i; + aCfgItem cobj, gobj; + aListViewItem *fparent; + + gobj = md->find(obj, md_forms, 0); + if ( gobj.isNull() ) gobj = md->insert( obj, md_forms, QString::null, -1 ); + fparent = new aListViewItem( parent, getLastChild(), md, gobj, QObject::tr("Forms") ); + n = md->count ( fparent->obj, md_form ); + for ( i = 0; i < n; i++ ) + { + cobj = md->find( fparent->obj, md_form, i ); + if ( !cobj.isNull() ) + { + new aListViewItem( fparent, getLastChild(), md, cobj, QString::null ); + } + } +} + +void +aListViewItem::loadWebForms (aListViewItem *parent) +{ + int n, i; + aCfgItem cobj, gobj; + aListViewItem *fparent; + + gobj = md->find(obj, md_webforms, 0); + if ( gobj.isNull() ) gobj = md->insert( obj, md_webforms, QString::null, -1 ); + fparent = new aListViewItem( parent, getLastChild(), md, md->find(obj, md_webforms, 0), QObject::tr("Web forms") ); + n = md->count ( fparent->obj, md_webform ); + for ( i = 0; i < n; i++ ) + { + cobj = md->find( fparent->obj, md_webform, i ); + if ( !cobj.isNull() ) + { + new aListViewItem( fparent, getLastChild(), md, cobj, QString::null ); + } + } +} + +void +aListViewItem::loadJournal () +{ + aListViewItem *fparent; + + fparent = new aListViewItem( this, getLastChild(), md, md->find(obj, md_columns, 0), QObject::tr("Columns") ); + loadColumns( fparent ); + loadForms ( this ); + loadWebForms ( this ); +} + +void +aListViewItem::loadIRegister () +{ + aListViewItem *fparent; + + fparent = new aListViewItem( this, getLastChild(), md, md->find(obj, md_resources, 0), QObject::tr("Resources") ); + loadFields ( fparent ); + fparent = new aListViewItem( this, getLastChild(), md, md->find(obj, md_dimensions, 0), QObject::tr("Dimensions") ); + loadFields ( fparent ); + fparent = new aListViewItem( this, getLastChild(), md, md->find(obj, md_information, 0), QObject::tr("Information") ); + loadFields ( fparent ); +} + +void +aListViewItem::loadARegister () +{ + aListViewItem *fparent; + + fparent = new aListViewItem( this, getLastChild(), md, md->find(obj, md_resources, 0), QObject::tr("Resources") ); + loadFields ( fparent ); + fparent = new aListViewItem( this, getLastChild(), md, md->find(obj, md_dimensions, 0), QObject::tr("Dimensions") ); + loadFields ( fparent ); + fparent = new aListViewItem( this, getLastChild(), md, md->find(obj, md_information, 0), QObject::tr("Information") ); + loadFields ( fparent ); +} + +void +aListViewItem::loadCatalogue () +{ + aListViewItem *fparent; + aCfgItem i; + + i = md->find(obj, md_element, 0); + if ( i.isNull() ) i = md->insert( obj, md_element, QString::null, -1 ); + fparent = new aListViewItem( this, getLastChild(), md, i, QObject::tr("Element") ); + loadFields ( fparent ); + i = md->find(obj, md_group, 0); + if ( i.isNull() ) i = md->insert( obj, md_group, QString::null, -1 ); + fparent = new aListViewItem( this, getLastChild(), md, i, QObject::tr("Group") ); + loadFields ( fparent ); + loadForms ( this ); + loadWebForms ( this ); +} + +void aListViewItem::loadReport () +{ + loadForms ( this ); + loadWebForms ( this ); +} + +void +aListViewItem::loadColumns ( aListViewItem *parent ) +{ + int i,n; + aCfgItem cobj; + + n = md->count ( parent->obj, md_column ); + for ( i = 0; i < n; i++) + { + cobj = md->find( parent->obj, md_column, i ); + if ( !cobj.isNull() ) + { + new aListViewItem( parent, getLastChild(), md, cobj, QString::null ); + } + } +} + + +/* +*edit selected object +*/ + +void +aListViewItem::edit() +{ + QWorkspace *ws = mainform->ws; + aWindowsList *wl = mainform->wl; + QString oclass = md->objClass( obj ); + int objid = md->id( obj ); + if ( wl->find( objid ) ) { + wl->get( objid )->setFocus(); + return; + } + + if ( oclass == md_metadata ) + { + dEditCfg *e = new dEditCfg( ws, 0, Qt::WDestructiveClose ); + wl->insert( objid, e ); + editor = e; + QObject::connect( mainform, SIGNAL( tosave() ), editor, SLOT( updateMD() ) ); + e->setData( this ); + e->show(); + // mainform->addTab(); + //--mainform->addTab(++mainform->lastTabId,e->name()); + mainform->addTab(e); + e->parentWidget()->setGeometry(0,0,e->parentWidget()->frameSize().width(), + e->parentWidget()->frameSize().height()); + return; + } +// if ( !md || !id ) return; + if ( oclass == md_document) + { + dEditDoc *e = new dEditDoc( ws, 0, Qt::WDestructiveClose ); + wl->insert( objid, e ); + editor = e; + QObject::connect( mainform, SIGNAL( tosave() ), editor, SLOT( updateMD() ) ); + e->setData( this ); + e->show(); + //--mainform->addTab(++mainform->lastTabId,e->name()); + mainform->addTab(e); + e->parentWidget()->setGeometry(0,0,e->parentWidget()->frameSize().width(), + e->parentWidget()->frameSize().height()); + return; + }; + if ( oclass == md_iregister) + { + dEditIReg *e = new dEditIReg( ws, 0, Qt::WDestructiveClose ); + wl->insert( objid, e ); + editor = e; + QObject::connect( mainform, SIGNAL( tosave() ), editor, SLOT( updateMD() ) ); + e->setData( this ); + e->show(); + //mainform->updateTabs(); + //--mainform->addTab(++mainform->lastTabId,e->name()); + mainform->addTab(e); + e->parentWidget()->setGeometry(0,0,e->parentWidget()->frameSize().width(), + e->parentWidget()->frameSize().height()); + return; + }; + if ( oclass == md_aregister) + { + dEditAReg *e = new dEditAReg( ws, 0, Qt::WDestructiveClose ); + wl->insert( objid, e ); + editor = e; + QObject::connect( mainform, SIGNAL( tosave() ), editor, SLOT( updateMD() ) ); + e->setData( this ); + e->show(); + //mainform->updateTabs(); + //--mainform->addTab(++mainform->lastTabId,e->name()); + mainform->addTab(e); + e->parentWidget()->setGeometry(0,0,e->parentWidget()->frameSize().width(), + e->parentWidget()->frameSize().height()); + return; + }; + if ( oclass == md_catalogue) + { + dEditCat *e = new dEditCat( ws, 0, Qt::WDestructiveClose ); + wl->insert( objid, e ); + editor = e; + QObject::connect( mainform, SIGNAL( tosave() ), editor, SLOT( updateMD() ) ); + e->setData( this ); + e->show(); + // mainform->updateTabs(); + //--mainform->addTab(++mainform->lastTabId,e->name()); + mainform->addTab(e); + e->parentWidget()->setGeometry(0,0,e->parentWidget()->frameSize().width(), + e->parentWidget()->frameSize().height()); + return; + }; + if ( oclass == md_field ) + { + dEditField *e = new dEditField( ws, 0, Qt::WDestructiveClose ); + wl->insert( objid, e ); + editor = e; + QObject::connect( mainform, SIGNAL( tosave() ), editor, SLOT( updateMD() ) ); + e->setData( this ); + e->show(); + //mainform->updateTabs(); + //--mainform->addTab(++mainform->lastTabId,e->name()); + mainform->addTab(e); + e->parentWidget()->setGeometry(0,0,e->parentWidget()->frameSize().width(), + e->parentWidget()->frameSize().height()); + return; + }; + if ( oclass == md_report ) + { + dEditReport *e = new dEditReport( ws, 0, Qt::WDestructiveClose ); + wl->insert( objid, e ); + editor = e; + QObject::connect( mainform, SIGNAL( tosave() ), editor, SLOT( updateMD() ) ); + e->setData( this ); + e->show(); + //mainform->updateTabs(); + //--mainform->addTab(++mainform->lastTabId,e->name()); + mainform->addTab(e); + e->parentWidget()->setGeometry(0,0,e->parentWidget()->frameSize().width(), + e->parentWidget()->frameSize().height()); + return; + }; + if ( oclass == md_journal ) + { + dEditJournal *e = new dEditJournal( ws, 0, Qt::WDestructiveClose ); + wl->insert( objid, e ); + editor = e; + QObject::connect( mainform, SIGNAL( tosave() ), editor, SLOT( updateMD() ) ); + e->setData( this ); + e->show(); + //mainform->updateTabs(); + //--mainform->addTab(++mainform->lastTabId, e->name()); + mainform->addTab(e); + e->parentWidget()->setGeometry(0,0,e->parentWidget()->frameSize().width(), + e->parentWidget()->frameSize().height()); + return; + }; + if ( oclass == md_form ) + { + dEditDialog *e = new dEditDialog( ws, 0, Qt::WDestructiveClose ); + wl->insert( objid, e ); + editor = e; + e->setData( this ); + QObject::connect( mainform, SIGNAL( tosave() ), editor, SLOT( updateMD() ) ); + e->show(); + //mainform->updateTabs(); + //--mainform->addTab(++mainform->lastTabId,e->name()); + mainform->addTab(e); + e->parentWidget()->setGeometry(0,0,e->parentWidget()->frameSize().width(), + e->parentWidget()->frameSize().height()); + return; + }; + if ( oclass == md_webform ) + { + dEditWebForm *e = new dEditWebForm( ws, 0, Qt::WDestructiveClose ); + wl->insert( objid, e ); + editor = e; + QObject::connect( mainform, SIGNAL( tosave() ), editor, SLOT( updateMD() ) ); + e->setData( this ); + e->show(); + //mainform->updateTabs(); + //--mainform->addTab(++mainform->lastTabId,e->name()); + mainform->addTab(e); + e->parentWidget()->setGeometry(0,0,e->parentWidget()->frameSize().width(), + e->parentWidget()->frameSize().height()); + return; + }; + if ( oclass == md_column ) + { + dEditColumns *e = new dEditColumns( ws, 0, Qt::WDestructiveClose ); + wl->insert( objid, e ); + editor = e; + QObject::connect( mainform, SIGNAL( tosave() ), editor, SLOT( updateMD() ) ); + e->setData( this ); + e->show(); + //mainform->updateTabs(); + //--mainform->addTab(++mainform->lastTabId,e->name()); + mainform->addTab(e); + e->parentWidget()->setGeometry(0,0,e->parentWidget()->frameSize().width(), + e->parentWidget()->frameSize().height()); + return; + } +} + +void aListViewItem::newObject() +{ + QString oclass = md->objClass( obj ); +// printf("oclass = %s\n",( const char *) oclass ); + if ( oclass == md_header || oclass == md_table || + oclass == md_element || oclass == md_group || + oclass == md_resources || oclass == md_dimensions || oclass == md_information || + oclass == md_columns ) + newField(); + if ( oclass == md_documents ) newDocument(); + if ( oclass == md_catalogues ) newCatalogue(); + if ( oclass == md_journals ) newJournal(); + if ( oclass == md_iregisters ) newIRegister(); + if ( oclass == md_aregisters ) newARegister(); + if ( oclass == md_reports ) newReport(); + if ( oclass == md_forms ) newForm(); + if ( oclass == md_webforms ) newWebForm(); + if ( oclass == md_tables ) newTable(); + if ( oclass == md_columns ) newColumn(); +} + +void aListViewItem::saveItem() +{ + + //md->saveOneObject() + QString oclass = md->objClass( obj ); + if ( oclass == md_field || + oclass == md_document || + oclass == md_catalogue || + oclass == md_journal || + oclass == md_iregister || + oclass == md_aregister || + oclass == md_report || + oclass == md_webform || + oclass == md_form || + oclass == md_table) + { + + QString fname; + Q3FileDialog fd( QString::null, + QObject::tr("any files (*)"), + 0, 0, TRUE ); + fd.setMode(Q3FileDialog::AnyFile); +// fd.addFilter(tr(" (*.bsa)")); + fd.setSelection( oclass + md->attr(obj,mda_id) ); + if ( fd.exec() == QDialog::Accepted ) + { + fname = QDir::convertSeparators(fd.selectedFile()); + md->saveOneObject(obj,fname); + } + } +} + +void aListViewItem::loadItem() +{ + + QString oclass = md->objClass( obj ); + + if ( oclass == md_header || + oclass == md_table || + oclass == md_element || + oclass == md_group || + oclass == md_resources || + oclass == md_dimensions || + oclass == md_information || + oclass == md_columns || + oclass == md_documents || + oclass == md_catalogues || + oclass == md_journals || + oclass == md_iregisters || + oclass == md_aregisters || + oclass == md_reports || + oclass == md_forms || + oclass == md_webforms || + oclass == md_tables || + oclass == md_columns ) + { + + QString fname; + Q3FileDialog fd( QString::null, + QObject::tr("any files (*)"), + 0, 0, TRUE ); + fd.setMode(Q3FileDialog::ExistingFiles); + aCfgItem loadObj; +// fd.addFilter(tr(" (*.bsa)")); +// fd.setSelection( QDir::convertSeparators(eCfgName->text())); + if ( fd.exec() == QDialog::Accepted ) + { + fname = QDir::convertSeparators(fd.selectedFile()); + // load object from file + // aCfgItem loadObj = c.loadOneObject("catalogue_copy.xml"); + // change name + // c.setAttr(loadObj, mda_name, "CATALOGUE1 COPY!!!"); + // append to cfg + // c.importCfgItem( c.find(c.find(0), md_catalogues) , loadObj); + // + loadObj = md->loadOneObject(fname); + if(loadObj.isNull()) + { + return; + } + else + { + md->setAttr(loadObj, mda_name, QString("%1_copy").arg(md->attr(loadObj, mda_name))); + QString loclass = md->objClass(loadObj); + if ( loclass==md_field && + (oclass == md_header || oclass == md_table || + oclass == md_element || oclass == md_group || + oclass == md_resources || oclass == md_dimensions || + oclass == md_information || oclass == md_columns )) + { + aCfgItem newobj = md->importCfgItem( obj, loadObj ); + aListViewItem *newitem = new aListViewItem( this, getLastChild(), md, newobj ); +// newitem->setOpen( TRUE ); + } + if ( loclass==md_document && oclass == md_documents ) + { + //md->importCfgItem( obj, loadObj ); + aCfgItem newobj = md->importCfgItem( obj, loadObj ); + aListViewItem *newitem = new aListViewItem( this, getLastChild(), md, newobj ); + } + if ( loclass==md_catalogue && oclass == md_catalogues ) + { + aCfgItem newobj = md->importCfgItem( obj, loadObj ); + aListViewItem *newitem = new aListViewItem( this, getLastChild(), md, newobj ); + } + if ( loclass==md_journal && oclass == md_journals ) + { + aCfgItem newobj = md->importCfgItem( obj, loadObj ); + aListViewItem *newitem = new aListViewItem( this, getLastChild(), md, newobj ); + } + if ( loclass==md_iregister && oclass == md_iregisters ) + { + aCfgItem newobj = md->importCfgItem( obj, loadObj ); + aListViewItem *newitem = new aListViewItem( this, getLastChild(), md, newobj ); + } + if ( loclass==md_aregister && oclass == md_aregisters ) + { + aCfgItem newobj = md->importCfgItem( obj, loadObj ); + aListViewItem *newitem = new aListViewItem( this, getLastChild(), md, newobj ); + } + if ( loclass==md_report && oclass == md_reports ) + { + aCfgItem newobj = md->importCfgItem( obj, loadObj ); + aListViewItem *newitem = new aListViewItem( this, getLastChild(), md, newobj ); + } + if ( loclass==md_form && oclass == md_forms ) + { + aCfgItem newobj = md->importCfgItem( obj, loadObj ); + aListViewItem *newitem = new aListViewItem( this, getLastChild(), md, newobj ); + } + if ( loclass==md_webform && oclass == md_webforms ) + { + aCfgItem newobj = md->importCfgItem( obj, loadObj ); + aListViewItem *newitem = new aListViewItem( this, getLastChild(), md, newobj ); + } + if ( loclass==md_table && oclass == md_tables ) + { + aCfgItem newobj = md->importCfgItem( obj, loadObj ); + aListViewItem *newitem = new aListViewItem( this, getLastChild(), md, newobj ); + } + } + } + } +} + + +void +aListViewItem::newField() +{ + aListViewItem *newitem; + aCfgItem newobj; + + QString oclass = md->objClass( obj ); + if (oclass == md_header || oclass == md_table || + oclass == md_element || oclass == md_group || + oclass == md_resources || oclass == md_dimensions || oclass == md_information) + { + setSelected( FALSE ); + setOpen( TRUE ); + newobj = md->insert( obj, md_field, QObject::tr("New field") ); + newitem = new aListViewItem( this, getLastChild(), md, newobj ); +// newitem->setSelected( TRUE ); + newitem->edit(); + } +} + + +void +aListViewItem::newDocument() +{ + aListViewItem *newitem; + aCfgItem newobj; + + if ( md->objClass( obj ) == md_documents ) { + setSelected( FALSE ); + setOpen( TRUE ); + newobj = md->insertDocument( QObject::tr("New document") ); +/* md->insert( newobj, md_header, QString::null, -1 ); + md->insert( newobj, md_tables, QString::null, -1 ); + md->insert( newobj, md_forms, QString::null, -1 ); + md->insert( newobj, md_webforms, QString::null, -1 ); +*/ newitem = new aListViewItem( this, getLastChild(), md, newobj ); +// newitem->setSelected( TRUE ); + newitem->setOpen( TRUE ); + newitem->edit(); + } +} + + +void +aListViewItem::newCatalogue() +{ + aListViewItem *newitem; + aCfgItem newobj; + + if ( md->objClass( obj ) == md_catalogues ) { + setSelected( FALSE ); + setOpen( TRUE ); + newobj = md->insertCatalogue( QObject::tr("New catalogue") ); +/* md->insert( newobj, md_element, QString::null, -1 ); + md->insert( newobj, md_group, QString::null, -1 ); + md->insert( newobj, md_forms, QString::null, -1 ); + md->insert( newobj, md_webforms, QString::null, -1 );*/ + newitem = new aListViewItem( this, getLastChild(), md, newobj ); +// newitem->setSelected( TRUE ); + newitem->setOpen( TRUE ); + newitem->edit(); + } +} + +void +aListViewItem::newJournal() +{ + aListViewItem *newitem; + aCfgItem newobj; + + if ( md->objClass( obj ) == md_journals ) { + setSelected( FALSE ); + setOpen( TRUE ); + newobj = md->insertJournal( QObject::tr("New journal") ); +/* md->insert( newobj, md_columns, QString::null, -1 ); + md->insert( newobj, md_forms, QString::null, -1 ); + md->insert( newobj, md_webforms, QString::null, -1 );*/ + newitem = new aListViewItem( this, getLastChild(), md, newobj ); +// newitem->setSelected( TRUE ); + newitem->setOpen( TRUE ); + newitem->edit(); + } +} + +void +aListViewItem::newIRegister() +{ + aListViewItem *newitem; + aCfgItem newobj; + + if ( md->objClass( obj ) == md_iregisters ) + { + setSelected( FALSE ); + setOpen( TRUE ); + newobj = md->insertIRegister( QObject::tr("New information register") ); +/* md->insert( newobj, md_resources, QString::null, -1 ); + md->insert( newobj, md_dimensions, QString::null, -1 ); + md->insert( newobj, md_information, QString::null, -1 );*/ + newitem = new aListViewItem( this, getLastChild(), md, newobj ); +// newitem->setSelected( TRUE ); + newitem->setOpen( TRUE ); + newitem->edit(); + } +} + +void +aListViewItem::newARegister() +{ + aListViewItem *newitem; + aCfgItem newobj; + + if ( md->objClass( obj ) == md_aregisters ) + { + setSelected( FALSE ); + setOpen( TRUE ); + newobj = md->insertARegister( QObject::tr("New accumulation register") ); +/* md->insert( newobj, md_resources, QString::null, -1 ); + md->insert( newobj, md_dimensions, QString::null, -1 ); + md->insert( newobj, md_information, QString::null, -1 );*/ + newitem = new aListViewItem( this, getLastChild(), md, newobj ); +// newitem->setSelected( TRUE ); + newitem->setOpen( TRUE ); + newitem->edit(); + } +} + +void +aListViewItem::newReport() +{ + aListViewItem *newitem; + aCfgItem newobj; + + if ( md->objClass( obj ) == md_reports ) + { + setSelected( FALSE ); + setOpen( TRUE ); + newobj = md->insert( obj, md_report, QObject::tr("New report") ); + md->insert( newobj, md_forms, QString::null, -1 ); + md->insert( newobj, md_webforms, QString::null, -1 ); + newitem = new aListViewItem( this, getLastChild(), md, newobj ); +// newitem->setSelected( TRUE ); + newitem->setOpen( TRUE ); + newitem->edit(); + } +} + +void +aListViewItem::newForm() +{ + aListViewItem *newitem; + aCfgItem newobj; + + if ( md->objClass( obj ) == md_forms ) + { + setSelected( FALSE ); + setOpen( TRUE ); + newobj = md->insert( obj, md_form, QObject::tr("New form") ); + newitem = new aListViewItem( this, getLastChild(), md, newobj ); +// newitem->setSelected( TRUE ); + newitem->setOpen( TRUE ); + newitem->edit(); + } +} + +void +aListViewItem::newWebForm() +{ + aListViewItem *newitem; + aCfgItem newobj; + + if ( md->objClass( obj ) == md_webforms ) + { + setSelected( FALSE ); + setOpen( TRUE ); + newobj = md->insert( obj, md_webform, QObject::tr("New web form") ); + newitem = new aListViewItem( this, getLastChild(), md, newobj ); +// newitem->setSelected( TRUE ); + newitem->setOpen( TRUE ); + newitem->edit(); + } +} + +void +aListViewItem::newTable() +{ + aListViewItem *newitem; + aCfgItem newobj; + + if ( md->objClass( obj ) == md_tables ) + { + setSelected( FALSE ); + setOpen( TRUE ); + newobj = md->insert( obj, md_table, QObject::tr("New Table") ); + newitem = new aListViewItem( this, getLastChild(), md, newobj ); +// newitem->setSelected( TRUE ); + newitem->setOpen( TRUE ); + newitem->edit(); + } +} + +void +aListViewItem::newColumn() +{ + aListViewItem *newitem; + aCfgItem newobj; + + if ( md->objClass( obj ) == md_columns ) + { + setSelected( FALSE ); + setOpen( TRUE ); + newobj = md->insert( obj, md_column, QObject::tr("New Column") ); + newitem = new aListViewItem( this, getLastChild(), md, newobj ); + newitem->edit(); + } +} + +aMetadataTreeView::aMetadataTreeView( QWidget *parent, aCfg *cfgmd ) +:ananasTreeView( parent, cfgmd ) +{ + aListViewItem *conf; + + if ( !md ) return; + conf = new aListViewItem( this, md, md->find( mdc_metadata ), md->info( mda_name )); + conf->setOpen( TRUE ); + connect( this, SIGNAL( contextMenuRequested( Q3ListViewItem*, const QPoint&, int) ), this, SLOT(ContextMenu() ) ); + connect( this, SIGNAL( returnPressed( Q3ListViewItem* ) ), this, SLOT( itemEdit() ) ); + connect( this, SIGNAL( doubleClicked( Q3ListViewItem* ) ), this, SLOT( itemEdit() ) ); + connect( this, SIGNAL( collapsed( Q3ListViewItem* ) ), this, SLOT( on_collapsed( Q3ListViewItem* ) ) ); +} + +void +aMetadataTreeView::on_collapsed( Q3ListViewItem * item ) +{ + aListViewItem *i = (aListViewItem *) item; + if ( i ) + { + QString oclass = md->objClass( i->obj ); + if ( oclass == md_metadata ) setOpen( i, true ); + } +} + + +void +aMetadataTreeView::ContextMenu() +{ + + Q3PopupMenu *m=new Q3PopupMenu( this, "PopupMenu" ); + Q_CHECK_PTR(m); + +/* QLabel *caption = new QLabel( "" + "Context Menu", this ); + caption->setAlignment( Qt::AlignCenter ); + m->insertItem( caption ); + m->insertItem( "&New", this, SLOT( itemNew() ), CTRL+Key_N ); + m->insertItem( "&Rename", this, SLOT( itemRename() ), CTRL+Key_O); + m->insertItem( "&Edit", this, SLOT( itemEdit() ), CTRL+Key_N ); + m->insertItem( "&Delete", this, SLOT( itemDelete() ), CTRL+Key_O );*/ + + ContextMenuAdd(m); + m->insertItem( tr("&New"), this, SLOT( itemNew() ), Qt::CTRL+Qt::Key_N ); + m->exec( QCursor::pos() ); + delete m; +} + + +void +aMetadataTreeView::itemRename() +{ + renameItem(); +} + +void +aMetadataTreeView::itemNew() +{ + aListViewItem *i = (aListViewItem *) selectedItem(); + if ( i ) + { + //if ( i->id == 0 ) + i->newObject(); + } +} + + +void +aMetadataTreeView::itemDelete() +{ + deleteItem(); +} + + +void +aMetadataTreeView::itemEdit() +{ + aListViewItem *i = (aListViewItem *) selectedItem(); + if ( i ) + { + i->edit(); + } +} + +void +aMetadataTreeView::itemSave() +{ + aListViewItem *i = (aListViewItem *) selectedItem(); + if ( i ) + { + i->saveItem(); + } +} + +void +aMetadataTreeView::itemLoad() +{ + aListViewItem *i = (aListViewItem *) selectedItem(); + if ( i ) + { + i->loadItem(); + } +} +void +aMetadataTreeView::itemMoveUp() +{ + moveUpItem(); +} + +void +aMetadataTreeView::itemMoveDown() +{ + + moveDownItem(); +} diff --git a/src/designer/mdtree.h b/src/designer/mdtree.h new file mode 100644 index 0000000..a7efc9f --- /dev/null +++ b/src/designer/mdtree.h @@ -0,0 +1,115 @@ +/**************************************************************************** +** $Id: mdtree.h,v 1.1 2008/11/05 21:16:27 leader Exp $ +** +** Header file of the Metadata Tree of Ananas Designer applications +** +** Created : 20031201 +** +** Copyright (C) 2003-2004 Leader InfoTech. All rights reserved. +** +** This file is part of the Designer application of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.leaderit.ru/page=ananas or email sales@leaderit.ru +** See http://www.leaderit.ru/gpl/ for GPL licensing information. +** +** Contact org@leaderit.ru if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#ifndef MDTREE_H +#define MDTREE_H +#include +#include +#include "acfg.h" +#include "formdesigner.h" +#include "atreeitems.h" + +extern aFormDesigner *formdesigner; +//#include "cfg.h" +class QWidget; + +class aListViewItem : public ananasListViewItem +{ +public: +/* int id; + aCfgItem obj; + QWidget *editor; + aCfg *md; +*/ + aListViewItem(ananasListViewItem *parent, ananasListViewItem *after, aCfg * cfgmd, aCfgItem cfgobj, const QString &name = QString::null ); +// aListViewItem(QListViewItem *parent, aCfg * cfgmd, aCfgItem cfgobj, const QString &name = QString::null ); + aListViewItem(Q3ListView *parent, aCfg * cfgmd, aCfgItem obj, const QString &name = QString::null ); + ~aListViewItem(); + QString text( int column ) const; + void loadTree(); + void setup(); + void update(); + void edit(); + void newObject(); + void newField(); + void newDocument(); + void newCatalogue(); + void newJournal(); + void newIRegister(); + void newARegister(); + void newReport(); + void newForm(); + void newWebForm(); + void newTable(); + void newColumn(); + void saveItem(); + void loadItem(); + + +protected: +// virtual void okRename( int col ); + virtual int compare( Q3ListViewItem *i, int col, bool accending ) const; +private: + void loadDocument (); + void loadJournal (); + void loadIRegister (); + void loadARegister (); + void loadCatalogue (); + void loadReport (); + void loadFields (aListViewItem *parent); + void loadForms (aListViewItem *parent); + void loadWebForms (aListViewItem *parent); + void loadColumns ( aListViewItem *parent ); +}; + + +class aMetadataTreeView : public ananasTreeView +{ + Q_OBJECT +public: +// aCfg *md; + + aMetadataTreeView( QWidget *parent, aCfg *cfgmd ); + +public slots: + void ContextMenu(); + void itemNew(); + void itemEdit(); + void itemMoveUp();//не работает, проверить поиск элементов в визуальном дереве + void itemMoveDown();//не работает, проверить поиск элементов в визуальном дереве + void itemDelete(); + void itemRename(); + void itemSave(); + void itemLoad(); +private slots: + void on_collapsed( Q3ListViewItem *item ); +private: + Q3IntDict editors; +}; + +#endif diff --git a/src/designer/pixmappreview.h b/src/designer/pixmappreview.h new file mode 100644 index 0000000..2dd995b --- /dev/null +++ b/src/designer/pixmappreview.h @@ -0,0 +1,51 @@ +/**************************************************************************** +** $Id: pixmappreview.h,v 1.1 2008/11/05 21:16:27 leader Exp $ +** +** Ffile of the Pixmap preview of Ananas Designer applications +** +** Created : 20031201 +** +** Copyright (C) 2003-2004 Leader InfoTech. All rights reserved. +** +** This file is part of the Designer application of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.leaderit.ru/page=ananas or email sales@leaderit.ru +** See http://www.leaderit.ru/gpl/ for GPL licensing information. +** +** Contact org@leaderit.ru if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#ifndef PIXMAPPREVIEW_H +#define PIXMAPPREVIEW_H + +#include +#include +#include +#include + +class PixmapPreview : public QLabel, public Q3FilePreview +{ + Q_OBJECT +public: + PixmapPreview( QWidget *parent=0 ) : QLabel( parent ) {} + void previewUrl( const Q3Url &u ) + { + QString path = u.path(); + QPixmap pix( path ); + if ( pix.isNull() ) setText( tr("This is not a pixmap") ); + else setPixmap( pix ); + } +}; + +#endif diff --git a/src/designer/roleeditor.cpp b/src/designer/roleeditor.cpp new file mode 100644 index 0000000..4eeb035 --- /dev/null +++ b/src/designer/roleeditor.cpp @@ -0,0 +1,135 @@ +/**************************************************************************** +** $Id: roleeditor.cpp,v 1.1 2008/11/05 21:16:27 leader Exp $ +** +** Code file of the Alias editor of Ananas +** Designer applications +** +** Created : 20031201 +** +** Copyright (C) 2003-2004 Leader InfoTech. All rights reserved. +** +** This file is part of the Designer application of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.leaderit.ru/page=ananas or email sales@leaderit.ru +** See http://www.leaderit.ru/gpl/ for GPL licensing information. +** +** Contact org@leaderit.ru if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#include +#include "roleeditor.h" +#include "acfg.h" + + +aRoleEditor::aRoleEditor( aCfg *c, aCfgItem o, Q3Table *t, const char *p ) +{ + ac = c; + obj = o; + tRoles = t; + tRoles->setNumRows( 0 ); + tRoles->setNumCols( 1 ); + tRoles->horizontalHeader()->setLabel( 0, tr("Read") ); + parent = p; + if ( !strcmp( parent, md_document ) ) { + tRoles->setNumCols( 5 ); + tRoles->horizontalHeader()->setLabel( 1, tr("Write") ); + tRoles->horizontalHeader()->setLabel( 2, tr("Delete") ); + tRoles->horizontalHeader()->setLabel( 3, tr("Turn On") ); + tRoles->horizontalHeader()->setLabel( 4, tr("Turn Off") ); + } + if ( !strcmp( parent, md_catalogue ) ) { + tRoles->setNumCols( 3 ); + tRoles->horizontalHeader()->setLabel( 1, tr("Write") ); + tRoles->horizontalHeader()->setLabel( 2, tr("Delete") ); + } + +} + +aRoleEditor::~aRoleEditor() +{ +} + +void +aRoleEditor::setData() +{ + int i, j, n; + aCfgItem orole, roles, role; + QString rolename, right; + + roles = ac->find( ac->find( mdc_root ), md_roles, 0 ); + roleCount = ac->count( roles, md_role ); + n = ac->countChild( obj, md_role ); + tRoles->setNumRows( roleCount ); + for ( i = 0; i < roleCount; i++ ) { + role = ac->findChild( roles, md_role, i ); + rolename = ac->attr( role, mda_name ); + tRoles->verticalHeader()->setLabel( i, rolename ); + Q3CheckTableItem *r = new Q3CheckTableItem( tRoles, QString::null ); + tRoles->setItem( i, 0, r ); + Q3CheckTableItem *w = new Q3CheckTableItem( tRoles, QString::null ); + Q3CheckTableItem *d = new Q3CheckTableItem( tRoles, QString::null ); + Q3CheckTableItem *on = new Q3CheckTableItem( tRoles, QString::null ); + Q3CheckTableItem *off = new Q3CheckTableItem( tRoles, QString::null ); + if ( !strcmp( parent, md_catalogue ) ) { + tRoles->setItem( i, 1, w ); + tRoles->setItem( i, 2, d ); + } + if ( !strcmp( parent, md_document ) ) { + tRoles->setItem( i, 1, w ); + tRoles->setItem( i, 2, d ); + tRoles->setItem( i, 3, on ); + tRoles->setItem( i, 4, off ); + } + for ( j = 0; j < n; j++) { + orole = ac->findChild( obj, md_role, j ); + if ( rolename == ac->attr( orole, mda_name ) ) { + right = ac->attr( orole, mda_rights ); + if ( right.find( "-r" ) > -1 ) r->setChecked( TRUE ); + if ( right.find( "-w" ) > -1 ) w->setChecked( TRUE ); + if ( right.find( "-d" ) > -1 ) d->setChecked( TRUE ); + if ( right.find( "-on" ) > -1 ) on->setChecked( TRUE ); + if ( right.find( "-off" ) > -1 ) off->setChecked( TRUE ); + } + } + } +} + +void aRoleEditor::updateMD() +{ + int i; + aCfgItem role; + + do { + role = ac->findChild( obj, md_role, 0 ) ; + if ( !role.isNull() ) ac->remove( role ); + } while ( !role.isNull() ); + for ( i = 0; i < tRoles->numRows(); i++ ) { + QString right; + Q3CheckTableItem *q; + role = ac->insert( obj, md_role, tRoles->text( i, 0 ), -1 ); + ac->setAttr( role, mda_name, tRoles->verticalHeader()->label( i )); + q = (Q3CheckTableItem *)tRoles->item( i, 4 ); + if ( q ) if ( q->isChecked() ) right.insert( 0, "-off" ); + q = (Q3CheckTableItem *)tRoles->item( i, 3 ); + if ( q ) if ( q->isChecked() ) right.insert( 0, "-on" ); + q = (Q3CheckTableItem *)tRoles->item( i, 2 ); + if ( q ) if ( q->isChecked() ) right.insert( 0, "-d" ); + q = (Q3CheckTableItem *)tRoles->item( i, 1 ); + if ( q ) if ( q->isChecked() ) right.insert( 0, "-w" ); + q = (Q3CheckTableItem *)tRoles->item( i, 0 ); + if ( q ) if ( q->isChecked() ) right.insert( 0, "-r" ); + ac->setAttr( role, mda_rights, right ); + } +} + diff --git a/src/designer/roleeditor.h b/src/designer/roleeditor.h new file mode 100644 index 0000000..9a65241 --- /dev/null +++ b/src/designer/roleeditor.h @@ -0,0 +1,55 @@ +/**************************************************************************** +** $Id: roleeditor.h,v 1.1 2008/11/05 21:16:27 leader Exp $ +** +** Header file of the Alias editor of Ananas +** Designer applications +** +** Created : 20031201 +** +** Copyright (C) 2003-2004 Leader InfoTech. All rights reserved. +** +** This file is part of the Designer application of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.leaderit.ru/page=ananas or email sales@leaderit.ru +** See http://www.leaderit.ru/gpl/ for GPL licensing information. +** +** Contact org@leaderit.ru if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#ifndef ROLEDITOR_H +#define ROLEDITOR_H + +#include +#include +#include "acfg.h" + +class aRoleEditor : public QObject +{ + Q_OBJECT +public: + aCfg *ac; + aCfgItem obj; + Q3Table *tRoles; + int roleCount; + + aRoleEditor( aCfg *c, aCfgItem o, Q3Table *tRoles, const char *p ); + ~aRoleEditor(); + + void setData(); + void updateMD( );//aCfgItem o ); +private: + const char *parent; +}; + +#endif diff --git a/src/designer/templates/inputform.tpl b/src/designer/templates/inputform.tpl new file mode 100644 index 0000000..df62376 --- /dev/null +++ b/src/designer/templates/inputform.tpl @@ -0,0 +1,22 @@ + + + + + AForm + + + + 0 + 0 + 500 + 381 + + + + New form + + + + + qPixmapFromMimeSource + diff --git a/src/designer/templates/inputform.ui.tpl b/src/designer/templates/inputform.ui.tpl new file mode 100644 index 0000000..1587630 --- /dev/null +++ b/src/designer/templates/inputform.ui.tpl @@ -0,0 +1,22 @@ + +AForm + + + AForm + + + + 0 + 0 + 500 + 381 + + + + New form + + + + + + diff --git a/src/designer/templates/inputformcat.tpl b/src/designer/templates/inputformcat.tpl new file mode 100644 index 0000000..be95ae7 --- /dev/null +++ b/src/designer/templates/inputformcat.tpl @@ -0,0 +1,30 @@ + + + + + Catalogue + + + 0 + + + $$$name$$$ + + + + 0 + 0 + 500 + 381 + + + + $$$caption$$$ + + + + qPixmapFromMimeSource + + wcatalogue.h + + diff --git a/src/designer/templates/inputformcat.ui.tpl b/src/designer/templates/inputformcat.ui.tpl new file mode 100644 index 0000000..7257f82 --- /dev/null +++ b/src/designer/templates/inputformcat.ui.tpl @@ -0,0 +1,31 @@ + +Catalogue + + + Catalogue + + + $$$id$$$ + + + $$$name$$$ + + + + 0 + 0 + 500 + 381 + + + + $$$caption$$$ + + + + + + + wcatalogue.h + + diff --git a/src/designer/templates/inputformdoc.tpl b/src/designer/templates/inputformdoc.tpl new file mode 100644 index 0000000..e7f19c5 --- /dev/null +++ b/src/designer/templates/inputformdoc.tpl @@ -0,0 +1,30 @@ + + + + + Document + + + 0 + + + $$$name$$$ + + + + 0 + 0 + 500 + 378 + + + + $$$caption$$$ + + + + qPixmapFromMimeSource + + wdocument.h + + diff --git a/src/designer/templates/inputformdoc.ui.tpl b/src/designer/templates/inputformdoc.ui.tpl new file mode 100644 index 0000000..ebd70ba --- /dev/null +++ b/src/designer/templates/inputformdoc.ui.tpl @@ -0,0 +1,31 @@ + +Document + + + Document + + + $$$id$$$ + + + $$$name$$$ + + + + 0 + 0 + 500 + 378 + + + + $$$caption$$$ + + + + + + + wdocument.h + + diff --git a/src/designer/templates/inputformjourn.tpl b/src/designer/templates/inputformjourn.tpl new file mode 100644 index 0000000..b0e32e4 --- /dev/null +++ b/src/designer/templates/inputformjourn.tpl @@ -0,0 +1,30 @@ + + + + + Journal + + + 0 + + + $$$name$$$ + + + + 0 + 0 + 500 + 378 + + + + $$$caption$$$ + + + + qPixmapFromMimeSource + + wjournal.h + + diff --git a/src/designer/templates/inputformjourn.ui.tpl b/src/designer/templates/inputformjourn.ui.tpl new file mode 100644 index 0000000..a7ea9a3 --- /dev/null +++ b/src/designer/templates/inputformjourn.ui.tpl @@ -0,0 +1,31 @@ + +Journal + + + Journal + + + $$$id$$$ + + + $$$name$$$ + + + + 0 + 0 + 500 + 378 + + + + $$$caption$$$ + + + + + + + wjournal.h + + diff --git a/src/designer/templates/inputformrep.tpl b/src/designer/templates/inputformrep.tpl new file mode 100644 index 0000000..8007c73 --- /dev/null +++ b/src/designer/templates/inputformrep.tpl @@ -0,0 +1,30 @@ + + + + + Report + + + 0 + + + $$$name$$$ + + + + 0 + 0 + 500 + 378 + + + + $$$caption$$$ + + + + qPixmapFromMimeSource + + wreport.h + + diff --git a/src/designer/templates/inputformrep.ui.tpl b/src/designer/templates/inputformrep.ui.tpl new file mode 100644 index 0000000..a1358b9 --- /dev/null +++ b/src/designer/templates/inputformrep.ui.tpl @@ -0,0 +1,31 @@ + +Report + + + Report + + + $$$id$$$ + + + $$$name$$$ + + + + 0 + 0 + 500 + 378 + + + + $$$caption$$$ + + + + + + + wreport.h + + diff --git a/src/extensions/README b/src/extensions/README new file mode 100644 index 0000000..34a7165 --- /dev/null +++ b/src/extensions/README @@ -0,0 +1,44 @@ +ANANAS EXTENSIONS SYSTEM +author: Valery Grazdankin, Leader InfoTech + +Ananas engine finding extentions +in 'extensions' directory +below application path directory (by default). +For Linux will be moving to /usr/share/ananas/extensions + +SHORT WAY FOR CREATE EXTENSION: + +1. Define object with AExtension parent +2. In constructor of the object call AExtension constructor + with Extension name string parameter. For example: + + AExtensionMy::AExtensionMy() : AExtension("MyExtension") + { + ... + } + This name will be used in Ananas script for 'new' + operator without parameters, for example: + + Ext = new MyExtension(); + +3. Define public slots: + it will be functions, callable from Ananas script. +4. Define Q_PROPERTY ( see demo ) + it will be object variables +5. + At end of extension implementation (*.cpp) file define and export + AnanasExtensionPlugin object for the extension, using template: + + #include + typedef AExtensionPlugin plugin_object_name; + A_EXPORT_PLUGIN( plugin_object_name ) + + For example: + + #include + typedef AExtensionPlugin AExtensionMyPlugin; + A_EXPORT_PLUGIN( AExtensionMyPlugin ) + +6. Compile plugin +7. Move it to Ananas extensions directory. +8. USE IT AND ENJOY diff --git a/src/extensions/example/aextexample.cpp b/src/extensions/example/aextexample.cpp new file mode 100644 index 0000000..cd50b73 --- /dev/null +++ b/src/extensions/example/aextexample.cpp @@ -0,0 +1,62 @@ +/**************************************************************************** +** $Id: aextexample.cpp,v 1.1 2008/11/05 21:16:27 leader Exp $ +** +** Extension object implementation file of +** Ananas application library +** +** Created : 20031201 +** +** Copyright (C) 2003-2006 Leader InfoTech. All rights reserved. +** Copyright (C) 2003-2006 Valery Grazdankin, Orenburg. +** Copyright (C) 2003-2005 Grigory Panov, Yoshkar-Ola. +** +** This file is part of the Designer application of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.leaderit.ru/page=ananas or email sales@leaderit.ru +** See http://www.leaderit.ru/gpl/ for GPL licensing information. +** +** Contact org@leaderit.ru if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#include "aextexample.h" +#include "acfg.h" + +AExtExample::AExtExample() + : AExtension("AExtExample") +{ + startTimer( 5000 ); +} + + + +AExtExample::~AExtExample() +{ +} + +void +AExtExample::PrintMessage( const QString &msg ) +{ + setLastMessage( msg ); + cfg_message(0, "AExtTest MSG:%s\n", (const char *) msg); +} + +void +AExtExample::timerEvent( QTimerEvent * ) +{ + emit event("10"); +} + +#include +typedef AExtensionPlugin AExtExamplePlugin; +A_EXPORT_PLUGIN( AExtExamplePlugin ) diff --git a/src/extensions/example/aextexample.h b/src/extensions/example/aextexample.h new file mode 100644 index 0000000..752e295 --- /dev/null +++ b/src/extensions/example/aextexample.h @@ -0,0 +1,64 @@ +/**************************************************************************** +** $Id: aextexample.h,v 1.1 2008/11/05 21:16:27 leader Exp $ +** +** Extension object header file of +** Ananas application library +** +** Created : 20031201 +** +** Copyright (C) 2003-2004 Leader InfoTech. All rights reserved. +** Copyright (C) 2003-2005 Grigory Panov, Yoshkar-Ola. +** +** This file is part of the Designer application of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.leaderit.ru/page=ananas or email sales@leaderit.ru +** See http://www.leaderit.ru/gpl/ for GPL licensing information. +** +** Contact org@leaderit.ru if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#ifndef AEXTEXAMPLE_H +#define AEXTEXAMPLE_H + +#include "aextension.h" + +/** + * \en + * Class for work with extensions + * \_en + * \ru + * \_ru + */ +class ANANAS_EXPORT AExtExample : public AExtension +{ + Q_OBJECT + Q_PROPERTY( QString lastMessage READ getLastMessage WRITE setLastMessage ) + +public: + + AExtExample(); + ~AExtExample(); +public: + QString getLastMessage() const { return vMessage;}; + void setLastMessage( const QString &v ){ vMessage = v;}; + +public slots: + void PrintMessage( const QString &msg ); +protected: + void timerEvent( QTimerEvent * ); +private: + QString vMessage; +}; + +#endif //AEXTEXAMPLE_H diff --git a/src/extensions/example/example.pro b/src/extensions/example/example.pro new file mode 100644 index 0000000..adfeb02 --- /dev/null +++ b/src/extensions/example/example.pro @@ -0,0 +1,17 @@ +include(../../lib/lib.pri) +TARGET = aextexample +SOURCES += aextexample.cpp +HEADERS += aextexample.h +include ( ../../ananas.pri ) +shared { +win32:DEFINES+= ANANAS_DLL +} else { +win32:DEFINES += ANANAS_NO_DLL +} +TEMPLATE =lib +LIBS += -L../../../lib -lananas4 +CONFIG += plugin +INCLUDEPATH += ../../lib +LANGUAGE = C++ +DESTDIR = .. +#win32:DLLDESTDIR = .. diff --git a/src/extensions/extensions.pro b/src/extensions/extensions.pro new file mode 100644 index 0000000..bf22596 --- /dev/null +++ b/src/extensions/extensions.pro @@ -0,0 +1,6 @@ +TEMPLATE = subdirs +SUBDIRS = example +SUBDIRS += text +SUBDIRS += xml +SUBDIRS += meta +#unix:SUBDIRS += te diff --git a/src/extensions/meta/aext_meta.cpp b/src/extensions/meta/aext_meta.cpp new file mode 100644 index 0000000..625a9be --- /dev/null +++ b/src/extensions/meta/aext_meta.cpp @@ -0,0 +1,217 @@ +/**************************************************************************** +** $Id: aext_meta.cpp,v 1.1 2008/11/05 21:16:27 leader Exp $ +** +** Extension object implementation file of +** Ananas application library +** +** Created : 20031201 +** +** Copyright (C) 2006 Andrey Paskal +** +** This file is part of the Designer application of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.leaderit.ru/page=ananas or email sales@leaderit.ru +** See http://www.leaderit.ru/gpl/ for GPL licensing information. +** +** Contact org@leaderit.ru if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +//#include +#include +#include + +#include "aext_meta.h" +#include "adatabase.h" +#include + +/** + *\en + * Create object. + *\_en \ru + * Создает объект. + *\_ru + */ +AExtMeta::AExtMeta() + : AExtension("Meta") +{ +} + + +/** + *\en + * Destroy object. + *\_en \ru + * Уничтожает объект. + *\_ru + */ +AExtMeta::~AExtMeta() +{ +} + +/** + * \en + * \_en + * \ru + * \brief Возвращает имя класса бизнес объекта по идентификатору класса, присвоенному классу в метаданных. + * + * Имя класса может быть например "Справочник товаров", "Справочник счетов". + * \param id - идентификатор класса в метаданных + * \return имя класса в бизнес схеме + * + * Пример использования + * \code + * meta = new Meta(); + * sys.Message(0,"id=129, Class name = "+meta.GetClassName(129)); + * \endcode + * + * \see GetBaseClassName(...) + * \_ru + */ +QString +AExtMeta::GetClassName(const long &id) +{ + return db->cfg.attr(db->cfg.find(id),"name"); +} + + +/** + * \en + * \_en + * \ru + * \brief Возвращает имя базового класса бизнес объекта по идентификатору класса, присвоенному классу в метаданных. + * + * Имя базового класса может быть, например "catalogue", "document", "aregister", "iregister","journal", "report". + * \param id - идентификатор класса в метаданных + * \return имя базового класса в бизнес схеме + * + * Пример использования + * \code + * meta = new Meta(); + * sys.Message(0,"id=129, Base class name = "+meta.GetBaseClassName(129)); + * \endcode + * + * \see GetClassName(...) + * \_ru + */ +QString +AExtMeta::GetBaseClassName(const long &id) +{ + return db->cfg.objClass(id); +} + +/** + * \en + * \_en + * \ru + * \brief Возвращает имя базового класса бизнес объекта по уникальному идентификатору + * бизнес объекта в базе данных. + * + * Имя базового класса может быть, например "catalogue", "document", "aregister", "iregister","journal", "report". + * \param id - уникальный идентификатор бизнес обхъекта в базе данных + * \return имя базового класса в бизнес схеме + * + * Пример использования + * \code + * meta = new Meta(); + * sys.Message(0,"uid=6, base class name ="+meta.GetBaseClassNameByObjectUid(6)); + * \endcode + * \see GetClassNameByObjectUid(...) + * \_ru + */ +QString +AExtMeta::GetBaseClassNameByObjectUid(const long &id) +{ + return db->cfg.objClass(db->uidType(id)); +} + +/** + * \en + * \_en + * \ru + * \brief Возвращает имя класса бизнес объекта по уникальному идентификатору бизнес объекта в базе данных + * + * Имя класса может быть например "Справочник товаров", "Справочник счетов". + * \param id - уникальный идентификатор бизнес объекта в базе данных + * \return имя класса в бизнес схеме + * + * Пример использования + * \code + * meta = new Meta(); + * sys.Message(0,"uid=6, class name ="+meta.GetClassNameByObjectUid(6)); + * \endcode + * \see GetBaseClassNameByObjectUid(...) + * \_ru + */ +QString +AExtMeta::GetClassNameByObjectUid(const long &id) +{ + return db->cfg.attr(db->cfg.find(db->uidType(id)),"name"); +} + +/** + * \en + * \_en + * \ru + * \brief Возвращает количество бизнес объектов указанного класса в бизнес схеме. + * + * Имя класса может быть, например, "catalogue", "document". + * \param className - Имя класса + * \return количество бизнес объектов + * + * Пример использования + * \code + * meta = new Meta(); + * \endcode + * \_ru + */ +int +AExtMeta::CountByClassName(const QString &className) { + return db->cfg.count(db->cfg.find(mdc_root),className); +} + +/** + * \en + * \_en + * \ru + * \brief Возвращает список имен бизнес объектов указанного класса в бизнес схеме. + * + * Имя класса может быть, например, "catalogue", "document". + * TODO: Требуется проверить возможность передачи возвращаемого значения в Скрипт. Возможно списки и не поддерживаются. + * \param className - Имя класса + * \return Список названий + * + * Пример использования + * \code + * meta = new Meta(); + * \endcode + * \_ru + */ +QStringList +AExtMeta::ListByClassName(const QString &className) { + QStringList sList; + QDomNodeList nodeList=db->cfg.find(mdc_root).elementsByTagName(className); + int i,cnt = nodeList.count(); + for (i=0; i AExtMetaPlugin; +A_EXPORT_PLUGIN( AExtMetaPlugin ) diff --git a/src/extensions/meta/aext_meta.h b/src/extensions/meta/aext_meta.h new file mode 100644 index 0000000..187438c --- /dev/null +++ b/src/extensions/meta/aext_meta.h @@ -0,0 +1,77 @@ +/**************************************************************************** +** $Id: aext_meta.h,v 1.1 2008/11/05 21:16:27 leader Exp $ +** +** Extension object header file of +** Ananas application library +** +** Created : 20031201 +** +** Copyright (C) 2006 Andrey Paskal +** +** This file is part of the Designer application of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.leaderit.ru/page=ananas or email sales@leaderit.ru +** See http://www.leaderit.ru/gpl/ for GPL licensing information. +** +** Contact org@leaderit.ru if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#ifndef AEXT_META_H +#define AEXT_META_H + + + +#include "aextension.h" +#include "acfg.h" + +/** + * \en + * Class for work with meta data API from Ananas Script. + * \_en + * \ru + * \brief Предоставляет доступ к интервейсу метаданных из Ананас скрипта. + * + * Пример использования функций GetBaseClassName, GetClassName, GetBaseClassNameByObjectUid, + * GetClassNameByObjectUid + * \code + * meta = new Meta(); + * sys.Message(0,"class id = 129, base class name ="+meta.GetBaseClassName(129)); + * sys.Message(0,"class id =129, class name ="+meta.GetClassName(129)); + * sys.Message(0,"uid=6, base class name ="+meta.GetBaseClassNameByObjectUid(6)); + * sys.Message(0,"uid=6, class name ="+meta.GetClassNameByObjectUid(6)); + * \endcode + * + * \_ru + */ +class ANANAS_EXPORT AExtMeta : public AExtension +{ + Q_OBJECT + +public: + + AExtMeta(); + ~AExtMeta(); +public: + +public slots: + QString GetBaseClassName(const long &ClassId); + QString GetClassName(const long &ClassId); + QString GetBaseClassNameByObjectUid(const long &ObjectUid); + QString GetClassNameByObjectUid(const long &ObjectUid); + int CountByClassName(const QString &className); + QStringList ListByClassName(const QString &className); +}; + + +#endif //AEXT_META_H diff --git a/src/extensions/meta/meta.pro b/src/extensions/meta/meta.pro new file mode 100644 index 0000000..6a84db6 --- /dev/null +++ b/src/extensions/meta/meta.pro @@ -0,0 +1,16 @@ +include(../../lib/lib.pri) +TARGET = aext_meta +SOURCES += aext_meta.cpp +HEADERS += aext_meta.h +include ( ../../ananas.pri ) +shared { +win32:DEFINES+= ANANAS_DLL +} else { +win32:DEFINES += ANANAS_NO_DLL +} +TEMPLATE =lib +LIBS += -L../../../lib -lananas4 +CONFIG += plugin +INCLUDEPATH += ../../lib +LANGUAGE = C++ +DESTDIR = .. diff --git a/src/extensions/te/README b/src/extensions/te/README new file mode 100644 index 0000000..dfc6489 --- /dev/null +++ b/src/extensions/te/README @@ -0,0 +1,55 @@ +Ananas script examples for trade equipment drivers: +TEDisplayVF2029, TEReaderBarcode + +1.global module: + +var TradeEq = 0; // global trade equipment manager +var TEDisplay = 0; // Display object +var TEReader = 0; // Reader object + +// EVENTS GLOBAL HANDLER +function on_event( src, data ) +{ + sys.Message(1,"Global module: on_event from "+src+" data="+data); +} + +function on_systemstart() +{ + TradeEq = new TradeEquipment(); + TEDisplay = TradeEq.newDriver("TEDisplayVF2029"); + if (TEDisplay) { + TEDisplay.setPortBaudRate(12); //9600 + TEDisplay.setPortNumberAndInit(2); // COM2 + } + TEReader = TradeEq.newDriver("TEReaderBarcode"); + if (TEReader) { + TEReader.PortNumber = 1; + TEReader.PortBaudRate = 9600; + TEReader.startDriver(); + } +} + +2.Document module + +// +function on_formstart(){ + TEReader.clearBuffer(); // clear unprocessed barcodescodes +} + +// DISPLAY TEXT ON ROW CHANGED. +function on_tablerow( name ){ + print("Table "+name+" row changed"); + TEDisplay.showText("ROW CHANGED","line1","scroll/left"); +} + +// EVENTS DOCUMENT HANDLER +function on_event( src, data ) +{ + sys.Message(1,"Document module: on_event from "+src+" data="+data); + if (src=="TradeEquipment") { + // NEED CHECK 'data' VALUE FOR READER EVENT FILTERS + bc = TEReader.text(); + SetValue("Barcode", bc); // SET FIELD VALUE TO BARCODE READED + TEReader.next(); + } +} diff --git a/src/extensions/te/aextte.cpp b/src/extensions/te/aextte.cpp new file mode 100644 index 0000000..fc128a6 --- /dev/null +++ b/src/extensions/te/aextte.cpp @@ -0,0 +1,99 @@ +/**************************************************************************** +** $Id: aextte.cpp,v 1.1 2008/11/05 21:16:28 leader Exp $ +** +** Extension object implementation file of +** Ananas application library +** +** Created : 20031201 +** +** Copyright (C) 2003-2006 Leader InfoTech. All rights reserved. +** Copyright (C) 2003-2006 Valery Grazdankin, Orenburg. +** Copyright (C) 2003-2005 Grigory Panov, Yoshkar-Ola. +** +** This file is part of the Designer application of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.leaderit.ru/page=ananas or email sales@leaderit.ru +** See http://www.leaderit.ru/gpl/ for GPL licensing information. +** +** Contact org@leaderit.ru if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ +#include + +#include "aextte.h" +#include "acfg.h" +#include "teglobal.h" +#include "tebase.h" + +AExtTE::AExtTE() + : AExtension("TradeEquipment") +{ + telib = 0; + te_drivers = 0; + te_driverExists = 0; + te_createDriverObject = 0; + telib = new QLibrary("tradeequip"); + if (telib) { + telib->load(); + te_drivers = (p_te_drivers) telib->resolve( "te_drivers" ); + te_driverExists = (p_te_driverExists) telib->resolve( "te_driverExists" ); + te_createDriverObject = (p_te_createDriverObject) telib->resolve( "te_createDriverObject" ); + } +} + + + +AExtTE::~AExtTE() +{ + if (telib) delete telib; +} + + +QStringList +AExtTE::drivers( const QString &baseclass ) +{ + QStringList l; + if (te_drivers) l = te_drivers( baseclass ); + return l; +} + +bool +AExtTE::driverExists( const QString &name ) +{ + if (te_driverExists) return te_driverExists( name, QString::null ); + return false; +} + + +QObject * +AExtTE::newDriver( const QString &name ) +{ + TEBase *te = 0; + if (te_createDriverObject) { + te = te_createDriverObject( name ); + connect( te, SIGNAL( deviceEvent(int) ), this, SLOT( deviceEvent(int))); + } + return ( QObject *) te; + +} + +void +AExtTE::deviceEvent( int eventCode ) +{ + const QObject *obj = sender(); + emit event(QString(obj->name())+"::"); +} + +#include +typedef AExtensionPlugin ATEPlugin; +A_EXPORT_PLUGIN( ATEPlugin ) diff --git a/src/extensions/te/aextte.h b/src/extensions/te/aextte.h new file mode 100644 index 0000000..bd9d82c --- /dev/null +++ b/src/extensions/te/aextte.h @@ -0,0 +1,71 @@ +/**************************************************************************** +** $Id: aextte.h,v 1.1 2008/11/05 21:16:28 leader Exp $ +** +** Extension object header file of +** Ananas application library +** +** Created : 20031201 +** +** Copyright (C) 2003-2004 Leader InfoTech. All rights reserved. +** Copyright (C) 2003-2005 Grigory Panov, Yoshkar-Ola. +** +** This file is part of the Designer application of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.leaderit.ru/page=ananas or email sales@leaderit.ru +** See http://www.leaderit.ru/gpl/ for GPL licensing information. +** +** Contact org@leaderit.ru if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#ifndef AEXTTE_H +#define AEXTTE_H + +#include "aextension.h" +class TEBase; +class QLibrary; + +typedef QStringList (*p_te_drivers)( const QString & ); +typedef bool (*p_te_driverExists)( const QString &, const QString & ); +typedef TEBase *(*p_te_createDriverObject)( const QString &className ); + +/** + * \en + * Class for work with Trade Equipment drivers + * \_en + * \ru + * \_ru + */ +class ANANAS_EXPORT AExtTE : public AExtension +{ + Q_OBJECT + +public: + + AExtTE(); + ~AExtTE(); + +public slots: + QStringList drivers( const QString &baseclass ); + bool driverExists( const QString &name ); + QObject *newDriver( const QString &name ); +protected slots: + void deviceEvent( int eventCode ); +private: + QLibrary *telib; + p_te_drivers te_drivers; + p_te_driverExists te_driverExists; + p_te_createDriverObject te_createDriverObject; +}; + +#endif //AEXTTE_H diff --git a/src/extensions/te/te.pro b/src/extensions/te/te.pro new file mode 100644 index 0000000..ffca994 --- /dev/null +++ b/src/extensions/te/te.pro @@ -0,0 +1,27 @@ +TARGET = aextte +SOURCES += aextte.cpp +HEADERS += aextte.h +include ( ../../ananas.pri ) +shared { + win32:DEFINES+= ANANAS_DLL +} else { + win32:DEFINES += ANANAS_NO_DLL +} +TEMPLATE =lib +CONFIG += plugin +INCLUDEPATH += ../../lib +LIBS += -L../../lib -lananas +LANGUAGE = C++ + +unix { + INCLUDEPATH += /usr/include/tradeequip +# LIBS += -L/usr/lib -ltradeequip +} + +win32 { + INCLUDEPATH += d:\src\tradeequip\src\lib +# LIBS += -L/src/tradeequip/lib -ltradeequip +} + +DESTDIR = .. +#win32:DLLDESTDIR = .. diff --git a/src/extensions/text/aexttext.cpp b/src/extensions/text/aexttext.cpp new file mode 100644 index 0000000..95f3cf6 --- /dev/null +++ b/src/extensions/text/aexttext.cpp @@ -0,0 +1,203 @@ +/**************************************************************************** +** $Id: aexttext.cpp,v 1.1 2008/11/05 21:16:28 leader Exp $ +** +** Extension object implementation file of +** Ananas application library +** +** Created : 20031201 +** +** Copyright (C) 2003-2006 Leader InfoTech. All rights reserved. +** Copyright (C) 2003-2006 Valery Grazdankin, Orenburg. +** Copyright (C) 2003-2005 Grigory Panov, Yoshkar-Ola. +** +** This file is part of the Designer application of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.leaderit.ru/page=ananas or email sales@leaderit.ru +** See http://www.leaderit.ru/gpl/ for GPL licensing information. +** +** Contact org@leaderit.ru if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#include +#include "aexttext.h" +#include "acfg.h" +#include +#include + +/*! +\en + \class AExtText aexttext.h + \brief The AExtText is Ananas extension class for work with text files. +\_en \ru + \class AExtText aexttext.h + \brief Класс расширения Ананас AExtText предназначен для работы с текстовыми файлами. + + Поддерживает работу с файлами в различных кодировках, + режимах: + RO - Только чтение + WO - Только запись + RW - чтение/запись + A - добавление к концу файла. +\_ru +*/ + + +// \param cmd (in) command text. +// \return - result. + + +/*! + *\en + * + *\_en \ru + * + *\_ru + */ +AExtText::AExtText() + : AExtension("Text") +{ + text = new QTextStream( &file ); + setCodec("UTF-8"); +} + + + +/*! + *\en + * + *\_en \ru + * + *\_ru + */ +AExtText::~AExtText() +{ + delete text; +} + + +/*! + *\en + * + *\_en \ru + * + *\_ru + */ +int +AExtText::open( const QString &filename, const QString &mode ) +{ + QIODevice::OpenMode m = QIODevice::ReadOnly; + file.close(); + file.setName( filename ); + if ( mode == "WO" ) m = QIODevice::WriteOnly; + if ( mode == "RW" ) m = QIODevice::ReadWrite; + if ( mode == "A" ) m = QIODevice::Append; + if ( file.open( m ) ) return 0; + return 1; +} + + +/*! + *\en + * + *\_en \ru + * + *\_ru + */ +void +AExtText::close() +{ + file.close(); +} + + +/*! + *\en + * + *\_en \ru + * + *\_ru + */ +QString +AExtText::readLine() +{ + return text->readLine(); +} + + + +/*! + *\en + * + *\_en \ru + * + *\_ru + */ +void +AExtText::writeLine( const QString &l ) +{ + *text << l << "\n"; +} + + + +/*! + *\en + * + *\_en \ru + * + *\_ru + */ +bool +AExtText::atEnd() +{ + return text->atEnd(); +} + + + +/*! + *\en + * + *\_en \ru + * + *\_ru + */ +QString +AExtText::getCodec() const +{ + QTextCodec *codec = text->codec(); + if ( codec ) return codec->name(); + return ""; +} + + + +/*! + *\en + * + *\_en \ru + * + *\_ru + */ +void +AExtText::setCodec( const QString &codecname ) +{ + QTextCodec *codec = QTextCodec::codecForName( ( const char *) codecname ); + if ( codec ) text->setCodec( codec ); +} + + +#include +typedef AExtensionPlugin AExtTextPlugin; +A_EXPORT_PLUGIN( AExtTextPlugin ) diff --git a/src/extensions/text/aexttext.h b/src/extensions/text/aexttext.h new file mode 100644 index 0000000..e4a31d4 --- /dev/null +++ b/src/extensions/text/aexttext.h @@ -0,0 +1,72 @@ +/**************************************************************************** +** $Id: aexttext.h,v 1.1 2008/11/05 21:16:28 leader Exp $ +** +** Extension object header file of +** Ananas application library +** +** Created : 20031201 +** +** Copyright (C) 2003-2004 Leader InfoTech. All rights reserved. +** Copyright (C) 2003-2005 Grigory Panov, Yoshkar-Ola. +** +** This file is part of the Designer application of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.leaderit.ru/page=ananas or email sales@leaderit.ru +** See http://www.leaderit.ru/gpl/ for GPL licensing information. +** +** Contact org@leaderit.ru if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#ifndef AEXTTEXT_H +#define AEXTTEXT_H + +#include "aextension.h" +#include + + +/** + * \en + * Class for work with extensions + * \_en + * \ru + * \_ru + */ +class ANANAS_EXPORT AExtText : public AExtension +{ + Q_OBJECT + Q_PROPERTY( QString codec READ getCodec WRITE setCodec ) + +public: + + AExtText(); + ~AExtText(); +public: + + QString getCodec() const ; + void setCodec( const QString &codecname ); + +public slots: + int open( const QString &filename, const QString &mode ); + void close(); + bool atEnd(); + + QString readLine(); + void writeLine( const QString &l ); + +private: + QFile file; + QTextStream *text; +}; + +#endif //AEXTTEXT_H diff --git a/src/extensions/text/text.pro b/src/extensions/text/text.pro new file mode 100644 index 0000000..6b017e3 --- /dev/null +++ b/src/extensions/text/text.pro @@ -0,0 +1,17 @@ +include(../../lib/lib.pri) +TARGET = aexttext +SOURCES += aexttext.cpp +HEADERS += aexttext.h +include ( ../../ananas.pri ) +shared { +win32:DEFINES+= ANANAS_DLL +} else { +win32:DEFINES += ANANAS_NO_DLL +} +TEMPLATE =lib +CONFIG += plugin +LIBS += -L../../../lib -lananas4 +INCLUDEPATH += ../../lib +LANGUAGE = C++ +DESTDIR = .. +#win32:DLLDESTDIR = .. diff --git a/src/extensions/xml/aextxml.cpp b/src/extensions/xml/aextxml.cpp new file mode 100644 index 0000000..24e785d --- /dev/null +++ b/src/extensions/xml/aextxml.cpp @@ -0,0 +1,425 @@ +/**************************************************************************** +** $Id: aextxml.cpp,v 1.1 2008/11/05 21:16:28 leader Exp $ +** +** Extension object implementation file of +** Ananas application library +** +** Created : 20031201 +** +** Copyright (C) 2003-2006 Leader InfoTech. All rights reserved. +** Copyright (C) 2003-2006 Valery Grazdankin, Orenburg. +** Copyright (C) 2003-2005 Grigory Panov, Yoshkar-Ola. +** +** This file is part of the Designer application of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.leaderit.ru/page=ananas or email sales@leaderit.ru +** See http://www.leaderit.ru/gpl/ for GPL licensing information. +** +** Contact org@leaderit.ru if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#include +#include + +#include "aextxml.h" +#include "acfg.h" +/*! +\en + \class AExtXML aextxml.h + \brief The AExtXML is Ananas extension class for work with XML files. +\_en \ru + \class AExtXML aextxml.h + \brief Класс расширения Ананас AExtXML предназначен для работы с XML файлами. +\_ru +*/ + + + +/*! + *\en + * Create object. + *\_en \ru + * Создает объект. + *\_ru + */ +AExtXML::AExtXML() + : AExtension("XML") +{ +} + + + +/*! + *\en + * Destroy object. + *\_en \ru + * Уничтожает объект. + *\_ru + */ +AExtXML::~AExtXML() +{ +} + + + +/*! + *\en + * Reads XML from file. + * \param fname (in) - name of XML file. + * \return true if OK. + *\_en \ru + * Читает файл XML. + * \param fname (in) - имя файла XML. + * \return true в случае успеха. + *\_ru + */ +bool +AExtXML::read(const QString &fname) +{ + QFile file( fname ); + QByteArray buf; + QString err; + int errLine = 0, errColumn = 0; + if ( !file.open( IO_ReadOnly ) ) return RC_ERROR; + buf = file.readAll(); + file.close(); + xml.setContent( QString("") ); + if ( !xml.setContent( buf, false, &err, &errLine, &errColumn ) ) { + cfg_message( 2, + ( const char *) QObject::tr( + "Error read XML line:%d col:%s %s"), + errLine, errColumn, ( const char *) err ); + return false; + } + rootnode = xml.documentElement(); + current = rootnode; + return true; +} + + + +/*! + *\en + * Writes XML file. + * \param fname (in) - name of XML file. + * \return error code. + *\_en \ru + * Записывает файл XML. + * \param fname (in) - имя файла XML. + * \return Код ошибки. + *\_ru + */ +bool +AExtXML::write(const QString &fname) +{ + QFile file( fname ); + QByteArray buf( xml.toString(4).utf8() ); + if ( file.open( IO_WriteOnly ) ) { + QTextStream ts( &file ); + ts.setEncoding(QTextStream::UnicodeUTF8); + xml.save(ts, 4); + file.close(); + return true; + } + return false; +} + + + +/*! + *\en + * Create new XML document. + * Old document content will be destroyed. + * \param rootnodename (in) - new XML docemrnt root node name. + * \return void. + *\_en \ru + * Создает новый XML документ. + * Старое содержимое документа уничтожается. + * \param rootnodename (in) - имя корневого узла документа XML. + * \return ничего. + *\_ru + */ +void +AExtXML::createNew( const QString &rootnodename ) +{ + xml.setContent(QString("\n")); + rootnode = xml.createElement( rootnodename ); + xml.appendChild( rootnode ); + current = rootnode; +} + + + +/*! + *\en + * Check current node is root node. + * \return true if current node is root. + *\_en \ru + * Проверяет, является ли текущий узел корневым. + * \return true - если текущий узел корневой. + *\_ru + */ +bool +AExtXML::isRoot() +{ + return current == rootnode; +} + + + +/*! + *\en + * + *\_en \ru + * + *\_ru + */ +bool +AExtXML::parent() +{ + QDomNode pn = current.parentNode(); + if ( pn.isNull() ) return false; + current = pn.toElement(); + return true; +} + + + +/*! + *\en + * + *\_en \ru + * + *\_ru + */ +bool +AExtXML::newChild( const QString &childname ) +{ + QDomElement ne = xml.createElement( childname ); + if ( ne.isNull() ) return false; + current.appendChild( ne ); + current = ne; + return true; +} + + + +/*! + *\en + * + *\_en \ru + * + *\_ru + */ +QString +AExtXML::nodeName() +{ + if (current.isNull()) return ""; + else return current.tagName(); +} + + + +/*! + *\en + * Sets text for current node. + * \param text (in) - new text value. + * \return void. + *\_en \ru + * Устанавливает текст текущего узла. + * \param text (in) - Значение нового текста. + * \return ничего. + *\_ru + */ +bool +AExtXML::setText( const QString &text ) +{ + QDomText t; + if (current.isNull()) return false; + while (!current.firstChild().isNull()) { + current.removeChild( current.firstChild() ); + } + t = xml.createTextNode( text ); + if ( t.isNull() ) return false; + current.appendChild( t ); + return true; +} + + + +/*! + *\en + * Returns text of current node. + * \return string. + *\_en \ru + * Возвращает текст текущего узла. + * \return Строка. + *\_ru + */ +QString +AExtXML::text() const +{ + if (current.isNull()) return ""; + return current.firstChild().nodeValue(); +} + + + +/*! + *\en + * Sets current node's attribute value. + * \param name (in) - attribute's name. + * \param value (in) - new value. + * \return void. + *\_en \ru + * Устанавливает значение атрибута текущего узла. + * \param name (in) - иям атрибута. + * \param value (in) - новое значение. + * \return ничего. + *\_ru + */ +bool +AExtXML::setAttr( const QString &name, const QString &value ) +{ + current.setAttribute( name, value ); + return true; +} + + + +/*! + *\en + * Returns current node's attribute value. + * \param name (in) - attribute name. + * \return attribute value. + *\_en \ru + * Возвращает значение атрибута текущего узла. + * \param name (in) - иям атрибута. + * \return значение атрибута. + *\_ru + */ +QString +AExtXML::attr( const QString &name ) const +{ + return current.attribute(name); +} + + + +/*! + *\en + * + *\_en \ru + * + *\_ru + */ +bool +AExtXML::removeAttr( const QString &name ) +{ + current.removeAttribute( name ); + return true; +} + + + +/*! + *\en + * + *\_en \ru + * + *\_ru + */ +bool +AExtXML::firstChild() +{ + QDomNode n = current.firstChild(); + if ( n.isNull() ) return false; + current = n.toElement(); + return true; +} + + + +/*! + *\en + * + *\_en \ru + * + *\_ru + */ +bool +AExtXML::lastChild() +{ + QDomNode n = current.lastChild(); + if ( n.isNull() ) return false; + current = n.toElement(); + return true; +} + + + +/*! + *\en + * + *\_en \ru + * + *\_ru + */ +bool +AExtXML::next() +{ + QDomNode n = current.nextSibling(); + if ( n.isNull() ) return false; + current = n.toElement(); + return true; +} + + + +/*! + *\en + * + *\_en \ru + * + *\_ru + */ +bool +AExtXML::prev() +{ + QDomNode n = current.previousSibling(); + if ( n.isNull() ) return false; + current = n.toElement(); + return true; +} + + + +/*! + *\en + * + *\_en \ru + * + *\_ru + */ +bool +AExtXML::childExists() +{ + QDomNode n = current.firstChild(); + if ( n.isNull() ) return false; + return true; +} + +#include +typedef AExtensionPlugin AExtXMLPlugin; +A_EXPORT_PLUGIN( AExtXMLPlugin ) diff --git a/src/extensions/xml/aextxml.h b/src/extensions/xml/aextxml.h new file mode 100644 index 0000000..715d33b --- /dev/null +++ b/src/extensions/xml/aextxml.h @@ -0,0 +1,83 @@ +/**************************************************************************** +** $Id: aextxml.h,v 1.1 2008/11/05 21:16:28 leader Exp $ +** +** Extension object header file of +** Ananas application library +** +** Created : 20031201 +** +** Copyright (C) 2003-2004 Leader InfoTech. All rights reserved. +** Copyright (C) 2003-2005 Grigory Panov, Yoshkar-Ola. +** +** This file is part of the Designer application of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.leaderit.ru/page=ananas or email sales@leaderit.ru +** See http://www.leaderit.ru/gpl/ for GPL licensing information. +** +** Contact org@leaderit.ru if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#ifndef AEXTXML_H +#define AEXTXML_H + +#include +#include "aextension.h" + +/** + * \en + * Class for work with extensions + * \_en + * \ru + * \_ru + */ +class ANANAS_EXPORT AExtXML : public AExtension +{ + Q_OBJECT + +public: + + AExtXML(); + ~AExtXML(); +public: + +public slots: + bool read(const QString &fname); + bool write(const QString &fname); + void createNew( const QString &rootnodename ); + + bool isRoot(); + bool parent(); + bool newChild( const QString &childname ); + QString nodeName(); + bool setText( const QString &text ); + QString text() const; + + bool setAttr( const QString &name, const QString &value ); + QString attr( const QString &name ) const; + bool removeAttr( const QString &name ); + + bool firstChild(); + bool lastChild(); + bool next(); + bool prev(); + bool childExists(); + +private: + QDomDocument xml; + QDomElement rootnode, current; + + +}; + +#endif //AEXTTEXT_H diff --git a/src/extensions/xml/xml.pro b/src/extensions/xml/xml.pro new file mode 100644 index 0000000..5048820 --- /dev/null +++ b/src/extensions/xml/xml.pro @@ -0,0 +1,23 @@ +include(../../lib/lib.pri) +TARGET = aextxml + +SOURCES += aextxml.cpp +HEADERS += aextxml.h + +include ( ../../ananas.pri ) + +shared { +win32:DEFINES+= ANANAS_DLL +} else { +win32:DEFINES += ANANAS_NO_DLL +} + +TEMPLATE =lib +CONFIG += plugin + +INCLUDEPATH += ../../lib +LIBS += -L../../../lib -lananas4 + +LANGUAGE = C++ +DESTDIR = .. +#win32:DLLDESTDIR = .. diff --git a/src/lib/acfg.cpp b/src/lib/acfg.cpp new file mode 100644 index 0000000..6346eeb --- /dev/null +++ b/src/lib/acfg.cpp @@ -0,0 +1,1818 @@ +/**************************************************************************** +** $Id: acfg.cpp,v 1.2 2008/11/08 20:16:35 leader Exp $ +** +** Code file of the Ananas configuration objects of Ananas +** Designer and Engine applications +** +** Created : 20031201 +** +** Copyright (C) 2003-2004 Leader InfoTech. All rights reserved. +** Copyright (C) Grigory Panov , Yoshkar-Ola. +** +** This file is part of the Library of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.leaderit.ru/page=ananas or email sales@leaderit.ru +** See http://www.leaderit.ru/gpl/ for GPL licensing information. +** +** Contact org@leaderit.ru if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +//--#include +#include + +#include "acfg.h" +#include "alog.h" + +#ifdef _MSC_VER +#define vsnprintf _vsnprintf +#endif + +#define context_startid 100 + +/*! + * Global configuration variable. + */ +//aCfg * ANANAS_EXPORT globalCfg = 0; + + +/* + */ +void (*cfg_messageproc)(int , const char *)=NULL; + +/*! + *\en + * Outputs error messages. + *\_en \ru + * Вывод сообщений об ошибках. + *\_ru + */ +void +cfg_message(int msgtype, const char *msgfmt,...){ + char msg[2048]; + char *ts=(char *)""; + va_list args; + + if (msgfmt) { + va_start(args, msgfmt); + vsnprintf(msg, sizeof(msg)-1, msgfmt, args); + va_end(args); + if (cfg_messageproc) cfg_messageproc(msgtype, msg); + else { + if (msgtype==1) ts=(char *)"- "; + if (msgtype==2) ts=(char *)"! "; + if (msgtype==2) ts=(char *)"!!! "; + printf("%s%s", ts, (const char *) QString::fromUtf8(msg).local8Bit()); + } + } +} + +/*! + *\en + *\_en \ru + * Выводит отладочные сообщения, если определен макрос ANANAS_DEBUG + *\_ru + */ +void +debug_message(const char *msgfmt,...){ +#ifdef ANANAS_DEBUG + char msg[2048]; + va_list args; + + if (msgfmt) { + va_start(args, msgfmt); + vsnprintf(msg, sizeof(msg)-1, msgfmt, args); + va_end(args); + printf("debug"); + printf("> %s", (const char *) QString::fromUtf8(msg).local8Bit()); + } +#endif +} + + +/*! + *\~english + * Ananas configuation object contaner constructor. + *\~russian + * Конструктор контейнера объекта конфигурации Ананас. + *\~ + * \param newid (in) - \~english container's ID.\~russian + * ID контейнера. \~ + * \param newitem (in) - \~english container's item.\~russian + * Элемент контейнера. \~ + */ +aCfgItemContaner::aCfgItemContaner(long newid, aCfgItem newitem) +{ + id = newid; + item = newitem; +} + + + +/*!\~english + * Ananas configuation object constructor. + *\~russian + * Конструктор объекта конфигурации АНАНАС. + *\~ + */ +aCfg::aCfg() : QObject(0, "Metadata"), xml( md_root ) +{ + setCompressed( false ); + setModified( false ); + idcache.setAutoDelete( TRUE ); + createNew(); +} + + + +/*!\en + * Ananas configuation object destructor. + *\_en \ru + * Деструктор объекта конфигурации АНАНАС. + *\_ru +*/ +aCfg::~aCfg() +{ + xml.setContent( QString("") ); +} + + + +/*! + * Reads configuration information (metadata) from file. + * \param fname (in) - name of configuration file. + * \return error code. + */ +int +aCfg::read(const QString &fname){ + QFile file( fname ); + QByteArray buf; + QString err; + int errLine = 0, errColumn = 0; + if ( !file.open( QIODevice::ReadOnly ) ) return RC_ERROR; + buf = file.readAll(); + file.close(); + xml.setContent( QString("") ); + if ( !xml.setContent( buf, false, &err, &errLine, &errColumn ) ) { + emit message( 2, QObject::tr( + "Error read configuration line:%1 col:%2 %3" + ).arg( errLine ).arg( errColumn ).arg( err )); +// cfg_message( 2, QObject::tr( +// ( const char *) QObject::tr( +// "Error read configuration line:%d col:%s %s"), +// errLine, errColumn, ( const char *) err ); + return RC_ERROR; + } + init(); +//CHECK_POINT + setModified( false ); +//CHECK_POINT + return RC_OK; +} + + + +/*!\~english + * helper method. Save current configuration. + *\~russian + * Вспомогательный метод. Сохраняет текущую конфирацию. + *\~ + */ +int +aCfg::write(const QString &fname) +{ + return write(xml, fname); +} + +/*!\~english + * Writes configuration information (metadata) to file. + *\~russian + * Записывает информацию о бизнес схеме ( метаданные ) в файл. + *\~ + * \param doc (in) - \~english xml document to save. \~russian xml для сохранения \~ + * \param fname (in) - \~english name of configuration file. \~russian имя файла для сохранения \~ + * \return \~english error code. \~russian код ошибки \~ + */ +int +aCfg::write(QDomDocument doc, const QString &fname) +{ + QFile file( fname ); + QByteArray buf( xml.toString(4).utf8() ); + if ( file.open( QIODevice::WriteOnly ) ) { + QTextStream ts( &file ); + //--ts.setEncoding(Q3TextStream::UnicodeUTF8); + doc.save(ts, 4); + //ts << toString(4); + file.close(); + return RC_OK; + } + return RC_ERROR; +} + +/*! + * Returns configuration file compression mode. + * \return boolean + */ +bool +aCfg::compressed() +{ + return fCompressed; +} + + +/*! + * Sets compression mode of configuration file. + * \param mode (in) - compression mode. + * \return void + */ +void +aCfg::setCompressed( bool mode ) +{ + fCompressed = mode; +} + + +/*! + * Returns modification status. + * \return boolean + */ +bool +aCfg::modified() +{ + return fModified; +} + + +/*! + * Set modification status. + * \param mode (in) - new value of modification status + * \return void + */ +void +aCfg::setModified( bool mode ) +{ + fModified = mode; +} + + +/*! + * Data structures initialization. Should be run after load metadata from configuration file. + * \return void + */ +void +aCfg::init(){ + QDomNode cur, sub; + long id; + +// QString s = xml.toString(4).local8Bit(); // fake call for trap troble + if ( !xml.isDocument() ) { + aLog::print(aLog::Error, tr("Bad configuration")); + return; + } +//CHECK_POINT + QDomElement rootnode = xml.documentElement(); +//CHECK_POINT +// QDomElement root = rootnode; +//CHECK_POINT + cfginfo = rootnode.namedItem( md_info ).toElement(); + md = rootnode.namedItem( md_metadata ).toElement(); + iface = rootnode.namedItem( md_interface ).toElement(); + actions = rootnode.namedItem( md_actions ).toElement(); + idcache.clear(); + cur = rootnode.firstChild(); + while (!cur.isNull()) { + if ( cur.toElement().hasAttribute( mda_id ) ) { + id = 0; + id = attr(cur.toElement(), mda_id).toInt(); + if (id) { + idcache.insert(id, new aCfgItemContaner( id, cur.toElement() ) ); + } +// printf("cache name=%s id=%ld\n",(const char *)cur.nodeName(), id); + } + sub = cur.firstChild(); + if (!sub.isNull()) cur = sub; + else + { + if (!cur.nextSibling().isNull()) cur = cur.nextSibling(); + else + { + sub = cur; + cur.clear(); + while (cur.isNull()) { + sub = sub.parentNode(); + if (sub.isNull()) break; + else cur = sub.nextSibling(); + } + } + }; + } +//CHECK_POINT +// printf("init ok\n"); +} + + +/*! + * Reads resource file. + * \param fname (in) - rc file name. + * \return error code. + */ +int +aCfg::readrc(const QString &fname) +{ + int r = RC_ERROR; + QString configfile; + + r = rc.read( fname ); + if ( r ) return r; + configfile = rc.value( "configfile" ); + if ( !configfile.isEmpty() ) { + r = read( configfile ); + if ( r ) createNew();//return r; +// init(); + r = RC_OK; + } else r = RC_ERROR; + return r; +} + + +/*! + * Writes resource file. + * \param (in) - rc file name to write to. + * \return int. + */ +int +aCfg::writerc(const QString &fname) +{ + int r = RC_ERROR; + QString configfile; + r = rc.write( fname ); + if ( r ) return r; + configfile = rc.value( "configfile" ); + if ( !configfile.isEmpty() ) { + r = write( configfile ); + } + if ( !r ) setModified( false ); + return r; +} + + + +/*! + * Creates new empty configuration. + * \return void. + */ +void +aCfg::createNew(){ + aCfgItem i; + xml.setContent(QString("\n")); + setModified( true ); + + xml.appendChild( xml.implementation().createDocumentType("ananas_configuration",QString::null,"ananas-cfg.dtd")); + rootnode = xml.createElement( md_root ); + xml.appendChild( rootnode ); + rootnode = xml.documentElement(); + cfginfo = insert( rootnode, md_info, QString::null, -1 ); + iface = insert( rootnode, md_interface, QString::null, -1 ); + md = insert( rootnode, md_metadata, QString::null, -1 ); + actions = insert( rootnode, md_actions, QString::null, -1 ); + init(); + setInfo( md_info_name, "New configuration" ); + setInfo( md_info_lastid, "0" ); + setInfo( md_info_author, "unnamed" ); + setInfo( md_info_date, QDateTime::currentDateTime().date().toString(Qt::ISODate) ); + //setInfo( md_info_dir, "newConfig" ); + insert( md, md_globals, QString::null, -1 ); + insert( md, md_catalogues, QString::null, -1 ); + insert( md, md_documents, QString::null, -1 ); + insert( md, md_journals, QString::null, -1 ); + i = insert( md, md_registers, QString::null, -1 ); + insert( i, md_iregisters, QString::null, -1 ); + insert( i, md_aregisters, QString::null, -1 ); +} + + +/*! + * Returns value of info section field of configuration. + * \param name (in) - name of field to fetch value from. + * \return info field's value. + */ +QString +aCfg::info(const QString &name) +{ + return text(cfginfo.namedItem( name ).toElement()); //.firstChild().nodeValue(); +} + +/*! + * Sets new value to specified field of info section of configuration. + * \param name (in) - field's name. + * \param value (in) - field's value. + * \return void. + */ +void +aCfg::setInfo(const QString &name, const QString &value) +{ + aCfgItem i; + i = cfginfo.namedItem( name ).toElement(); + if (i.isNull()) { + i = xml.createElement( name ); + cfginfo.appendChild( i ); + } + setText(i, value); + setModified( true ); +} + + +/*! + * Generates new unique ID for metadata tree object. + * \return new unique ID. + */ +long +aCfg::nextID() +{ + long id = 0; + id = info( md_info_lastid ).toLong(); + if (id == 0 ) id = context_startid; + ++id; + setInfo( md_info_lastid, QString("%1").arg(id) ); + return id; +} + + + +/*! + * Counts specified objects in metadata tree. + * \param context (in) - parent of objects to count. May be a root + * of metadata tree. + * \param classname (in) - class of objects to count. + * \return number of objects. + */ +int +aCfg::count(aCfgItem context, const QString &classname){ + return context.elementsByTagName( classname ).count(); +} + + +/*! + * Counts specified child objects of object in metadata tree. + * Only child objects will be counted, not subchild objects. + * \param context (in) - parent of objects to count. May be a root + * of metadata tree. + * \param classname (in) - class of objects to count. + * \return number of objects. + */ +int +aCfg::countChild(aCfgItem context, const QString &classname){ + int n = 0; + aCfgItem i = firstChild( context ); + while ( !i.isNull() ) { + if ( classname.isEmpty() ) n++; + else + if ( objClass( i ) == classname ) n++; + i = nextSibling( i ); + } + return n; +} + + +/*! + * \en + * Finds object by its name and number. + * \param context (in) - context to seach in. + * \param name (in) - name of object to search for. + * \param n (in) - number of object in found context. + * \return founded object. + * \_en + * \ru + * Находит элемент метаданных в заданном контексте (поддереве) метаданных по имени тэга + * и порядковому номеру. Порядковый номер имеет смысл, если в контексте может находиться + * более одного элемента с одним и тем же тэгом. Так, например, внутри документа может быть несколько + * полей. Поэтому, делая поиск элемента метаданных, описывающего поле, + * внутри контекста (поддерева), описывающего документ, необходимо задавать порядковый номер поля. + * \param context (in) - контекст (поддерево) метаданных,для сужения пространства поиска. + * \param name (in) - имя тэга, с помощью которого описывается элемент метаданных, который мы ищем. + * Возможные значения для этого параметра смотрите в файле acfg.h под заголовком Metadata tags. + * \param n (in) - порядковый номер объекта, на случай, если таких объектов несколько. + * \return ссылку на найденный элемент метаданных или NULL, если элемент не найден. + * \_ru + */ +aCfgItem +aCfg::find(aCfgItem context, const QString &name, int n) +{ + QDomNodeList l = context.elementsByTagName( name ); + return l.item( n ).toElement(); +} + + +/*! + * \en + * \brief Finds object by unique ID in metadata tree. + * \param id (in) - id to search for. + * \return founded object. + * \_en + * \ru + * \brief Находит описание объекта в метаданных по его уникальному в рамках файла метаданных идентификатору. + * + * \param id - идетнификатор объекта в метаданных + * \return ссылку на элемент метаданных + * \_ru + */ +aCfgItem +aCfg::find(long id) +{ + long idl = id; + aCfgItem i; + aCfgItemContaner *ic; + + if ( id == 0 || id == mdc_metadata ) return md; + if ( id == mdc_root ) return rootnode; + if ( id == mdc_info ) return cfginfo; + if ( id == mdc_interface ) return iface; + if ( id == mdc_actions ) return actions; + + ic = idcache.find( idl ); + if (ic) i = ic->item; +// if (!i.isNull()) printf("!founded id=%li\n", id); +// else printf("!NOT founded id=%li\n", id); + return i; +} + +/*! + *\en + * Finds object by its full name. + * \param name (in) - object's full name. + * \return founded object. + *\_en \ru + * \brief Находит объект в текущей (открытой) конфигурации по его полному имени. + * + * \n Полное имя имеет вид ".[.]" + * \n OType может принимать только одно из следующих значений: + * - Document - для объектов типа Документ + * - Catalog - для объектов типа Каталог (примером каталога является Справочник товаров) + * - DocJournal - для объектов типа журнал документов + * - InfoRegister - для объектов типа Информационный Регистр + * - AccumulationRegister - для объектов типа Накопительный регистр. + * Накопительный регистр отличается от информационного тем, что по его записям выполняется автоматический расчет остатков. + * - Form - для объектов типа Экранная форма. + * + * OName задает имя объекта, которое было присвоено объекту во время редактирования конфигурации в программе Анананс-Дизайнер. + * Для поиска документа "Приходная накладная" нужно вызвать find("Document.Приходная накладная"); + * Для поиска формы с именем "Основная форма" в этом документе надо вызвать find("Document.Приходная накладная.Form.Основная форма"); + * \param name (in) - полное имя объекта. + * \return ссылка на найденный объект в случае успеха или NULL в случае, если объект не найден. + *\_ru + */ +aCfgItem +aCfg::find(const QString &name) +{ + QString oType, oName, omType, extName; + aCfgItem gobj, obj, sobj, item; + + oType = name.section( ".", 0, 0 ); + oName = name.section( ".", 1, 1 ); + extName = name.section( ".", 2 ); + gobj = md; + while ( !oType.isEmpty() && !oName.isEmpty() ) { + if (oType == "Document" || oType == tr("Document") ) { + omType = md_document; + gobj = findChild( gobj, md_documents ); + } + if (oType == "Catalogue" || oType == tr("Catalogue") ) { + omType = md_catalogue; + gobj = findChild( gobj, md_catalogues ); + } + if (oType == "DocJournal" || oType == tr("DocJournal")) { + omType = md_journal; + gobj = findChild( gobj, md_journals ); + } + if (oType == "Report" || oType == tr("Report")) { + omType = md_report; + gobj = findChild( gobj, md_reports ); + } + if (oType == "InfoRegister" || oType == tr("InfoRegister") ) { + omType = md_iregister; + gobj = findChild( find(gobj,md_registers,0),md_iregisters ); + } + if (oType == "AccumulationRegister" || oType == tr("AccumulationRegister") ) + { + omType = md_aregister; + gobj = findChild( find(gobj,md_registers,0),md_aregisters ); + } + if (oType == "Form" || oType == tr("Form")) { + omType = md_form; + gobj = findChild( gobj, md_forms ); + } + if ( !gobj.isNull() ) item = findName( gobj, omType, oName ); + if ( item.isNull() ) break; + gobj = item; + oType = extName.section( ".", 0, 0 ); + oName = extName.section( ".", 1, 1 ); + extName = extName.section( ".", 2 ); + } + return item; +} + +/* + * ??? Parameter classname is what for ??? + */ +aCfgItem +aCfg::findName(aCfgItem context, const QString &classname, const QString &name ) +{ + aCfgItem item; + + if ( !context.isNull() && !classname.isEmpty() ){ + item = firstChild( context ); + while ( !item.isNull() ) { + if ( attr( item, mda_name ) == name ){ + break; + } + item = nextSibling( item ); + } + } + return item; +} + +/* + * Finds child object by its class name and number. + * \param context (in) - parent object. + * \param classname (in) - class name of child to search for. + * \param n (in) - number of child (0..countChild( context, classname )-1). + * \return child number n or Null object. + */ +aCfgItem +aCfg::findChild(aCfgItem context, const QString &classname, int n) +{ + int in = 0; + aCfgItem i = firstChild( context ); + while ( !i.isNull() ) { + if ( classname.isEmpty() ) { + if ( in == n ) break; + in++; + } + else { + if ( objClass( i ) == classname ) { + if ( in == n ) break; + in++; + } + } + i = nextSibling( i ); + } + return i; +} + + + +/*! + * Swaps two items in metadata tree. + * \param item1 (in) - first item to swap. + * \param item2 (in) - second item to swap. + * \return true or false. + */ +bool +aCfg::swap(aCfgItem &item1, aCfgItem &item2) +{ + aCfgItem item, ic1, ic2, p1, p2; + + if ( item1.isNull() || item2.isNull() || ( item1 == item2 ) ) + { + if(item1.isNull()) aLog::print(aLog::Debug, tr("aCfg swap: first element is null")); + else + if(item2.isNull()) aLog::print(aLog::Debug, tr("aCfg swap: second element is null")); + else + aLog::print(aLog::Error, tr("aCfg swap element himself")); + return false; + } + p1 = parent( item1 ); + p2 = parent( item2 ); + if ( p1.isNull() || p2.isNull() || ( p1 != p2 ) ) + { + if(p1.isNull()) aLog::print(aLog::Debug, tr("aCfg swap: first parent null")); + else + if(p2.isNull()) aLog::print(aLog::Debug, tr("aCfg swap: second parent null")); + else + aLog::print(aLog::Error, tr("aCfg swap elements with differernt parents")); + return false; + } + p1.insertBefore( item1, item2 ); + setModified( true ); + return true; +} + +/*! + * Returns onject's order number among siblings. + * \param item (in) - object. + * \return object's order number. + */ +int +aCfg::order( aCfgItem item ) +{ + int i = 0; + aCfgItem current = item; + while ( !current.isNull() ) + { + ++i; + current = previousSibling( current ); + } + return i; +} + + +/*! + * Returns parent object. + * \param context (in) - object. + * \return paren object. +*/ +aCfgItem +aCfg::parent( aCfgItem context ) +{ + return context.parentNode().toElement(); +} + + +/*! + * Returns the first child item of the context. + * If there is no child, a null context is returned. + * Changing the returned item will also change the item + * in the metadata tree. + * \param context (in) - node in metadata tree. + * \return aCfgItem - node in metafata tree if found, NULL if not found. + */ +aCfgItem +aCfg::firstChild( aCfgItem context ) +{ + return context.firstChild().toElement(); +} + + +/*! + * Returns the last child item of the context. + * If there is no child, a null context is returned. + * Changing the returned item will also change the item + * in the metadata tree. + */ +aCfgItem +aCfg::lastChild( aCfgItem context ) +{ + return context.lastChild().toElement(); +} + + +/*! + * Returns the next sibling in the netadata tree. + * Changing the returned item will also change the item in the metadata tree. + */ +aCfgItem +aCfg::nextSibling( aCfgItem context ) +{ + return context.nextSibling().toElement(); +} + + +/*! + * Returns the previous sibling in the netadata tree. + * Changing the returned item will also change the item in the metadata tree. + */ +aCfgItem +aCfg::previousSibling( aCfgItem context ) +{ + return context.previousSibling().toElement(); +} + + +/*! + * Returns text of object. + * \param context (in) - object. + * \return string. + */ +QString +aCfg::text(aCfgItem context) +{ + if (context.isNull()) return ""; + return context.firstChild().nodeValue(); +} + + +/*! + * Sets text for object. + * \param context (in) - object. + * \param value (in) - new value. + * \return void. + */ +void +aCfg::setText(aCfgItem context, const QString &value) +{ + QDomText t; + if (context.isNull()) return; + while (!context.firstChild().isNull()) { + context.removeChild( context.firstChild() ); + } + t = xml.createTextNode( value ); + context.appendChild( t ); + setModified( true ); +} + + +/*! + * Returns binary value of object. + * \param context (in) - object to get value of. + * \return array of bytes. + */ +QByteArray +aCfg::binary( aCfgItem context ) +{ + unsigned int i, d, blen; + bool ok; + QString vs = text( context ); + blen = attr( context, mda_length ).toInt(); + QByteArray b( blen ); + for ( i=0; i < blen; i++ ){ + d = 0xff & vs.mid( i*2, 2 ).toInt( &ok, 16 ); + if ( ok ) b.data()[ i ] = d; + else b.data()[ i ] = 0; + } + return b; +} + + +/*! + * Sets binary value of metadata tree node. + * \param context (in) - metadata tree node. + * \param value (in) - new binary value. + * \param format (in) - format of binary data. + * \return void. + */ +void +aCfg::setBinary( aCfgItem context, const QByteArray &value, const QString &format ) +{ + QString vs ="", s; + unsigned int i, d; + for ( i=0; i= 100 ) setAttr(i, mda_id, id ); + if ( !name.isNull()) setAttr(i, mda_name, name ); + context.appendChild( i ); + if ( id > 0 ) idcache.insert(id, new aCfgItemContaner( id, i ) ); + setModified( true ); + return i; +} + +/*! + *\~english + * Saves configuration object to file. + *\~russian + * Сохраняет объект бизнес схемы в файл. + *\~ + * \param context - \~english object to save \~russian объект для сохранения \~ + * \param fileName - \~english file name \~russian имя файла \~ + * \return - \~english error code \~russian код ошибки \~ + */ +int +aCfg::saveOneObject(aCfgItem context, const QString &fileName) +{ + int res=RC_ERROR; + if(!context.isNull()) + { + QDomDocument doc; + if(context.isDocument()) + { + doc = context.toDocument(); + } + else + { + doc.setContent(QString("\n")); + doc.appendChild(context.cloneNode(true)); + } + res = write(doc,fileName); + if(res==RC_OK) + { + aLog::print(aLog::Info, tr("aCfg saveOneObject: context save to file `%1'").arg(fileName)); + } + } + else + { + aLog::print(aLog::Error, tr("aCfg saveOneObject: context is null")); + } + return res; +} + +/*! + *\~english + * Load configuration object from file. + *\~russian + * Загружает объект бизнес схемы из файла. + *\~ + * \param fileName - \~english file name \~russian имя файла \~ + * \return - \~english object, stored in xml file \~russian объект, хранящийся в xml файле \~ + */ +aCfgItem +aCfg::loadOneObject( const QString &fileName ) +{ + aCfgItem res; + QDomDocument doc; + + if(fileName!="") + { + QFile file( fileName ); + QByteArray buf; + QString err; +// int errLine = 0, errColumn = 0; + if ( file.open( QIODevice::ReadOnly ) ) + { + buf = file.readAll(); + file.close(); + if(doc.setContent( buf, false )) + { + res = doc.documentElement(); + } + else + { + aLog::print(aLog::Error, tr("aCfg loadOneObject: invalid cfg file `%1'").arg(fileName)); + } + + } + else + { + aLog::print(aLog::Error, tr("aCfg loadOneObject: invalid file name or not permission to file `%1'").arg(fileName)); + } + } + return res; +} + +/*! + * Removes metadata object from metadata tree. + * All children objects also removed. + * \param context (in) - metadata object. + * \return nothing. + */ +void +aCfg::remove(aCfgItem context) +{ + long id; + aCfgItem child; + + QDomNode own = context.parentNode(); + if (!own.isNull()) { + id = attr( context, mda_id ).toLong(); + child = firstChild(context); + remove(child); + idcache.remove( id ); + own.removeChild(context); + setModified( true ); + } +} + + +/*! + *\~english + * Import configuration object from another configuration. + *\~russian + * Импортирует объект конфигурации из другой конфигурации в текущую. + * Устанавливает новые Id для всех потомков объекта. + *\~ + * \param context - \~english parent for imported object \~russian родитель для импортируемого объекта \~ + * \param objFromAnotherCfg - \~english imported object \~russian импортируемый объект \~ + */ +aCfgItem +aCfg::importCfgItem(aCfgItem context, aCfgItem objFromAnotherCfg ) +{ + aCfgItem item = xml.importNode(objFromAnotherCfg,true).toElement(); + if(!item.isNull()) + { + context.appendChild( item ); + setupNewId(item); + } + return item; + +} +/*! + *\~english + * Sets new id for all children of object \a obj + *\~russian + * Устанавивает новый id для всех потомков объекта \a obj + *\~ + */ +void +aCfg::setupNewId( aCfgItem obj ) +{ + if(!obj.isNull()) + { + if(attr(obj, mda_id)!="") + { + long id; + aLog::print(aLog::Debug, tr("aLog setup new id for %1").arg(attr(obj, mda_name))); + id = nextID(); + aLog::print(aLog::Debug, tr("aLog next id is %1").arg( id ) ); + setAttr(obj,mda_id,id); + idcache.insert(id, new aCfgItemContaner( id, obj ) ); + } + aCfgItem i = firstChild(obj); + while(!i.isNull()) + { + setupNewId(i); + i = nextSibling(i); + } + } +} + +/*! + * Gets ID for metadata object by complete name. + * Name like "Document.Invoice", "Report.Total", etc. + * \param name (in) - full object's name. + * \return object's ID. + */ +long +aCfg::getId( QString &name ) +{ + QString p1, p2, p3; + p1 = name.section( ".", 0, 0 ); + p2 = name.section( ".", 1, 1 ); + p3 = name.section( ".", 2, 2 ); + + return 0; +} + + +/*! + * Returns configuration object ID. + * \param context (in) - object which ID we looking for. + * \return object's ID. + */ +long +aCfg::id(aCfgItem context) +{ + long i = 0; + QString sid; + + if ( !context.isNull() ) { + sid = attr( context, mda_id ); + if ( !sid.isEmpty() ) i=sid.toLong(); + } + return i; +} + +/* + * ??? + */ +void +aCfg::addTypes( QStringList &list, aCfgItem context, const QString &tobject, const QString &tname) +{ + aCfgItem obj; + int i, n; + long oid; + + if ( context.isNull() ) return; + n = count( context, tobject ); + for (i=0; i>formtype)%2 && attr( fobj, mda_type ).toInt() == mode ) + return id(fobj); + } + return 0; +} + +/*! + * Gets journal's documents list. + * \param journal (in) - journal to get list from. + * \return list of documents IDs. + */ +QStringList +aCfg::getJournalDocuments( aCfgItem journal ) +{ + QStringList l; + l.clear(); + if ( objClass(journal) != md_journal ) + return l; + aCfgItem dobj, pobj, jobj; + uint n, m; + int type = attr(journal,mda_type).toInt(); + switch ( type ) + { + case 0: + pobj = find( find( mdc_metadata ), md_documents, 0 ); + n = count(pobj,md_document); + for ( uint i = 0; i < n; i++ ) + { + dobj = find ( pobj, md_document, i ); + if ( !dobj.isNull()) + l.append( attr( dobj, mda_id )); + } + break; + case 1: + n = count(journal,md_used_doc); + for ( uint j = 0; j < n; j++ ) + { + dobj = find( journal, md_used_doc, j ); + QString id = text(dobj); + if ( !find(id.toLong()).isNull() ) + l.append( text(dobj) ); + else + remove(dobj); + } + break; + case 2 : + pobj = find( find( mdc_metadata ), md_documents, 0 ); + n = count(pobj,md_document); + for ( uint i = 0; i < n; i++ ) + { + jobj = find ( pobj, md_document, i ); + if ( !jobj.isNull()) + l.append ( attr( jobj, mda_id )); + } + pobj = find( find( mdc_metadata ), md_journals, 0 ); + n = count( pobj, md_journal ); + for ( uint i = 0; i < n; i++ ) + { + jobj = find ( pobj, md_journal, i ); + if ( !jobj.isNull()) + { + m = count ( jobj, md_used_doc ); + for ( uint j = 0; j < m; j++ ) + { + dobj = find( jobj, md_used_doc, j ); + QString str = text(dobj); + l.remove ( str ); + } + } + } + break; + } + return l; +} + +/*! + * + */ +aCfgItem +aCfg::findJournal(int jtype, aCfgItem doc) +{ + aCfgItem res; + uint n,m; + aCfgItem js = find( find( mdc_metadata ), md_journals, 0 ); + if(js.isNull()) return res; + + n = count( js, md_journal ); + switch(jtype) + { + case 0: + for ( uint i = 0; i < n; i++ ) + { + aCfgItem jobj = find ( js, md_journal, i ); + if ( !jobj.isNull()) + { + if(attr(jobj, mda_type).toInt()==0) return jobj; + } + } + break; + + case 1: + for ( uint i = 0; i < n; i++ ) + { + aCfgItem jobj = find ( js, md_journal, i ); + if ( !jobj.isNull()) + { + if(attr(jobj, mda_type).toInt()==1) + { + m = count ( jobj, md_used_doc ); + for ( uint j = 0; j < m; j++ ) + { + QString dobj = text(find( jobj, md_used_doc, j )); + if(dobj==attr(doc, mda_id)) return jobj; + + } + } + } + } + break; + + default: + break; + } + return res; +} + + +/*! + * Return list of object database tables. + * Every string in string list stored in format, + * consist of table id, table's human name fields, + * separated by tabulate char. + * This function used by Database tables plugins. + * For example: + * 0\tHeader + * 123\tTable1 + * id = 0 for document header, catalogue element; + * id = 1 for catalogue group; + * id = metadata object id for document table. + * \param obj (in) - metadata object. + * \return list of tables. + */ +QStringList +aCfg::objTables( aCfgItem obj ) +{ + QStringList list; + QString t; + int i, n; + long oid, tid; + aCfgItem objt; + + if ( obj.isNull() ) return list; + t = objClass( obj ); + oid = id( obj ); + if ( t == md_journal ) { + list << QString("0\t")+QObject::tr("Documents"); + } + if ( t == md_catalogue ) { + list << QString("0\t")+QObject::tr("Element"); + list << QString("1\t")+QObject::tr("Group"); + } + if ( t == md_document ) { + list << QString("0\t")+QObject::tr("Header"); + n = count( obj, md_table ); + for (i=0; i, Yoshkar-Ola +** Copyright (C) 2003-2005 Grigory Panov , Yoshkar-Ola +** +** This file is part of the Library of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.leaderit.ru/page=ananas or email sales@leaderit.ru +** See http://www.leaderit.ru/gpl/ for GPL licensing information. +** +** Contact org@leaderit.ru if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +/* +Ananas configuration objects. +(c) 2004 Leader InfoTech +*/ +#ifndef ACFG_H +#define ACFG_H + +#include "ananasglobal.h" + +#include +//#include +#include +#include "acfgrc.h" + +#ifdef __BORLANDC__ +#define CHECK_POINT printf("%s:%i %s()\n",__FILE__,__LINE__,__FUNC__); +#else +#define CHECK_POINT printf("%s:%i %s()\n",__FILE__,__LINE__,__FUNCTION__); +#endif + + +extern void (*cfg_messageproc)(int , const char *); +void ANANAS_EXPORT cfg_message(int msgtype, const char *msgfmt,...); +void ANANAS_EXPORT debug_message(const char *msgfmt,...); + +class QObject; + +/*! + * \~english Metadata object methods return codes. \~russian + * Коды возвратов методов объекта метаданных. \~ + */ +#define RC_OK 0 /**< All right - no errors */ +#define RC_ERROR 1 /**< Error while executing method */ + +/*! +Metadata system contexts id. +*/ +#define mdc_unknown 0 /**< Unknown context */ +#define mdc_root 1 /**< Root context */ +#define mdc_info 2 /**< Info context */ +#define mdc_interface 3 /**< Interface context */ +#define mdc_metadata 4 /**< Metadata context */ +#define mdc_globals 5 /**< Metadata context */ +#define mdc_actions 6 /**< Actions context */ + +//#define mdc_documents 6 /**< Metadata context */ +//#define mdc_catalogues 7 /**< Metadata context */ +//#define mdc_iregisters 8 /**< Metadata context */ +//#define mdc_aregisters 9 /**< Metadata context */ +//#define mdc_reports 10 /**< Metadata context */ +//#define mdc_journals 11 /**< Metadata context */ + +/*! +Metadata tags. +*/ +#define md_root "ananas_configuration" +#define md_interface "interface" + +#define md_info "info" +#define md_info_name "name" +#define md_info_author "author" +#define md_info_date "date" +#define md_info_mdate "mdate" +#define md_info_remark "remark" +#define md_info_lastid "lastid" +//#define md_info_dir "dir" + +#define md_metadata "metadata" /**< Metadata tag */ +#define md_globals "globals" +#define md_languages "languages" +#define md_language "language" +#define md_aliases "aliases" +#define md_alias "alias" +#define md_roles "roles" +#define md_role "role" +#define md_description "description" +#define md_sourcecode "sourcecode" +#define md_servermodule "server_module" +#define md_clientmodule "client_module" +#define md_formsource "form_source" +#define md_menutext "menutext" +#define md_argument "argument" + +#define md_documents "documents" +#define md_document "document" + +#define md_catalogues "catalogues" +#define md_catalogue "catalogue" +#define md_element "element" +#define md_group "group" + +#define md_string_view "string_view" +#define md_svfunction "svfunction" + +#define md_registers "registers" +#define md_iregisters "iregisters" +#define md_iregister "iregister" +#define md_aregisters "aregisters" +#define md_aregister "aregister" + +#define md_reports "reports" +#define md_report "report" + +#define md_journals "journals" +#define md_journal "journal" +#define md_columns "columns" +#define md_column "column" +#define md_used_doc "used_doc" +#define md_fieldid "fieldid" + +#define md_field "field" +#define md_forms "forms" +#define md_form "form" +#define md_defaultmod "defaultmod" +#define md_webforms "webforms" +#define md_webform "webform" +#define md_formdesign "dialogform" + +#define md_tables "tables" +#define md_table "table" +#define md_header "header" + +#define md_resources "resources" +#define md_dimensions "dimensions" +#define md_information "information" + +/*! +Action metadata object items. +*/ +#define md_actions "actions" +#define md_actiongroup "actiongroup" +#define md_action "action" +#define md_objectid "objectid" +#define md_formid "formid" +#define md_actiontype "actiontype" +#define md_active_picture "active_picture" +#define md_passive_picture "passive_picture" + +/*! +Interface metadata object items. +*/ +#define md_interface "interface" +#define md_toolbars "toolbars" +#define md_toolbar "toolbar" +#define md_popupmenus "popupmenus" +#define md_popupmenu "popupmenu" +#define md_mainmenu "mainmenu" +#define md_submenu "submenu" +#define md_command "command" +#define md_comaction "comaction" +#define md_separator "separator" +#define md_key "key" +#define md_menutext "menutext" +//key modifiers +#define md_km_ctrl "Ctrl+" +#define md_km_alt "Alt+" +#define md_km_shift "Shift+" + +#define md_image_collection "image_collection" +#define md_image "image" + + +/*! +Metadata attributes. +*/ +#define mda_name "name" +#define mda_id "id" +#define mda_type "type" +#define mda_readonly "readonly" +#define mda_lang "lang" +#define mda_nz "nz" +#define mda_sort "sort" +#define mda_no_unconduct "no_unconduct" +#define mda_plus "plus" +#define mda_sum "sum" +#define mda_tag "tag" +#define mda_trfile "trfile" +#define mda_length "length" +#define mda_format "format" +#define mda_stdf "stdf" +#define mda_rights "rights" + +/*! +Actions types +*/ + +#define md_action_new 0 +#define md_action_edit 1 +#define md_action_view 2 +#define md_action_execute 3 + +/*! + * Default forms types. + * If bit with some number set in 1 form can use for this action. + */ + +#define md_form_nouse 0 +#define md_form_new 1 +#define md_form_view 2 +#define md_form_edit 3 +#define md_form_select 4 + + +/*! + * Catalogue forms types. + */ + +#define md_form_elem_list 0 +#define md_form_elem 1 +#define md_form_group 2 + + +/*! +System object id +*/ + +#define md_systemjournal 1 +#define md_aregarhive 2 + +//class aCfg; +//extern aCfg cfg; + +#define ERR_Code int + +#define err_unknown -1//some ote error +#define err_noerror 0// result successful +#define err_notable 1// no table with such name +#define err_objnotfound 2// no such object in metadata +#define err_incorrecttype 3// object has othe metadata id +#define err_uidnotfound 4// no such id in unicues +#define err_notselected 5// select return nothing +#define err_nodatabase 6// database is not inited +#define err_selecterror 7// select return some error +#define err_condition 8// error in condition +#define err_noobject 9// aObject didn't init md object +#define err_nosysjournal 10// system journal not inited +#define err_inserterror 11// insert in aSQLTable return false +#define err_execerror 12// exec return false +#define err_updateerror 13// update reutrn false +#define err_abstractobj 14// you need to use hi level object or specimen of object +#define err_fieldnotfound 15// no filed with such name +#define err_copyerror 16// object don't copy +#define err_nocatalogue 17// catalogue not found +#define err_nogroup 18// group not found +#define err_deleteerror 19// object don't deleted or don't mark deleted +#define err_nodocument 20// no such document +#define err_emptyperiod 21// you try close empty period +#define err_noresources 22// the register object have no resources tag in metadata +#define err_incorrectname 23// object have incorrect name +#define err_closeperiod 24// close period error +#define err_conducterror 25// error when document conducting +#define err_docconducted 26// you can't change conducted document or conduct document once more +#define err_docunconducted 27// you can unconduct document if it not conducted +#define err_cyclereparent 28//you have cycle when try reparent +#define err_readonly 29//object is readonly +#define err_invaliddate 30// invalid date or datetime specified +#define err_nodimensions 31// the register object have no dimensions tag in metadata +#define err_nowidgetfound 32// there is no such widget in form + +#define md_user_roles "userroles" +#define md_users "users" +#define md_user "user" +#define md_usr_role "u_role" +#define md_roles "roles" +#define md_role "role" +#define md_rl_users "r_users" +#define md_rl_user "r_user" +#define md_right_roles "rroles" + +#define perm_read 0 +#define perm_execute 1 +#define perm_create 2 +#define perm_delete 3 +#define perm_turn_on 4 +#define perm_turn_off 5 +#define perm_admin 6 + +#define aPermission int + +#define aCfgItem QDomElement + + + +/*! + * \en + * Configuration item container. + * Using for id caching and fast search items by id. + *\_en + *\ru + * \brief Контейнер для элемента метаданных бизнес схемы Ананаса. + * Наследует QObject. + * + * Используется для кэширования id и быстрого поиска элементов по id. + *\_ru + */ +class ANANAS_EXPORT aCfgItemContaner: public QObject +{ +public: + long id; + aCfgItem item; + aCfgItemContaner(long newid, aCfgItem newitem); +}; + +/* +class ANANAS_EXPORT aCfgFieldType: public QObject +{ +public: + QString name, type; + aCfgFieldType( const QString &newname, const QString &newtype); + aCfgFieldType( aCfgItem newitem ); +}; +*/ + + + +/*! + *\en + * Metadata object for metadata script access. + *\_en + *\ru + * \brief Объект метаданных для обеспечения доступа из скриптов. + * Наследует QObject. + *\_ru + */ +class ANANAS_EXPORT AMetadataObject: public QObject +{ +Q_OBJECT +public: + AMetadataObject( aCfgItem newitem ); +public slots: + QString Class(); +private: + aCfgItem item; +}; + + + +/*! \en + * System configuration object. + * + * Using for story and edit accountine + * system configuration. + *\_en \ru + * \brief Класс реализует програмный интерфейс доступа к элементам метаданных системы. + * Наследует QObject. + * + * Взаимосвязанный набор метаданных, записанный в файл, называется конфигурацией + * (прикладной настройкой) системы. Методы класса позволяют загружать конфигурацию из + * файла, записывать её в файл. + *\_ru + */ +class ANANAS_EXPORT aCfg: public QObject //QDomDocument +{ + Q_OBJECT + +public: + enum fieldType { ftUnknown, ftChar, ftNumberic, ftDate, ftObject }; + aCfgRc rc; + + aCfg(); + ~aCfg(); + + int read(const QString &fname); + int write(const QString &fname); + int write(QDomDocument doc, const QString &fname); + int readrc(const QString &fname); + int writerc(const QString &fname); + bool compressed(); + void setCompressed( bool mode ); + bool modified(); + void setModified( bool mode ); +// void print(); + void createNew(); + + QString info(const QString &name); + void setInfo(const QString &name, const QString &value); + + long getId( QString &name ); + long id(aCfgItem context); + + QString objClass( long id ); + QString objClass( aCfgItem context ); + + int count(aCfgItem context, const QString &classname); + int countChild(aCfgItem context, const QString &classname = QString::null ); + + QString attr(aCfgItem context, const QString &name); + void setAttr(aCfgItem context, const QString &name, const QString &value); + void setAttr(aCfgItem context, const QString &name, int value); + + QString text(aCfgItem context); + void setText(aCfgItem context, const QString &value ); + QByteArray binary( aCfgItem context ); + void setBinary( aCfgItem context, const QByteArray &value, const QString &format = QString::null ); + QString binaryFormat( aCfgItem context ); + QString sText(aCfgItem context, const QString & subname ); + void setSText(aCfgItem context, const QString & subname, const QString &value); + + aCfgItem find(aCfgItem context, const QString &name, int n = 0 ); + aCfgItem find(long id); + aCfgItem find(const QString &name); + aCfgItem findChild(aCfgItem context, const QString &classname, int n = 0 ); + aCfgItem findName(aCfgItem context, const QString &classname, const QString &name = QString::null ); + + bool swap( aCfgItem &item1, aCfgItem &item2); + int order( aCfgItem item ); + aCfgItem parent( aCfgItem context ); + aCfgItem firstChild( aCfgItem context ); + aCfgItem lastChild( aCfgItem context ); + aCfgItem nextSibling( aCfgItem context ); + aCfgItem previousSibling( aCfgItem context ); + + aCfgItem insert(aCfgItem context, const QString &otype, const QString &name = QString::null, long id = 0); + int saveOneObject(aCfgItem context, const QString &fileName); + aCfgItem loadOneObject(const QString &fileName); + void remove(aCfgItem context); + + aCfgItem importCfgItem( aCfgItem context, aCfgItem obj ); + void setupNewId( aCfgItem obj ); + + QStringList types( const QString &filter = QString::null, aCfgItem *obj = 0 ); + QStringList ObjectTypes(); + + // Hi level functions. + aCfgItem insertDocument( const QString &name ); + aCfgItem insertDocumentTable(aCfgItem owner, const QString &name ); + aCfgItem insertCatalogue( const QString &name ); + aCfgItem insertIRegister ( const QString &name ); + aCfgItem insertARegister ( const QString &name ); + aCfgItem insertJournal ( const QString &name ); + aCfgItem insertReport ( const QString &name ); + aCfgItem insertField( aCfgItem owner, const QString §ion, const QString &name,const QString &ftype ); + aCfgItem insertForm( aCfgItem owner, const QString &name ); + aCfgItem insertWebForm( aCfgItem owner, const QString &name ); + + long getDefaultFormId( aCfgItem owner, int actiontype, int mode =0 ); + QStringList getJournalDocuments( aCfgItem journal ); + aCfgItem findJournal(int jtype, aCfgItem doc); + QStringList objTables( aCfgItem obj ); + QStringList objTables( int objid ); + aCfgItem objTable( aCfgItem obj, int id ); + aCfgItem objTable( int objid, int id ); + +public slots: + QString Info( QString partname ); + +signals: + void message( int messageType, const QString & messageText ); + +private: + QDomDocument xml; + bool fCompressed, fModified; + // QDomElement root; + aCfgItem rootnode, cfginfo, md, + iface, + actions; + Q3IntDict idcache; + long nextID(); + void init(); + + void addTypes( QStringList &list, aCfgItem context, const QString &tobject, const QString &tname); +}; + +#endif diff --git a/src/lib/acfgrc.cpp b/src/lib/acfgrc.cpp new file mode 100644 index 0000000..4108db9 --- /dev/null +++ b/src/lib/acfgrc.cpp @@ -0,0 +1,266 @@ +/**************************************************************************** +** $Id: acfgrc.cpp,v 1.3 2008/11/27 20:20:55 leader Exp $ +** +** Code file of the recorse work file of Ananas +** Designer and Engine applications +** +** Created : 20031201 +** +** Copyright (C) 2003-2004 Leader InfoTech. All rights reserved. +** +** This file is part of the Library of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.leaderit.ru/page=ananas or email sales@leaderit.ru +** See http://www.leaderit.ru/gpl/ for GPL licensing information. +** +** Contact org@leaderit.ru if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#include +#include +#include +#include +//#include +#include +#include +#include + +#include "acfg.h" +#include "acfgrc.h" +#include "messageswindow.h" + +QPixmap +rcIcon( const char *name ) +{ +// QString iconname = QString(":/images/%1").arg(name); +//printf("get icon %s ",(const char *) iconname.toUtf8().data()); + QPixmap pm(QString(":/images/%1").arg(name)); +//printf("\n"); + return pm; +} + + + +void +aMessageOutput( QtMsgType type, const char *msg ) +{ + switch ( type ) { + case QtDebugMsg: + cfg_message( 0, "%s\n", msg ); + break; + case QtWarningMsg: + cfg_message( 1, "%s\n", msg ); + break; + case QtFatalMsg: + cfg_message( 2, "%s\n", msg ); + abort(); // deliberately core dump + } +} + +void +setMessageHandler( bool ) // GUI ) +{ +// qInstallMsgHandler( aMessageOutput ); +// if ( GUI ) { +// cfg_messageproc = messageproc; +// cfg_message( 0, ""); +// } +} + +void +unsetMessageHandler() +{ + qInstallMsgHandler( 0 ); + cfg_messageproc = 0; +} + +/*! +Ananas resource file object. +*/ +aCfgRc::aCfgRc() +{ + values.setAutoDelete( TRUE ); + filename = QString::null; +} + + +/** + * \ru + * \brief Читает данные из файла ресурсов указанного в параметре при вызове. + * + * И заполняет объекта класса данными из файла ресурса. + * \param fname имя файла ресурса, включая полный путь. + * \return 0 - в случае успешной загрузки данных из файла ресурсов. + * 1 - если не удалось открыть файл ресурсов для чтения. + * \_ru + */ +int +aCfgRc::read(const QString &fname) +{ + QStringList l; + QFile file( fname ); + + filename = fname; + values.clear(); + if ( file.open( QIODevice::ReadOnly ) ) + { + Q3TextStream stream( &file ); + QString line, k, v; + + stream.setEncoding(Q3TextStream::UnicodeUTF8); + while ( !stream.eof() ) { + line = stream.readLine(); // line of text excluding '\n' + k = line.section("=",0,0); + v = line.section("=",1,100); if ( v.isNull() ) v = ""; + values.insert( k, new QString( v ) ); + } + file.close(); + return 0; + } + return 1; +} + + + +/** + * \ru + * \brief Записывает данные в файл ресурсов, указанный в параметрах вызова. + * + * В файл ресурса записываются данные, хранимые в объекте. + * \param fname - имя файла ресурсов, включая полный путь. + * \return 0, в случе успешной записы данных в файл ресурсов. + * 1, если не удалось открыть файл ресурсов на запись. + * \_ru + */ +int +aCfgRc::write(const QString &fname) +{ + QFile file( fname ); +// int i; + + if ( file.open( QIODevice::WriteOnly ) ) + { + Q3TextStream stream( &file ); + Q3DictIterator it( values ); +// int i, vc; + + stream.setEncoding(Q3TextStream::UnicodeUTF8); + for( ; it.current(); ++it ) + stream << it.currentKey() << "=" << *it.current() << endl; +// cout << endl; +// vc = values.count(); +// for ( i = 0; i< vc; i++) stream << *it << "\n"; + file.close(); + return 0; + } + return 1; +} + + + +/** + * \ru + * \brief Записывает данные объекта в файл ресурсов. + * + * В качестве имени файла ресурсов используется значение, хранящееся + * в поле filename объекта. + * Использует метод aCfgRc::write(const QString &fname) + * \return 0, в случе успешной записы данных в файл ресурсов. + * 1, если не удалось открыть файл ресурсов на запись. + * \_ru + * \see aCfgRc::write(const QString &fname) + */ +int +aCfgRc::write() +{ + return write( filename ); +} + + + +/** + * \ru + * \brief Возвращает значение именованного параметра. + * + * Метод предоставляет доступ к параметрам файла ресурсов, хранимым в объекте. + * \param name - имя параметра, значение которого требуется получить. + * Состав и количество параметров вида ИМЯ=ЗНАЧЕНИЕ не контролируются методом. + * \return строку со значением параметра или пустую строку "", если параметр не + * найден. + * \_ru + */ +QString +aCfgRc::value(const QString &name, const QString &defValue) +{ + QString *s; + s = values.find( name ); + if ( s ) return *s; else return defValue; +} + + + +/** + * \ru + * \brief Задает значение именованного параметра. + * + * Метод предоставляет доступ к параметрам файла ресурсов, хранимым в объекте. + * \param name - имя параметра, значение которого требуется задать. + * \param value - новое значение параметра с именем name. + * Состав и количество параметров вида ИМЯ=ЗНАЧЕНИЕ не контролируются методом. + * Однако, для успешного создания соединения с SQL сервером должны быть заданы + * как минимум приведенные в примере ниже шесть праметров. + * \code + * setValue( "configfile" , "resourses/inventory-demo.cfg"); + * setValue( "dbhost" , "localhost"); + * setValue( "dbname" , "tests_tmp_db"); + * setValue( "dbuser" , "root"); + * setValue( "dbpass" , ""); + * setValue( "dbtype" , "mysql"); + * + * \endcode + * \_ru + */ +void +aCfgRc::setValue(const QString &name, const QString &value) +{ + if (values.find( name )) values.replace( name, new QString( value )); + else values.insert( name, new QString( value )); +} + + +/** + * \ru + * \brief Возвращает количество параметров, информация о которых храниться в объекте. + * + * \return количество параметров, информация о которых храниться в объекте. + * \_ru + */ +int +aCfgRc::count() +{ + return ( int ) values.count(); +} + + + +/** + * \ru + * \brief Возвращает имя используемого rc файла с полным путем. + * \_ru + */ +QString +aCfgRc::getRcFileName() +{ + return filename; +} diff --git a/src/lib/acfgrc.h b/src/lib/acfgrc.h new file mode 100644 index 0000000..db50621 --- /dev/null +++ b/src/lib/acfgrc.h @@ -0,0 +1,72 @@ +/**************************************************************************** +** $Id: acfgrc.h,v 1.2 2008/11/09 21:09:11 leader Exp $ +** +** Header file of the recorse work file of Ananas +** Designer and Engine applications +** +** Created : 20031201 +** +** Copyright (C) 2003-2004 Leader InfoTech. All rights reserved. +** +** This file is part of the Library of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.leaderit.ru/page=ananas or email sales@leaderit.ru +** See http://www.leaderit.ru/gpl/ for GPL licensing information. +** +** Contact org@leaderit.ru if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#ifndef ACFGRC_H +#define ACFGRC_H + +#include "ananasglobal.h" + +#include +#include +//Added by qt3to4: +#include + +QPixmap ANANAS_EXPORT rcIcon(const char *name); +void ANANAS_EXPORT setMessageHandler(bool GUI = false); +void ANANAS_EXPORT unsetMessageHandler(); + + +/** + * \ru + * \brief Класс для работы с файлом ресурсов. + * + * Класс aCfgRc реализует интерфейс управления файлом ресурсов бизнес-схемы Ананаса, + * содержащим параметры соединения с SQL сервером, имя бизнес схемы, + * отображаемое пользователю для выбора при запуске Ананаса, и ссылку на файл метаданных + * бизнес-схемы Ананаса. + * \_ru + */ +class ANANAS_EXPORT aCfgRc: public QObject +{ +public: + aCfgRc(); + int read(const QString &fname); + int write(const QString &fname); + int write(); + QString value(const QString &name, const QString &defValue = QString::null ); + void setValue(const QString &name, const QString &value); + int count(); + QString getRcFileName(); + +private: + QString filename; + Q3Dict values; +}; + +#endif diff --git a/src/lib/acmanifest.cpp b/src/lib/acmanifest.cpp new file mode 100644 index 0000000..e1285e0 --- /dev/null +++ b/src/lib/acmanifest.cpp @@ -0,0 +1,247 @@ +/**************************************************************************** +** $Id: acmanifest.cpp,v 1.2 2008/11/08 20:16:35 leader Exp $ +** +** Work with manifest.xml implementation file of +** Ananas application +** +** Created : 20060927 +** +** Copyright (C) 2003-2004 Leader InfoTech. All rights reserved. +** Copyright (C) 2006 Grigory Panov , Yoshkar-Ola. +** +** This file is part of the Library of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.leaderit.ru/page=ananas or email sales@leaderit.ru +** See http://www.leaderit.ru/gpl/ for GPL licensing information. +** +** Contact org@leaderit.ru if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#include "alog.h" +#include "acmanifest.h" +#include +#include + +//#define ERROR true + + +aCManifest::aCManifest():QObject() +{ +} + +aCManifest::~aCManifest() +{ +} + + + // place your castom types before mf_other + // enum type{ mf_metadata, mf_template, mf_dir, mf_script, mf_form, mf_picture, mf_other=100 }; + +void +aCManifest::create() +{ + manifest.setContent(QString("")); + QDomElement root = manifest.createElement("manifest:manifest"); + manifest.appendChild(root); + rootNode = root; + currentNode.clear(); + return; +} + +QString +aCManifest::toString() +{ + return manifest.toString(4); //indent - 4 space +} + +bool +aCManifest::write(const QString& fname) +{ + QFile file(fname); + QByteArray buf( manifest.toString(4).utf8() ); + if ( file.open( QIODevice::WriteOnly ) ) + { + QTextStream ts( &file ); + //--ts.setEncoding(Q3TextStream::UnicodeUTF8); + manifest.save(ts, 4); + file.close(); + } + else + { + aLog::print(aLog::Error, tr("aCManifest save xml %1").arg(fname)); + txtError = QString("aCManifest save xml %1").arg(fname); + return false; + } + return true; +} + + +bool +aCManifest::read(const QString& fname) +{ + QFile file( fname ); + QByteArray buf; + QString err; + int errLine = 0, errColumn = 0; + if ( !file.open( QIODevice::ReadOnly ) ) + { + aLog::print(aLog::Error, tr("aCManifest read file `%1'").arg(fname)); + return false; + } + buf = file.readAll(); + file.close(); + manifest.setContent( QString("") ); + if ( !manifest.setContent( buf, false, &err, &errLine, &errColumn ) ) + { + aLog::print(aLog::Error, tr("aCManifest read line: %1 column: %2").arg(errLine).arg(errColumn)); + txtError = err; + return RC_ERROR; + } + if(!manifest.documentElement().isNull()) + { + rootNode = manifest.documentElement().firstChild().toElement(); + } + currentNode.clear(); + return true; + +} + + +void +aCManifest::clear() +{ + manifest.clear(); + currentNode.clear(); + //manifest.setContent(""); + rootNode.clear(); +} + + +bool +aCManifest::isExists( const QString &fname ) +{ + //TODO implement this! + return isValid(); +} + +bool +aCManifest::addEntry( const QString &fname, int type) +{ + if(isValid()) + { + QDomElement entry = manifest.createElement("manifest:file-entry"); + entry.setAttribute("manifest:full-path",fname); + entry.setAttribute("manifest:type",type); + rootNode.appendChild(entry); + return true; + } + else + { + return false; + } +} + +bool +aCManifest::removeEntry( const QString &fname, bool withChilds ) +{ + + bool res = false; + if(isValid()) + { + QDomElement root = manifest.documentElement().firstChild().toElement(); + QDomElement el = root.firstChild().toElement(); + QString attr; + while(!el.isNull()) + { + printf("element is %s\n",el.nodeName().ascii()); + attr = el.attribute("manifest:full-path"); + if(withChilds) + { + if(attr.find(fname)!=0) // only if attr begining from fname + { + printf("remove entry %s\n",attr.ascii()); + } + } + else + { + if(attr==fname) + { + printf("remove entry %s\n",attr.ascii()); + root.removeChild(el); + res = true; + } + } + el = root.nextSibling().toElement(); + + } + } + return res; +} + +bool +aCManifest::isValid() +{ + if(rootNode.isNull()) + { + aLog::print(aLog::Error, tr("aCManifest invalid manifest")); + txtError = "aCManifest invalid manifest"; + return false; + } + return true; +} + + +aCManifest::record +aCManifest::first() +{ + aCManifest::record rec; + if(isValid()) + { + QDomElement node = rootNode.firstChild().toElement(); + if(!node.isNull()) + { + currentNode = node; + rec.name = node.attribute("manifest:full-path"); + rec.type = node.attribute("manifest:type", "0").toInt(); + } + } + return rec; +} + + +aCManifest::record +aCManifest::next() +{ + aCManifest::record rec; + if(isValid() && !currentNode.isNull()) + { + QDomElement node = currentNode.nextSibling().toElement(); + if(!node.isNull()) + { + currentNode = node; + rec.name = node.attribute("manifest:full-path"); + rec.type = node.attribute("manifest:type", "0").toInt(); + } + } + return rec; + +} + +QString +aCManifest::lastError() const +{ + return txtError; +} + + diff --git a/src/lib/acmanifest.h b/src/lib/acmanifest.h new file mode 100644 index 0000000..5058b60 --- /dev/null +++ b/src/lib/acmanifest.h @@ -0,0 +1,98 @@ +/**************************************************************************** +** $Id: acmanifest.h,v 1.1 2008/11/05 21:16:28 leader Exp $ +** +** manifest.xml function header file of +** Ananas application library +** +** Created : 20031201 +** +** Copyright (C) 2003-2004 Leader InfoTech. All rights reserved. +** Copyright (C) 2006 Grigory Panov , Yoshkar-Ola. +** +** This file is part of the Designer application of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.leaderit.ru/page=ananas or email sales@leaderit.ru +** See http://www.leaderit.ru/gpl/ for GPL licensing information. +** +** Contact org@leaderit.ru if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#ifndef ACMANIFEST_H +#define ACMANIFEST_H + +#include "qdom.h" +#include "qstringlist.h" +#include "ananas.h" +#include + + + +/** + * \en + * Class for work with manifest.xml + * \_en + * \ru + * \brief Класс aCManifest предназначен для работы с файлом manifest.xml + * Наследует QObject. + * + * \_ru + */ +#define mf_invalid 0 +#define mf_metadata 1 +#define mf_template 2 +#define mf_dir 3 +#define mf_script 4 +#define mf_form 5 +#define mf_picture 6 +#define mf_other 100 + +class ANANAS_EXPORT aCManifest: public QObject +{ + Q_OBJECT +public: + + aCManifest(); + virtual ~aCManifest(); + // enum type{ mf_invalid, mf_metadata, mf_template, mf_dir, mf_script, mf_form, mf_picture, mf_other=100 }; + struct record + { + QString name; + int type; + }; + // place your castom types before mf_other + + virtual void create(); + virtual QString toString(); + virtual bool write(const QString& fname); + virtual bool read(const QString& fname); + virtual void clear(); + virtual bool isValid(); + + virtual aCManifest::record first(); + virtual aCManifest::record next(); + + virtual bool isExists( const QString &fname ); + virtual bool addEntry( const QString &fname, int type); + virtual bool removeEntry( const QString &fname, bool withChilds ); + virtual QString lastError() const; + +private: + QString txtError; + QDomDocument manifest; + QDomElement rootNode, currentNode; + +}; + + +#endif //ACMANIFEST_H diff --git a/src/lib/acontainer.cpp b/src/lib/acontainer.cpp new file mode 100644 index 0000000..4e795fd --- /dev/null +++ b/src/lib/acontainer.cpp @@ -0,0 +1,402 @@ +/**************************************************************************** +** $Id: acontainer.cpp,v 1.2 2008/11/08 20:16:35 leader Exp $ +** +** Data container implementation file of +** Ananas application +** +** Created : 20060209 +** +** Copyright (C) 2006 Grigory Panov , Yoshkar-Ola. +** +** This file is part of the Library of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.leaderit.ru/page=ananas or email sales@leaderit.ru +** See http://www.leaderit.ru/gpl/ for GPL licensing information. +** +** Contact org@leaderit.ru if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#include "alog.h" +#include "acontainer.h" +#include "acmanifest.h" +#include "aservice.h" +#include +#include +#include +#include +#include +#include + + +aContainer::aContainer():QObject() +{ +} + +aContainer::aContainer(const QString& name):QObject(0, name) +{ + manifest = new aCManifest(); +} + +aContainer::~aContainer() +{ + delete manifest; + manifest = 0; +} + +bool +aContainer::open() +{ + return open(name()); +} + +bool +aContainer::open(const QString& name) +{ + close(); + generateName4TmpDir(); + if(createTmpDir()) + { + extractManifest(name, manifest); + if(manifest) + { + if(extractData(name)) + { + setName(name); + aLog::print(aLog::Debug, tr("aContainer unzip")); + return true; + } + } + cleanupTmpFiles(); + } + aLog::print(aLog::Error, tr("aContainer unzip")); + return false; +} + + +void +aContainer::create() +{ + generateName4TmpDir(); + createTmpDir(); + manifest->create(); +} + +void +aContainer::close() +{ + cleanupTmpFiles(); +} + +void +aContainer::generateName4TmpDir() +{ + QString temp; +#ifndef _Windows + temp = getenv("TMPDIR"); + if(temp=="" || temp.isEmpty()) + temp = P_tmpdir; +#else + temp = getenv("TEMP"); +#endif + tmpDirName = QString(temp+"/%1").arg(QDateTime::currentDateTime().toTime_t()); + tmpDirName = QDir::convertSeparators(tmpDirName); + +} + +bool +aContainer::createTmpDir() +{ + QDir dir; + if(!dir.mkdir(tmpDirName)) + { + setLastError(tr("Can't create temporary directory")); + aLog::print(aLog::Error, "aContainer create temporary directory %1"); + return false; + } + else + { + aLog::print(aLog::Debug, tr("aContainer create temporary directory %1").arg(tmpDirName)); + return true; + } + +} + +bool +aContainer::save(const QString& name) +{ + setName(name); + if(manifest) + { + aCManifest::record rec; + rec = manifest->first(); + while(rec.type!=mf_invalid) + { + compressFile(rec.name); + rec = manifest->next(); + } + } + else + { + setLastError(tr("No manifest found!")); + aLog::print(aLog::Error, "aContainer save: manifest is null"); + return false; + } + return true; +} + +bool +aContainer::save() +{ + return save(name()); + +} + +bool +aContainer::addFile(const QString& filename, const QString &newname, int type) +{ + bool res = false; + if(!aService::copyFile( QDir::convertSeparators(filename), QDir::convertSeparators(tmpDirName + newname), true)) + { + aLog::print(aLog::Error, tr("aContainer error copy file")); + } + else + { + if(manifest) + { + manifest->addEntry(newname, type); + res = true; + } + else + { + aLog::print(aLog::Error, tr("aContainer manifest is null")); + } + } + return res; +} + +QString +aContainer::realPath(const QString &fname) const +{ + return ""; +} + + +bool +aContainer::extractManifest(const QString& archName, aCManifest *mf) +{ +#ifndef Q_OS_WIN32 + Q3Process process( QString("unzip") ); +// process.setWorkingDirectory (dir); + process.addArgument("-op"); + process.addArgument( archName ); + process.addArgument("/META-INF/manifest.xml"); + process.addArgument( "-d" ); + process.addArgument( tmpDirName ); + +#else + Q3Process process( QString("7z") ); +// process.setWorkingDirectory ( templateDir); +// printf("working dir = `%s'\n", QString(templateDir).ascii()); + process.addArgument( "x" ); + process.addArgument( "-y" ); + process.addArgument( QString("-o%1").arg(tmpDirName) ); + process.addArgument( archName ); + +#endif + + if( !process.start() ) + { + setLastError(tr("Can't start unzip")); + aLog::print(aLog::Error, tr("aContainer start unzip")); + return false; + } + + while( process.isRunning() ); + + if( !process.normalExit() ) + { + setLastError(tr("Unzip ended anormal")); + aLog::print(aLog::Error, tr("aContainer unzip dead")); + return false; + } + else + { + aLog::print(aLog::Debug, tr("aContainer unzip normal")); + } + if( process.exitStatus() ) + { + setLastError(tr("Unzip ended with code %1").arg(process.exitStatus())); + return false; + } + if(mf && mf->read(tmpDirName + QDir::convertSeparators("/META-INF/manifest.xml"))) + { + return true; + } + return false; +} + +bool +aContainer::extractData(const QString& archName) +{ +#ifndef Q_OS_WIN32 + Q3Process process( QString("unzip") ); +// process.setWorkingDirectory (dir); + process.addArgument("-op"); + process.addArgument( archName ); + process.addArgument( "-d" ); + process.addArgument( tmpDirName ); + +#else + Q3Process process( QString("7z") ); +// process.setWorkingDirectory ( templateDir); +// printf("working dir = `%s'\n", QString(templateDir).ascii()); + process.addArgument( "x" ); + process.addArgument( "-y" ); + process.addArgument( QString("-o%1").arg(tmpDirName) ); + process.addArgument( archName ); + +#endif + + if( !process.start() ) + { + setLastError(tr("Can't start unzip")); + aLog::print(aLog::Error, tr("aContainer start unzip")); + return false; + } + + while( process.isRunning() ); + + if( !process.normalExit() ) + { + setLastError(tr("Unzip ended anormal")); + aLog::print(aLog::Error, tr("aContainer unzip dead")); + return false; + } + else + { + aLog::print(aLog::Debug, tr("aContainer unzip normal")); + } + if( process.exitStatus() ) + { + setLastError(tr("Unzip ended with code %1").arg(process.exitStatus())); + return false; + } + return true; +} + +bool +aContainer::compressFile(const QString& fileName) +{ + +#ifndef Q_OS_WIN32 + + Q3Process processUpdate( QString("zip") ); + processUpdate.setWorkingDirectory(tmpDirName); +// processUpdate.addArgument( "-r" ); // recurce into subdirectories +// processUpdate.addArgument( "-0" ); // store only + processUpdate.addArgument( name() ); // cfg name + processUpdate.addArgument("."); + processUpdate.addArgument("-i"); + processUpdate.addArgument(fileName); +#else + Q3Process processUpdate( QString("7z") ); + processUpdate.setWorkingDirectory(tmpDirName); + processUpdate.addArgument( "a" ); + processUpdate.addArgument( "-tzip" ); + processUpdate.addArgument( fileName ); + processUpdate.addArgument( "-r" ); + processUpdate.addArgument("."); +#endif + + if( !processUpdate.start() ) + { + setLastError(tr("Unable to start zip")); + aLog::print(aLog::Error, tr("aContainer zip start error")); + return false; + } + + while( processUpdate.isRunning() ); + + if( !processUpdate.normalExit() ) + { + setLastError(tr("Zip ended with error")); + aLog::print(aLog::Error, tr("aContainer zip dead")); + return false; + } + + if( processUpdate.exitStatus() ) + { + setLastError(tr("Zip ended with code %1").arg(processUpdate.exitStatus())); + return false; + } + + return true; +} + + + + +void +aContainer::setLastError(const QString& errorText) +{ + txtError = errorText; +} + + +QString +aContainer::lastError() const +{ + return txtError; +} + +void +aContainer::cleanupTmpFiles() +{ + QFile file; + QDir dir; + + if(manifest && tmpDirName!="") + { + aCManifest::record rec; + rec = manifest->first(); + while(rec.type!=mf_invalid) + { + if(rec.type!=mf_dir && rec.type!=mf_invalid) + { + file.setName(tmpDirName + QDir::convertSeparators(rec.name)); + if(file.remove()) + aLog::print(aLog::Debug, tr("aContainer delete file %1").arg(rec.name)); + } + rec = manifest->next(); + } + rec = manifest->first(); + while(rec.type!=mf_invalid) + { + if(rec.type==mf_dir) + { + if(dir.rmdir(tmpDirName + QDir::convertSeparators(rec.name) )) + aLog::print(aLog::Debug, tr("aContainer delete directory %1").arg(rec.name)); + } + rec = manifest->next(); + } + } + + + file.setName(QDir::convertSeparators(tmpDirName+"/META-INF/manifest.xml")); + if(file.remove()) aLog::print(aLog::Debug, tr("aContainer delete file %1").arg(file.name())); + if(dir.rmdir(QDir::convertSeparators(tmpDirName))) aLog::print(aLog::Debug, tr("aContainer delete directory %1").arg(tmpDirName + "/META-INF")); + //aLog::print(aLog::Info, tr("aContainer cleanup temporary files")); + +} + diff --git a/src/lib/acontainer.h b/src/lib/acontainer.h new file mode 100644 index 0000000..9ff4a27 --- /dev/null +++ b/src/lib/acontainer.h @@ -0,0 +1,93 @@ +/**************************************************************************** +** $Id: acontainer.h,v 1.1 2008/11/05 21:16:28 leader Exp $ +** +** Data container functions header file of +** Ananas application library +** +** Created : 20031201 +** +** Copyright (C) 2003-2004 Leader InfoTech. All rights reserved. +** Copyright (C) 2003-2006 Grigory Panov, Yoshkar-Ola. +** +** This file is part of the Designer application of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.leaderit.ru/page=ananas or email sales@leaderit.ru +** See http://www.leaderit.ru/gpl/ for GPL licensing information. +** +** Contact org@leaderit.ru if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#ifndef ACONTAINER_H +#define ACONTAINER_H + +#include "qdom.h" +#include "qstringlist.h" +#include "ananas.h" +#include "acmanifest.h" +#include + + +//class aDatabase; + +/** + * \en + * Class for work with data container + * \_en + * \ru + * \brief Класс предназначен для работы с контейнерами данных. + * Наследует QObject. + * + * \_ru + */ +class ANANAS_EXPORT aContainer: public QObject +{ + Q_OBJECT +public: + + aContainer(); + aContainer(const QString& name); + virtual ~aContainer(); + + virtual bool open(); + virtual bool open(const QString &name); + virtual void create(); + virtual void close(); + + virtual bool save(); + virtual bool save(const QString& name); + virtual bool addFile(const QString& filename, const QString &newname, int type); + virtual QString realPath(const QString &fname) const; + + virtual QString lastError() const; + void setLastError(const QString& errorText); + +//signals: + //void progress(int,int); + +protected: + void generateName4TmpDir(); + bool createTmpDir(); + bool extractManifest(const QString& archName, aCManifest *mf); + bool extractData(const QString& archName); + bool compressFile(const QString& fileName); + void cleanupTmpFiles(); + +private: + QString txtError; + aCManifest *manifest; + QString tmpDirName; + +}; + +#endif //ACONTAINER_H diff --git a/src/lib/adataexchange.cpp b/src/lib/adataexchange.cpp new file mode 100644 index 0000000..71c5d17 --- /dev/null +++ b/src/lib/adataexchange.cpp @@ -0,0 +1,631 @@ +/**************************************************************************** +** $Id: adataexchange.cpp,v 1.2 2008/11/08 20:16:35 leader Exp $ +** +** Import/export function implementation file of +** Ananas application +** +** Created : 20060209 +** +** Copyright (C) 2006 Grigory Panov , Yoshkar-Ola. +** +** This file is part of the Library of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.leaderit.ru/page=ananas or email sales@leaderit.ru +** See http://www.leaderit.ru/gpl/ for GPL licensing information. +** +** Contact org@leaderit.ru if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#include "alog.h" +#include "adataexchange.h" +#include "aservice.h" +#include +#include +#include +#include +#include +#include +#include + +//#define ERROR true + +aBackup::aBackup():QObject() +{ +} + + +aBackup::~aBackup() +{ +} + +bool +aBackup::importData(const QString& rcfile, const QString &archfile, bool dropBase, bool replaceTemplates) +{ + + + int prg=0; + int totalSteps=10; + QString tmpDirName; + QString filename = archfile; + + QDir dir; + QString temp; + QStringList templatesName; + +#ifndef _Windows + temp = getenv("TMPDIR"); + if(temp=="" || temp.isEmpty()) + temp = P_tmpdir; +#else + temp = getenv("TEMP"); +#endif + tmpDirName = QString(temp+"/%1").arg(QDateTime::currentDateTime().toTime_t()); + tmpDirName = QDir::convertSeparators(tmpDirName); + //printf("tmp dir name = %s\n",tmpDirName.ascii()); + if(!dir.mkdir(tmpDirName)) + { + setLastError(tr("Can't create temporary directory")); + aLog::print(aLog::Error, "aBackup create temporary directory %1"); + return true; + } + else + { + aLog::print(aLog::Debug, tr("aBackup create temporary directory %1").arg(tmpDirName)); + } + if(unzipArchive(archfile, tmpDirName)==true) + { + cleanupTmpFiles(tmpDirName, &templatesName); + + //printf("unzip error!\n"); + aLog::print(aLog::Error, tr("aBackup import data: unzip")); + return true; + } + else + { + aLog::print(aLog::Debug, tr("aBackup unzip")); + } + + + QString srcDirName = QDir::convertSeparators(tmpDirName + "/templates/"); + dir.setPath(srcDirName); + templatesName = dir.entryList("templ_*.odt;templ_*.ods"); + + + qApp->processEvents(); + emit(progress(++prg,totalSteps)); + + filename.truncate( filename.length() - QString(".bsa").length() ); + aLog::print(aLog::Debug, tr("aBackup filename = %1").arg(filename)); + + //printf("filename = %s\n",filename.ascii()); + changeRC(rcfile, tmpDirName + "/busines-schema.cfg"); + + QFile f(tmpDirName+"/content.xml"); + QDomDocument xml; + xml.setContent(&f); +// printf("%s\n",xml.toString(4).ascii()); + aDatabase db; + if(db.init(rcfile)) + { + emit(progress(++prg,totalSteps)); + if(!dropBase) + { + db.done(); + cleanupTmpFiles(tmpDirName, &templatesName); + return false; + } + db.drop(db.cfg.rc.value("dbname")); + emit(progress(++prg,totalSteps)); + db.create(); + + emit(progress(++prg,totalSteps)); + + db.exchangeDataSystables ( xml, true); + emit(progress(++prg,totalSteps)); + db.exchangeDataCatalogues( xml, true ); + emit(progress(++prg,totalSteps)); + db.exchangeDataDocuments ( xml, true ); + emit(progress(++prg,totalSteps)); + db.exchangeDataJournals ( xml, true ); + db.exchangeDataInfoRegisters ( xml, true ); + emit(progress(++prg,totalSteps)); + db.exchangeDataAccumulationRegisters ( xml, true ); + emit(progress(++prg,totalSteps)); + db.exchangeDataUniques ( xml, true ); + } + else + { + setLastError(tr("Can't connect to database")); + cleanupTmpFiles(tmpDirName, &templatesName); + return true; + } + qApp->processEvents(); + + QString destDirName = QDir::convertSeparators(db.cfg.rc.value("workdir")); + + //create template directory + QDir destDir; +// destDir.setPath(destDirName); + if(!destDir.exists(destDirName)) + { + aLog::print(aLog::Debug, tr("aBackup template dir `%1' not exists, try create").arg(destDirName)); + if(!destDir.mkdir(destDirName,true)) + { + aLog::print(aLog::Error, tr("aBackup create template dir `%1' fail").arg(destDirName)); + } + else + { + aLog::print(aLog::Debug, tr("aBackup create template dir `%1'").arg(destDirName)); + } + } + else + { + aLog::print(aLog::Debug, tr("aBackup template dir `%1' exists").arg(destDirName)); + } + + for(uint i=0; iprocessEvents(); + + if(withTemplates) + { + srcDirName = QDir::convertSeparators(cfg.rc.value("workdir")); + aLog::print(aLog::Debug, tr("aBackup workdir=%1").arg(srcDirName)); + dir.setPath(srcDirName); + templatesName = dir.entryList("templ_*.odt;templ_*.ods"); + for(uint i=0; iprocessEvents(); + emit(progress(++prg,totalSteps)); + // create dump + if(dumpBase(rcfile,tmpDirName, prg, totalSteps )==true) + { + cleanupTmpFiles(tmpDirName, &templatesName); + aLog::print(aLog::Error, tr("aBackup dump base error")); + return true; + } + else + { + aLog::print(aLog::Debug, tr("aBackup bump base")); + } + + if(writeXml(QDir::convertSeparators(tmpDirName+"/META-INF/manifest.xml"), createManifest(templatesName))==true) + { + setLastError(tr("Can't write file META-INF/manifest.xml")); + aLog::print(aLog::Error, tr("aBackup write manifest.xml")); + cleanupTmpFiles(tmpDirName, &templatesName); + return true; + } + else + { + aLog::print(aLog::Debug, tr("aBackup write manifest.xml")); + } +// printf("%s\n",(createManifest(templatesName)).toString().ascii()); + if(withTemplates) + { + QString destNamePref = tmpDirName + "/templates"; + dir.mkdir(destNamePref); + bool res = false; + for(uint i=0; i")); + QDomElement root = xml.createElement( "AnanasDump" ); + xml.appendChild( root ); + aDatabase db; + if(db.init(rcfile)) + { + emit (progress(++prg,totalSteps)); + db.exchangeDataSystables ( xml, false ); + emit (progress(++prg,totalSteps)); + db.exchangeDataCatalogues( xml, false ); + emit (progress(++prg,totalSteps)); + db.exchangeDataDocuments ( xml, false ); + emit (progress(++prg,totalSteps)); + db.exchangeDataJournals ( xml, false ); + emit (progress(++prg,totalSteps)); + db.exchangeDataInfoRegisters ( xml, false ); + emit (progress(++prg,totalSteps)); + db.exchangeDataAccumulationRegisters ( xml, false ); + + db.exchangeDataUniques ( xml, true ); + + aLog::print(aLog::Debug, tr("aBackup dump tables ok")); + } + else + { + setLastError(tr("Can't connect to database")); + aLog::print(aLog::Error, tr("aBackup init rc file %1").arg(rcfile)); + db.done(); + return true; + } + qApp->processEvents(); + emit (progress(++prg,totalSteps)); + db.done(); + if(writeXml(tmpDirName+"/content.xml",xml)==true) + { + setLastError(tr("Can't write content.xml")); + aLog::print(aLog::Error, tr("aBackup write content.xml")); + return true; + } + else + { + aLog::print(aLog::Info, tr("aBackup dump base to xml compleet")); + } + return false; +} + +bool +aBackup::writeXml(const QString & name2Save, QDomDocument xml) +{ + QFile file(name2Save); + QByteArray buf( xml.toString(4).utf8() ); + if ( file.open( QIODevice::WriteOnly ) ) + { + QTextStream ts( &file ); + //--ts.setEncoding(Q3TextStream::UnicodeUTF8); + xml.save(ts, 4); + file.close(); + } + else + { + aLog::print(aLog::Error, tr("aBackup save xml %1").arg(name2Save)); + return true; + } + return false; +} + +bool +aBackup::checkStructure() +{ + return false; +} + +QDomDocument +aBackup::createManifest(const QStringList& templates) +{ + QDomDocument manifest; + manifest.setContent(QString("")); + + QDomElement root = manifest.createElement("manifest:manifest"); + manifest.appendChild(root); + + QDomElement entry = manifest.createElement("manifest:file-entry"); + entry.setAttribute("manifest:full-path","business-schema.cfg"); + root.appendChild(entry); + + entry = manifest.createElement("manifest:file-entry"); + entry.setAttribute("manifest:full-path","content.xml"); + root.appendChild(entry); + if(templates.count()>0) + { + QDomElement templatesDir = manifest.createElement("manifest:file-entry"); + templatesDir.setAttribute("manifest:full-path","templates/"); + + for(uint i=0; i cfg; +// QString configFileName; + + cfg = aTests::readConfig(QDir::convertSeparators(nameRC)); + +// configFileName = cfg["configfile"]; +// configFileName.truncate( configFileName.length() - QString(".bsa").length() ); +// cfg["configfile"] = configFileName + ".cfg"; + + cfg["configfile"] = newConfigName; + + aTests::writeConfig(QDir::convertSeparators(nameRC), cfg); +} + + +void +aBackup::setLastError(const QString& errorText) +{ + txtError = errorText; +} + + +QString +aBackup::lastError() const +{ + return txtError; +} + +void +aBackup::cleanupTmpFiles(const QString& tmpDirName, QStringList *files) +{ + QFile file; + QDir dir; + file.setName(QDir::convertSeparators(tmpDirName+"/content.xml")); + aLog::print(aLog::Debug, tr("aBackup delete file %1").arg(file.name())); + file.remove(); + file.setName(QDir::convertSeparators(tmpDirName+"/busines-schema.cfg")); + aLog::print(aLog::Debug, tr("aBackup delete file %1").arg(file.name())); + file.remove(); + file.setName(QDir::convertSeparators(tmpDirName+"/META-INF/manifest.xml")); + aLog::print(aLog::Debug, tr("aBackup delete file %1").arg(file.name())); + file.remove(); + for(uint i=0; icount(); i++) + { + file.setName(QDir::convertSeparators(tmpDirName + "/templates/"+ (*files)[i])); + aLog::print(aLog::Debug, tr("aBackup delete file %1").arg(file.name())); + file.remove(); + } + aLog::print(aLog::Debug, tr("aBackup delete directory %1").arg(tmpDirName + "/META-INF")); + dir.rmdir(QDir::convertSeparators(tmpDirName + "/META-INF")); + aLog::print(aLog::Debug, tr("aBackup delete directory %1").arg(tmpDirName + "/templates")); + dir.rmdir(QDir::convertSeparators(tmpDirName + "/templates")); + aLog::print(aLog::Debug, tr("aBackup delete directory %1").arg(tmpDirName)); + dir.rmdir(QDir::convertSeparators(tmpDirName)); + aLog::print(aLog::Info, tr("aBackup cleanup temporary files")); + +} + diff --git a/src/lib/adataexchange.h b/src/lib/adataexchange.h new file mode 100644 index 0000000..b832704 --- /dev/null +++ b/src/lib/adataexchange.h @@ -0,0 +1,84 @@ +/**************************************************************************** +** $Id: adataexchange.h,v 1.1 2008/11/05 21:16:28 leader Exp $ +** +** Import/export data function header file of +** Ananas application library +** +** Created : 20031201 +** +** Copyright (C) 2003-2004 Leader InfoTech. All rights reserved. +** Copyright (C) 2003-2006 Grigory Panov, Yoshkar-Ola. +** +** This file is part of the Designer application of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.leaderit.ru/page=ananas or email sales@leaderit.ru +** See http://www.leaderit.ru/gpl/ for GPL licensing information. +** +** Contact org@leaderit.ru if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#ifndef ADATEXCHANGE_H +#define ADATEXCHANGE_H + +#include "qdom.h" +#include "qstringlist.h" +#include "ananas.h" +#include + + +class aDatabase; + +/** + * \en + * Class for work make backup and restore databases + * \_en + * \ru + * \brief Класс aBackup определяет программный интерфейс для бэкапа и востановления базы данных. + * Наследует QObject. + * + * \_ru + */ +class ANANAS_EXPORT aBackup: public QObject +{ + Q_OBJECT +public: + + aBackup(); + virtual ~aBackup(); + + virtual bool importData(const QString& rcfile, const QString &archfile, bool dropDB, bool replaceTemplates=0); + virtual bool exportData(const QString& rcfile, const QString &archfile, bool withTemplates=0 ); + virtual QString lastError() const; + +signals: + void progress(int,int); + +protected: + virtual void setLastError(const QString & errorText); + virtual bool unzipArchive(const QString& archName, const QString& tmpDirName); + virtual bool zipArchive(const QString& archName, const QString& tmpDirName); + virtual bool checkStructure(); + virtual QDomDocument createManifest(const QStringList& templates); + virtual void changeRC(const QString& nameRC, const QString& newConfigName); + virtual bool dumpBase(const QString& rcfile, const QString& tmpDirName, int &progress, int totalSteps); + virtual bool writeXml(const QString & fileName, QDomDocument xml); + void cleanupTmpFiles(const QString& tmpDirName, QStringList *files); + +private: + QString txtError; +// QString tmpDirName; + +}; + +#endif //ADATEXCHANGE_H diff --git a/src/lib/adatafield.cpp b/src/lib/adatafield.cpp new file mode 100644 index 0000000..de9e744 --- /dev/null +++ b/src/lib/adatafield.cpp @@ -0,0 +1,213 @@ +/**************************************************************************** +** $Id: adatafield.cpp,v 1.1 2008/11/05 21:16:28 leader Exp $ +** +** Code file of the Ananas database field of Ananas +** Designer and Engine applications +** +** Created : 20031201 +** +** Copyright (C) 2003-2004 Leader InfoTech. All rights reserved. +** +** This file is part of the Library of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.leaderit.ru/page=ananas or email sales@leaderit.ru +** See http://www.leaderit.ru/gpl/ for GPL licensing information. +** +** Contact org@leaderit.ru if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +//#include +//#include "acfg.h" +#include "adatafield.h" + +/*! +Create Ananas database field contaner. +*/ +/* +aDataField::aDataField(aCfg *newmd, aCfgItem newcontext ) +:QObject( 0, "aField" ) // name ) +{ + md = newmd; + context = newcontext; +// fType = type; + fTName = ""; +// field = new QSqlField( fTName ); + fSys = false; +} +*/ + +/*! + * Create Ananas field contaner. + */ +aDataField::aDataField( QObject *parent, const QString &name, const QString &type ) +:QObject( parent, "aField" ) +{ + init( name, type ); +} + + +/*! + * Create Ananas field contaner. + */ +aDataField::aDataField(const QString &name, const QString &type ) +:QObject( 0, "aField" ) +{ + init( name, type ); +} + + +aDataField::aDataField( const aDataField &field ) +:QObject( 0, "aField" ) +{ + init( field.fieldName(), field.fType ); +} + +/*! + * Destroy object. + */ + +aDataField::~aDataField() +{ +// delete field; +} + +aDataField& +aDataField::operator=( const aDataField& other ) +{ + Type = other.Type; + context = other.context; + id = other.id;; + md = other.md; + fSys = other.fSys; + Width = other.Width; + Dec = other.Dec; + Name = other.Name; + fType = other.fType; + aType = other.aType; + fieldData = other.fieldData; + return *this; +} + +bool +aDataField::operator==( const aDataField& other ) const +{ + return ( + fSys == other.fSys && + Name == other.Name && + fType == other.fType && + id == other.id && + context == other.context + ); +} + + +bool +aDataField::operator!=( const aDataField& other ) const +{ + return !( other == *this ); +} + +void +aDataField::init( const QString &name, const QString &type ) +{ + QString t; + + fSys = true; + Name = name; + fType = type; + Type = QVariant::Invalid; + if ( !type.isNull() ) { + aType = ( (const char *) type.section(" ",0,0).upper() )[0]; + Width = type.section(" ",1,1).toInt(); + Dec = type.section(" ",2,2).toInt(); + switch ( aType ){ + case 'C': + Type = QVariant::String; + fieldData = QString(""); + break; + case 'N': + Type = QVariant::Double; + fieldData = ( double ) 0.0; + default: + Type = QVariant::Invalid; + } + } +} + +/*! +Return pointer to asociated sql field. +*/ +//QSqlField * +//aField::sqlField(){ +// return field; +//} + + +/*! + * + */ +QVariant +aDataField::internalValue() +{ + return fieldData; +} + + +/*! + * + */ +void +aDataField::setInternalValue( const QVariant &value) +{ + fieldData = value; +} + + + +/*! + * Возвращает значение поля данных. + */ +QVariant +aDataField::value() +{ + return fieldData; +} + + +/*! + * Устанавливает значение поля данных. + */ +void +aDataField::setValue( const QVariant &value) +{ + fieldData = value; +} + + + +/*! + * + */ +int +aDataField::ObjectType() +{ + return oType; +} + + +QString +aDataField::fieldName() const +{ + return Name; +} diff --git a/src/lib/adatafield.h b/src/lib/adatafield.h new file mode 100644 index 0000000..c6b6d23 --- /dev/null +++ b/src/lib/adatafield.h @@ -0,0 +1,106 @@ +/**************************************************************************** +** $Id: adatafield.h,v 1.1 2008/11/05 21:16:28 leader Exp $ +** +** Header file of the Ananas data field of Ananas +** Designer and Engine applications +** +** Created : 20031201 +** +** Copyright (C) 2003-2004 Leader InfoTech. All rights reserved. +** +** This file is part of the Library of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.leaderit.ru/page=ananas or email sales@leaderit.ru +** See http://www.leaderit.ru/gpl/ for GPL licensing information. +** +** Contact org@leaderit.ru if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#ifndef ADATAFIELD_H +#define ADATAFIELD_H +//#include + +#include +#include +#include "ananasglobal.h" +#include "acfg.h" + + +//class aCfg; +//class aCfgItem; +//class QObject; +//#define + +/*! + * \en + * aDataField object unite all ananas types for access them from + * Ananas Script. + * Object translate calls from script to special type object + * with check correct call functions and parameters. + * \_en + * \ru + * \brief Класс определяет программный интерфейс для доступа к полям бизнес объектов Ананаса. + * Наследует QObject. + * + * Позволяет получить и задать значение поля любого типа. Предназначен для использования из Ананас-скрипта. + * \_ru + */ + +class ANANAS_EXPORT aDataField : public QObject +{ + Q_OBJECT +// Q_PROPERTY( Priority priority READ priority WRITE setPriority ) +// Q_ENUMS( Priority ) +// Q_CLASSINFO( "Author", "Oscar Peterson") +public: +// enum fieldType ( Unknown, Numberic, Character, Date, Object ); + aCfgItem context; + long id; + aCfg *md; + bool fSys; + int Width, Dec; + QString Name, fType; + char aType; + QVariant::Type Type; +// QVariant field; + int oType; + + +// aField( aCfg *newmd, aCfgItem newcontext ); + aDataField( QObject *parent, const QString &fname = QString::null, const QString &ftype = QString::null ); + aDataField( const QString &fname = QString::null, const QString &ftype = QString::null ); + aDataField( const aDataField &field ); + ~aDataField(); + + aDataField& operator=( const aDataField& other ); + bool operator==( const aDataField& other ) const; + bool operator!=( const aDataField& other ) const; +// aDataField& operator[]( const int& i ){}; + +// QSqlField *sqlField(); + virtual QVariant internalValue(); + virtual void setInternalValue( const QVariant &value); +public slots: + virtual QString fieldName() const; + virtual int ObjectType(); + virtual QVariant value(); + virtual void setValue( const QVariant &value); +private: + QVariant fieldData; + + void init( const QString &fname = QString::null, const QString &ftype = QString::null ); +}; + + +#endif diff --git a/src/lib/aextension.cpp b/src/lib/aextension.cpp new file mode 100644 index 0000000..2bf1234 --- /dev/null +++ b/src/lib/aextension.cpp @@ -0,0 +1,50 @@ +/**************************************************************************** +** $Id: aextension.cpp,v 1.1 2008/11/05 21:16:28 leader Exp $ +** +** Extension object implementation file of +** Ananas application library +** +** Created : 20031201 +** +** Copyright (C) 2003-2006 Leader InfoTech. All rights reserved. +** Copyright (C) 2003-2006 Valery Grazdankin, Orenburg. +** Copyright (C) 2003-2005 Grigory Panov, Yoshkar-Ola. +** +** This file is part of the Designer application of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.leaderit.ru/page=ananas or email sales@leaderit.ru +** See http://www.leaderit.ru/gpl/ for GPL licensing information. +** +** Contact org@leaderit.ru if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#include "aextension.h" + +AExtension::AExtension( const char *name ) + : QObject( 0, name ) +{ + if (name==0) setName( className() ); +} + + + +AExtension::~AExtension() +{ +} + + +int AExtension::init(aDatabase* dbo){ + db = dbo; + return 0; +} diff --git a/src/lib/aextension.h b/src/lib/aextension.h new file mode 100644 index 0000000..70a05b6 --- /dev/null +++ b/src/lib/aextension.h @@ -0,0 +1,61 @@ +/**************************************************************************** +** $Id: aextension.h,v 1.1 2008/11/05 21:16:28 leader Exp $ +** +** Extension object header file of +** Ananas application library +** +** Created : 20031201 +** +** Copyright (C) 2003-2004 Leader InfoTech. All rights reserved. +** Copyright (C) 2003-2005 Grigory Panov, Yoshkar-Ola. +** +** This file is part of the Designer application of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.leaderit.ru/page=ananas or email sales@leaderit.ru +** See http://www.leaderit.ru/gpl/ for GPL licensing information. +** +** Contact org@leaderit.ru if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#ifndef AEXTENSION_H +#define AEXTENSION_H + +#include "ananasglobal.h" +#include "adatabase.h" +#include + +/** + * \en + * Class for work with extensions + * \_en + * \ru + * \_ru + */ +class ANANAS_EXPORT AExtension : public QObject +{ + Q_OBJECT + +public: + aDatabase* db; + + AExtension( const char *name = 0 ); + ~AExtension(); + int init(aDatabase* dbo); + +signals: + void event( const QString &data ); + +}; + +#endif //AEXTENSION_H diff --git a/src/lib/aextensionfactory.cpp b/src/lib/aextensionfactory.cpp new file mode 100644 index 0000000..e19b803 --- /dev/null +++ b/src/lib/aextensionfactory.cpp @@ -0,0 +1,136 @@ +/**************************************************************************** +** $Id: aextensionfactory.cpp,v 1.1 2008/11/05 21:16:28 leader Exp $ +** +** ... +** +** Created : 20060209 +** +** Copyright (C) 2003-2006 Leader InfoTech. All rights reserved. +** +** This file is part of the Library of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.leaderit.ru/page=ananas or email sales@leaderit.ru +** See http://www.leaderit.ru/gpl/ for GPL licensing information. +** +** Contact org@leaderit.ru if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#include "aextensionfactory.h" +#include +#include +#include +#include +#include +#include +#include +#include + +class AExtensionFactoryPrivate : public QObject +{ +public: + AExtensionFactoryPrivate(); + ~AExtensionFactoryPrivate(); + + QHash hash; + QStringList extensionKeys; +}; + +static AExtensionFactoryPrivate *instance = 0; + +AExtensionFactoryPrivate::AExtensionFactoryPrivate() +: QObject( qApp ) +{ + QString extensionsDirName; + AExtensionInterface *iface = 0; + QObject *plugin = 0; + QPluginLoader pluginLoader; + +#ifdef Q_OS_WIN32 + extensionsDirName = qApp->applicationDirPath()+"/extensions"; +#else + extensionsDirName = "/usr/share/ananas4/extensions"; +#endif + + hash.clear(); + extensionKeys.clear(); + QDir extensionsDirectory( extensionsDirName ); + QStringList extensionFiles = extensionsDirectory.entryList( QDir::Files ); + QString fileName = extensionFiles.first(); + for (int i=0; i(plugin); + if( iface ) { + extensionKeys.append( iface->key()); + hash[ iface->key()] = iface; + } + } + } +} + +AExtensionFactoryPrivate::~AExtensionFactoryPrivate() +{ +// delete instance; +// instance = 0; +} + +/*! + Creates a AExtension object that matches \a key. This is either a + built-in extensions, or a extension from a extension plugin. + + \sa keys() +*/ +AExtension *AExtensionFactory::create( const QString& key ) +{ + AExtension *ret = 0; + AExtensionInterface *iface = 0; +// QString extension = key; + + if ( !instance ) instance = new AExtensionFactoryPrivate(); + if ( instance->hash.contains( key ) ){ + iface = instance->hash.value( key ); + if ( iface ) ret = iface->create(); + } + if (ret) ret->setName(key); + return ret; +} + + + +QMetaObject *AExtensionFactory::metaObject( const QString &key ) +{ + QMetaObject *ret = 0; + AExtensionInterface *iface = 0; + + if ( !instance ) instance = new AExtensionFactoryPrivate(); + if ( instance->hash.contains( key ) ){ + iface = instance->hash.value( key ); + if ( iface ) ret = iface->metaObject(); + } + return ret; +}; + +/*! + Returns the list of keys this factory can create styles for. + + \sa create() +*/ +QStringList AExtensionFactory::keys() +{ + if ( !instance ) instance = new AExtensionFactoryPrivate(); + return instance->extensionKeys; +} + diff --git a/src/lib/aextensionfactory.h b/src/lib/aextensionfactory.h new file mode 100644 index 0000000..1c742bd --- /dev/null +++ b/src/lib/aextensionfactory.h @@ -0,0 +1,64 @@ +/**************************************************************************** +** $Id: aextensionfactory.h,v 1.1 2008/11/05 21:16:28 leader Exp $ +** +** ... +** +** Created : 20060209 +** +** Copyright (C) 2003-2006 Leader InfoTech. All rights reserved. +** +** This file is part of the Library of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.leaderit.ru/page=ananas or email sales@leaderit.ru +** See http://www.leaderit.ru/gpl/ for GPL licensing information. +** +** Contact org@leaderit.ru if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#ifndef AEXTENSIONFACTORY_H +#define AEXTENSIONFACTORY_H + +#include "QString" +#include "QStringList" +#include "aextension.h" + +/*! + * \en + * \brief The AExtensionFactory class creates AExtension objects. + * + * The style factory creates a AExtension object for a given key with + * AExtensionFactory::create(key). + * + * The styles are either built-in or dynamically loaded from a style + * plugin (see \l AExtensionPlugin). + * + * AExtensionFactory::keys() returns a list of valid keys, typically + * including "XXXX". + * \_en + * \ru + * \brief Опеределяет интерфейс для создания объектов класса AExtension + * + * + * \_ru + */ + +class AExtensionFactory +{ +public: + static QStringList keys(); + static AExtension *create( const QString &key ); + static QMetaObject *metaObject( const QString &key ); +}; + +#endif //AEXTENSIONFACTORY_H diff --git a/src/lib/aextensioninterface_p.h b/src/lib/aextensioninterface_p.h new file mode 100644 index 0000000..1842fe0 --- /dev/null +++ b/src/lib/aextensioninterface_p.h @@ -0,0 +1,52 @@ +/**************************************************************************** +** $Id: aextensioninterface_p.h,v 1.1 2008/11/05 21:16:28 leader Exp $ +** +** Definition of AExtensionInterface class +** +** Created : 20060209 +** +** Copyright (C) 2003-2006 Leader InfoTech. All rights reserved. +** +** This file is part of the Library of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.leaderit.ru/page=ananas or email sales@leaderit.ru +** See http://www.leaderit.ru/gpl/ for GPL licensing information. +** +** Contact org@leaderit.ru if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#ifndef AEXTENSIONINTERFACE_H +#define AEXTENSIONINTERFACE_H + +#include +#ifndef QT_H +#include +#endif // QT_H + +#ifndef QT_NO_COMPONENT + +// {EDDD5AD8-DF3C-400c-A711-163B72FE5F61} +#ifndef IID_AExtensionFactory +#define IID_AExtensionFactory QUuid(0xeddd5ad8, 0xdf3c, 0x400c, 0xa7, 0x11, 0x16, 0x3b, 0x72, 0xfe, 0x5f, 0x61) +#endif + +class AExtension; + +struct ANANAS_EXPORT AExtensionFactoryInterface : public QFeatureListInterface +{ + virtual AExtension* create( const QString& name ) = 0; +}; + +#endif //QT_NO_COMPONENT +#endif // AEXTENSIONINTERFACE_P_H diff --git a/src/lib/aextensionplugin.cpp b/src/lib/aextensionplugin.cpp new file mode 100644 index 0000000..f204511 --- /dev/null +++ b/src/lib/aextensionplugin.cpp @@ -0,0 +1,126 @@ +/**************************************************************************** +** $Id: aextensionplugin.cpp,v 1.1 2008/11/05 21:16:28 leader Exp $ +** +** Extension plugin class implementation file of +** +** Created : 20060209 +** +** Copyright (C) 2003-2006 Leader InfoTech. All rights reserved. +** +** This file is part of the Library of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.leaderit.ru/page=ananas or email sales@leaderit.ru +** See http://www.leaderit.ru/gpl/ for GPL licensing information. +** +** Contact org@leaderit.ru if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#include "aextensionplugin.h" + +//#ifndef QT_NO_COMPONENT + +//#include "aextensioninterface_p.h" + +/*! + \fn QStringList AExtensionPlugin::keys() const + + Returns the list of extensions (keys) this plugin supports. + + These keys are usually the class names of the custom extension that + are implemented in the plugin. + + \sa create() +*/ + +/*! + \fn AExtension* AExtensionPlugin::create( const QString& key ) + + Creates and returns a AExtension object for the driver key \a key. + The driver key is usually the class name of the required driver. + + \sa keys() +*/ +/* +class AExtensionPluginPrivate : public AExtensionFactoryInterface +{ +public: + AExtensionPluginPrivate( AExtensionPluginBase *p ) + : plugin( p ) + { + } + virtual ~AExtensionPluginPrivate(); + + QRESULT queryInterface( const QUuid &iid, QUnknownInterface **iface ); + Q_REFCOUNT; + + QStringList featureList() const; + AExtension *create( const QString &key ); + +private: + AExtensionPluginBase *plugin; +}; + +AExtensionPluginPrivate::~AExtensionPluginPrivate() +{ + delete plugin; +} + +QRESULT AExtensionPluginPrivate::queryInterface( const QUuid &iid, QUnknownInterface **iface ) +{ + *iface = 0; + + if ( iid == IID_QUnknown ) + *iface = this; + else if ( iid == IID_QFeatureList ) + *iface = this; + else if ( iid == IID_AExtensionFactory ) + *iface = this; + else + return QE_NOINTERFACE; + + (*iface)->addRef(); + return QS_OK; +} + +QStringList AExtensionPluginPrivate::featureList() const +{ + return plugin->keys(); +} + +AExtension *AExtensionPluginPrivate::create( const QString &key ) +{ + return plugin->create( key ); +} +*/ +/*! + Constructs a Ananas extension plugin. This is invoked automatically by + the \c Q_EXPORT_PLUGIN macro. +*/ + +AExtensionPluginBase::AExtensionPluginBase() + :QObject()// QGPlugin( d = new AExtensionPluginPrivate( this ) ) +{ +} + +/*! + Destroys the Ananas extension plugin. + + You never have to call this explicitly. Qt destroys a plugin + automatically when it is no longer used. +*/ +AExtensionPluginBase::~AExtensionPluginBase() +{ + // don't delete d, as this is deleted by d +} + diff --git a/src/lib/aextensionplugin.h b/src/lib/aextensionplugin.h new file mode 100644 index 0000000..a7dcd04 --- /dev/null +++ b/src/lib/aextensionplugin.h @@ -0,0 +1,139 @@ +/**************************************************************************** +** $Id: aextensionplugin.h,v 1.1 2008/11/05 21:16:28 leader Exp $ +** +** Extension plugin object header file of +** Ananas application library +** +** Created : 20031201 +** +** Copyright (C) 2003-2004 Leader InfoTech. All rights reserved. +** Copyright (C) 2003-2005 Grigory Panov, Yoshkar-Ola. +** +** This file is part of the Designer application of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.leaderit.ru/page=ananas or email sales@leaderit.ru +** See http://www.leaderit.ru/gpl/ for GPL licensing information. +** +** Contact org@leaderit.ru if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#ifndef AEXTENSIONPLUGIN_H +#define AEXTENSIONPLUGIN_H + +#include +//#ifndef QT_H +//#include "qgplugin.h" +//#include "qstringlist.h" +//#endif // QT_H + +#include "ananasglobal.h" +#include +#include + +class AExtension; +//class AExtensionPluginPrivate; + +//#define A_EXPORT_PLUGIN(pluginobjectname) typedef AExtensionPlugin pluginobjectname##Plugin; Q_EXPORT_PLUGIN(pluginobjectname) +#define A_EXPORT_PLUGIN(pluginobjectname) Q_EXPORT_PLUGIN2(pluginobjectname,pluginobjectname) + +class AExtensionInterface +{ +public: + virtual ~AExtensionInterface(){}; + virtual QString key() const = 0; + virtual AExtension *create() = 0; + virtual QMetaObject *metaObject() = 0; +}; + +Q_DECLARE_INTERFACE(AExtensionInterface,"Ananas.Extensions.AExtensionInterface/1.0") + + +/*! + * \en + * \brief Class for work with extensions + * \_en + * \ru + * \brief Базовый класс в иерархии классов для работы с расширениями. Наследует QGPlugin. + * \_ru + */ +class ANANAS_EXPORT AExtensionPluginBase : public QObject, public AExtensionInterface +{ + Q_OBJECT + Q_INTERFACES(AExtensionInterface) +public: + + AExtensionPluginBase(); + ~AExtensionPluginBase(); + virtual QString key() const = 0; + virtual AExtension *create() = 0; + virtual QMetaObject *metaObject() = 0; + +//private: +// AExtensionPluginPrivate *d; +}; + +/*! + * \en + * \brief The AExtensionPlugin class provides an abstract base for custom AExtension plugins. + * + * \ingroup plugins + * \mainclass + * + * The Ananas Extension plugin is a simple plugin interface that makes it + * easy to create your own Ananas extension plugins that can be loaded + * dynamically by Ananas and Qt. + * + * Writing a Ananas extension plugin is achieved by subclassing this base class, + * reimplementing the pure virtual functions keys() and create(), and + * exporting the class with the \c Q_EXPORT_PLUGIN macro. See the + * Ananas extensions plugins that come with Ananas for example + * implementations (in the + * \c{extensions} subdirectory of the source + * distribution). Read the \link plugins-howto.html plugins + * documentation\endlink for more information on plugins. + * \_en + * \ru + * \brief Базовый класс для создания собственных расширений. Наследует AExtensionPluginBase + * \_ru + */ +template +class ANANAS_EXPORT AExtensionPlugin : public AExtensionPluginBase +{ +// Q_OBJECT +public: + + AExtensionPlugin() + { + type o; + extName = o.name(); + }; + ~AExtensionPlugin(){}; + QString key() const + { + return extName; + }; + AExtension *create() + { + return new type(); + }; + QMetaObject *metaObject() + { + return (QMetaObject *) &type::staticMetaObject; + }; + +private: + QString extName; +}; + +#endif //AEXTENSIONPLUGIN_H diff --git a/src/lib/afilter.cpp b/src/lib/afilter.cpp new file mode 100644 index 0000000..5744712 --- /dev/null +++ b/src/lib/afilter.cpp @@ -0,0 +1,219 @@ +/**************************************************************************** +** $Id: afilter.cpp,v 1.1 2008/11/05 21:16:28 leader Exp $ +** +** Filter implementation file of +** Ananas application library +** +** Created : 20070315 +** +** Copyright (C) 2007 Ananas Project. +** Copyright (C) 2007 Grigory Panov , Moscow +** +** This file is part of the Library of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.leaderit.ru/page=ananas or email sales@leaderit.ru +** See http://www.leaderit.ru/gpl/ for GPL licensing information. +** +** Contact org@leaderit.ru if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#include "afilter.h" +#include +//Added by qt3to4: +#include + +/*! + * \~english + * Constructor + * \~russian + * Конструктор. + * \~ + */ +aFilter::aFilter() +{ +} + +/*! + * \~english + * Destructor + * \~russian + * Деструктор. + * \~ + */ +aFilter::~aFilter() +{ +} + +/*! + * \~english + * Dump filter conditions to stdout + * \~russian + * Выводит содержимое фильтра на stdout. + * \~ + */ +void +aFilter::Dump() const +{ + printf("%s\n", toString().ascii()); +} + +/*! + * \~english + * Converts filter into its sql retpesentation. \a removeFirst give you ability to remove first AND or OR operator + * \~russian + * Переводит фильтр в его sql представление. Параметр \a removeFirst отвечает за удаление ведущего оператора AND или OR + * \~ + */ +QString +aFilter::toString(bool removeFirst) const +{ + QString str = QString::null; + Q3ValueList::const_iterator it; + for ( it = conditions.begin(); it != conditions.end(); ++it ) + { + filterCondition flt = (*it); + if(it != conditions.begin() && removeFirst) + { + str+= flt.AndOr + " "; + } + str+= flt.fname + " "; + str+= flt.operation + " "; + str+= flt.value + " "; + } + return str; +} + + +void +aFilter::Add(const QString& fname, const Q_INT64 value, OperationEnum op, bool AndOp, bool replace) +{ + AddHelper(fname, QString::number(value), op, AndOp, replace); +} +void +aFilter::Add(const QString& fname, const int value, OperationEnum op, bool AndOp, bool replace) +{ + AddHelper(fname, QString::number(value), op, AndOp, replace); +} +void +aFilter::Add(const QString& fname, const double value, OperationEnum op, bool AndOp, bool replace) +{ + AddHelper(fname, QString::number(value), op, AndOp, replace); +} +/* +void +aFilter::Add(const QString& fname, bool value, OperationEnum op, bool AndOp, bool replace) +{ + AddHelper(fname, value?"true":"false", op, AndOp, replace); +} +*/ +void +aFilter::Add(const QString& fname, const QString& value, OperationEnum op, bool AndOp, bool replace) +{ + // need escape string + AddHelper(fname, Escape(value), op, AndOp, replace); +} + +void +aFilter::Add(const QString& fname, const char* value, OperationEnum op, bool AndOp, bool replace) +{ + // need escape string + AddHelper(fname, Escape(QString(value)), op, AndOp, replace); +} + +void +aFilter::Add(const QString& fname, const QDateTime& value, OperationEnum op, bool AndOp, bool replace) +{ + AddHelper(fname, Escape(value.toString(Qt::ISODate)), op, AndOp, replace); +} + +void +aFilter::Add(const QString& fname, const QDate& value, OperationEnum op, bool AndOp, bool replace) +{ + AddHelper(fname, Escape(value.toString(Qt::ISODate)), op, AndOp, replace); +} + + +QString +aFilter::Escape(const QString& val) +{ + QString res = val; + res.replace("\"","\"\""); + res.replace("'","''"); + res.insert(0,"\""); + res.append("\""); + //printf("%s\n",res.ascii()); + return res; +} + +void +aFilter::AddHelper(const QString& fname, const QString& value, OperationEnum op, bool AndOp, bool replace) +{ + filterCondition flt; + flt.AndOr = AndOp?"AND":"OR"; + flt.fname = fname; + flt.value = value; + switch(op) + { + case OperationEnumEquals: + flt.operation = "="; + break; + case OperationEnumNotEquals: + flt.operation = "<>"; + break; + case OperationEnumGreaterThen: + flt.operation = ">"; + break; + case OperationEnumLessThen: + flt.operation = "<"; + break; + case OperationEnumGreaterOrEquals: + flt.operation = ">="; + break; + case OperationEnumLessOrEquals: + flt.operation = "<="; + break; + case OperationEnumLike: + flt.operation = "like"; + break; + default: + printf("boo! operation not exists!"); + break; + + } + if(replace) // replace all entries, append to end list of conditions, if nothing found + { + Q3ValueList::iterator it; + bool isFound = false; + for ( it = conditions.begin(); it != conditions.end(); ++it ) + { + if((*it).fname == fname) + { + (*it) = flt; + isFound = true; + } + } + if(!isFound) conditions.append(flt); + } + else + { + conditions.append(flt); + } + +} + +void +aFilter::Clear() +{ + conditions.clear(); +} diff --git a/src/lib/afilter.h b/src/lib/afilter.h new file mode 100644 index 0000000..7d24a89 --- /dev/null +++ b/src/lib/afilter.h @@ -0,0 +1,81 @@ +/**************************************************************************** +** $Id: afilter.h,v 1.1 2008/11/05 21:16:28 leader Exp $ +** +** Filter declaration file of +** Ananas application library +** +** Created : 20070315 +** +** Copyright (C) 2007 Ananas Project. +** Copyright (C) 2007 Grigory Panov , Moscow +** +** This file is part of the Library of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.leaderit.ru/page=ananas or email sales@leaderit.ru +** See http://www.leaderit.ru/gpl/ for GPL licensing information. +** +** Contact org@leaderit.ru if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#ifndef afilter_h +#define afilter_h + +#include +#include +#include +#include "ananasglobal.h" + +ANANAS_EXPORT enum OperationEnum{ + OperationEnumEquals, + OperationEnumNotEquals, + OperationEnumGreaterThen, + OperationEnumLessThen, + OperationEnumGreaterOrEquals, + OperationEnumLessOrEquals, + OperationEnumLike + }; + +class ANANAS_EXPORT aFilter +{ +public: + aFilter(); + virtual ~aFilter(); + void Dump() const; + + void Add(const QString& fname, const char* value, OperationEnum op, bool AndOp = true, bool replace = true); + void Add(const QString& fname, const Q_INT64 value, OperationEnum op, bool AndOp = true, bool replace = true); + void Add(const QString& fname, const int value, OperationEnum op, bool AndOp = true, bool replace = true); + void Add(const QString& fname, const double value, OperationEnum op, bool AndOp = true, bool replace = true); + //void Add(const QString& fname, bool value, OperationEnum op, bool AndOp = true, bool replace = true); + void Add(const QString& fname, const QString& value, OperationEnum op, bool AndOp = true, bool replace = true); + void Add(const QString& fname, const QDateTime& value, OperationEnum op, bool AndOp = true, bool replace = true); + void Add(const QString& fname, const QDate& value, OperationEnum op, bool AndOp = true, bool replace = true); + QString toString(bool removeFirst = true) const; + void Clear(); +protected: + void AddHelper(const QString& fname, const QString& value, OperationEnum op, bool And, bool replace); + QString Escape(const QString& val); +private: + struct filterCondition + { + QString fname; + QString value; + QString operation; + QString AndOr; + }f; + //typedef struct filterCondition FilterCondition; + Q3ValueList conditions; +}; + +#endif diff --git a/src/lib/alog.cpp b/src/lib/alog.cpp new file mode 100644 index 0000000..07300a2 --- /dev/null +++ b/src/lib/alog.cpp @@ -0,0 +1,169 @@ +/**************************************************************************** +** $Id: alog.cpp,v 1.2 2008/11/08 20:16:35 leader Exp $ +** +** Log functions source file of +** Ananas application library +** +** Created : 20060402 +** +** Copyright (C) 2006 Grigory Panov, Yoshkar-Ola. +** +** This file is part of the Designer application of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.leaderit.ru/page=ananas or email sales@leaderit.ru +** See http://www.leaderit.ru/gpl/ for GPL licensing information. +** +** Contact org@leaderit.ru if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#include "alog.h" +#include +#include +#include +#include "aservice.h" + + +QString aLog::logName = ""; +int aLog::logLevel = aLog::Debug; +QFile aLog::f; +bool aLog::msg_was_show = false; +//const int aLog::Error = 0; +//const int aLog::Info = 1; +//const int aLog::Debug = 2; + + +/*! + *\~english + * Writes text to log, if /a status less init status. + * \param status - message status ( aLog::Error, aLog::Info, aLog::Debug ) + * \param text - message + *\~russian + * Пишет текст в лог, если статус сообщения меньше установленного при инициализации. К тексту добавляется дата и статус. + * \param status - статус сообщения ( aLog::Error, aLog::Info, aLog::Debug ). + * \param text - сообщение + *\~ +*/ +void +aLog::print( int status, + const QString &text) +{ + QString st; +// switch(status) +// { +// case aLog::Error: + if(status == aLog::Error) st = "ERROR"; +// break; +// case aLog::Info: + else if(status == aLog::Info) st = "INFO"; +// break; +// default: + else st = "DEBUG"; +// break; +// } + if(status<=logLevel) + { + QString endline; + +#ifdef Q_OS_WIN32 + endline = "\r\n"; +#else + endline = "\n"; +#endif + const QString toWrite = QString("%1 %2 %3%4")\ + .arg(QDateTime::currentDateTime().toString(Qt::ISODate).replace('T',' '))\ + .arg(st)\ + .arg(text)\ + .arg(endline); + aLog::printr(toWrite); + } +} + +/*! + *\~english + * Writes raw text to log. + *\~russian + * Пишет текст в лог без изменения. + *\~ + * \param text - \~english text \~russian текст \~ +*/ +void +aLog::printr( const QString &toWrite) +{ + if(aLog::f.handle () !=-1) + { + aLog::f.writeBlock((const char*)toWrite.local8Bit(),strlen((const char*)toWrite.local8Bit())); + aLog::f.flush(); + } + else + { + if(!aLog::msg_was_show) + { + printf("Log system not initialized!\n"); + aLog::msg_was_show = true; + } + } +} + + +/*! + *\~english + * Inits log system. + *\~russian + * Инициализирует систему логирования. Выполняется один раз при запуске програмы, если параметры не указаны, осуществляется попытка прочитать из из конфигурационного файла. Если это не удается, используются параметры по умолчанию. + *\~ + * \param log_name - \~english logfile name. Default ~/.ananas.ananas.log \~russian Путь к логу. Значение по умолчанию ~/.ananas/ananas.log \~ + * \param status - \~english showing status \~russian статус скрытия сообщений. Все сообщения, имеющие больший статус, не попадут в лог ( ERROR= 0, INFO= 1, DEBUG= 2 ). Значение по умолчанию DEBUG \~ +*/ +void +aLog::init(const QString &log_name, int show_up) +{ + bool ok; + QString log; + if(log_name =="" || logName==QString::null) + { + log = aService::readConfigVariable("log", &ok); + if(!ok) log = QDir::homeDirPath()+"/.ananas/ananas.log"; + } + else + { + log = log_name; + } + + aLog::logLevel = show_up; + const QString logLev = aService::readConfigVariable("logLevel", &ok); + + if(logLev=="ERROR") aLog::logLevel = aLog::Error; + if(logLev=="INFO") aLog::logLevel = aLog::Info; + if(logLev=="DEBUG") aLog::logLevel = aLog::Debug; + + aLog::logName = log; + + if (aLog::f.isOpen()) f.close(); + aLog::f.setName(getLogName()); + aLog::f.open( IO_WriteOnly | IO_Append ); + +} + +QString +aLog::getLogName() +{ + return aLog::logName; +} + +void +aLog::close() +{ + aLog::f.close(); +} + diff --git a/src/lib/alog.h b/src/lib/alog.h new file mode 100644 index 0000000..4e59725 --- /dev/null +++ b/src/lib/alog.h @@ -0,0 +1,98 @@ +/**************************************************************************** +** $Id: alog.h,v 1.2 2008/11/08 20:16:35 leader Exp $ +** +** Log functions header file of +** Ananas application library +** +** Created : 20051024 +** +** Copyright (C) 2003-2005 Grigory Panov, Yoshkar-Ola. +** +** This file is part of the Designer application of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.leaderit.ru/page=ananas or email sales@leaderit.ru +** See http://www.leaderit.ru/gpl/ for GPL licensing information. +** +** Contact org@leaderit.ru if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#ifndef ALOG_H +#define ALOG_H + +//#include "ananas.h" +#include "ananasglobal.h" +#include +#include + + +// for bcc32.exe compatibility +// in file wingdi.h +// #define ERROR 0 + +//#ifdef Q_OS_WIN32 +//#define ERROR IRROR +//#endif + +/*! + * \~english + * Class contain static functions for log system + * \~russian + * \brief Класс содержит статические функции для записи сообщений в лог файл Ананаса. + * \~ +*/ +class ANANAS_EXPORT aLog +{ + public: + enum MessageType { Error, Info, Debug }; +// enum status { + /*! + * \~english Error + * \~russian Сообщение об ошибке + * \~ + */ +/* +#ifdef Q_OS_WIN32 + static const int IRROR;//, +#else + static const int ERROR; +#endif +*/ /*! + * \~english Info + * \~russian Информационное сообщение + * \~ + */ +// static const int INFO;//, + /*! + * \~english Info + * \~russian Отладочное сообщение + * \~ + */ +// static const int DEBUG;// }; + + static void print( int status, const QString &text); + static void printr( const QString &text); + static void init( const QString &logname="", int loglevel=0); + static void close(); + static QString getLogName(); + + + private: + aLog(); + static QString logName; + static int logLevel; + static QFile f; + static bool msg_was_show; + +}; +#endif// ALOG_H diff --git a/src/lib/amenubar.cpp b/src/lib/amenubar.cpp new file mode 100644 index 0000000..2c77c7d --- /dev/null +++ b/src/lib/amenubar.cpp @@ -0,0 +1,183 @@ +/**************************************************************************** +** $Id: amenubar.cpp,v 1.1 2008/11/05 21:16:28 leader Exp $ +** +** Code file of the Ananas Menu bar of Ananas +** Designer and Engine applications +** +** Created : 20031201 +** +** Copyright (C) 2003-2004 Leader InfoTech. All rights reserved. +** +** This file is part of the Library of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.leaderit.ru/page=ananas or email sales@leaderit.ru +** See http://www.leaderit.ru/gpl/ for GPL licensing information. +** +** Contact org@leaderit.ru if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +/****************************************************************** + ******************************************************************/ + +#include "amenubar.h" +//Added by qt3to4: +#include +#include + + +AMenuBar::AMenuBar( QWidget* parent , const char* name ) + :QMenuBar( parent, name ) { + +} + +AMenuBar::AMenuBar( aCfg *cfg, QWidget* parent , const char* name ) +:QMenuBar( parent, name ) +{ + md = cfg; + ReadMenu( md->find( md->find( mdc_interface ), md_mainmenu) ); +} + +void +AMenuBar::ReadMenu( aCfgItem obj ) +{ + aCfgItem cobj; + Q3PopupMenu *parent; + QString text, aKey ; + long id; + + if ( !md ) + return; + cobj = md->firstChild ( obj ); + while ( !cobj.isNull() ) + { + id = md->id( cobj ); + if ( md->objClass ( cobj ) == md_submenu ) + { + parent = new Q3PopupMenu (); + insertItem( md->attr( cobj, mda_name ), parent ); + ReadMenu( parent, cobj ); + } + if ( md->objClass ( cobj ) == md_command ) + { + text = md->sText ( cobj, md_menutext ); + if ( text == "" ) text = md->attr( cobj, mda_name ); + aKey = md->sText ( cobj, md_key ); + QMenuBar::insertItem( text, this, SLOT(on_Item()), QKeySequence( aKey ), id ); + } + if ( md->objClass ( cobj ) == md_separator ) + { + insertSeparator(); + } + cobj = md->nextSibling ( cobj ); + } + +} + +void +AMenuBar::ReadMenu( Q3PopupMenu *parent, aCfgItem obj ) +{ + aCfgItem cobj, apix; + Q3PopupMenu *mparent; + QString text, aKey; + long id, pid; + QPixmap pix; + + if ( !md ) + return; + + cobj = md->firstChild ( obj ); + while ( !cobj.isNull() ) + { + id = md->id( cobj ); + if ( md->objClass ( cobj ) == md_submenu ) + { + mparent = new Q3PopupMenu (); + parent->insertItem( md->attr ( cobj, mda_name ), mparent ); + ReadMenu( mparent, cobj ); + } + if ( md->objClass ( cobj ) == md_command ) + { + text = md->sText ( cobj, md_menutext ); + if ( text == "" ) + text = md->attr( cobj, mda_name ); + aKey = md->sText ( cobj, md_key ); + pid = md->text( md->findChild( cobj, md_comaction, 0 ) ).toLong(); + apix = md->findChild( md->find( pid ), md_active_picture, 0 ); + pix.loadFromData( md->binary( apix ) ); + parent->insertItem( pix, text, this, SLOT(on_Item()), QKeySequence( aKey ), id ); + pix = 0; + } + if ( md->objClass ( cobj ) == md_separator ) + { + parent->insertSeparator(); + } + cobj = md->nextSibling ( cobj ); + } + +} + + +AMenuBar::~AMenuBar(){ +} + +int AMenuBar::insertItem ( const QString & text, Q3PopupMenu * popup, int id, int index ) { + return QMenuBar::insertItem ( text, popup, id, index); +}; + +/* +int +AMenuBar::insertItem ( const QString & text, const QObject * receiver, const char * member, const QKeySequence & accel, int id , int index ) { + return QMenuBar::insertItem( text, receiver, member, accel, id, index); +} +int +AMenuBar::insertItem ( const QPixmap & pixmap, const QObject * receiver, const char * member, const QKeySequence & accel , int id , int index ) { + return QMenuBar::insertItem ( pixmap, receiver, member, accel, id, index); +} +int AMenuBar::insertItem ( const QIconSet & icon, const QPixmap & pixmap, const QObject * receiver, const char * member, const QKeySequence & accel , int id , int index ) { + return QMenuBar::insertItem ( icon, pixmap, receiver, member, accel, id, index); +}; +int AMenuBar::insertItem ( const QString & text, int id , int index ) { + return QMenuBar::insertItem( text, id, index ); +}; +int AMenuBar::insertItem ( const QIconSet & icon, const QString & text, int id , int index ) { + return QMenuBar::insertItem ( icon, text, id, index); +}; +int AMenuBar::insertItem ( const QIconSet & icon, const QString & text, QPopupMenu * popup, int id, int index ) { + return QMenuBar::insertItem ( icon, text, popup, id, index); +}; +int AMenuBar::insertItem ( const QPixmap & pixmap, int id , int index ) { + return QMenuBar::insertItem ( pixmap, id, index); +}; +int AMenuBar::insertItem ( const QIconSet & icon, const QPixmap & pixmap, int id , int index ) { + return QMenuBar::insertItem ( icon, pixmap, id, index); +}; +int AMenuBar::insertItem ( const QPixmap & pixmap, QPopupMenu * popup, int id, int index ) { + return QMenuBar::insertItem ( pixmap, popup, id, index); +}; +int AMenuBar::insertItem ( const QIconSet & icon, const QPixmap & pixmap, QPopupMenu * popup, int id , int index ) { + return QMenuBar::insertItem ( icon, pixmap, popup, id, index); +}; +int AMenuBar::insertItem ( QWidget * widget, int id, int index ) { + return QMenuBar::insertItem ( widget, id, index); +}; +int AMenuBar::insertItem ( const QIconSet & icon, QCustomMenuItem * custom, int id , int index ) { + return QMenuBar::insertItem ( icon, custom, id, index); +}; +int AMenuBar::insertItem ( QCustomMenuItem * custom, int id , int index ) { + return QMenuBar::insertItem ( custom, id, index); +}; +int AMenuBar::insertSeparator ( int index ) { + return QMenuBar::insertSeparator ( index); +}; +*/ diff --git a/src/lib/amenubar.h b/src/lib/amenubar.h new file mode 100644 index 0000000..33e617a --- /dev/null +++ b/src/lib/amenubar.h @@ -0,0 +1,82 @@ +/**************************************************************************** +** $Id: amenubar.h,v 1.1 2008/11/05 21:16:28 leader Exp $ +** +** Header file of the Ananas Menu bar of Ananas +** Designer and Engine applications +** +** Created : 20031201 +** +** Copyright (C) 2003-2004 Leader InfoTech. All rights reserved. +** +** This file is part of the Library of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.leaderit.ru/page=ananas or email sales@leaderit.ru +** See http://www.leaderit.ru/gpl/ for GPL licensing information. +** +** Contact org@leaderit.ru if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +/**************************************************************************** +****************************************************************************/ + +#ifndef AMENUBAR_H +#define AMENUBAR_H + +#include +//Added by qt3to4: +#include + +#include "acfg.h" + +class ANANAS_EXPORT AMenuBar : public QMenuBar +{ + Q_OBJECT + + private: + aCfg *md; + + public: + AMenuBar( QWidget* parent = 0, const char* name = 0 ); + AMenuBar( aCfg *cfg, QWidget* parent = 0, const char* name = 0 ); + ~AMenuBar(); + + void ReadMenu( aCfgItem obj ); + void ReadMenu( Q3PopupMenu *parent, aCfgItem obj ); + + public slots: + void on_Item(){}; + + int insertItem ( const QString & text, Q3PopupMenu * popup, int id = -1, int index = -1 ); +/* + int insertItem ( const QString & text, const QObject * receiver, const char * member, const QKeySequence & accel = 0, int id = -1, int index = -1 ); + int insertItem ( const QPixmap & pixmap, const QObject * receiver, const char * member, const QKeySequence & accel = 0, int id = -1, int index = -1 ); + int insertItem ( const QIconSet & icon, const QPixmap & pixmap, const QObject * receiver, const char * member, const QKeySequence & accel = 0, int id = -1, int index = -1 ); + int insertItem ( const QString & text, int id = -1, int index = -1 ); + int insertItem ( const QIconSet & icon, const QString & text, int id = -1, int index = -1 ); + int insertItem ( const QIconSet & icon, const QString & text, QPopupMenu * popup, int id = -1, int index = -1 ); + int insertItem ( const QPixmap & pixmap, int id = -1, int index = -1 ); + int insertItem ( const QIconSet & icon, const QPixmap & pixmap, int id = -1, int index = -1 ); + int insertItem ( const QPixmap & pixmap, QPopupMenu * popup, int id = -1, int index = -1 ); + int insertItem ( const QIconSet & icon, const QPixmap & pixmap, QPopupMenu * popup, int id = -1, int index = -1 ); + int insertItem ( QWidget * widget, int id = -1, int index = -1 ); + int insertItem ( const QIconSet & icon, QCustomMenuItem * custom, int id = -1, int index = -1 ); + int insertItem ( QCustomMenuItem * custom, int id = -1, int index = -1 ); + int insertSeparator ( int index = -1 ); +*/ +private: + Q3IntDict cfgItems; +}; + + +#endif // AMENUBAR_H diff --git a/src/lib/amoney.cpp b/src/lib/amoney.cpp new file mode 100644 index 0000000..ddc94fa --- /dev/null +++ b/src/lib/amoney.cpp @@ -0,0 +1,604 @@ +/**************************************************************************** +** $Id: amoney.cpp,v 1.1 2008/11/05 21:16:28 leader Exp $ +** +** Service functions header file of +** Ananas application library +** +** Copyright (C) 2007 Andrey Paskal. +** +** This file is part of the Designer application of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** +**********************************************************************/ + +#include "amoney.h" +#include + + +/** + * \ru + * \brief Конструктор + * \_ru + */ +AMoney::AMoney(){ + this->amount = 0.0; + this->degree = new Degree(); + this->currency = new Currency("RUR"); +} + + +/** + * \ru + * \brief Конструктор + * \param initialValue - первоначальное количество денег + * \param currency - тип валюты. По умолчанию "RUR". Допустимые значения: "RUR" - рубль, "EUR" - евро, "USD" - доллары США + * \_ru + */ +AMoney::AMoney(double initialValue, QString currency){ + this->amount = initialValue; + this->degree = new Degree(); + this->currency = new Currency( currency ); +} + + +/** + * \ru + * \brief Конвертор в строку + * Периводит числовое значение к значению типа QString. Для преобразования числа в текст (пропись) + * используйте метод toText() + * \_ru + */ +QString +AMoney::toString(){ + return QString::number( this->amount ); +} + + +/** + * \ru + * \brief Сравнивает два экземпляра объектов данного класса. + * + * \_ru + */ +bool +AMoney::equal( AMoney &money){ + return this->amount == money.getAmount(); +} + + +/** + * \ru + * \brief Возвращает количество денег. + * + * \_ru + */ +double +AMoney::getAmount() { + return this->amount; +} + +/** + * \ru + * \brief Задает количество денег. + * Валюта не меняется. Если были рубли, то и остаються рубли. + * \_ru + */ +void +AMoney::setAmount(double val) { + this->amount = val; +} + +/** + * \ru + * \brief Задает количество денег в требуемой валюте. + * \param cur - валюта. Допустимые значения смотри в описании конструктора. + * \_ru + */ +void +AMoney::setAmount(double val, QString cur) { + this->amount = val; + this->currency->setId( cur ); +} + +/** + * \ru + * \brief Возвращает валюту хранимой суммы. + * Возможные значения смотри в описании конструктора. + * \_ru + */ +QString +AMoney::getCurrency(){ + return this->currency->getId(); +} + +/** + * \ru + * \brief Задает валюту хранимой суммы. + * Возможные значения смотри в описании конструктора. + * \_ru + */ +void +AMoney::setCurrency(QString cur) { + this->currency->setId( cur ); +} + +/** + * \ru + * \brief Конвертор суммы в пропись. Публичный интерфейс. + * Возвращает значение хранимой суммы прописью с учетом валюты. + * Например, "Сто долларов США 20 центов" + * \_ru + */ +QString +AMoney::toText(){ + + uint integerKopeiki; + qulonglong integerRubli; + + integerRubli = QVariant( this->amount).toULongLong(); + + double decimal = this->amount-integerRubli; + +#ifdef Q_OS_UNIX + integerKopeiki = round( decimal*100.0 ); +#else + integerKopeiki = decimal * 100.0; +#endif + + QString rubliText; + if ( integerRubli > 0 ) { + rubliText = valueToText( integerRubli ); + } else { + rubliText = "Ноль"; + } + + QString kopeikiText; + if ( integerKopeiki > 0 ) { + kopeikiText = decimalValueToText( integerKopeiki ); + } else { + kopeikiText = "ноль"; + } + return this->firstUp( + rubliText + " " + this->integerCurrencyName( rubliText ) + " " + + QString::number( integerKopeiki ) + " " + this->decimalCurrencyName( kopeikiText ) + ); +} + + +/** + * \ru + * \brief Собирает строку из текстовых троек, вставляя между ними слова "сотен", "тысяч", "миллионов", ... + * + * Внутренний метод. Не предназнвчен для внешнего использования. + * \param value - числовое значение целого типа, которое необходимо перевести в пропись. + * \return возвращает пропись для заданного числа без валюты + * \_ru + */ +QString +AMoney::valueToText( qulonglong value ){ + QString sValue = QString::number( value); + QString tripleText; + QString coupleSingleText; + QString degreeText; + QString result; + this->degree->setValue(0); + + while ( sValue.length() >= 3 ) { + if ( !sValue.endsWith("000")) { + tripleText = tripleToText( sValue.right(3) ); + result = tripleText + this->degreeText( tripleText, this->degree->getValue() ) + result ; + } + sValue = sValue.left( sValue.length() - 3); + this->degree->setValue( this->degree->getValue() +1); + + } + if (sValue.length() > 0) { + if (sValue.length() == 2) { + coupleSingleText = coupleToText( sValue ); + } else { + coupleSingleText = singleToText( sValue ); + } + degreeText = this->degreeText( coupleSingleText, this->degree->getValue() ); + if ( result != "" && (coupleSingleText + degreeText) != "") { + result = coupleSingleText + degreeText + " " + result ; + } else { + result = coupleSingleText + degreeText + result ; + } + } + return result; +} + + +/** + * \ru + * \brief Вспомогательная функция для копеек, центов.... + * + * Используется для перевода цифры в пропись для дробной части суммы. + * Эта функция необходима, так как дробная часть может имерь род отличный от целой части суммы. + * Например, рубль - муж.род, копейка - жен.род. + * + * \_ru + */ +QString +AMoney::decimalValueToText( qulonglong value ){ + QString currencyId = this->currency->getId(); + this->currency->setId( "d"+ currencyId); + QString result = valueToText( value ); + this->currency->setId( currencyId ); + return result; +} + +/** + * \ru + * \brief Преобразует однозначное число в текст. + * + * Учитывается род Муж. или Жен. преобразуемого числа + * \param string - строка, содержащая один символ [0-9] + * \return возвращает "один" или "одна" или "два" или "две" или "три" ..."девять". + * + * \_ru + */ +QString +AMoney::singleToText( QString string ) { + + bool male; + + if ( this->degree->getValue() > 0 ) { + male = this->degree->isMale(); + } else { + male = this->currency->isMale(); + } + + if ( male ) { + if (string == "1") return "один"; + if (string == "2") return "два"; + } else { + if (string == "1") return "одна"; + if (string == "2") return "две"; + } + if (string == "0") return ""; + if (string == "3") return "три"; + if (string == "4") return "четыре"; + if (string == "5") return "пять"; + if (string == "6") return "шесть"; + if (string == "7") return "семь"; + if (string == "8") return "восемь"; + if (string == "9") return "девять"; + + return "undefinded"; +} + +/** + * \ru + * \brief Преобразует двузначное число в текст. + * + * \param string - строка, содержащая два символа [0-9][0-9] + * \return возвращает пропись двузначного числа. + * + * \_ru + */ +QString +AMoney::coupleToText( QString string ) { + + QString result = ""; + + if (string.left(1) == "0") return singleToText( string.right(1) ); + + if (string == "10") return "десять"; + if (string == "11") return "одинадцать"; + if (string == "12") return "двенадцать"; + if (string == "13") return "тринадцать"; + if (string == "14") return "четырнадцать"; + if (string == "15") return "пятнадцать"; + if (string == "16") return "шестьнадцать"; + if (string == "17") return "семьнадцать"; + if (string == "18") return "восемьнадцать"; + if (string == "19") return "девятьнадцать"; + + if (string.left(1) == "2" ) result = "двадцать"; + if (string.left(1) == "3" ) result = "тридцать"; + if (string.left(1) == "4" ) result = "сорок"; + if (string.left(1) == "5" ) result = "пятьдесят"; + if (string.left(1) == "6" ) result = "шестьдесят"; + if (string.left(1) == "7" ) result = "семьдесят"; + if (string.left(1) == "8" ) result = "восемьдесят"; + if (string.left(1) == "9" ) result = "девяносто"; + + + if (string.right(1) != "0") { + result += " " + singleToText( string.right(1) ); + } + + return result; +} + +/** + * \ru + * \brief Преобразует трехначное число в текст. + * + * \param string - строка, содержащая три символа [0-9][0-9][0-9] + * \return возвращает пропись трехзначного числа. + * + * \_ru + */ +QString +AMoney::tripleToText( QString string ) { + QString result = ""; + + if ( string.left(1) == "0" ) return coupleToText( string.right(2) ); + + if ( string.left(1) == "1" ) result = "сто"; + if ( string.left(1) == "2" ) result = "двести"; + if ( string.left(1) == "3" ) result = "триста"; + if ( string.left(1) == "4" ) result = "четыреста"; + if ( string.left(1) == "5" ) result = "пятьсот"; + if ( string.left(1) == "6" ) result = "шестьсот"; + if ( string.left(1) == "7" ) result = "семьсот"; + if ( string.left(1) == "8" ) result = "восемьсот"; + if ( string.left(1) == "9" ) result = "девятьсот"; + + return result + coupleToText( string.right(2) ); +} + +/** + * \ru + * \brief Возвращает слово "тысячи", "миллионы", "миллиарды" в нужной численности. + * \param string - пропись числа, для которого нужно вернуть название порядка + * \param degreeLevel - значение порядка. 1 - тысячи, 2 - миллионы, 3 - миллиарды, 4 - триллионы. + * \_ru + */ +QString +AMoney::degreeText( QString string, int degreeLevel) { + QString result = ""; + + if ( degreeLevel < 1 ) return result; + + if (degreeLevel == 1) { + if ( string.endsWith("одна") ) { + result = " тысяча"; + } else if ( string.endsWith("две") || string.endsWith("три") || string.endsWith("четыре") ) { + result = " тысячи"; + } else { + result = " тысяч"; + } + } else if (degreeLevel == 2) { + if ( string.endsWith("один") ) { + result = " миллион"; + } else if ( string.endsWith("два") || string.endsWith("три") || string.endsWith("четыре") ) { + result = " миллиона"; + } else { + result = " миллионов"; + } + } else if (degreeLevel == 3) { + if ( string.endsWith("один") ) { + result = " миллиард"; + } else if ( string.endsWith("два") || string.endsWith("три") || string.endsWith("четыре") ) { + result = " миллиарда"; + } else { + result = " миллиардов"; + } + } else if (degreeLevel == 4) { + if ( string.endsWith("один") ) { + result = " триллион"; + } else if ( string.endsWith("два") || string.endsWith("три") || string.endsWith("четыре") ) { + result = " триллиона"; + } else { + result = " триллионов"; + } + } + + return result; +} + +/** + * \ru + * \brief Возвращает прописью название валюты для целой части числа. + * \param string - пропись числа, для которого нужно вернуть название валюты прописью. + * + * \_ru + */ +QString +AMoney::integerCurrencyName( QString string ){ + QString result = ""; + + if (string == "") return ""; + + if ( this->currency->is("USD") ) { + if ( string.endsWith("один") ) { + result = "доллар США"; + } else if ( string.endsWith("два") || string.endsWith("три") || string.endsWith("четыре") ) { + result = "доллара США"; + } else { + result = "долларов США"; + } + } else if ( this->currency->is("EUR") ) { + result = "евро"; + } else { + if ( string.endsWith("один") ) { + result = "рубль"; + } else if ( string.endsWith("два") || string.endsWith("три") || string.endsWith("четыре") ) { + result = "рубля"; + } else { + result = "рублей"; + } + } + + return result; +} + +/** + * \ru + * \brief Возвращает прописью название валюты для дробной части числа. + * \param string - пропись числа, для которого нужно вернуть название валюты прописью. + * + * \_ru + */ +QString +AMoney::decimalCurrencyName(QString string ){ + QString result = ""; + + if (string == "") return ""; + + if ( this->currency->is("USD") || this->currency->is("EUR") ) { + if ( string.endsWith("один") ) { + result = "цент"; + } else if ( string.endsWith("два") || string.endsWith("три") || string.endsWith("четыре") ) { + result = "цента"; + } else { + result = "центов"; + } + } else { + if ( string.endsWith("одна") ) { + result = "копейка"; + } else if ( string.endsWith("две") || string.endsWith("три") || string.endsWith("четыре") ) { + result = "копейки"; + } else { + result = "копеек"; + } + } + + return result; +} + +/** + * \ru + * \brief Поднимает регистр первой буквы слова, если первой идет одна из букв: о,д,т,ч,п,ш,с,в. + * \param str - строка, первый символ которой нужно перевести в верхний регистр. + * \_ru + */ +QString +AMoney::firstUp( QString str) { + + return str.left(1).upper() + str.right( str.length() - 1); +} + +/** + * \ru + * \brief Конструктор + * \param - значение порядка. 0 - сотни (по умолчанию), 1 - тысячи, 2 - миллионы, 3 - миллиарды, 4 - триллионы. + * \_ru + */ +Degree::Degree( int val) { + this->setValue( val ); +} + + +/** + * \ru + * \brief Возвращает значение порядок. + * Возможные значения смотри в описании конструктора. + * \_ru + */ +int +Degree::getValue() { + return this->value; +} + +/** + * \ru + * \brief Задает значение порядка. + * Допустимые значения смотри в описании конструктора. + * \_ru + */ +void +Degree::setValue( int val ) { + this->value = val; + if (this->value == 1) { + this->male = false; + } else { + this->male = true; + } +} + +/** + * \ru + * \brief Возвращает true, если текущий порядок имеет мужской род. + * + * Например, миллион, миллиард. + * Возвращает false, если текущий порядок имеет женский род + * Например, тысяча + * \_ru + */ +bool +Degree::isMale() { + return this->male; +} + + +/** + * \ru + * \brief Конструктор + * \param - Обозначение валюты. + * Допустимые значения параметра: + * RUR - русский рубль, значение по умолчанию + * dRUR - копейка + * USD - доллар США + * dUSD - цент + * EUR - евро + * dEUR = dUSD + * \_ru + */ +Currency::Currency( QString newId) { + setId( newId ); +} + + +/** + * \ru + * \brief Возвращает истину, если текущая валюта равна значению, указанному в рараметре. + * Допустимые значения параметра смотри в описании конструктора. + * \_ru + */ +bool +Currency::is( QString str ){ + return this->id == str; +} + +/** + * \ru + * \brief Возвращает истину, если текущая валюта имеет мужской род. + * Например, копейка. + * \_ru + */ +bool +Currency::isMale( ){ + return this->male; +} + + +/** + * \ru + * \brief Возвращает символьное обозначение, идентификатор валюты. + * Допустимые значения смотри в описании конструктора. + * \_ru + */ +QString +Currency::getId() { + return this->id; +} + +/** + * \ru + * \brief Установка типа валюты. + * Допустимые значения смотри в описании конструктора. + * \_ru + */ +void +Currency::setId(QString newId) { + + if ( newId == "dRUR") { + this->male = false; + } else { + this->id = newId; + this->male = true; + } +} diff --git a/src/lib/amoney.h b/src/lib/amoney.h new file mode 100644 index 0000000..fd96b1f --- /dev/null +++ b/src/lib/amoney.h @@ -0,0 +1,110 @@ +/**************************************************************************** +** $Id: amoney.h,v 1.1 2008/11/05 21:16:28 leader Exp $ +** +** Service functions header file of +** Ananas application library +** +** Copyright (C) 2007 Andrey Paskal. +** +** This file is part of the Designer application of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** +**********************************************************************/ +#ifndef AMONEY_H_ +#define AMONEY_H_ +#include "ananas.h" +#include "qstring.h" + +class Degree; +class Currency; + +/** + * \ru + * \brief Класс для хранения денежных значений в различной валюте и получения их прописного представления. + * \_ru + */ +class ANANAS_EXPORT AMoney{ + public: + AMoney(); + AMoney( double amount, QString currency = "RUR"); + + double getAmount(); + void setAmount( double ); + void setAmount( double, QString currency); + QString getCurrency(); + void setCurrency( QString ); + QString toString(); + QString toText(); + bool equal( AMoney &sum ); + + private: + double amount; + Currency* currency; + Degree* degree; + + QString degreeText( QString , int ); + QString valueToText( qulonglong ); + QString decimalValueToText( qulonglong ); + QString singleToText( QString ); + QString coupleToText( QString ); + QString tripleToText( QString ); + QString integerCurrencyName( QString ); + QString decimalCurrencyName( QString ); + QString firstUp( QString ); + +}; + + + +/** + * \ru + * \brief содержит знания о роде (М/Ж) числовых порядков. + * После задания порядка (сотни, тысячи, миллионы....) можно узнать род + * методом isMale() + * \_ru + */ +class Degree { + public: + Degree( int = 0 ); + int getValue(); + void setValue( int value); + bool isMale(); + + private: + int value; + bool male; +}; + +/** + * \ru + * \brief содержит знания о роде (М/Ж) валюты. + * После задания одного из поддерживаемых типов валюты можно узнать род + * методом isMale() + * Поддерживаемые типы валют можно увидеть в описании конструктора. + * \_ru + */ +class Currency { + public: + Currency( QString currensyId = "RUR"); + + QString getId(); + void setId( QString ); + bool isMale(); + bool is( QString ); + + private: + QString id; + bool male; +}; + + +#endif /*AMONEY_H_*/ diff --git a/src/lib/ananas.cpp b/src/lib/ananas.cpp new file mode 100644 index 0000000..d4db687 --- /dev/null +++ b/src/lib/ananas.cpp @@ -0,0 +1,160 @@ +/**************************************************************************** +** $Id: ananas.cpp,v 1.2 2008/11/09 21:09:11 leader Exp $ +** +** Code file of the Ananas Library of Ananas +** Designer and Engine applications +** +** Created : 20031201 +** +** Copyright (C) 2003-2004 Leader InfoTech. All rights reserved. +** +** This file is part of the Library of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.leaderit.ru/page=ananas or email sales@leaderit.ru +** See http://www.leaderit.ru/gpl/ for GPL licensing information. +** +** Contact org@leaderit.ru if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#include "ananas.h" +#include "dselectdb.h" +#include "dlogin.h" + + + +/*! + * Library version number. + */ +const char * +ANANAS_EXPORT +ananas_libversion() +{ + static const char libver[]=ANANAS_LIBVERSION; + return libver; +} + + +/*! + * Select database and user login. + */ +bool +ANANAS_EXPORT +ananas_login( QString &rcfile, QString &username, QString &userpassword, aDatabase *db, int appId ) +{ + dSelectDB dselectdb; + dLogin dlogin; + + if ( rcfile.isEmpty() ) { + if (dselectdb.exec()==QDialog::Accepted) rcfile = dselectdb.rcfile; + } + if ( !rcfile.isEmpty() ) { + if (dlogin.exec()==QDialog::Accepted) { + username = dlogin.username; + userpassword = dlogin.password; + if ( !db ) db = aDatabase::database(); + if ( !db->init( rcfile ) ) return false; + return ( db->login( username, userpassword, appId ) ); + } return false; + } + return false; +} + + +/*! + * Select database and user login. + */ +void +ANANAS_EXPORT +ananas_logout( aDatabase *db ) +{ + if ( !db ) db = aDatabase::database(); + db->logout(); +} + + +/*! + * Select database and user login. + */ +/* +bool +ANANAS_EXPORT +ananas_login( QString &rcfile, QString &username, QString &userpassword ) +{ + dSelectDB dselectdb; + //dLogin dlogin; + + if ( rcfile.isEmpty() ) { + if (dselectdb.exec()==QDialog::Accepted) rcfile = dselectdb.rcfile; + } + if ( !rcfile.isEmpty() ) { +// if (dlogin.exec()==QDialog::Accepted) { +// username = dlogin.username; +// userpassword = dlogin.password; + return true; +// } return false; + } + return false; + // return true; +} +*/ + + +/*! + * \en + * \brief Return object string presentation. + * \_en + * \ru + * \brief Возвращает текстовое представление бизнес объекта Ананаса + * + * \param db - база данных бизнес объекта + * \param uid - уникальный идентификатор бизнес объекта + * \param oid - уникальный идентификатор типа данных, соответствующих бизнес объекту, как определено в метаданных. + * \_ru + */ +QString +ANANAS_EXPORT +ananas_objectstr( aDatabase *db, qulonglong uid, int oid ) +{ + QString res = ""; + + //TODO: make this more faster + aCfgItem fto; + QString oclass; + +// printf("objstr uid = %Ld\n", uid ); + if ( !db ) return "<>"; + if ( !oid ) oid = db->uidType( oid ); + fto = db->cfg.find( oid ); + if ( !fto.isNull() ) { + oclass = db->cfg.objClass( fto ); +// printf("oid = %i, oclass = %s\n", oid, ( const char *) oclass ); + if ( oclass == md_catalogue ) { + aCatalogue cat( fto, db ); + cat.select( uid ); + if ( cat.selected() ) { + res = cat.displayString(); + } + }else if ( oclass == md_document ) { + aDocument doc(fto, db); + doc.select( uid ); + if( doc.selected() ){ + res = doc.displayString(); + } + } + } + + return res; +} + + diff --git a/src/lib/ananas.h b/src/lib/ananas.h new file mode 100644 index 0000000..b882181 --- /dev/null +++ b/src/lib/ananas.h @@ -0,0 +1,131 @@ +/**************************************************************************** +** $Id: ananas.h,v 1.3 2008/12/10 21:04:03 leader Exp $ +** +** Header file of the Ananas Library of Ananas +** Designer and Engine applications +** +** Created : 20031201 +** +** Copyright (C) 2003-2004 Leader InfoTech. All rights reserved. +** +** This file is part of the Library of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.leaderit.ru/page=ananas or email sales@leaderit.ru +** See http://www.leaderit.ru/gpl/ for GPL licensing information. +** +** Contact org@leaderit.ru if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +/*! \ru + *\mainpage Проект Ананас. Справочное руководство по библиотеке ananaslib + * + * + * В Справочном руководстве приведено описание классов, составляющих ядро системы Ананас. + * Документ предназначен для использования в качестве Справочника по интерфейсу прикладного программирования Ананаса. + * Интерфейс предоставляет доступ к управлению метаданными Ананаса, данными, хранящимися в базе данных, + * прикладными объектами системы. Справочное руководство предназначено для программистов. Пользовательское + * описание системы Ананас содержится в Руководстве пользователя. + * + * \section intro_sec Введение + * Ананас - вольная платформа, обеспечивающая ускоренное создание приложений автоматизации учетной деятельности, + * бизнес процессов организаций и компаний, работающих в различных сферах деятельности. + * Библиотека ananaslib, являясь частью платформы Ананас, обеспечивает удобный и понятный доступ к реализованным + * в системе функциям, для программ на языке программирования С++. Настоящее справочное руководство содержит описание + * методов доступа. + * + * \section main_classes_sec Основные классы + * \subsection adocument_class_sec Класс aDocument + * Один из важных аспектов методологии работы Ананаса с данными - управление первичными учетными документами. + * Для отражения хозяйственных операций Ананас предусматривает их регистрацию с помощью электронных документов. + * Электронные документы могут иметь произвольную структуру, состоящую из набора полей и одной или нескольких + * табличных частей. Информация о структуре документов хранится в системе. Управление документами осуществляется + * через экземпляры класса aDocument. + + * \subsection acatalog_class_sec Класс aCatalogue + * Ананас поддерживает ведение баз данных (картотек) произвольной структуры + * с возможностью классификации/разнесения элементов по иерархически + * организованным группам. Типичным примером использования этой возможности является ведение Каталога товаров, + * Справочника контрагентов, Реестра сотрудников. Унифицированный интерфейс доступа к таким базам данных (картотекам) + * обеспечивает класс aCatalogue. + * + * \subsection adocjournal_class_sec Класс aDocJournal + * Все электронные документы, хранящиеся в базе данных Ананаса, регистрируются системой в момент их создания в + * журнале документов. Для работы с журналом документов используется класс aDocJournal. + * + * + * \subsection airegister_class_sec Класс aIRegister, aARegister + * Ананас поддерживает ведение Регистров. Регисты служат для хронологической записи информации. В системе существует + * два типа регистров: информационные и накопительные. Накопительный, отличается от информационного поддержкой + * автоматически пересчитываемых остатков по разрезам учета. Для работы с информационными регистрами используется + * класс aIRegister. Для работы с накопительными - aARegister. + * + * \subsection acfg_class_sec Класс aCfg + * Ананас разработан с учетом требований адаптируемости к различным сферам учетной деятельности. Для этих целей + * поддерживается работа с произвольно настраиваемыми структурами данных. Такой подход требует хранения информации, + * описывающей структуры данных. Такую информацию принято называть метаданными. Для управления структурами данных и для + * работы с метаданными используется класс aCfg. + * + * \subsection aform_class_sec Класс aForm + * Все бизнес объекты Ананаса, атрибуты которых может редактировать пользователь, имеют хотя бы одну экранную + * форму, работая с которой, пользователь осуществляет изменение значений атрибутов бизнес объектов. + * Класс aForm предоставляет набор методов, предназначенных для использования Ананас.Скриптом модуля экранной формы + * бизнес объекта Ананаса. Проектируя и программируя пользовательский интерфейс (Presentation layer) + * бизнес схемы Ананаса разработчик имеет дело с объектами класса aForm и расположенными в них виджетами. + * \_ru + */ + +#ifndef ANANAS_H +#define ANANAS_H + +#include "acfg.h" +#include "acfgrc.h" +#include "ametadata.h" +#include "adatabase.h" +#include "asqlfield.h" +#include "adatafield.h" +#include "asqltable.h" +#include "aform.h" +#include "engine.h" +#include "aobject.h" +#include "awidget.h" +#include "messageswindow.h" +#include "adocjournal.h" +#include "adocument.h" +#include "acatalogue.h" +#include "airegister.h" +#include "aaregister.h" +#include "atemplate.h" +#include "areport.h" +#include "aextension.h" +#include "aextensionfactory.h" +#include "adataexchange.h" +//#include "dlogin.h" +//#include "deditrc.h" +//#include "dselectdb.h" +#include "atime.h" +#include "auser.h" +#include "arole.h" +#include "aservice.h" +#include "atests.h" +#include "afilter.h" + +#define ANANAS_LIBVERSION "0.9.6" +extern const char ANANAS_EXPORT *ananas_libversion(); +//extern bool ANANAS_EXPORT ananas_login( QString &rcfile, QString &username, QString &userpassword ); +extern bool ANANAS_EXPORT ananas_login( QString &rcfile, QString &username, QString &userpassword, aDatabase *db=0, int appId = 0 ); +extern void ANANAS_EXPORT ananas_logout( aDatabase *db=0 ); +extern QString ANANAS_EXPORT ananas_objectstr( aDatabase *db, qulonglong uid, int oid ); + + +#endif diff --git a/src/lib/ananasglobal.h b/src/lib/ananasglobal.h new file mode 100644 index 0000000..b273646 --- /dev/null +++ b/src/lib/ananasglobal.h @@ -0,0 +1,87 @@ +/**************************************************************************** +** $Id: ananasglobal.h,v 1.1 2008/11/05 21:16:28 leader Exp $ +** +** Header file of the Ananas Library of Ananas +** Designer and Engine applications +** +** Created : 20040901 +** +** Copyright (C) 2003-2004 Leader InfoTech. All rights reserved. +** Copyright (C) 2003-2004 Linux Center (Orenburg). All rights reserved. +** +** This file is part of the Library of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.leaderit.ru/page=ananas or email sales@leaderit.ru +** See http://www.leaderit.ru/gpl/ for GPL licensing information. +** +** Contact org@leaderit.ru if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#ifndef ANANASGLOBAL_H +#define ANANASGLOBAL_H + +#include + +#define ANANAS_DEBUG + +#define ANANAS_VERSION_STRING "0.4.3" +#define ANANAS_VERSION_MAJOR 0 +#define ANANAS_VERSION_MINOR 4 +#define ANANAS_VERSION_MICRO 3 + +// helper macros +#define ANANAS_MAKE_VERSION(maj, min, mic) (((maj) << 16) | ((min) << 8) | (mic)) +#define ANANAS_VERSION \ + ANANAS_MAKE_VERSION(ANANAS_VERSION_MAJOR, ANANAS_VERSION_MINOR, ANANAS_VERSION_MICRO) + +// evaluate to true if this version is (maj, min, mic) at minimum +#define ANANAS_IS_VERSION(maj, min, mic) \ + (ANANAS_VERSION >= ANANAS_MAKE_VERSION(maj, min, mic)) + +#if defined(Q_OS_WIN32) && !defined(ANANAS_NO_DLL) +# if defined(ANANAS_DLL) +# define ANANAS_EXPORT __declspec(dllexport) +# else +# define ANANAS_EXPORT __declspec(dllimport) +# endif +#else +# define ANANAS_EXPORT +#endif + +#ifdef _MSC_VER +#define LLU_SPEC "%I64u" +#else +#define LLU_SPEC "%llu" +#endif + +#if defined (ANANAS_DLL) +# define ANANAS_TEMPLATE_EXTERN +#elif defined (Q_TEMPLATEDLL) +# define ANANAS_TEMPLATE_EXTERN Q_TEMPLATE_EXTERN +#else +# define ANANAS_TEMPLATE_EXTERN +#endif + + +//#if defined(Q_ULLONG) +# define ANANAS_UID qulonglong +# define ANANAS_UID_VALUE( v ) v.toULongLong() +//#error yes +//#else +//# define ANANAS_UID unsigned int +//# define ANANAS_UID_VALUE( v ) v.toUInt() +//#error no +//#endif + +#endif diff --git a/src/lib/arole.cpp b/src/lib/arole.cpp new file mode 100644 index 0000000..7a0dd07 --- /dev/null +++ b/src/lib/arole.cpp @@ -0,0 +1,423 @@ +/**************************************************************************** +** $Id: arole.cpp,v 1.1 2008/11/05 21:16:28 leader Exp $ +** +** Role object implementation file of +** Ananas application library +** +** Created : 20050527 +** +** Copyright (C) 2003-2005 Grigory Panov, Yoshkar-Ola. +** +** This file is part of the Designer application of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.leaderit.ru/page=ananas or email sales@leaderit.ru +** See http://www.leaderit.ru/gpl/ for GPL licensing information. +** +** Contact org@leaderit.ru if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#include "arole.h" +#include "auser.h" +/*! + * \en + * Constructor. + * \_en + * \ru + * Конструктор. Создает экземпляр роли и настраивает его на работу с заданным id. + * \param roleId - идентификатор роли. + * \param adb - ссылка на базу данных. + * \_ru + */ +aRole::aRole( qulonglong roleId, aDatabase * adb ):aObject("",adb) +{ + + initObject(); + Select(roleId); +} + + +/*! + * \en + * Constructor. + * \_en + * \ru + * Конструктор. Создает экземпляр роли. Для работы необходимо выбрать нужную роль с помощью функции Select( Q_ULLONG id ). + * \param adb - ссылка на базу данных. + * \_ru + */ +aRole::aRole( aDatabase * adb ):aObject("",adb) +{ + + initObject(); +} + + + + +ERR_Code +aRole::initObject() +{ + ERR_Code err = aObject::initObject(); + err = tableInsert( db_roles,""); + if(err) return err; + err = tableInsert( db_right_roles, md_right_roles ); + return err; +} + + + +/*! + * \en + * Sets role name. + * \_en + * \ru + * Устанавливает имя роли. + * \_ru + * \param rname - \en role name \_en \ru имя роли \_ru + * \return \en error code \_en \ru код ошибки \_ru +*/ +ERR_Code +aRole::SetName( const QString &rname ) +{ + setSysValue( "name", rname ); + return err_noerror; +} + + +/*! + * \en + * Gets role name. + * \_en + * \ru + * Функция получения имени роли. + * \_ru + * \return \en role name \_en \ru имя роли \_ru +*/ +QString +aRole::GetName( ) +{ + + return sysValue( "name" ).toString(); +} + + +ERR_Code +aRole::Update() +{ + ERR_Code err = aObject::Update(); + if ( !err ){ + err = TableUpdate( md_right_roles ); + } + return err; +} + + + +/*! + * \en + * Sets primary table selected. + * \_en + * \ru + * Устанавливает основную таблицу выбранной. + * \_ru + * \return \en error code \_en \ru код ошибки \_ru +*/ +ERR_Code +aRole::Select( ) +{ + aSQLTable * t = table(); + if ( !t ) return err_notable; + QString flt = ""; + if ( t->select( flt ) ) + if ( t->first() ) + { + setSelected(true); + } + else return err_notselected; + else return err_selecterror; + return err_noerror; +} + + +/*! + * \en + * Select role. + * \_en + * \ru + * Выбирает роль с заданным идентификатором. + * \_ru + * \param id - \en role id \_en \ru id роли \_ru + * \return \en error code \_en \ru код ошибки \_ru +*/ +ERR_Code +aRole::Select( qulonglong id ) +{ + aSQLTable * t = table(); + if ( !t ) return err_notable; + QString flt; + flt = QString("id=%1").arg(id); + if ( t->select( flt ) ) + if ( t->first() ) + { + setSelected(true); + } + else return err_notselected; + else return err_selecterror; + return err_noerror; +} + + +/*! + * \en + * Adds permission to role + * \_en + * \ru + * Добавляет к роли право \a p + * \_ru + * \param p - \en permission \_en \ru право \_ru + * \return \en error code \_en \ru код ошибки \_ru +*/ +ERR_Code +aRole::addPermission( aPermission p ) +{ + aSQLTable *tg = table( md_right_roles ); + if ( !tg ) return err_notable; + setSelected(true, md_right_roles); + qulonglong idg; + QSqlRecord* rec = tg->primeInsert(); // get edit buffer for table groups + idg = rec->value("id").toULongLong(); + rec->setValue("id",idg ); + rec->setValue("permission",p); + tg->insert(); // insert record + tg->update(); +return err_noerror; +} + + +/*! + * \en + * Removs permission from role + * \_en + * \ru + * Убирает у роли право \a p + * \_ru + * \param p - \en permission \_en \ru право \_ru + * \return \en error code \_en \ru код ошибки \_ru +*/ +ERR_Code +aRole::delPermission( aPermission p ) +{ +/* aSQLTable *tg = table( md_user_roles ); + if (!tg ) return err_notable; + setSelected(true, md_right_roles); +// tg->select(parentId); +// setSelected(true,md_group); + Q_ULLONG idg; + QSqlRecord* rec = tg->primeInsert(); // get edit buffer for table groups + idg = rec->value("id").toULongLong(); + //printf( "idg=%lu\n", idg ); + rec->setValue("id",idg ); + rec->setValue("permission",p); + tg->insert(); // insert record + tg->update();*/ +return err_noerror; +} + + +/*! + * \en + * Check permission \a p. + * \_en + * \ru + * Проверяет, есть ли у роли право \a p + * \_ru + * \param p - \en permission \_en \ru право \_ru + * \return \en true, if role has perission \_en \ru true, если у роли есть право \_ru +*/ +bool +aRole::hasPermission( aPermission p ) +{ + aSQLTable *tg = table( md_right_roles ); + if (!tg ) return err_notable; + tg->select(QString("idr=%1").arg(sysValue("id").toULongLong())); + if( tg->first() ) + { + return true; + } + else + { + return false; + } + +} + + + +/*! + * \en + * Adds user to role + * \_en + * \ru + * Добавляет к пользователю данную роль. + * \_ru + * \param userId - \en user id \_en \ru идентификатор пользовыателя \_ru + * \return \en error code \_en \ru код ошибки \_ru +*/ + +ERR_Code +aRole::addUser( qulonglong userId ) +{ + aUser *user = new aUser(userId, db); + user->addRole(sysValue("id").toULongLong()); + delete user; +return err_noerror; +} + + +/*! + * \en + * Delete user from role + * \_en + * \ru + * Удаляет у пользователя данную роль + * \_ru + * \param userId - \en user id \_en \ru идентификатор пользовыателя \_ru + * \return \en error code \_en \ru код ошибки \_ru +*/ +ERR_Code +aRole::delUser( qulonglong userId ) +{ + aUser *user = new aUser(userId, db); + user->delRole(sysValue("id").toULongLong()); + delete user; +return err_noerror; +} + + +/*! + * \en + * Check user have role. + * \_en + * \ru + * Проверяет, принадлежит ли пользователь к данной роли. + * \_ru + * \param userId - \en user id \_en \ru id пользователя \_ru + * \return \en true, if role has user \_en \ru true, если у пользователя есть эта роль\_ru +*/ +bool +aRole::hasUser(qulonglong userId) +{ + aUser *user = new aUser(userId, db); + bool res; + if(user->hasRole(sysValue("id").toULongLong())) + { + res = true; + } + else + { + res =false; + } + delete user; + return res; +} + + +/*! + * \en + * Adds new pole. + * \_en + * \ru + * Добавляет новую роль. + * \_ru + */ +ERR_Code +aRole::New(const QString &rname) +{ + aSQLTable *te = table(); + if (!te) return err_notable; + QSqlRecord *rec; + qulonglong ide; + rec = te->primeInsert(); // get edit buffer for table elements + ide = rec->value("id").toULongLong(); + rec->setValue("id",ide); // set defult values for all user fields = id + rec->setValue( "name", rname ); + te->insert(); // insert edit buffer as new line in table + te->select(QString("id=%1").arg(ide),false); // set cursor to inserted record + te->first(); + setSelected(true); + return err_noerror; +} + + + + + +/*! + * \en + * Delete this role. + * \_en + * \ru + * Удаляет эту роль. Не удаляет роль у пользователей. + * \_ru + */ +ERR_Code +aRole::Delete() +{ + aSQLTable * t = table(); + qulonglong ide=0; + if ( !t ) return err_notable; + ide = t->sysValue("id").toULongLong(); + if ( ide ) + { + printf("ide=" LLU_SPEC "\n",ide); + t->primeDelete(); + t->del(); + setSelected( false ); + } + else return err_notselected; + return err_noerror; +} + + + +bool +aRole::Next() +{ + return aObject::Next( ); //return !groupSelect(); + //else return false; +} + +bool +aRole::Prev() +{ + return aObject::Prev( ); //return !groupSelect(); +// else return false; +} + +bool +aRole::First() +{ + return aObject::First( ); //return !groupSelect(); + //else return false; +} + +bool +aRole::Last() +{ + return aObject::Last( ); //return !groupSelect(); + //else return false; +} + + + diff --git a/src/lib/arole.h b/src/lib/arole.h new file mode 100644 index 0000000..3dff46d --- /dev/null +++ b/src/lib/arole.h @@ -0,0 +1,101 @@ +/**************************************************************************** +** $Id: arole.h,v 1.1 2008/11/05 21:16:28 leader Exp $ +** +** Role object header file of +** Ananas application library +** +** Created : 20050527 +** +** Copyright (C) 2003-2005 Grigory Panov, Yoshkar-Ola. +** +** This file is part of the Designer application of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.leaderit.ru/page=ananas or email sales@leaderit.ru +** See http://www.leaderit.ru/gpl/ for GPL licensing information. +** +** Contact org@leaderit.ru if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#ifndef AROLE_H +#define AROLE_H + +#include "aobject.h" +#include "adatabase.h" +#include "acfg.h" +//#include "auser.h" + +//class aUser; +//class aPermission; +//class aObject; + + + +/*! + * \en + * Not visual object used for working with catalogues in database. + * Used as interface between database and script or wObjects* + * \_en + * \ru + * \brief Класс предоставляет методы управления ролями. Не используется в настоящее время. + * Наследует aObject. + * + * \_ru +*/ +class ANANAS_EXPORT aRole: public aObject +{ + Q_OBJECT +public: + + aRole(); + aRole(qulonglong roleId, aDatabase * adb); + aRole(aDatabase * adb); + virtual ERR_Code initObject(); + +//public slots: + + virtual ERR_Code New(const QString &name); + + virtual ERR_Code Delete(); + virtual ERR_Code Update(); + virtual ERR_Code Select(); + virtual ERR_Code Select(qulonglong id); + + virtual ERR_Code addPermission( aPermission ); + virtual ERR_Code delPermission( aPermission ); + virtual bool hasPermission( aPermission ); + + virtual ERR_Code addUser( qulonglong userId ); + virtual ERR_Code delUser( qulonglong userId ); + +// QValueList< aUser *> getUsers( bool assigned); + + bool hasUser( qulonglong userId); + + virtual ERR_Code SetName( const QString & ); + virtual QString GetName(); + + //virtual ERR_Code setLogin( const QString & ); + //virtual ERR_Code setFirstName( const QString & ); + //virtual ERR_Code setLastName( const QString & ); + +//irtual Q_ULLONG getUserId( const QString &login, const QString &password ); +//irtual ERR_Code getRoles(QValueList *lst); + bool First(); + bool Next(); + bool Last(); + bool Prev(); +}; + + +#endif// AROLE_H diff --git a/src/lib/aservice.cpp b/src/lib/aservice.cpp new file mode 100644 index 0000000..85433f0 --- /dev/null +++ b/src/lib/aservice.cpp @@ -0,0 +1,547 @@ +/**************************************************************************** +** $Id: aservice.cpp,v 1.2 2008/11/08 20:16:35 leader Exp $ +** +** Service functions source file of +** Ananas application library +** +** Created : 20050425 +** +** Copyright (C) 2003-2006 Grigory Panov, Yoshkar-Ola. +** +** This file is part of the Designer application of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.leaderit.ru/page=ananas or email sales@leaderit.ru +** See http://www.leaderit.ru/gpl/ for GPL licensing information. +** +** Contact org@leaderit.ru if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#include "qsettings.h" +#include "aservice.h" +#include "alog.h" +#include "amoney.h" +#include +#include + + +/*! + *\~english + * Converted double currency value to string representation (ru currency). + *\~russian + * Конвертирует валюту, записанную в виде десятичного числа в ее текстовое представление. + *\~ + * \param rubli - \~english Value to convertions \~russian Значение для конвертации \~ + * \return - \~english Converted value \~russian Сконвертированное значение \~ + * \see parts2money(Q_ULLONG rubli, unsigned int kopeyki, bool positive) + * \see part2string(unsigned int st3, unsigned int st2, unsigned int st1, int stepen) + * \see convertNumber2MoneyFormat(double number) +*/ +QString +aService::number2money( double rubli, + bool need_kopeyki, + bool male, + const QString &end1, + const QString &end2, + const QString &end3) +{ + bool neg = rubli<0; + //printf("chislo=%f\n",rubli); + if(neg) + { + rubli = -rubli; + } + qulonglong r = QVariant(rubli).toULongLong(); + double tmp = rubli-r; + + uint kop; +#ifdef Q_OS_UNIX + kop = round(tmp*100.0); +#else + kop = tmp * 100.0; +#endif + return parts2money(r,kop, need_kopeyki, !neg, male, end1, end2, end3); +} + + +/** + * \ru + * \brief Конвертирует числовое представление денег в пропись с учетом указанной валюты. + * \param amount - сумма денег для преобразование в пропись. + * \param currency - строка с обозначением валюты. Допустимые значения: "RUR" - рубль, "USD" - доллар, "EUR" - евро. + * \returns значение суммы прописью. + * \_ru + */ +QString +aService::number2money( QString currency, double amount ) { + AMoney* money = new AMoney( amount, currency ); + return money->toText(); +} + + + +/*! + *\~english + * Converted currency value to string representation (ru currency). + *\~russian + * Конвертирует валюту, записанную в виде рублей и копеек в ее текстовое представление. + *\~ + * \return - \~english Converted value \~russian Сконвертированное значение \~ + * \see number2money(double rubli) + * \see part2string(unsigned int st3, unsigned int st2, unsigned int st1, int stepen) +*/ +QString +aService::parts2money(qulonglong rubli, + unsigned int kopeyki, + bool need_kopeyki, + bool positive, + bool male, + const QString &end1, + const QString &end2, + const QString &end3) +{ +// if(cur!=ru) return QString("%1 dollars %2 cents").arg(rubli).arg(kopeyki); + QString chislo = (QString("%1").arg(rubli)); + int len = chislo.length(); + //printf("length=%d\n",len); + int count=0; + int a,b,c; + int stepen=(len-1)/3; + int offset=(len%3); + if(offset) offset = 3-offset; + //printf("offset=%d\n",offset); + QString res = ""; + bool has_sum=false; + if(!positive) res+="минус "; + while(count mapMaleCur; + QMap mapFeMaleCur; + QMap mapHungred; + QMap mapDec; + + mapFeMaleCur[0]=""; + mapFeMaleCur[1]="одна"; + mapFeMaleCur[2]="две"; + mapFeMaleCur[3]="три"; + mapFeMaleCur[4]="четыре"; + mapFeMaleCur[5]="пять"; + mapFeMaleCur[6]="шесть"; + mapFeMaleCur[7]="семь"; + mapFeMaleCur[8]="восемь"; + mapFeMaleCur[9]="девять"; + + mapFeMaleCur[10]="копеек"; + mapFeMaleCur[11]="копейка"; + mapFeMaleCur[12]= mapFeMaleCur[13]= mapFeMaleCur[14]="копейки"; + mapFeMaleCur[15]= mapFeMaleCur[16]= mapFeMaleCur[17]= mapFeMaleCur[18]= mapFeMaleCur[19]="копеек"; + + mapFeMaleCur[20]="тысяч"; + mapFeMaleCur[21]="тысяча"; + mapFeMaleCur[22]= mapFeMaleCur[23]= mapFeMaleCur[24]="тысячи"; + mapFeMaleCur[25]= mapFeMaleCur[26]= mapFeMaleCur[27]= mapFeMaleCur[28]= mapFeMaleCur[29]="тысяч"; + + mapMaleCur[0]=""; + mapMaleCur[1]="один"; + mapMaleCur[2]="два"; + mapMaleCur[3]="три"; + mapMaleCur[4]="четыре"; + mapMaleCur[5]="пять"; + mapMaleCur[6]="шесть"; + mapMaleCur[7]="семь"; + mapMaleCur[8]="восемь"; + mapMaleCur[9]="девять"; + + if(male==true) + { + mapMaleCur[10]=end1; //"рублей"; + mapMaleCur[11]=end2;//"рубль"; + mapMaleCur[12]= mapMaleCur[13]= mapMaleCur[14]=end3;//"рубля"; + mapMaleCur[15]= mapMaleCur[16]= mapMaleCur[17]= mapMaleCur[18]= mapMaleCur[19]=end1;//"рублей"; + } + else + { + mapFeMaleCur[10]= end1;//"копеек"; + mapFeMaleCur[11]= end2;//"копейка"; + mapFeMaleCur[12]= mapFeMaleCur[13]= mapFeMaleCur[14]=end3;//"копейки"; + mapFeMaleCur[15]= mapFeMaleCur[16]= mapFeMaleCur[17]= mapFeMaleCur[18]= mapFeMaleCur[19]=end1;//"копеек"; + } + mapMaleCur[30]="миллионов"; + mapMaleCur[31]="миллион"; + mapMaleCur[32]= mapMaleCur[33]= mapMaleCur[34]="миллиона"; + mapMaleCur[35]= mapMaleCur[36]=mapMaleCur[37]=mapMaleCur[38]=mapMaleCur[39]="миллионов"; + mapMaleCur[40]="миллиардов"; + mapMaleCur[41]="миллиард"; + mapMaleCur[42]= mapMaleCur[43]= mapMaleCur[44]="миллиарда"; + mapMaleCur[45]= mapMaleCur[46]=mapMaleCur[47]=mapMaleCur[48]=mapMaleCur[49]="миллиардов"; + mapHungred[0]=""; + mapHungred[1]="сто"; + mapHungred[2]="двести"; + mapHungred[3]="триста"; + mapHungred[4]="четыреста"; + mapHungred[5]="пятьсот"; + mapHungred[6]="шестьсот"; + mapHungred[7]="семьсот"; + mapHungred[8]="восемьсот"; + mapHungred[9]="девятьсот"; + + mapDec[0]="десять"; + mapDec[1]="одиннадцать"; + mapDec[2]="двенадцать"; + mapDec[3]="тринадцать"; + mapDec[4]="четырнадцать"; + mapDec[5]="пятнадцать"; + mapDec[6]="шестнадцать"; + mapDec[7]="семнадцать"; + mapDec[8]="восемнадцать"; + mapDec[9]="девятнадцать"; + mapDec[10]=""; + mapDec[11]=""; + mapDec[12]="двадцать"; + mapDec[13]="тридцать"; + mapDec[14]="сорок"; + mapDec[15]="пятьдесят"; + mapDec[16]="шестьдесят"; + mapDec[17]="семьдесят"; + mapDec[18]="восемьдесят"; + mapDec[19]="девяносто"; + + + if(stepen==1 || stepen==-1 || stepen==0 && male==false) + { + part1 = mapHungred[st3]; + part2 = mapDec[10+st2]; + int mult = 20; + if(stepen==-1) mult=10; + if(stepen==0) mult=10; + switch(st2) + { + case 0: + part3=mapFeMaleCur[st1]; + suff=mapFeMaleCur[st1+mult]; + break; + case 1: + part3=mapDec[st1]; + suff=mapFeMaleCur[9+mult]; + break; + default: + part3=mapFeMaleCur[st1]; + suff=mapFeMaleCur[st1+mult]; + break; + } + if(stepen==-1 && st3==0 && st2==0 && st1==0) + { + part3="ноль"; + } + } + else + { + part1 = mapHungred[st3]; + part2 = mapDec[10+st2]; + int mult = 10*(stepen+1); + switch(st2) + { + case 0: + part2=""; + part3=mapMaleCur[st1]; + suff=mapMaleCur[st1+mult]; + break; + case 1: + part2=""; + part3=mapDec[st1]; + suff=mapMaleCur[9+mult]; + break; + default: + part3=mapMaleCur[st1]; + suff=mapMaleCur[st1+mult]; + break; + } + } + if(stepen==-1) // если убрать этот блок, копейки будут выводиться прописью + { + part1 = part2 =""; + part3 = QString("%1%2").arg(st2).arg(st1); + } +return part1+" "+part2 +" "+part3+" "+suff+" "; +} + + +/*! + *\~english + * Converted date from ISO format (yyyy-mm-dd) to local format. + *\~russian + * Конвертирует дату из ISO формата в локальный формат. + *\~ + * \param ISODate - \~english Date to convertion \~russian Дата для конвертации \~ + * \return - \~english Converted value \~russian Сконвертированное значение \~ +*/ +QString +aService::Date2Print(const QString &ISODate) +{ + QString res; + QDate dat = QDate::fromString(ISODate, Qt::ISODate); + res = dat.toString(Qt::LocalDate); + return res; +} + + +/*! + *\~english + * Writes window size to config file. + *\~russian + * Пишет размер окна в конфиг. + *\~ + * \param windowSize - \~english Rect of window geometry \~russian Прямоугольник, представляющий окно \~ + * \param mdname - \~english Unical name \~russian Имя окна (должно быть уникальным) \~ + * \see loadSizeFromConfig(const QString &mdname) +*/ +void +aService::saveSize2Config(QRect windowSize, const QString &mdname) +{ + QSettings settings; + //--settings.insertSearchPath( QSettings::Unix, QString(QDir::homeDirPath())+QString("/.ananas")); + //--settings.insertSearchPath( QSettings::Windows, "/ananasgroup/ananas" ); + settings.beginGroup(QString("/config/%1").arg(mdname)); + settings.writeEntry("/left", windowSize.left()); + settings.writeEntry("/top", windowSize.top()); + settings.writeEntry("/right", windowSize.right()); + settings.writeEntry("/bottom", windowSize.bottom()); +} + + +/*! + *\~english + * Reads window size from config file. + *\~russian + * Читает размер окна из конфиг. + *\~ + * \param mdname - \~english Window name. + * If config not contains info about mdname, + * return default value (400x300) + * \~russian Имя окна. + * Если конфиг не содержит информации об окне с таким именем, + * возвращает значение по умолчанию (400x300) \~ + * \return - \~english Window size \~russian Размер окна \~ + * \see saveSize2Config(QRect windowSize, const QString &mdname) + * +*/ +QRect +aService::loadSizeFromConfig(const QString &mdname) +{ + QSettings settings; + //--settings.insertSearchPath( QSettings::Unix, QString(QDir::homeDirPath())+QString("/.ananas")); + //--settings.insertSearchPath( QSettings::Windows, "/ananasgroup/ananas" ); + settings.beginGroup(QString("/config/%1").arg(mdname)); + int l = settings.readNumEntry("/left", 0); + int t = settings.readNumEntry("/top", 0); + int r = settings.readNumEntry("/right", 400); + int b = settings.readNumEntry("/bottom", 300); + return QRect(l,t,r,b); +} + + +/*! + *\~english + * Reads variable from config file. + *\~russian + * Читает переменную из конфига. + *\~ + * \param name - \~english variable name to read \~russian Имя переменной для чтения \~ + * \param ok (out) - \~english true if success, false otherwise + \~russian true если успешно иначе false \~ + * \return - \~english Variable value \~russian Значение переменной \~ + * \see writeConfigVariable(const QString &name, const QString &value) + * \see loadSizeFromConfig(const QString &mdname) + * \see saveSize2Config(QRect windowSize, const QString &mdname) +*/ +QString +aService::readConfigVariable(const QString &name, bool *ok) +{ + QSettings settings; + //--settings.insertSearchPath( QSettings::Unix, QString(QDir::homeDirPath())+QString("/.ananas")); + //--settings.insertSearchPath( QSettings::Windows, "/ananasgroup/ananas" ); + settings.beginGroup(QString("/config/variables")); + return settings.readEntry(QString("/%1").arg(name), "", ok); +} + + +/*! + *\~english + * Writes variable to config file. + *\~russian + * Пишет переменную в конфиг. + *\~ + * \param name - \~english Variable name \~russian Имя переменной \~ + * \param value - \~english Variable value \~russian Значение переменной \~ + * \see loadSizeFromConfig(const QString &mdname) + * \see saveSize2Config(QRect windowSize, const QString &mdname) + * \see readConfigVariable(const QString &name, bool *ok) +*/ +void +aService::writeConfigVariable(const QString &name, const QString &value) +{ + QSettings settings; + //--settings.insertSearchPath( QSettings::Unix, QString(QDir::homeDirPath())+QString("/.ananas")); + //--settings.insertSearchPath( QSettings::Windows, "/ananasgroup/ananas" ); + settings.beginGroup(QString("/config/variables")); + settings.writeEntry(QString("/%1").arg(name), value); +} + +/*! + *\~english + * Converted number to money format (publi.kk). + *\~russian + * Конвертирует число с плавающей точкой в числовой денежный формат (рубли.кк) + *\~ + * \param number - \~english number to convertion \~russian число для конвертации \~ + * \return - \~english Converted value \~russian Сконвертированное значение \~ +*/ +QString +aService::convertNumber2MoneyFormat(double number) +{ + return QString("%1").arg(number,0,'f',2); +} + +bool +aService::copyFile(const QString& srcFileName, const QString& destFileName, bool replaceIfExists) +{ + + QFile srcFile(srcFileName); + QFile destFile(destFileName); + + if(!srcFile.exists()) + { + aLog::print(aLog::Error, QObject::tr("aService copy: source file %1 not exist").arg(srcFileName)); + return false; + } + if(destFile.exists() && !replaceIfExists) + { + aLog::print(aLog::Error, QObject::tr("aService copy: replace destination file %1").arg(destFileName)); + return false; + } + + if(!srcFile.open( QIODevice::ReadOnly )) + { + aLog::print(aLog::Error, QObject::tr("aService copy: source file %1 open for read error").arg(srcFileName)); + return false; + } + if(!destFile.open( QIODevice::WriteOnly)) + { + aLog::print(aLog::Error, QObject::tr("aService copy: destination file %1 open for write error").arg(destFileName)); + return false; + } + + const int BUFFER_SIZE = 1024; + Q_INT8 buffer[BUFFER_SIZE]; + QDataStream srcStream(&srcFile); + QDataStream destStream(&destFile); + + while(!srcStream.atEnd()) + { + int i = 0; + while(!srcStream.atEnd() && i < BUFFER_SIZE) + { + srcStream >> buffer[i]; + i++; + } + for(int k = 0; k < i; k++) + { + destStream << buffer[k]; + } + } + srcFile.close(); + destFile.close(); + + aLog::print(aLog::Info, QObject::tr("aService copy file %1 to %2 ok").arg(srcFileName).arg(destFileName)); + return true; +} diff --git a/src/lib/aservice.h b/src/lib/aservice.h new file mode 100644 index 0000000..46a74f6 --- /dev/null +++ b/src/lib/aservice.h @@ -0,0 +1,86 @@ +/**************************************************************************** +** $Id: aservice.h,v 1.1 2008/11/05 21:16:28 leader Exp $ +** +** Service functions header file of +** Ananas application library +** +** Created : 20050425 +** +** Copyright (C) 2003-2005 Grigory Panov, Yoshkar-Ola. +** +** This file is part of the Designer application of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.leaderit.ru/page=ananas or email sales@leaderit.ru +** See http://www.leaderit.ru/gpl/ for GPL licensing information. +** +** Contact org@leaderit.ru if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#ifndef ASERVICE_H +#define ASERVICE_H + +//#include +#include "ananas.h" + +/*! + * \~english + * Class contains static functions for various destination: convertation, work with config file etc. + * \~russian + * \brief Класс содержит статические методы различного назначения: конвертации, работы с конфигом и т.д. + * Не наследует свойства других классов. + * + * Врапперы для некоторых функций для работы со скриптами есть в классе aForm + * \~ + * \see aForm aTests + */ +class ANANAS_EXPORT aService +{ + public: + + static QString number2money( double rubli, + bool need_kopeyki=true, + bool male=true, + const QString &end1="рублей", + const QString &end2="рубль", + const QString &end3="рубля"); + static QString number2money( QString currency, double rubli ); + static QString parts2money( qulonglong rubli, + unsigned int kopeyki, + bool need_kopeyki=true, + bool positive = true, + bool male=true, + const QString &end1="рублей", + const QString &end2="рубль", + const QString &end3="рубля"); + static QString Date2Print(const QString &ISODate); + static void saveSize2Config(QRect size, const QString &mdname); + static QRect loadSizeFromConfig(const QString &mdname); + static QString readConfigVariable(const QString &name, bool *ok); + static void writeConfigVariable(const QString &name, const QString &value); + static QString convertNumber2MoneyFormat(double number); + static bool copyFile(const QString& srcFileName, const QString& destFileName, bool replaceIfExists=true); + protected: + + static QString part2string( unsigned int st3, + unsigned int st2, + unsigned int st1, + int stepen, + bool male, + const QString &end1, + const QString &end2, + const QString &end3); + private: + aService(); +}; +#endif// AREPORT_H diff --git a/src/lib/asqlfield.cpp b/src/lib/asqlfield.cpp new file mode 100644 index 0000000..d92a3cd --- /dev/null +++ b/src/lib/asqlfield.cpp @@ -0,0 +1,155 @@ +/**************************************************************************** +** $Id: asqlfield.cpp,v 1.1 2008/11/05 21:16:28 leader Exp $ +** +** Code file of the Ananas database field of Ananas +** Designer and Engine applications +** +** Created : 20031201 +** +** Copyright (C) 2003-2004 Leader InfoTech. All rights reserved. +** +** This file is part of the Library of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.leaderit.ru/page=ananas or email sales@leaderit.ru +** See http://www.leaderit.ru/gpl/ for GPL licensing information. +** +** Contact org@leaderit.ru if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#include +#include "acfg.h" +#include "asqlfield.h" + +/*! +Create Ananas database field contaner. +*/ +/* +aField::aField(aCfg *newmd, aCfgItem newcontext ) +:QObject( 0, "aField" ) // name ) +{ + md = newmd; + context = newcontext; +// fType = type; + fTName = ""; +// field = new QSqlField( fTName ); + fSys = false; +} +*/ + +/*! +Create Ananas field contaner. +*/ +/* +aField::aField(const QString &name, const QString &type ) +:QObject( 0, "aField" ) +{ + QString t; + + fSys = true; + Name = name; +// Type = type; + aType = ( (const char *) type.section(" ",0,0).upper() )[0]; + Width = type.section(" ",1,1).toInt(); + Dec = type.section(" ",2,2).toInt(); + switch ( aType ){ + case 'C': + Type = QVariant::String; + field = QString(""); + break; + case 'N': + Type = QVariant::Double; + field = ( double ) 0.0; + default: + Type = QVariant::Invalid; + } +} +*/ + +/*! +Destroy object. +*/ + +//aField::~aField() +//{ +// delete field; +//} + + +/*! +Return pointer to asociated sql field. +*/ +//QSqlField * +//aField::sqlField(){ +// return field; +//} + + +//QVariant +//aField::value() +//{ +// return field; +//} + + +//void +//aField::setValue( const QVariant &value) +//{ +// field = value; +//} + + +aSQLField::aSQLField( aCfg *newmd, aCfgItem newcontext ) +: QObject( 0, "aSQLField" ) +{ + +} + + +aSQLField::aSQLField( const QString &name, const QString &type, const QString &tname ) +: QObject( 0, "aSQLField" ) +{ + tName = tname; +} + + +aSQLField::~aSQLField() +{ + +} + + +QSqlField * +aSQLField::sqlField() +{ + return field; +} + + +QVariant +aSQLField::value() +{ + return ""; +} + + +void +aSQLField::setValue( const QVariant &value) +{ + +} +QWidget * +aSQLField::editor() +{ + return NULL; +} diff --git a/src/lib/asqlfield.h b/src/lib/asqlfield.h new file mode 100644 index 0000000..ac0c166 --- /dev/null +++ b/src/lib/asqlfield.h @@ -0,0 +1,85 @@ +/**************************************************************************** +** $Id: asqlfield.h,v 1.1 2008/11/05 21:16:28 leader Exp $ +** +** Header file of the Ananas database field of Ananas +** Designer and Engine applications +** +** Created : 20031201 +** +** Copyright (C) 2003-2004 Leader InfoTech. All rights reserved. +** +** This file is part of the Library of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.leaderit.ru/page=ananas or email sales@leaderit.ru +** See http://www.leaderit.ru/gpl/ for GPL licensing information. +** +** Contact org@leaderit.ru if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#ifndef ASQLFIELD_H +#define ASQLFIELD_H +#include +#include "acfg.h" + +/* +class ANANAS_EXPORT aField : public QObject //SqlField +{ + Q_OBJECT +public: +// enum fieldType ( Unknown, Numberic, Character, Date, Object ); + aCfgItem context; + long id; + aCfg *md; + bool fSys; + int Width, Dec; + QString Name; + char aType; + QVariant::Type Type; + + +// aField( aCfg *newmd, aCfgItem newcontext ); + aField( const QString &fname = QString::null, const QString &ftype = QString::null ); + ~aField(); + +// QSqlField *sqlField(); +public slots: + virtual QVariant value(); + virtual void setValue( const QVariant &value); +private: + QVariant field; +}; +*/ + +class ANANAS_EXPORT aSQLField: public QObject //aField +{ + Q_OBJECT +public: + QString tName; + QWidget *editorWidget; + + aSQLField( aCfg *newmd, aCfgItem newcontext ); + aSQLField( const QString &name = QString::null, const QString &type = QString::null, const QString &tname = QString::null ); + ~aSQLField(); + + QSqlField *sqlField(); + virtual QWidget *editor(); + +public slots: + virtual QVariant value(); + virtual void setValue( const QVariant &value); +private: + QSqlField *field; +}; + +#endif diff --git a/src/lib/asqltable.cpp b/src/lib/asqltable.cpp new file mode 100644 index 0000000..8d5ba35 --- /dev/null +++ b/src/lib/asqltable.cpp @@ -0,0 +1,1111 @@ +/**************************************************************************** +** $Id: asqltable.cpp,v 1.3 2008/11/09 21:09:11 leader Exp $ +** +** Code file of the Ananas database table of Ananas +** Designer and Engine applications +** +** Created : 20031201 +** +** Copyright (C) 2003-2004 Leader InfoTech. All rights reserved. +** +** This file is part of the Library of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.leaderit.ru/page=ananas or email sales@leaderit.ru +** See http://www.leaderit.ru/gpl/ for GPL licensing information. +** +** Contact org@leaderit.ru if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ +//#include + +#include "asqltable.h" +#include +//Added by qt3to4: +#include +#include "adatabase.h" +#include +#include + +#include "acatalogue.h" +#include "adocument.h" +#include "aaregister.h" +#include "alog.h" + +/*! + * \~english + * Constructor + * \~russian + * Создает таблицу доступа к базе данных, позволяющую работать с одной + * sql таблицей или одним sql представлением (view). + * \param context - объект метаданных, который описывает таблицу. + * \param adb - ссылка на объект базы данных, которой + * принадлежит sql таблица. + * \~ + */ +aDataTable::aDataTable( aCfgItem context, aDatabase *adb ) +:Q3SqlCursor( QString::null, false, *adb->db() ) +{ + db = adb; + md = &db->cfg; + mdobjId = 0; + tableName = db->tableDbName( db->cfg, context, &mdobjId ); + if ( !tableName.isEmpty() ) { + setName( tableName, true ); + init (context, adb ); + } + selected = false; + p_cat.setAutoDelete ( true ); + p_reg.setAutoDelete ( true ); + p_doc.setAutoDelete ( true ); +} + + + +/*! + * \~english + * Constructor + * \~russian + * Создает таблицу доступа к базе данных, позволяющую работать с одной + * sql таблицей или одним sql представлением (view). + * \param tname - имя sql таблицы в базе данных + * \param adb - ссылка на объект базы данных, которой + * принадлежит sql таблица. + * \~ + * + */ +aDataTable::aDataTable( const QString &tname, aDatabase *adb ) +:Q3SqlCursor( tname, true, *adb->db() ) +{ + db = adb; + md = &db->cfg; + tableName = tname; + mdobjId = 0; + selected = false; + p_cat.setAutoDelete ( true ); + p_reg.setAutoDelete ( true ); + p_doc.setAutoDelete ( true ); + +} + +/*! + * \~english + * Destructor + * \~russian + * Деструктор + * \~ + * + */ +aSQLTable::~aSQLTable() +{ +// delete p_reg; +// delete p_cat; + p_reg.clear(); + p_cat.clear(); + p_doc.clear(); +} + +/*! + * \~english + * Inits table object. + * \~russian + * Инициализирует объект. + * \see setObject() + * \param context - объект метаданных, который описывает таблицу. + * \param adb - ссылка на объект базы данных, которой + * принадлежит sql таблица. + * \~ + */ +void +aDataTable::init( aCfgItem context, aDatabase *adb ) +{ + db = adb; + fnames.clear(); + fnames.setAutoDelete( true ); + userFilter.clear(); + userFilter.setAutoDelete( true ); + setObject( context ); + +} + + + +/*! + * \~english + * Sets md object to table. + * \~russian + * Задает объект метаданных для таблицы. + * Заполняет внутренние объекты именами полей для последующего использования в + * функциях SetValue() и Value(), добавляет информацию о них в sql курсор. + * В случае, если добавляется накопительный регистр, к объетку добавляются также виртуальные поля - ресурсы регистра + * После вызова этой функции с таблицей можно начинать работу. + * \param context - объект метаданных, который описывает таблицу. + * \~ + */ +void +aDataTable::setObject( aCfgItem context ) +{ + aCfgItem cobj, parent; + parent = obj = context; + + + mdobjId = md->id(obj); + while ( !mdobjId ) + { + parent = md->parent(parent); + mdobjId = md->id(parent); + } + if ( context.isNull() ) + { + aLog::print(aLog::Error,QObject::tr("aDataTable try set mdobject to null")); + return; + } + mapCat.clear(); + mapDoc.clear(); + mapReg.clear(); + mapDim.clear(); + mapSum.clear(); + //TODO: test to memory leak + p_cat.clear(); + p_reg.clear(); + p_doc.clear(); +// printf("before delete p_cat\n"); +// if(p_cat) + //delete p_cat; + +// p_cat.clear(); +// printf("after delete p_cat\n"); +// if(p_reg) + //delete p_reg; +// p_reg.clear(); + if(md->objClass(context) == md_field && md->objClass(md->parent(context))== md_dimensions) + { + insertFieldInfo(context,false); + aCfgItem res; + aCfgItem ress = md->findChild(md->parent(md->parent(context)),md_resources); + uint n = md->count( ress, md_field ); + for ( uint i = 0; i < n; i++ ) + { + res = md->find( ress, md_field, i ); + insertFieldInfo(res,false); + } + } + uint n = md->count( context, md_field ); + for ( uint i = 0; i < n; i++ ) + { + cobj = md->find( context, md_field, i ); + insertFieldInfo(cobj); + + } + +// r = *this; +} + + +/*! + * \~english + * Appends info about field to object. + * \~russian + * Добавляет информацию о поле к объекту. + * \param obj - объект метаданных, который описывает поле. + * \param calculatd - указывает будет ли поле вычисляемым. + * \~ + */ +void +aSQLTable::insertFieldInfo(aCfgItem cobj, bool calculated) +{ + QString fname, fdbname, objt;//, fid; + int fid ; + + if ( !cobj.isNull() ) + { + fid = md->id(cobj); + fname = md->attr(cobj, mda_name); + objt = md->attr( cobj, mda_type ).upper(); + fdbname = QString("uf%1").arg( fid ); + if ( objt[0]=='O' ) + { + fnames.insert( fname, new QString(fdbname) ); + fdbname = QString("text_uf%1").arg( fid ); + append( Q3SqlFieldInfo( fdbname, QVariant::String ) ); + // setGenerated( fdbname, false ); + setCalculated( fdbname, calculated ); + int ftid = objt.section(" ", 1, 1 ).toInt(); + aCfgItem fto = md->find( ftid ); + if ( !fto.isNull() ) + { + if ( md->objClass( fto ) == md_catalogue ) + { + mapCat[fid] = fto; + } + if ( md->objClass( fto ) == md_document ) + { + mapDoc[fid] = fto; + } + } + } + else + if ( objt[0]==' ' ) + { + fdbname = QString("text_uf%1").arg( fid ); + append( Q3SqlFieldInfo( fdbname, QVariant::String ) ); + setCalculated( fdbname, calculated ); + // setGenerated( fdbname, false ); + fnames.insert( fname, new QString(fdbname) ); + int ftid = objt.section(" ", 1, 1 ).toInt(); + aCfgItem fto = md->find( ftid ); + if ( !fto.isNull() ) + { + if ( md->objClass( fto ) == md_aregister ) + { + aCfgItem s_field = md->find(objt.section(" ",2,2).toInt()); + aCfgItem dim_fields = md->find(fto,md_dimensions); + + if(!dim_fields.isNull()) + { + int cnt = md->count( dim_fields, md_field ); + for ( int k = 0; k < cnt; k++ ) + { + aCfgItem dim_field = md->find( dim_fields, md_field, k ); + QString type = md->attr(dim_field, mda_type); + if(type[0]=='O') + { + + if(type.section(" ",1,1).toInt()== mdobjId) + { + mapReg[fid]=fto; + mapDim[fid]= md->attr(dim_field,mda_name); + mapSum[fid] = md->attr(s_field,mda_name); + break; + } + } + } + } + } + } + + } + else + { + fnames.insert( fname, new QString(fdbname) ); + } + } +} + + +/*! + * \~english + * Gets metadata object. + * \~russian + * Получение объекта метаданных, которым инициализировали таблицу. + * \return объект метаданных, который описывает таблицу. + * \~ + */ +qulonglong +aDataTable::getIdd(void) +{ + return 0; +} +long +aDataTable::getMdObjId() +{ + return mdobjId; +} + + + +/*! + * \~english + * Stub. + * \~russian + * Заглушка. + * \~ + */ +void +aDataTable::appendField( aSQLField * ) // fieldinfo ) +{ + +} + + + +/*! + * \~english + * Stub. + * \~russian + * Заглушка. + * \~ + */ +void +aDataTable::insertField( int /*pos*/, aSQLField * ) // fieldinfo ) +{ + +} + + + +/*! + * \~english + * Stub. + * \~russian + * Заглушка. + * \~ + */ +void +aDataTable::removeField( int ) // pos ) +{ + +} + + + +/*! + * \~english + * Stub. + * \~russian + * Заглушка. + * \~ + */ +void +aDataTable::clearFields() +{ + +} + + + +/*! + * \~english + * Stub. + * \~russian + * Заглушка. + * \~ + */ +bool +aDataTable::checkStructure( bool ) //update ) +{ + bool rc = false; + if ( name().isEmpty() ) { + + } else { + + } + return rc; +} + + + +/*! + * \~english + * Return field falue. + * \~russian + * Возвращает значение поля с номером \a i. + * \param i - номер поля. + * \return значение поля + * \~ + */ +QVariant +aDataTable::value ( int i ) +{ + // QVariant v = QSqlCursor::value( i ); + + QVariant v = sysValue(Q3SqlCursor::fieldName(i)); + return v; +} + + + +/*! + * \~english + * Return field falue. + * \~russian + * Возвращает значение поля с именем \a name. + * Для получения значения необходимо указывать имя поля в метаданных + * \param name - имя поля в метаданных. + * \return значение поля или QVariant::Invalid, если поля не существует. + * \~ + */ +QVariant +aDataTable::value ( const QString & name ) +{ + QString fname; + QVariant v; + + if ( !fnames[name] ) + { + aLog::print(aLog::Error, QObject::tr("aDataTable get value of unknown field `%1'").arg(name)); + return QVariant::Invalid; + } + fname = * fnames[ name ]; + + //v = QSqlCursor::value( fname ); + + return sysValue(fname); +} + + + +/*! + * Return true if column name exists in database table. + */ + /*! + * \~english + * Check field existing. + * \~russian + * Проверяет существование поля в таблице + * \param name - имя поля в таблице (не в метаданных!). + * \return \~engish true if column name exists in database table \~russian true, если столбец с данным именем есть в таблице. \~ + * \~ + */ + +bool +aDataTable::sysFieldExists( const QString & name ) +{ + return contains( name ); +} + + + +/*! + * Return value of the column of the database table. + */ +QVariant +aDataTable::sysValue ( const QString & name ) +{ + if(isCalculated(name)) return calcFieldValue(name); + else return Q3SqlCursor::value( name ); +} + + + +/*! + * + */ +void +aDataTable::setSysValue ( const QString & name, QVariant value ) +{ + if ( name == QString("pnum") ) + { + aLog::print(aLog::Info, QObject::tr("aDataTable get document prefix to `%1'").arg(value.toString())); + // debug_message("document prefix set to '%s'\n",(const char*)value.toString()); + } + + Q3SqlCursor::setValue( name, value ); +} + + + +/*! + * Set value of the column of the database table. + */ +void +aDataTable::setValue ( int i, QVariant value ) +{ + Q3SqlCursor::setValue( i, value ); +} + + + +/*! + * + */ +bool +aDataTable::setValue ( const QString & name, QVariant value ) +{ + QString fname; + if ( !fnames[name] ) return false; + fname = * fnames[ name ]; + if ( contains( fname ) ) { + Q3SqlCursor::setValue( fname, value ); + } + else return false; + return true; +} + + + +/*! + * + */ +QSqlRecord * +aDataTable::primeInsert() +{ + QSqlRecord *rec; + QVariant v; + + rec = Q3SqlCursor::primeInsert(); + if ( sysFieldExists("id") ) { + rec->setValue("id", QVariant( db->uid( mdobjId ) ) ); + } + return rec; +} + + + +/*! + * + *//* +QSqlRecord * +aDataTable::primeUpdate() +{ + QSqlRecord *rec; + + rec = QSqlCursor::primeUpdate(); + *rec = r; + return rec; +} +*/ + + +/*! + * + */ +bool +aDataTable::select( const QString & filter, bool usefltr ) +{ + bool res; + QString flt = getFilter(); + if ( usefltr ) + { + if ( flt == "" ) flt = filter; + else if ( filter != "" ) flt = flt + " AND " + filter; + } + else flt = filter; + res = Q3SqlCursor::select( flt ); +// next(); +// r = *this; + return res; +} + + + +/*! + * + */ +bool +aDataTable::select( qulonglong id ) +{ + bool res; +// printf("aSQLTable::select %llu\n",id); + res = Q3SqlCursor::select( QString( "id=%1" ).arg( id ) ); + //setSelected(true); +// next(); +// r = *this; + return res; +} + + + +/*! + * + */ +void +aDataTable::clearFilter() +{ + aLog::print(aLog::Debug, QObject::tr("aDataTable clear filter")); + userFilter.clear(); +} + + +/*QDict +aDataTable::getUserFilter() { + return this.userFilter; +}; + +void +setUserFilter( QDict newFilter) { + this.userFilter = newFilter; +}; +*/ + +/** + * + */ +void +aDataTable::setFilter ( const QString & newFilter ) { + Q3SqlCursor::setFilter( newFilter ); +} + + +/*! + * + */ +bool +aDataTable::setFilter( const QString& name, const QVariant& value ) +{ + + aLog::print(aLog::Debug, QObject::tr("aDataTable set filter %1='%2'").arg(name).arg(value.toString())); + if ( !fnames[name] ) + { + aLog::print(aLog::Error, QObject::tr("aDataTable set filter %1='%2', %3 not exist").arg(name).arg(value.toString()).arg(name)); + return false; + } + QVariant *v = new QVariant(value); + userFilter.replace(*fnames[name], v ); + Q3SqlCursor::setFilter(getFilter()); + return true; +} + + + +/*! + * + */ +QString +aDataTable::getFilter() +{ + QString filter = "", fid, type; + aCfgItem field; + Q3DictIteratorit( userFilter ); + if ( it.toFirst() ) + { + fid = it.currentKey().mid(2); + field = md->find(fid.toLong() ); + if ( !field.isNull() ) + { + type = md->attr( field, mda_type ); + if ( type[0] == 'N' || type[0] == 'O' ) + filter = it.currentKey() + "=" + it.current()->toString(); + else + filter = it.currentKey() + "='" + it.current()->toString() + "'"; + } + } + ++it; + for (;it.current();++it) + { + fid = it.currentKey().mid(2); + field = md->find(fid.toLong() ); + if ( !field.isNull() ) + { + type = md->attr( field, mda_type ); + if ( type[0] == 'N' || type[0] == 'O' ) + filter += " and " + it.currentKey() + "=" + it.current()->toString(); + else + filter += " and " + it.currentKey() + "='" + it.current()->toString() + "'"; + } + } + return filter; +} + + + +/*! + * + */ +QString +aDataTable::getNFilter() +{ + QString filter = "", fid, type; + aCfgItem field; + Q3DictIteratorit( userFilter ); + if ( it.toFirst() ) + { + fid = it.currentKey().mid(2); + field = md->find(fid.toLong() ); + if ( !field.isNull() ) + { + type = md->attr( field, mda_type ); + if ( type[0] == 'N' || type[0] == 'O' ) + filter = tableName + "." + it.currentKey() + "=" + it.current()->toString(); + else + filter = tableName + "." + it.currentKey() + "='" + it.current()->toString() + "'"; + } + } + ++it; + for (;it.current();++it) + { + fid = it.currentKey().mid(2); + field = md->find(fid.toLong() ); + if ( !field.isNull() ) + { + type = md->attr( field, mda_type ); + if ( type[0] == 'N' || type[0] == 'O' ) + filter += " and " + tableName + "." + it.currentKey() + "=" + it.current()->toString(); + else + filter += " and " + tableName + "." + it.currentKey() + "='" + it.current()->toString() + "'"; + } + } + return filter; +} + + + +/*! + * + */ +void +aDataTable::printRecord(){ + unsigned int i; + Q3DictIterator it( fnames ); + QString fname, sname; + + for (i=0; i< count(); i++){ + fname = ""; + sname = field( i ).name(); + it.toFirst(); + for( ; it.current(); ++it ){ + if ( *it.current() == sname ) { + fname = it.currentKey(); + break; + } + } + printf("%s(%s)=%s\n", + ( const char *) fname, + ( const char *) sname, + ( const char *) value( i ).toString().local8Bit() ); + } + +/* for (i=0; i< r.count(); i++){ + fname = ""; + sname = r.field( i )->name(); + it.toFirst(); + for( ; it.current(); ++it ){ + if ( *it.current() == sname ) { + fname = it.currentKey(); + break; + } + } + printf("r:%s(%s)=%s\n", + ( const char *) fname, + ( const char *) sname, + ( const char *) r.value( i ).toString().local8Bit() ); + } +*/ +} + + + +/*! + * +*/ +bool +aDataTable::exec( QString query ) +{ + return Q3SqlCursor::exec( query ); +} + + + +QVariant +aDataTable::calc_rem(int fid, qulonglong id) +{ + aCfgItem o,fto; + QString t,oclass; + int ftid,oid; + QVariant v=""; + fto = mapReg[fid];// = md->find( ftid ); + if ( !fto.isNull() ) + { + if(p_reg[QString("%1").arg(fid)]==0) + { + p_reg.insert(QString("%1").arg(fid), new aARegister( fto, db )); + } + v = ((aARegister*)p_reg[QString("%1").arg(fid)])->getSaldo( QDateTime::currentDateTime(), + mapDim[fid], + id, + mapSum[fid]);//md->attr(s_field,mda_name)); + if(!v.isValid()) v = ""; + } + return v; +} + + +QVariant +aDataTable::calc_obj(int fid, qulonglong idd) +{ + aCfgItem o,fto; + QString t,oclass; + int ftid; + QVariant v=""; +// printf("calculate cat %d, %llu\n",fid, idd); + o = mapCat[fid]; + if( !o.isNull() ) + { + aCatalogue *pCat = (aCatalogue*)p_cat[QString("%1").arg(fid)]; +// printf("obj not null\n"); + if(pCat==0) + { + p_cat.insert(QString("%1").arg(fid), new aCatalogue( o, db )); + pCat = (aCatalogue*)p_cat[QString("%1").arg(fid)]; + } + pCat->select( idd ); + + if ( pCat->selected() ) + { +// printf("select ok\n"); + v = QVariant( pCat->displayString() ); + } + } + else + { + o = mapDoc[fid]; + if(!o.isNull()) + { + aDocument *pDoc = (aDocument*)p_doc[QString("%1").arg(fid)]; +// printf("obj not null\n"); + if(pDoc==0) + { + p_doc.insert(QString("%1").arg(fid), new aDocument( o, db )); + pDoc = (aDocument*)p_doc[QString("%1").arg(fid)]; + } + pDoc->select( idd ); + if ( pDoc->selected() ) + { + v = QVariant( pDoc->displayString() ); + } + } + } + + return v; +} + +/*! + * Calculate value object type fields. + */ +QVariant +aDataTable::calculateField( const QString &name ) +{ + QVariant v; + if(name=="system_icon") return v; + else return QVariant(""); +// return QVariant::Invalid; +} + +/*! + * Calculate value object type fields. + */ +QVariant +aDataTable::calcFieldValue( const QString &name ) +{ + + QVariant v="", fv=0; + int fid = 0; //, ftid; + qulonglong id = 0; + aCfgItem o, fto; + QString t, oclass; + if ( name.left(5)=="text_" ) + { + if(sysFieldExists(name.mid(5))) + { + fv = sysValue( name.mid( 5 ) ); + id = fv.toULongLong(); + } + else + { + id = 0; + } + fid = name.mid( 7 ).toInt(); + v = QVariant(""); + if ( fid && id ) + { + v=calc_obj(fid,id); + } + else + { + if(fid) + { + id = sysValue("id").toULongLong(); + v=calc_rem(fid,id); + } + } + } +// printf("calculate field %s\n", name.ascii()); + return v; +} + + + +/*! + * Gets list of user and calculation fields. + */ +QStringList +aDataTable::getUserFields() +{ + QStringList lst; + uint i; + const QString text_uf = "text_uf"; + for(i=0; iuid( mdobjId ); + aLog::print(aLog::Debug, QString("aDataTable new record with id=%1 for meta object with id=%2").arg(Uid).arg(mdobjId)); + + rec->setValue("id", QVariant( Uid ) ); + } + if ( insert() ) + { + if ( select(QString("id=%1").arg(Uid), false) ) + if ( first() ) + { + res = true; + } + else + { + aLog::print(aLog::Error, QString("aDataTable record with id=%1 not found").arg(Uid)); + } + } + return res; +} + + +bool +aDataTable::Copy() +{ + QSqlRecord *rec = new QSqlRecord( *editBuffer(true) ); + if ( New() ) + { + for ( unsigned int i=0; icount(); i++ ) + { + if ( rec->field( i ).name() != QString("id") ) + { + setValue( i, rec->value( i ) ); +// printf("field %s, before %s, after %s\n",rec->field( i )->name().ascii(), rec->value( i ).toString().ascii(), value( i ).toString().ascii()); + } + } + } + delete rec; + return Update(); +// Q_ULLONG Uid = db->uid( t->id ); +// r->setValue("id",Uid); +// if ( t->insert() ) return Uid; + +// return true; +} + + +bool +aDataTable::Delete() +{ + QSqlRecord *rec; + rec = primeDelete(); + del(); +// fNewNotUpdated = false; + return true; +} + + +bool +aDataTable::Update() +{ + QSqlRecord *rec; + + rec = Q3SqlCursor::primeUpdate(); + //for ( unsigned int i=0; icount(); i++ ) rec->setValue( i, value( i ) ); + update(); + QSqlError err = lastError(); + if(!err.type() == QSqlError::None) + { + aLog::print(aLog::Error, QString("%1 %2").arg(err.text()).arg(err.driverText()) ); + } + return true; +} + diff --git a/src/lib/asqltable.h b/src/lib/asqltable.h new file mode 100644 index 0000000..32f206c --- /dev/null +++ b/src/lib/asqltable.h @@ -0,0 +1,139 @@ +/**************************************************************************** +** $Id: asqltable.h,v 1.1 2008/11/05 21:16:28 leader Exp $ +** +** Header file of the Ananas database table of Ananas +** Designer and Engine applications +** +** Created : 20031201 +** +** Copyright (C) 2003-2004 Leader InfoTech. All rights reserved. +** +** This file is part of the Library of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.leaderit.ru/page=ananas or email sales@leaderit.ru +** See http://www.leaderit.ru/gpl/ for GPL licensing information. +** +** Contact org@leaderit.ru if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#ifndef ASQLTABLE_H +#define ASQLTABLE_H +#include +#include +#include "acfg.h" +//#include "aaregister.h" +//#include "adatarecord.h" + +// temporray define for old definitions +#define aSQLTable aDataTable + + +class aDatabase; +class aSQLField; + +/*! + * \~english + * Provides browsing and editing Ananas's sql tables mantained by Ananas.Designer. + * \~russian + * \brief Определяет программный интерфейс модели данных aDataTable. Наследует QSqlCursor. + * + * Позволяет работать с табличными представлениями данных, определенных метаданными бизнес схемы. + * \~ + */ +class ANANAS_EXPORT aDataTable : public Q3SqlCursor +{ +public: + aDatabase* db; + QString tableName; + bool selected; + + aSQLTable( aCfgItem context, aDatabase *adb ); + aSQLTable( const QString &tname, aDatabase *adb ); + virtual ~aSQLTable(); + void init( aCfgItem context, aDatabase *adb ); + void setObject(aCfgItem context); + void appendField( aSQLField * fieldinfo ); + void insertField( int pos, aSQLField * fieldinfo ); + void removeField( int pos ); + void clearFields(); + bool checkStructure( bool update ); + long getMdObjId(); + qulonglong getIdd(); + void printRecord(); + //QDict getUserFilter(); + //void setUserFilter( QDict ); + + virtual QVariant value ( int i ); + virtual QVariant value ( const QString & name ); + virtual void setValue ( int i, QVariant value ); + virtual bool setValue ( const QString & name, QVariant value ); + virtual QVariant sysValue ( const QString & name ); + virtual void setSysValue ( const QString & name, QVariant value ); + virtual bool sysFieldExists( const QString & name ); + + virtual QSqlRecord *primeInsert(); +// virtual QSqlRecord *primeUpdate(); + + virtual bool select( const QString & filter="", bool usefltr = true ); + virtual bool select( qulonglong id ); + virtual void clearFilter(); + virtual bool setFilter( const QString &name, const QVariant &value ); + virtual void setFilter( const QString& ); + virtual QString getFilter(); + virtual QString getNFilter(); + virtual bool exec( QString query ); + virtual QStringList getUserFields(); + virtual ERR_Code setMarkDeleted( bool Deleted ); + virtual bool isMarkDeleted(); + + virtual bool New(); + virtual bool Copy(); + virtual bool Delete(); + virtual bool Update(); + + virtual bool seek ( int i, bool relative = FALSE ); + virtual bool next (); + virtual bool prev (); + virtual bool first (); + virtual bool last (); + + +protected: + QVariant calcFieldValue( const QString &name ); + virtual QVariant calculateField( const QString &name ); + virtual QVariant calc_obj(int fid,qulonglong idd); + virtual QVariant calc_rem(int fid,qulonglong id); + void insertFieldInfo(aCfgItem cobj, bool calculated=true); + + long mdobjId; + +private: +// bool fNewNotUpdated; + aCfgItem obj; + aCfgItem init_obj; + aCfg* md; + Q3Dict p_cat; + Q3Dict p_doc; + Q3Dict p_reg; + QMap mapCat, mapReg, mapDoc; + QMap mapDim,mapSum; + QStringList fildsList; + Q3Dict fnames; + Q3Dict userFilter; +// QDict dataRecord; +// aDataRecord dataRecord; +// QSqlRecord r; +}; + +#endif diff --git a/src/lib/atests.cpp b/src/lib/atests.cpp new file mode 100644 index 0000000..31299c2 --- /dev/null +++ b/src/lib/atests.cpp @@ -0,0 +1,239 @@ +/**************************************************************************** +** $Id: atests.cpp,v 1.2 2008/11/08 20:16:35 leader Exp $ +** +** Tests functions source file of +** Ananas application library +** +** Created : 20051024 +** +** Copyright (C) 2003-2005 Grigory Panov, Yoshkar-Ola. +** +** This file is part of the Designer application of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.leaderit.ru/page=ananas or email sales@leaderit.ru +** See http://www.leaderit.ru/gpl/ for GPL licensing information. +** +** Contact org@leaderit.ru if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#include "atests.h" +#include "alog.h" +#include +#include +#include + +/*! + *\~english + * Writes text to log. + *\~russian + * Пишет текст в лог. + *\~ + * \param log_name - \~english Full path to logfile \~russian Полный путь к лог файлу \~ + * \param test_name - \~english Test name \~russian Имя теста \~ + * \param status - \~english OK, ERROR or SKIP \~russian OK, ОШИБКА или ПРОПУЩЕН \~ + * \param text - \~english Comment \~russian Комментарий \~ +*/ +void +aTests::print2log( const QString &log_name, + const QString &test_name, + const QString &status, + const QString &text) +{ + QString toWrite = QString("%1::%2::%3::%4\r\n")\ + .arg(QDateTime::currentDateTime().toString(Qt::ISODate).replace('T',' '))\ + .arg(test_name)\ + .arg(status)\ + .arg(text); + + QFile f; + if(log_name==QString::null) + { + f.open( QIODevice::WriteOnly, stdout ); + f.writeBlock((const char*)toWrite,strlen((const char*)toWrite)); + } + else + { + f.setName(log_name); + f.open( QIODevice::WriteOnly | QIODevice::Append ); + f.writeBlock((const char*)toWrite,strlen((const char*)toWrite)); + f.flush(); + } + f.close(); + +// else printf("error write to log\n"); +} + + +/*! + *\~english + * Reads config into QMap object. + *\~russian + * Считывает конфиг в объект QMap. + *\~ + * \param conf_name - \~english configfile name \~russian Путь к конфигу \~ + * \param log_name - \~english logfile name \~russian Путь к логу (не обязательно) \~ + * \return - \~english map with config values \~russian map со значениями конфига \~ +*/ +QMap +aTests::readConfig(const QString &conf_name,const QString &log_name) +{ + QMap map; + QString str, buff; + QStringList list; + QFile f(conf_name); + if(!f.exists()) + { + aLog::print(aLog::Error, QObject::tr("aTests file %1 not exists").arg(f.name())); + } + else + { + if(!f.open( QIODevice::ReadOnly )) + { + aLog::print(aLog::Error, QObject::tr("aTests file %1 not open for read").arg(f.name())); + } + else + { + while(!f.atEnd()) + { + str=f.readLine(1024); + if(!str.isEmpty()) + //--if(f.readLine(str,1024)!=-1) + { + if(str==QString::null || str[0]=='#' || str[0]=='\n') continue; + QString s = str.section("=",0,0); + map[s] = (str.right(str.length() - s.length()-1)).stripWhiteSpace(); + aLog::print(aLog::Debug, QString("map[%1] = %2").arg(s).arg(map[s])); + } + else + { + break; + } + } + f.close(); + } + } + return map; +} + + +/*! + *\~english + * Writes config. + *\~russian + * Пишет конфиг из объекта QMap. + *\~ + * \param conf_name - \~english configfile name \~russian Путь к конфигу \~ + * \param log_name - \~english logfile name \~russian Путь к логу (не обязательно) \~ + * \return - \~english true, if successful \~russian true - успех \~ +*/ +bool +aTests::writeConfig(const QString &conf_name, QMap map, const QString &log_name) +{ + QString str; + QFile f(conf_name); + if(!f.exists()) + { + aLog::print(aLog::Error, QObject::tr("aTests file %1 not exists").arg(f.name())); + } + //else + //{ + if(f.open( QIODevice::WriteOnly )) + { + QMap::Iterator it; + for ( it = map.begin(); it != map.end(); ++it ) + { + str= QString("%1=%2\n").arg(it.key()).arg(it.data()); + f.writeBlock((const char*)str,strlen((const char*)str)); + f.flush(); + } + f.close(); + if(log_name!=QString::null) + { + aTests::print2log(log_name,conf_name,"OK","write config"); + } + } + else + { + aLog::print(aLog::Error, QObject::tr("aTests file %1 not open for read").arg(f.name())); + return 0; + } + //} + return 1; +} +/*! + *\~english + * Writes line in log with name \a log_name + *\~russian + * Пишет строку в лог с именем \a log_name + *\~ + * \param log_name - \~english logfile name \~russian Путь к логу (не обязательно) \~ +*/ +void +aTests::printline2log(const QString &log_name) +{ + QString toWrite; + toWrite.fill('=',60); + toWrite+="\n"; + QFile f; + if(log_name==QString::null) + { + f.open( QIODevice::WriteOnly, stdout ); + f.writeBlock((const char*)toWrite,strlen((const char*)toWrite)); + } + else + { + f.setName(log_name); + f.open( QIODevice::WriteOnly | QIODevice::Append ); + f.writeBlock((const char*)toWrite,strlen((const char*)toWrite)); + f.flush(); + } + f.close(); +} + +/*! + *\~english + * Find parament in command line. + *\~russian + * Ищет параметр с именем \a requestedParam в коммандной строке и если находит, то возвращает его + * значение (то, что идет после знака = до первого пробела). Заменяет знак ~ на $(HOME) + *\~ + * \param argc - \~english parametr command line count \~russian число параметров коммандной строки \~ + * \param argv - \~english command line paraments \~russian параметры коммандной строки \~ + * \param requestedParam - \~english param for search \~russian параметр для поиска \~ + * \return - \~english parametr value \~russian значение параметра \~ +*/ +QString +aTests::parseCommandLine(int argc, char** argv, const QString requestedParam) +{ + + QString param,value; + for(int j=1;j + +/*! + * \~english + * Class contain static functions for test utilites + * \~russian + * \brief Класс содержит статические функции для утилит тестирования. + * + * Предназначен для использования при отладке и тестировании кода. + * \~ +*/ +class ANANAS_EXPORT aTests +{ + public: + + static QMap readConfig(const QString &cfg_name, const QString &log_name=QString::null); + static bool writeConfig(const QString &cfg_name,QMap cfg, const QString &log_name=QString::null); + static void print2log( const QString &log_name, + const QString &test_name, + const QString &status, + const QString &text=""); + + static void printline2log(const QString &log_name); + static QString parseCommandLine(int argc, char** argv, const QString requestedParam); + + private: + aTests(); +}; +#endif// ATESTS_H diff --git a/src/lib/atime.cpp b/src/lib/atime.cpp new file mode 100644 index 0000000..9cbadf0 --- /dev/null +++ b/src/lib/atime.cpp @@ -0,0 +1,119 @@ +/**************************************************************************** +** $Id: atime.cpp,v 1.1 2008/11/05 21:16:28 leader Exp $ +** +** Engine applications +** +** Created : 20041109 +** +** Copyright (C) 2003-2004 Grigory Panov, Yoshkar-Ola. +** +** This file is part of the Library of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.leaderit.ru/page=ananas or email sales@leaderit.ru +** See http://www.leaderit.ru/gpl/ for GPL licensing information. +** +** Contact org@leaderit.ru if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#include "atime.h" +//#include "adatabase.h" +//#include "adocjournal.h" + + + +/*! + *\en + * Constructor that create object aTime for work in ananas script. + *\_en + *\ru + * Конструктор, который создает aTime для работы в ананас скрипте. + *\_ru + */ +aTime::aTime(): QObject() +{ + time = new QTime; + +} + +/*! + *\en + * Destructor + *\_en + *\ru + * Деструктор + *\_ru + */ +aTime::~aTime() +{ + delete time; +} + +/*! + *\en + * Starts timer. + *\_en + *\ru + * Запускает таймер. + *\_ru + */ +void +aTime::start() +{ + time->start(); +} + + +/*! + *\en + * Restarts timer. + *\_en + *\ru + * Перезапускает таймер. + *\_ru + */ +int +aTime::restart() +{ + time->restart(); + return 0; +} + +/*! + *\en + * Gets elapsed time from last call of start() or restart() + *\_en + *\ru + * Возвращает количество миллисекунд с последнего запуска таймера. + *\_ru + */ +int +aTime::elapsed() +{ + return time->elapsed(); +} + +/*! + *\en + * Return current date for ananas.script + *\_en + *\ru + * Возвращает текущую дату в ISO формате. Используется для работы с Ананас.Скриптом + *\_ru + */ +QString +aTime::CurrentDate() +{ + return QDate::currentDate().toString(Qt::ISODate); +} + diff --git a/src/lib/atime.h b/src/lib/atime.h new file mode 100644 index 0000000..702af8b --- /dev/null +++ b/src/lib/atime.h @@ -0,0 +1,64 @@ +/**************************************************************************** +** $Id: atime.h,v 1.1 2008/11/05 21:16:28 leader Exp $ +** +** Header file of the Accumulation Register of Ananas +** Engine applications +** +** Created : 20031201 +** +** Copyright (C) 2003-2004 Leader InfoTech. All rights reserved. +** +** This file is part of the Library of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.leaderit.ru/page=ananas or email sales@leaderit.ru +** See http://www.leaderit.ru/gpl/ for GPL licensing information. +** +** Contact org@leaderit.ru if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#ifndef ATIME_H +#define ATIME_H + +#include +#include +//#include "airegister.h" +#include "ananas.h" + + + + +/*! + *\en + *\_en + *\ru + * \brief Сервисный класс для работы с объектом Время + *\_ru + */ +class ANANAS_EXPORT aTime : public QObject +{ + Q_OBJECT +public: + aTime(); + ~aTime(); +protected: + QTime *time; +public slots: + + virtual void start(); + virtual int restart(); + virtual int elapsed(); + virtual QString CurrentDate(); +}; + +#endif// ATIME_H diff --git a/src/lib/auser.cpp b/src/lib/auser.cpp new file mode 100644 index 0000000..7caeed7 --- /dev/null +++ b/src/lib/auser.cpp @@ -0,0 +1,402 @@ +/**************************************************************************** +** $Id: auser.cpp,v 1.1 2008/11/05 21:16:28 leader Exp $ +** +** User object implementation file of +** Ananas application library +** +** Created : 20050527 +** +** Copyright (C) 2003-2005 Grigory Panov, Yoshkar-Ola. +** +** This file is part of the Designer application of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.leaderit.ru/page=ananas or email sales@leaderit.ru +** See http://www.leaderit.ru/gpl/ for GPL licensing information. +** +** Contact org@leaderit.ru if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#include "auser.h" +//Added by qt3to4: +#include +//#include "ananas.h" + + +/*!\en Constructor for concrete object class creating + * \_en + * \ru Конструктор для создания конкретного объекта класса + * \_ru + */ +aUser::aUser( qulonglong userId, aDatabase * adb ):aObject("",adb) +{ + + initObject(); + Select(userId); + +} +/*!\en Constructor for abstract object class creating + * \_en + * \ru Конструктор для создания абстрактного объекта класса + * \_ru + */ +aUser::aUser( aDatabase * adb ):aObject("",adb) +{ + +// Select(userId); + initObject(); +} + + + + +/*!\en Reimplement base class function + * \_en + * \ru Переопределяет функцию базового класса + * \_ru + */ +ERR_Code +aUser::initObject() +{ + ERR_Code err = aObject::initObject(); // don't handle errors + //if ( err ) return err; + //aCfgItem e;// = md->find( obj, md_group ), e = md->find( obj, md_element ); + err = tableInsert( db_users, ""); + + if(err) return err; + err = tableInsert( db_user_roles, md_user_roles ); + return err; +} + +/*!\en Returns list of roles, (un)assigned for this user. List elements must be deleted in called procedure. + * \_en + * \ru Возвращает список ролей, (не)назначенных данному пользователю. Элементы списка должны быть удалены в вызывающей процедуре + * \_ru + * \param assibned \en true for return assigned roles, false for retun unassigned roles\_en + * \ru true для возврата назначенных ролей, false для возврата неназначенных ролей \_ru + */ +Q3ValueList< aRole *> +aUser::getRoles(bool assigned) +{ + Q3ValueList list; + qulonglong rid; + aRole *rl = new aRole(db); + rl->Select(); + if(rl->First()) + { + do + { + rid = rl->sysValue("id").toULongLong(); + if(!(hasRole(rid) ^ assigned))// !XOR + { + aRole *r = new aRole(rid,db); + list.insert(list.end(),r); + } + }while(rl->Next()); + } + delete rl; + return list; +} + +/*!\en Gets user id + * \_en + * \ru Получение id пользователя + * \_ru + * \param login \en user login \_en \ru логин пользователя\_ru + * \param password \en user password \_en \ru пассворд пользователя\_ru + * \return \en 0 if login and password has no match, user id otherwise \_en + * \ru 0 если логин и пароль не совпадают, в противном случае id пользователя\_ru + */ +qulonglong +aUser::getUserId(const QString &login, const QString &password) +{ + aSQLTable * t = table(); + t->select(QString("login='%1' AND password='%2'").arg(login).arg(password)); + if(t->first()) + { + return t->sysValue( "id").toULongLong(); + } + else + { + return 0; + } + +} + + + +/*!\en Updates table values + * \_en + * \ru Обновляет значения таблиц + * \_ru + */ +ERR_Code +aUser::Update() +{ + ERR_Code err = aObject::Update(); + if ( !err ){ + err = TableUpdate( md_user_roles ); + } + return err; +} + + +/*!\en Selected table and clear filter + * \_en + * \ru Выбирает таблицу и сбрасывает фильтр + * \_ru + */ +ERR_Code +aUser::Select( ) +{ + aSQLTable * t = table(); + if ( !t ) return err_notable; +// setSelected(true,md_group); +// setSelected(true); + QString flt = ""; +// groupSelect(); + if ( t->select( flt ) ) + if ( t->first() ) + { + setSelected(true); + } + else return err_notselected; + else return err_selecterror; + return err_noerror; +} + +/*!\en Select table and set filter to user with given id + * \_en + * \ru Выбирает таблицу и устанавлиет фильтр на пользователя с переданным в параметре id + * \_ru + * \param id - \en user id \_en \ru id пользователя \_ru + */ +ERR_Code +aUser::Select( qulonglong id) +{ + aSQLTable * t = table(); + if ( !t ) return err_notable; +// setSelected(true,md_group); +// setSelected(true); + QString flt; + flt = QString("id=%1").arg(id); +// groupSelect(); + if ( t->select( flt ) ) + if ( t->first() ) + { + setSelected(true); + } + else return err_notselected; + else return err_selecterror; + return err_noerror; +} + +/*!\en Assign role to user + * \_en + * \ru Назначет пользователю роль + * \_ru + * \param roleId - \en id role to asssign \_en \ru id роли для назначения\_ru + */ +ERR_Code +aUser::addRole( qulonglong roleId ) +{ + aSQLTable *tg = table( md_user_roles ); + if (!tg ) return err_notable; + setSelected(true, md_user_roles); +// tg->select(parentId); +// setSelected(true,md_group); + qulonglong idg; + QSqlRecord* rec = tg->primeInsert(); // get edit buffer for table groups + idg = sysValue("id").toULongLong(); + //printf( "idg=%lu\n", idg ); + rec->setValue("id",idg ); + rec->setValue("idr",roleId ); + tg->insert(); // insert record + //tg->update(); +return err_noerror; +} + +/*!\en Drop role + * \_en + * \ru Сбрасывает назначение роли пользователю + * \_ru + * \param roleId - \en id role to drop \_en + * \ru id роли, назначение которой будет сброшено\_ru + */ +ERR_Code +aUser::delRole( qulonglong roleId ) +{ + aSQLTable *t = table( md_user_roles ); + qulonglong ide=0; + if ( !t ) return err_notable; + ide = sysValue("id").toULongLong(); + t->select(QString("id=%1 and idr=%2").arg(ide).arg(roleId)); + if ( t->first() ) + { + //printf("del usr_role \n"); + t->primeDelete(); + t->del(); +// setSelected( false ); + } + else return err_notselected; + return err_noerror; +return err_noerror; +} + +/*!\en Checks role assign + * \_en + * \ru Проверяет, назначена ли роль данному пользователю + * \_ru + * \param rid - \en role id to check \_en + * \ru id роль для проверки \_ru + * \return \en true, if role assigned, false otherwise \_en + * \ru true, если роль назначена, false в противном случае \_ru + */ +bool +aUser::hasRole(qulonglong rid) +{ + aSQLTable *tg = table( md_user_roles ); + if (!tg ) return err_notable; + tg->select(QString("id=%1 AND idr=%2").arg(sysValue("id").toULongLong()).arg(rid)); + if(tg->first()) + return true; + else return false; +// setSelected(true, md_user_roles); + + +} + +/*!\en + * Inserts new element in elements table + \_en \ru + * Вставляет новый элемент в таблицу элементов + *\_ru + * \param login - \en login \_en \ru логин \_ru + * \param password - \en password \_en \ru пароль \_ru + * \param firstName - \en first name \_en \ru имя пользователя \_ru + * \param lastName - \en last name \_en \ru фамилия пользователя \_ru + */ +ERR_Code +aUser::New(const QString &login, + const QString &password, + const QString &firstName, + const QString &lastName) +{ + aSQLTable *te = table(); + if (!te) return err_notable; + QSqlRecord *rec; + qulonglong ide; + rec = te->primeInsert(); // get edit buffer for table elements + ide = rec->value("id").toULongLong(); +// printf(">>>id=%lu\n",ide); + rec->setValue("id",ide); // set defult values for all user fields = id + rec->setValue( "login", login ); + rec->setValue( "password", password ); + rec->setValue( "fname", firstName ); + rec->setValue( "lname", lastName ); + te->insert(); // insert edit buffer as new line in table + te->select(QString("id=%1").arg(ide),false); // set cursor to inserted record + te->first(); + setSelected(true); + return err_noerror; +} + + + + + +/*!\en + * Delets user. + \_en \ru + * удаляет пользователя. + *\_ru + */ +ERR_Code +aUser::Delete() +{ + aSQLTable * t = table(); + qulonglong ide=0; + if ( !t ) return err_notable; + ide = t->sysValue("id").toULongLong(); + if ( ide ) + { + // printf("ide=" LLU_SPEC "\n",ide); + t->primeDelete(); + t->del(); +//TODO: clear roles, assigned to user + setSelected( false ); + } + else return err_notselected; + return err_noerror; +} + + +/*!\en Updates roles table values + *\_en + * \ru Обновляет значение таблицы ролей + *\_ru + */ +ERR_Code +aUser::UpdateRole() +{ + return TableUpdate( md_user_roles ); +} + + +/*!\en Next + *\_en + * \ru + *\_ru + */ +bool +aUser::Next() +{ + return aObject::Next( ); //return !groupSelect(); + //else return false; +} + +/*!\en Rpev + *\_en \ru + *\_ru + */ +bool +aUser::Prev() +{ + return aObject::Prev( ); //return !groupSelect(); +// else return false; +} + +/*!\en First + *\_en \ru + *\_ru + */ +bool +aUser::First() +{ + return aObject::First( ); //return !groupSelect(); + //else return false; +} + +/*!\en Last + *\_en \ru + *\_ru + */ +bool +aUser::Last() +{ + return aObject::Last( ); //return !groupSelect(); + //else return false; +} + + + diff --git a/src/lib/auser.h b/src/lib/auser.h new file mode 100644 index 0000000..f49d9cc --- /dev/null +++ b/src/lib/auser.h @@ -0,0 +1,95 @@ +/**************************************************************************** +** $Id: auser.h,v 1.1 2008/11/05 21:16:28 leader Exp $ +** +** User object header file of +** Ananas application library +** +** Created : 20050527 +** +** Copyright (C) 2003-2005 Grigory Panov, Yoshkar-Ola. +** +** This file is part of the Designer application of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.leaderit.ru/page=ananas or email sales@leaderit.ru +** See http://www.leaderit.ru/gpl/ for GPL licensing information. +** +** Contact org@leaderit.ru if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#ifndef AUSER_H +#define AUSER_H + +#include "arole.h" +#include "adatabase.h" +#include "acfg.h" +#include "aobject.h" +#include +//class aDatabase; +//class aRole; +//class aObject; + + + +/*! + * \en + * Not visual object used for working with users in database. + * \_en + * \ru + * \brief Определяет программный интерфейс для управления пользователями. Не используется в настоящий момент. + * Наследует aObject. + * \_ru +*/ +class ANANAS_EXPORT aUser: public aObject +{ + Q_OBJECT +public: + aUser(); + aUser(qulonglong userId, aDatabase * adb); + aUser(aDatabase * adb); + virtual ERR_Code initObject(); + +//public slots: + + virtual ERR_Code New( const QString &login, + const QString &passwd="", + const QString &Name="", + const QString &LastName=""); + + virtual ERR_Code Delete(); + virtual ERR_Code Update(); + virtual ERR_Code Select(); + virtual ERR_Code Select( qulonglong userId ); + + virtual ERR_Code addRole( qulonglong roleId ); + virtual ERR_Code delRole( qulonglong roleId ); + virtual ERR_Code UpdateRole(); + + Q3ValueList< aRole *> getRoles( bool assigned); + + bool hasRole( qulonglong roleId); +// virtual ERR_Code setPassword( const QString & ); + //virtual ERR_Code setLogin( const QString & ); + //virtual ERR_Code setFirstName( const QString & ); + //virtual ERR_Code setLastName( const QString & ); + + virtual qulonglong getUserId( const QString &login, const QString &password ); + //virtual ERR_Code getRoles(QValueList *lst); + bool First(); + bool Next(); + bool Last(); + bool Prev(); +}; + + +#endif// AUSER_H diff --git a/src/lib/dialogs/awindowslist.cpp b/src/lib/dialogs/awindowslist.cpp new file mode 100644 index 0000000..2427415 --- /dev/null +++ b/src/lib/dialogs/awindowslist.cpp @@ -0,0 +1,176 @@ +/**************************************************************************** +** $Id: awindowslist.cpp,v 1.1 2008/11/05 21:16:28 leader Exp $ +** +** Main window of Ananas Designer applications +** +** Created : 20031201 +** +** Copyright (C) 2003-2004 Leader InfoTech. All rights reserved. +** +** This file is part of the Designer application of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.leaderit.ru/page=ananas or email sales@leaderit.ru +** See http://www.leaderit.ru/gpl/ for GPL licensing information. +** +** Contact org@leaderit.ru if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#include "awindowslist.h" +#include "acfg.h" + +/*! + * \~english + * Constructor + * \~russian + * Конструктор. + * \~ + */ +aWindowsList::aWindowsList() + : QWidget() +{ +} + + +/*! + * \~english + * Destructor + * \~russian + * Деструктор. + * \~ + */ +aWindowsList::~aWindowsList() +{ +} + + +/*! + * \~english + * Insert window into list. + * \~russian + * Добавляет ссылку на окно в список. + * \~ + * \param id - \~english object class id \~russian идентификатор класса объекта \~ + * \param window - \~english link to form \~russian ссылка на форму \~ + * \param ido - \~english object id (default 0) \~russian идентификатор объекта (по умолчанию 0) \~ + */ +void +aWindowsList::insert( int id, QWidget *window, qulonglong ido ) +{ + list.insert( conv( id, ido ), window ); +} + +/*! + * \~english + * Remove window from list. + * \~russian + * Удаляет окно из списка. + * \~ + * \param id - \~english object class id \~russian идентификатор класса объекта \~ + * \param ido - \~english object id (default 0) \~russian идентификатор объекта (по умолчанию 0) \~ + */ +void +aWindowsList::remove( int id, qulonglong ido ) +{ + list.remove( conv( id, ido ) ); +} + +/*! + * \~english + * Remove window from list. + * \~russian + * Удаляет окно из списка. + * \~ + * \param window - \~english link to form \~russian ссылка на форму \~ + */ +void +aWindowsList::remove( QWidget *window ) +{ + Q3DictIterator it( list ); + for ( ; it.current(); ++it ) + { + if ( it.current() == window ) { + list.remove( it.currentKey() ); + break; + } + } +} + +/*! + * \~english + * Find window with \a id and \a ido. + * \~russian + * Ищет окно по его \a id и \a ido + * \~ + * \param id - \~english object class id \~russian идентификатор класса объекта \~ + * \param ido - \~english object id (default 0) \~russian идентификатор объекта (по умолчанию 0) \~ + * \return \~english true, if window found \~russian true, если окно найдено. \~ + */ +bool +aWindowsList::find( int id, qulonglong ido ) +{ + if ( !list.find( conv( id, ido ) ) ) return FALSE; + return TRUE; +} + +/*! + * \~english + * Find object in list with link + * \~russian + * Ищет объект в списке по ссылке. + * \~ + * \param window - \~english link to form \~russian ссылка на форму \~ + * \return \~english true, if window found \~russian true, если окно найдено. \~ + */ +bool +aWindowsList::find( QWidget *window ) +{ + Q3DictIterator it( list ); + for ( ; it.current(); ++it ) if ( it.current() == window ) return TRUE; + return FALSE; +} + + +/*! + * \~english + * Get window with \a id and \a ido. + * \~russian + * Функция получения ссылки на окно по его \a id и \a ido + * \~ + * \param id - \~english object class id \~russian идентификатор класса объекта \~ + * \param ido - \~english object id (default 0) \~russian идентификатор объекта (по умолчанию 0) \~ + * \return \~english link to window, or 0 if window not found \~russian ссылка на окно или 0\~ + */ +QWidget * +aWindowsList::get( int id, qulonglong ido ) +{ + return list.find( conv( id, ido ) ); +} + + +/*! + * \~english + * Create key for store in list. + * \~russian + * Создает ключ из параметров \a id и \a ido + * \~ + * \param id - \~english object class id \~russian идентификатор класса объекта \~ + * \param ido - \~english object id (default 0) \~russian идентификатор объекта (по умолчанию 0) \~ + * \return \~english key \~russian ключ \~ + */ +QString +aWindowsList::conv( int id, qulonglong ido ) +{ + return QString("%1_%2").arg( id ).arg( ido ); +} + diff --git a/src/lib/dialogs/awindowslist.h b/src/lib/dialogs/awindowslist.h new file mode 100644 index 0000000..92a1dab --- /dev/null +++ b/src/lib/dialogs/awindowslist.h @@ -0,0 +1,69 @@ +/**************************************************************************** +** $Id: awindowslist.h,v 1.1 2008/11/05 21:16:28 leader Exp $ +** +** Main window of Ananas Designer applications +** +** Created : 20031201 +** +** Copyright (C) 2003-2004 Leader InfoTech. All rights reserved. +** +** This file is part of the Designer application of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.leaderit.ru/page=ananas or email sales@leaderit.ru +** See http://www.leaderit.ru/gpl/ for GPL licensing information. +** +** Contact org@leaderit.ru if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#ifndef AWINDOWSLIST_H +#define AWINDOWSLIST_H + +#include "ananasglobal.h" + + +#include +#include + +/*! + * \~english + * Contains list of opened window. + * \~russian + * \brief Класс определяет интерфейс управления списком открытых окон. + * Наследует QWidget. + * + * Объект класса содержит ссылки на все открытые окна. При открыти окна проверяется, есть ли оно в списке, + * и если есть, то ему просто передается фокус. + * \~ + */ +class ANANAS_EXPORT aWindowsList : public QWidget +{ + Q_OBJECT +public: + aWindowsList(); + virtual ~aWindowsList(); + + void insert( int id, QWidget *window, qulonglong ido = 0 ); + void remove( int id, qulonglong ido = 0 ); + void remove( QWidget *window ); + bool find( int id, qulonglong ido = 0 ); + bool find( QWidget *window ); + QWidget *get( int id, qulonglong ido = 0 ); + +private: + Q3Dict list; + QString conv( int id, qulonglong ido ); +}; + + +#endif //AWINDOWSLIST_H diff --git a/src/lib/dialogs/deditrc.cpp b/src/lib/dialogs/deditrc.cpp new file mode 100644 index 0000000..8ce6e30 --- /dev/null +++ b/src/lib/dialogs/deditrc.cpp @@ -0,0 +1,127 @@ +#include "deditrc.h" + +#include +//#include +#include +#include +#include + +#include "atests.h" +/* + * Constructs a dEditRC as a child of 'parent', with the + * name 'name' and widget flags set to 'f'. + * + * The dialog will by default be modeless, unless you set 'modal' to + * true to construct a modal dialog. + */ +dEditRC::dEditRC(QWidget* parent, const char* name, bool modal, Qt::WindowFlags fl) + : QDialog(parent, name, modal, fl) +{ + setupUi(this); + +} + +/* + * Destroys the object and frees any allocated resources + */ +dEditRC::~dEditRC() +{ + // no need to delete child widgets, Qt does it all for us +} + +/* + * Sets the strings of the subwidgets using the current + * language. + */ +void dEditRC::languageChange() +{ + retranslateUi(this); +} + + + +void dEditRC::setdata(QString nameRC, rcListViewItem *item) +{ +// QFile f; +// QString s, sv, sn; +// char buf[1025]; + it = item; + QMap cfg; + + cfg = aTests::readConfig(QDir::convertSeparators(nameRC)); + eRCFile->setText(QDir::convertSeparators(nameRC)); + eDBType->setCurrentItem(0); + + eDBTitle->setText(cfg["dbtitle"]); + eDBName->setText(cfg["dbname"]); + eDBUserName->setText(cfg["dbuser"]); + ePass->setText(cfg["dbpass"]); + eDBHost->setText(cfg["dbhost"]); + eDBPort->setText(cfg["dbport"]); + eCfgName->setText(QDir::convertSeparators(cfg["configfile"])); + if(cfg["dbtype"]=="postgres") eDBType->setCurrentItem(3); + if(cfg["dbtype"]=="mysql") eDBType->setCurrentItem(2); + if(cfg["dbtype"]=="internal") eDBType->setCurrentItem(1); + eWorkDir->setText(QDir::convertSeparators(cfg["workdir"])); +} + + +void dEditRC::updatecfg() +{ + QMap cfg; + + cfg["dbtitle"] = eDBTitle->text(); + cfg["dbname"] = eDBName->text(); + if(eDBType->currentItem()==1) cfg["dbtype"] ="internal"; + if(eDBType->currentItem()==2) cfg["dbtype"] ="mysql"; + if(eDBType->currentItem()==3) cfg["dbtype"]= "postgres"; + cfg["dbuser"] = eDBUserName->text(); + cfg["dbpass"] = ePass->text(); + cfg["dbhost"] = eDBHost->text(); + cfg["dbport"] = eDBPort->text(); + cfg["workdir"] = QDir::convertSeparators(eWorkDir->text()); + cfg["configfile"]= QDir::convertSeparators(eCfgName->text()); + + aTests::writeConfig(QDir::convertSeparators(eRCFile->text()),cfg); +} + + + +void dEditRC::onOK() +{ + updatecfg(); + it->rcfile = QDir::convertSeparators(eRCFile->text()); + it->setText(0,eDBTitle->text()); + accept(); +} + + +void dEditRC::onRCFile() +{ + Q3FileDialog fd( QString::null, + tr("ananas config resource (*.rc)"), + 0, 0, TRUE ); + fd. setMode ( Q3FileDialog::AnyFile ); + fd.setSelection( QDir::convertSeparators(eRCFile->text())); + if ( fd.exec() == QDialog::Accepted ) { + eRCFile->setText(QDir::convertSeparators(fd.selectedFile())); + setdata(eRCFile->text(),it); + } else { + return; + } +} + + +void dEditRC::onCFGFile() +{ + Q3FileDialog fd( QString::null, + tr("ananas config file (*.cfg)"), + 0, 0, TRUE ); + fd. setMode ( Q3FileDialog::AnyFile ); + fd.setSelection( QDir::convertSeparators(eCfgName->text())); + if ( fd.exec() == QDialog::Accepted ) { + eCfgName->setText(QDir::convertSeparators(fd.selectedFile())); + } else { + return; + } +} diff --git a/src/lib/dialogs/deditrc.h b/src/lib/dialogs/deditrc.h new file mode 100644 index 0000000..af330f9 --- /dev/null +++ b/src/lib/dialogs/deditrc.h @@ -0,0 +1,36 @@ +#ifndef DEDITRC_H +#define DEDITRC_H + +#include "ui_deditrc.h" + +class ANANAS_EXPORT dEditRC : public QDialog, public Ui::dEditRC +{ + Q_OBJECT + +public: + dEditRC(QWidget* parent = 0, const char* name = 0, bool modal = false, Qt::WindowFlags fl = 0); + ~dEditRC(); + +public slots: + virtual void setdata( QString nameRC, rcListViewItem * item ); + virtual void updatecfg(); + +signals: + void onOk(QString rc); + +protected slots: + virtual void languageChange(); + + virtual void onCFGFile(); + + +private: + rcListViewItem *it; + +private slots: + virtual void onOK(); + virtual void onRCFile(); + +}; + +#endif // DEDITRC_H diff --git a/src/lib/dialogs/deditrc.ui b/src/lib/dialogs/deditrc.ui new file mode 100644 index 0000000..a512e9a --- /dev/null +++ b/src/lib/dialogs/deditrc.ui @@ -0,0 +1,460 @@ + + + + ANANAS_EXPORT + dEditRC + + + + 0 + 0 + 777 + 402 + + + + Resource file + + + + + + + + + 180 + 0 + + + + Resource file name + + + false + + + + + + + + + + + 30 + 32767 + + + + ... + + + + + + + + + + + + 180 + 0 + + + + Data base header + + + false + + + + + + + + + + + + + + + 180 + 0 + + + + Data base name + + + false + + + + + + + + + + + + + + + 180 + 0 + + + + + 160 + 32767 + + + + Data base server type + + + false + + + + + + + false + + + false + + + + Unknown + + + + + internal + + + + + mysql + + + + + postgres + + + + + + + + + + + + + 180 + 0 + + + + Data base server address + + + false + + + + + + + + + + + + + + + 180 + 0 + + + + Data base server port + + + false + + + + + + + + + + + 146 + 21 + + + + Expanding + + + Horizontal + + + + + + + + + + + + 180 + 0 + + + + Data base server user + + + false + + + + + + + + + + + + + + + 180 + 0 + + + + Data base server password + + + false + + + + + + + QLineEdit::Password + + + + + + + + + + + + 180 + 0 + + + + Work directory + + + false + + + + + + + + + + + + + + + 180 + 0 + + + + Configuration file name + + + false + + + + + + + + + + + 30 + 32767 + + + + ... + + + + + + + + + + 130 + 16 + + + + Expanding + + + Vertical + + + + + + + + + + 470 + 21 + + + + Expanding + + + Horizontal + + + + + + + + 80 + 32767 + + + + OK + + + true + + + + + + + + 20 + 21 + + + + Fixed + + + Horizontal + + + + + + + + 80 + 32767 + + + + Cancel + + + + + + + + + qPixmapFromMimeSource + + eRCFile + bFileRC + eDBTitle + eDBName + eDBType + eDBHost + eDBPort + eDBUserName + ePass + eWorkDir + eCfgName + bFileCFG + bOK + bCancel + + + rclistviewitem.h + qstringlist.h + ananasglobal.h + + + + bCancel + clicked() + dEditRC + reject() + + + bFileRC + clicked() + dEditRC + onRCFile() + + + bOK + clicked() + dEditRC + onOK() + + + bFileCFG + clicked() + dEditRC + onCFGFile() + + + diff --git a/src/lib/dialogs/dhelpcfgform.cpp b/src/lib/dialogs/dhelpcfgform.cpp new file mode 100644 index 0000000..fb548f9 --- /dev/null +++ b/src/lib/dialogs/dhelpcfgform.cpp @@ -0,0 +1,42 @@ +#include "dhelpcfgform.h" + +#include +#include +#include + +/* + * Constructs a HelpCfgForm as a child of 'parent', with the + * name 'name' and widget flags set to 'f'. + * + * The dialog will by default be modeless, unless you set 'modal' to + * true to construct a modal dialog. + */ +HelpCfgForm::HelpCfgForm(QWidget* parent, const char* name, bool modal, Qt::WindowFlags fl) + : QDialog(parent, name, modal, fl) +{ + setupUi(this); + + init(); +} + +/* + * Destroys the object and frees any allocated resources + */ +HelpCfgForm::~HelpCfgForm() +{ + // no need to delete child widgets, Qt does it all for us +} + +/* + * Sets the strings of the subwidgets using the current + * language. + */ +void HelpCfgForm::languageChange() +{ + retranslateUi(this); +} + +void HelpCfgForm::init() +{ + textEdit1->setText( tr("Make group, item, set item paramert and press Ok button. See http://ananas.lrn.ru/index.php?title=Manual:Disigner for details" )); +} diff --git a/src/lib/dialogs/dhelpcfgform.h b/src/lib/dialogs/dhelpcfgform.h new file mode 100644 index 0000000..785f249 --- /dev/null +++ b/src/lib/dialogs/dhelpcfgform.h @@ -0,0 +1,22 @@ +#ifndef HELPCFGFORM_H +#define HELPCFGFORM_H + +#include "ui_dhelpcfgform.h" + + +class HelpCfgForm : public QDialog, public Ui::HelpCfgForm +{ + Q_OBJECT + +public: + HelpCfgForm(QWidget* parent = 0, const char* name = 0, bool modal = false, Qt::WindowFlags fl = 0); + ~HelpCfgForm(); + + virtual void init(); + +protected slots: + virtual void languageChange(); + +}; + +#endif // HELPCFGFORM_H diff --git a/src/lib/dialogs/dhelpcfgform.ui b/src/lib/dialogs/dhelpcfgform.ui new file mode 100644 index 0000000..6f8e77b --- /dev/null +++ b/src/lib/dialogs/dhelpcfgform.ui @@ -0,0 +1,94 @@ + + + + + HelpCfgForm + + + + 0 + 0 + 608 + 508 + + + + Create busines shema + + + + + + Qt::RichText + + + + + + Q3TextEdit::WidgetWidth + + + false + + + + + + + + 201 + 20 + + + + Expanding + + + Horizontal + + + + + + + + 171 + 20 + + + + Expanding + + + Horizontal + + + + + + + + 0 + 0 + 0 + 0 + + + + Close + + + + + + + qPixmapFromMimeSource + + + closeButton + clicked() + HelpCfgForm + accept() + + + diff --git a/src/lib/dialogs/dialogs.pri b/src/lib/dialogs/dialogs.pri new file mode 100644 index 0000000..003e3d4 --- /dev/null +++ b/src/lib/dialogs/dialogs.pri @@ -0,0 +1,24 @@ +HEADERS += \ + dialogs/deditrc.h \ + dialogs/dhelpcfgform.h \ + dialogs/dimportdb.h \ + dialogs/dlogin.h \ + dialogs/dselectdb.h \ + dialogs/messageswindow.h \ + dialogs/awindowslist.h + +SOURCES += \ + dialogs/awindowslist.cpp \ + dialogs/deditrc.cpp \ + dialogs/dhelpcfgform.cpp \ + dialogs/dimportdb.cpp \ + dialogs/dlogin.cpp \ + dialogs/dselectdb.cpp \ + dialogs/messageswindow.cpp + + +FORMS += \ + dialogs/deditrc.ui \ + dialogs/dhelpcfgform.ui \ + dialogs/dlogin.ui \ + dialogs/dselectdb.ui diff --git a/src/lib/dialogs/dimportdb.cpp b/src/lib/dialogs/dimportdb.cpp new file mode 100644 index 0000000..8f3ead2 --- /dev/null +++ b/src/lib/dialogs/dimportdb.cpp @@ -0,0 +1,64 @@ +/**************************************************************************** +** Form implementation generated from reading ui file 'deditrc.ui' +** +** Created: Пнд Фев 13 14:29:13 2006 +** by: The User Interface Compiler ($Id: dimportdb.cpp,v 1.1 2008/11/05 21:16:28 leader Exp $) +** +** WARNING! All changes made in this file will be lost! +****************************************************************************/ + +#include "dimportdb.h" +#include "atests.h" +#include +#include +#include +#include + +dImportDB::dImportDB( QWidget* parent, const char* name, bool modal, Qt::WFlags fl ) + : dEditRC( parent, name, modal, fl ) +{ + if ( !name ) + setName( "dImportDB" ); + languageChange(); + +} + +/* + * Destroys the object and frees any allocated resources + */ +dImportDB::~dImportDB() +{ + // no need to delete child widgets, Qt does it all for us +} + +/* + * Sets the strings of the subwidgets using the current + * language. + */ +void +dImportDB::languageChange() +{ + dEditRC::languageChange(); + setCaption( tr( "Resource file" ) ); + textLabel8_2->setText( tr( "archive file" ) ); + bOK->setText( tr( "Import" ) ); +} + +void +dImportDB::onCFGFile() +{ + Q3FileDialog fd( QString::null, + tr("any files (*)"), + 0, 0, TRUE ); + fd.setMode(Q3FileDialog::AnyFile); + fd.addFilter(tr("ananas business schema archiff file (*.bsa)")); + fd.setSelection( QDir::convertSeparators(eCfgName->text())); + if ( fd.exec() == QDialog::Accepted ) + { + eCfgName->setText(QDir::convertSeparators(fd.selectedFile())); + } + else + { + return; + } +} diff --git a/src/lib/dialogs/dimportdb.h b/src/lib/dialogs/dimportdb.h new file mode 100644 index 0000000..2c011d9 --- /dev/null +++ b/src/lib/dialogs/dimportdb.h @@ -0,0 +1,30 @@ +/**************************************************************************** +** Form interface generated from reading ui file 'deditrc.ui' +** +** Created: Пнд Фев 13 14:06:55 2006 +** by: The User Interface Compiler ($Id: dimportdb.h,v 1.1 2008/11/05 21:16:28 leader Exp $) +** +** WARNING! All changes made in this file will be lost! +****************************************************************************/ + +#ifndef DIMPORTDB_H +#define DIMPORTDB_H + +#include "ananasglobal.h" +#include "deditrc.h" + +class ANANAS_EXPORT dImportDB : public dEditRC +{ + Q_OBJECT + +public: + dImportDB( QWidget* parent = 0, const char* name = 0, bool modal = FALSE, Qt::WFlags fl = 0 ); + ~dImportDB(); + + +protected slots: + virtual void languageChange(); + virtual void onCFGFile(); +}; + +#endif // DIMPORTDB_H diff --git a/src/lib/dialogs/dlogin.cpp b/src/lib/dialogs/dlogin.cpp new file mode 100644 index 0000000..a1c2a71 --- /dev/null +++ b/src/lib/dialogs/dlogin.cpp @@ -0,0 +1,52 @@ +#include "dlogin.h" + +#include +#include +#include + +/* + * Constructs a dLogin as a child of 'parent', with the + * name 'name' and widget flags set to 'f'. + * + * The dialog will by default be modeless, unless you set 'modal' to + * true to construct a modal dialog. + */ +dLogin::dLogin(QWidget* parent, const char* name, bool modal, Qt::WindowFlags fl) + : QDialog(parent, name, modal, fl) +{ + setupUi(this); + + init(); +} + +/* + * Destroys the object and frees any allocated resources + */ +dLogin::~dLogin() +{ + // no need to delete child widgets, Qt does it all for us +} + +/* + * Sets the strings of the subwidgets using the current + * language. + */ +void dLogin::languageChange() +{ + retranslateUi(this); +} + +void dLogin::init() +{ + username = ""; + password = ""; +} + + +void dLogin::buttonOK() +{ + username = eName->text(); + password = ePassword->text(); + accept(); +} + diff --git a/src/lib/dialogs/dlogin.h b/src/lib/dialogs/dlogin.h new file mode 100644 index 0000000..aaf31bc --- /dev/null +++ b/src/lib/dialogs/dlogin.h @@ -0,0 +1,26 @@ +#ifndef DLOGIN_H +#define DLOGIN_H + +#include "ui_dlogin.h" + + +class ANANAS_EXPORT dLogin : public QDialog, public Ui::dLogin +{ + Q_OBJECT + +public: + dLogin(QWidget* parent = 0, const char* name = 0, bool modal = false, Qt::WindowFlags fl = 0); + ~dLogin(); + + QString username, password; + +public slots: + virtual void init(); + virtual void buttonOK(); + +protected slots: + virtual void languageChange(); + +}; + +#endif // DLOGIN_H diff --git a/src/lib/dialogs/dlogin.ui b/src/lib/dialogs/dlogin.ui new file mode 100644 index 0000000..cf27a3b --- /dev/null +++ b/src/lib/dialogs/dlogin.ui @@ -0,0 +1,96 @@ + + + + ANANAS_EXPORT + dLogin + + + + 0 + 0 + 303 + 89 + + + + Ananas: Login + + + + Fixed + + + + + Login name + + + false + + + + + + + Password + + + false + + + + + + + + + + QLineEdit::Password + + + + + + + &Cancel + + + Alt+C + + + + + + + O&K + + + Alt+K + + + true + + + + + + + qPixmapFromMimeSource + + ananasglobal.h + + + + bOK + clicked() + dLogin + buttonOK() + + + bCancel + clicked() + dLogin + reject() + + + diff --git a/src/lib/dialogs/dselectdb.cpp b/src/lib/dialogs/dselectdb.cpp new file mode 100644 index 0000000..b11d066 --- /dev/null +++ b/src/lib/dialogs/dselectdb.cpp @@ -0,0 +1,520 @@ +#include "dselectdb.h" + +#include +#include +#include + +#include "atests.h" +#include "dhelpcfgform.h" +/* + * Constructs a dSelectDB as a child of 'parent', with the + * name 'name' and widget flags set to 'f'. + * + * The dialog will by default be modeless, unless you set 'modal' to + * true to construct a modal dialog. + */ +dSelectDB::dSelectDB(QWidget* parent, const char* name, bool modal, Qt::WindowFlags fl) + : QDialog(parent, name, modal, fl) + ,settings( QSettings::IniFormat, QSettings::UserScope, "Ananas company Ltd", "Ananas4") +{ + setupUi(this); + + init(); +} + +/* + * Destroys the object and frees any allocated resources + */ +dSelectDB::~dSelectDB() +{ + // no need to delete child widgets, Qt does it all for us +} + +/* + * Sets the strings of the subwidgets using the current + * language. + */ +void dSelectDB::languageChange() +{ + retranslateUi(this); +} + + +//#include "acfgobj.h" +#include +#include +#include +#include +#include +#include +//Added by qt3to4: +#include + +#include "deditrc.h" +#include "dimportdb.h" +#include "acfgrc.h" +#include "atests.h" +#include "adataexchange.h" +#include "alog.h" + +void dSelectDB::init() +{ + aLog::init("ananas.log", aLog::Debug); + createMenu(); + progressBar1->hide(); + QString fname; + withgroups = 1; + //--settings.insertSearchPath( QSettings::Unix, QString(QDir::homeDirPath())+QString("/.ananas")); + //--settings.insertSearchPath( QSettings::Windows, "/ananasgroup/ananas" ); + + local = settings.entryList("/groups").count(); + changes = false; + /*--if(!local) + { + + aLog::print(aLog::Debug, tr("dSelectDB local settings not found")); + settings.insertSearchPath( QSettings::Windows, "/ananasgroup/ananas/globalsettings"); +#ifdef Q_OS_WIN32 + QStringList subkeys = settings.subkeyList("/ananasgroup/ananas/globalsettings"); + settings.insertSearchPath(QSettings::Windows,"/ananasgroup/ananas/globalsettings"); + QStringList entryGroup; + for(uint i=0; ihideColumn( 1 ); + listDBRC->setSorting( -1 ); + listDBRC->header()->hide(); + listDBRC->setRootIsDecorated(1); + buttonOk->setEnabled( FALSE ); + return; +} + +void dSelectDB::readSettings(QStringList entryGroup) +{ + rcfile=""; + ro_mode=0; + QFile f, fc; + QString s, sp, sn, rc; + rcListViewItem *item, *gitem=NULL; //, *subitem; + for(uint j=0; jlastItem(); + if(lastIt!=NULL) + { + while(lastIt->depth()>0) + { + lastIt =(rcListViewItem *) lastIt->parent(); + } + gitem= new rcListViewItem(listDBRC, lastIt, groupName, "", true ); + gitem->setOpen(true); + } + else + { + gitem= new rcListViewItem(listDBRC, groupName, "", true ); + gitem->setOpen(true); + } +// withgroups=1; + QMap cfg; + for(int k = eitems.count()-1; k>=0; k--) + { + if(k<0) break; + rc = settings.readEntry(entryGroup[j]+"/"+eitems[k]); + cfg = aTests::readConfig(QDir::convertSeparators(rc)); + sn=cfg["dbtitle"]; + if (gitem) item= new rcListViewItem( gitem, sn, rc ); + else item= new rcListViewItem( listDBRC, sn, rc ); + } + } +} + + +void dSelectDB::itemSelect( Q3ListViewItem *item ) +{ + if (! item ) return; + rcListViewItem *i = ( rcListViewItem *) item ; + buttonOk->setEnabled( !i->group ); +} + + +void dSelectDB::newGroup() +{ + Q3ListViewItem *gitem; + gitem = new rcListViewItem(listDBRC, tr("New group"), "", true ); + listDBRC->setRootIsDecorated(1); + gitem->setOpen(true); + listDBRC->setSelected(gitem, true); + editItem(); + withgroups=1; + changes = true; + //saveRC(); +} + + +void dSelectDB::newItem() +{ + rcListViewItem *item, *gitem; + QString rc; + item= ( rcListViewItem *) listDBRC->selectedItem(); + if (!item) return; + if (withgroups) { + if (item->parent()) gitem = ( rcListViewItem *) item->parent(); + else gitem=item; + item = new rcListViewItem(gitem, tr("New shema"), "myrc"); + gitem->setOpen(true); + + } else { + item = new rcListViewItem(listDBRC, tr("New shema"), "myrc"); + } + listDBRC->setSelected(item, true); + editItem(); + changes = true; +} + + +void dSelectDB::editItem() +{ + rcListViewItem *item; + dEditRC *d = new dEditRC(this); + + item = ( rcListViewItem *) listDBRC->selectedItem(); + if (!item) return; + if ( item->group ) + { + // Group + item->setRenameEnabled(0, true); + item->startRename(0); + changes = true; + } + else + { + // Resource + d->setdata( QDir::convertSeparators(item->rcfile), item ); + if ( d->exec() == QDialog::Accepted ) + { + changes = true; + } + } +} + + + +void dSelectDB::deleteItem() +{ + Q3ListViewItem *item; + item=listDBRC->selectedItem(); + if (item) + { + QString msg = tr("Delete item?"); + if(QMessageBox::question(this,tr("confirm delete"),msg,QMessageBox::Ok,QMessageBox::Cancel)!=QMessageBox::Ok) + { + return; + } + + delete item; + if (listDBRC->childCount()==0) withgroups=0; + changes = true; + } +} + + +void dSelectDB::saveRC() +{ + rcListViewItem *item, *gitem; + QFile f( rcfile ); + aLog::print(aLog::Info, tr("dSelectDB save settings")); + if (!local) + { + if(!changes) return; + QString home = QDir::homeDirPath(); +#ifndef Q_OS_WIN32 + QString msg = QString("Все внесенные изменения будут сохранены локально в вашем домашнем каталоге.\nПри очередном запуске программы будут использованы локальные настройки из каталога\n%1/.ananas.\nЕсли Вы хотите использовать глобальные настройки, вам следует удалить каталог\n%2/.ananas").arg(home).arg(home); +#else + QString msg = tr("save settings local?"); +#endif + if(QMessageBox::question(this,tr("save"),QString::fromUtf8(msg),QMessageBox::Ok,QMessageBox::Cancel)!=QMessageBox::Ok) + { + return; + } + } + //--settings.removeSearchPath( QSettings::Unix, "/etc/ananas" ); + //--settings.removeSearchPath( QSettings::Windows, "/ananasgroup/ananas/globalsettings"); + + + gitem= ( rcListViewItem *) listDBRC->firstChild(); + uint gcount=0; + uint ecount=0; + clearSettings(); + + settings.beginGroup("/groups"); + + while (gitem) + { + if (withgroups) + { + settings.writeEntry(QString::number(gcount),gitem->text(0)); + if(gitem->childCount()) + { + item = ( rcListViewItem *) gitem->firstChild(); + while (item) + { + settings.writeEntry(QString::number(gcount)+"/"+QString::number(ecount),item->rcfile); + item = ( rcListViewItem *) item->nextSibling(); + ++ecount; + } + } + } + ++gcount; + gitem = ( rcListViewItem *) gitem->nextSibling(); + } + settings.endGroup(); +} + + +void dSelectDB::onOK() +{ + rcListViewItem *item; + + saveRC(); + item = ( rcListViewItem *) listDBRC->selectedItem(); + if (item) { + if ( !item->rcfile.isEmpty() ) { + rcfile = item->rcfile; + accept(); + } + } +} + + +void dSelectDB::onCancel() +{ + //saveRC(); + reject(); +} + + +void dSelectDB::ItemRenamed(Q3ListViewItem *item, int col) +{ + if (!item) return; + if (col>1) return; +} + + +void dSelectDB::clearSettings() +{ + QStringList eitems; + QStringList entryGroup =settings.entryList("/groups"); + settings.beginGroup("/groups"); + for(uint j=0; j=0; k--) + { + if(k<0) break; + settings.removeEntry(entryGroup[j]+"/"+eitems[k]); + } + } + settings.endGroup(); +} + + +void dSelectDB::onHelp() +{ + HelpCfgForm f; + f.exec(); +} + +void dSelectDB::createMenu() +{ + + menuBar = new QMenuBar(this); + Q3PopupMenu *menuFile = new Q3PopupMenu(this); + menuFile->insertItem(tr("E&xit"), this, SLOT(onCancel())); + + Q3PopupMenu *menuEdit = new Q3PopupMenu(this); + menuEdit->insertItem(tr("New &group"), this, SLOT(newGroup())); + menuEdit->insertItem(tr("&New shema"), this, SLOT(newItem())); + menuEdit->insertSeparator(); + menuEdit->insertItem(tr("Edi&t"), this, SLOT(editItem())); + menuEdit->insertSeparator(); + menuEdit->insertItem(tr("&Delete"), this, SLOT(deleteItem())); + + Q3PopupMenu *menuAction = new Q3PopupMenu(this); + menuAction->insertItem(tr("&Import"), this, SLOT(importItem())); + menuAction->insertItem(tr("&Export"), this, SLOT(exportItem())); + + menuBar->insertItem(tr("Program"), menuFile); + menuBar->insertItem(tr("Actions"), menuEdit); + menuBar->insertItem(tr("Service"), menuAction); + layout()->setMenuBar(menuBar); + menuBar->show(); +} + + +void dSelectDB::importItem() +{ + rcListViewItem *item,*gitem; + dImportDB *d = new dImportDB(this); + item = (rcListViewItem *)listDBRC->selectedItem(); + if (!item) return; + if (withgroups) + { + if (item->parent()) gitem = ( rcListViewItem *) item->parent(); + else gitem=item; + item = new rcListViewItem(gitem, tr("New shema"), "myrc"); + gitem->setOpen(true); + + } + else + { + item = new rcListViewItem(listDBRC, tr("New shema"), "myrc"); + } + listDBRC->setSelected(item, true); + d->setdata("", item ); + if ( d->exec() == QDialog::Accepted ) + { + bool res; + QString rcfile = item->rcfile; + QString filename = d->eCfgName->text(); + progressBar1->show(); + progressBar1->reset(); + aBackup newBase; + connect (&newBase, SIGNAL(progress(int,int)), progressBar1, SLOT( setProgress(int,int))); + if(newBase.importData(rcfile, filename, true)==false) + { + QMessageBox::information(this,tr("Backup"),newBase.lastError(),Qt::NoButton); + progressBar1->hide(); + aLog::print(aLog::Info, tr("dSelectDB business schema import")); + } + else + { + aLog::print(aLog::Error, tr("dSelectDB restore: %1").arg(newBase.lastError())); + QMessageBox::critical(this,tr("Backup"),newBase.lastError(),0, Qt::NoButton); + progressBar1->hide(); + delete item; + item =0; + return; + } + + + + changes = true; + } + else + { + delete item; + item = 0; + return; + } +} + + +void dSelectDB::exportItem() +{ +// progressBar1->setTotalSteps(10); + QString dir,rcfile,filename; +#ifndef Q_OS_WIN32 + dir = "/home"; +#endif + + rcListViewItem *item = ( rcListViewItem *) listDBRC->selectedItem(); + if (item) + { + if ( !item->rcfile.isEmpty() && !item->group ) + { + rcfile = item->rcfile; + } + else + { + QMessageBox::information(this,tr("Select item"),tr("Please, select item for export"),Qt::NoButton); + return; + } + + Q3FileDialog *fdlg = new Q3FileDialog(this, "fileDialog",true); // create modal dialog + fdlg->setMode ( Q3FileDialog::AnyFile ); + if(fdlg->exec()==QDialog::Accepted) + { + filename = fdlg->selectedFile(); + } + else + { + return; + } + delete fdlg; + fdlg = 0; + + aBackup backupBase; + progressBar1->show(); + progressBar1->reset(); + connect (&backupBase, SIGNAL(progress(int,int)), progressBar1, SLOT( setProgress(int,int))); + if(backupBase.exportData(rcfile, filename, true )==0) + { + aLog::print(aLog::Info, tr("dSelectDB backup ok")); + QMessageBox::information(this,tr("Backup"),backupBase.lastError(),Qt::NoButton); + progressBar1->hide(); + + } + else + { + aLog::print(aLog::Debug, tr("dSelectDB backup: %1").arg(backupBase.lastError())); + QMessageBox::critical(this,tr("Backup"),backupBase.lastError(),0, Qt::NoButton); + progressBar1->hide(); + return; + } + } + else + { + QMessageBox::information(this,tr("Select item"),tr("Please, select item for export"),Qt::NoButton); + return; + } + +} + + +void dSelectDB::onDblClick( Q3ListViewItem *item) +{ + + if (! (( rcListViewItem *)item)->group ) + { + onOK(); + + } +} + diff --git a/src/lib/dialogs/dselectdb.h b/src/lib/dialogs/dselectdb.h new file mode 100644 index 0000000..817019a --- /dev/null +++ b/src/lib/dialogs/dselectdb.h @@ -0,0 +1,54 @@ +#ifndef DSELECTDB_H +#define DSELECTDB_H + +#include "ui_dselectdb.h" + + +class ANANAS_EXPORT dSelectDB : public QDialog, public Ui::dSelectDB +{ + Q_OBJECT + +public: + dSelectDB(QWidget* parent = 0, const char* name = 0, bool modal = false, Qt::WindowFlags fl = 0); + ~dSelectDB(); + + QString rcfile; + +public slots: + void newItem(); + void editItem(); + void deleteItem(); + void onCancel(); + void ItemRenamed( Q3ListViewItem * item, int col ); + void onHelp(); + void createMenu(); + virtual void onDblClick(Q3ListViewItem *); + +protected: + QSettings settings; + + virtual void clearSettings(); + +protected slots: + virtual void languageChange(); + +private: + int withgroups; + QMenuBar *menuBar; + bool changes; + int ro_mode; + bool local; + +private slots: + void init(); + void readSettings( QStringList entryGroup ); + void itemSelect( Q3ListViewItem * item ); + void newGroup(); + void saveRC(); + void onOK(); + void importItem(); + void exportItem(); + +}; + +#endif // DSELECTDB_H diff --git a/src/lib/dialogs/dselectdb.ui b/src/lib/dialogs/dselectdb.ui new file mode 100644 index 0000000..ac202a1 --- /dev/null +++ b/src/lib/dialogs/dselectdb.ui @@ -0,0 +1,181 @@ + + + + ANANAS_EXPORT + dSelectDB + + + + 0 + 0 + 443 + 415 + + + + Information base + + + true + + + + + + + + &OK + + + + + + true + + + true + + + + + + + &Cancel + + + Alt+C + + + true + + + + + + + &Help + + + Alt+H + + + true + + + + + + + + 20 + 80 + + + + Expanding + + + Vertical + + + + + + + + + + + Select data base + + + false + + + + + + + Q3ScrollView::AlwaysOff + + + true + + + + Name + + + true + + + true + + + + + Resource file + + + true + + + true + + + + + + + + true + + + + + + + + + qPixmapFromMimeSource + + ananasglobal.h + qmenubar.h + q3popupmenu.h + qsettings.h + rclistviewitem.h + qmessagebox.h + + + + buttonOk + clicked() + dSelectDB + onOK() + + + buttonCancel + clicked() + dSelectDB + onCancel() + + + listDBRC + selectionChanged(Q3ListViewItem*) + dSelectDB + itemSelect(Q3ListViewItem*) + + + buttonHelp + clicked() + dSelectDB + onHelp() + + + listDBRC + doubleClicked(Q3ListViewItem*) + dSelectDB + onDblClick(Q3ListViewItem*) + + + diff --git a/src/lib/dialogs/messageswindow.cpp b/src/lib/dialogs/messageswindow.cpp new file mode 100644 index 0000000..3c12310 --- /dev/null +++ b/src/lib/dialogs/messageswindow.cpp @@ -0,0 +1,140 @@ +/**************************************************************************** +** $Id: messageswindow.cpp,v 1.1 2008/11/05 21:16:28 leader Exp $ +** +** Header file of the Mesages window of Ananas +** Designer and Engine applications +** +** Created : 20031201 +** +** Copyright (C) 2003-2004 Leader InfoTech. All rights reserved. +** +** This file is part of the Library of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.leaderit.ru/page=ananas or email sales@leaderit.ru +** See http://www.leaderit.ru/gpl/ for GPL licensing information. +** +** Contact org@leaderit.ru if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +/* +*/ +#include +#include +#include +#include +#include +//Added by qt3to4: +#include +#include "messageswindow.h" +#include "acfg.h" + +/* + * Constructs a MessagesWindow as a child of 'parent', with the + * name 'name' and widget flags set to 'f'. + * + */ +MessagesWindow *msgwindow = 0; + + +void +messageproc(int n, const char *msg){ + if (msgwindow) msgwindow->message( n, QObject::trUtf8( msg ) ); +} + + +MessagesWindow::MessagesWindow( QWidget* parent, Qt::WFlags fl ) + : Q3DockWindow( parent, "MessagesWindow", fl ) +{ + msgBrowser = new Q3TextBrowser( this, "msgBrowser" ); + boxLayout()->addWidget( msgBrowser ); + languageChange(); + setMinimumSize( QSize( 1, 1 ) ); + msgBrowser->setMinimumSize( QSize( 1, 1 ) ); + //--clearWState( WState_Polished ); + //--setWindowState( WState_Polished ); + setResizeEnabled( TRUE ); + setExpanded(false); + setCloseMode( Q3DockWindow::Always ); + msgBrowser->show(); + msgwindow = this; + connect(msgBrowser, SIGNAL(doubleClicked(int,int)), this, SLOT(on_click())); + cfg_messageproc=messageproc; +} + +/* + * Destroys the object and frees any allocated resources + */ +MessagesWindow::~MessagesWindow() +{ + msgwindow=NULL; + cfg_messageproc = 0; +} + +void +MessagesWindow::message( int msgtype, const QString &msg) +{ + char st[4][50]={ + "", + "", + "", + ""}; + if (msgtype<0) msgtype=0; + if (msgtype>3) msgtype=3; + msgBrowser->append( tr( st[ msgtype ] )+msg ); + show(); +} + + +/* + * Sets the strings of the subwidgets using the current + * language. + */ +void MessagesWindow::languageChange() +{ + setCaption( tr( "Messages window" ) ); + msgBrowser->setText( QString::null ); +} + +void +MessagesWindow::hideEvent ( QHideEvent *e ) +{ + msgBrowser->clear(); + Q3DockWindow::hideEvent( e ); +} + + +void +MessagesWindow::on_click() +{ + setExpanded(!expanded); +} + + +void +MessagesWindow::setExpanded(bool exp) +{ + if(exp) setFixedExtentHeight ( 150 ); + else setFixedExtentHeight ( 30 ); + expanded = exp; + updateGeometry(); +} + + +bool +MessagesWindow::isExpanded() +{ + return expanded; +} + + diff --git a/src/lib/dialogs/messageswindow.h b/src/lib/dialogs/messageswindow.h new file mode 100644 index 0000000..d647fee --- /dev/null +++ b/src/lib/dialogs/messageswindow.h @@ -0,0 +1,67 @@ +/**************************************************************************** +** $Id: messageswindow.h,v 1.1 2008/11/05 21:16:28 leader Exp $ +** +** Header file of the Mesages window of Ananas +** Designer and Engine applications +** +** Created : 20031201 +** +** Copyright (C) 2003-2004 Leader InfoTech. All rights reserved. +** +** This file is part of the Library of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.leaderit.ru/page=ananas or email sales@leaderit.ru +** See http://www.leaderit.ru/gpl/ for GPL licensing information. +** +** Contact org@leaderit.ru if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +/* +*/ +#ifndef MESSAGESWINDOW_H +#define MESSAGESWINDOW_H + +#include "ananasglobal.h" + +#include +//Added by qt3to4: +#include + +class Q3TextBrowser; + +void messageproc(int n, const char *msg); + +class ANANAS_EXPORT MessagesWindow : public Q3DockWindow +{ + Q_OBJECT + +public: +// bool empty; + MessagesWindow( QWidget* parent = 0, Qt::WFlags fl = Qt::WType_TopLevel ); + ~MessagesWindow(); + + Q3TextBrowser* msgBrowser; +private: + bool expanded; +public slots: + void message( int msgtype, const QString &msg); +protected slots: + virtual void languageChange(); + virtual void hideEvent ( QHideEvent *e ); + void on_click(); + void setExpanded(bool exp); + bool isExpanded(); +}; + +#endif // MESSAGESWINDOW_H diff --git a/src/lib/images/lib_database.png b/src/lib/images/lib_database.png new file mode 100644 index 0000000000000000000000000000000000000000..5f6aad33da0652a5543d8e5d5d1e935473ecdcae GIT binary patch literal 1039 zcmV+q1n~QbP)sSRoB3v?J9##Vpy40iYq}| zP{%;(CW~8>T{LQBBgSSi8W zCw3Ao=(;f>Hd zdWY`_@t$jZ)@VBl?KUerqwHM|95uc&1aI(rycJz4O5AH84|~@GFCRE^t!QXg>|yVE z;5o%RjX?Ms!pD~}IKGT`k1eBr^cVESmV|iEH9q4W?sbrdyjRu(!+Gcy?4DWd_RrwJ z;S|Cj{(!O1Z{yS#_k?)QH9m8A&*A0$m$38TkL*T4FgKb#H(}bpfaZO3Ft{#4zbA#p z-QS4yd2<}k)a-*?s)MYqf^NI7AozaOb`MOir}Bcg)xU!}tAfr?l6ZeUjmY&hTw_U8 zzoan1lQ-km)>f2iYN4&|KuyySc33|{{jM+3=$t`q^9X7!3i>WABK9*dbQc)71)N?1 zeCHRlaO0X$#N%=F_xGc%tqmcfZ0ER zBa6VRqe-Tm%nKeLAIHeZ2qKY)ct~$=FS@$ApjNB#=|UP`5$t>#`1W_;yFdN|2WHbu zSy?k-ECnaGAuZo!|?EMUNEmbF?zioWo2d1Xf$GK$or4mR)q^=&6x1Z&^#$| zEliRhW?WHG0h7rDm&+yc?djY=m7TeR|2Jdy8W1h53w;5%TuH+{{m(w4{!w7Pb&Zb002ov JPDHLkV1mdf@KFE& literal 0 HcmV?d00001 diff --git a/src/lib/images/lib_dbgroup.png b/src/lib/images/lib_dbgroup.png new file mode 100644 index 0000000000000000000000000000000000000000..30052901351d9e7bf76d6a5d3e229c1c7f4f5b63 GIT binary patch literal 681 zcmV;a0#^NrP)&zV_?Ao z5*83PzydZjIWo7*mC0P7hIDZfE_3<5-#swH6o9F#hCt|ta3lSv7N(?2IL zy)c3$7$;MJ&(F`%?RJq!Bt{CxokjufbUJ9a+a%)acs$M&j5m$)X|IKa2VBURhC+KI0TMX>AvRR4N6(-#;8IO+Bl- zh83R)tFO#hJGNjwyarojgISZfU%W%TUhh~iy;)|pDlGQ|&-^Q}9IwI}dakHR+-Ecz z!SnoRFjKIoBEM7f%VkAP8q;0c^`*cpfoeg8rK6{cn#5~rwfg_SOu_sNmJSWHrdyA0 z4!=Pz{qU9vreX9LNKH2$&P@hp31;q3!yr5%HO=X-PX=ZQ6pziT`ZN6tYfOW(K6naU P00000NkvXXu0mjfdXp^n literal 0 HcmV?d00001 diff --git a/src/lib/images/print.png b/src/lib/images/print.png new file mode 100644 index 0000000000000000000000000000000000000000..b03cafd5ff9e1b926ea5bcd1dc029de7e38e9d93 GIT binary patch literal 801 zcmV++1K#|JP)jmT}D@cR5DP ztvauYjsHn8&u|fR(H(bUysl8IEVqvNO5ik0>27xEM4h$Zbs&*tc1HvF|wd&4O)mf5Q^6Qk6q^>QDNPuAA z9@uNkczj8kWvCYP9&|Z+aa1y{nGSXyBSBDJUzK7>+yXFMFycFB^tDeviAj=6&;kLH z-wE&Dp3p8qQ}&+h5q3guiwP6n@EVI{%$QR-W$<^O5AK9C%TbhcYH8(jog;B8|9Y z0;&Y}J5bvYXuB-KUQNo4h2rZb6%dtAMM1?c3Sc!wQ3_S;pNTKG)OJ&Ew;D(Nq@p)x z++_NHDfu*OjM7Fx^X3LwFk5-xJY#P>R2{W{>K@$Q>a)Q-OHa09tkt+6L!GVaDC!w8 zC=f*v&tD#tjP2A`=?0_#XMh~URCJ5-8!#0=<2h>irv)M~JRZ`CI<59*cN6>d2cN&4 zq17T7OtaPeHL2fdFW!w?hQ~wVIBo&>mQJ&D_T|$VskOcUi>+NhNQHuGUd}lsei(E3 f?2uls=O3Ye<>Gvn%R+N&00000NkvXXu0mjfQ9xUj literal 0 HcmV?d00001 diff --git a/src/lib/lib.pri b/src/lib/lib.pri new file mode 100644 index 0000000..99447cc --- /dev/null +++ b/src/lib/lib.pri @@ -0,0 +1,17 @@ +# include paths for Ananas library + +INCLUDEPATH += \ + ../lib/metadata \ + ../lib/dialogs \ + ../lib/objects \ + ../lib/widgets \ + ../lib/report \ + ../lib/sys + +INCLUDEPATH += \ + ../../lib/metadata \ + ../../lib/dialogs \ + ../../lib/objects \ + ../../lib/widgets \ + ../../lib/report \ + ../../lib/sys diff --git a/src/lib/lib.pro b/src/lib/lib.pro new file mode 100644 index 0000000..209ff48 --- /dev/null +++ b/src/lib/lib.pro @@ -0,0 +1,132 @@ +include(../plugins/plugins.pri) +include(lib.pri) + +TARGET = ananas4 +TEMPLATE = lib +shared:CONFIG += dll +unix:VERSION = 1.0.1 + +DESTDIR = ../../lib +DLLDESTDIR = ../../bin + +INCLUDEPATH += ../lib ../plugins +LIBS += -L../../lib +LIBS +=-lqt4-qdataschema + +shared { + win32:DEFINES += ANANAS_DLL +} else { + win32:DEFINES += ANANAS_NO_DLL +} + +win32 { + CONFIG -= console +# CONFIG += dll +} + +#LIBS += -L$(QTDIR)/plugins/designer -lqsa # Why? -L../designer -lformdesigner +unix{ + LIBS += -L/usr/X11R6/lib/ +} +win32 { + #LIBS += -L..\..\plugins -lananasplugin +} + +#MOC_DIR = ../../tmp/moc/$$TARGET +#OBJECTS_DIR = ../../tmp/obj/$$TARGET +#UI_DIR = ../../tmp/ui/$$TARGET + +include ( ../ananas.pri ) + +HEADERS = \ + acfg.h \ + acfgrc.h \ + acmanifest.h \ + acontainer.h \ + adataexchange.h \ + adatafield.h \ + aextension.h \ + aextensionplugin.h \ + aextensionfactory.h \ + afilter.h \ + alog.h \ + amenubar.h \ + amoney.h \ + ananas.h \ + ananasglobal.h \ + arole.h \ + aservice.h \ + asqlfield.h \ + asqltable.h \ + atests.h \ + atime.h \ + auser.h \ + rclistviewitem.h + +SOURCES = \ + acfg.cpp \ + acfgrc.cpp \ + acmanifest.cpp \ + acontainer.cpp \ + adataexchange.cpp \ + adatafield.cpp \ + aextension.cpp \ + aextensionplugin.cpp \ + aextensionfactory.cpp \ + afilter.cpp \ + alog.cpp \ + amenubar.cpp \ + amoney.cpp \ + ananas.cpp \ + arole.cpp \ + aservice.cpp \ + asqlfield.cpp \ + asqltable.cpp \ + atests.cpp \ + atime.cpp \ + auser.cpp \ + rclistviewitem.cpp + +#FORMS = \ +# deditrc.ui \ +# dhelpcfgform.ui \ +# dlogin.ui \ +# dselectdb.ui + +RESOURCES += \ + lib.qrc + +TRANSLATIONS = \ + ../../translations/ananas-lib-en.ts \ + ../../translations/ananas-lib-ru.ts + +unix{ + alib.path = $(LIBDIR) + alib.files = libananas4.so.$$VERSION + alib.extra = cp -df libananas4.so* $(INSTALL_ROOT)$(LIBDIR) + + alibheader.path = $(INCLUDEDIR) + alibheader.files = $$HEADERS + alibheader.files += .ui/*h + } + +win32 { + alib.path = $(QTDIR)\lib + alib.files += ananas4.dll + alib.files += ananas4.lib +# alibheader.path = $(INCLUDEDIR) +# alibheader.files = $$HEADERS +# alibheader.files += tmp\ui\*h + } + +#INSTALLS += alib +unix{ +# INSTALLS += alibheader +} + +include(metadata/metadata.pri) +include(dialogs/dialogs.pri) +include(objects/objects.pri) +include(widgets/widgets.pri) +include(report/report.pri) +include(sys/sys.pri) diff --git a/src/lib/lib.qrc b/src/lib/lib.qrc new file mode 100644 index 0000000..5a3ede7 --- /dev/null +++ b/src/lib/lib.qrc @@ -0,0 +1,7 @@ + + + images/lib_database.png + images/lib_dbgroup.png + images/print.png + + diff --git a/src/lib/metadata/ametadata.cpp b/src/lib/metadata/ametadata.cpp new file mode 100644 index 0000000..8bf566e --- /dev/null +++ b/src/lib/metadata/ametadata.cpp @@ -0,0 +1,117 @@ +/**************************************************************************** +** $Id: ametadata.cpp,v 1.3 2008/12/14 10:53:02 leader Exp $ +** +** Code file of the Ananas configuration objects of Ananas +** Designer and Engine applications +** +** Created : 20031201 +** +** Copyright (C) 2003-2004 Leader InfoTech. All rights reserved. +** Copyright (C) Grigory Panov , Yoshkar-Ola. +** +** This file is part of the Library of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.leaderit.ru/page=ananas or email sales@leaderit.ru +** See http://www.leaderit.ru/gpl/ for GPL licensing information. +** +** Contact org@leaderit.ru if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#include "ametadata.h" + +#define context_startid 100 + +AMetaData AMetaData_default; + +/*! + * \class AMetaData + * + */ +AMetaData::AMetaData() +:AMetaObjectGroup( "MetaData", (AMetaObjectGroup *) 0 ) +{ +/* + int i = qRegisterMetaType("AMetaDataInfo"); +printf("metatype=%i\n", i); + +int id = QMetaType::type("AMetaDataInfo"); + if (id != -1) { + void *myClassPtr = QMetaType::construct(id); + if (myClassPtr) printf("OK\n"); + + QMetaType::destroy(id, myClassPtr); + myClassPtr = 0; + } +*/ +} + + +AMetaData* +AMetaData::metadata() +{ + return &AMetaData_default; +} + + +void +AMetaData::clear() +{ + +} + + + +ACataloguesGroup * +AMetaData::catalogues() +{ + return &v_catalogues; +} + + + +ADocumentsGroup * +AMetaData::documents() +{ + return &v_documents; +} + + +AReportsGroup * +AMetaData::reports() +{ + return &v_reports; +} + + +AJournalsGroup * +AMetaData::journals() +{ + return &v_journals; +} + + +AInfoRegistersGroup * +AMetaData::inforegisters() +{ + return &v_inforegisters; +} + + + +AAccRegistersGroup * +AMetaData::accregisters() +{ + return &v_accregisters; +} + diff --git a/src/lib/metadata/ametadata.h b/src/lib/metadata/ametadata.h new file mode 100644 index 0000000..4a2fcf9 --- /dev/null +++ b/src/lib/metadata/ametadata.h @@ -0,0 +1,105 @@ +/**************************************************************************** +** $Id: ametadata.h,v 1.3 2008/12/14 10:53:02 leader Exp $ +** +** Header file of the Ananas configuration objects of Ananas +** Designer and Engine applications +** +** Created : 20031201 +** +** Copyright (C) 2003-2004 Leader InfoTech. All rights reserved. +** Copyright (C) Andrey Paskal , Yoshkar-Ola +** Copyright (C) 2003-2005 Grigory Panov , Yoshkar-Ola +** +** This file is part of the Library of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.leaderit.ru/page=ananas or email sales@leaderit.ru +** See http://www.leaderit.ru/gpl/ for GPL licensing information. +** +** Contact org@leaderit.ru if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ +#ifndef AMETADATA_H +#define AMETADATA_H + +#include +#include + +#include "ametaobject.h" +#include "ametaobjectgroup.h" + + +#ifdef __BORLANDC__ +#define CHECK_POINT printf("%s:%i %s()\n",__FILE__,__LINE__,__FUNC__); +#else +#define CHECK_POINT printf("%s:%i %s()\n",__FILE__,__LINE__,__FUNCTION__); +#endif + +/*! + * \~english Metadata object methods return codes. \~russian + * Коды возвратов методов объекта метаданных. \~ + */ +#define RC_OK 0 /**< All right - no errors */ +#define RC_ERROR 1 /**< Error while executing method */ + + +//#define aPermission int + +#include +#include + +/*! + *\en + * Metadata object for metadata script access. + *\_en + *\ru + * \brief Объект метаданных для обеспечения доступа из скриптов. + * Наследует QObject. + *\_ru + */ +class AMetaData: public AMetaObjectGroup +{ +Q_OBJECT +//Q_PROPERTY( AMetaDataInfo info READ info SCRIPTABLE true ) +//Q_PROPERTY( AMetaDataGlobal* global READ global SCRIPTABLE true ) +public: + AMetaData(); + void clear(); + + static AMetaData* metadata(); + +public slots: + AMetaDataInfo *info(){ return &v_info;}; + AMetaDataGlobal *global(){ return &v_global;}; + + ADocumentsGroup* documents(); + ACataloguesGroup* catalogues(); + AReportsGroup* reports(); + AJournalsGroup* journals(); + AInfoRegistersGroup* inforegisters(); + AAccRegistersGroup* accregisters(); + + QString test(){ return QString("AMETADATA TEST STRING");}; + +private: + AMetaDataInfo v_info; + AMetaDataGlobal v_global; +//groups + ACataloguesGroup v_catalogues; + ADocumentsGroup v_documents; + AReportsGroup v_reports; + AJournalsGroup v_journals; + AInfoRegistersGroup v_inforegisters; + AAccRegistersGroup v_accregisters; +}; + +#endif diff --git a/src/lib/metadata/ametadataio.cpp b/src/lib/metadata/ametadataio.cpp new file mode 100644 index 0000000..f94fe8f --- /dev/null +++ b/src/lib/metadata/ametadataio.cpp @@ -0,0 +1,77 @@ +/**************************************************************************** +** $Id: ametadataio.cpp,v 1.2 2008/12/13 22:19:15 leader Exp $ +** +** Code file of the Ananas configuration objects of Ananas +** Designer and Engine applications +** +** Created : 20031201 +** +** Copyright (C) 2003-2004 Leader InfoTech. All rights reserved. +** Copyright (C) Grigory Panov , Yoshkar-Ola. +** +** This file is part of the Library of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.leaderit.ru/page=ananas or email sales@leaderit.ru +** See http://www.leaderit.ru/gpl/ for GPL licensing information. +** +** Contact org@leaderit.ru if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#include +#include +#include +#include +#include +#include + +#include "ametadataio.h" + +/*! + * \class AMetaDataIO + * + */ +AMetaDataIO::AMetaDataIO() +:QObject() +{ +} + + +AMetaDataIO::~AMetaDataIO() +{ +} + + +int +AMetaDataIO::read( const QString &name, AMetaData *md ) +{ + if ( !md ) md = AMetaData::metadata(); +} + + +int +AMetaDataIO::write( const QString &name, AMetaData *md ) +{ + if ( !md ) md = AMetaData::metadata(); +} + + +QObject * +AMetaDataIO::createObject( const QString &name ) +{ + QObject *o = 0; + if ( name == "AMetaObject" ) return new AMetaObject(); +// if ( name == "AMetaObjectGroup" ) return new AMetaObjectGroup(); + + return o; +} diff --git a/src/lib/metadata/ametadataio.h b/src/lib/metadata/ametadataio.h new file mode 100644 index 0000000..f515e92 --- /dev/null +++ b/src/lib/metadata/ametadataio.h @@ -0,0 +1,51 @@ +/**************************************************************************** +** $Id: ametadataio.h,v 1.3 2008/12/15 22:22:48 leader Exp $ +** +** Header file of the Ananas configuration objects of Ananas +** Designer and Engine applications +** +** Created : 20031201 +** +** Copyright (C) 2003-2008 Valeriy Grazhdankin. All rights reserved. +** +** This file is part of the Library of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.leaderit.ru/page=ananas or email sales@leaderit.ru +** See http://www.leaderit.ru/gpl/ for GPL licensing information. +** +** Contact org@leaderit.ru if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ +#ifndef AMETADATAIO_H +#define AMETADATAIO_H + +#include +#include "ametadata.h" + +class AMetaDataIO: public QObject +{ +Q_OBJECT +public: + AMetaDataIO(); + ~AMetaDataIO(); + virtual int read( const QString &name, AMetaData *md = 0); + virtual int write( const QString &name, AMetaData *md = 0); + virtual QObject *createObject( const QString &name ); + //virtual void storeGroup( AMetaObjectGroup *g ); + virtual void storeGroupBegin( AMetaObjectGroup *g ); + +signals: + void message( int msg_class, const QString & msg ); +}; + +#endif diff --git a/src/lib/metadata/ametadataioxml.cpp b/src/lib/metadata/ametadataioxml.cpp new file mode 100644 index 0000000..29d0e72 --- /dev/null +++ b/src/lib/metadata/ametadataioxml.cpp @@ -0,0 +1,373 @@ +/**************************************************************************** +** $Id: ametadataioxml.cpp,v 1.2 2008/12/13 22:19:15 leader Exp $ +** +** Code file of the Ananas configuration objects of Ananas +** Designer and Engine applications +** +** Created : 20031201 +** +** Copyright (C) 2003-2004 Leader InfoTech. All rights reserved. +** Copyright (C) Grigory Panov , Yoshkar-Ola. +** +** This file is part of the Library of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.leaderit.ru/page=ananas or email sales@leaderit.ru +** See http://www.leaderit.ru/gpl/ for GPL licensing information. +** +** Contact org@leaderit.ru if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#include +#include +#include +#include +#include +#include + +#include "ametadataioxml.h" + + +/*! +Metadata tags. +*/ +#define md_root "ananas_configuration" +#define md_interface "interface" + +#define md_info "info" +#define md_info_name "name" +#define md_info_author "author" +#define md_info_date "date" +#define md_info_mdate "mdate" +#define md_info_remark "remark" +#define md_info_lastid "lastid" +//#define md_info_dir "dir" + +#define md_metadata "metadata" /**< Metadata tag */ +#define md_globals "globals" +#define md_languages "languages" +#define md_language "language" +#define md_aliases "aliases" +#define md_alias "alias" +#define md_roles "roles" +#define md_role "role" +#define md_description "description" +#define md_sourcecode "sourcecode" +#define md_servermodule "server_module" +#define md_clientmodule "client_module" +#define md_formsource "form_source" +#define md_menutext "menutext" +#define md_argument "argument" + +#define md_documents "documents" +#define md_document "document" + +#define md_catalogues "catalogues" +#define md_catalogue "catalogue" +#define md_element "element" +#define md_group "group" + +#define md_string_view "string_view" +#define md_svfunction "svfunction" + +#define md_registers "registers" +#define md_iregisters "iregisters" +#define md_iregister "iregister" +#define md_aregisters "aregisters" +#define md_aregister "aregister" + +#define md_reports "reports" +#define md_report "report" + +#define md_journals "journals" +#define md_journal "journal" +#define md_columns "columns" +#define md_column "column" +#define md_used_doc "used_doc" +#define md_fieldid "fieldid" + +#define md_field "field" +#define md_forms "forms" +#define md_form "form" +#define md_defaultmod "defaultmod" +#define md_webforms "webforms" +#define md_webform "webform" +#define md_formdesign "dialogform" + +#define md_tables "tables" +#define md_table "table" +#define md_header "header" + +#define md_resources "resources" +#define md_dimensions "dimensions" +#define md_information "information" + +/*! +Action metadata object items. +*/ +#define md_actions "actions" +#define md_actiongroup "actiongroup" +#define md_action "action" +#define md_objectid "objectid" +#define md_formid "formid" +#define md_actiontype "actiontype" +#define md_active_picture "active_picture" +#define md_passive_picture "passive_picture" + +/*! +Interface metadata object items. +*/ +#define md_interface "interface" +#define md_toolbars "toolbars" +#define md_toolbar "toolbar" +#define md_popupmenus "popupmenus" +#define md_popupmenu "popupmenu" +#define md_mainmenu "mainmenu" +#define md_submenu "submenu" +#define md_command "command" +#define md_comaction "comaction" +#define md_separator "separator" +#define md_key "key" +#define md_menutext "menutext" +//key modifiers +#define md_km_ctrl "Ctrl+" +#define md_km_alt "Alt+" +#define md_km_shift "Shift+" + +#define md_image_collection "image_collection" +#define md_image "image" + + +/*! +Metadata attributes. +*/ +#define mda_name "name" +#define mda_id "id" +#define mda_type "type" +#define mda_readonly "readonly" +#define mda_lang "lang" +#define mda_nz "nz" +#define mda_sort "sort" +#define mda_no_unconduct "no_unconduct" +#define mda_plus "plus" +#define mda_sum "sum" +#define mda_tag "tag" +#define mda_trfile "trfile" +#define mda_length "length" +#define mda_format "format" +#define mda_stdf "stdf" +#define mda_rights "rights" + +/*! +Actions types +*/ + +#define md_action_new 0 +#define md_action_edit 1 +#define md_action_view 2 +#define md_action_execute 3 + +/*! + * Default forms types. + * If bit with some number set in 1 form can use for this action. + */ + +#define md_form_nouse 0 +#define md_form_new 1 +#define md_form_view 2 +#define md_form_edit 3 +#define md_form_select 4 + + +/*! + * Catalogue forms types. + */ + +#define md_form_elem_list 0 +#define md_form_elem 1 +#define md_form_group 2 + +/*! +System object id +*/ + +#define md_systemjournal 1 +#define md_aregarhive 2 + +//class aCfg; +//extern aCfg cfg; + +#define ERR_Code int + +#define md_user_roles "userroles" +#define md_users "users" +#define md_user "user" +#define md_usr_role "u_role" +#define md_roles "roles" +#define md_role "role" +#define md_rl_users "r_users" +#define md_rl_user "r_user" +#define md_right_roles "rroles" + +#define perm_read 0 +#define perm_execute 1 +#define perm_create 2 +#define perm_delete 3 +#define perm_turn_on 4 +#define perm_turn_off 5 +#define perm_admin 6 + +/*! + * \class AMetaDataIOXML + * + */ +AMetaDataIOXML::AMetaDataIOXML() +:AMetaDataIO() +{ +} + + +int +AMetaDataIOXML::read( const QString &name, AMetaData *md ) +{ + QFile file( name ); + QByteArray buf; + QString err; + int errLine = 0, errColumn = 0; +// QDomDocument xml; + QDomNode cur, sub; + QDomElement node, rootnode, cfginfo, mdelement, iface, actions; + long id; + + if ( !md ) md = AMetaData::metadata(); + if ( !file.open( QIODevice::ReadOnly ) ) return 1; + buf = file.readAll(); + file.close(); + xml.setContent( QString("") ); + if ( !xml.setContent( buf, false, &err, &errLine, &errColumn ) ) { + emit message( 2, QObject::tr( + "Error read configuration line:%1 col:%2 %3" + ).arg( errLine ).arg( errColumn ).arg( err )); + return 1; + } + if ( !xml.isDocument() ) { +// aLog::print(aLog::Error, tr("Bad configuration")); + return 1; + } + md->clear(); + rootnode = xml.documentElement(); + + node = rootnode.namedItem( md->info()->className() ).toElement(); + XMLToAMetaObject( node, md->info() ); + node = rootnode.namedItem( md->global()->className() ).toElement(); + XMLToAMetaObject( node, md->global() ); + + mdelement = rootnode.namedItem( md_metadata ).toElement(); + iface = rootnode.namedItem( md_interface ).toElement(); + actions = rootnode.namedItem( md_actions ).toElement(); + return 0; +} + + +int +AMetaDataIOXML::write( const QString &name, AMetaData *md ) +{ + QFile file( name ); + + if ( !md ) md = AMetaData::metadata(); +// QDomDocument xml("ananas4_configuration"); + QDomNode cur, sub; + QDomElement node, rootnode, cfginfo, mdelement, iface, actions; + + xml.setContent(QString("\n")); + xml.appendChild( xml.implementation().createDocumentType("ananas_configuration", + QString::null,"ananas-cfg.dtd")); + rootnode = xml.createElement( md_root ); + xml.appendChild( rootnode ); + rootnode = xml.documentElement(); + + rootnode.appendChild( AMetaObjectToXML( md->info() ) ); + rootnode.appendChild( AMetaObjectToXML( md->global() ) ); + + + node = xml.createElement( md_info ); + rootnode.appendChild( node ); + + + node = xml.createElement( md_interface ); + rootnode.appendChild( node ); + + node = xml.createElement( md_metadata ); + rootnode.appendChild( node ); + + node = xml.createElement( md_actions ); + rootnode.appendChild( node ); + + + if ( !file.open( QIODevice::WriteOnly ) ) return 1; + QTextStream ts( &file ); + xml.save( ts, 4 ); + file.close(); + return 0; +} + +#include + +void +AMetaDataIOXML::XMLToAMetaObject( QDomElement e, AMetaObject *o ) +{ + int i; + QDomElement se; + QDomNode cur; + QString s, t; + int id; + + cur = e.firstChild(); + while (!cur.isNull()) { + se = cur.toElement(); + if ( se.hasAttribute( mda_id ) ) { + id = 0; + id = se.attribute( mda_id ).toInt(); + o->setId( id ); + } + s = se.text(); +// qDebug() << se.tagName() << ":" << s; + if ( !s.isNull() ) o->setText( se.tagName(), s ); + cur = cur.nextSibling(); + } + +} + + + +QDomElement +AMetaDataIOXML::AMetaObjectToXML( AMetaObject *o ) +{ + int i; + QDomElement e, se; + + e = xml.createElement( o->className() ); + for ( i=0; i< o->textCount(); i++ ){ + se = xml.createElement( o->textName( i ) ); + se.appendChild( xml.createTextNode( o->text( i ) ) ); + e.appendChild( se ); + } + return e; +} + + +QString +AMetaDataIOXML::text() +{ + return xml.toString( 4 ); +} diff --git a/src/lib/metadata/ametadataioxml.h b/src/lib/metadata/ametadataioxml.h new file mode 100644 index 0000000..bae4f59 --- /dev/null +++ b/src/lib/metadata/ametadataioxml.h @@ -0,0 +1,50 @@ +/**************************************************************************** +** $Id: ametadataioxml.h,v 1.2 2008/12/13 22:19:15 leader Exp $ +** +** Header file of the Ananas configuration objects of Ananas +** Designer and Engine applications +** +** Created : 20031201 +** +** Copyright (C) 2003-2008 Grazhdankin Valeriy. All rights reserved. +** +** This file is part of the Library of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.leaderit.ru/page=ananas or email sales@leaderit.ru +** See http://www.leaderit.ru/gpl/ for GPL licensing information. +** +** Contact org@leaderit.ru if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#ifndef AMETADATAOIXML_H +#define AMETADATAIOXML_H +#include "ametadataio.h" +#include +#include + +class AMetaDataIOXML: public AMetaDataIO +{ +Q_OBJECT +public: + AMetaDataIOXML(); + int read(const QString &name, AMetaData *md = 0); + int write( const QString &name, AMetaData *md = 0); + QString text(); +private: + void XMLToAMetaObject( QDomElement e, AMetaObject *o ); + QDomElement AMetaObjectToXML( AMetaObject *o ); + QDomDocument xml; +}; + +#endif diff --git a/src/lib/metadata/ametadocument.cpp b/src/lib/metadata/ametadocument.cpp new file mode 100644 index 0000000..0de6592 --- /dev/null +++ b/src/lib/metadata/ametadocument.cpp @@ -0,0 +1,61 @@ +/**************************************************************************** +** $Id: ametadocument.cpp,v 1.1 2008/12/15 22:22:48 leader Exp $ +** +** Code file of the Ananas configuration objects of Ananas +** Designer and Engine applications +** +** Created : 20031201 +** +** Copyright (C) 2003-2004 Leader InfoTech. All rights reserved. +** Copyright (C) Grigory Panov , Yoshkar-Ola. +** +** This file is part of the Library of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.leaderit.ru/page=ananas or email sales@leaderit.ru +** See http://www.leaderit.ru/gpl/ for GPL licensing information. +** +** Contact org@leaderit.ru if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ +#include "ametadocument.h" + +/*! + * \class AMetaDocument + * + */ +AMetaDocument::AMetaDocument() +:AMetaObject("Document") +{ +} + + +AMetaFields * +AMetaDocument::fields() +{ + return &v_fields; +} + + + +AMetaTables * +AMetaDocument::tables() +{ + return &v_tables; +} + + +AMetaForms * +AMetaDocument::forms() +{ + return &v_forms; +} diff --git a/src/lib/metadata/ametadocument.h b/src/lib/metadata/ametadocument.h new file mode 100644 index 0000000..91ff5e8 --- /dev/null +++ b/src/lib/metadata/ametadocument.h @@ -0,0 +1,56 @@ +/**************************************************************************** +** $Id: ametadocument.h,v 1.1 2008/12/15 22:22:48 leader Exp $ +** +** Header file of the Ananas configuration objects of Ananas +** Designer and Engine applications +** +** Created : 20031201 +** +** Copyright (C) 2003-2004 Leader InfoTech. All rights reserved. +** Copyright (C) Andrey Paskal , Yoshkar-Ola +** Copyright (C) 2003-2005 Grigory Panov , Yoshkar-Ola +** +** This file is part of the Library of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.leaderit.ru/page=ananas or email sales@leaderit.ru +** See http://www.leaderit.ru/gpl/ for GPL licensing information. +** +** Contact org@leaderit.ru if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ +#ifndef AMETADOCUMENT_H +#define AMETADOCUMENT_H + +#include "ametaobject.h" +#include "ametaobjectgroup.h" +#include "ametafield.h" + + +class AMetaDocument: public AMetaObject +{ +Q_OBJECT +public: + AMetaDocument(); + +public slots: + AMetaFields *fields(); + AMetaTables *tables(); + AMetaForms *forms(); + +private: + AMetaFields v_fields; + AMetaTables v_tables; + AMetaForms v_forms; +}; + +#endif diff --git a/src/lib/metadata/ametafield.cpp b/src/lib/metadata/ametafield.cpp new file mode 100644 index 0000000..e979278 --- /dev/null +++ b/src/lib/metadata/ametafield.cpp @@ -0,0 +1,176 @@ +/**************************************************************************** +** $Id: ametafield.cpp,v 1.1 2008/12/15 22:22:48 leader Exp $ +** +** Code file of the Ananas configuration objects of Ananas +** Designer and Engine applications +** +** Created : 20031201 +** +** Copyright (C) 2003-2004 Leader InfoTech. All rights reserved. +** Copyright (C) Grigory Panov , Yoshkar-Ola. +** +** This file is part of the Library of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.leaderit.ru/page=ananas or email sales@leaderit.ru +** See http://www.leaderit.ru/gpl/ for GPL licensing information. +** +** Contact org@leaderit.ru if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ +#include "ametafield.h" + + +/*! + * \class AMetaField + * + */ +AMetaField::AMetaField() +:AMetaObject("MetaField") +{ + setFieldType( Unknown ); + setFieldSubType( 0 ); + setWidth( 0 ); + setDecimals( 0 ); + setNotNull( false ); + setNotNegative( false ); + setCalcSumm( false ); +} + + +AMetaField::AMetaField( FieldTypes t, int st, int w, int d, bool notnul, bool notneg, bool calcsum ) +:AMetaObject("MetaField") +{ + setFieldType( t ); + setFieldSubType( st ); + setWidth( w ); + setDecimals( d ); + setNotNull( notnul ); + setNotNegative( notneg ); + setCalcSumm( calcsum ); +} + + +int +AMetaField::fieldType() +{ + return attr("type").toInt(); +} + + + +void +AMetaField::setFieldType( FieldTypes t ) +{ + setAttr( "type", t ); +} + + + +int +AMetaField::fieldSubType() +{ + return attr("subtype").toInt(); +} + + +void +AMetaField::setFieldSubType( int st ) +{ + setAttr( "subtype", st ); +} + + +int +AMetaField::width() +{ + return attr("width").toInt(); +} + + +void +AMetaField::setWidth( int w ) +{ + setAttr( "width", w ); +} + + + +int +AMetaField::decimals() +{ + return attr("decimals").toInt(); +} + + +void +AMetaField::setDecimals( int d ) +{ + setAttr( "decimals", d ); +} + + + +bool +AMetaField::notNull() +{ + return attr("notnull").toBool(); +} + + +void +AMetaField::setNotNull( bool f ) +{ + setAttr( "notnull", f ); +} + + +bool +AMetaField::notNegative() +{ + return attr("notnegative").toBool(); +} + + +void +AMetaField::setNotNegative( bool f ) +{ + setAttr( "notnegative", f ); +} + + + +bool +AMetaField::calcSumm() +{ + return attr("calcsumm").toBool(); +} + + +void +AMetaField::setCalcSumm( bool f ) +{ + setAttr( "calcsumm", f ); +} + + + +/*! + * \class AMetaFields + * + */ +AMetaFields::AMetaFields() +:AMetaObjectGroup("MetaFields") +{ + +} + diff --git a/src/lib/metadata/ametafield.h b/src/lib/metadata/ametafield.h new file mode 100644 index 0000000..9e3c5e6 --- /dev/null +++ b/src/lib/metadata/ametafield.h @@ -0,0 +1,95 @@ +/**************************************************************************** +** $Id: ametafield.h,v 1.1 2008/12/15 22:22:48 leader Exp $ +** +** Header file of the Ananas configuration objects of Ananas +** Designer and Engine applications +** +** Created : 20031201 +** +** Copyright (C) 2003-2004 Leader InfoTech. All rights reserved. +** Copyright (C) Andrey Paskal , Yoshkar-Ola +** Copyright (C) 2003-2005 Grigory Panov , Yoshkar-Ola +** +** This file is part of the Library of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.leaderit.ru/page=ananas or email sales@leaderit.ru +** See http://www.leaderit.ru/gpl/ for GPL licensing information. +** +** Contact org@leaderit.ru if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ +#ifndef AMETAFIELD_H +#define AMETAFIELD_H + +#include "ametaobject.h" +#include "ametaobjectgroup.h" + + +class AMetaField: public AMetaObject +{ +Q_OBJECT +Q_ENUMS( FieldTypes ) +Q_PROPERTY( int fieldtype READ fieldType SCRIPTABLE true ) +Q_PROPERTY( int fieldsubtype READ fieldSubType SCRIPTABLE true ) +Q_PROPERTY( int width READ width SCRIPTABLE true ) +Q_PROPERTY( int decimals READ decimals SCRIPTABLE true ) +Q_PROPERTY( bool notnull READ notNull SCRIPTABLE true ) +Q_PROPERTY( bool notnegative READ notNegative SCRIPTABLE true ) +Q_PROPERTY( bool calcsumm READ calcSumm SCRIPTABLE true ) + +public: + enum FieldTypes { Unknown, Char, String, Number, Date, Object, Document, Catalogue }; + AMetaField(); + + AMetaField( FieldTypes t, int st = 0, int w = 0, + int d = 0, bool notnul = false, bool notneg = false, + bool calcsum = false ); + + int fieldType(); + void setFieldType( FieldTypes t ); + + int fieldSubType(); + void setFieldSubType( int st ); + + int width(); + void setWidth( int w ); + + int decimals(); + void setDecimals( int d ); + + bool notNull(); + void setNotNull( bool f ); + + bool notNegative(); + void setNotNegative( bool f ); + + bool calcSumm(); + void setCalcSumm( bool f ); + +private: + +}; + + +class AMetaFields: public AMetaObjectGroup +{ +Q_OBJECT +public: + AMetaFields(); + +public slots: + + +}; + +#endif diff --git a/src/lib/metadata/ametaform.cpp b/src/lib/metadata/ametaform.cpp new file mode 100644 index 0000000..4f98592 --- /dev/null +++ b/src/lib/metadata/ametaform.cpp @@ -0,0 +1,40 @@ +/**************************************************************************** +** $Id: ametaform.cpp,v 1.1 2008/12/15 22:22:48 leader Exp $ +** +** Code file of the Ananas configuration objects of Ananas +** Designer and Engine applications +** +** Created : 20031201 +** +** Copyright (C) 2003-2004 Leader InfoTech. All rights reserved. +** Copyright (C) Grigory Panov , Yoshkar-Ola. +** +** This file is part of the Library of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.leaderit.ru/page=ananas or email sales@leaderit.ru +** See http://www.leaderit.ru/gpl/ for GPL licensing information. +** +** Contact org@leaderit.ru if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ +#include "ametaform.h" + + +/*! + * \class AMetaField + * + */ +AMetaForm::AMetaForm() +:AMetaObject("MetaForm") +{ +} diff --git a/src/lib/metadata/ametaform.h b/src/lib/metadata/ametaform.h new file mode 100644 index 0000000..0436d21 --- /dev/null +++ b/src/lib/metadata/ametaform.h @@ -0,0 +1,45 @@ +/**************************************************************************** +** $Id: ametaform.h,v 1.1 2008/12/15 22:22:48 leader Exp $ +** +** Header file of the Ananas configuration objects of Ananas +** Designer and Engine applications +** +** Created : 20031201 +** +** Copyright (C) 2003-2004 Leader InfoTech. All rights reserved. +** Copyright (C) Andrey Paskal , Yoshkar-Ola +** Copyright (C) 2003-2005 Grigory Panov , Yoshkar-Ola +** +** This file is part of the Library of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.leaderit.ru/page=ananas or email sales@leaderit.ru +** See http://www.leaderit.ru/gpl/ for GPL licensing information. +** +** Contact org@leaderit.ru if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ +#ifndef AMETAFORM_H +#define AMETAFORM_H + +#include "ametaobject.h" + +class AMetaForm: public AMetaObject +{ +Q_OBJECT +public: + AMetaForm(); +private: + +}; + +#endif diff --git a/src/lib/metadata/ametaobject.cpp b/src/lib/metadata/ametaobject.cpp new file mode 100644 index 0000000..7f19273 --- /dev/null +++ b/src/lib/metadata/ametaobject.cpp @@ -0,0 +1,386 @@ +/**************************************************************************** +** $Id: ametaobject.cpp,v 1.2 2008/12/15 22:22:48 leader Exp $ +** +** Code file of the Ananas configuration objects of Ananas +** Designer and Engine applications +** +** Created : 20031201 +** +** Copyright (C) 2003-2004 Leader InfoTech. All rights reserved. +** Copyright (C) Grigory Panov , Yoshkar-Ola. +** +** This file is part of the Library of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.leaderit.ru/page=ananas or email sales@leaderit.ru +** See http://www.leaderit.ru/gpl/ for GPL licensing information. +** +** Contact org@leaderit.ru if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#include +//#include +#include +#include +#include +#include + +#include "ametaobject.h" +#include "ametaobjectgroup.h" + +/*! + * \class AMetaObject + * + */ +/*! + *\en + * Metadata object for metadata script access. + *\_en + *\ru + * \brief Объект метаданных для обеспечения доступа из скриптов. + * Наследует QObject. + *\_ru + */ + +AMetaObject::AMetaObject(const QString &objectclass, + const QString &objectname, + AMetaObjectGroup *parent) +:QObject( parent ) +{ + setObjectName( objectname ); + setClassName( objectclass ); + setDescription(""); +} + + +Q_ULONG +AMetaObject::id() +{ + return v_id; +} + + +void +AMetaObject::setId( Q_ULONG new_id ) +{ + v_id = new_id; +} + + +void +AMetaObject::setClassName( const QString &name ) +{ + v_className = name; +} + + +QString +AMetaObject::className() +{ + return v_className; +} + + +QString +AMetaObject::name() +{ + return objectName(); +} + + +QString +AMetaObject::description() +{ + return text("description"); +} + +void +AMetaObject::setDescription( const QString &descr ) +{ + setText( "description", descr ); +} + + +void +AMetaObject::setAttr( const QString &name, const QVariant &value ) +{ + if ( value.isNull() && attrExists( name ) ) v_attr.remove( name ); + else v_attr[ name ] = value; +} + + + +void +AMetaObject::setText( const QString &name, const QString &text ) +{ + if ( text.isNull() && textExists( name ) ) v_text.remove( name ); + else v_text[ name ] = text; +} + + +void +AMetaObject::setRawdata( const QString &name, const QByteArray &data ) +{ + if ( data.isNull() && rawdataExists( name ) ) v_rawdata.remove( name ); + else v_rawdata[ name ] = data; +} + + + +QVariant +AMetaObject::attr( const QString &name ) const +{ + return v_attr.value( name, QVariant() ); +} + + + +QString +AMetaObject::text( const QString &name ) const +{ + return v_text.value( name, QString::null ); +} + + + +QByteArray +AMetaObject::rawdata( const QString &name ) const +{ + return v_rawdata.value( name, QByteArray() ); +} + + + +QVariant +AMetaObject::attr( int idx ) const +{ + return attr( attrName( idx ) ); +} + + + +QString +AMetaObject::text( int idx ) const +{ + return text( textName( idx ) ); +} + + + +QByteArray +AMetaObject::rawdata( int idx ) const +{ + return rawdata( rawdataName( idx ) ); +} + + + +QString +AMetaObject::attrName( int idx ) const +{ + if ( idx < 0 || idx >= attrCount() ) return QString::null; + return v_attr.keys().at( idx ); +} + + + +QString +AMetaObject::textName( int idx ) const +{ + if ( idx < 0 || idx >= textCount() ) return QString::null; + return v_text.keys().at( idx ); +} + + + +QString +AMetaObject::rawdataName( int idx ) const +{ + if ( idx < 0 || idx >= rawdataCount() ) return QString::null; + return v_rawdata.keys().at( idx ); +} + + + +bool +AMetaObject::attrExists( const QString &name ) +{ + return v_attr.contains( name ); +} + + + +bool +AMetaObject::textExists( const QString &name ) +{ + return v_text.contains( name ); +} + + + +bool +AMetaObject::rawdataExists( const QString &name ) +{ + return v_rawdata.contains( name ); +} + + + +int +AMetaObject::attrCount() const +{ + return v_attr.size(); +} + + + +int +AMetaObject::textCount() const +{ + return v_text.size(); +} + + +int +AMetaObject::rawdataCount() const +{ + return v_rawdata.size(); +} + + + +/*! + * \class AMetaCatalogue + * + */ +AMetaCatalogue::AMetaCatalogue() +:AMetaObject("Catalogue") +{ +} + + + +/*! + * \class AMetaDataInfo + * + */ +AMetaDataInfo::AMetaDataInfo() +:AMetaObject("Info") +{ + setAppName("new"); + setAuthor("unknown"); + setDate( QDate::currentDate() ); + setLastId( 100 ); + +} + + +AMetaDataInfo::AMetaDataInfo( const AMetaDataInfo &info ) +:AMetaObject("Info") +{ +} + + +AMetaDataInfo::~AMetaDataInfo() +{ +} + + +AMetaDataInfo& +AMetaDataInfo::operator=(const AMetaDataInfo&) +{ + return *this; +} + + +QString +AMetaDataInfo::appName() +{ + return text("name"); +} + + +void +AMetaDataInfo::setAppName( const QString &name ) +{ + setText( "name", name ); +} + + +long +AMetaDataInfo::lastId() +{ + return text( "lastid" ).toLong(); +} + + +void +AMetaDataInfo::setLastId( long id ) +{ + setText( "lastid", QString::number( id ) ); +} + + +QString +AMetaDataInfo::author() +{ + return text("author"); +} + + +void +AMetaDataInfo::setAuthor( const QString &name ) +{ + setText( "author", name ); +} + + +QDate +AMetaDataInfo::date() +{ + return QDate::fromString( text("date"), Qt::ISODate ); +} + + +void +AMetaDataInfo::setDate( QDate d ) +{ + setText( "date", d.toString( Qt::ISODate ) ); +} + + + +/*! + * \class AMetaDataGlobal + * + */ +AMetaDataGlobal::AMetaDataGlobal() +:AMetaObject("Global") +{ + setSourceCode("function on_systemstart()\n{\n}\n"); +} + + +QString +AMetaDataGlobal::sourceCode() +{ + return text("sourcecode"); +} + + +void +AMetaDataGlobal::setSourceCode( const QString &src ) +{ + setText( "sourcecode", src ); +} + diff --git a/src/lib/metadata/ametaobject.h b/src/lib/metadata/ametaobject.h new file mode 100644 index 0000000..18bb096 --- /dev/null +++ b/src/lib/metadata/ametaobject.h @@ -0,0 +1,162 @@ +/**************************************************************************** +** $Id: ametaobject.h,v 1.2 2008/12/15 22:22:48 leader Exp $ +** +** Header file of the Ananas configuration objects of Ananas +** Designer and Engine applications +** +** Created : 20031201 +** +** Copyright (C) 2003-2004 Leader InfoTech. All rights reserved. +** Copyright (C) Andrey Paskal , Yoshkar-Ola +** Copyright (C) 2003-2005 Grigory Panov , Yoshkar-Ola +** +** This file is part of the Library of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.leaderit.ru/page=ananas or email sales@leaderit.ru +** See http://www.leaderit.ru/gpl/ for GPL licensing information. +** +** Contact org@leaderit.ru if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ +#ifndef AMETAOBJECT_H +#define AMETAOBJECT_H + +#include +#include + +#ifdef __BORLANDC__ +#define CHECK_POINT printf("%s:%i %s()\n",__FILE__,__LINE__,__FUNC__); +#else +#define CHECK_POINT printf("%s:%i %s()\n",__FILE__,__LINE__,__FUNCTION__); +#endif + +/*! + * \~english Metadata object methods return codes. \~russian + * Коды возвратов методов объекта метаданных. \~ + */ +#define RC_OK 0 /**< All right - no errors */ +#define RC_ERROR 1 /**< Error while executing method */ + +#include +#include +class AMetaObjectGroup; + +class AMetaObject: public QObject +{ +Q_OBJECT +// system properties +Q_PROPERTY( Q_ULONG id READ id SCRIPTABLE true ) +Q_PROPERTY( QString name READ name SCRIPTABLE true ) +Q_PROPERTY( QString className READ className SCRIPTABLE true ) +Q_PROPERTY( QString description READ description SCRIPTABLE true ) + +public: + AMetaObject( const QString &objectclass = QString::null, + const QString &objectname = QString::null, + AMetaObjectGroup *parent = 0 ); + + void setClassName( const QString &name ); + + Q_ULONG id(); + void setId( Q_ULONG ); + QString className(); + QString name(); + + QString description(); + void setDescription( const QString &descr ); + + void setAttr( const QString &name, const QVariant &value ); + void setText( const QString &name, const QString &text ); + void setRawdata( const QString &name, const QByteArray &data ); + + QVariant attr( const QString &name ) const; + QString text( const QString &name ) const; + QByteArray rawdata( const QString &name ) const; + + QVariant attr( int idx ) const; + QString text( int idx ) const; + QByteArray rawdata( int idx ) const; + + QString attrName( int idx ) const; + QString textName( int idx ) const; + QString rawdataName( int idx ) const; + + bool attrExists( const QString &name ); + bool textExists( const QString &name ); + bool rawdataExists( const QString &name ); + + int attrCount() const; + int textCount() const; + int rawdataCount() const; + +public slots: + +private: + Q_ULONG v_id; + QString v_className; + QHash v_attr; + QHash v_text; + QHash v_rawdata; +}; + + + +class AMetaCatalogue: public AMetaObject +{ +Q_OBJECT +public: + AMetaCatalogue(); +}; + + + +class AMetaDataInfo: public AMetaObject +{ +Q_OBJECT +Q_PROPERTY( QString appname READ appName SCRIPTABLE true ) +Q_PROPERTY( QString author READ author SCRIPTABLE true ) +Q_PROPERTY( QDate date READ date SCRIPTABLE true ) +public: + AMetaDataInfo(); + AMetaDataInfo( const AMetaDataInfo &info ); + ~AMetaDataInfo(); + AMetaDataInfo& operator=(const AMetaDataInfo&); + + QString appName(); + void setAppName( const QString &name ); + long lastId(); + void setLastId( long id ); + QString author(); + void setAuthor( const QString &name ); + QDate date(); + void setDate( QDate d ); +}; + + +class AMetaDataGlobal: public AMetaObject +{ +Q_OBJECT +public: + AMetaDataGlobal(); + + QString sourceCode(); + void setSourceCode( const QString &src ); + +}; + +Q_DECLARE_METATYPE ( AMetaDataInfo ) + +//qRegisterMetaType("MetaDataInfo"); +//Q_DECLARE_METATYPE ( AMetaDataGlobal ) + +#endif diff --git a/src/lib/metadata/ametaobjectgroup.cpp b/src/lib/metadata/ametaobjectgroup.cpp new file mode 100644 index 0000000..bd2e97a --- /dev/null +++ b/src/lib/metadata/ametaobjectgroup.cpp @@ -0,0 +1,220 @@ +/**************************************************************************** +** $Id: ametaobjectgroup.cpp,v 1.2 2008/12/15 22:22:48 leader Exp $ +** +** Code file of the Ananas configuration objects of Ananas +** Designer and Engine applications +** +** Created : 20031201 +** +** Copyright (C) 2003-2004 Leader InfoTech. All rights reserved. +** Copyright (C) Grigory Panov , Yoshkar-Ola. +** +** This file is part of the Library of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.leaderit.ru/page=ananas or email sales@leaderit.ru +** See http://www.leaderit.ru/gpl/ for GPL licensing information. +** +** Contact org@leaderit.ru if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#include +#include +#include +#include +//--#include +#include +#include + +#include "ametaobject.h" +#include "ametaobjectgroup.h" + +#define context_startid 100 + + +/*! + * \class AMetaObjectGroup + * + */ +AMetaObjectGroup::AMetaObjectGroup( const QString &groupname ) +:QObject() +{ + setObjectName( groupname ); +} + + + + +AMetaObjectGroup::AMetaObjectGroup( const QString &groupname, AMetaObject *parent ) +:QObject( parent ) +{ + setObjectName( groupname ); +} + + +AMetaObjectGroup::AMetaObjectGroup( const QString &groupname, AMetaObjectGroup *parent ) +:QObject( parent ) +{ + setObjectName( groupname ); +} + + +QString +AMetaObjectGroup::name() +{ + return objectName(); +} + + + +AMetaObject * +AMetaObjectGroup::metaObject( const QString &name ) +{ + return findChild( name ); +} + + + +AMetaObject * +AMetaObjectGroup::metaObject( int idx ) +{ + return v_metaObjects.at( idx ); +} + + +void +AMetaObjectGroup::append( AMetaObject *obj ) +{ + obj->setParent( this ); + v_metaObjects.append( obj ); + connect( obj, SIGNAL(destroyed(QObject*)), this, SLOT(destroyed(QObject *))); +} + + +int +AMetaObjectGroup::count() const +{ + return v_metaObjects.count(); +} + + +void +AMetaObjectGroup::clear() +{ + v_metaObjects.clear(); +} + + +void +AMetaObjectGroup::destroyed( QObject *obj ) +{ + if ( obj->inherits("AMetaObject") ){ + v_metaObjects.removeAll( ( AMetaObject *) obj ); + } +} + + + +/*! + * \class ADocumentsGroup + * + */ +ADocumentsGroup::ADocumentsGroup() +:AMetaObjectGroup("Documents") +{ + +} + + + +/*! + * \class ACataloguesGroup + * + */ +ACataloguesGroup::ACataloguesGroup() +:AMetaObjectGroup("Catalogues") +{ + +} + + + +/*! + * \class AReportsGroup + * + */ +AReportsGroup::AReportsGroup() +:AMetaObjectGroup("Reports") +{ + +} + + + +/*! + * \class AReportsGroup + * + */ +AJournalsGroup::AJournalsGroup() +:AMetaObjectGroup("Journals") +{ + +} + + + +/*! + * \class AInformationRegistersGroup + * + */ +AInfoRegistersGroup::AInfoRegistersGroup() +:AMetaObjectGroup("InfoRegisters") +{ + +} + + + +/*! + * \class AInformationRegistersGroup + * + */ +AAccRegistersGroup::AAccRegistersGroup() +:AMetaObjectGroup("AccRegisters") +{ + +} + + + +/*! + * \class AMetaTables + * + */ +AMetaTables::AMetaTables() +:AMetaObjectGroup("MetaTables") +{ + +} + + + +/*! + * \class AMetaForms + * + */ +AMetaForms::AMetaForms() +:AMetaObjectGroup("MetaForms") +{ + +} diff --git a/src/lib/metadata/ametaobjectgroup.h b/src/lib/metadata/ametaobjectgroup.h new file mode 100644 index 0000000..52210a6 --- /dev/null +++ b/src/lib/metadata/ametaobjectgroup.h @@ -0,0 +1,185 @@ +/**************************************************************************** +** $Id: ametaobjectgroup.h,v 1.2 2008/12/15 22:22:48 leader Exp $ +** +** Header file of the Ananas configuration objects of Ananas +** Designer and Engine applications +** +** Created : 20031201 +** +** Copyright (C) 2003-2004 Leader InfoTech. All rights reserved. +** Copyright (C) Andrey Paskal , Yoshkar-Ola +** Copyright (C) 2003-2005 Grigory Panov , Yoshkar-Ola +** +** This file is part of the Library of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.leaderit.ru/page=ananas or email sales@leaderit.ru +** See http://www.leaderit.ru/gpl/ for GPL licensing information. +** +** Contact org@leaderit.ru if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ +#ifndef AMETAOBJECTGROUP_H +#define AMETAOBJECTGROUP_H + +#include +#include +#include + +#include "ametaobject.h" + +#include +#include + + +/*! + *\en + * Metadata object for metadata script access. + *\_en + *\ru + * \brief Объект метаданных для обеспечения доступа из скриптов. + * Наследует QObject. + *\_ru + */ +class AMetaObjectGroup: public QObject +{ +Q_OBJECT +Q_PROPERTY( QString name READ name SCRIPTABLE true ) +public: + AMetaObjectGroup( const QString &groupname ); + AMetaObjectGroup( const QString &groupname, AMetaObject *parent ); + AMetaObjectGroup( const QString &groupname, AMetaObjectGroup *parent ); + + QString name(); +// QMetaObject *metaObject(const QString &objClass, const QString &objName); +// QMetaObject *metaObject(const QString &objClass, const QString &objName); + AMetaObject *metaObject( const QString &name ); + AMetaObject *metaObject( int idx ); + void append( AMetaObject *object ); + int count() const; + void clear(); + +public slots: + QString test(){ return QString("TEST STRING");}; + +private slots: + void destroyed( QObject *obj ); + +private: + QList v_metaObjects; +}; + + +class ACataloguesGroup: public AMetaObjectGroup +{ +Q_OBJECT +public: + ACataloguesGroup(); + +public slots: + + +}; + + + +class ADocumentsGroup: public AMetaObjectGroup +{ +Q_OBJECT +public: + ADocumentsGroup(); + +public slots: + QString test(){ return QString("DOCUMENTS TEST STRING");}; + + +}; + + + +class AReportsGroup: public AMetaObjectGroup +{ +Q_OBJECT +public: + AReportsGroup(); + +public slots: + + +}; + + + +class AJournalsGroup: public AMetaObjectGroup +{ +Q_OBJECT +public: + AJournalsGroup(); + +public slots: + + +}; + + + +class AInfoRegistersGroup: public AMetaObjectGroup +{ +Q_OBJECT +public: + AInfoRegistersGroup(); + +public slots: + + +}; + + + +class AAccRegistersGroup: public AMetaObjectGroup +{ +Q_OBJECT +public: + AAccRegistersGroup(); + +public slots: + + +}; + + + +class AMetaTables: public AMetaObjectGroup +{ +Q_OBJECT +public: + AMetaTables(); + +public slots: + + +}; + + + +class AMetaForms: public AMetaObjectGroup +{ +Q_OBJECT +public: + AMetaForms(); + +public slots: + + +}; + +#endif diff --git a/src/lib/metadata/metadata.pri b/src/lib/metadata/metadata.pri new file mode 100644 index 0000000..d914a90 --- /dev/null +++ b/src/lib/metadata/metadata.pri @@ -0,0 +1,19 @@ +HEADERS += \ + metadata/ametadata.h \ + metadata/ametaobject.h \ + metadata/ametaobjectgroup.h \ + metadata/ametafield.h \ + metadata/ametadocument.h \ + metadata/ametaform.h \ + metadata/ametadataio.h \ + metadata/ametadataioxml.h + +SOURCES += \ + metadata/ametadata.cpp \ + metadata/ametaobject.cpp \ + metadata/ametaobjectgroup.cpp \ + metadata/ametafield.cpp \ + metadata/ametadocument.cpp \ + metadata/ametaform.cpp \ + metadata/ametadataio.cpp \ + metadata/ametadataioxml.cpp diff --git a/src/lib/objects/aaregister.cpp b/src/lib/objects/aaregister.cpp new file mode 100644 index 0000000..5b7a027 --- /dev/null +++ b/src/lib/objects/aaregister.cpp @@ -0,0 +1,585 @@ +/**************************************************************************** +** $Id: aaregister.cpp,v 1.3 2008/11/09 21:09:11 leader Exp $ +** +** Code file of the Accumulation Register of Ananas +** Engine applications +** +** Created : 20031201 +** +** Copyright (C) 2003-2004 Leader InfoTech. All rights reserved. +** Copyright (C) Andrey Paskal , Yoshkar-Ola +** Copyright (C) 2005 Grigory Panov , Yoshkar-Ola +** +** This file is part of the Library of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.leaderit.ru/page=ananas or email sales@leaderit.ru +** See http://www.leaderit.ru/gpl/ for GPL licensing information. +** +** Contact org@leaderit.ru if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#include "aaregister.h" +#include "adatabase.h" +#include "adocjournal.h" +#include "alog.h" +#include +//Added by qt3to4: +#include + + +/*! + *\en + * Constructor that create object of aAregister by metadata object. + *\_en + *\ru + * Конструктор, который создает объект по элементу метаданных. + *\_ru + *\param context -\en configuration item, \_en \ru + элемент конфигурации,\_ru + *\param adb -\en link on ananas database.\_en \ru + ссылка на базу данных.\_ru + */ +aARegister::aARegister( aCfgItem context, aDatabase * adb ) +:aIRegister( context, adb ) +{ + concrete = !context.isNull(); + initObject(); +} + + + +/*! + *\en + * Сonstructor that create object of aAregister by metadata name + *\_en + *\ru + * Конструктор, который создает объект по имени рагистра остатков из конфигурации. + *\_ru + *\param context -\en md name of register,\_en \ru + имя регистра, заданное в конфигурации через Ананас-Дизайнер,\_ru + *\param adb - + \en link on ananas database.\_en + \ru ссылка на базу данных. Необязательный параметр. Если не задан или задано нулевое + значение, создавамый объект для работы с регистром не будет связан с базой данный. + То есть объект не будет заполнен данными из регистра, хранящимися в базе данных, + и все изменения, вносимые в него, не будут сохранены в базе данных. + \_ru + */ +aARegister::aARegister( QString name, aDatabase *adb ) +:aIRegister( name, adb, "AccumulationRegister.") +{ + if ( name.isEmpty() ) concrete = false; + else concrete = true; + initObject(); +} + +/*! + *\en + * Destructor + *\_en + *\ru + * Деструктор. + *\_ru + */ +aARegister::~aARegister() +{ +} + + +/*! + *\en + * Initing this object by metadata object. + * Сreating used tables and filters + *\_en + *\ru + * Инициализирует объект элементом конфигурации. + * В процесе инициализации выполняется настройка на таблицы базы данных. + * Этот метод вызывается конструктором. + *\_ru + *\return -\en error code.\_en \ru код ошибки.\_ru + */ +ERR_Code +aARegister::initObject() +{ + int len_uf; + //resnames.clear(); + ERR_Code err = aIRegister::initObject(); + if ( err ) + { + aLog::print(aLog::Error, tr("Accumulation Register init")); + return err; + } + err = tableInsert( db->tableDbName(*md,obj), obj ); + if ( err ) + { + aLog::print(aLog::Error, tr("Accumulation Register create main table")); + return err; + } + aCfgItem field, dims = md->find(obj, md_dimensions,0); + aCfgItem ress = md->find(obj, md_resources,0); + //if ( res.isNull() ) return err_noresources; + tablename = table()->tableName; + uint n = md->count( dims, md_field ); + for ( uint i = 0; i < n; i++ ) + { + field = md->find( dims, md_field, i ); + err = tableInsert( db->tableDbName(*md,field), field, md->attr(field,mda_name) ); + if ( err ) + { + aLog::print(aLog::Error, tr("Accumulation Register create saldo table")); + return err; + } + long mdid = md->id(field); + QString f_name = md->attr(field,mda_name); + dimnames[mdid]=f_name; + } + ress = md->find(obj, md_resources,0); + n = md->count( ress, md_field ); + for ( uint i = 0; i < n; i++ ) + { + field = md->find( ress, md_field, i ); + long mdid = md->id(field); + QString f_name = md->attr(field,mda_name); + resnames[mdid]=f_name; + resSysNames[f_name]=QString("uf%1").arg(md->attr(field,mda_id)); + } + return err_noerror; +} + + +/*! + *\en + * \brief Adds new line to register table. + * + * \return Error code + * \see SetDocument( aDocument * doc ) + * \see SetTable( const QString & tblname ) + *\_en + *\ru + * \brief Добавляет новую строку к таблице регистра. + * + * \return Код ошибки + * \see SetDocument( aDocument * doc ) + * \see SetTable( const QString & tblname ) + *\_ru + */ +int +aARegister::New() +{ + if ( !docseted ) return err_nodocument; + aSQLTable * t = table(); + if ( !t ) return err_notable; + qulonglong idd = nowDoc->getUid(); + if ( !idd ) return err_notselected; + int err = aObject::New(); + if ( err ) return err; + t->setSysValue( "idd", idd ); + t->setSysValue( "date", nowDoc->Value("DocDate") ); + if ( tableseted ) + { + aSQLTable * tt = nowDoc->getTable ( tname ); + t->setSysValue("iddt",tt->sysValue("id")); + t->setSysValue("ln",tt->sysValue("ln")); + } + err = Update(); + if ( err ) return err; + else return select(getUid()); +} + +/*! + *\en + * Updates information in database. + * Reimplements aObject function for recalc rests. + *\_en + *\ru + * Обновляет информацию в регитре. + * Все новые значения, заданные с помощью SetValue, сохраняются в базе данных. + * Выполняет пересчет остатков. + *\_ru + *\return -\en error code.\_en \ru код ошибки.\_ru + */ +int +aARegister::Update() +{ + aIRegister::Update(); + qulonglong uid = getUid(); + resum( table(), nowDoc->Value("DocDate").toDateTime(), true ); + aLog::print(aLog::Debug, tr("Accumulation Register update")); + return err_noerror;//aIRegister::Update(); +} + + +/*! + *\en + * Deletes records from accumulation registers. + * Deletes all records from accumulation register tables that contents reference to doc. + *\_en + *\ru + * Удаляет все записи в регистре, ссылающиеся на досумент. + *\_ru + *\param doc - \en document to delete\_en \ru + документ для удаления\_ru + *\return - \en false if can't find tag in meta data or have no document.\_en \ru + false если в конфигурации отсутствует раздел регистров остатков или нет документа.\_ru + */ +bool +aARegister::deleteDocument( aDocument * doc ) +{ + qulonglong idd = doc->getUid(); + if ( !idd ) return false; + aSQLTable *t = table(); + if ( t->select(QString("idd=%1").arg(idd) )) + { + if(t->first()) + { + do + { + resum( t, doc->Value("DocDate").toDateTime(), false ); + }while(t->next()); + } + db->db()->exec(QString("delete from %1 where idd=%2").arg(t->tableName).arg(idd)); + aLog::print(aLog::Info, QString("Accumulation register delete document with idd=%1").arg(idd)); + } + return true; +} + + + + +/*! + *\en + * Gets saldo. + * Helper metod. + *\_en + * \see getSaldo(const QDateTime &date, const QString & dimfieldname, QVariant dimvalue, const QString &resname) + *\ru + * Функция получения остатка. Вспомогательный метод. Служит для совместимости со скриптами. + *\_ru + *\param strdate - \en date\_en \ru дата, за которую надо получить остаток. Дата задается в виде строки в ISO формате.\_ru + *\param dimfieldname - \en name of dimensions field\_en \ru измерение, по которому нужно получить остаток\_ru + *\param dimvalue - \en value of dimensions field\_en \ru значение измерения, по которому надо получить остаток\_ru + *\param resname - \en name of resounces field\_en \ru ресурс, значение которого надо получить\_ru + *\return - \en Saldo value or QVariant::Invalid on error.\_en \ru + Значение остатка или QVariant::Invalid при ошибке или неправильных параметрах.\_ru + */ +QVariant +aARegister::getSaldo(const QString & strdate, const QString & dimfieldname, QVariant dimvalue, const QString &resname) +{ + QDateTime data = QDateTime::fromString(strdate,Qt::ISODate); + + if (!data.isValid()){ + QDate dt = QDate::fromString(strdate,Qt::ISODate); + if(dt.isValid()) + { + QTime tm; + data.setDate(dt); + data.setTime(tm); + return getSaldo(data,dimfieldname, dimvalue,resname); + } + else + { + aLog::print(aLog::Error, QString(tr("Accumulation register convert datetime from string %1")).arg(strdate)); + return QVariant::Invalid; + } + } + else + { + return getSaldo(data,dimfieldname, dimvalue,resname); + } +} + + + +/*! + * \ru + * Выбирает остаток на заданную дату-время. + * Выбирает остаток на заданную дату-время для одного (любого из заданных в регистре) + * аналитического разреза (измерения) с указанным значением. + * Проще говоря, метод позволяет получить, например, остаток по дебету или кредиту требуемого счета + * на требуемую дату, если регистр используется для хранения бухгалтерских проводок, в каждой из которых + * указывается один дебетуемый и один кредитуемый счет. + * \param date - дата, на которую требуется получить остаток. + * \param dimfieldname - название аналитического разреза регистра. + * \param dimvalue - значение (точка) аналитического разреза, для которого требуется определить остаток. + * Например для Аналитического разреза "Счет по дебету" значение может быть "41.1" или любой другой + * номер счета бухгалтерского плана счетов. + * \return возвращает значение остатка. + * \_ru + */ + +QVariant +aARegister::getSaldo(const QDateTime &date, const QString & dimfieldname, QVariant dimvalue, const QString &resname) +{ + aSQLTable *t_dim = table(dimfieldname); + if(!t_dim) + { + aLog::print(aLog::Error,QString(tr("Accumulation register not found table %1")).arg(dimfieldname)); + return QVariant::Invalid; + } + t_dim->clearFilter(); + if(!t_dim->setFilter(dimfieldname,dimvalue)) + { + aLog::print(aLog::Error,tr("Accumulation register set filter")); + return QVariant::Invalid; + } + QString flt = QString("date<='%1' and %2").arg(date.toString(Qt::ISODate)).arg(t_dim->getFilter()); + + QString query = QString("select * from %1 where %2").arg(t_dim->tableName).arg(flt); + t_dim->clearFilter(); + t_dim->select(); + + QSqlQuery q = db->db()->exec(query); + q.last(); + if(q.isValid()) + { + return q.value(t_dim->position(resSysNames[resname])); + } + else + { + aLog::print(aLog::Debug,"Accumulation register record empty"); + } + return QVariant::Invalid;// t_dim->value(resname);//QVariant::Invalid; +} + + +/*! + * \ru + * Вычисляет сумму за определенный период. + * Выбирает сумму для одного (минимум) аналитического разреза (измерения) с указанным значением. + * Если необходимо сальдо по нескольким измерениям, установите по ним фильтры \see aIRegister::SetFilter() + * \param from - дата начала периода. + * \param to - дата окончания периода. + * \param dimfieldname - название аналитического разреза регистра. + * \param dimvalue - значение (точка) аналитического разреза, для которого требуется определить остаток. + * Например для Аналитического разреза "Счет по дебету" значение может быть "41.1" или любой другой + * номер счета бухгалтерского плана счетов. + * \return возвращает значение остатка. + * \_ru + */ +QVariant +aARegister::getSaldoByManyDimensions(const QString &from, const QString &to, const QString & dimfieldname, QVariant dimvalue, const QString &resname) +{ + aSQLTable *t = table(); + QString currentFilter; + + if(!t) + { + aLog::print(aLog::Error,QString(tr("Accumulation register not found main table"))); + return QVariant::Invalid; + } + currentFilter = t->filter(); // QSqlCursor method call + + if(!t->setFilter(dimfieldname,dimvalue)) + { + aLog::print(aLog::Error,tr("Accumulation register set filter")); + t->setFilter( currentFilter ); // QSqlCursor method call + t->select(); + return QVariant::Invalid; + } + QString flt = QString("date>='%1' and date<='%2' and %3 ").arg(from).arg(to).arg(t->getFilter()); + + QString query = QString("select sum(%1) from %2 where %3").arg(resSysNames[resname]).arg(t->tableName).arg(flt); + + aLog::print(aLog::Info,QString("Accumulation register query %1").arg(query)); + QSqlQuery q = db->db()->exec(query); + q.last(); + if(q.isValid()) + { + t->setFilter( currentFilter ); + t->select(); + return q.value(0);//t->position(resSysNames[resname])); + } + else + { + aLog::print(aLog::Debug,"Accumulation register record empty"); + } + t->setFilter( currentFilter ); + t->select(); + return 0; + +} +/*! + *\en + * Recalculates rest tables. + *\_en + *\ru + * Пересчитывает таблицы остатков. + * Таблицы остатков пересчитывается для всех занчений с равной или более поздней датой. + * В передаваемой таблице должны быть выбрана запись, обусловившая пересчет. + *\_ru + *\param t - \en table with selected record \_en \ru + * таблица с выбранной записью\_ru + *\param dd - \en date for start recalculation.\_en \ru + * дата, с которой пересчитаются остатки.\_ru + *\param plus - \en true for new record, false for delete\_en \ru + * true для новой записи, false для удаления записи.\_ru + */ +void +aARegister::resum( aSQLTable * t, const QDateTime & dd, bool plus ) +{ + aCfgItem dims; + dims = md->find( obj, md_dimensions ); + int dims_count = md->count(dims,md_field); + for(uint i=0; ifindChild(dims,md_field,i); + long dimId = atoi(md->attr(dim,mda_id).ascii()); + aSQLTable *t_dim = table(md->attr(dim,mda_name)); + QVariant v = t->value(md->attr(dim,mda_name)); + if(v.isValid() && !v.isNull() && v!=QString()) + { + recalculate_saldo(t_dim, t, dd, plus, dimId, v ); + } + } +} + + + +/*! + *\ru + * Выбирает запись в таблице остатков с заданной датой, если ее нет, то создает новую. + * После этого вызывает функцию для обновления значений остатков. + *\_ru + *\param t_dim - \en saldo table \_en \ru таблица остатков для обновления\_ru + *\param t - \en table \_en \ru таблица оборотов с выбранной записью, из которой берутся значения\_ru + *\param dd - \en date for start recalculation.\_en \ru дата, с которой пересчитаются остатки.\_ru + *\param plus - \en true for new record, false for delete\_en \ru true для новой записи, false для удаления записи.\_ru + *\param dimId - \en dimension id\_en \ru id поля измерения в метаданных\_ru + *\param dimValue - \en dimension value\_en \ru значение поля измерения в метаданных\_ru + */ +void //protected +aARegister::recalculate_saldo(aSQLTable *t_dim, aSQLTable *t, const QDateTime & dd, bool plus, long dimId, QVariant dimValue) +{ + QString query = QString("select * from %1 where date='%2' and uf%3='%4'").arg(t_dim->tableName).arg(dd.toString(Qt::ISODate)).arg(dimId).arg(dimValue.toString()); + + QSqlQuery q =db->db()->exec(query); + q.first(); + if(!q.isValid()) + { + t_dim->select(); + QString where = QString("date<'%2' and uf%3='%4'").arg(dd.toString(Qt::ISODate)).arg(dimId).arg(dimValue.toString()); + query = QString("select * from %1 where %2").arg(t_dim->tableName).arg(where); + QString values; + q = db->db()->exec(query); + q.last(); + if(q.isValid()) + { + //t_dim->select(query,false); + //t_dim->last(); + insert_values(&q,t_dim,dd,plus,dimId,dimValue); + } + else + { + insert_values(0,t_dim,dd,plus,dimId,dimValue); + } + } + update_values(t_dim,dd,plus,dimId,dimValue,t); +} + +/*! + *\ru + * Добавляет запись в таблицу остатков. + *\_ru + *\param q - \en query with selected record \_en \ru запрос с данными для добавления. Если q!=0, то данные из q попадут в добавляемую строку\_ru + *\param t_dim - \en saldo table \_en \ru таблица остатков\_ru + *\param dd - \en date for start recalculation.\_en \ru дата, с которой пересчитаются остатки.\_ru + *\param plus - \en true for new record, false for delete\_en \ru true для новой записи, false для удаления записи.\_ru + *\param dimId - \en dimension id\_en \ru id поля измерения в метаданных\_ru + *\param dimValue - \en dimension value\_en \ru значение поля измерения в метаданных\_ru + */ + +int //protected +aARegister::insert_values(QSqlQuery *q, aSQLTable *t_dim, const QDateTime & dd, bool plus, long dimId, QVariant dimValue) +{ + int res=0; + QString ins_col = QString("date,uf%1,").arg(dimId); + QString ins_val = QString("'%1','%2',").arg(dd.toString(Qt::ISODate)).arg(dimValue.toString()); + QMap::Iterator it; + QVariant res_value; + for ( it = resSysNames.begin(); it != resSysNames.end(); ++it ) + { + if(q) + { + res_value = q->value(t_dim->position(it.data())); + } + else + { + res_value = 0; + } + ins_col+=QString("%1,").arg(it.data()); + ins_val+=QString("%2,").arg(res_value.toString()); + } + ins_col.truncate(ins_col.length()-1); + ins_val.truncate(ins_val.length()-1); + QString query = QString("insert into %1 (%2) values(%3)").arg(t_dim->tableName).arg(ins_col).arg(ins_val); + db->db()->exec(query); + t_dim->select(); + return res; +} + + + +/*! + *\ru + * Обновляет записи в таблице остатков с датой, большей или равной заданной. + *\_ru + *\param t_dim - \en saldo table \_en \ru таблица остатков для обновления\_ru + *\param t - \en table \_en \ru таблица оборотов с выбранной записью, из которой берутся значения\_ru + *\param dd - \en date for start recalculation.\_en \ru дата, с которой пересчитаются остатки.\_ru + *\param plus - \en true for new record, false for delete\_en \ru true для новой записи, false для удаления записи.\_ru + *\param dimId - \en dimension id\_en \ru id поля измерения в метаданных\_ru + *\param dimValue - \en dimension value\_en \ru значение поля измерения в метаданных\_ru + */ +int //protected +aARegister::update_values(aSQLTable *t_dim, const QDateTime & dd, bool plus, long dimId, QVariant dimValue, aSQLTable *t) +{ + QMap::Iterator it; + QString upd; + QString where = QString("date>='%1' and uf%2='%3'").arg(dd.toString(Qt::ISODate)).arg(dimId).arg(dimValue.toString()); + QVariant res_value; + QString sign;//="-"; + //if(plus) sign="+"; + for ( it = resnames.begin(); it != resnames.end(); ++it ) + { + if(t) + { + res_value = t->value(it.data()); + } + else + { + res_value = 0; + } + if(plus) sign="+"; + else sign ="-"; + upd+=QString("uf%1=uf%2%3%4,").arg(it.key()).arg(it.key()).arg(sign).arg(res_value.toString()); + } + upd.truncate(upd.length()-1); + QString query = QString("update %1 set %2 where %3").arg(t_dim->tableName).arg(upd).arg(where); + db->db()->exec(query); + return 0; +} + + + + + +QString +aARegister::trSysName( const QString & sname) +{ + if(sname == tr("RecordDate") || sname == "RecordDate" ) + { + return "date"; + } + else return ""; +} diff --git a/src/lib/objects/aaregister.h b/src/lib/objects/aaregister.h new file mode 100644 index 0000000..ac1e906 --- /dev/null +++ b/src/lib/objects/aaregister.h @@ -0,0 +1,104 @@ +/**************************************************************************** +** $Id: aaregister.h,v 1.1 2008/11/05 21:16:29 leader Exp $ +** +** Header file of the Accumulation Register of Ananas +** Engine applications +** +** Created : 20031201 +** +** Copyright (C) 2003-2004 Leader InfoTech. All rights reserved. +** Copyright (C) 2003-2004 Andrey Paskal . +** +** This file is part of the Library of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.leaderit.ru/page=ananas or email sales@leaderit.ru +** See http://www.leaderit.ru/gpl/ for GPL licensing information. +** +** Contact org@leaderit.ru if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#ifndef AAREGISTER_H +#define AAREGISTER_H + +#include "acfg.h" +#include "airegister.h" +//Added by qt3to4: +#include + + + +/*! + *\en + * Object for working with accumulation register in database. + * Using for provide between database tables and wobjects or ananas scripts + *\_en + *\ru + *\brief Класс aARegister определяет программный интерфейс Накопительных регистров. Наследует aIRegister. + * + * Накопительный регистр расширяет функциональность информационного регистра aIRegister, + * автоматически расчитывая остатки по каждому измерению. + * В базе данных хранятся остатки по каждому измерению и на каждое время изменения значения ресурсов. + * Реквизиты накопительного регистра деляться на три вида: измерения, ресурсы, примечания. + * \see aIRegister + *\_ru + */ +class ANANAS_EXPORT aARegister : public aIRegister +{ + Q_OBJECT +public: + aARegister(aCfgItem context, aDatabase * adb = 0); + aARegister(QString name, aDatabase * adb = 0); + virtual ~aARegister(); + + virtual ERR_Code initObject(); + + virtual bool deleteDocument( aDocument * doc ); + //virtual bool deleteTable( Q_ULLONG iddt ); + virtual QString trSysName( const QString & sname ); +public slots: + virtual ERR_Code New(); + virtual int Update(); + //int SelectCountByDoc(); + //int ClosePeriod( const QDateTime & date = QDateTime::currentDateTime() ); + //int SelectRemainders(const QDateTime & date = QDateTime::currentDateTime() ); + //int SelectRemainders(const QString & strdate); + //int SelectRemainder(const QString & strdate, const QString & dimfieldname, QVariant dimvalue); + QVariant getSaldo(const QDateTime &date, const QString & dimfieldname, QVariant dimvalue, const QString &resname); + QVariant getSaldo(const QString &dateISO, const QString & dimfieldname, QVariant dimvalue, const QString &resname); + + QVariant getSaldoByManyDimensions(const QString &from, const QString &to, const QString & dimfieldname, QVariant dimvalue, const QString &resname); + /* + QVariant SumValue( const QString & name ); + bool SumNext(); + bool SumPrev(); + bool SumFirst(); + bool SumLast(); + */ +protected: + void recalculate_saldo(aSQLTable *t, aSQLTable *t_dim, const QDateTime & dd, bool plus, long dimId, QVariant dimValue); + int insert_values(QSqlQuery *q, aSQLTable *t_dim, const QDateTime & dd, bool plus, long dimId, QVariant dimValue); + int update_values(aSQLTable *t_dim, const QDateTime & dd, bool plus, long dimId, QVariant dimValue, aSQLTable *t=0); +private: + + void resum( aSQLTable * t, const QDateTime & dd, bool plus ); + QString tablename; + QSqlQuery sumQuery; + QMap resnames; + QMap resSysNames; + QMap dimnames; + //QDateTime actualDate; + //ERR_Code makeTmpTable( const QDateTime & date ); +}; + +#endif// AAREGISTER_H diff --git a/src/lib/objects/acatalogue.cpp b/src/lib/objects/acatalogue.cpp new file mode 100644 index 0000000..63b6a54 --- /dev/null +++ b/src/lib/objects/acatalogue.cpp @@ -0,0 +1,1146 @@ +/**************************************************************************** +** $Id: acatalogue.cpp,v 1.3 2008/11/09 21:09:11 leader Exp $ +** +** Catalogue metadata object implementation file of +** Ananas application library +** +** Created : 20031201 +** +** Copyright (C) 2003-2004 Leader InfoTech. All rights reserved. +** Copyright (C) 2003-2004 Grigory Panov, Yoshkar-Ola. +** +** This file is part of the Designer application of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.leaderit.ru/page=ananas or email sales@leaderit.ru +** See http://www.leaderit.ru/gpl/ for GPL licensing information. +** +** Contact org@leaderit.ru if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#include "acfg.h" +#include "aobject.h" +#include "adatabase.h" +#include "acatalogue.h" +#include "alog.h" +//Added by qt3to4: +#include + + +/*!\en + *\_en \ru + *\_ru + */ +aCatalogue::aCatalogue( aCfgItem context, aDatabase * adb ) +:aObject( context, adb, 0, "aCatalogue") +{ + concrete = !context.isNull(); + initObject(); +} + + + +/*!\en + *\_en \ru + *\_ru + */ +aCatalogue::aCatalogue(QString name, aDatabase * adb) +:aObject( "Catalogue."+name, adb, 0, "aCatalogue") +{ + if ( name.isEmpty() ) concrete = false; + else concrete = true; + initObject(); +} + + + +ERR_Code +aCatalogue::initObject() +{ + ERR_Code err = aObject::initObject(); + if ( err ) return err; + aCfgItem g = md->find( obj, md_group ), e = md->find( obj, md_element ); + err = tableInsert( aDatabase::tableDbName( *md, e ), e ); + if ( err ) return err; + return tableInsert( aDatabase::tableDbName( *md, g ), g, md_group ); +} + +/* +Q_ULLONG +aCatalogue::getCatGroup() +{ + aSQLTable * t = table(); + if ( !t ) return 0; + if ( !selected() ) return 0; + return t->sysValue("idg").toULongLong(); +}*/ + +qulonglong +aCatalogue::getGroup() +{ + aSQLTable * t = table(md_group); + if ( !t ) return 0; + if ( !selected(md_group) ) return 0; + return t->sysValue("id").toULongLong(); +} + +ERR_Code +aCatalogue::setGroup( qulonglong idg ) +{ + aSQLTable * t = table(); + if ( !t ) return err_notable; + if ( !selected() ) return err_notselected; + t->setSysValue( "idg", idg ); + t->primeUpdate(); + t->update(); + return err_noerror; +} + +ERR_Code +aCatalogue::SetGroup( aCatalogue * cat ) +{ + if ( !cat ) return setGroup( 0 ); + else return setGroup(cat->getGroup()); +} + +qulonglong +aCatalogue::getOwner() +{ + aSQLTable * t = table(); + if ( !t ) return 0; + if ( !selected() ) return 0; + return t->sysValue("ido").toULongLong(); +} + +ERR_Code +aCatalogue::setOwner( qulonglong ido ) +{ + aSQLTable * t = table(); + if ( !t ) return err_notable; + if ( !selected() ) return err_notselected;; + t->setSysValue( "ido", ido ); + t->primeUpdate(); + t->update(); + return err_noerror; +} + +ERR_Code +aCatalogue::SetOwner( aCatalogue * cat ) +{ + if ( !cat ) return setOwner( 0 ); + else return setOwner(cat->getUid()); +} + +ERR_Code +aCatalogue::New( bool child ) +{ + qulonglong group = getGroup(), parent = getUid(); + ERR_Code err = aObject::New(); + if ( err ) return err; + aSQLTable * t = table(); + t->setSysValue( "idg", group ); + if ( child ) t->setSysValue( "ido", parent ); + t->primeUpdate(); + t->update(); + if ( group ) groupSelect(); + setSelected(true); + return err_noerror; +} + + +ERR_Code +aCatalogue::New( ) +{ + return New(false); +} + + +ERR_Code +aCatalogue::Delete() +{ + aSQLTable * t = table(); + if ( !t ) return err_notable; + if ( !selected() ) return err_notselected; + qulonglong ido = t->sysValue("id").toULongLong(); + if ( ido ) + { + aLog::print(aLog::Debug, tr("aCatalogue delete ido=%1").arg(ido)); + aCatalogue cat( obj, db ); + while ( !cat.selectByOwner(ido) ) + { + cat.Delete(); + } + } + return aObject::Delete(); +} + +ERR_Code +aCatalogue::Update() +{ + ERR_Code err = aObject::Update(); + if ( !err ) + { + + aLog::print(aLog::Debug, tr("aCatalogue update")); + err = TableUpdate( md_group ); + if(err) + { + aLog::print(aLog::Error, tr("aCatalogue update groups error %1").arg(err)); + } + else + { + aLog::print(aLog::Debug, tr("aCatalogue update groups")); + } + } + else + { + aLog::print(aLog::Error, tr("aCatalogue update elements error %1").arg(err)); + } + return err; +} + +ERR_Code +aCatalogue::Copy() +{ + return aObject::Copy(); +} + +ERR_Code +aCatalogue::Select( bool grouponly ) +{ + aSQLTable * t = table(); + if ( !t ) return err_notable; +// setSelected(true,md_group); +// setSelected(true); + qulonglong idg = getGroup(); + QString flt = ""; +// groupSelect(); + if ( grouponly ) flt = QString("idg=%1").arg( idg ); + if ( t->select( flt ) ) + if ( t->first() ) + { + setSelected(true); + qulonglong newidg = t->sysValue("idg").toULongLong(); + + aLog::print(aLog::Debug, tr("aCatalogue select group id=%1").arg(idg)); + if ( newidg != idg ) groupSelect( newidg ); + return err_noerror; + } + else return err_notselected; + else return err_selecterror; +} + +/*! + *\~english + * Select group. + * Get group id from current element and select group table + * with this id. + *\~russian + *\~ + * \return \~english Error code \~russian \~ + */ +int +aCatalogue::GroupSelect() +{ + aSQLTable * t = table(); + if(!t) return err_notable; + if ( !selected() ) return err_notselected;; + qulonglong idg = t->sysValue("idg").toULongLong(); + return groupSelect(idg); +} +void +aCatalogue::UnSelect( bool grouponly ) +{ + if (!grouponly ) + { + setSelected(false); + } + setSelected(false, md_group); +} +ERR_Code +aCatalogue::groupSelect ( qulonglong idg ) +{ + if ( !idg ) return err_noerror; + aSQLTable * t = table( md_group ); + if ( !t ) return err_notable; + setSelected( false, md_group ); + if ( t->select( idg ) ) + if ( t->first() ) + { + setSelected( true, md_group ); + return err_noerror; + } + else return err_notselected; + else return err_selecterror; +} + + +ERR_Code +aCatalogue::groupSelect () +{ + aSQLTable * t = table(md_group); + if ( !t ) return err_notable; + qulonglong idg = t->sysValue("id").toULongLong(); + return groupSelect( idg ); +} + +ERR_Code +aCatalogue::selectByOwner ( qulonglong ido ) +{ + aSQLTable * t = table(); + + if ( !t ) return err_notable; + if ( t->select(QString("ido=%1").arg(ido),false) ) + if ( t->first() ) + { + setSelected(true); + return err_noerror; + } + else return err_notselected; + else return err_selecterror; +} + +ERR_Code +aCatalogue::selectByGroup ( qulonglong idg ) +{ + aSQLTable * t = table(); + if ( !t ) return err_notable; + setSelected(false); + if ( t->select(QString("idg=%1").arg(idg),false ) ) + if ( t->first() ) + { + setSelected(true); + return err_noerror; + } + else return err_notselected; + else return err_selecterror; +} + +ERR_Code +aCatalogue::groupByParent(qulonglong idp ) +{ + aSQLTable * t = table( md_group ); + if ( !t ) return err_notable; +//f ( !selected(md_group) ) return err_notselected; + setSelected( false, md_group ); + if ( t->select(QString("idp=%1").arg(idp),false) ) + if ( t->first() ) + { + setSelected(true,md_group); + return err_noerror; + } + else + { + return err_notselected; + } + else return err_selecterror; +} + + + +/*!\en + * Select groups depth level. + * \param level (in) - level +\_en \ru + * + *\_ru +*/ +int +aCatalogue::selectByLevel(int level ) +{ + aSQLTable * t = table(md_group); + if ( !t ) return err_notable; +// if ( !selected(md_group) ) return err_notselected; + setSelected( false, md_group ); + if ( t->select(QString("level=%1").arg(level),false) ) + if ( t->first() ) + { + + setSelected(true, md_group); + return err_noerror; + } + else + { + return err_notselected; + } + else + { + return err_selecterror; + } + +} + + + +/*!\en + * Gets id of group on the id of element + * \param ide (in) - id of element. + * \return id of group. + \_en \ru + * Получает идентификационный номер группы по номеру элемента + * \param ide (in) - идентификационный номер элемента. + * \return идентификационный номер группы. + *\_ru + */ +qulonglong +aCatalogue::idGroupByElement(qulonglong ide ) +{ + aSQLTable * t = table(); + if ( !t ) return 0; + t->select(QString("id=%1").arg(ide), false); + if ( t->first() ) + { + setSelected(true); + return sysValue("idg").toLongLong(); + } + else return 0; +} + +ERR_Code +aCatalogue::GroupNew( bool reparent ) +{ + aSQLTable * te = table(), *tg = table( md_group ); + if ( !te || !tg ) return err_notable; +// groupSelect(); +// setSelected(true, md_group); + qulonglong idp = getGroup(), level = tg->sysValue("level").toULongLong(), + idg = tg->primeInsert()->value("id").toULongLong(); + if ( tg->insert() ) + { + if ( idp ) level++; + tg->select( idg ); + if ( !tg->first() ) return err_selecterror; + tg->selected = true; + aLog::print(aLog::Info,tr("aCatalogue new group with id=%1").arg(idg) ); + tg->setSysValue("idp",idp); + tg->setSysValue("level",level); + if ( reparent ) te->setSysValue("idg",idg); + } + return Update(); +} + + + +/*!\en + * Inserts new group in groups table + * \param parentId (in) - id parent group, or 0 if no parent. + \_en \ru + * Вставляет новую группу в таблицу групп + * \param parentId (in) - идентификационный номер группы предка или 0 если нет предка. + *\_ru +*/ +ERR_Code +aCatalogue::newGroup(qulonglong parentId ) +{ + aSQLTable *tg = table( md_group ); + if (!tg ) return err_notable; + setSelected(true, md_group); + tg->select(parentId); + setSelected(true,md_group); + qulonglong level, idg; + if(tg->first()) + { + level = tg->sysValue("level").toULongLong()+1; + } + else level=0; + QSqlRecord* rec = tg->primeInsert(); // get edit buffer for table groups + idg = rec->value("id").toULongLong(); + aLog::print(aLog::Info,tr("aCatalogue new group with id=%1").arg(idg) ); + rec->setValue("id",idg ); + rec->setValue("idp",parentId); + rec->setValue("level",level); + rec->setValue("df","0"); + tg->insert(); // insert record + tg->select(QString("id=%1").arg(idg),false); // set cursor to inserted record + tg->first(); + setSelected(true,md_group); + //tg->update(); +return groupSelect(idg); +} + + + +/*!\en + * Inserts new element in elements table + * \param parentId (in) - id parent group. + \_en \ru + * Вставляет новый элемент в таблицу элементов + * \param parentId (in) - идентификационный номер группы предка. + *\_ru + */ +ERR_Code +aCatalogue::newElement(qulonglong parentId ) +{ + aSQLTable *te = table(); + if (!te) return err_notable; + QSqlRecord *rec; + qulonglong ide; + rec = te->primeInsert(); // get edit buffer for table elements + ide = rec->value("id").toULongLong(); + rec->setValue("id",ide); // set defult values for all user fields = id + //for(uint i=0; i< rec->count(); i++) + //{ + // rec->setValue(i,ide); +// printf("%s\n",rec->fieldName(i).ascii()); + //} + rec->setValue("idg",parentId); + rec->setValue("df","0"); + rec->setNull("ido"); + te->insert(); // insert edit buffer as new line in table + te->select(QString("id=%1").arg(ide),false); // set cursor to inserted record + te->first(); + setSelected(true); + return err_noerror; +} + + + +/*!\en + * Mark deleted element only. Don't supports link one to many. + * \return id of deleted element. + \_en \ru + * Только выделяет удаляемый элемент. Не поддерживает связь один ко многим. + * \return идентификационный номер удаляемого элемента. + *\_ru + */ +qulonglong +aCatalogue::setMarkDeletedElement(qulonglong id_el,bool del) +{ + select(id_el); + SetMarkDeleted(del); + Update(); +return table()->sysValue("id").toULongLong(); +} +qulonglong +aCatalogue::setMarkDeletedGroup(qulonglong id_gr, bool del) +{ + groupSelect(id_gr); + SetMarkDeleted(del, md_group); + GroupUpdate(); +return table()->sysValue("id").toULongLong(); +} + + + +/*!\en + * Delets element only. Don't supports link one to many. + * \return id of deleted element. + \_en \ru + * Только удаляет элемент. Не поддерживает связь один ко многим. + * \return идентификационный номер удаляемого элемента. + *\_ru + */ +qulonglong +aCatalogue::delElement() +{ + aSQLTable * t = table(); + qulonglong ide=0; + if ( !t ) return ide; + ide = t->sysValue("id").toULongLong(); + if ( ide ) + { + aLog::print(aLog::Info,tr("aCatalogue delete element with id=%1").arg(ide)); + t->primeDelete(); + t->del(); + setSelected( false ); + } + return ide; +} + + + +/*!\en + * Mark deleted group with child elements and groups. + * \param idg (in) - id mark deleted group. + * \param listDelId (in,out) - list of id mark deleted elements and groups. + \_en \ru + * Выделяет удаляемую группу с дочерними элементами и группами. + * При первом вызове параметр listDelId должен быть пустой, он не обнуляется + * автоматически при вызове этой функции. + * Функция рекурсивно вызывает сама себя для всех дочерних подгрупп и + * добавляет их id в список. Также туда добавляются и id элементов, + * содержащихся в этих группах. Для изменения атрибута удаления используте функции + * setElementMarkDeleted(id)(для элементов) и setGroupMarkDeleted(id) (для групп) + * \param idg (in) - идентификационный номер выделенной для удаления группы. + * \param listDelId (in,out) - список идентификационных номеров выделенных для удаления элементов и групп. + *\_ru + */ +void +aCatalogue::getMarkDeletedList(qulonglong idg, + Q3ValueList &listDelId) +{ + Q3ValueList lst; + aSQLTable * tg = table ( md_group ); + if ( !tg ) return; + qulonglong tmp; + if ( idg ) + { + + // delete elements in group; + if(selectByGroup(idg)==err_noerror) + { + do + { + listDelId << sysValue("id").toULongLong(); + } + while(Next()); + } + if (groupByParent(idg)==err_noerror) + { + do + { + lst << GroupSysValue("id").toULongLong(); + }while(NextInGroupTable()); + + Q3ValueList::iterator it = lst.begin(); + while(it!= lst.end()) + { + getMarkDeletedList((*it),listDelId); + ++it; + } + } + + } + tg->select(QString("id=%1").arg(idg),false); + if(tg->first()) + { + listDelId << idg; + } + return; +} +bool +aCatalogue::isGroupMarkDeleted() +{ + return IsMarkDeleted(md_group); +} +bool +aCatalogue::isElementMarkDeleted() +{ + return IsMarkDeleted(); +} + + + +/*!\en + * Delets group with child elements and groups. + * \param idg (in) - id deleted group. + * \param listDelId (in,out) - list of id deleted elements and groups. + \_en \ru + * Физически удаляет группу со всеми ее дочерними элементами и группами. + * \param idg (in) - идентификационный номер выделенной для удаления группы. + * \param listDelId (in,out) - список идентификационных номеров выделенных для удаления элементов и групп. + *\_ru + */ +qulonglong +aCatalogue::delGroup(qulonglong idg, Q3ValueList &listDelId) +{ + aSQLTable * tg = table ( md_group ); + if ( !tg ) return 0; + //if ( !selected( md_group ) ) return err_notselected; + qulonglong tmp;// idg = tg->sysValue("id").toULongLong(); + groupSelect(idg); + if ( idg ) + { + + aLog::print(aLog::Info,tr("aCatalogue delete group with id=%1").arg(idg)); + // printf("idg=" LLU_SPEC "\n",idg); + // delete elements in group; + while(selectByGroup(idg)==err_noerror) + { + listDelId << delElement(); + } + while (groupByParent(idg)==err_noerror) + { + delGroup(GroupSysValue("id").toULongLong(), listDelId); + //printf(">>>idg=%lu\n",tmp); + } + } + tg->select(QString("id=%1").arg(idg),false); + if(tg->first()) + { + tg->primeDelete(); + tg->del(); + listDelId << idg; + setSelected( false, md_group ); + } + return idg; +} +ERR_Code +aCatalogue::GroupDelete() +{ + aSQLTable * tg = table ( md_group ); + if ( !tg ) return err_notable; + getGroup(); + if ( !selected( md_group ) ) + { + + aLog::print(aLog::Info,tr("aCatalogue delete without selection")); + //debug_message(">>not seletc in delete\n"); + return err_notselected; + } + + qulonglong idg = tg->sysValue("id").toULongLong(); + if ( idg ) + { + //printf("idg=" LLU_SPEC "\n",idg); + aCatalogue cat( obj,db ); + while ( !cat.selectByGroup(idg) ) cat.Delete(); + while ( !cat.groupByParent(idg) ) + { + //printf("delete group\n"); + cat.GroupDelete(); + } + } + tg->primeDelete(); + tg->del(); + aLog::print(aLog::Info,tr("aCatalogue delete group with id=%1").arg(idg)); + if(tg->first()) + { + setSelected( true, md_group ); + } + else + { + setSelected( false, md_group ); + } + return err_noerror; +} + +ERR_Code +aCatalogue::GroupMarkDeleted() +{ + aSQLTable * t = table ( md_group ); + if ( !t ) return err_notable; + if ( !selected( md_group ) ) return err_notselected; + if ( SetMarkDeleted( true, md_group ) ) return err_noerror; + else return err_deleteerror; +} + +ERR_Code +aCatalogue::GroupUpdate() +{ + aLog::print(aLog::Debug, tr("aCatalogue update group")); + return TableUpdate( md_group ); +} + +ERR_Code +aCatalogue::GroupSetGroup( aCatalogue * cat ) +{ + aSQLTable * t = table( md_group ); + if ( !t ) return err_notable; + qulonglong newidp, oldidp = t->sysValue("idp").toULongLong(); + if ( !cat ) newidp = 0; + else newidp = cat->getGroup(); + if ( newidp == oldidp ) return err_noerror; + t->setSysValue( "idp", newidp ); + t->primeUpdate(); + t->update(); + return err_noerror; +} + +QVariant +aCatalogue::GroupValue( const QString & name ) +{ + aSQLTable * t = table( md_group ); + if ( !t ) return QVariant::Invalid; + return t->value( name ); +} + + + +/*!\en + * Gets system field value in table of group. + * \param name (in) - field name. + * \return field value or QVariant::Invalid if no field. + \_en \ru + *\_ru + */ +QVariant +aCatalogue::GroupSysValue( const QString & name ) +{ + aSQLTable * t = table( md_group ); + if ( !t ) return QVariant::Invalid; + //if(name=="id") return t->sysValue(name).toString(); + return t->sysValue( name );//.toString(); +} + +ERR_Code +aCatalogue::GroupSetValue( const QString & name, const QVariant & value ) +{ + aSQLTable * t = table( md_group ); + if ( !t ) return err_notable; + if ( !selected( md_group ) ) return err_notselected; + if ( t->setValue( name, value ) ) return err_noerror; + else return err_fieldnotfound; + +} + + +ERR_Code +aCatalogue::GroupSetSysValue( const QString & name, const QVariant & value ) +{ + aSQLTable * t = table( md_group ); + if ( !t ) return err_notable; + if ( !selected( md_group ) ) return err_notselected; + t->setSysValue( name, value); + return err_noerror; + //else return err_fieldnotfound; + +} + +QVariant +aCatalogue::GetElementValue(QVariant ide, const QString &fname) +{ + aSQLTable * t = table(); + if ( !t ) return ""; + t->select(ide.toULongLong()); + if ( !t->first() ) return ""; + else return t->value( fname ); + + +} +bool +aCatalogue::Next() +{ + return aObject::Next(); //return !groupSelect(); + //else return false; +} + +bool +aCatalogue::Prev() +{ + return aObject::Prev(); //return !groupSelect(); +// else return false; +} + +bool +aCatalogue::First() +{ + return aObject::First(); //return !groupSelect(); + //else return false; +} + +bool +aCatalogue::Last() +{ + return aObject::Last(); //return !groupSelect(); + //else return false; +} + +bool +aCatalogue::NextInGroupTable() +{ + return aObject::Next(md_group); +} + +bool +aCatalogue::PrevInGroupTable() +{ + return aObject::Prev(md_group); +} + +bool +aCatalogue::FirstInGroupTable() +{ + return aObject::First(md_group); +} + +bool +aCatalogue::LastInGroupTable() +{ + return aObject::Last(md_group); +} + + + +/*!\en + * Gets list user and calculation fields in table of elements. + \_en \ru + *\_ru + */ +QStringList +aCatalogue::getUserFields() +{ + QStringList l; + aSQLTable *t = table(); + if(t) l = t->getUserFields(); + return l; +} + + + +/*!\en + * Gets list user and calculation fields in table of Groups. + \_en \ru + *\_ru + */ +QStringList +aCatalogue::getGroupUserFields() +{ + QStringList l; + aSQLTable *t = table( md_group ); + if(t) l = t->getUserFields(); + return l; +} + + +aCfgItem +aCatalogue::displayStringContext() +{ + return md->find( md->find( obj, md_element ), md_string_view ); +} + + + +aCatElement::aCatElement(aCfgItem context, aDatabase * adb) +:aObject( context, adb, 0, "aElement") +{ +} + + + + +aCatGroup::aCatGroup(aCfgItem context, aDatabase * adb) +:aObject( context, adb, 0, "aGroup") +{ + int err = initObject(); +} + + + + +/*! + *\ru + * Возвращает id родительской группы + *\_ru + */ +qulonglong +aCatGroup::parentUid() +{ + if ( !selected() ) return 0; + else return table()->sysValue("idp").toULongLong(); +} + + + +void +aCatGroup::setLevel( qulonglong newLevel ) +{ + if ( !selected() ) return; + aSQLTable * t = table(); + qulonglong level = t->sysValue("level").toULongLong(); + if ( level == newLevel ) return; + aCatGroup tgr( obj, db ); + QString query; + query = QString("UPDATE %1 SET level=%2 WHERE id=%3")\ + .arg(t->tableName).arg(newLevel).arg(getUid()); +// printf("%s\n",(const char*) query); + db->db()->exec(query); + if ( !tgr.SelectChild( this )); + do + { + tgr.setLevel( newLevel + 1 ); + } + while ( tgr.Next() ); +} + + + +QString +aCatGroup::trSysName( const QString & sname ) +{ + if (( sname == "Level" )||( sname == QString::fromUtf8("Уровень") )) return "Level"; + return ""; +} + + + +QVariant +aCatGroup::sysValue( const QString & sname ) +{ + if ( sname == "Level" ) + return table()->sysValue("level"); + return QVariant::Invalid; +} + + + +/*! + *\~english + * Init object. + * We can work with object only after inited. + * Auto call from constructor. + *\~russian + *\brief Инициализирует объект элементом конфигурации. + * + * Мы можем работать с объектом после его инициализации. + * Функция вызывается из конструктора. + *\~ + * \return \en error code. \_en \ru + код ошибки.\_ru + */ +ERR_Code +aCatGroup::initObject() +{ + ERR_Code err = aObject::initObject(); + if ( err ) return err; + aCfgItem g = md->find( obj, md_group ); + return tableInsert( aDatabase::tableDbName( *md, g ), g ); +} + + +/*! + *\ru + *\brief Ничего не делает. Возвращает 0. + * + *\return Код ошибки. + *\_ru + */ + +ERR_Code +aCatGroup::New(aCatGroup *group) +{ + int rc = 0; + return rc; +} +/*! + *\en + * Create new group in table. + * New group added in root group and have level 0. + * \return Error code. + *\_en + *\ru + * \brief Добавляет группу в справочник. + * + * Группа добавляется как корневая и имеет уровень 0. + * \return Код ошибки. + *\_ru + */ +ERR_Code +aCatGroup::New() +{ + int rc = 0; + qulonglong level = 0, idg=0, idp = 0; + aSQLTable * t; + aLog::print(aLog::Info, tr("aCatGroup new group")); + int err = aObject::New(); + if(!err) + { + aLog::print(aLog::Info, tr( "aCatGroup new group ok")); + setSelected(true); + } + else + { + aLog::print(aLog::Error, tr("aCatGroup new group error %1").arg(err)); + } + return err; +} + + + +/*! + *\~english + * Select all groups. + * Select all groups use filter (if it's seted). + *\~russian + * \brief Выбирает все группы. + * + * Выбирает все группы используя фильтр (если он установлен). + *\~ + *\return \~english Error code. \~russian Код ошибки.\~ + */ +ERR_Code +aCatGroup::Select() +{ + return aObject::select(""); +} + + + +/*! + *\~english + * Select all childs. + * Select childs ( not include ) for parent. + * If parent = 0 or not parent, selected all root groups. + *\~russian + * Выбирает всех потомков. + * Выбирает всех потомков (первого уровня) для группы parent. + * Если параметр отсутствует или нулевой, находятся все группы 0 - уровня. + * Навигация по выбранным записям стандартная(Next(), Prev(), First(), Last()) + *\~ + *\param parent - \~english parent group. \~russian родительская группа.\~ + *\return \~english Error code. \~russian Код ошибки.\~ + */ +ERR_Code +aCatGroup::SelectChild( aCatGroup * parent ) +{ + qulonglong idp = 0; + if ( parent ) idp = parent->getUid(); + QString query; + query = QString("idp=%1").arg(idp); +// printf("%s\n",(const char*)query); + return select(query); +} + + + +/*! + *\~english + * Set parent for group. + * Set for current group new parent. + * Check for cycle parent and recalc levels. + *\~russian + * Устанавливает родителя для группы. + * устанавливает текущей группе родителя переданного в качестве параметра. + * Выполняется проверка на циклическое присваивание и пересчет уровней вложенности. + *\~ + *\param parent - \~english new parent group. \~russian новая родительская группа.\~ + *\return \~english Error code. \~russian Код ошибки.\~ + */ + +ERR_Code +aCatGroup::SetParent( aCatGroup * parent ) +{ + aSQLTable * t = table(); + if ( !t ) return err_notable; + qulonglong idp = 0, uid = getUid(); + if ( parent ) idp = parent->getUid(); + if ( idp == uid ) return err_cyclereparent; + qulonglong level, tmpid = idp; + aCatGroup tg( obj, db ); + while ( tmpid ) + { + tg.select(tmpid); + tmpid = tg.parentUid(); + if ( tmpid == uid ) return err_cyclereparent; + } + QString query; + query = QString("UPDATE %1 SET idp=%2 WHERE id=%3").arg(t->tableName).arg(idp).arg(uid); + level = parent->Value("Level").toULongLong(); +// printf("%s\n",(const char*)query); + QSqlDatabase tdb = *db->db(); + tdb.exec(query); + if ( !tdb.lastError().type() ) + { + if (idp) setLevel(level+1); + else setLevel(0); + return err_noerror; + } + else return err_execerror; +} + + +aCfgItem +aCatGroup::displayStringContext() +{ + return md->find( md->find( obj, md_group ), md_string_view ); +} diff --git a/src/lib/objects/acatalogue.h b/src/lib/objects/acatalogue.h new file mode 100644 index 0000000..24a3e1e --- /dev/null +++ b/src/lib/objects/acatalogue.h @@ -0,0 +1,175 @@ +/**************************************************************************** +** $Id: acatalogue.h,v 1.1 2008/11/05 21:16:29 leader Exp $ +** +** Catalogue metadata object header file of +** Ananas application library +** +** Created : 20031201 +** +** Copyright (C) 2003-2004 Leader InfoTech. All rights reserved. +** +** This file is part of the Designer application of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.leaderit.ru/page=ananas or email sales@leaderit.ru +** See http://www.leaderit.ru/gpl/ for GPL licensing information. +** +** Contact org@leaderit.ru if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#ifndef ACATALOGUE_H +#define ACATALOGUE_H + +#include "acfg.h" +#include "aobject.h" +//Added by qt3to4: +#include + +class aDatabase; +class aCatGroup; +//class aObject; + + + +/*!\en + * Not visual object used for working with catalogues in database. + * Used as interface between database and script or wObjects* + *\_en + *\ru + *\brief Класс aCatalogue определяет программный интерфейс иерархических справочников. + * Наследует aObject. + * + * Не визуальный объект используемый для работы с иерархическими каталогами (справочниками). + * Используется как интерфейс между базой данных и скриптами или wObjects* + *\_ru + */ +class ANANAS_EXPORT aCatalogue :public aObject +{ + Q_OBJECT +public: + + aCatalogue(aCfgItem context, aDatabase * adb = 0); + aCatalogue(QString name, aDatabase * adb = 0); +// virtual ERR_Code initObject(aDatabase * adb); + virtual ERR_Code initObject(); + +protected: + virtual aCfgItem displayStringContext(); + +private: +// Q_ULLONG getCatGroup(); + qulonglong getGroup(); + qulonglong getOwner(); + ERR_Code setOwner( qulonglong ido ); + ERR_Code setGroup( qulonglong idg ); + ERR_Code selectByOwner ( qulonglong ido ); + ERR_Code groupSelect (); + ERR_Code groupByParent(qulonglong idp ); +public slots: + //virtual aCatGroup * group(); + virtual int New( bool child); + virtual int New(); + virtual int Delete(); + + virtual int newGroup( qulonglong parentId ); + virtual int newElement( qulonglong parentId ); + + virtual int Update(); + virtual int Copy(); + virtual int SetOwner( aCatalogue * cat ); + virtual int SetGroup( aCatalogue * cat ); + virtual int Select( bool grouponly = false ); + void UnSelect( bool grouponly = false ); + virtual int selectByLevel ( int level ); + virtual int selectByGroup ( qulonglong idg ); + virtual qulonglong idGroupByElement(qulonglong ide ); + virtual int groupSelect ( qulonglong idg ); + + virtual QVariant GetElementValue(QVariant ide, const QString &fname); + + virtual qulonglong delElement(); + virtual qulonglong delGroup(qulonglong idg, Q3ValueList &listDelId); + + qulonglong setMarkDeletedElement(qulonglong el_id, bool del); + qulonglong setMarkDeletedGroup(qulonglong gr_id, bool del); + void getMarkDeletedList(qulonglong idg, Q3ValueList &listDelId); + + virtual bool isGroupMarkDeleted(); + virtual bool isElementMarkDeleted(); + + virtual bool Next(); + virtual bool Prev(); + virtual bool First(); + virtual bool Last(); + + virtual bool NextInGroupTable(); + virtual bool PrevInGroupTable(); + virtual bool FirstInGroupTable(); + virtual bool LastInGroupTable(); + + virtual int GroupNew( bool reparent = false ); + virtual int GroupDelete(); + virtual int GroupMarkDeleted(); + virtual int GroupUpdate(); + virtual int GroupSelect(); + virtual int GroupSetGroup( aCatalogue * cat ); + virtual QVariant GroupValue( const QString & name ); + virtual int GroupSetValue( const QString & name, const QVariant & value); + virtual QVariant GroupSysValue( const QString & name ); + virtual int GroupSetSysValue( const QString & name, const QVariant & value); +// virtual ERR_Code GroupSelectChild( aCatalogue * parent = 0 ); + virtual QStringList getUserFields(); + virtual QStringList getGroupUserFields(); +}; + +class ANANAS_EXPORT aCatElement :public aObject +{ + Q_OBJECT +public: + aCatElement(aCfgItem context, aDatabase * adb = 0); + +}; + + + +/*! + *\~english + * Object for work with catalogue group. + *\~russian + *\brief Класс aCatGroup определяет программный интерфейс для управления группами иерархических + * справочников (каталогов). Наследует aObject. + * + * Иерархический справочник может состоять из элементов и групп. Группы, в отличие от элементов + * предназначены не для хранения данных, а для группировки элементов. + */ +class ANANAS_EXPORT aCatGroup :public aObject +{ + Q_OBJECT + qulonglong parentUid(); + void setLevel( qulonglong newlevel ); + virtual QString trSysName( const QString & sname ); + QVariant sysValue( const QString & sname ); +public: + aCatGroup(aCfgItem context, aDatabase * adb = 0); + virtual ERR_Code initObject(); +public slots: + ERR_Code New(); + ERR_Code New(aCatGroup *gr); + ERR_Code Select(); + ERR_Code SelectChild( aCatGroup * parent = 0 ); + ERR_Code SetParent( aCatGroup * parent ); +protected: + virtual aCfgItem displayStringContext(); +}; + +#endif// ACATALOGUE_H diff --git a/src/lib/objects/adocjournal.cpp b/src/lib/objects/adocjournal.cpp new file mode 100644 index 0000000..6169f4b --- /dev/null +++ b/src/lib/objects/adocjournal.cpp @@ -0,0 +1,726 @@ +/**************************************************************************** +** $Id: adocjournal.cpp,v 1.3 2008/11/09 21:09:11 leader Exp $ +** +** Documents journal metadata object implementation file of +** Ananas application library +** +** Created : 20040701 +** +** Copyright (C) 2003-2004 Leader InfoTech. All rights reserved. +** +** This file is part of the Designer application of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.leaderit.ru/page=ananas or email sales@leaderit.ru +** See http://www.leaderit.ru/gpl/ for GPL licensing information. +** +** Contact org@leaderit.ru if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#include +//Added by qt3to4: +#include + +#include "acfg.h" +#include "aobject.h" +#include "adatabase.h" +#include "adocjournal.h" +#include "alog.h" + +/*! + * \en + * Constructor. Init object with \a context. + * \_en + * \ru + * Конструктор. Инициализирует объект объектом метаданных. + * \_ru + * \param context - \en md object\_en \ru объект метаданных \_ru + * \param adb - \en link to database\_en \ru ссылка на базу данных \_ru +*/ +aDocJournal::aDocJournal( aCfgItem context, aDatabase * adb ) +:aObject( context, adb, 0, "aDocJournal") +{ + initObject(); +} + + +/*! + * \en + * Constructor. Init object with md object, founded by \a name. + * \_en + * \ru + * Конструктор. Инициализирует объект объектом метаданных с именем \a name. + * \_ru + * \param name - \en md object name\_en \ru имя объекта метаданных \_ru + * \param adb - \en link to database\_en \ru ссылка на базу данных \_ru +*/ +aDocJournal::aDocJournal( const QString & name, aDatabase * adb) +:aObject( name, adb, 0, "aDocJournal") +{ + db = adb; + initObject(); +} + + +/*! + * \en + * Constructor. Creates system journal. + * \_en + * \ru + * Конструктор. Создает экземпляр системного журнала, в котором хранятся ссылки на все созданные документы. + * \_ru + * \param adb - \en link to database\_en \ru ссылка на базу данных \_ru +*/ +aDocJournal::aDocJournal( aDatabase * adb ) +{ + db = adb; + initObject(); +} + + + +ERR_Code +aDocJournal::initObject() +{ + ERR_Code err = err_noerror; + aCfgItem mditem, docitem, header; + + + journalType=0; + + setInited( true ); + md = 0; + if ( db ) md = &db->cfg; + if(!md) + { + aLog::print(aLog::Error, tr("aDocJournal md object not exists")); + return err_objnotfound; + } +// aObject::initObject(); + journalType= md->attr(obj,mda_type).toInt(); + if (journalType) + { + mditem= md->find(obj,md_fieldid); + if (mditem.isNull()) + { + aLog::print(aLog::Error, tr("aDocJournal columns not defined")); + return err; + } + else + { + aLog::print(aLog::Debug, tr("aDocJournal column defined")); + } + docitem= md->parent( md->parent( md->find(md->text(mditem).toLong()))); + + header = md->find( docitem, md_header ); + if(header.isNull()) aLog::print(aLog::Error, tr("aDocJournal invalid column define")); + //table for special journal + err = tableInsert( aDatabase::tableDbName( *md, header ), header ); +// printf("table name is %s\n", aDatabase::tableDbName( *md, header ).ascii()); + } + else + { + //table for common journal + err = tableInsert( "a_journ" ); + } + + return err; +} + + + +/*! + *\~english + * Get current document id. + * Get database id for current document. + *\~russian + * Возвращает id текущего документа. + * Возвращает id документа в базе данных. + *\~ + *\return \~english database document id. \~russian id документа в базе данных.\~ + */ +qulonglong +aDocJournal::docId() +{ + if (!journalType) { + return table()->sysValue("idd").toULongLong(); + } else { + return table()->sysValue("id").toULongLong(); + } +} + + + +/*! + *\~english + * Gets current document type. + *\~russian + * Получение типа текущего документа. + *\~ + *\return \~english database document type. \~russian тип документа в базе данных.\~ + */ +int +aDocJournal::docType() +{ + return db->uidType( docId() ); +} + + + +/*! + *\~english + * Delets current document. + *\~russian + * Удаляет текущий документ. + *\~ + *\see deleteDocument( Q_ULLONG idd ) + *\return \~english error code \~russian код ошибки.\~ + */ +ERR_Code +aDocJournal::Delete() +{ + ERR_Code err; + aDocument * doc = CurrentDocument(); + if ( !doc ) return err_notselected; + else err = doc->Delete(); + delete doc; + doc = 0; + return err; +} + + + +/*! + *\~english + * Delets document with id =\a idd. + *\~russian + * Удаляет документ с заданным идентификатором. + *\~ + *\see Delete() + *\param idd - \~english document id \~russian идентификатор документа \~ + *\return \~english error code \~russian код ошибки.\~ + */ +ERR_Code +aDocJournal::deleteDocument( qulonglong idd ) +{ + aSQLTable * t = table(); + qulonglong Uid = findDocument(idd); + db->markDeleted( Uid ); + if (t->exec("DELETE FROM a_journ WHERE idd =" + QString("%1").arg(idd))) + { + aLog::print(aLog::Info, tr("aDocJournal delete document with idd=%1").arg(idd)); + return err_noerror; + } + else + { + aLog::print(aLog::Error, tr("aDocJournal delete document with idd=%1").arg(idd)); + return err_execerror; + } +} + + + +/*! + *\~english + * Create new record in system journal. + * Record create afte crate new document and use information about doc's + * database id, prefix and metadata id(type). + * Document number generate automatically by nextNumber(). + *\~russian + * Добавляет запись в системный журнал. + * Запись добавляется после создания документа и использует информацию о его + * id в базе данных, префиксе номера и id в конфигурации. + * Номер досумента генерируется функцией nextNumber() + *\~ + *\param idd - \~english database document id.\~russian id базы данных.\~ + *\param docPrefix - \~english document number prefix. + \~russian перфикс номера документа.\~ + *\param type - \~english document metadata id. + \~russian id документа в конфигурации.\~ + *\return \~english error code.\~russian код ошибки.\~ + */ +ERR_Code +aDocJournal::New( qulonglong idd, const QString & docPrefix, int type ) +{ + //qulonglong Uid =0;// db->uid( md_systemjournal ); + aDataTable * t = table(); + if ( !t ) return err_notable; + //t->exec("LOCK TABLE a_journ WRITE"); + //printf("insert into ajourn id=%llu idd=%llu, docPrefix=%s, type=%d\n",Uid,idd, (const char*)docPrefix.local8Bit(), type); +// t->exec("LOCK TABLE a_journ WRITE"); + QSqlRecord *rec; + rec = t->primeInsert(); // get edit buffer for table elements +// t->primeInsert(); + //ide = rec->value("id").toULongLong(); + //rec->setValue("id",Uid); + rec->setValue("idd",idd); + rec->setValue("typed",type); + rec->setValue("num",nextNumber(docPrefix,type)); + rec->setValue("pnum",docPrefix); + rec->setValue("ddate",QDateTime::currentDateTime()); + + t->insert(); // insert edit buffer as new line in table +//TODO: error handle + aLog::print(aLog::Info, tr("aDocJournal new document with idd=%1").arg(idd)); + /* + t->primeInsert(); + t->insert(); + t->setSysValue( "id", Uid ); + t->setSysValue( "idd", idd ); + t->setSysValue( "typed", type ); + t->setSysValue( "num", nextNumber(docPrefix,type) ); + t->setSysValue( "pnum", docPrefix ); + t->setSysValue( "ddate", QDateTime::currentDateTime() ); + Update(); + t->exec("UNLOCK TABLE"); + */ + + int err = selectDocument( idd ); + setSelected(!err); + return err; +} + + + +/*! + *\~english + * Select document with id =\a idd. + *\~russian + * Выбирает документ с заданным идентификатором. + *\~ + *\param idd - \~english document id \~russian идентификатор документа \~ + *\see findDocument( Q_ULLONG idd ) + *\return \~english error code \~russian код ошибки.\~ + */ +ERR_Code +aDocJournal::selectDocument( qulonglong idd ) +{ + aDataTable * t = table(); + if ( !t ) return err_notable; + QString flt; + flt = QString("idd=%1").arg(idd); + if ( t->select(flt) ) + if ( t->first() ) + { + setSelected(true); + return err_noerror; + } + else return err_notselected; + return err_selecterror; +} + + + + +/*! + *\~english + * Generate next document number. + *\~russian + * Генерирует следующий номер для документа. + * Номер представляет собой строку, состоящую из префикса номера и числа. + * Номер документа генерируется используя префикс номера документа + * и его тип (id в конфигурации), как следующий за максимальным для даного сочетания. + * Номер является уникальным в для доументов одного типа. + *\~ + *\param prefix - \~english \~russian префикс номера.\~ + *\param mdId - \~english \~russian id документа в конфигурации.\~ + *\return \~english document number \~russian номер документа (только число).\~ + */ +QString +aDocJournal::nextNumber( const QString &prefix, int mdId ) +{ + QString num="0", query; + query = QString("SELECT MAX(num)+1 FROM a_journ where pnum='%1' AND typed=%2").arg( prefix ).arg(mdId); + QSqlQuery q = db->db()->exec( query ); + if ( q.first() ) num = q.value( 0 ).toString(); + if ( num == "0" ) num = "1"; + aLog::print(aLog::Info, tr("aDocJournal generated next number for %1 is %2").arg(prefix).arg(num)); + //debug_message("<<>>\n%s\nreturn: %s\n", + // (const char*)query,(const char*)num); + return num; +} + + + +/*! + *\~english + * Gets current document date. + *\~russian + * Возвращает дату текущего документа. + *\~ + *\see setDate( QVariant date ) + *\return \~english document date \~russian дата документа \~ + */ +QVariant +aDocJournal::getDate() +{ + aSQLTable * t = table(); + if ( !t || !selected() ) return QVariant::Invalid; + else return t->sysValue("ddate"); +} + + +/*! + *\~english + * Gets current document prefix + number. + *\~russian + * Возвращает строку префикс + номер текущего документа. + *\~ + *\see setNumber( QVariant number ) + *\return \~english document number \~russian номер документа \~ + */ +QString +aDocJournal::getNumber() +{ + aSQLTable * t = table(); + if ( !t || !selected() ) return ""; + else return t->sysValue("pnum").toString() + t->sysValue("num").toString(); +} + +/*! + *\~english + * Gets current document number. + *\~russian + * Возвращает номер текущего документа. + *\~ + *\see getNumber( QVariant number ) + *\return \~english document number \~russian номер документа \~ + */ +int +aDocJournal::getSerialNumber() +{ + aSQLTable * t = table(); + if ( !t || !selected() ) return 0; + else return t->sysValue("num").toInt(); +} + +/*! + *\~english + * Sets current document date. + *\~russian + * Устанавливает дату текущего документа. + *\~ + *\see getDate() + *\param date - \~english document date \~russian дата документа \~ + *\return \~english error code \~russian код ошибки.\~ + */ +ERR_Code +aDocJournal::setDate( QVariant date ) +{ + aSQLTable * t = table(); + if ( !t ) return err_notable; + if ( !selected() ) return err_notselected; + t->setSysValue( "ddate", date ); + return err_noerror; +} + + + +/*! + *\~english + * Sets current document number. + *\~russian + * Устанавливает номер текущего документа. + *\~ + *\see getNumber() + *\param number - \~english document number \~russian номер документа \~ + *\return \~english error code \~russian код ошибки.\~ + */ +ERR_Code +aDocJournal::setNumber( QVariant number ) +{ + aSQLTable * t = table(); + if ( !t ) return err_notable; + if ( !selected() ) return err_notselected; + QString pr; + int num; + decodeDocNum( number.toString(), pr, num ); + t->setSysValue( "pnum", pr ); + t->setSysValue( "num", num ); + return err_noerror; +// return Update(); + /*QString query; + Q_ULLONG idd = docId(); + QSqlQuery q = db->db()->exec ( QString("SELECT pnum, num FROM a_journ WHERE idd=%1").arg( idd ) ); + if ( q.first() ) return q.value(0).toString()+q.value(1).toString(); + else return "";*/ +} + + + +/*! + *\~english + * Find document by id. + *\~russian + * Ищет документ в системном журнале по его идентификатору. + *\~ + *\see findDoc( const QString & number, int type ) selectDocument( Q_ULLONG idd ) + *\param idd - \~english document number \~russian номер документа \~ + *\return \~english document id or 0 if document not found + * \~russian id документа или 0, если документ не найден.\~ + */ +qulonglong +aDocJournal::findDocument( qulonglong idd ) +{ + aSQLTable * t = table(); + if ( !t ) return 0; + if (t->exec(QString("SELECT * FROM a_journ WHERE idd=%1").arg(idd)) ) + if ( t->first() ) + { + setSelected( true ); + return getUid(); + } + else + { + aLog::print(aLog::Debug, tr("aDocJournal document not found with idd=%1").arg(idd)); + } + return 0; +} + + + +/*! + *\~english + * Find document by number and type. + *\~russian + * Ищет документ по его номеру и типу. + *\~ + *\see findDocument( Q_ULLONG idd ) + *\param number - \~english document number \~russian номер документа, состоящий из префикса и номера \~ + *\param type - \~english document type \~russian тип документа \~ + *\return \~english document id or 0 if document not found + * \~russian id документа или 0, если документ не найден.\~ + */ +qulonglong +aDocJournal::findDoc( const QString & number, int type ) +{ + QString pref; + int num; + decodeDocNum( number, pref, num ); + if ( table()->select(QString("pnum='%1' AND num=%2 AND typed=%3").arg(pref).arg(num).arg(type)) ) + if ( table()->first() ) + { + setSelected(true); + return table()->sysValue("idd").toULongLong(); + } + else + { + aLog::print(aLog::Debug, tr("aDocJournal document not found with number=%1 and type=%2 ").arg(number).arg(type)); + } + return 0; +} + + + +/*! + *\~english + * Gets current document. + *\~russian + * Возвращает текущий документ. Полученный документ необходимо удалить после использования. + * \code + * aDocument *doc = sysJournal->CurrentDocument(); + * //какие-то действия с документом + * delete doc; + * doc=0; + * \endcode + *\~ + *\return \~english current document + * \~russian текущий документ \~ + */ +aDocument* +aDocJournal::CurrentDocument() +{ + aCfgItem i = md->find( docType() ); + if(!i.isNull()) + { + aDocument *d = new aDocument( i, db ); + if(!d->select( docId() )) + { + return d; + } + else + { + delete d; + return 0; + } + } + else + { + return 0; + } +} + + + +/*! + *\~english + * Select documents at some period. + *\~russian + * Выбирает документы определенного типа за некоторый период. + *\~ + *\param from - \~english begin date \~russian дата начала периода \~ + *\param to - \~english end date \~russian дата окончания периода \~ + *\param nmName - \~english document type \~russian тип документа \~ + *\return \~english error code + * \~russian код ошибки \~ + */ +ERR_Code +aDocJournal::Select( QDateTime from, QDateTime to, const QString & mdName ) +{ + aSQLTable * t = table(); + if ( !t ) + return err_notable; + QString fltr, docType = ""; + if ( mdName != "" ) + { + aCfgItem item = md->find( "Document." + mdName ); + if ( item.isNull() ) + return err_objnotfound; + int type = md->id( item ); + docType = QString(" AND typed=%1").arg(type); + } + if ( from.isNull() ) + if ( !to.isNull() ) + fltr = "ddate<='" + to.toString("yyyy-MM-dd hh:mm:ss") + "'"; + else + return err_condition; + else + if ( !to.isNull() ) + fltr = "ddate>='" + from.toString("yyyy-MM-dd hh:mm:ss") + "' AND ddate<='" +\ + to.toString("yyyy-MM-dd hh:mm:ss") + "'"; + else + fltr = "ddate>='" + from.toString("yyyy-MM-dd hh:mm:ss") + "'"; + if ( t->select( fltr + docType ) ) + if ( t->first() ) + { + setSelected(true); + return err_noerror; + } + else return err_notselected; + return err_selecterror; +} + + + +/*! + *\~english + * Select document by number and type. + *\~russian + * Выбирает документ определенного типа и номера. + *\~ + *\param number - \~english document number \~russian составной номер документа \~ + *\param nmName - \~english document type \~russian тип документа \~ + *\return \~english error code + * \~russian код ошибки \~ + */ +ERR_Code +aDocJournal::Select( const QString & number, const QString & mdName ) +{ + aSQLTable * t = table(); + if ( !t ) return err_notable; + QString dFilter = "", pref; + if ( mdName != "" ) + { + aCfgItem tObj = md->find( "Document."+mdName ); + if ( tObj.isNull() ) return err_objnotfound; + else dFilter = QString(" AND typed=%1").arg(md->attr(tObj,mda_id));; + } + int num; + //printf(">>>>>>>>>>>>decode doc num %s\n",number.ascii()); + decodeDocNum( number, pref, num ); + if ( t->select(QString("pnum='%1' AND num=%2").arg(pref).arg(num) + dFilter) ) + if ( t->first() ) + { +// printf(">document selected!\n"); + + aLog::print(aLog::Debug, tr("aDocJournal select document with number=%1 and md name=%2").arg(number).arg(mdName)); + setSelected(true); + return err_noerror; + } + else return err_notselected; + return err_selecterror; + +} + + + +/*! + *\~english + * Gets current document prefix + *\~russian + * Выбирает префикс текущего документа. + *\~ + *\return \~english prexix + * \~russian префикс \~ + */ +QString +aDocJournal::getPrefix() +{ + QString pref = ""; + qulonglong dUid = docId(); + if ( dUid ) + { + QSqlQuery q = db->db()->exec(QString("SELECT pnum FROM a_journ WHERE idd=%1").arg(dUid)); + if ( q.first() ) pref = q.value(0).toString(); + } + return pref; +} + + + +QString +aDocJournal::selectionFilter( QDateTime from, QDateTime to, const QString & mdName, bool full ) +{ + QString fltr="", docType = "", journ=""; + if ( full ) journ="a_journ."; + if ( mdName != "" ) + { + aCfgItem item = md->find( "Document." + mdName ); + if ( item.isNull() ) + return ""; + int type = md->id( item ); + docType = " AND " + journ + QString("typed=%1").arg(type); + } + if ( from.isNull() ) + if ( !to.isNull() ) + fltr = journ + "ddate<='" + to.toString("yyyy-MM-dd hh:mm:ss") + "'"; + else + return ""; + else + if ( !to.isNull() ) + fltr = journ + "ddate>='" + from.toString("yyyy-MM-dd hh:mm:ss") + "' AND " + journ + "ddate<='" + to.toString("yyyy-MM-dd hh:mm:ss") + "'"; + else + fltr = journ + "ddate>='" + from.toString("yyyy-MM-dd hh:mm:ss") + "'"; + return fltr + docType; +} + +QString +aDocJournal::selectionFilter( const QString & num, const QString & mdName, bool full ) +{ + QString pref, fltr="", journ=""; + int nm; + decodeDocNum( num, pref, nm ); + if ( full ) + { + fltr=QString("a_journ.num=%1 AND a_journ.pnum='%2'").arg(nm).arg(pref); + journ = "a_journ."; + } + else fltr=QString(" num=%1 AND pnum='%2'").arg(nm).arg(pref); + if ( mdName != "" ) + { + aCfgItem tObj = md->find( "Document."+mdName ); + if ( tObj.isNull() ) return ""; + else fltr += QString(" AND %1typed=%2").arg(journ).arg(md->id(tObj)); + } + return fltr; +} diff --git a/src/lib/objects/adocjournal.h b/src/lib/objects/adocjournal.h new file mode 100644 index 0000000..8804c70 --- /dev/null +++ b/src/lib/objects/adocjournal.h @@ -0,0 +1,110 @@ +/**************************************************************************** +** $Id: adocjournal.h,v 1.1 2008/11/05 21:16:29 leader Exp $ +** +** Documents journal metadata object header file of +** Ananas application library +** +** Created : 20040701 +** +** Copyright (C) 2003-2004 Leader InfoTech. All rights reserved. +** Copyright (C) Andrey Paskal , Yoshkar-Ola +** +** This file is part of the Designer application of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.leaderit.ru/page=ananas or email sales@leaderit.ru +** See http://www.leaderit.ru/gpl/ for GPL licensing information. +** +** Contact org@leaderit.ru if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#ifndef ADOCJOURNAL_H +#define ADOCJOURNAL_H + +#include +#include "acfg.h" +#include "aobject.h" +#include "adocument.h" + +class aDatabase; + + + +/*! + *\~english + * Not visual object used for working with system journal. + * Used as interface between database and script or wObjects + * Included in aDocument for linked document and system journal + *\~russian + * \brief Определяет программный интерфейс управления общим (системным) журналом документов. + * Наследует aObject. + * + * Невизуальный объект для работы с системным журналом документов базы данных. + * Все хранящиеся в базе данных Ананаса документы система регистрирует в журнале. + * Используется для доступа к системному журналу скриптами и визуальными объектами. + * Включается в объект aDocument, для обеспечения работы документа с ситемным журналом. + *\~ + */ +class ANANAS_EXPORT aDocJournal :public aObject +{ + Q_OBJECT +private: + /*!\ru Тип журнала. \n + * 0 - общий, содержит список документов всех типовб. \n + * 1 - специализированный журнал, содрежит список документов одного типа, + * например "Расходные накладные". + * \_ru + */ + int journalType; +public: + aDocJournal(aCfgItem context, aDatabase * adb = 0); + aDocJournal( const QString & name, aDatabase * adb = 0); + aDocJournal( aDatabase * adb = 0); + virtual ERR_Code initObject(); + ERR_Code selectDocument( qulonglong idd ); + virtual qulonglong docId(); + int docType(); + + /*!\ru \return тип журнала. \n + * 0 - общий, содержит список документов всех типовб. \n + * 1 - специализированный журнал, содержит список документов одного типа, + * например "Расходные накладные". \n + * \_ru + */ + int type() { return journalType; } + QString nextNumber( const QString &prefix, int mdId ); + QVariant getDate(); + QString getNumber(); + // may be need return ULongLong ? + int getSerialNumber(); + ERR_Code setDate( QVariant date ); + ERR_Code setNumber( QVariant number ); + + virtual ERR_Code New ( qulonglong idd, const QString & docPrefix, int type ); + virtual ERR_Code deleteDocument ( qulonglong idd ); + qulonglong findDocument( qulonglong idd ); +// Q_ULLONG docId( Q_ULLONG id ); + qulonglong findDoc( const QString & num, int type ); + QString getPrefix(); + QString selectionFilter( QDateTime from, QDateTime to, const QString & mdName = "", + bool full=false ); + QString selectionFilter( const QString & num, const QString & mdName = "", bool full=false ); + +public slots: + aDocument* CurrentDocument(); + virtual ERR_Code Delete(); + virtual ERR_Code Select( QDateTime from, QDateTime to, const QString & mdName = "" ); + virtual ERR_Code Select( const QString & num, const QString & mdName = "" ); +}; + +#endif// ADOCJOURNAL_H diff --git a/src/lib/objects/adocument.cpp b/src/lib/objects/adocument.cpp new file mode 100644 index 0000000..cca5253 --- /dev/null +++ b/src/lib/objects/adocument.cpp @@ -0,0 +1,1522 @@ +/**************************************************************************** +** $Id: adocument.cpp,v 1.3 2008/11/09 21:09:11 leader Exp $ +** +** Document metadata object implementation file of +** Ananas application library +** +** Created : 20031201 +** +** Copyright (C) 2003-2004 Leader InfoTech. All rights reserved. +** +** This file is part of the Designer application of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.leaderit.ru/page=ananas or email sales@leaderit.ru +** See http://www.leaderit.ru/gpl/ for GPL licensing information. +** +** Contact org@leaderit.ru if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + + +#include "acfg.h" +#include "alog.h" +#include "aobject.h" +#include "adatabase.h" +#include "adocument.h" +#include "adocjournal.h" +#include "airegister.h" +#include "aaregister.h" +//Added by qt3to4: +#include + + + +/*! + *\en + * Create object aDocument by ananas configuration object. + * New object initing by md ojbect + * Use for creating object if you have md object, for example in default document form + *\_en + *\ru + * \brief Создает объект и инициализирует его по метаданным бизнес схемы. + *\_ru + * \param context - \en md object used for initing aDocument. \_en \ru + * элемент метаданных бизнес схемы, инициализирующий объект.\_ru + * \param adb - \en ananas database for working. \_en \ru + * ссылка на базу данных.\_ru +*/ +aDocument::aDocument( aCfgItem context, aDatabase * adb ) +:aObject( context, adb, 0, "aDocument") +{ + if ( context.isNull() ) concrete = false; + else concrete = true; + initObject(); + sysJournal = new aDocJournal(adb); +} + + + +/*! + *\en + * Create object aDocument by document metadata name. + * new object initing by md ojbect with some name + * Use for creating object if you know it's name + *\_en + *\ru + * Создает объект и инициализирует его по метаданным бизнес схемы. + * Документ инициализируется элементом метаданных, найденым по его имени, + * причем поиск осуществляется только среди документов. + *\_ru + * \param name - \en md name of document.\_en \ru + имя документа в метаданных бизнес схемы.\_ru + * \param adb - \en ananas database for working. \_en \ru + * ссылка на базу данных\_ru + */ +aDocument::aDocument(const QString & name, aDatabase * adb) +:aObject( "Document."+name, adb, 0, "aDocument") +{ + if ( name.isEmpty() ) concrete = false; + else concrete = true; + initObject(); + sysJournal = new aDocJournal(adb); +} + + + +/*! + *\en + * Destroy object aDocument. + * Use for delete system journal and free memory. + *\_en + *\ru + * Уничтожает объект. + * Используется для удаления системного журнала и освобождения занятой под него памяти. + *\_ru + */ +aDocument::~aDocument() +{ + delete sysJournal; + sysJournal=0; +} + + + +/*! + * \en + * Translate name of system field. + * Used for translate same system names from different languages ot english, + * result used from working with system fields + * \_en + * \ru + * Используется для перевода предопределенных имен для системных полей. + * Позволяет использовать для обращения к системным полям из скриптов назавания, + * близкие по смыслу к их назначению с учетом языка пользователя. + * Например к полю номер документа можно обратиться используя имя "НомерДок" или "DocNumber". + * \_ru + * \param sname - \en field name on same language. \_en \ru + * одно из предопределенных имен поля.\_ru + * \return \en field name on english \_en \ru имя поля\_ru + */ +QString +aDocument::trSysName( const QString & sname ) +{ + if (( sname == "DocDate" )||( sname == QString::fromUtf8("ДатаДок") )) return "DocDate"; + if (( sname == "DocNumber" )||( sname == QString::fromUtf8("НомерДок") )) return "DocNumber"; + if (( sname == "SerialNumber" )||( sname == "ПНомДок" )) return "SerialNumber"; + if (( sname == "TableLine" )||( sname == QString::fromUtf8("ЛинияТабл") )) return "TableLine"; + return ""; +} + + + +/*! + * \en + * Init object aDocument. + * Used for insert table for document header and tables for all table part of document. + * After that we can work wthith document' tables by it name, name of heared table = "" + * \_en + * \ru + * Инициализирует объект элементом метаданных бизнес схемы. + * В процесе инициализации выполняется настройка на шапку документа + * и все его табличные части. После инициализации появляется возможность + * работать с полями и таблицами, используя их имена, определенные в бизнес схеме. + * \_ru + * \return \en error code. \_en \ru код ошибки.\_ru + */ +ERR_Code +aDocument::initObject() +{ + aCfgItem o, og; + int i, nt; + QString tdbname, tname; + + pref=""; + ERR_Code error = aObject::initObject(); + if ( error ) + return error; + og = md->find( obj, md_header ); + error = tableInsert( aDatabase::tableDbName( *md, og ), og ); + if ( error ) + return error; + og = md->find( obj, md_tables ); + nt = md->count( og, md_table ); + for ( i=0; i< nt; i++ ) { + o = md->find( og, md_table, i ); + tdbname = aDatabase::tableDbName( *md, o ); + tname = md->attr( o, mda_name ); + error = tableInsert( tdbname, o, tname ); + if ( error ) + return error; + } + return err_noerror; +} + + + +/*! + *\en + * Get value for some system field of document. + * Used for read some system field of document: DocDate - Date and time of document, + * DocNumber - Number of document. + *\_en + *\ru + * Читает значение системного поля. + * Используется для получения значения системного поля по его имени + *\_ru + * \param sname - \en name of system field. \_en \ru + * имя ситемного поля. \_ru + * \return \en field value or QVariant::Invalid if used unknown field name.\_en \ru + * значение поля или ошибочное значение, если имя поля неизвестно.\_ru + */ +QVariant +aDocument::sysValue( const QString & sname, const QString & ) +{ + if ( sname == "DocDate" ) + return sysJournal->getDate(); + if ( sname == "DocNumber" ) + return sysJournal->getNumber(); + if ( sname == "SerialNumber" ) + return sysJournal->getSerialNumber(); + return QVariant::Invalid; +} + + + +/*! + * \en + * Set value for some system field of document. + * Used for write some system field of document: DocDate - Date and time of document, + * DocNumber - Number of document. + * \_en + * \ru + * Устанавливает значение системного поля. + * Используется для установки значения системного поля по его имени + * \_ru + * \param sname - \en name of system field\_en \ru + имя ситемного поля.\_ru + * \param value - \en new value of field\_en \ru + устанавливаемое значение\_ru + * \return \en error code. \_en \ru + код ошибки.\_ru + */ +ERR_Code +aDocument::setSysValue( const QString & sname, QVariant value, const QString &) +{ + if ( sname == "DocDate" ) + return sysJournal->setDate( value ); + if ( sname == "DocNumber" ) + return sysJournal->setNumber( value ); + return err_fieldnotfound; +} + + + +/*! + * \en + * Get some field value of current table line. + * Get value for field by metadata name or sustem value ln if use name "TableLine". + * \_en + * \ru + * \brief ScriptAPI. Читает значение поля табличной части документа. + * + * Используется для получения значения поля таблицы по именам таблицы и поля. + * При вызове функции используются имена, указанные в бизнес схеме. + * Кроме этого может использоваться продопределенное имя "TableLine" для + * получения номера текущей записи + * \_ru + * \param tablename - \en metadata name of table\_en \ru + имя таблицы в бизнес схеме\_ru + * \param name - \en name of field\_en \ru + имя поля в бизнес схеме\_ru + * \return \en field value\_en \ru + значение поля\_ru + */ +QVariant +aDocument::TableValue( const QString & tablename, const QString & name ) +{ + if ( trSysName(name) == "TableLine" ) return table(tablename)->sysValue("ln"); + else return tValue( tablename, name ); +} + + + +/*! + * \en + * Set some field value of current table line. + * Set value for field by metadata name + * \_en + * \ru + * \brief ScriptAPI. Записывает значение в поле текущей строки табличной части документа. + * \_ru + * \param tablename - \en metadata name of table,\_en \ru + имя таблицы в бизнес схеме,\_ru + * \param name - \en metadata name of field,\_en \ru + имя поля в бизнес схеме,\_ru + * \param value - \en new field value.\_en \ru + новое значение поля.\_ru + * \return \en error code. \_en \ru + код ошибки.\_ru + */ +ERR_Code +aDocument::TableSetValue( const QString & tablename, const QString & name, const QVariant &value ) +{ + return setTValue( tablename, name, value ); +} + + + +/*! + * \en + * Create new document. + * Create new document header record by selected type in database, + * if object not seted, return error. + * New document also registred in system journal and make current + * \_en + * \ru + * \brief ScriptAPI. Создает и регистрирует в системном журнале объект aDocument. + * + * Создает новую запись в БД с данными из шапки документа. При этом резервируется уникальный Id записи таблицы. + * При этом документ регистрируется в системном журнале и получает следующий по порядку номер. + * \_ru + * \return \en error code. \_en \ru + код ошибки.\_ru + */ +ERR_Code +aDocument::New() +{ + if ( !sysJournal ) + { + aLog::print(aLog::Error, tr("aDocument have no sysjournal")); + return err_nosysjournal; + } + ERR_Code err = aObject::New(); + if ( err ) + { + aLog::print(aLog::Error, tr("aDocument aObject::New() ended with error code = %1").arg(err)); + return err; + } + if ( obj.isNull() ) + { + aLog::print(aLog::Error, tr("aDocument metaobject is null=%1")); + return err_noobject; + } + qulonglong Uid = getUid(); + SetPrefix(md->attr(obj,mda_name)); + aLog::print(aLog::Debug, tr("aDocument new type = %1").arg(md->id(obj))); + err = sysJournal->New( Uid, Prefix(), md->id(obj) ); + if ( err ) + { + aLog::print(aLog::Error, tr("aDocument New() error while added record in sysJournal =%1").arg(err)); + table()->exec(QString("DELETE FROM %1 WHERE id=%2").arg(table()->tableName).arg(Uid)); + db->markDeleted( Uid ); + return err; + } + + aLog::print(aLog::Debug, tr("aDocument new document")); + return err_noerror; +} + + + +/*! + * \en + * Create new table line. + * Create new table line for table of now document + * if document not selected, or no table with some name return error. + * New line begin current in table + * \_en + * \ru + * \brief ScriptAPI. Добавляет новую строку табличной части документа. + * + * Строка добавляется в таблицу текущего документа, если документ не выбран + * или не имеет таблицы с таким именем - возникает ошибка. + * При создании строки ей автоматически присваивается очередной номер. + * \_ru + * \param tablename - \en metadata name of table.\_en \ru + имя таблицы в бизнес схеме.\_ru + * \return \en error code. \_en \ru + код ошибки.\_ru + */ +ERR_Code +aDocument::TableNewLine( const QString & tablename ) +{ + if ( IsConducted() ) return err_docconducted; + aSQLTable *t = table( tablename ); + if ( !t ) return err_notable; + qulonglong tUid = t->primeInsert()->value("id").toULongLong(), dUid = getUid(); + if ( !dUid ) return err_abstractobj; + if ( t->insert() ) + { + t->select( QString("id=%1").arg(tUid), false ); + if (!t->first()) + return err_selecterror; + t->setSysValue("idd",dUid); + QString query; + QVariant ln; + query = QString("SELECT MAX(ln)+1 FROM %1 WHERE idd=%2").arg( t->tableName ).arg(dUid); + QSqlQuery q = db->db()->exec( query ); + if ( q.first() ) + { + ln = q.value( 0 ); + if ( !ln.toInt() ) ln = 1; + } + else + { + aLog::print(aLog::Error, tr("aDocument select new table line number")); + return err_execerror; + } + t->setSysValue("ln",ln); + t->selected = true; + aLog::print(aLog::Info, tr("aDocument new table line number=%1").arg(ln.toString())); + return TableUpdate( tablename ); + } + aLog::print(aLog::Error, tr("aDocument insert new table line")); + return err_inserterror; +} + + + +/*! + * \en + * Delete current document. + * Delete document header, all tables and system journal record, + * If document conducted (turn on) it unconduct (make turn off). + * \_en + * \ru + * \brief ScriptAPI. Удаляет текущий документ. + * + * Документ удаляется полностью вместе с табличными частями, также документ удаляется из системного журнала. + * Идентификатор документа не освободжается и повторно не используется. + * \_ru + * \return \en error code. \_en \ru + код ошибки.\_ru + */ +ERR_Code +aDocument::Delete() +{ + if ( !selected() ) return err_notselected; + if(IsConducted()) UnConduct(); + qulonglong uid = getUid(); + sysJournal->deleteDocument(uid); + + aLog::print(aLog::Debug, tr("aDocument delete from sysjournal")); + db->markDeleted( uid ); + aLog::print(aLog::Debug, tr("aDocument delete from unicues")); + aCfgItem tobj; + uint n = md->count( obj, md_table ); + for ( uint i = 0; i < n; i++ ) + { + tobj = md->find(obj,md_table,i); + if ( tobj.isNull() ) continue; + tableDeleteLines( md->attr(tobj,mda_name) ); + aLog::print(aLog::Debug, tr("aDocument delete table %1").arg(md->attr(tobj,mda_name))); + } + return aObject::Delete(); +} + + + +/*! + * \en + * Delete current table line. + * When deleted table line also deleted all records in all reegisters which contain link on this line + * Don't work if document conducted. + * \_en + * \ru + * \brief ScriptAPI. Удаляет текущую строку табличной части документа. + * + * Также удаляются все записи, связанные с этой строкой во всех регистрах. + * Не работает для проведенных документов. + * \_ru + * \param tablename - \en metadata name of table\_en \ru + имя таблицы в бизнес схеме\_ru + * \return \en error code. \_en \ru + код ошибки.\_ru + */ +ERR_Code +aDocument::TableDelete( const QString & tablename ) +{ + if ( IsConducted() ) + { + aLog::print(aLog::Error, tr("aDocument delete table of conducted document")); + return err_docconducted; + } + aSQLTable * t = table(tablename); + if ( !t ) + { + aLog::print(aLog::Error, tr("aDocument deleted table not exist")); + return err_notable; + } + if ( !t->selected ) + { + //а эта проверка нужна??? + aLog::print(aLog::Error, tr("aDocument deleted table not selected")); + return err_notselected; + } + qulonglong tUid = t->sysValue("id").toULongLong(); + aIRegister * reg = new aIRegister("",db); + reg->deleteTable(tUid); + delete reg; + aLog::print(aLog::Debug, tr("aDocument delete table from info register")); + //reg = new aARegister("",db); + //reg->deleteTable(tUid); + //delete reg; + db->markDeleted( tUid ); + t->primeDelete(); + t->del(); + t->selected = false; + aLog::print(aLog::Info, tr("aDocument delete table")); + return err_noerror; +} + + + + +/*! + * \en + * Delete all table lines. + * Delete all table lines for current document. + * Delete all table lines, don't take document conductions and make any chanded in registers. + * \_en + * \ru + * Удаляет все строки таблицы. + * Удаляет все строки таблицы для текущего документа. + * Функция является внутренней для документа, не проверяет проведен ли документ + * и не вызывает никах изменения в регистрах. + * \_ru + * \param tablename - \en metadata name of table\_en \ru + имя таблицы в бизнес схеме\_ru + * \return \en error code. \_en \ru + код ошибки.\_ru + */ +ERR_Code +aDocument::tableDeleteLines( const QString & tablename ) +{ + qulonglong dUid = getUid(); + if ( !dUid ) + { + aLog::print(aLog::Error, tr("aDocument not selected")); + return err_notselected; + } + QString tdbname = table( tablename )->tableName; + if ( tdbname == "" ) + { + aLog::print(aLog::Error, tr("aDocument table name is empty")); + return err_notable; + } + db->db()->exec(QString("DELETE FROM %1 WHERE idd=%2").arg(tdbname).arg(dUid)); + return err_noerror; +} + + + +/*! + * \en + * Updete current record in database. + * Also update record for document system journal and all table parts. + * Don't work for conducted (Turn on) documents + * \_en + * \ru + * \brief ScriptAPI. Обновляет информацию в базе данных. + * + * Заносит запись из буфера ОЗУ в базу данных. Обновляется информация в шапке документа, + * табличных частях, журнале документов. + * Не работает для проведенных документов. + * \_ru + * \return \en error code. \_en \ru + код ошибки.\_ru + */ +ERR_Code +aDocument::Update() +{ + if ( IsConducted() ) return err_docconducted; + ERR_Code e = aObject::Update(); + if ( e ) + { + aLog::print(aLog::Error, tr("aDocument update error=%1").arg(e)); + return e; + } + e = sysJournal->Update(); + //TODO: may be it fix bug with saving values in first line; + //e += TableUpdate(); + return e; +} + + + +/*! + *\en + * Update table. + * Use for insert information from bufer into database. + * Information is inserting in table with md name=teblename, + * if used TableUpdate() - updating all tables of document. + * If document already conducted return error. + *\_en + *\ru + * \brief SrciptAPI. Обновляет текущую запись табличной части документа. + * + * Копирует информацию из буфера в текущую строку таблицы. + * Если имя не указано или задана пустая строка, обновляются все таблицы документа. + * Не работает для проведенного досумента. + *\_ru + * \param tablename - \en metadata name of table\_en \ru + имя таблицы в бизнес схеме\_ru + * \return \en error code. \_en \ru + код ошибки.\_ru + */ +ERR_Code +aDocument::TableUpdate( const QString & tablename ) +{ + if ( IsConducted() ) + { + aLog::print(aLog::Debug, tr("aDocument conducted table update")); + return err_docconducted; + } + if ( tablename != "" ) return aObject::TableUpdate(tablename); + aCfgItem tobj; + uint n = md->count( obj, md_table ); + ERR_Code err = 0; + for ( uint i = 0; i < n; i++ ) + { + tobj = md->find(obj,md_table,i); + if ( tobj.isNull() ) continue; + err += aObject::TableUpdate( md->attr(tobj,mda_name) ); + } + return err; +} + + + +/*! + * \en + * Check document on mark deleted + * \_en + * \ru + * \brief ScriptAPI. Проверяет помечен ли документ как удаленный. + * \_ru + * \return \en true if document is mark deleted and fasle in othe event\_en \ru + значение флага удаления.\_ru + */ +bool +aDocument::IsMarkDeleted() +{ + return sysJournal->IsMarkDeleted(); +} + + + +/*! + * \en + * Check document on marked + * \_en + * \ru + * \brief ScriptAPI. Проверяет помечен ли документ. + * \_ru + * \return \en true if document is marked and fasle in othe event\_en \ru + значение флага.\_ru + */ +bool +aDocument::IsMarked() +{ + return sysJournal->IsMarked(); +} + + + +/*! + * \en + * Set document deleted flag + * \_en + * \ru + * \brief ScriptAPI. Устанавливает флаг удаления. + * \_ru + * \param Deleted - \en deleted flag\_en \ru + флаг удаления\_ru + * \return \en error code. \_en \ru + код ошибки.\_ru + */ +ERR_Code +aDocument::SetMarkDeleted( bool Deleted ) +{ + return sysJournal->SetMarkDeleted( Deleted ); +} + + + +/*! + * \en + * Set document marked flag + * \_en + * \ru + * \brief ScriptAPI Помечает документ. + * + * В последствии помеченные документы можно рассматривать как группу документов, + * подобранных для обработки. + * \_ru + * \param Marked - \en marked flag\_en \ru + флаг отметки\_ru + * \return \en error code. \_en \ru + код ошибки.\_ru + */ +ERR_Code +aDocument::SetMarked( bool Marked ) +{ + return sysJournal->SetMarked( Marked ); +} + + + +/*! + * \en + * Set document prefix. + * Document prefix used for generate document number. + * \_en + * \ru + * \brief ScriptAPI. Задает префикс документа. + * + * Префикс документа используется для генерации номера документа. + * \_ru + * \see Prefix() Select( const QString & num ) + * \param pr - \en new document prefix.\_en \ru + Новый префикс документа.\_ru + */ +void +aDocument::SetPrefix( const QString & pr ) +{ + pref = pr; +} + + + +/*! + * \en + * Get document prefix. + * \_en + * \ru + * \brief ScriptAPI. Возвращает префикс документа. + * \_ru + * \see SetPrefix( const QString & pr ) Select( const QString & num ) + * \return \en document prefix.\_en \ru + текущий префикс документа.\_ru + */ +QString +aDocument::Prefix() +{ + return pref; +} + + + +/*! + * \en + * Select document by dates. + * If set only one date (othe isNull) select records before or after date. + * If adocument inited by some document type from metadata selected only this documents from jpurnal, + * otherwise - select all documents from system journal with such date + * \_en + * \ru + * \brief ScriptAPI. Выбирает документы по интервалу времени. + * + * Выбирает из системного журнала документы, значение поля "дата" которых + * лежит в указанном диапазоне. Если объект настроен на конкретный тип документа из бизнес схемы, + * выбираются только документы этого типа, в противном случае - все документы журнала, + * соответствующие условию. + * \_ru + * \param from - \en begin date of selection if isNull - selected from first date of system journal,\_en \ru + начальная дата диапазона, если дата isNull, первая дата журнала,\_ru + * \param to - \en end date of selection if isNull - selected to last date of system journal.\_en \ru + конечная дата диапазона, если isNull - до наиболее позднего документа.\_ru + * \return \en error code. \_en \ru + код ошибки.\_ru + */ +ERR_Code +aDocument::Select( QDateTime from, QDateTime to ) +{ + aSQLTable * t = table(); + if ( !t ) return err_notable; + QString query, dname = "", jFltr; + if ( concrete ) dname = md->attr(obj, mda_name); + jFltr = sysJournal->selectionFilter( from, to, dname, true ); + if ( jFltr == "" ) return err_selecterror; + query = QString("SELECT %1.* FROM %2, a_journ WHERE a_journ.idd=%3.id AND %4").arg(t->tableName).arg(t->tableName).arg(t->tableName).arg( jFltr ); + if ( IsFiltred() ) query = query + QString(" AND %1").arg(t->getNFilter()); + if ( t->exec(query) ) + if ( t->first() ) + { + setSelected(true); + sysJournal->findDocument(getUid()); + return err_noerror; + } + else return err_notselected; + else + return err_selecterror; +} + + + +/*! + * \en + * Select document by number. + * Document number string which conteyn document prefix and some number + * If adocument inited by some document type from metadata selected only this documents from jpurnal, + * otherwise - select all documents from system journal with such date + * \_en + * \ru + * \brief ScriptAPI. Выбирает документы по номеру. + * + * Номер задается как строка, которая содержит префикс и число. + * Если объект настроен на конкретный тип документа из бизнес схемы, + * выбираются только документы этого типа, в противном случае - все документы + * с таким номером. + * \_ru + * \see Prefix() SetPrefix() + * \param num - \en document number\_en \ru + \_ru + * \return \en error code. \_en \ru + код ошибки.\_ru + */ +ERR_Code +aDocument::Select( const QString & num ) +{ + aSQLTable * t = table(); + if ( !t ) return err_notable; + QString query, dname = "", jFltr; + if ( concrete ) dname = md->attr(obj, mda_name); + jFltr = sysJournal->selectionFilter( num, dname, true ); + if ( jFltr == "" ) return err_selecterror; + query = QString("SELECT %1.* FROM %2, a_journ WHERE a_journ.idd=%3.id AND %4").arg(t->tableName).arg(t->tableName).arg(t->tableName).arg( jFltr ); + if ( IsFiltred() ) query = query + QString(" AND %1").arg(t->getNFilter()); + if ( t->exec(query) ) + if ( t->first() ) + { + setSelected(true); + sysJournal->findDocument(getUid()); + return err_noerror; + } + else return err_notselected; + else + return err_selecterror; +} + +bool +aDocument::Select() +{ + aSQLTable *t = table(); + if(!t) return false; + t->select(); + if(t->first()) + { + setSelected(true); + return true; + } + else + { + return false; + } +} + + +/*! + * \en + * Select table lines by name and document uid. + * If document uid = 0 selected table in current document. + * \_en + * \ru + * Выбирает строку таблицы по имени и uid документа. + * Если uid документа не указан или равен 0, выбирается строка текущего. + * \_ru + * \param name - \en table metadata name\_en \ru имя таблицы в бизнес схеме\_ru + * \param idd - \en document database id (uid)\_en \ru идентификатор экземпляра документа в базе\_ru + * \return \en error code. \_en \ru код ошибки.\_ru + */ +ERR_Code +aDocument::tableSelect( const QString & name, qulonglong idd ) +{ + qulonglong dUid = idd; + if ( !dUid ) dUid = getUid(); + if ( !dUid ) return err_abstractobj; + aSQLTable * t = table( name ); + if ( !t ) return err_notable; + if ( t->select(QString("idd=%1").arg(dUid))) + if ( t->first() ) + { + setSelected( true, name ); + return err_noerror; + } + else return err_notselected; + else return err_selecterror; +} + + + +/*! + * \en + * Get table by it's metadataname name. + * This function added for get access to document table by it name for othe objects. + * \_en + * \ru + * Возвращает таблицу дакумента по имени. + * Функция позволяет получить ссылку на таблизу документа по ее имени. + * \_ru + * \see aObject::table() + * \param tname - \en metadata table name.\_en \ru + имя таблицы в бизнес схеме.\_ru + * \return \en link on aSQLTable or 0 if table not found.\_en \ru + ссылка на таблицу.\_ru + */ +aSQLTable * +aDocument::getTable( const QString & tname ) +{ + return table(tname); +} + + + +/*! + * \en + * Select table by name. + * Make table with such name current + * \_en + * \ru + * \brief ScriptAPI. Выбирает табличную часть документа по ее имени. + * + * Используется, если документ имеет более одной табличной части. + * \_ru + * \param name - \en table metadata name\_en \ru имя таблицы \_ru + * \return \en error code. \_en \ru + код ошибки.\_ru + */ +ERR_Code +aDocument::TableSelect( const QString & name ) +{ + return tableSelect( name ); +} + + + +/*! + * \en + * Copy current document. + * Create document with header and table pats like current document. + * New document have current date and next unical number. + * \_en + * \ru + * \brief ScriptAPI. Копирует текущий документ + * \_ru + * \return \en error code. \_en \ru + код ошибки.\_ru + */ +ERR_Code +aDocument::Copy() +{ + if ( !sysJournal ) return err_nosysjournal; + QString nowPrefix = sysJournal->getPrefix(); + qulonglong oldUid = getUid(); + ERR_Code err = aObject::Copy(); + if ( err ) return err; + qulonglong Uid = getUid(); + err = sysJournal->New( Uid, nowPrefix, md->id(obj) ); + if ( err ) + { + table()->exec(QString("DELETE FROM %1 WHERE id=%2").arg(table()->tableName).arg(Uid)); + db->markDeleted( Uid ); + return err; + } + aDocument doc( obj, db ); + err = doc.select(oldUid); + if ( err ) return err; + aCfgItem tObj, fObj; + QString tname, query, tdbname, fname ; + uint n = md->count(obj,md_table), m; + for ( uint i = 0; i < n; i++ ) + { + tObj = md->find( doc.obj, md_table, i ); + if ( tObj.isNull() ) continue; + tname = md->attr( tObj, mda_name ); + if ( !doc.TableSelect(tname) ) + { + TableNewLine(tname); + m = md->count( tObj, md_field ); + for ( uint j = 0; j < m; j++ ) + { + fObj = md->find( tObj, md_field, j ); + if ( fObj.isNull() ) continue; + fname = md->attr( fObj, mda_name ); + TableSetValue( tname, fname, doc.TableValue( tname, fname ) ); + } + TableUpdate( tname ); + while ( doc.TableNext( tname ) ) + { + TableNewLine(tname); + m = md->count( tObj, md_field ); + for ( uint j = 0; j < m; j++ ) + { + fObj = md->find( tObj, md_field, j ); + if ( fObj.isNull() ) continue; + fname = md->attr( fObj, mda_name ); + TableSetValue( tname, fname, doc.TableValue( tname, fname ) ); + } + TableUpdate( tname ); + } + } + } + return err_noerror; +} + + + +/*! + * \en + * Make current next selected header. + * Use for navigation by selected documents. + * \_en + * \ru + * \brief ScriptAPI. Переход к следующему документу. + * \_ru + * \return \en operation result.\_en \ru + результат операции (успешно или нет)\_ru + */ +bool +aDocument::Next() +{ + if ( aObject::Next() ) if ( sysJournal->findDocument( getUid() ) ) return true; + return false; +} + + + +/*! + * \en + * Make current prev selected header. + * Use for navigation by selected documents. + * \_en + * \ru + * \brief ScriptAPI. Переход к предыдущему документу + * \_ru + * \return \en operation result.\_en \ru + результат операции (успешно или нет)\_ru + */ +bool +aDocument::Prev() +{ + if ( aObject::Prev() ) if ( sysJournal->findDocument( getUid() ) ) return true; + return false; +} + + + +/*! + * \en + * Make current first selected header. + * Use for navigation by selected documents. + * \_en + * \ru + * \brief ScriptAPI. Переходит к первому документу + * \_ru + * \return \en operation result.\_en \ru + результат операции (успешно или нет)\_ru + */ +bool +aDocument::First() +{ + + printf("aDoc::first uid = %llu\n", getUid()); + if ( aObject::First() ) if ( sysJournal->findDocument( getUid() ) ) return true; + return false; +} + + + +/*! + * \en + * Make current last selected header. + * Use for navigation by selected documents. + * \_en + * \ru + * \brief ScriptAPI. Переходит к последнему документу + * \_ru + * \return \en operation result.\_en \ru + результат операции (успешно или нет)\_ru + */ +bool +aDocument::Last() +{ + if ( aObject::Last() ) if ( sysJournal->findDocument( getUid() ) ) return true; + return false; +} + + + +/*! + * \en + * Make current next selected line in table. + * Use for navigation in table. + * \_en + * \ru + * \brief ScriptAPI. Переход к следуещей записи в табличной части документа + * \_ru + * \param name - \en metadata table name.\_en \ru + имя таблицы из бизнес схемы.\_ru + * \return \en operation result.\_en \ru + результат операции (успешно или нет)\_ru + */ +bool +aDocument::TableNext( const QString & name ) +{ + aSQLTable * t = table(name); + if ( !t ) return false; + if ( t->next() ) return true; + else return false; +} + + + +/*! + * \en + * Make current prev selected line in table. + * Use for navigation in table + * \_en + * \ru + * \brief ScriptAPI. Переход к предыдущей записи в табличной части документа + * \_ru + * \param name - \en metadata table name.\_en \ru + имя таблицы из бизнес схемы.\_ru + * \return \en operation result.\_en \ru + результат операции (успешно или нет)\_ru + */ +bool +aDocument::TablePrev( const QString & name) +{ + aSQLTable * t = table(name); + if ( !t ) return false; + if ( t->prev() ) return true; + else return false; +} + + + +/*! + * \en + * Make current first selected line in table. + * Use for navigation in table + * \_en + * \ru + * \brief ScriptAPI. Переход к первой записи в табличной части документа + * \_ru + * \param name - \en metadata table name.\_en \ru + имя таблицы из бизнес схемы.\_ru + * \return \en operation result.\_en \ru + результат операции (успешно или нет)\_ru + */ +bool +aDocument::TableFirst( const QString & name) +{ + aSQLTable * t = table(name); + if ( !t ) return false; + if ( t->first() ) return true; + else return false; +} + + + +/*! + * \en + * Make current last selected line in table. + * Use for navigation in table + * \_en + * \ru + * \brief ScriptAPI. Переход к последней записи в табличной части документа + * \_ru + * \param name - \en metadata table name.\_en \ru + имя таблицы из бизнес схемы.\_ru + * \return \en operation result.\_en \ru + результат операции (успешно или нет)\_ru + */ +bool +aDocument::TableLast( const QString & name ) +{ + aSQLTable * t = table(name); + if ( !t ) return false; + if ( t->last() ) return true; + else return false; +} + + + + +/*! + * \en + * Set filter for some field. + * If filter seted, on select selected only records where that field equal value. + * If seted filters for diferent fields it's group by and. + * If filter reseted it override previous value + * \_en + * \ru + * \brief ScripAPI. Устанавливает фильтр на доступные документы. + * + * Доступными становяться только документы, удовлетворяющие условию. + * Например, для получения всех накладных с номером 0003 нужно сделать примерно следующее: + * \code + * aDocument * doc = new aDocument("Накладная", db); + * doc->SetFilter("Номер","0003"); + * doc->First(); + * do{ + * //какие-то действия + * }while(doc->Next()); + * delete doc; + * \endcode + * \_ru + * \see ClearFilter() + * \param valname - \en metadata name of field.\_en \ru имя поля в метаданных \_ru + * \param value - \en filter value.\_en \ru Значение фильтра \_ru + * \return \en error code. \_en \ru код ошибки.\_ru + */ +ERR_Code +aDocument::SetFilter( const QString & valname, const QVariant & value ) +{ + return aObject::SetFilter( valname, value ); +} + + + +/*! + * \en + * Clear all filters values. + * \_en + * \ru + * \brief ScriptAPI. Сбрасывает фильтр. + * \_ru + * \see SetFilter( const QString & valname, const QVariant & value ) + * \return \en error code. \_en \ru код ошибки.\_ru + */ +ERR_Code +aDocument::ClearFilter() +{ + return aObject::ClearFilter(); +} + +/* +ERR_Code +aDicument::TableSetFilter( const QString & tname, const QString & valname, const QVariant & value ) +{ +} + +ERR_Code +aDicument::TableClearFilter( const QString & tname ) +{ +} +*/ + + + +/*! + * \en + * Set conduct flag for current document. + * \_en + * \ru + * Устанавливает флаг проведения для текущего документа. Не используйте эту функцию напрямую. Используйте Conduct() и UnConduct() + * \_ru + * \param cond - \en conducted flag, flag set on 1 if cond true adn 0 if cond false\_en \ru значение флага \_ru + * \see Conduct() Unconduct() IsConducted() + * \return \en error code. \_en \ru код ошибки.\_ru + */ +ERR_Code +aDocument::setConduct( bool cond ) +{ + qulonglong idd = getUid(); + + if (!idd) return err_nodocument; + QSqlDatabase *tdb = db->db(); + QString query; + query = QString("UPDATE a_journ SET cf='%1' WHERE idd=%2").arg( ( int ) cond).arg( idd ); + tdb->exec(query); + if ( !tdb->lastError().type() ) + { + aLog::print(aLog::Debug, tr("aDocument conduct")); + return err_noerror; + } + else + { + aLog::print(aLog::Error, tr("aDocument conduct")); + return err_conducterror; + } +} + +/** + * \brief Deprecated + */ +ERR_Code +aDocument::Conduct(){ + aLog::print(aLog::Debug, tr("Deprecated method call. aDocument::Conduct(...)")); + return this->SignIn(); +} + +/*! + * \en + * Make document conducted. + * Work only for unconducted documents otherwise return error err_docconducted + * \_en + * \ru + * \brief ScriptAPI. Вызывает проведение документа. + * \_ru + * \see SignOut() IsSignedIn() + * \return \en error code. \_en \ru код ошибки.\_ru + */ +ERR_Code +aDocument::SignIn() +{ + if ( IsConducted() ) return err_docconducted; + else return setConduct(true); + +} + + +/** + * \brief Deprecated + */ +ERR_Code +aDocument::UnConduct(){ + aLog::print(aLog::Debug, tr("Deprecated method call. aDocument::UnConduct()")); + return this->SignOut(); +} + +/*! + * \en + * Make document unconducted. + * Work only for conducted documents otherwise return error err_docunconducted + * \_en + * \ru + * \brief ScriptAPI. Отменяет проведение документа. + * \_ru + * \see SignIn() IsSignedIn() + * \return \en error code. \_en \ru код ошибки.\_ru + */ +ERR_Code +aDocument::SignOut() +{ + if ( !IsConducted() ) return err_docunconducted; + ERR_Code err = setConduct(false); + if ( err ) return err; + //Q_ULLONG uid = getUid(); + aIRegister * reg = new aIRegister("",db); + reg->deleteDocument(this); + delete reg; + aCfgItem aReg, aRegs; + aRegs= md->find(md->find(md->find(mdc_metadata),md_registers,0),md_aregisters,0); + if ( aRegs.isNull() ) return 1; //TODO: set error code + uint n = md->count( aRegs, md_aregister ); + aARegister *areg; + for ( uint i = 0; i < n; i++ ) + { + aReg = md->find( aRegs, md_aregister, i ); + if ( aReg.isNull() ) continue; + areg = new aARegister(aReg,db); + areg->deleteDocument(this); + aLog::print(aLog::Debug, tr("aDocument delete from accumulation register")); + delete areg; + areg = 0; + } + return err_noerror; +} + + +/** + * \brief Deprecated + */ +bool +aDocument::IsConducted(){ + aLog::print(aLog::Debug, tr("Deprecated method call. aDocument::IsConducted()")); + return this->IsSignedIn(); +} + +/*! + * \en + * Check document conducting. + * \_en + * \ru + * \brief ScriptAPI. Проверяет, проведен ли документ. + * \_ru + * \see SignIn() SignOut() + * \return \en true, if document is conducted. \_en \ru true, если документ проведен \_ru + */ +bool +aDocument::IsSignedIn() +{ + qulonglong idd = getUid(); + if (!idd) return false; + QSqlQuery q = db->db()->exec(QString("SELECT cf FROM a_journ WHERE idd=%1").arg(idd)); + if ( q.first() ) return q.value(0).toBool(); + else return false; +} + + + +/*! + * \en + * Select document with id = \a uid. + * \_en + * \ru + * Выбирает документ с заданным идентификатором. + * \_ru + */ +ERR_Code +aDocument::select( qulonglong uid) +{ + ERR_Code res= err_noerror; + qulonglong idd = 0; + if ( !sysJournal ) return err_nosysjournal; + res = aObject::select(uid); + if(res != err_noerror) return res; + idd = sysJournal->findDocument(uid); + if (idd == 0) return err_nodocument; + aCfgItem tobj; + uint n = md->count( obj, md_table ); + for ( uint i = 0; i < n; i++ ) + { + tobj = md->find(obj,md_table,i); + if ( tobj.isNull() ) continue; + tableSelect(md->attr(tobj,mda_name), uid); +// aObject::select( QString("idd=%1").arg(uid), md->attr(tobj,mda_name) ); + } + return res; +} + +/** + * \ru + * \brief ScriptAPI. Выбирает документ с заданным идентификатором. + * \_ru + */ +int +aDocument::SelectDocument( QVariant uid ) +{ + return select(uid.toULongLong()); +} + +/*! + * \en + * Sets position in document table tname at \a pos. + * \_en + * \ru + * \brief ScriptAPI. Устанавливает позицию в табличной части документа на строку с заданным номером. + * \_ru + * \param pos - \en line number \_en \ru номер строки \_ru + * \param tname - \en table name \_en \ru имя таблицы \_ru + */ +void +aDocument::Seek(int pos, const QString &tname) +{ + aSQLTable * t = table(tname); + if(t && t->first()) + { + setSelected( true, tname ); + for(int i=0; inext()) continue; + else break; + } + } +} + +/** + * \en + * Get value of document field. + * \_en + * \ru + * \brief ScriptAPI. Получение значения атрибута документа c указанным идентификатором. + * + * С помощью этого метода можно получить значение атрибута документа, не являющегося текущим. + * Вызов метода приводит к смене текущего документа. + * Для получения значения атрибута текущего документа используйте метод Value(...), + * унаследованный от aObject. + * \_ru + * + * \param docId - \en document id \_en \ru id документа \_ru + * \param fname - \en md field name \_en \ru имя поля в метаданных \_ru + * + * \return \en value of field \_en \ru значение поля или строку "Unknown", в случае ошибки \_ru + * + */ +QVariant +aDocument::GetDocumentValue(QVariant docId, const QString &fname) +{ + //aSQLTable * t = table(); + //if ( !t ) return ""; + //t->select(docId.toULongLong()); + //if ( !t->first() ) return ""; + //else + //{ + if(!select(docId.toULongLong())) + { + QVariant val = Value( fname ); + if(val.type()==QVariant::ULongLong || + val.type()==QVariant::LongLong) + { + return val.toString(); + } + else + { + return val; + } + } + else + { + aLog::print(aLog::Error, tr("aDocument::GetDocumentValue(...): Can't find aDocument")); + return "Unknown"; + } + //} + +} +/*! + * \en + * Return field value with name = \a name of the primary object database table. + * \_en + * \ru + * Возвращает значения поля с именем = \a name основг\ной таблицы объекта. + * \_ru + * \param name - \en field name \_en \ru имя поля \_ru + * \return \en field value \_en \ru значение поля. Поля типа Q_ULLONG и DateTime переводятся в строки. \_ru + */ +QVariant +aDocument::Value( const QString & name, const QString &tableName ) +{ + QVariant res = aObject::Value(name, tableName); + if(res.type() == QVariant::ULongLong || res.type() == QVariant::LongLong) + { + return QVariant(res.toString()); + } + //if(res.type() == QVariant::DateTime) + //{ + // return QVariant(res.toDate().toString(Qt::ISODate)); + //} + return res; +} diff --git a/src/lib/objects/adocument.h b/src/lib/objects/adocument.h new file mode 100644 index 0000000..50bf259 --- /dev/null +++ b/src/lib/objects/adocument.h @@ -0,0 +1,140 @@ +/**************************************************************************** +** $Id: adocument.h,v 1.1 2008/11/05 21:16:29 leader Exp $ +** +** Document metadata object header file of +** Ananas application library +** +** Created : 20031201 +** +** Copyright (C) 2003-2004 Leader InfoTech. All rights reserved. +** +** This file is part of the Designer application of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.leaderit.ru/page=ananas or email sales@leaderit.ru +** See http://www.leaderit.ru/gpl/ for GPL licensing information. +** +** Contact org@leaderit.ru if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#ifndef ADOCUMENT_H +#define ADOCUMENT_H + +#include +#include "acfg.h" +#include "aobject.h" +//#include "adocjournal.h" + +class aDocJournal; + +class aDatabase; + + + +/*! + * \en + * Not visual object used for working with documents in database. + * Used as interface between database and script or wObjects + * \_en + * \ru + * \brief Определяет программный интерфейс для работы с бизнес объектами типа Документ и их атрибутами. + * Наследует aObject. + * + * Объект класса предоставляет навигационный доступ ко всем документам, имеющим тип, указанный при инициализации + * объекта. С помощью методов класса можно управлять как документом целиком, так и отдельными его реквизитами. + * В том числе табличными частями, если они определены в метаданных у документа. + * Обеспечивает единообразный доступ к полям и таблицам документов, + * хранимых в базе данных. Информация о составе и структуре полей и табличных частей документа + * храниться в метаданных. + * Позволяет создавать, удалять, изменять, копировать, проводить и распроводить документы. + * \_ru + */ +class ANANAS_EXPORT aDocument :public aObject +{ + Q_OBJECT + ERR_Code tableDeleteLines( const QString & tablename ); + ERR_Code tableSelect( const QString & tablename, qulonglong = 0 ); +public: + + aDocument( aCfgItem context, aDatabase * adb = 0 ); + aDocument( const QString & name, aDatabase * adb = 0 ); + virtual ~aDocument(); + + virtual ERR_Code select ( qulonglong uid ); + virtual ERR_Code initObject(); + virtual QString trSysName( const QString & sname ); + virtual QVariant sysValue( const QString & sname, const QString & = ""); // second parameter is here to make method declaration identical to aObject::sysValue + virtual ERR_Code setSysValue( const QString & sname, QVariant value, const QString & = ""); // third parameter makes method declaration identical to aObject::setSysValue + + aSQLTable * getTable( const QString & tablename ); +public slots: + + virtual ERR_Code New(); + virtual ERR_Code Delete(); + virtual ERR_Code Update(); + virtual ERR_Code Select( QDateTime from, QDateTime to ); + virtual bool Select(); + virtual ERR_Code Select( const QString & num ); + virtual int SelectDocument( QVariant uid ); + virtual ERR_Code Copy(); + + virtual bool Next(); + virtual bool Prev(); + virtual bool First(); + virtual bool Last(); + + virtual ERR_Code TableNewLine( const QString & tablename ); + virtual ERR_Code TableDelete(const QString & tablename); + virtual ERR_Code TableSelect( const QString & name ); + + virtual QVariant TableValue( const QString & tablename, const QString & name ); + virtual ERR_Code TableSetValue( const QString & tablename, const QString & name, + const QVariant &value ); + virtual ERR_Code TableUpdate( const QString & tablename = "" ); + + virtual bool TableNext( const QString & name); + virtual bool TablePrev( const QString & name); + virtual bool TableFirst( const QString & name); + virtual bool TableLast( const QString & name); + + virtual bool IsMarkDeleted(); + virtual bool IsMarked(); + virtual ERR_Code SetMarkDeleted( bool Deleted ); + virtual ERR_Code SetMarked( bool Marked ); + + void SetPrefix( const QString & pr ); + QString Prefix(); + + virtual QVariant Value( const QString & name, const QString &tableName = "" ); + + virtual ERR_Code SetFilter( const QString & valname, const QVariant & value ); + virtual ERR_Code ClearFilter(); + + ERR_Code Conduct(); //depricated + ERR_Code UnConduct(); //depricated + bool IsConducted(); // depricated + ERR_Code SignIn(); + ERR_Code SignOut(); + bool IsSignedIn(); +// virtual ERR_Code TableSetFilter( const QString & tname, const QString & valname, const QVariant & value ); +// virtual ERR_Code TableClearFilter( const QString & tname ); + void Seek(int pos, const QString &tname); + QVariant GetDocumentValue(QVariant ide, const QString &fname); + +private: + QString pref; + aDocJournal* sysJournal; + ERR_Code setConduct( bool cond ); +}; + +#endif// ADOCUMENT_H diff --git a/src/lib/objects/airegister.cpp b/src/lib/objects/airegister.cpp new file mode 100644 index 0000000..ead4d50 --- /dev/null +++ b/src/lib/objects/airegister.cpp @@ -0,0 +1,554 @@ +/**************************************************************************** +** $Id: airegister.cpp,v 1.3 2008/11/09 21:09:11 leader Exp $ +** +** Code file of the Information Register of Ananas +** Engine applications +** +** Created : 20031201 +** +** Copyright (C) 2003-2004 Leader InfoTech. All rights reserved. +** +** This file is part of the Library of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.leaderit.ru/page=ananas or email sales@leaderit.ru +** See http://www.leaderit.ru/gpl/ for GPL licensing information. +** +** Contact org@leaderit.ru if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#include "airegister.h" +#include "adatabase.h" +#include "adocjournal.h" +#include "adocument.h" +#include "alog.h" + + +/*! + *\en + * \brief Create object aIRegister by ananas configuration object. + * + * New object initing by md ojbect + * \param context - md object used for initing aDocument + * \param adb - ananas database for working + *\_en + *\ru + * \brief Создает новый экземпляр объекта информационного регистра по описанию в бизнес схеме. + * + * \param context - Ссылка на объект бизнес схемы, описывающий регистр. + * \param adb - Можно не передавать. Значение по умолчанию = 0. Текущая база данных Ананаса. + * + *\_ru + */ +aIRegister::aIRegister( aCfgItem context, aDatabase * adb ) +: aObject( context, adb ) +{ + concrete = !context.isNull(); + initObject(); +} + + + +/*! + *\en + * \brief Create object aIRegister by information register metadata name. + * + * New object initing by md ojbect with some name. + * Use for creating object if you know it's name. + * \param name - md name of document + * \param adb - ananas database for working + * \param type - ananas database for working + *\_en + *\ru + * \brief Создает новый экземпляр объекта информационного регистра по имени. + * + * Новый объект создается по описанию объекта с таким именем, хранимом в бизнес схеме. + * \param name - Имя Регистра в бизнес схеме + * \param adb - Можно не передавать. Значение по умолчанию = 0. Ссылка на текущую базу данных Ананаса + * \param type - Можно не передавать. Значение по умолчанию = "InfoRegister". Тип (класс) реристра в бизнес схеме + * + *\_ru + */ +aIRegister::aIRegister( const QString & name, aDatabase * adb, const QString & type ) +:aObject( type+name, adb ) +{ + if ( name.isEmpty() ) concrete = false; + else concrete = true; + initObject(); +} + +/*! + * \ru + * Деструктор. + * \_ru + */ + +aIRegister::~aIRegister() +{ +} + + +/*! + *\en + * \brief Initing this object by information registr from metadata object + * + * \return Error code + *\_en + *\ru + * \brief Инициализирует объект информационного регистра. + * + * \return Код ошибки + *\_ru + */ +ERR_Code +aIRegister::initObject() +{ + docseted = false; + tableseted = false; + ERR_Code err = aObject::initObject(); + if ( err ) + return err; + return tableInsert( db->tableDbName(*md,obj), obj ); +} + + +/*! + *\ru + * \brief Устанавливает фильтр на записи регистра. + * + * После установки фильтра навигация происходит по записям значение данного поля которых равно указанному значению. + * \param name - Имя столбца в метаданных, на который устанавливается фильтр + * \param value - Значение для фильтрации + * \return Код ошибки + *\_ru + *\en + * \brief Sets filter. + * + * \param name - Field name. + * \param value - Field value. + * \return Error code + *\_en + */ +int +aIRegister::SetFilter( const QString & name, const QVariant & value ) +{ + if ( (md->findName( md->find(obj,md_dimensions,0), md_field, name )).isNull() ) + return err_incorrecttype; + return aObject::SetFilter( name, value ); +} + + + +/*! + *\ru + * \brief Отфильтровывает записи регистра, принадлежащие документу. Подготовливает регистр для добавления записи + * функцией New. + * + * + * Задав документ для регистра, получаем возможность работать только с записями регистра, указывающими на этот документом. + * + * \param - Ссылка на существующий документ + * \return Код ошибки + * \see New() + * + *\_ru + *\en + * \brief Sets document. + * + * \param doc - Reference to documetn. + * \return Error code + * \see New() + *\_en + */ +int +aIRegister::SetDocument( aDocument * doc ) +{ + nowDoc = doc; + if ( !doc ) return err_nodocument; + docseted = true; + SetFilter( "idd", doc->getUid() ); + return err_noerror; +} + +/*! + *\ru + * \brief Возвращает документ, на основании которого была сделана текущая запись регистра. + * + * Возвращяет хранящийся в текущей записи регистра указатель на документ (не идентификатор, а объект), + * позволяющий обратиться к реквизитам документа. + * \return Указатель на документ, если текущая запись регистра имеет ссылку на документ и этот докуменрт существует. + * Возврат ошибки будет свидетельствовать, что с данными не все в порядке, т.е. нарушена ссылочная целостность. + *\_ru + *\en + * \brief Gets document. + * + * \return Document pointer + *\_en + */ +aDocument* +aIRegister::GetDocument() +{ + //TODO: проверить, не происходит ли утечек памяти + qulonglong doc_id = table()->sysValue("idd").toULongLong(); + aCfgItem o = md->find(db->uidType(doc_id)); + if(!o.isNull()) + { + aDocument * d = new aDocument(o, db); + if(d) + { + d->select(doc_id); + } + return d; + } + return 0; +} + + +/*! + *\en + * \brief Sets table. + * + * \param tblname - Table name. + * \return Error code + *\_en + *\ru + * \brief Задает табличную часть документа для использования при добавдении новых записей регистра методом New. + * + * Вновь добавляемые записи регистра будут содержать ссылку на текущую запись указанной табличной части документа. + * Используется только когда нужно добавить строки из таблицы документа. + * До вызова этой функции должна быть вызвана функция установки документа SetDocument( aDocument * doc ). + * \param tblname - Имя таблицы документа. + * \return Код ошибки + * \see SetDocument( aDocument * doc ) + *\_ru + */ +int +aIRegister::SetTable( const QString & tblname ) +{ + if ( tblname == "" ) + { + tname = ""; + tableseted = false; + return err_notable; + } + if ( !docseted ) return err_nodocument; + tableseted = true; + tname = tblname; + return err_noerror; +} + + + +/*! + *\en + * \brief Adds new line to infomation register table. + * + * \return Error code + * \see SetDocument( aDocument * doc ) + * \see SetTable( const QString & tblname ) + *\_en + *\ru + * \brief Добавляет новую строку к таблице информационного регистра. + * + * Для каждой строки информационного регистра обязательным является указание того, какая строка + * табличной части какого документа с ней связана. То есть каждая запись в регистре обязательно связана + * ровно с одной строкой табличной части какого-либо документа. И если при редактировании документа + * пользователем удаляется строка в его табличной части, то происходит автоматическое удаление соответствующих + * строк регистра. + * Перед вызовом необходимо указать ссылку на документ и на одну из его (возможно нескольких) табличных частей. + * Важно чтобы в табличной части документа была задана требуемая текущая запись (строка). Именно с ней будет связана + * создаваемая запись регистра. + * Для указания документа и табличной части перед выховом этой функции нужно вызвать функции SetDocument() и SetTable() + * Иначе запись не будет создана и вернется ошибка. + * \return Код ошибки + * \see SetDocument( aDocument * doc ) + * \see SetTable( const QString & tblname ) + *\_ru + */ +int +aIRegister::New() +{ + if ( !docseted ) return err_nodocument; + aSQLTable * t = table(); + if ( !t ) return err_notable; + qulonglong idd = nowDoc->getUid(); + if ( !idd ) return err_notselected; + int err = aObject::New(); + if ( err ) return err; + t->setSysValue( "idd", idd ); + //t->setSysValue( "date", nowDoc->Value("DocDate") ); + if ( tableseted ) + { + aSQLTable * tt = nowDoc->getTable ( tname ); + t->setSysValue("iddt",tt->sysValue("id")); + t->setSysValue("ln",tt->sysValue("ln")); + } + err = Update(); + if ( err ) return err; + else return select(getUid()); +} + + +/*! + *\en + * \brief Delete all record with document id from all information registers. + * + * \param doc - document to delete. + * \return true - ok, false - error + *\_en + *\ru + * \brief Удаляет все записи с идентификатором данного документа из всех информационных регистров. + * + * \param doc - Документ, записи о котором будут удалены. + * \return true - успех, false - ошибка + *\_ru + */ +bool +aIRegister::deleteDocument( aDocument * doc ) +{ + QString tdbname; + aCfgItem iReg, iRegs = md->find(md->find(md->find(mdc_metadata),md_registers,0),md_iregisters,0); + if ( iRegs.isNull() ) + { + aLog::print(aLog::Error, tr("aIRegister metaobject is null")); + return false; + } + qulonglong idd = doc->getUid(); + if ( !idd ) + { + aLog::print(aLog::Error, tr("aIRegister deleted document have invalid idd")); + return false; + } + uint n = md->count( iRegs, md_iregister ); + for ( uint i = 0; i < n; i++ ) + { + iReg = md->find( iRegs, md_iregister, i ); + if ( iReg.isNull() ) continue; + if ( md->attr( iReg, mda_no_unconduct)=="1") continue; + tdbname = db->tableDbName( db->cfg, iReg ); + db->db()->exec(QString("DELETE FROM %1 WHERE idd=%2").arg(tdbname).arg(idd)); + } + return true; +} + + + +/*! + *\en + * \brief Removes records with given table id + * + * \param iddt - table id. + * \return true - ok, false - error + *\_en + *\ru + * \brief Удаляет все записи из всех информационных регистрах о таблице с данным идентификатором + * + * \param iddt - id таблицы. + * \return true - успех, false - ошибка + *\_ru + */ +bool +aIRegister::deleteTable( qulonglong iddt) +{ + QString tdbname; + aCfgItem iReg, iRegs = md->find(md->find(md->find(mdc_metadata),md_registers,0),md_iregisters,0); + if ( iRegs.isNull() ) + { + aLog::print(aLog::Error, tr("aIRegister metaobject is null")); + return false; + } + uint n = md->count( iRegs, md_iregister ); + for ( uint i = 0; i < n; i++ ) + { + iReg = md->find( iRegs, md_iregister, i ); + if ( iReg.isNull() ) continue; + if ( md->attr( iReg, mda_no_unconduct)=="1") continue; + tdbname = db->tableDbName( db->cfg, iReg ); + db->db()->exec(QString("DELETE FROM %1 WHERE iddt=%2").arg(tdbname).arg(iddt)); + } + return true; +} + + + +/*! + *\en + * \brief Selects records for date interval. + * + * \return Error code + * \see Select( QDateTime from, QDateTime to ) + *\_en + *\ru + * \brief Выбирает записи в информационном регистре за заданный период. + * + * Вспомогательный метод для скриптов. + * \param from - дата начала периода в строке в фрмате ISO 8601 (ГГГГ-ММ-ДД) + * \param to - дата окончания периода в строке в формате ISO 8601 (ГГГГ-ММ-ДД) + * \return Код ошибки + * \see Select( QDateTime from, QDateTime to ) + *\_ru + */ +int +aIRegister::Select( const QString &from, const QString &to) +{ + //printf("from %s, to %s\n",from.ascii(),to.ascii() ); + aLog::print(aLog::Debug, tr("aIRegister select period from %1 to %2").arg(from).arg(to)); + return Select(QDateTime::fromString(from+"T00:00:00",Qt::ISODate), QDateTime::fromString(to+"t00:00:00",Qt::ISODate)); +} + + +/*! + *\en + * \brief Selects records for period + * + * \param from - Period begin date + * \param to - Period end date + * \return Error code + *\_en + *\ru + * \brief Выбирает записи в информационном регистре за заданный период. + * + * \param from - Дата начала периода + * \param to - Дата окончания периода + * \return Код ошибки + *\_ru + */ +int +aIRegister::Select( QDateTime from, QDateTime to ) +{ + aDocJournal journ(db); + aSQLTable * t = table(); + if ( !t ) return err_notable; + QString query, flt; + flt = journ.selectionFilter( from, to, "", true ); + if ( flt == "" ) return err_selecterror; + query = QString("SELECT %1.* FROM a_journ, %2 WHERE %3.idd=a_journ.idd AND %4").arg(t->tableName).arg(t->tableName).arg(t->tableName).arg(flt); + if ( IsFiltred() ) + { + QString tf = t->getNFilter(); + if ( tf != "" ) + query = query + QString(" AND %1").arg(tf); + } + if ( t->exec(query) ) + if ( t->first() ) + { + setSelected(true); + return err_noerror; + } + else return err_notselected; + else + return err_selecterror; +} + + +/*! + *\en + * + * \return Error code + *\_en + *\ru + * \brief Выбирает первую запись регистра по документу, установленному перед этим функцией SetDocument( aDocument * doc ). + * + * \return Код ошибки + * \see SetDocument( aDocument * doc ) + *\_ru + */ +int +aIRegister::SelectByDoc() +{ + if ( !docseted ) return err_nodocument; + qulonglong uidd = nowDoc->getUid(); + if ( !uidd ) return err_nodocument; + aSQLTable * t = table(); + if ( !t ) return err_notable; + if ( t->select(QString("idd=%1").arg(uidd)) ) + if (t->first()) return err_noerror; + else return err_notselected; + else return err_selecterror; +} + +/*! + *\en + * \brief Return field value with name = name of the primary object database table. + * + * \param name - field name + * \return field value + *\_en + *\ru + * \brief Возвращает значения поля с именем = name основной таблицы объекта. + * + * \param name - имя поля + * \return значение поля. Поля типа Q_ULLONG и DateTime переводятся в строки. + *\_ru + */ +QVariant +aIRegister::Value( const QString & name, const QString &tableName ) +{ + QVariant res = aObject::Value(name, tableName); + if(res.type() == QVariant::ULongLong || res.type() == QVariant::LongLong) + { + return QVariant(res.toString()); + } + //if(res.type() == QVariant::DateTime) + //{ + // return QVariant(res.toDate().toString(Qt::ISODate)); + //} + return res; +} + +/** + * \ru + * \brief Переход к следующей записи регистра. + * \_ru + */ +bool +aIRegister::Next() +{ + return aObject::Next(); +} + + +/** + * \ru + * \brief Переход к предыдущей записи регистра. + * \_ru + */ +bool +aIRegister::Prev() +{ + return aObject::Prev(); +} + + +/** + * \ru + * \brief Переход к первой записи регистра. + * \_ru + */ +bool +aIRegister::First() +{ + return aObject::First(); +} + + +/** + * \ru + * \brief Переход к последней записи регистра. + * \_ru + */ +bool +aIRegister::Last() +{ + return aObject::Last(); +} diff --git a/src/lib/objects/airegister.h b/src/lib/objects/airegister.h new file mode 100644 index 0000000..d7ab9b6 --- /dev/null +++ b/src/lib/objects/airegister.h @@ -0,0 +1,93 @@ +/**************************************************************************** +** $Id: airegister.h,v 1.1 2008/11/05 21:16:29 leader Exp $ +** +** Header file of the Information Register of Ananas +** Engine applications +** +** Created : 20031201 +** +** Copyright (C) 2003-2004 Leader InfoTech. All rights reserved. +** +** This file is part of the Library of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.leaderit.ru/page=ananas or email sales@leaderit.ru +** See http://www.leaderit.ru/gpl/ for GPL licensing information. +** +** Contact org@leaderit.ru if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#ifndef AIREGISTER_H +#define AIREGISTER_H +#include +#include +#include +#include +#include "acfg.h" +#include "aobject.h" + +class aDatabase; + +class aDocJournal; + +class aDocument; + + + +/*! + * \en + * Object for working with information register in database. + * Using for provide between database tables and wobjects or ananas scripts + * \_en + * \ru + * \class aIRegister aIRegister.h + * \brief Класс aIRegister определяет программный интерфейс Информационных регистров. + * + * Информационный регистр служит для хронологической записи данных. + * Для хранения остатков следует использовать Накопительные регистры aARegister + * \see aARegister + * \_ru + */ +class ANANAS_EXPORT aIRegister :public aObject +{ + Q_OBJECT +public: + aIRegister(aCfgItem registerItem, aDatabase * adb = 0); + aIRegister( const QString & name, aDatabase * adb = 0, const QString & type = "InfoRegister."); + virtual ~aIRegister(); +// ERR_Code initObject(aDatabase * adb); + virtual ERR_Code initObject(); + virtual bool deleteDocument( aDocument * doc ); + virtual bool deleteTable( qulonglong iddt ); +public slots: + virtual int SetDocument( aDocument * doc ); + virtual aDocument * GetDocument(); + virtual int SetTable( const QString & tblname ); + virtual int New(); + virtual int Select( const QString &from, const QString & to); + virtual int Select( QDateTime from, QDateTime to ); + virtual int SelectByDoc(); + virtual QVariant Value( const QString & name, const QString &tableName = "" ); + + virtual int SetFilter( const QString & fieldName, const QVariant & value ); + virtual bool Next(); + virtual bool Prev(); + virtual bool First(); + virtual bool Last(); +protected: + bool docseted, tableseted; + QString tname; + aDocument * nowDoc; +}; + +#endif// AIREGISTER_H diff --git a/src/lib/objects/aobject.cpp b/src/lib/objects/aobject.cpp new file mode 100644 index 0000000..cad317a --- /dev/null +++ b/src/lib/objects/aobject.cpp @@ -0,0 +1,1136 @@ +/**************************************************************************** +** $Id: aobject.cpp,v 1.3 2008/11/09 21:09:11 leader Exp $ +** +** Code file of the Ananas Object of Ananas +** Designer and Engine applications +** +** Created : 20031201 +** +** Copyright (C) 2003-2004 Leader InfoTech. All rights reserved. +** Copyright (C) 2005-2006 Grigory Panov , Yoshkar-Ola. +** +** This file is part of the Library of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.leaderit.ru/page=ananas or email sales@leaderit.ru +** See http://www.leaderit.ru/gpl/ for GPL licensing information. +** +** Contact org@leaderit.ru if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#include +#include +#include +#include +#include "adatabase.h" +#include "aobject.h" +#include "aform.h" +#include "alog.h" + + +/*! + * \en + * Craeate abstract aObject. + * \param parent - parent object + * \param name - name of object + * \_en + * \ru + * Создает абстрактный не связанный с базой данных объект управления данными. + * Созданный таким образом объект не использует информацию из метаданных о составе и + * типах полей. То есть он не является какой-либо моделью данных. И на самом деле малопригоден + * для использования. В дазе данных ни как не отражается создание этого объекта. Для того, + * что бы зарегистрировать вновь созданный абстрактный объект в базе данных, необходимо + * сначала проинициализировать его с использованием метаданных, а затем вызвать метод New(). + * \_ru + */ +aObject::aObject( QObject *parent, const char *name ) +:QObject( parent, name ) +{ + db = 0; + vInited = false; + filtred = false; + selectFlag = false; +} + + + +/*! + * \en + * Create aObject, inited by md object. + * md object finding by name + * \param oname - md name of object, name contens prefix + * Document. for documents, + * InfoRegister. for information registers, + * Catalogue. for catalogues, + * AccumulationRegister. for Accumulation registers, + * DocJournal. for journals + * \param adb - link on object aDataBase used for work + * \param parent - parent object + * \param name - name of object + * \_en + * \ru + * Создает объект как модель данных, описанную в метаданных. На описание в метаданных + * указывает один из передаваемых при вызове параметров - имя элемента метаданных. + * После успешного создания объекта с ним можно работать как с объектом данных со структурой, + * описанной в метаданных, и индентифицируемой именем, переданным в параметрах вызова. + * + * \_ru + */ +aObject::aObject( const QString &oname, aDatabase *adb, QObject *parent, const char *name ) +:QObject( parent, name ) +{ + vInited = false; + filtred = false; + selectFlag = false; + db = adb; + if ( adb ) + { + obj = adb->cfg.find( oname ); + setObject( obj ); + } +} + + + +/*! + * Create aObject, inited by md object. + * \param context - hi leve md object + * \param adb - link on object aDataBase used for work + * \param parent - parent object + * \param name - name of object + */ +aObject::aObject( aCfgItem context, aDatabase *adb, QObject *parent, const char *name ) +:QObject( parent, name ) +{ + filtred = false; + vInited = false; + db = adb; + if ( adb ) + { + setObject( context ); + } +} + + + +/*! + * virtual destructor. + */ +aObject::~aObject() +{ +} + + + +/*! + * Tune on metadata object and it's database tables. + * \param adb - link on database object + * \return error code + */ +ERR_Code +aObject::init() +{ + if ( isInited() ) return err_noerror; + return initObject(); +} + + + +/*! + * Set new object type after create + * /param newobject - new md object + * \return error code + */ +ERR_Code +aObject::setObject( aCfgItem newobject ) +{ + setInited( false ); + obj = newobject; + return init(); +} + + + +/*! + * Init object after create. + * Need setObject( id ), where id - if of the metadata object of the adb->cfg loaded Configuration. + * \return error code + */ +ERR_Code +aObject::initObject() +{ + aCfgItem fg, f; + QString tname; + + setInited( true ); +// db = adb; + md = 0; + if ( db ) md = &db->cfg; + else + { + aLog::print(aLog::Error, tr("aObject have no database!")); + return err_nodatabase; + } + if ( obj.isNull() ) + { + aLog::print(aLog::Error, tr("aObject md object not found")); + return err_objnotfound; + } + return err_noerror; +} + + + +/*! + * + */ +bool +aObject::checkStructure() +{ + return false; +} + + + +/*! + * Return the table of object by it's name. + * /param name - name of table for main table use name="" or empty parametr + * /return link on aDataTable or 0 if table not found + */ +aDataTable * +aObject::table( const QString &name ) +{ + if ( !dbtables[ name ] ) + { + if (name!="" && !name.isEmpty()) + { + aLog::print(aLog::Error, tr("aObject table with name %1 not found").arg(name)); + cfg_message(1, tr("Table `%s' not found.\n").utf8(),(const char*) name); + } + // else + // { + // cfg_message(1, tr("Table name is empty.\n").utf8()); + // } + return 0; + } + return dbtables[ name ]; +} + + + +/*! + * Insert table name and it link into internal buffer. + * used for finding table by it's md name or some default name + * /param dbname - database name of table + * /param obj - md object, used for aDataTable initing + * /param name - name of table, used for finding table in buffer + * /return error code + */ +ERR_Code +aObject::tableInsert( const QString &dbname, aCfgItem obj, const QString &name ) +{ + if ( db ) + { + aDataTable *t = db->table( dbname ); + if ( !t ) + return err_notable; + t->setObject( obj ); + dbtables.insert( name, t ); + return err_noerror; + } + aLog::print(aLog::Error, tr("aObject have no database!")); + return err_nodatabase; +} + + + +/*! + * Insert table name and it link into internal buffer. + * used for finding table by it's md name or some default name + * table not inited by md object + * /param dbname - database name of table + * /param name - name of table, used for finding table in buffer + * /return error code + */ +ERR_Code +aObject::tableInsert( const QString &dbname, const QString &name ) +{ + if ( db ) { + aDataTable *t = db->table( dbname ); + if ( !t ) return err_notable; + dbtables.insert( name, t ); + return err_noerror; + } + aLog::print(aLog::Error, tr("aObject have no database!")); + return err_nodatabase; +} + + + +/*! + * Remove table from buffer. + * /param name - table name + * /return err_notable if table not found + */ +ERR_Code +aObject::tableRemove( const QString &name ) +{ + if ( !dbtables[name] ) + { + aLog::print(aLog::Error, tr("aObject table with name %1 not found").arg(name)); + return err_notable; + } + dbtables.remove( name ); + return err_noerror; +} + + + +/*! + * + */ +QString +aObject::trSysName( const QString & ) +{ + return ""; +} + + + +/*! + * Gets system field value. + * \param name (in) - field name. + * \return field value or QVariant::Invalid if field no exist. + */ +QVariant +aObject::sysValue( const QString & name, const QString &tableName ) +{ + aDataTable *t = table( tableName ); + if ( t && t->sysFieldExists( name ) ) + { + return t->sysValue(name); + } + else return QVariant::Invalid; +} + + + +/*! + * Sets system field value. + * \param name (in) - field name. + * \param value (in) - sets value. + */ +int +aObject::setSysValue( const QString & name, QVariant value, const QString &tableName ) +{ + aDataTable *t = table( tableName ); + if ( t ) + { + t->setSysValue( name, value ); + return err_noerror; + } + return err_notable; +} + + + +/*! + * Return field value of the primary object database table. + */ +QVariant +aObject::Value( const QString & name, const QString &tableName ) +{ + + aDataTable *t = table( tableName ); + QString trName = trSysName(name); + + if ( trName != "" ) return sysValue( trName ); + else + { + if ( t ) return t->value( name ); + } + return QVariant(""); +} + + + +/*! + * Set field value of the primary object database table. + */ +int +aObject::SetValue( const QString & name, const QVariant &value, const QString &tableName ) +{ + aDataTable *t = table( tableName ); + QString trName = trSysName(name); + + if ( trName != "" ) return setSysValue( trName, value ); + else + { + if ( t ) + { + t->setValue( name, value ); + return err_noerror; + } + + } + return err_notable; +// return setTValue( "", name, value ); +} + + + +/*! + * Check object selecting. + * \return true if object record selected in database. + */ +bool +aObject::IsSelected() +{ + return selected(); +} + + + +/*! + * + */ +bool +aObject::IsMarkDeleted(const QString & tname) +{ + aDataTable *t = table( tname ); + if ( t && t->sysFieldExists( "df" ) ) return t->sysValue( "df" ).toInt() == 1; + return false; +} + + + +/*! + * + */ +bool +aObject::IsMarked() +{ + aDataTable *t = table(); + if ( t && t->sysFieldExists( "mf" ) ) return t->sysValue( "mf" ).toInt() == 1; + return false; +} + + + +/*! + * + */ +/* +int +aObject::TableSetMarkDeleted( bool Deleted, const QString & tname ) +{ + aDataTable *t = table( tname ); + if ( t && t->sysFieldExists( "df" ) ) { + QString v = "0"; + if ( Deleted ) v = "1"; + t->setSysValue( "df", QVariant( v ) ); + return err_noerror; + } + return err_incorrecttype; // Object can not be mark deleted +} +*/ + + +/*! + * + */ +int +aObject::SetMarkDeleted( bool Deleted, const QString & tname ) +{ + aDataTable *t = table( tname ); + if ( t && t->sysFieldExists( "df" ) ) + { + QString v = "0"; + if ( Deleted ) v = "1"; + t->setSysValue( "df", QVariant( v ) ); + return err_noerror; + } + else + { + aLog::print(aLog::Error, tr("aObject have no system field %1").arg("df")); + return err_incorrecttype; // Object can not be mark deleted + } +} + + + +/*! + * + */ +int +aObject::SetMarked( bool Marked ) +{ + aDataTable *t = table(); + if ( t && t->sysFieldExists( "mf" ) ) { + QString v = ""; + if ( Marked ) v = "1"; + t->setSysValue( "mf", QVariant( v ) ); +// t->printRecord(); + return err_noerror; + } + aLog::print(aLog::Error, tr("aObject have no system field %1").arg("mf")); + return err_incorrecttype; // Object can not be marked +} + + + +/*! + * Add new object record in database. + */ +int +aObject::New() +{ + aDataTable *t = table(); + + if ( !t ) return err_notable; + setSelected ( t->New() ); +/* Q_ULLONG Uid = t->primeInsert()->value("id").toULongLong(); + if ( t->insert() ) + { + if ( t->select(QString("id=%1").arg(Uid), false) ) + if ( t->first() ) + { + setSelected(true); + return err_noerror; + } + return err_selecterror; + } +*/ if ( selected() ) return err_noerror; + return err_inserterror; +} + + + +/*! + * Copy current selected object data in database. + */ +/*Q_ULLONG +aObject::copy( const QString & tablename ) +{ + aDataTable * t = table( tablename ); + + if ( !t ) return 0; + if ( !selected(tablename) ) return 0; + QSqlRecord * r = t->primeUpdate(); + Q_ULLONG Uid = db->uid( t->id ); + r->setValue("id",Uid); + if ( t->insert() ) return Uid; + else return 0; +} +*/ + + +/*! + * + */ +int +aObject::Copy() +{ +// QSqlRecord r; + +// Q_ULLONG Uid = copy(); +// if ( !Uid ) return err_copyerror; + aDataTable *t = table(); + if ( t->Copy() ) return err_noerror; +// if ( t->select(QString("id=%1").arg(Uid)) ) +// if ( t->first() ) +// return err_noerror; + return err_copyerror; +} + + + +/*! +* Delete curent selected object record from database. +*/ +int +aObject::Delete() +{ + aDataTable * t = table(); + if ( !t ) return err_notable; + db->markDeleted(getUid()); + t->Delete(); +// if ( !selected() ) return err_notselected; +// t->primeDelete(); +// t->del(); + setSelected (false); + return err_noerror; +} + + + +/*! + *\~english + * Update curent selected object record to database. + *\~russian + *\~ + */ +int +aObject::Update() +{ + aDataTable *t = table(); + QSqlRecord *r; + int i; + + if ( !t ) return err_notable; + t->Update(); +/* + r = t->primeUpdate(); + t->printRecord(); + for ( i=0;icount();i++ ) r->setValue( i, t->value( i ) ); + + t->update(); +*/ + if ( t->lastError().type() ) + { + //debug_message("update error %i %s\n",t->lastError().type(), ( const char *)t->lastError().text()); + + aLog::print(aLog::Error, tr("aObject update error. Driver message: %1").arg(t->lastError().text())); + return err_updateerror; + } + else { + return err_noerror; + } +} + + + +/*! + *\~english + * Update object attributes from curent selected object database record. + *\~russian + *\~ + *//* +void +aObject::updateAttributes( const QString & tname ) +{ + aDataTable *t = table(); + +} +*/ + +/*! + *\~english + * Conduct document. + * Do nothing. Added for wDocument compatibility. + *\~russian + * Проводит документ. + * Ничего не делает. Предназначена для совместимости и работы в wDocument. + *\~ + *\return \~english error code - abstract object.\~russian код ошибки - абстрактный обект.\~ + */ +int +aObject::Conduct() +{ + return err_abstractobj; +} + +/*! + *\~english + * UnConduct document. + * Do nothing. Added for wDocument compatibility. + *\~russian + * Распроводит документ. + * Ничего не делает. Предназначена для совместимости и работы в wDocument. + *\~ + *\return \~english error code - abstract object.\~russian код ошибки - абстрактный обект.\~ + */ +int +aObject::UnConduct() +{ + return err_abstractobj; +} + +bool +aObject::IsConducted() +{ + return 0; +} + + + +/*! + *\~english + * Return document database id. + * always return 0. Added for wJournal compatibility. + *\~russian + * Возвращает id документа в базе данных. + * Всегда возвращает 0. Предназначена для совместимости и работы в wJournal. + *\~ + *\return \~english 0.\~russian 0.\~ + */ +qulonglong +aObject::docId() +{ + return 0; +} + + +/*! + * \ru + * Позиционирует указатель в БД на запись, соотвествующую объекту + * с указанным идентификатором. + * \param id - Идентификатор объекта. + * \return возвращает код ошибки или 0 в случае успеха. + * \_ru + */ +ERR_Code +aObject::select( qulonglong id ) +{ + aDataTable * t = table(); + if ( !t ) return err_notable; + setSelected (false); + long otype = db->uidType( id ); +// debug_message("otype=%li\n",otype); + if ( !otype ) return err_objnotfound; + if ( concrete && ( otype != t->getMdObjId() ) ) return err_incorrecttype; + if ( !concrete ) + { + aCfgItem tmpObj = md->find( otype ); + if ( tmpObj.isNull() ) return err_objnotfound; + setObject ( tmpObj ); + } + if ( t->select( QString("id=%1").arg(id), false ) ) + if ( t->first() ) + { +// t->primeUpdate(); + setSelected (true); +// t->printRecord(); + return err_noerror; + } + else return err_notselected; + return err_selecterror; +} + + + +/*! + * + */ +ERR_Code +aObject::select(const QString & query, const QString &tableName) +{ + aDataTable * t = table(tableName); + if ( !t ) return err_notable; + if (t->select(query)) + if( t->first() ) + { + setSelected (true); + return err_noerror; + } + else return err_notselected; + return err_selecterror; +} + + + +/*! + * Return field value of the secondary object database table. + */ +QVariant +aObject::tValue( const QString & tablename, const QString & name ) +{ + aDataTable *t = table( tablename ); +//CHECK_POINT + if ( t ) return t->value( name ); + return QVariant(""); +} + + + +/*! + * Set field value of the secondary object database table. + */ +ERR_Code +aObject::setTValue( const QString & tablename, const QString & name, const QVariant &value ) +{ + aDataTable *t = table( tablename ); + if ( t ) + { + t->setValue( name, value ); + return err_noerror; + } + return err_notable; +} + + + +/*! + * + */ +ERR_Code +aObject::decodeDocNum( QString nm, QString & pref, int & num) +{ + + aLog::print(aLog::Debug, tr("aObject decode doc number %1").arg(nm)); + int pos = -1; + for ( uint i = nm.length(); i > 0; i-- ) + { + if ( ( nm.at(i-1) >='0' ) && ( nm.at(i-1) <= '9' ) ) + continue; + else + { + pos = i; + break; + } + } + if ( pos == -1 ) + { +//CHECK_POINT + pref = ""; + num = nm.toInt(); + return err_incorrectname; + } + if ( pos == ( int ) nm.length() ) + { +//CHECK_POINT + pref = nm; + num = -1; + return err_incorrectname; + } +//CHECK_POINT + pref = nm.left( pos ); + num = nm.mid(pos).toInt(); + aLog::print(aLog::Debug, tr("aObject decode doc number ok, pref=%1 num=%2").arg(pref).arg(num)); + return err_noerror; +} + + + +/*! + * + */ +/* +bool +aObject::Next() +{ + return table()->next(); +// return dbtables[""]->next(); +} +*/ + + +/*! + * + */ +/* +bool +aObject::Prev() +{ +// return dbtables[""]->prev(); + return table()->prev(); +} +*/ + + +/*! + * + */ +/* +bool +aObject::First() +{ +// return dbtables[""]->first(); + return table()->first(); +} +*/ + + +/*! + * + */ +/* +bool +aObject::Last() +{ +// return dbtables[""]->last(); + return table()->last(); +} +*/ + + +/*! + * + */ +bool +aObject::Next( const QString& tableName ) +{ + return table(tableName)->next(); +} + + + +/*! + * + */ +bool +aObject::Prev( const QString& tableName ) +{ + return table(tableName)->prev(); +} + + + +/*! + * + */ +bool +aObject::First( const QString& tableName ) +{ + return table(tableName)->first(); +} + + + +/*! + * + */ +bool +aObject::Last( const QString& tableName ) +{ + return table(tableName)->last(); +} + +/*! + * \ru + * Возвращает уникальный идентификатор объекта из базы данных. + * В качестве объекта например может выступать "Приходная накладная" от такого-то числа за таким то номером. + * Каждый вновь созданный в системе документ или элемент справочника, включая группы справочника имеет свой уникальный + * неповторяющийся идентификатор. Если какое-либо поле, какого-либо объекта имеет тип Объект (например Document.Накладная), + * то в качестве значения ему нужно задавать уникальный идентификатор объекта, возвращаемый функцией Uid(). + * Не существует возможности изменить существующий идентификатор какого-либо объекта. Созданием и управлением + * идентификаторами объектов занимается система. + * \return строка со значением уникального идентификатора. + * \_ru + */ +QString +aObject::Uid() +{ + return QString::number(getUid()); +} + + +/*! + * + */ +qulonglong +aObject::getUid() +{ + qulonglong Uid = 0; + if ( selected() ) Uid = table()->sysValue("id").toULongLong(); + return Uid; +} + + + +/*! + * + */ +void +aObject::setSelected( bool sel, const QString & tablename ) +{ + if ( tablename == "" ) selectFlag = sel; + else table(tablename)->selected = sel; +} + + + +/*! + * + */ +bool +aObject::selected( const QString & tablename ) +{ + if ( tablename == "" ) return selectFlag; + else return table(tablename)->selected; +} + + + +/*! + * + */ +ERR_Code +aObject::setTFilter( const QString & tname, const QString & valname, const QVariant & value ) +{ + aDataTable * t = dbtables[tname]; + if ( !t ) return err_notable; + if ( t->setFilter( valname, value ) ) return err_noerror; + else return err_fieldnotfound; +} + + + +/*! + * + */ +ERR_Code +aObject::clearTFilter( const QString & tname ) +{ + aDataTable * t = dbtables[tname]; + if ( !t ) return err_notable; + t->clearFilter(); + return err_noerror; +} + + + +/*! + * + */ +int +aObject::SetFilter( const QString & valname, const QVariant & value ) +{ + int err = setTFilter( "", valname, value ); + filtred = !err; + return err; +} + + + +/*! + * + */ +int +aObject::ClearFilter() +{ + filtred = false; + return clearTFilter(""); +} + + + +/*! + * + */ +int +aObject::TableSetFilter( const QString & tname, const QString & valname, const QVariant & value ) +{ + return setTFilter( tname, valname, value ); +} + + + +/*! + * + */ +int +aObject::TableClearFilter( const QString & tname ) +{ + return clearTFilter(tname); +} + + + +/*! + * \ru + * Обновляет базу данных данными табличной части объекта. Обычно вызывается + * после метода TableSetValue. + * \param tablename - имя таблицы. Необходим для указания имени, так как + * в объекте возможно наличие нескольких табличных частей. + * \return возвращает код ошибки или 0 в случае успеха. + * \_ru + */ +int +aObject::TableUpdate( const QString & tablename ) +{ + aDataTable *t = table( tablename ); + if ( !t ) + { + + aLog::print(aLog::Error, tr("aObject table update: no table found with name %1").arg(tablename)); + return err_notable; + } +// t->primeUpdate(); + t->Update(); + if (t->lastError().type()) + { + + aLog::print(aLog::Error, tr("aObject update error. Driver message: %1").arg(t->lastError().text())); + return err_updateerror; + } + return err_noerror; +} + + + +/*! + * + */ +QString +aObject::displayString() +{ + QString res="***"; + int stdfc = 0, fid; + aCfgItem sw, f; + + sw = displayStringContext(); +// if ( md->objClass( obj ) == md_catalogue ) { +// sw = md->find( md->find( obj, md_element ), md_string_view ); +// } else { +// sw = md->find( obj, md_string_view ); +// } + if ( !sw.isNull() ) { + stdfc = md->attr( sw, mda_stdf ).toInt(); + switch ( stdfc ) { + case 0: + fid = md->sText( sw, md_fieldid ).toInt(); + res = table()->sysValue( QString( "uf%1" ).arg( fid ) ).toString(); +//printf("fid=%i res=%s\n",fid, ( const char *) res ); + break; + case 1: + break; + case 2: + break; + } + } + else + { + + aLog::print(aLog::Debug, tr("aObject display string context is null")); + } +// res = + return res; +} + + + + +aCfgItem +aObject::displayStringContext() +{ + return md->find( obj, md_string_view ); +} + + + +/** + * \ru + * Вид объекта, так как он описан в метаданных. + * \_ru + */ +QString +aObject::Kind( const QString & name ) +{ + QString wasKind = md->objClass( obj ); + if ( !name.isEmpty() ) { + // Set new kind. + + } + return wasKind; +} diff --git a/src/lib/objects/aobject.h b/src/lib/objects/aobject.h new file mode 100644 index 0000000..22ff56e --- /dev/null +++ b/src/lib/objects/aobject.h @@ -0,0 +1,170 @@ +/**************************************************************************** +** $Id: aobject.h,v 1.1 2008/11/05 21:16:29 leader Exp $ +** +** Header file of the Ananas Object of Ananas +** Designer and Engine applications +** +** Created : 20031201 +** +** Copyright (C) 2003-2004 Leader InfoTech. All rights reserved. +** +** This file is part of the Library of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.leaderit.ru/page=ananas or email sales@leaderit.ru +** See http://www.leaderit.ru/gpl/ for GPL licensing information. +** +** Contact org@leaderit.ru if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#ifndef AOBJECT_H +#define AOBJECT_H + +#include +#include "acfg.h" +#include "asqltable.h" + + +class aDatabase; + + + +/*! + * \en + * The parent object for hi level not visual objects + * for worcs with SQL database + * \_en + * \ru + * \brief Базовый класс для невизуальных классов (моделей в терминологии MVC) Ананаса, + * которым необходим доступ к базе данных. + * Наследует QObject. + * + * Как правило такие классы предоставляют методы + * для работы с пользовательскими "объектами" типа "Журнал операций", + * первичный учетный документ "Приходная накладная", "Справочник товаров", + * "Элемент справочника товаров" и др. + * + * Для доступа к данным базы данных через методы такого объекта + * сначала необходимо создать объект, указав в параметре вызова + * конструктора имя элемента метаданных, описывающего модель данных объекта, + * затем вызвать метод New(). + * \_ru + */ +class ANANAS_EXPORT aObject : public QObject +{ + Q_OBJECT +public: + aCfg * md; + aCfgItem obj; + aDatabase * db; + + aObject( QObject *parent = 0, const char *name = 0 ); + aObject( const QString &oname, aDatabase *adb, QObject *parent = 0, const char *name = 0 ); + aObject( aCfgItem context, aDatabase *adb, QObject *parent = 0, const char *name = 0 ); + virtual ~aObject(); + + virtual bool checkStructure(); + + ERR_Code init(); +// aCfgItem *getMDObject(); +// void setMDObject( aCfgItem object ); + ERR_Code decodeDocNum( QString nm, QString & pref, int & num); + virtual ERR_Code select( qulonglong id ); + qulonglong getUid(); + bool selected( const QString & tablename = "" ); + //void selectTable(const QString & tablename = ""); + ERR_Code select(const QString & query, const QString &tableName = ""); + aDataTable *table( const QString &name = "" ); + +// void updateAttributes( const QString & tname = "" ); + virtual qulonglong docId(); + + + virtual bool Next(const QString &tableName = "" ); + virtual bool Prev(const QString &tableName = "" ); + virtual bool First(const QString &tableName = "" ); + virtual bool Last(const QString &tableName = "" ); + +public slots: + virtual QString Uid(); + virtual bool IsSelected(); + virtual bool IsMarkDeleted( const QString & tname = "" ); + virtual bool IsMarked(); +// virtual int TableSetMarkDeleted( bool Deleted, const QString & tablename = "" );//depricated + virtual int SetMarkDeleted( bool Deleted, const QString & tablename = "" ); + virtual int SetMarked( bool Marked ); + +// virtual aObject *GetAttrib( const QString & AttribName ); +// virtual void SetAttrib( const QString & AttribName, const *aObject ); + + virtual int New(); + virtual int Copy(); + virtual int Delete(); + virtual int Update(); + virtual int Conduct(); + virtual int UnConduct(); + virtual bool IsConducted(); + virtual QString Kind( const QString & name = QString::null ); +// virtual ERR_Code Select( QString num ){return err_incorrecttype;}; +// virtual ERR_Code Select( QDateTime from, QDateTime to, QString mdName){return err_incorrecttype;}; +// virtual ERR_Code Select( aObject* ){return err_incorrecttype;}; + + virtual QVariant Value( const QString & name, const QString &tableName = "" ); + virtual int SetValue( const QString & name, const QVariant &value, const QString &tableName = "" ); + + virtual QVariant sysValue( const QString & name, const QString &tableName = "" ); + virtual int setSysValue( const QString & name, QVariant value, const QString &tableName = "" ); + +// virtual bool Next(); +// virtual bool Prev(); +// virtual bool First(); +// virtual bool Last(); + + virtual int SetFilter( const QString & valname, const QVariant & value ); + virtual int ClearFilter(); + virtual int TableSetFilter( const QString & tname, const QString & valname, const QVariant & value ); + virtual int TableClearFilter( const QString & tname ); + virtual bool IsFiltred() {return filtred;}; + virtual int TableUpdate( const QString & tablename ); + virtual QString displayString(); + +protected: + bool concrete; + virtual aCfgItem displayStringContext(); +// Q_ULLONG lastUid; + virtual ERR_Code setObject( aCfgItem newobject ); +// virtual ERR_Code initObject( aDatabase *adb ); + virtual ERR_Code initObject(); + bool isInited() { return vInited; }; + void setInited( bool flag ){ vInited = flag; }; + ERR_Code tableInsert( const QString &dbname, aCfgItem obj, const QString &name = "" ); + ERR_Code tableInsert( const QString &dbname, const QString &name = "" ); + ERR_Code tableRemove( const QString &name = "" ); + + virtual QVariant tValue( const QString & tablename, const QString & name ); + virtual ERR_Code setTValue(const QString & tablename, const QString & name, const QVariant &value); + virtual QString trSysName( const QString & sname ); +// Q_ULLONG copy(const QString & tablename = ""); + void setSelected( bool sel, const QString & tablename = "" ); + virtual ERR_Code setTFilter( const QString & tname, const QString & valname, const QVariant & value ); + virtual ERR_Code clearTFilter( const QString & tname ); + +private: + bool vInited, selectFlag, filtred; + Q3Dict dbtables; + +// QDict attributes; +}; + + +#endif diff --git a/src/lib/objects/aobjectlist.cpp b/src/lib/objects/aobjectlist.cpp new file mode 100644 index 0000000..cc2d52a --- /dev/null +++ b/src/lib/objects/aobjectlist.cpp @@ -0,0 +1,548 @@ +/**************************************************************************** +** $Id: aobjectlist.cpp,v 1.3 2008/11/09 21:09:11 leader Exp $ +** +** Code file of the Ananas Objects List of Ananas +** Designer and Engine applications +** +** Created : 20031201 +** +** Copyright (C) 2003-2004 Leader InfoTech. All rights reserved. +** Copyright (C) 2005-2006 Grigory Panov , Yoshkar-Ola. +** +** This file is part of the Library of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.leaderit.ru/page=ananas or email sales@leaderit.ru +** See http://www.leaderit.ru/gpl/ for GPL licensing information. +** +** Contact org@leaderit.ru if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#include +#include +#include +#include +#include "adatabase.h" +#include "aobjectlist.h" +#include "aform.h" +#include "alog.h" + + +/*! + * \en + * Craeate abstract aObjectListList. + * \param parent - parent object + * \param name - name of object + * \_en + * \ru + * Создает абстрактный не связанный с базой данных объект управления данными. + * Созданный таким образом объект не использует информацию из метаданных о составе и + * типах полей. То есть он не является какой-либо моделью данных. И на самом деле малопригоден + * для использования. В дазе данных ни как не отражается создание этого объекта. Для того, + * что бы зарегистрировать вновь созданный абстрактный объект в базе данных, необходимо + * сначала проинициализировать его с использованием метаданных, а затем вызвать метод New(). + * \_ru + */ +aObjectList::aObjectList( QObject *parent, const char *name ) +:QObject( parent, name ) +{ + db = 0; + vInited = false; + filtred = false; + selectFlag = false; +} + + + +/*! + * \en + * Create aObjectList, inited by md object. + * md object finding by name + * \param oname - md name of object, name contens prefix + * Document. for documents, + * InfoRegister. for information registers, + * Catalogue. for catalogues, + * AccumulationRegister. for Accumulation registers, + * DocJournal. for journals + * \param adb - link on object aDataBase used for work + * \param parent - parent object + * \param name - name of object + * \_en + * \ru + * Создает объект как модель данных, описанную в метаданных. На описание в метаданных + * указывает один из передаваемых при вызове параметров - имя элемента метаданных. + * После успешного создания объекта с ним можно работать как с объектом данных со структурой, + * описанной в метаданных, и индентифицируемой именем, переданным в параметрах вызова. + * + * \_ru + */ +aObjectList::aObjectList( const QString &oname, aDatabase *adb, QObject *parent, const char *name ) +:QObject( parent, name ) +{ + vInited = false; + filtred = false; + selectFlag = false; + db = adb; + if ( adb ) + { + obj = adb->cfg.find( oname ); + setObject( obj ); + } +} + + + +/*! + * Create aObjectList, inited by md object. + * \param context - hi leve md object + * \param adb - link on object aDataBase used for work + * \param parent - parent object + * \param name - name of object + */ +aObjectList::aObjectList( aCfgItem context, aDatabase *adb, QObject *parent, const char *name ) +:QObject( parent, name ) +{ + filtred = false; + vInited = false; + db = adb; + if ( adb ) + { + setObject( context ); + } +} + + + +/*! + * virtual destructor. + */ +aObjectList::~aObjectList() +{ +} + + + +/*! + * Tune on metadata object and it's database tables. + * \param adb - link on database object + * \return error code + */ +ERR_Code +aObjectList::init() +{ + if ( isInited() ) return err_noerror; + return initObject(); +} + + + +/*! + * Set new object type after create + * /param newobject - new md object + * \return error code + */ +ERR_Code +aObjectList::setObject( aCfgItem newobject ) +{ + setInited( false ); + obj = newobject; + return init(); +} + + + +/*! + * Init object after create. + * Need setObject( id ), where id - if of the metadata object of the adb->cfg loaded Configuration. + * \return error code + */ +ERR_Code +aObjectList::initObject() +{ + aCfgItem fg, f; + QString tname; + + setInited( true ); +// db = adb; + md = 0; + if ( db ) md = &db->cfg; + else + { + aLog::print(aLog::Error, tr("aObjectList have no database!")); + return err_nodatabase; + } + if ( obj.isNull() ) + { + aLog::print(aLog::Error, tr("aObjectList md object not found")); + return err_objnotfound; + } + return err_noerror; +} + + + + + +/*! + * Return field value of the primary object database table. + */ +QVariant +aObjectList::Value( const QString & name ) +{ + + aDataTable *t = table; + if ( t ) return t->value( name ); + return QVariant(""); +} + + + +/*! + * Set field value of the primary object database table. + */ +int +aObjectList::SetValue( const QString & name, const QVariant &value ) +{ + aDataTable *t = table; + if ( t ) + { + t->setValue( name, value ); + return err_noerror; + } + return err_notable; +} + + + +/*! + * Check object selecting. + * \return true if object record selected in database. + */ +bool +aObjectList::IsSelected() +{ + return selected(); +} + + + +/*! + * + */ +bool +aObjectList::IsMarkDeleted() +{ + aDataTable *t = table; + if ( t && t->sysFieldExists( "df" ) ) return t->sysValue( "df" ).toInt() == 1; + return false; +} + + + +/*! + * + */ +bool +aObjectList::IsMarked() +{ + aDataTable *t = table; + if ( t && t->sysFieldExists( "mf" ) ) return t->sysValue( "mf" ).toInt() == 1; + return false; +} + + + +/*! + * + */ +int +aObjectList::SetMarkDeleted( bool Deleted ) +{ + aDataTable *t = table; + if ( t && t->sysFieldExists( "df" ) ) + { + QString v = "0"; + if ( Deleted ) v = "1"; + t->setSysValue( "df", QVariant( v ) ); + return err_noerror; + } + else + { + aLog::print(aLog::Error, tr("aObjectList have no system field %1").arg("df")); + return err_incorrecttype; // Object can not be mark deleted + } +} + + + +/*! + * + */ +int +aObjectList::SetMarked( bool Marked ) +{ + aDataTable *t = table; + if ( t && t->sysFieldExists( "mf" ) ) { + QString v = ""; + if ( Marked ) v = "1"; + t->setSysValue( "mf", QVariant( v ) ); +// t->printRecord(); + return err_noerror; + } + aLog::print(aLog::Error, tr("aObjectList have no system field %1").arg("mf")); + return err_incorrecttype; // Object can not be marked +} + + + + + +/*! + * \ru + * Позиционирует указатель в БД на запись, соотвествующую объекту + * с указанным идентификатором. + * \param id - Идентификатор объекта. + * \return возвращает код ошибки или 0 в случае успеха. + * \_ru + */ +ERR_Code +aObjectList::select( qulonglong id ) +{ + aDataTable * t = table; + if ( !t ) return err_notable; + setSelected (false); + long otype = db->uidType( id ); + if ( !otype ) return err_objnotfound; +// if ( concrete && ( otype != t->getMdObjId() ) ) return err_incorrecttype; +// if ( !concrete ) +// { + aCfgItem tmpObj = md->find( otype ); + if ( tmpObj.isNull() ) return err_objnotfound; + setObject ( tmpObj ); +// } + if ( t->select( QString("id=%1").arg(id), false ) ) + if ( t->first() ) + { +// t->primeUpdate(); + setSelected (true); +// t->printRecord(); + return err_noerror; + } + else return err_notselected; + return err_selecterror; +} + + + +/*! + * + */ +ERR_Code +aObjectList::select(const QString & query ) +{ + aDataTable * t = table; + if ( !t ) return err_notable; + if (t->select(query)) + if( t->first() ) + { + setSelected (true); + return err_noerror; + } + else return err_notselected; + return err_selecterror; +} + + + + + +/*! + * + */ +bool +aObjectList::Next() +{ + return table->next(); +} + + + +/*! + * + */ +bool +aObjectList::Prev() +{ + return table->prev(); +} + + + +/*! + * + */ +bool +aObjectList::First() +{ + return table->first(); +} + + + +/*! + * + */ +bool +aObjectList::Last() +{ + return table->last(); +} + +/*! + * \ru + * Возвращает уникальный идентификатор объекта из базы данных. + * В качестве объекта например может выступать "Приходная накладная" от такого-то числа за таким то номером. + * Каждый вновь созданный в системе документ или элемент справочника, включая группы справочника имеет свой уникальный + * неповторяющийся идентификатор. Если какое-либо поле, какого-либо объекта имеет тип Объект (например Document.Накладная), + * то в качестве значения ему нужно задавать уникальный идентификатор объекта, возвращаемый функцией Uid(). + * Не существует возможности изменить существующий идентификатор какого-либо объекта. Созданием и управлением + * идентификаторами объектов занимается система. + * \return строка со значением уникального идентификатора. + * \_ru + */ +QString +aObjectList::Uid() +{ + return QString::number(getUid()); +} + + +/*! + * + */ +qulonglong +aObjectList::getUid() +{ + qulonglong Uid = 0; + if ( selected() ) Uid = table->sysValue("id").toULongLong(); + return Uid; +} + + + +/*! + * + */ +void +aObjectList::setSelected( bool sel ) +{ + selectFlag = sel; +} + + + +/*! + * + */ +bool +aObjectList::selected() +{ + return selectFlag; +} + + + +/*! + * + */ +ERR_Code +aObjectList::SetFilter( const QString & valname, const QVariant & value ) +{ + aDataTable *t = table; + if ( !t ) return err_notable; + if ( t->setFilter( valname, value ) ) return err_noerror; + else return err_fieldnotfound; +} + + + +/*! + * + */ +ERR_Code +aObjectList::ClearFilter() +{ + aDataTable * t = table; + if ( !t ) return err_notable; + t->clearFilter(); + return err_noerror; +} + + + + +/*! + * + */ +QString +aObjectList::displayString() +{ + QString res="***"; + int stdfc = 0, fid; + aCfgItem sw, f; + + sw = displayStringContext(); +// if ( md->objClass( obj ) == md_catalogue ) { +// sw = md->find( md->find( obj, md_element ), md_string_view ); +// } else { +// sw = md->find( obj, md_string_view ); +// } + if ( !sw.isNull() ) { + stdfc = md->attr( sw, mda_stdf ).toInt(); + switch ( stdfc ) { + case 0: + fid = md->sText( sw, md_fieldid ).toInt(); + res = table->sysValue( QString( "uf%1" ).arg( fid ) ).toString(); +//printf("fid=%i res=%s\n",fid, ( const char *) res ); + break; + case 1: + break; + case 2: + break; + } + } + else + { + + aLog::print(aLog::Debug, tr("aObjectList display string context is null")); + } +// res = + return res; +} + + + + +aCfgItem +aObjectList::displayStringContext() +{ + return md->find( obj, md_string_view ); +} + + + +aObject * +aObjectList::currentObject() const +{ + return 0; +} diff --git a/src/lib/objects/aobjectlist.h b/src/lib/objects/aobjectlist.h new file mode 100644 index 0000000..c2bf8a6 --- /dev/null +++ b/src/lib/objects/aobjectlist.h @@ -0,0 +1,112 @@ +/**************************************************************************** +** $Id: aobjectlist.h,v 1.1 2008/11/05 21:16:29 leader Exp $ +** +** Header file of the Ananas Objects List of Ananas +** Designer and Engine applications +** +** Created : 20031201 +** +** Copyright (C) 2003-2004 Leader InfoTech. All rights reserved. +** +** This file is part of the Library of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.leaderit.ru/page=ananas or email sales@leaderit.ru +** See http://www.leaderit.ru/gpl/ for GPL licensing information. +** +** Contact org@leaderit.ru if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#ifndef AOBJECTLIST_H +#define AOBJECTLIST_H + +#include +#include "acfg.h" +#include "asqltable.h" + + +class aDatabase; +class aObject; + + +/*! + * \en + * The parent object for hi level not visual objects lists + * for worcs with SQL database + * \_en + * \ru + +* \_ru + */ +class ANANAS_EXPORT aObjectList : public QObject +{ + Q_OBJECT +// Q_PROPERTY( aObject currentObject READ currentObject ) +public: + aCfg * md; + aCfgItem obj; + aDatabase * db; + + aObjectList( QObject *parent = 0, const char *name = 0 ); + aObjectList( const QString &oname, aDatabase *adb, QObject *parent = 0, const char *name = 0 ); + aObjectList( aCfgItem context, aDatabase *adb, QObject *parent = 0, const char *name = 0 ); + virtual ~aObjectList(); + + ERR_Code init(); + ERR_Code decodeDocNum( QString nm, QString & pref, int & num); + virtual ERR_Code select( qulonglong id ); + qulonglong getUid(); + bool selected(); + void setSelected( bool sel ); + ERR_Code select(const QString & query ); + +// virtual Q_ULLONG docId(); + + +public slots: + virtual aObject *currentObject() const; + + virtual QString Uid(); + virtual bool IsSelected(); + virtual bool IsMarkDeleted(); + virtual bool IsMarked(); + virtual int SetMarkDeleted( bool Deleted ); + virtual int SetMarked( bool Marked ); + virtual QVariant Value( const QString & name ); + virtual int SetValue( const QString & name, const QVariant &value ); + + virtual bool Next(); + virtual bool Prev(); + virtual bool First(); + virtual bool Last(); + + virtual int SetFilter( const QString & valname, const QVariant & value ); + virtual int ClearFilter(); + virtual bool IsFiltred() {return filtred;}; + virtual QString displayString(); + +protected: + virtual aCfgItem displayStringContext(); + virtual ERR_Code setObject( aCfgItem newobject ); + virtual ERR_Code initObject(); + bool isInited() { return vInited; }; + void setInited( bool flag ){ vInited = flag; }; +private: + aDataTable *table; + bool vInited, selectFlag, filtred; + Q3Dict dbtables; +// QDict attributes; +}; + + +#endif diff --git a/src/lib/objects/objects.pri b/src/lib/objects/objects.pri new file mode 100644 index 0000000..6474384 --- /dev/null +++ b/src/lib/objects/objects.pri @@ -0,0 +1,17 @@ +HEADERS += \ + objects/aobject.h \ + objects/aaregister.h \ + objects/acatalogue.h \ + objects/adocjournal.h \ + objects/adocument.h \ + objects/airegister.h \ + objects/aobjectlist.h + +SOURCES += \ + objects/aobject.cpp \ + objects/aaregister.cpp \ + objects/acatalogue.cpp \ + objects/adocjournal.cpp \ + objects/adocument.cpp \ + objects/airegister.cpp \ + objects/aobjectlist.cpp diff --git a/src/lib/rclistviewitem.cpp b/src/lib/rclistviewitem.cpp new file mode 100644 index 0000000..3a5a1e3 --- /dev/null +++ b/src/lib/rclistviewitem.cpp @@ -0,0 +1,69 @@ +/**************************************************************************** +** $Id: rclistviewitem.cpp,v 1.1 2008/11/05 21:16:28 leader Exp $ +** +** Code file of the Ananas select database window +** of Ananas Designer and Engine applications +** +** Created : 20031201 +** +** Copyright (C) 2003-2004 Leader InfoTech. All rights reserved. +** +** This file is part of the Library of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.leaderit.ru/page=ananas or email sales@leaderit.ru +** See http://www.leaderit.ru/gpl/ for GPL licensing information. +** +** Contact org@leaderit.ru if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ +#include "rclistviewitem.h" +#include "qpixmap.h" + +rcListViewItem::rcListViewItem( Q3ListView *parent, + const QString &name, + const QString &rc, + bool fgroup): Q3ListViewItem( parent, name ) + { + init( rc, fgroup ); + }; + +rcListViewItem::rcListViewItem( Q3ListView *parent, + rcListViewItem* after, + const QString &name, + const QString &rc, + bool fgroup ): Q3ListViewItem( parent, after, name ) + { + init( rc, fgroup ); + }; + +rcListViewItem::rcListViewItem( rcListViewItem *parent, + const QString &name, + const QString &rc, + bool fgroup): Q3ListViewItem( parent, name ) + { + init( rc, fgroup ); + }; + +rcListViewItem::~rcListViewItem() + { +// rcfile = ""; + }; + +void +rcListViewItem::init( const QString &rc, bool fgroup) + { + group = fgroup; + rcfile = rc; + if ( group ) setPixmap(0, QPixmap(":/images/lib_dbgroup.png") ); + else setPixmap(0, QPixmap(":/images/lib_database.png") ); + }; diff --git a/src/lib/rclistviewitem.h b/src/lib/rclistviewitem.h new file mode 100644 index 0000000..8a99709 --- /dev/null +++ b/src/lib/rclistviewitem.h @@ -0,0 +1,71 @@ +/**************************************************************************** +** $Id: rclistviewitem.h,v 1.1 2008/11/05 21:16:28 leader Exp $ +** +** Code file of the Ananas select database window +** of Ananas Designer and Engine applications +** +** Created : 20031201 +** +** Copyright (C) 2003-2004 Leader InfoTech. All rights reserved. +** +** This file is part of the Library of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.leaderit.ru/page=ananas or email sales@leaderit.ru +** See http://www.leaderit.ru/gpl/ for GPL licensing information. +** +** Contact org@leaderit.ru if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ +#ifndef RCLISTVIEWITEM_H +#define RCLISTVIEWITEM_H + +//#include +//#include +#include +//#include +//#include + +//#include "deditrc.h" +//#include "acfgrc.h" +//#include "atests.h" + +class Q3ListView; +class Q3ListViewItem; + +class rcListViewItem : public Q3ListViewItem +{ +public: + QString rcfile; + bool group; + + rcListViewItem( Q3ListView *parent, + const QString &name = QString::null, + const QString &rc = QString::null, + bool fgroup = false ); + + rcListViewItem( Q3ListView *parent, + rcListViewItem* after, + const QString &name = QString::null, + const QString &rc = QString::null, + bool fgroup = false ); + + rcListViewItem( rcListViewItem *parent, + const QString &name = QString::null, + const QString &rc = QString::null, + bool fgroup = false ); + + virtual ~rcListViewItem(); + void init( const QString &rc = QString::null, bool fgroup = false ); +}; +#endif + diff --git a/src/lib/report/acalctemplate.cpp b/src/lib/report/acalctemplate.cpp new file mode 100644 index 0000000..393cbc6 --- /dev/null +++ b/src/lib/report/acalctemplate.cpp @@ -0,0 +1,151 @@ +/**************************************************************************** +** $Id: acalctemplate.cpp,v 1.2 2008/11/08 20:16:36 leader Exp $ +** +** Report metadata object header file of +** Ananas application library +** +** Created : 20050202 +** +** Copyright (C) 2003 by HaPK, email : theHaPK@yandex.ru +** Copyright (C) 2003-2006 Grigory Panov , Yoshkar-Ola. +** +** This file is part of the Designer application of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.leaderit.ru/page=ananas or email sales@leaderit.ru +** See http://www.leaderit.ru/gpl/ for GPL licensing information. +** +** Contact org@leaderit.ru if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#include "acalctemplate.h" +#include "alog.h" + +#include +#include + + +aCalcTemplate::aCalcTemplate() : aOOTemplate() +{ + +} + +aCalcTemplate::~aCalcTemplate() +{ +} + + +/** + * \~english + * Return true, if node contain tag + * \~russian + * Возвращает истину, когда текст ноды содержит тег с заданным именем. + * \~ + * \param node - \~english context for searching \~russian узел, с которого осуществляется поиск. \~ + * \param sname - \~english tag name \~russian имя тега для поиска \~ + * \param params - \~english true, if find simple tag and false, if section + * \~russian true, если ищется обычный тег и false, если ищется тег секции \~ + */ +bool +aCalcTemplate::getNodeTags(QDomNode node, const QString &tagname, bool params ) +{ + if(node.isText()) + { + QString str = node.nodeValue(); + QRegExp re; + // printf("n->text=%s\n",str.ascii()); + if(params) + { + re.setPattern(QString("%1.*%2").arg(open_token).arg(close_token)); + } + else + { + re.setPattern(QString("%1.*%2").arg(open_token_section).arg(close_token_section)); + } + re.setMinimal(true); + int pos = re.search(str,0); + + while(pos != -1) + { + // printf("find string =%s\n",str.mid(pos+2, re.matchedLength()-4).ascii()); + if(tagname == str.mid(pos+2, re.matchedLength()-4)) + { + // printf(">>>>>>>>>ok!\n"); + return true; + } + pos+= re.matchedLength(); + pos = re.search(str,pos); + } + + } + return false; +} + + + +QDomNode +aCalcTemplate::getCellNode(QDomNode node) +{ + while(!node.parentNode().isNull()) + { + QDomNode parent = node.parentNode(); + if(parent.nodeName() == "table:table-cell") + { + return parent; + } + else + { + return getCellNode(parent); + } + } +} + + /** + * \~english + * Addes to tag value of parametr \a tagName + * \~russian + * Добавляет к тегу значение параметра \a tagName. После вызова этой функции тег не исчезает, + * и к нему можно добавить еще значения, которые добавятся к концу текста, содержащего тег. + * \~ + * \param node - \~english context \~russian узел к которому добавляется значение \~ + * \param sname - \~english tag name \~russian имя тега \~ + */ +void +aCalcTemplate::insertTagsValues(QDomNode node, const QString &tagName) +{ + QDomNode n = node; + QString val = getValue(tagName); + bool ok; + val.toDouble(&ok); + if(ok) + { + aLog::print(aLog::Debug, QString("aCalcTemplate append double value %1 to tag").arg(val)); + QDomNode cellNode = getCellNode(n); + if(!cellNode.isNull()) + { + cellNode.toElement().setAttribute("office:value-type", "float"); + cellNode.toElement().setAttribute("office:value", val); + } + else + { + aLog::print(aLog::Error, "aCalcTemplate cell not found\n"); + } + } + else + { + aLog::print(aLog::Debug, "aCalcTemplate append string value to tag\n"); + } + n.setNodeValue(n.nodeValue()+getValue(tagName)); +} + + diff --git a/src/lib/report/acalctemplate.h b/src/lib/report/acalctemplate.h new file mode 100644 index 0000000..0b43acd --- /dev/null +++ b/src/lib/report/acalctemplate.h @@ -0,0 +1,58 @@ +/**************************************************************************** +** $Id: acalctemplate.h,v 1.1 2008/11/05 21:16:29 leader Exp $ +** +** Report metadata object header file of +** Ananas application library +** +** Created : 20050202 +** +** Copyright (C) 2003-2005 Grigory Panov , Yoshkar-Ola. +** +** This file is part of the Designer application of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.leaderit.ru/page=ananas or email sales@leaderit.ru +** See http://www.leaderit.ru/gpl/ for GPL licensing information. +** +** Contact org@leaderit.ru if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ +#ifndef ACALCTEMPLATE_H +#define ACALCTEMPLATE_H + +#include +#include +#include +#include + +#include "ananasglobal.h" +#include "aootemplate.h" + +/** + * \en + * Class for work with pattern in OpenOffice Calc format + * \_en + * \ru + * \brief Класс определяет интерфейс для работы с шаблонами в формате OpenOffice Calc. + * \_ru + */ +class ANANAS_EXPORT aCalcTemplate : public aOOTemplate +{ +public: + aCalcTemplate(); + virtual ~aCalcTemplate(); +protected: + virtual bool getNodeTags(QDomNode node, const QString &tagname, bool params ); + virtual void insertTagsValues(QDomNode node, const QString &tagName); + QDomNode getCellNode(QDomNode node); +}; +#endif // ACALCTEMPLATE_H diff --git a/src/lib/report/aootemplate.cpp b/src/lib/report/aootemplate.cpp new file mode 100644 index 0000000..b42ac6d --- /dev/null +++ b/src/lib/report/aootemplate.cpp @@ -0,0 +1,645 @@ +/**************************************************************************** +** $Id: aootemplate.cpp,v 1.2 2008/11/08 20:16:36 leader Exp $ +** +** Report metadata object header file of +** Ananas application library +** +** Created : 20050202 +** +** Copyright (C) 2003 by HaPK, email : theHaPK@yandex.ru +** Copyright (C) 2003-2006 Grigory Panov , Yoshkar-Ola. +** +** This file is part of the Designer application of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.leaderit.ru/page=ananas or email sales@leaderit.ru +** See http://www.leaderit.ru/gpl/ for GPL licensing information. +** +** Contact org@leaderit.ru if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#include "aootemplate.h" +#include "alog.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +aOOTemplate::aOOTemplate() : iTemplate() +{ + +} + +aOOTemplate::~aOOTemplate() +{ +} + +/** + * \en + * Open pattern. + * \_en + * \ru + * Открывает шаблон. Распаковывает его во временный каталог в директории /tmp + * \_ru + * \param fname \ru имя шаблона\_ru + */ +bool +aOOTemplate::open( const QString &fname ) +{ + QDir dir; + QString temp; + +#ifndef Q_OS_WIN32 + temp = getenv("TMPDIR"); + if(temp=="" || temp.isEmpty()) + temp = P_tmpdir; +#else + temp = getenv("TEMP"); +#endif + copyName = QString(temp+"/%1").arg(QDateTime::currentDateTime().toTime_t()); + copyName = QDir::convertSeparators(copyName); + aLog::print(aLog::Debug, tr("aOOTemplate temporary directory is %1").arg(copyName)); +// printf("copy name = %s\n",copyName.ascii()); + if(!dir.mkdir(copyName)) + { + aLog::print(aLog::Error, tr("aOOTemplate create temporary directory %1").arg(copyName)); + return false; + } + else + { + aLog::print(aLog::Debug, tr("aOOTemplate create temporary directory %1").arg(copyName)); + } +#ifndef Q_OS_WIN32 + Q3Process process( QString("unzip") ); + process.setWorkingDirectory (templateDir); + process.addArgument( fname ); + process.addArgument( "-d" ); + process.addArgument( copyName ); + +#else + Q3Process process( QString("7z") ); + process.setWorkingDirectory ( templateDir); + //printf("working dir = `%s'\n", QString(templateDir).ascii()); + process.addArgument( "x" ); + process.addArgument( "-y" ); + process.addArgument( QString("-o%1").arg(copyName) ); + process.addArgument( fname ); + +#endif + + if( !process.start() ) + { + aLog::print(aLog::Error, tr("aOOTemplate start unzip")); + return false; + } + + while( process.isRunning() ); + + if( !process.normalExit() ) + { + aLog::print(aLog::Error, tr("aOOTemplate unzip dead")); + return false; + } + else + { + aLog::print(aLog::Debug, tr("aOOTemplate unzip normal")); + } + if( process.exitStatus() ) + { + return false; + } + + QFile content (QDir::convertSeparators( copyName+"/content.xml") ); + docTpl.setContent( &content, false ); + + QFile style (QDir::convertSeparators( copyName+"/styles.xml") ); + docStyle.setContent( &style, false ); + + aLog::print(aLog::Info, tr("aOOTemplate open")); +return true; +} +/** + * \en + * Closes pattern. Deletes temporary files. + * \_en + * + * \ru + * Закрывает шаблон. Удаляет временные файлы. + * \_ru + */ +void +aOOTemplate::close() +{ + values.clear(); + // QDir dir; + docTpl.clear(); + docStyle.clear(); +#ifndef Q_OS_WIN32 + system( "rm -Rf "+copyName); +#else + system( "rd /S /Q \""+copyName+"\""); +#endif + QDir dir; + dir.rmdir(copyName); + +} +/** + * \en + * clears internal variable. + * \_en + * \ru + * Обнуляет внутренние переменные. + * \_ru + */ +void +aOOTemplate::clear() +{ + values.clear(); +// cleanUpTags(); +} +/** + * \en + * Returns value parameter `name` + * \_en + * \ru + * Возвращает значение параметра по его имени. + * \_ru + */ +QString +aOOTemplate::getValue( const QString &name ) +{ + if(values.find( name )!=values.end()) + { + return values.find( name ).data(); + } + else + { + aLog::print(aLog::Info, tr("aOOTemplate value for field %1 not setted").arg(name)); + return ""; + } +} + +/** + * \en + * Sets value parameter `name' + * \_en + * \ru + * Устанавливает значение параметра по его имени. + * \_ru + */ +void +aOOTemplate::setValue( const QString &name, const QString &value ) +{ + values[name]=value; +} +/** + * \en + * Execute replace tags to values. + * \_en + * \ru + * Выполняет подстановку значения параметра в шаблоне. + * Есть 2 типа тегов + * \arg обычные теги + * \arg секции - могут находиться ТОЛЬКО в строках таблицы. + + * Для подстановки значений обычных тегов необходимо выполнить setValue() где name = PARAM (сейчас #define PARAM "param") а value - значение для подстановки. Потом выполнить exec() с параметром = имени тега. + * Для подстановки секций необходимо задать нужные параметры, используя setValue() + * а потом выполнить exec() с именем секции. + * exec может вызываться нужное число раз как для обычных тегов, так и для секций + * \_ru + */ +QString +aOOTemplate::exec( const QString &sname ) +{ + setValue(sname, getValue(PARAM)); + //search tags in content + QDomNode n = docTpl.lastChild(); + while( !n.isNull() ) + { + searchTags(n, sname); + n = n.previousSibling(); + } + //search tags in colontituls + n = docStyle.lastChild(); + while( !n.isNull() ) + { + searchTags(n, sname); + n = n.previousSibling(); + } + return docTpl.toString(); + +} +/** + * \~english + * Added value to end tag with name `sname'. Don't deletes tag. + * \~russian + * Рекурсивная функция поиска и замены тегов на их значения в node. + * Не заменяет теги, а дописывает значения в конец. + * Для удаления тэгов используйте функцию cleanUpTags() + * \~ + * \param node - \~english context for searching \~russian узел, с которого осуществляется поиск. \~ + * \param sname - \~english tag name \~russian имя тега для поиска \~ + * \see cleanUpTags() getNodeTags() insertRowValues() + */ +void +aOOTemplate::searchTags(QDomNode node, const QString &sname ) +{ +QDomNode n = node.lastChild(); + while( !n.isNull() ) + { + + // printf("n->name=%s\n",n.nodeName().ascii()); + bool res = getNodeTags(n, sname, false); + if( res ) + { + insertRowValues(n); + } + else + { + res = getNodeTags(n, sname, true); + if(res) + { + insertTagsValues(n, sname); + } + else + { + searchTags(n, sname); + } + } + n = n.previousSibling(); + } +} +/** + * \~english + * Return true, if node contain tag + * \~russian + * Возвращает истину, когда текст ноды содержит тег с заданным именем. + * \~ + * \param node - \~english context for searching \~russian узел, с которого осуществляется поиск. \~ + * \param sname - \~english tag name \~russian имя тега для поиска \~ + * \param params - \~english true, if find simple tag and false, if section + * \~russian true, если ищется обычный тег и false, если ищется тег секции \~ + */ +bool +aOOTemplate::getNodeTags(QDomNode node, const QString &tagname, bool params ) +{ + if(node.isText()) + { + QString str = node.nodeValue(); + QRegExp re; + // printf("n->text=%s\n",str.ascii()); + if(params) + { + re.setPattern(QString("%1.*%2").arg(open_token).arg(close_token)); + } + else + { + re.setPattern(QString("%1.*%2").arg(open_token_section).arg(close_token_section)); + } + re.setMinimal(true); + int pos = re.search(str,0); + + while(pos != -1) + { + // printf("find string =%s\n",str.mid(pos+2, re.matchedLength()-4).ascii()); + if(tagname == str.mid(pos+2, re.matchedLength()-4)) + { + // printf(">>>>>>>>>ok!\n"); + return true; + } + pos+= re.matchedLength(); + pos = re.search(str,pos); + } + + } + return false; +} + +/** + * \~english + * insert new row in table and replace tag to value + * \~russian + * Вставляет новую строку в таблицу, заменяет теги на значения, удаляет тег секции из строки таблицы. + * Выполняет рекурсивный поиск узла, содержащего строку таблицы. У этого узла в OpenOffic'е есть + * специальное имя, которое распознается функцией. После того, как узел найден, строка строка дублируется, + * а из текущей строки удаляются все теги секции, чтобы избежать мнократного размножения строк таблицы. + * \~ + * \see searchTags() + */ +void +aOOTemplate::insertRowValues(QDomNode node) +{ + QDomNode n = node; + while(!n.parentNode().isNull()) + { + n = n.parentNode(); + if( n.nodeName()=="table:table-row" ) + { + n.parentNode().insertAfter(n.cloneNode(true),n); + clearTags(n,true); + QMap::Iterator it; + for ( it = values.begin(); it != values.end(); ++it ) + { + searchTags(n,it.key()); + } + + } + } +} + + + /** + * \~english + * Addes to tag value of parametr \a tagName + * \~russian + * Добавляет к тегу значение параметра \a tagName. После вызова этой функции тег не исчезает, + * и к нему можно добавить еще значения, которые добавятся к концу текста, содержащего тег. + * \~ + * \param node - \~english context \~russian узел к которому добавляется значение \~ + * \param sname - \~english tag name \~russian имя тега \~ + */ +void +aOOTemplate::insertTagsValues(QDomNode node, const QString &tagName) +{ + QDomNode n = node; + n.setNodeValue(n.nodeValue()+getValue(tagName)); +} + +/** + * \en + * clears all tags from pattern + * \_en + * \ru + * Удаляет все теги из документа, а также строки, в которых содержится тег секции + * \_ru + */ +void +aOOTemplate::cleanUpTags() +{ + + //clear tags in content + QDomNode n = docTpl.lastChild(); + while( !n.isNull() ) + { + clearTags(n,false); + // clearRow(n); + n = n.previousSibling(); + } + n = docTpl.lastChild(); + while( !n.isNull() ) + { + // clearTags(n,false); + clearRow(n); + n = n.previousSibling(); + } + + //clear tags in colontituls + n = docStyle.lastChild(); + while( !n.isNull() ) + { + clearTags(n,false); + // clearRow(n); + n = n.previousSibling(); + } + n = docStyle.lastChild(); + while( !n.isNull() ) + { + // clearTags(n,false); + clearRow(n); + n = n.previousSibling(); + } +} + + + + /** + * \~english + * Deletes tags from \a node + * \~russian + * Удаляет рекурсивно теги из \a node. + * \~ + * \param node - \~english context \~russian узел из которого нужно удалить теги \~ + * \param section - \~russian true, если надо удалить тег секции \~ + */ +void +aOOTemplate::clearTags(QDomNode node, bool section ) +{ + if(node.isNull()) return; + + QDomNode n = node.lastChild(); + while( !n.isNull() ) + { + if(n.isText()) + { + QString str = n.nodeValue(); + QRegExp re; + // printf("n->text tag = %s\n",str.ascii()); + if(section) + { + re.setPattern(QString("%1.*%2").arg(open_token_section).arg(close_token_section)); + } + else + { + re.setPattern(QString("%1.*%2").arg(open_token).arg(close_token)); + } + re.setMinimal(true); + int pos = re.search(str,0); + + while(pos != -1) + { + str = str.remove(re); + //printf("str = %s\n",str.ascii()); + pos = re.search(str,0); + } + n.setNodeValue(str); + + } + else + { + clearTags(n,section); + } + n = n.previousSibling(); + } + +} + +/** + * \~english + * Deletes row, having section tag + * \~russian + * Рекурсивная функция. Удаляет строки, содержащие тег секции + * \~ +* \param node - \~english context \~russian узел из которого нужно удалить строки \~ + */ +void +aOOTemplate::clearRow(QDomNode node) +{ +QDomNode n = node.lastChild(); + while( !n.isNull() ) + { + if(n.isText()) + { + QString str = n.nodeValue(); + QRegExp re; + //printf("n->text row=%s\n",str.ascii()); + re.setPattern(QString("%1.*%2").arg(open_token_section).arg(close_token_section)); + re.setMinimal(true); + int pos = re.search(str,0); + if(pos!=-1) + { + // printf(">>>find string =%s\n",str.ascii()); + QDomNode tmp = n; + while(!tmp.parentNode().isNull()) + { + tmp = tmp.parentNode(); + if( tmp.nodeName()=="table:table-row" ) + { + // printf("row removed\n"); + tmp.parentNode().removeChild(tmp); + break; + } + } + } + //n.setNodeValue(str); + + } + else + { + //clearTags(n); + clearRow(n); + } + n = n.previousSibling(); + } + +} +/** + * \en + * Returns patten + * \_en + * \ru + * Возвращает результат, т.е. шаблон в текстовом виде. Включена в интерфейс временно. + * \_ru + */ +QString +aOOTemplate::result() +{ + return docTpl.toString(); +} +/** + * \en + * Save pattern + * \_en + * \ru + * Сохраняет шаблон в файл с заданным именем. Перед сохранением необходимо выполнить функцию cleanUpTags() чтобы удалить тэги из сохраняемого документа. + * \_ru + */ +bool +aOOTemplate::save( const QString & fname ) +{ + + QString homeDir = QString("%1").arg(QDir::convertSeparators(QDir::homeDirPath ())); + QFile fContent( QDir::convertSeparators(copyName+"/content.xml") ); + if( !fContent.open( QIODevice::WriteOnly ) ) + { + aLog::print(aLog::Error, tr("aOOTemplate save %1 open for write").arg(fContent.name())); + return false; + } + QTextStream stream4content(&fContent); + docTpl.save(stream4content,2); + fContent.close(); + + QFile fStyle( QDir::convertSeparators(copyName+"/styles.xml") ); + if( !fStyle.open( QIODevice::WriteOnly ) ) + { + aLog::print(aLog::Error, tr("aOOTemplate save %1 open for write").arg(fContent.name())); + return false; + } + QTextStream stream4styles(&fStyle); + docStyle.save(stream4styles,2); + fStyle.close(); + + + + QString curDir;// = QDir::convertSeparators(QDir::irPath()); + curDir = QDir::convertSeparators(templateDir); + aLog::print(aLog::Debug, tr("aOOTemplate save working dir =%1").arg(curDir)); + +#ifndef Q_OS_WIN32 + + Q3Process process( QString("zip") ); + process.setWorkingDirectory(copyName); + process.addArgument( "-r" ); + process.addArgument( fname ); + process.addArgument("."); +#else + Q3Process process( QString("7z") ); + process.setWorkingDirectory(copyName); + process.addArgument( "a" ); + process.addArgument( "-tzip" ); + process.addArgument( fname ); + process.addArgument( "-r" ); + process.addArgument("."); +#endif + + + + if( !process.start() ) + { + aLog::print(aLog::Error, tr("aOOTemplate start zip")); + return false; + } + + while( process.isRunning() ); + + if( !process.normalExit() ) + { + aLog::print(aLog::Error, tr("aOOTemplate zip dead")); + return false; + } + else + { + aLog::print(aLog::Debug, tr("aOOTemplate zip normal to %1").arg(fname)); + } + if( process.exitStatus() ) + { + return false; + } + return true; +} +void +aOOTemplate::setDir(const QString &dir) +{ + templateDir = dir; +} + +QString +aOOTemplate::getDir() +{ + QString homeDir = QString("%1").arg(QDir::convertSeparators(QDir::homeDirPath ())); +#ifdef Q_OS_WIN32 + if(homeDir.right(1)!="\\") homeDir.append("\\"); +#else + + if(homeDir.right(1)!="/") homeDir.append("/"); +#endif + return QDir::convertSeparators(homeDir); +} + diff --git a/src/lib/report/aootemplate.h b/src/lib/report/aootemplate.h new file mode 100644 index 0000000..3a83ce9 --- /dev/null +++ b/src/lib/report/aootemplate.h @@ -0,0 +1,146 @@ +/**************************************************************************** +** $Id: aootemplate.h,v 1.1 2008/11/05 21:16:29 leader Exp $ +** +** Report metadata object header file of +** Ananas application library +** +** Created : 20050202 +** +** Copyright (C) 2003-2005 Grigory Panov , Yoshkar-Ola. +** +** This file is part of the Designer application of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.leaderit.ru/page=ananas or email sales@leaderit.ru +** See http://www.leaderit.ru/gpl/ for GPL licensing information. +** +** Contact org@leaderit.ru if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ +#ifndef AOOTEMPLATE_H +#define AOOTEMPLATE_H + +#include +#include +#include +#include +#include + +#define open_token "<:" +#define close_token ":>" +#define open_token_section "\\[:" +#define close_token_section ":\\]" +#define PARAM "param" + +#include "ananasglobal.h" +#include "itemplate.h" + +/** + * \en + * Class for work with pattern in OpenOffice format + * \_en + * \ru + * \brief Класс определяет интерфейс для работы с шаблонами в формате OpenOffice. Наследует iTemplate. + * + * Описание шаблона: \n + * Шаблон представляет собой обычный документ OpenOffice. + * Он предназначен для того, чтобы быстро создавать отчеты. + * Внешне шаблон отличается от того документа, который необходимо сгенерировать + * только наличием специальных тегов. + * Эти теги при генерации заменяются на конкретные значения. \n + * Предусмотрено два типа тегов: \n + * 1) Тег секции \n + * С помощью него можно размножать строки таблицы. + * Для этого надо просто записать его в любую ячейку строки. \n + * Формат тега [:имя тега:] \n + * В имени допустимы любые символы. \n + * При вызове exec() с параметром = имени этого тега к таблице будет добавлена еще + * одна строка. Если в этой строке есть простые теги, + * то произойдет замена тега на значение, заданное с помощью функции setValue() \n + * 2) Простой тег. \n + * С помощью него можно вставлять в документ обычный текст, дату, и т.п. \n + * формат тега <:имя тега:> \n + * При вызове exec() с параметром = имени этого тега, рядом допишется значение, + * предварительно заданное с помощью функции setValue() \n + * Функция setValue() задает значения для подстановки. + * Для прстых тегов надо задавать setValue("param",значение для подстановки); + * после чего надо выполнить exec(имя простого тега) \n + * Для тегов секции setValue(имя простого тега, значение для подстановки); + * после чего выполнить exec(имя секции); + * \_ru + */ +class ANANAS_EXPORT aOOTemplate : public iTemplate +{ +public: + aOOTemplate(); + virtual ~aOOTemplate(); + virtual bool open( const QString &fname ); + virtual void close(); + virtual void clear(); + virtual QString getValue( const QString &name ); + virtual void setValue( const QString &name, const QString &value ); + virtual QString exec( const QString &sname ); + virtual QString result(); + virtual bool save( const QString & fname ); + virtual void setDir( const QString &dirName ); + virtual QString getDir(); + virtual void cleanUpTags(); +protected: +/** + * \en + * directory name for unzip + * \_en + * \ru + * Имя директории для распаковки + * \_ru + */ + QString copyName; + protected: +/** + * \en + * directory template name + * \_en + * \ru + * Имя директории шаблонов + * \_ru + */ + QString templateDir; + + QMap values; + + void searchTags(QDomNode node, const QString &sname ); + virtual bool getNodeTags(QDomNode node, const QString &tagname, bool params ); + void insertRowValues(QDomNode node); + virtual void insertTagsValues(QDomNode node, const QString &tagName); + void clearTags(QDomNode node, bool section ); + void clearRow(QDomNode node); +/** + * \en + * Variable for store unpacking teplate content + * \_en + * \ru + * Переменная для хранения содержимого распакованного шаблона. + * \_ru + */ + QDomDocument docTpl; + +/** + * \en + * Variable for store unpacking teplate stales + * \_en + * \ru + * Переменная для хранения стилей (колонтитулы в т.ч.) распакованного шаблона. + * \_ru + */ + QDomDocument docStyle; +}; +#endif // AOOTEMPLATE_H diff --git a/src/lib/report/areport.cpp b/src/lib/report/areport.cpp new file mode 100644 index 0000000..9216c61 --- /dev/null +++ b/src/lib/report/areport.cpp @@ -0,0 +1,574 @@ +/**************************************************************************** +** $Id: areport.cpp,v 1.2 2008/11/08 20:16:36 leader Exp $ +** +** Report metadata object implementation file of +** Ananas application library +** +** Created : 20040701 +** +** Copyright (C) 2003-2004 Leader InfoTech. All rights reserved. +** Copyright (C) 2003-2006 Grigory Panov , Yoshkar-Ola. +** +** This file is part of the Designer application of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.leaderit.ru/page=ananas or email sales@leaderit.ru +** See http://www.leaderit.ru/gpl/ for GPL licensing information. +** +** Contact org@leaderit.ru if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +//Added by qt3to4: +#include +#include "acfg.h" +#include "aobject.h" +#include "adatabase.h" +#include "areport.h" +#include "acalctemplate.h" +#include "aservice.h" +#include "alog.h" +#include "stdlib.h" +/*! +* \en +* Constuct object +* \_en +* \ru +* Создает объект +* \_ru +*/ +aReportBrowser::aReportBrowser( QWidget *parent, const char *name, Qt::WFlags f ) +:Q3MainWindow( parent, name, f ) +{ + QAction *a; + + Q3ToolBar *t = new Q3ToolBar( this, "ReportTool" ); + a = new QAction( + //QPixmap::fromMimeSource("print.png"), + QPixmap(":/images/print.png"), + tr("Print"), + QKeySequence("Ctrl+P"), + t, + tr("Print report") + ); + a->addTo( t ); + connect( a, SIGNAL( activated() ), this, SLOT( print() ) ); + t->show(); + + textBrowser = new Q3TextBrowser( this, "textBrowser" ); + textBrowser->setTextFormat( Qt::RichText ); + textBrowser->setFocus(); +// textBrowser->showMaximized(); + setCentralWidget( textBrowser ); +// if ( layout() ) delete layout(); +// QGridLayout *l = new QGridLayout( this ); +// l->addWidget( textBrowser, 1, 0 ); + languageChange(); +} + + + +/*! +* \en +* Appends text to browser. +* \_en +* \ru +* Добавляет текст в браузер +* \_ru +* \param text - \en text to append \_en \ru текст для добавления \_ru +*/ +void +aReportBrowser::append( const QString &text ) +{ + textBrowser->append( text ); +} + + + +/*! +* \en +* Clears browser. +* \_en +* \ru +* Очищает браузер +* \_ru +*/ +void +aReportBrowser::clear() +{ + textBrowser->clear(); +} + + + +/*! +* \en +* Print browser content. +* \_en +* \ru +* Печатает содержимое браузера. +* \_ru +*/ +void +aReportBrowser::print() +{ + QPrinter printer; + QPainter p; + + if (!printer.setup()) return; + if ( p.begin( &printer ) ){ + Q3PaintDeviceMetrics metrics( p.device() ); + int dpiy = metrics.logicalDpiY(); + int margin = (int) ( (2/2.54)*dpiy ); // 2 cm margins + QRect body( margin, margin, metrics.width() - 2*margin, metrics.height() - 2*margin ); + Q3SimpleRichText richText( textBrowser->text(), + QFont(), + textBrowser->context(), + textBrowser->styleSheet(), + textBrowser->mimeSourceFactory(), + body.height() ); + richText.setWidth( &p, body.width() ); + QRect view( body ); + int page = 1; + do { + richText.draw( &p, body.left(), body.top(), view, colorGroup() ); + view.moveBy( 0, body.height() ); + p.translate( 0 , -body.height() ); + p.drawText( view.right() - p.fontMetrics().width( QString::number( page ) ), + view.bottom() + p.fontMetrics().ascent() + 5, QString::number( page ) ); + if ( view.top() >= richText.height() ) + break; + printer.newPage(); + page++; + } while (TRUE); + } +} + + + +/**! + * Sets the strings of the subwidgets using the current + * language. + */ +void aReportBrowser::languageChange() +{ +} + + + +/*! +* \en +* Constuct object +* \_en +* \ru +* Создает объект +* \param context - объект метаданных для инициализации. +* \param report_type - тип отчета. RT_text - для отчета в формате HTML, RT_office - для отчета в формате OpenOffice +* \param e - енжин. +* \_ru +*/ +aReport::aReport( aCfgItem context, RT_type report_type, aEngine * e ) +:aObject( context, 0, 0, "aReport") +{ + engine = e; + md = e->md; + browser = new aReportBrowser( e->ws ); + type = report_type; + if(report_type==RT_text) + { + tpl = new aTemplate(); + } + if(report_type == RT_office_writer) + { + tpl = new aOOTemplate(); + } + if(report_type==RT_office_calc) + { + tpl = new aCalcTemplate(); + } +} + + + +/*! +* \en +* Constuct object +* \_en +* \ru +* Создает объект +* \param name - имя объекта. +* \param report_type - тип отчета. RT_text - для отчета в формате HTML, RT_office - для отчета в формате OpenOffice +* \param e - енжин. +* \_ru +*/ +aReport::aReport(QString name, RT_type report_type, aEngine * e ) +:aObject( name, 0, 0, "aReport") +{ + engine = e; + md = e->md; + browser = new aReportBrowser( e->ws ); + type = report_type; + if(report_type==RT_text) + { + tpl = new aTemplate(); + } + if(report_type == RT_office_writer) + { + tpl = new aOOTemplate(); + } + if(report_type == RT_office_calc) + { + tpl = new aCalcTemplate(); + } +} + + + +/*! +* \en +* Destructor +* \_en +* \ru +* Деструктор +* \_ru +*/ +aReport::~aReport() +{ + if(tpl) + { + delete tpl; + tpl=0; + } +} + + + +/*! +* \en +* Init object. +* \_en +* \ru +* Инициализирует объект. Объект не содержит никаких таблиц в базе данных. +* \_ru +*/ +ERR_Code +aReport::initObject() +{ + ERR_Code err = aObject::initObject(); + if ( err ) return err; + return err_noerror; +} + + + +/*! +* \en +* Set template. +* \_en +* \ru +* Задает имя файла шаблона. Расширение указывать необходимо. +* \_ru +* \param name - \en template name \_en \ru имя шаблона \_ru +* \see path2workdir() +*/ +void +aReport::setTable( const QString &name ) +{ + tpl->setDir(path2workdir()); + tpl->open( name ); + tplName = name; +} + + + +/*! +* \en +* Sets tag value. +* \_en +* \ru +* Задает значение тега. +* \_ru +* \param name - \en tag name \_en \ru имя тега \_ru +* \param value - \en tag value \_en \ru значение тега \_ru +*/ +void +aReport::setValue( const QString &name, const QString &value ) +{ + tpl->setValue( name, value ); +} + + + +/*! +* \en +* Gets tag value. +* \_en +* \ru +* Возвращает значение тега. +* \_ru +* \param name - \en tag name \_en \ru имя тега \_ru +* \return \en tag value \_en \ru значение тега \_ru +*/ +QString +aReport::value( const QString &name ) +{ + return tpl->getValue( name ); +} + + + +/*! +* \en +* Clear browser content. +* \_en +* \ru +* Очищает содержимое браузра. Используется для текстово отчета. +* \_ru +*/ +void +aReport::clear() +{ + browser->clear(); +} + + + +/*! +* \en +* Update report value. +* \_en +* \ru +* Обновляет репорт на основе заданных перед этим функцией setValue() значений. +* \_ru +*/ +void +aReport::exec( const QString §ion ) +{ + tpl->exec( section ); +} + + + +/*! +* \en +* Shows report. +* \_en +* \ru +* Показывает отчет. +* \_ru +*/ +void +aReport::show() +{ + if(type==RT_text) + { + browser->textBrowser->setText( tpl->result() ); + browser->show(); + } + if(type==RT_office_writer || type==RT_office_calc) + { + QString fileName = getName4NewTemplate(); + tpl->cleanUpTags(); + tpl->save(fileName); + QString startCatalog = "/usr/bin"; + QString filter; + bool sofficeFound = false; + + bool ok; + QString oowriter = aService::readConfigVariable("OpenOfficeExecutable", &ok); + if(!ok || oowriter == "" ) + { +#ifdef Q_OS_WIN32 + aLog::print(aLog::Info,tr("aReport OpenOfficeExecutable not found in registery")); + startCatalog = QString("%1\\Program Files\\OpenOffice.org1.1.1\\program").arg(getenv("HOMEDRIVE")); + QFile soffice(startCatalog + "\\soffice.exe"); + if(!soffice.exists()) + { + startCatalog = QString("%1\\Program Files\\OpenOffice.org 2.0\\program").arg(getenv("HOMEDRIVE")); + soffice.setName(startCatalog + "\\soffice.exe"); + if(!soffice.exists()) + { + startCatalog = QString("%1\\Program Files").arg(getenv("HOMEDRIVE")); + } + else + { + aService::writeConfigVariable("OpenOfficeExecutable",startCatalog + "\\soffice.exe"); + aLog::print(aLog::Info,tr("aReport OpenOfficeExecutable found %1").arg(startCatalog + "\\soffice.exe")); + } + } + else + { + aService::writeConfigVariable("OpenOfficeExecutable",startCatalog + "\\soffice.exe"); + aLog::print(aLog::Info,tr("aReport OpenOfficeExecutable found %1").arg(startCatalog + "\\soffice.exe")); + } + filter = "Executable files (*.exe)"; +#else + aLog::print(aLog::Info,tr("aReport OpenOfficeExecutable not found in ~/.ananas/configrc")); + QFile soffice(startCatalog + "/ooffice"); + if(!soffice.exists()) + { + soffice.setName(startCatalog + "/ooffice2"); + if(soffice.exists()) + { + aService::writeConfigVariable("OpenOfficeExecutable",startCatalog + "/ooffice2"); + aLog::print(aLog::Info,tr("aReport OpenOfficeExecutable found %1").arg(startCatalog + "/ooffice2")); + } + } + else + { + aService::writeConfigVariable("OpenOfficeExecutable",startCatalog + "/ooffice"); + aLog::print(aLog::Info,tr("aReport OpenOfficeExecutable found %1").arg(startCatalog + "/ooffice")); + } +#endif + } + oowriter = aService::readConfigVariable("OpenOfficeExecutable", &ok); + if(!ok || oowriter == "" ) + { + + Q3FileDialog dlg(0,"select_file_dialog",true); + dlg.addFilter( filter ); + dlg.setMode(Q3FileDialog::ExistingFile); + dlg.setDir(QDir(startCatalog)); + dlg.setCaption("Для отображения отчета необходим OpenOffice. Укажите исполняемый файл OpenOffice"); + if(dlg.exec()==QDialog::Accepted) + { + oowriter = dlg.selectedFile(); + //printf("select %s", oowriter.ascii()); + Q3Process process( oowriter ); + process.addArgument( "-n" ); + process.addArgument( QDir::convertSeparators( fileName ) ); + if( !process.start() ) + { + QMessageBox::warning(0, tr("Warning"), tr("Unable to start OpenOffice (%1)").arg(oowriter), QMessageBox::Ok,QMessageBox::NoButton); +// printf("Unable to start OpenOffice Writer\n"); + } + else + { + aService::writeConfigVariable("OpenOfficeExecutable",oowriter); + aLog::print(aLog::Info,tr("aReport OpenOfficeExecutable set to %1").arg(oowriter)); + } + } + } + else + { + + Q3Process process( oowriter ); + process.addArgument( "-n" ); + process.addArgument( QDir::convertSeparators( fileName ) ); + if( !process.start() ) + { + QMessageBox::warning(0, tr("Warning"), tr("Unable to start OpenOffice (%1)").arg(oowriter), QMessageBox::Ok,QMessageBox::NoButton); +// printf("Unable to start OpenOffice Writer\n"); + } + else + { + aService::writeConfigVariable("OpenOfficeExecutable",oowriter); + aLog::print(aLog::Info,tr("aReport OpenOfficeExecutable set to %1").arg(oowriter)); + } + } + + //tpl->open( tplName ); + } +} + + + +/*! +* \en +* Return path to working dir. +* \_en +* \ru +* Возвращает путь к рабочей директории. +* \_ru +* \see setTable( const QString &name ) +*/ +QString +aReport::path2workdir() +{ + QString res; +#ifndef Q_OS_WIN32 + res = "/usr/share/ananas/"; +#else + res = ""; +#endif + if(md!=NULL) + { + res = md->rc.value("workdir"); + } + aLog::print(aLog::Debug, tr("aReport working dir = %1").arg(res)); + return res; +} + + + +/*! +* \en +* Close report. +* \_en +* \ru +* Закрывает отчет. Удаляет временные файлы. +* \_ru +*/ +void +aReport::close() +{ + tpl->close(); +} + + +/*! +* \en +* Gets name for new template. Need for OpenOffice v2. +* \_en +* \ru +* Получение имени для нового шаблона. Нужна из-за блокировок в OpenOffice v2. +* \_ru +*/ +QString +aReport::getName4NewTemplate() +{ + uint count=0; + QFile tmpf; + QString suff = ".odt"; + QString fname; + if(type==RT_office_calc) suff = ".ods"; + do + { + // tpl->getDir() должно заканчиваться на / + fname = QDir::convertSeparators(QString(tpl->getDir()+".ananas-report%1%2").arg(count).arg(suff)); + tmpf.setName(fname); + if(tmpf.exists()) + { + if(tmpf.remove()) break; + else ++count; + } + else + { + break; + } + }while(count<100); + + aLog::print(aLog::Debug, tr("aReport name for template = %1").arg(fname)); + return fname; +} diff --git a/src/lib/report/areport.h b/src/lib/report/areport.h new file mode 100644 index 0000000..5e59def --- /dev/null +++ b/src/lib/report/areport.h @@ -0,0 +1,121 @@ +/**************************************************************************** +** $Id: areport.h,v 1.1 2008/11/05 21:16:29 leader Exp $ +** +** Report metadata object header file of +** Ananas application library +** +** Created : 20031201 +** +** Copyright (C) 2003-2004 Leader InfoTech. All rights reserved. +** Copyright (C) 2003-2005 Grigory Panov , Yoshkar-Ola. +** +** This file is part of the Designer application of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.leaderit.ru/page=ananas or email sales@leaderit.ru +** See http://www.leaderit.ru/gpl/ for GPL licensing information. +** +** Contact org@leaderit.ru if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#ifndef AREPORT_H +#define AREPORT_H + +#include +#include +#include +#include "acfg.h" +#include "aobject.h" +#include "engine.h" +#include "atemplate.h" +#include "aootemplate.h" + +class aDatabase; + +/** + * \ru + * \brief Класс для показа отчета в формате HTML. Наследует QMainWindow. + * + * \see aTemplate aReport + * \_ru + */ +class ANANAS_EXPORT aReportBrowser :public Q3MainWindow +{ + Q_OBJECT +public: + QWorkspace *ws; + Q3TextBrowser *textBrowser; + aReportBrowser( QWidget *parent = 0, const char *name = 0, Qt::WFlags f = Qt::WDestructiveClose ); + void append( const QString &text ); + void clear(); +public slots: + void print(); + +protected slots: + virtual void languageChange(); +}; + +/** + * \ru + * \brief Определяет программный интерфейс для работы со всеми типами отчетов. + * Наследует aObject. + * + * Применяется для генерирования документов для печати в форматах OpenOffice *.odt,*ods и HTML. + * \see aTemplate aOOTemplate + * \_ru + */ + +class ANANAS_EXPORT aReport :public aObject +{ + Q_OBJECT +public: + +/*! + * \ru + * Перечисление типов возможных отчетов. + * \_ru + */ + enum RT_type { + RT_text/**отчет в формате HTML*/, + RT_office_writer/**отчет в формате OpenOffice Writer*/, + RT_office_calc/**отчет в формате OpenOffice Calc*/ + }; + + aEngine *engine; + iTemplate *tpl; + aReportBrowser *browser; + RT_type type; + + aReport( aCfgItem context, RT_type r_type = RT_text, aEngine * e = 0 ); + aReport( QString name, RT_type r_type = RT_text, aEngine * e = 0 ); + virtual ~aReport(); + virtual ERR_Code initObject(); + + QString path2workdir(); + +public slots: + void setTable( const QString &name ); + void setValue( const QString &name, const QString &value ); + QString value( const QString &name ); + void clear(); + void exec( const QString §ion ); + void close(); + void show(); +protected: + QString getName4NewTemplate(); +private: + QString tplName; + +}; + +#endif// AREPORT_H diff --git a/src/lib/report/atemplate.cpp b/src/lib/report/atemplate.cpp new file mode 100644 index 0000000..8637dd3 --- /dev/null +++ b/src/lib/report/atemplate.cpp @@ -0,0 +1,208 @@ +/**************************************************************************** +** $Id: atemplate.cpp,v 1.2 2008/11/08 20:16:36 leader Exp $ +** +** Report metadata object header file of +** Ananas application library +** +** Created : 20031201 +** +** Copyright (C) 2003-2004 Leader InfoTech. All rights reserved. +** Copyright (C) 2003-2005 Grigory Panov, Yoshkar-Ola. +** +** This file is part of the Designer application of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.leaderit.ru/page=ananas or email sales@leaderit.ru +** See http://www.leaderit.ru/gpl/ for GPL licensing information. +** +** Contact org@leaderit.ru if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#include +#include +#include +#include +#include +#include + +#include "atemplate.h" +#include "alog.h" + +aTemplate::aTemplate() + : iTemplate() +{ + clear(); +} + + + +aTemplate::~aTemplate() +{ +} + + + +bool +aTemplate::open( const QString &fname ) +{ + QFile file( QDir::convertSeparators(QDir::currentDirPath()+"/"+templateDir+"/"+fname) ); + if ( file.open( QIODevice::ReadOnly ) ) + { + QTextStream stream( &file ); + tpl = stream.read(); + file.close(); + return true; + } + else + { + return false; + } +} + + + +void +aTemplate::close() +{ + freeValues(); +} + + + +QString +aTemplate::getValue( const QString &name ) +{ + QString * pStr=values.find( name ); + return pStr==0?(QString::null):*pStr; +} + + + +void +aTemplate::setValue( const QString &name, const QString &value ) +{ + values.remove( name ); + if ( !value.isEmpty() ) values.insert( name, new QString( value ) ); +} + + + +void +aTemplate::freeValues() +{ + values.clear(); +} + + +QString +aTemplate::exec( const QString &sname ) +{ + int c = 0, c1 = 0, sec_start = 0, sec_end = 0, sec_len = 0, sfound = 0, l; + QString token, tname, tparam, sec_buf = "", v; + + if ( tpl.isEmpty() ) return ""; + + while ( !sfound ) { + sec_len = 0; + c = tpl.find( token_open, c ); + if ( c >= 0 ) { + c += strlen( token_open ); + c1 = tpl.find( token_close, c ); + if ( c1 >= 0 ) { + l = c1 - c; + token = tpl.mid( c, l ); + tname = token.section( " ", 0, 0 ); + tparam = token.section( " ", 1, 1 ); + if ( tname == "section" && tparam == sname ) { + sec_end = tpl.find( QString(token_open"endsection"token_close), c1 ); + if ( sec_end > 0 ) { + sfound = 1; + sec_start = c1 + QString( token_close ).length(); + sec_len = sec_end - sec_start; + } else break; + } + } else break; + } else break; + } + + if ( sfound && sec_len ) { + c = sec_start; + while ( c < sec_end ) { + c1 = tpl.find( token_open, c ); + l = c1 - c; + if ( l ) sec_buf.append( tpl.mid( c, l ) ); + if ( c1 < sec_end ) { + c = c1 + QString( token_open ).length(); + c1 = tpl.find( token_close, c ); + if ( c1 ) { + l = c1 - c; + token = tpl.mid( c, l ); + tname = token.section( " ", 0, 0 ); + tparam = token.section( " ", 1, 1 ); + c1 += QString( token_close ).length(); + v = getValue( tname ); + if ( !v.isEmpty() ) sec_buf.append( v ); + } else break; + } + c = c1; + } + } + buf.append( sec_buf ); +// printf("%s",( const char *) sec_buf.local8Bit() ); + return sec_buf; +} + + + +bool +aTemplate::save( const QString & fname) +{ + QFile file( QDir::convertSeparators(QDir::currentDirPath()+"/"+templateDir+"/"+fname) ); + if ( file.open( QIODevice::WriteOnly ) ) + { + QTextStream stream( &file ); + stream << result(); + file.close(); + aLog::print(aLog::Info, tr("aTemplate save file %1").arg(file.name())); + return true; + } + else + { + aLog::print(aLog::Error, tr("aTemplate save file %1").arg(file.name())); + return false; + } +} + + + +void +aTemplate::cleanUpTags() +{ +} + + + +void +aTemplate::setDir(const QString &dir) +{ + templateDir = dir; +} + + + +QString +aTemplate::getDir() +{ + return templateDir; +} + diff --git a/src/lib/report/atemplate.h b/src/lib/report/atemplate.h new file mode 100644 index 0000000..275491e --- /dev/null +++ b/src/lib/report/atemplate.h @@ -0,0 +1,134 @@ +/**************************************************************************** +** $Id: atemplate.h,v 1.1 2008/11/05 21:16:29 leader Exp $ +** +** Report metadata object header file of +** Ananas application library +** +** Created : 20031201 +** +** Copyright (C) 2003-2004 Leader InfoTech. All rights reserved. +** Copyright (C) 2003-2005 Grigory Panov, Yoshkar-Ola. +** +** This file is part of the Designer application of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.leaderit.ru/page=ananas or email sales@leaderit.ru +** See http://www.leaderit.ru/gpl/ for GPL licensing information. +** +** Contact org@leaderit.ru if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#ifndef ATEMPLATE_H +#define ATEMPLATE_H + +#include "ananasglobal.h" +#include "itemplate.h" + +#define token_open "<#" +#define token_close "#>" + +#include +#include +#include + +/** + * \en + * Class for work with pattern in HTML format + * \_en + * \ru + * \brief Класс для работы с шаблонами в HTML формате. + * Наследует iTemplate. + * + * Приведенный пример показывает создание таблицы размеров 10х10. + * \code + * function printreport() + * { + * p = new Report("Report1"); + * p.setTable("report.tpl"); + * p.setValue("title","Заголовок таблицы :"+Value("eHeader") + Value("fNDS")); + * p.exec("main"); + * for ( i = 1; i<10; i++) + * { + * p.setValue("value", String(i) ); + * p.exec("trow"); + * for ( j=1; j<10; j++) + * { + * p.setValue("value", String(i)+":"+String(j) ); + * p.exec("col"); + * } + * p.exec("endrow"); + * } + * p.exec("endmain"); + * p.show(); + * delete p; + * } + * \endcode + * Шаблон: + * \code +<#section main#> + +
+Ananas HTTP Server +
+ +<#title#> + +<#endsection#> + +<#section endmain#> +
+ +<#endsection#> + +<#section trow#><#value#>)<#endsection#> + +<#section endrow#> +<#endsection#> + +<#section col#><#value#><#endsection#> + * \endcode + * \_ru + */ +class ANANAS_EXPORT aTemplate : public iTemplate +{ + Q_OBJECT +public: + + aTemplate(); + virtual ~aTemplate(); + + bool open( const QString &fname ); + void close(); + void clear(){ buf="";}; + + QString getValue( const QString &name ); + void setValue( const QString &name, const QString &value ); + QString exec( const QString &sname ); + QString result(){ return buf;}; + bool save( const QString & fname ); + void cleanUpTags(); + virtual void setDir(const QString &dir); + virtual QString getDir(); + +protected: + QString templateDir; + +private: + QString buf; + QString tpl; + Q3Dict values; + + void freeValues(); +}; + +#endif //ATEMPLATE_H diff --git a/src/lib/report/itemplate.cpp b/src/lib/report/itemplate.cpp new file mode 100644 index 0000000..d40db4d --- /dev/null +++ b/src/lib/report/itemplate.cpp @@ -0,0 +1,108 @@ +/**************************************************************************** +** $Id: itemplate.cpp,v 1.1 2008/11/05 21:16:29 leader Exp $ +** +** Report metadata object header file of +** Ananas application library +** +** Created : 20031201 +** +** Copyright (C) 2003-2004 Leader InfoTech. All rights reserved. +** Copyright (C) 2003-2005 Grigory Panov, Yoshkar-Ola. +** +** This file is part of the Designer application of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.leaderit.ru/page=ananas or email sales@leaderit.ru +** See http://www.leaderit.ru/gpl/ for GPL licensing information. +** +** Contact org@leaderit.ru if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +//#include +//#include +//#include +//#include + +#include "itemplate.h" + + +iTemplate::iTemplate() + : QObject() +{ +} + +iTemplate::~iTemplate() +{ +} + +bool +iTemplate::open( const QString &) +{ + return true; +} + +void +iTemplate::close() +{ +} + +QString +iTemplate::getValue( const QString & ) +{ + return ""; +} + + +void +iTemplate::setValue( const QString &, const QString & ) +{ +} + + +bool +iTemplate::save( const QString & ) +{ + return true; +} + + +QString +iTemplate::exec( const QString & ) +{ + return ""; +} + +void +iTemplate::clear() +{ +} + +QString +iTemplate::result() +{ + return ""; +} +void +iTemplate::cleanUpTags() +{ +} +void +iTemplate::setDir(const QString &) +{ +} + +QString +iTemplate::getDir() +{ + return ""; +} diff --git a/src/lib/report/itemplate.h b/src/lib/report/itemplate.h new file mode 100644 index 0000000..a334087 --- /dev/null +++ b/src/lib/report/itemplate.h @@ -0,0 +1,184 @@ +/**************************************************************************** +** $Id: itemplate.h,v 1.1 2008/11/05 21:16:29 leader Exp $ +** +** Report metadata object header file of +** Ananas application library +** +** Created : 20031201 +** +** Copyright (C) 2003-2004 Leader InfoTech. All rights reserved. +** Copyright (C) 2003-2005 Grigory Panov, Yoshkar-Ola. +** +** This file is part of the Designer application of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.leaderit.ru/page=ananas or email sales@leaderit.ru +** See http://www.leaderit.ru/gpl/ for GPL licensing information. +** +** Contact org@leaderit.ru if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#ifndef ITEMPLATE_H +#define ITEMPLATE_H + +#include "ananasglobal.h" + +#include +//#include +//#include + +/** + * \~english + * Interface for work with report + * \~russian + * \brief Интерфейс для работы с отчетами. Наследует QObject. + * + * Классы, генерирующие отчеты, должны использовать этот интерфейс. + * Содержит чистые виртуальные функции, не допускается создание объектов этого класса напрямую. + * Пример: + * \code + * iTemplate *tpl = new aTemplate(); // aTemplate должен реализовывать интерфейс iTemplate + * tpl->open("test.tpl"); + * tpl->close(); + * delete tpl; + * \endcode + * \~ + */ +class ANANAS_EXPORT iTemplate : public QObject +{ + Q_OBJECT +public: +/** + * \en + * Constructor + * \_en + * \ru + * Конструктор. + * \_ru + */ + iTemplate(); +/** + * \en + * Destructor + * \_en + * \ru + * Деструктор + * \_ru + */ + virtual ~iTemplate(); + +/** + * \en + * Opens pattern + * \_en + * \ru + * Открывает шаблон. + * \_ru + */ + virtual bool open( const QString &fname )=0; +/** + * \en + * Closes pattern. + * \_en + * \ru + * Закрывает шаблон. + * \_ru + */ + virtual void close(); +/** + * \en + * Clears internal variable. + * \_en + * \ru + * Обнуляет внутренние переменные. + * \_ru + */ + virtual void clear(); +/** + * \en + * Get value of parameter `name' + * \_en + * \ru + * Возвращает значение параметра по его имени. + * \_ru + */ + virtual QString getValue( const QString &name ); +/** + * \en + * Set value of parameter `name' + * \_en + * \ru + * Устанавливает значение параметра по его имени. + * \_ru + */ + virtual void setValue( const QString &name, const QString &value ); +/** + * \en + * Replaces tads to values + * \_en + * \ru + * Выполняет подстановку значения параметра в шаблоне. + * Может вызываться несколько раз. + * \_ru + */ + virtual QString exec( const QString &sname ); +/** + * \en + * Returns document. + * \_en + * \ru + * Возвращает результат, т.е. шаблон в текстовом виде. Включена в интерфейс временно. + * \_ru + */ + virtual QString result(); +/** + * \en + * Saves document to file + * \_en + * \ru + * Сохраняет документ в файл с заданным именем. + * \_ru + */ + virtual bool save( const QString & fname ); +/** + * \en + * Clears all tags + * \_en + * \ru + * Очищает все теги + * \_ru + */ + + virtual void cleanUpTags(); +/** + * \en + * Sets working directory + * \_en + * \ru + * Устанавливает рабочую директорию + * \_ru + */ + virtual void setDir(const QString &dir); + + /** + * \en + * Gets working directory + * \_en + * \ru + * Возвращает рабочую директорию + * \_ru + */ + virtual QString getDir(); +}; + +#endif //ITEMPLATE_H diff --git a/src/lib/report/report.pri b/src/lib/report/report.pri new file mode 100644 index 0000000..9fc0be5 --- /dev/null +++ b/src/lib/report/report.pri @@ -0,0 +1,13 @@ +HEADERS += \ + report/acalctemplate.h \ + report/aootemplate.h \ + report/areport.h \ + report/atemplate.h \ + report/itemplate.h + +SOURCES += \ + report/acalctemplate.cpp \ + report/aootemplate.cpp \ + report/areport.cpp \ + report/atemplate.cpp \ + report/itemplate.cpp diff --git a/src/lib/sys/aapplication.cpp b/src/lib/sys/aapplication.cpp new file mode 100644 index 0000000..2e064c2 --- /dev/null +++ b/src/lib/sys/aapplication.cpp @@ -0,0 +1,46 @@ +/**************************************************************************** +** $Id: aapplication.cpp,v 1.1 2008/11/09 21:08:09 leader Exp $ +** +** Code file of the Ananas Library of Ananas +** Designer and Engine applications +** +** Created : 20031201 +** +** Copyright (C) 2003-2004 Leader InfoTech. All rights reserved. +** +** This file is part of the Library of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.leaderit.ru/page=ananas or email sales@leaderit.ru +** See http://www.leaderit.ru/gpl/ for GPL licensing information. +** +** Contact org@leaderit.ru if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#include "aapplication.h" +#include "dselectdb.h" +#include "dlogin.h" + + +AApplication::AApplication( int & argc, char ** argv, AApplicationType aat ) + :QApplication( argc, argv, true ) +{ + v_aat = aat; +} + +int +AApplication::applicationType() +{ + return v_aat; +} + diff --git a/src/lib/sys/aapplication.h b/src/lib/sys/aapplication.h new file mode 100644 index 0000000..65a533f --- /dev/null +++ b/src/lib/sys/aapplication.h @@ -0,0 +1,55 @@ +/**************************************************************************** +** $Id: aapplication.h,v 1.2 2008/11/21 20:58:12 leader Exp $ +** +** Header file of the Ananas Library of Ananas +** Designer and Engine applications +** +** Created : 20031201 +** +** Copyright (C) 2003-2004 Leader InfoTech. All rights reserved. +** +** This file is part of the Library of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.leaderit.ru/page=ananas or email sales@leaderit.ru +** See http://www.leaderit.ru/gpl/ for GPL licensing information. +** +** Contact org@leaderit.ru if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#ifndef AAPPLICATION_H +#define AAPPLICATION_H + +#include "ananasglobal.h" +#include + +class ANANAS_EXPORT AApplication : public QApplication +{ +Q_OBJECT +public: + + enum AApplicationType { + Unknown, + Ananas, + Designer, + Administrator + }; + + AApplication( int & argc, char ** argv, AApplicationType aat = Unknown ); + int applicationType(); + +private: + int v_aat; +}; + +#endif diff --git a/src/lib/sys/adatabase.cpp b/src/lib/sys/adatabase.cpp new file mode 100644 index 0000000..a0a91e3 --- /dev/null +++ b/src/lib/sys/adatabase.cpp @@ -0,0 +1,1668 @@ +/**************************************************************************** +** $Id: adatabase.cpp,v 1.6 2008/12/10 21:04:03 leader Exp $ +** +** Database abstaraction layer +** of Ananas Project +** +** Created : 20031201 +** +** Copyright (C) 2003-2004 Leader InfoTech. All rights reserved. +** Copyright (C) 2003-2005 Grigory Panov , Yoshkar-Ola +** +** This file is part of the Library of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.leaderit.ru/page=ananas or email sales@leaderit.ru +** See http://www.leaderit.ru/gpl/ for GPL licensing information. +** +** Contact org@leaderit.ru if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +/* +*/ +/* +for mysql server set variable in /var/lib/mysql/my.cnf +default-character-set=utf8 + +*/ +#include +#include +#include +#include +#include +#include +#include +//Added by qt3to4: +#include +#include +#include +#include +#include + +#include "alog.h" + +#include "asqltable.h" +#include "aapplication.h" + +#include "adatabase.h" + + +QStringList dd; + +static aDatabase aDatabase_default; + +/*! + * + */ +QString +qds_field ( const QString fname, const QString &tdef, const QString &descr = "" ) +{ + int n1, n2; + bool notnull, serial; + char t=' '; + QString st, dt="F="+fname+"|"+descr+"|"; + + if ( tdef.isEmpty() ) return ""; + n1=0; n2=0; + st = tdef.section ( " ", 0, 0 ).lower(); + n1 = tdef.section ( " ", 1, 1 ).toInt(); + n2 = tdef.section ( " ", 2, 2 ).toInt(); + if ( !st.isEmpty() ) t = ( ( const char * ) st ) [0]; + serial = ( st.mid ( 1 ).contains ( 's' ) > 0 ); + notnull = ( st.mid ( 1 ).contains ( 'n' ) > 0 ); +// if ( serial && t=='l') t='i'; + switch ( t ) + { + case 'i': + dt.append ( "I|0|0|" ); + break; + case 'l': + dt.append ( "L|0|0|" ); + break; + case 'c': + dt.append ( QString ( "S|%1|0|" ).arg ( n1 ) ); + break; + case 'n': + dt.append ( QString ( "N|%1|%2|" ).arg ( n1 ).arg ( n2 ) ); + break; + case 'd': + dt.append ( "D|0|0|" ); + break; + case 'o': + dt.append ( "L|0|0|" ); + break; + case 'b': + dt.append ( "C|1|0|" ); + break; + default: + dt.append ( "I|0|0|" ); + break; + } + if ( !serial && notnull ) dt.append ( "N" ); + if ( serial ) dt.append ( "PS" ); + return dt; +} + + + +void +qds_fields ( aCfg &cfg, aCfgItem context ) +{ + + int j, ifld; + QString t, flddef=""; + aCfgItem of, item; + int id, n=0; + aCfgItem dim_field; + + /* + if(cfg.objClass(context) == md_field && cfg.objClass(cfg.parent(context))== md_dimensions) + { + dim_field = context; + t = cfg.attr( dim_field, mda_type ); + if ( !t.isEmpty() ) + { + if(t[0]!=' ') + { + flddef.append( QString("uf%1 %2,").arg(cfg.id(dim_field)).arg(t) ); + } + } + } + */ + ifld = cfg.count ( context, md_field ); + for ( j = 0; j < ifld; j++ ) + { + item = cfg.find ( context, md_field, j ); + id = cfg.id ( item ); + if ( id ) + { + t = cfg.attr ( item, mda_type ); + if ( !t.isEmpty() ) + { + if ( t[0]!=' ' ) + { + dd<driverName(); + if ( name == "QMYSQL" ) name = "QMYSQL"; + return name; +} + + +/*! + * \~english + * Return text feature for dynamic SQL by feature name. + * \~russian + * Возвращает код реализации какой либо осбенности сервера БД по ее ключу. + * \~ + * \return \~english Code for dynamic SQL creation \~russian Код для формирования динамического SQL \~ + */ +QString +aDatabase::feature(const QString& featureName) +{ + QString res = QString::null; + if(driverName() == "QMYSQL") + { + res = featuresMySQL[featureName]; + } + if(driverName() == "QSQLITE") + { + res = featuresSQLite[featureName]; + } + if(driverName() == "QPSQL7") + { + res = featuresPostgreSQL[featureName]; + } + return res; +} + +/*! + * \~english + * This is overloaded method, provided for convenience. + * \~russian + * Перегружет метод init( aCfgRc *rc, const QString &dbname ) + * \~ + * \see init( aCfgRc *rc, const QString &dbname ) + * \param rcname (in) - \~english rc file name. \~russian имя файла ресурса \~ + * \param dbname (in) - \~english parameter to pass trough. \~russian имя базы данных \~ + * \return \~english true, if no error \~russian true, если ошибок не было \~ + */ +bool +aDatabase::init( const QString &rcname, const QString &dbname ) +{ + if ( rcname.isEmpty() ) return false; + if ( cfg.readrc( rcname ) ) return false; + return init( &cfg.rc, dbname ); +} + +/** + * \en + * \brief Creates database on SQL server. + * + * Uses rc file parameters values and makes connection to database server. + * Then creates database with name obtained from rc file. + * \param rc (in) - rc object reference. + * \param dbname (in) - unused now. + * \return true, if no error + * \_en \ru + * \brief Открывает соединение с базой данных на SQL сервере или создает базу данных. + * + * Если БД не удалось открыть, метод пытается создать базу данных на SQL сервере, + * используя переданные параметры соединения с SQL сервером. При этом создается пустая база данных + * без таблиц и других элементов. + * \param rc (in) - ссылка на инициализированный объект, + * хранящий данные файла ресурсов, необходимые для установления соединения. Проще говоря, объект + * с параметрами соединения. + * \param dbname (in) - не используется + * \return frue, если не было ошибок + * \_ru + * \see init( const QString &rcname, const QString &dbname ) + */ +bool +aDatabase::init ( aCfgRc *rc, const QString &dbname ) +{ + fillFeatures(); + if ( !rc ) return false; + if ( !prepareDatabaseConnect ( rc ) ) return false; + + qds_dd ( cfg ); + qds->setDataDictionary ( dd ); + if ( qds->open() ) + { + aLog::print ( aLog::Info,tr ( "aDatabase open connection to %1" ).arg ( rc->value ( "dbname" ) ) ); + } + else + { + cfg_message ( 3, ( const char * ) tr ( "Can't open database connection\n" ).utf8() ); + aLog::print ( aLog::Error,tr ( "aDatabase open connection to %1" ).arg ( rc->value ( "dbname" ) ) ); + }; + QSqlQuery q = db()->exec ( QString ( "SELECT * FROM %1" ).arg ( qds->tableName ( "netusers" ) ) ); + if ( !q.first() ) + { + db()->exec ( QString ( "INSERT INTO %1 (users,updates) VALUES (0,0)" ).arg ( qds->tableName ( "netusers" ) ) ); + } + v_updatesCount = updatesCount(); + v_timerId = startTimer ( 5000 ); + return true; +} + +/** + * \ru + * \brief Инициализирует драйвер sql соединения. + * + * Для инициализации используются параметры из файла ресурсов бизнес схемы. + * \param dbParams - объект хранящий данные файла ресурсов. + * \return true, если драйвер успешно инициализирован. false, если возникла ошибка. + * \_ru + */ +bool +aDatabase::prepareDatabaseConnect ( aCfgRc* dbParams ) +{ + QString driver = "UNKNOWN"; + QString dbtype; + + dbtype = dbParams->value ( "dbtype" ); + done(); + + /**/ + QString qds_dbtype = "QSQLITE"; + if ( dbtype=="internal" ) qds_dbtype = "QSQLITE"; + if ( dbtype=="mysql" ) qds_dbtype = "QMYSQL"; + if ( dbtype=="postgres" ) qds_dbtype = "QPOSTGRESQL"; + + if ( qds==0 ) qds = new QDataSchema ( qds_dbtype, "ANANAS" ); + //qds->setNameSpace("qds_"); + + qds->db()->setDatabaseName ( dbParams->value ( "dbname" ) ); + qds->db()->setUserName ( dbParams->value ( "dbuser" ) ); + qds->db()->setPassword ( dbParams->value ( "dbpass" ) ); + qds->db()->setHostName ( dbParams->value ( "dbhost","localhost" ) ); + qds->db()->setPort ( dbParams->value ( "dbport","0" ).toInt() ); + + dataBase = qds->db(); + return true; +} + + + +void +aDatabase::fillFeatures() +{ + featuresMySQL["autoincrement"] = "select last_insert_id()"; + featuresMySQL["encoding"] = "character set utf8"; + featuresMySQL["systemDatabase"] = "mysql"; + featuresPostgreSQL["autoincrement"] = "select currval('uniques_id_seq')"; + featuresPostgreSQL["encoding"] = "with encoding='UTF-8'"; + featuresPostgreSQL["systemDatabase"] = "template1"; + featuresSQLite["autoincrement"] = "select last_insert_rowid()"; + featuresSQLite["encoding"] = ""; +} + +/*! + * \~english + * Closes database connection. + * \~russian + * Закрывает соединение с базой данных и освобождает все занятые ресурсы. + * \~ + */ +void +aDatabase::done() +{ + killTimer( v_timerId ); +// if ( db() ) +// { +// db()->close(); +// } + if ( qds ) + { + delete qds; + qds = 0; + } +} + + + +/** + * \en + * \brief Returns database connection. + * + * \param dbname (in) - database connection name. Default value used if dbname is empty. + * \return database connection. + * \_en \ru + * \brief Возвращает ссылку на соединение с базой данных. + * + * \param dbname (in) - имя базы данных + * \return соединение с базой данных. Возвращаемый объект удалять не следует. + */ +QSqlDatabase* +aDatabase::db ( const QString &dbname ) +{ + if ( qds ) return qds->db(); + return 0; +} + + +/*! + * \~english + * Check database structure. + * \~russian + * проверяет структуру базы данных. + * \~ + * \return \~english true, if structure is valid. \~russian true, если база данных корректна \~ + */ +bool +aDatabase::checkStructure() +{ + if ( qds ) + { + if ( qds->verifyStructure() ) + { + return false; + } + else return true; + } + return false; +} + + + +/*! + * \~english + * Helper method. + * \~russian + * Вспомогательный метод. Создает новую базу данных. + * \~ + * \see createdb() + */ +bool +aDatabase::create() +{ + return createdb ( false ); +} + +bool +aDatabase::drop ( const QString& dbname ) +{ + + QString query = QString ( "drop database %1" ).arg ( dbname ); + if ( !dataBase ) return true; + if ( dataBase->exec ( query ).lastError().type() ==QSqlError::None ) + { + aLog::print ( aLog::Error,tr ( "aDatabase drop database %1" ).arg ( dbname ) ); + } + query = QString ( "create database %1 %2" ).arg ( dbname ).arg ( feature ( "encoding" ) ); + //if ( driverName() == "QPSQL7" ) query.append( " with encoding='UTF-8'" ); +//#ifdef MYSQL_UTF8 + //if ( driverName() == "QMYSQL3" ) query.append( " character set utf8" ); +//#endif + //printf("query = %s\n",query.ascii()); + QSqlQuery q = db()->exec ( query ); + if ( db()->lastError().type() !=QSqlError::None ) + { + reportError ( db()->lastError(),query ); + } + dataBase->setDatabaseName ( dbname ); + if ( !dataBase->open() ) + { + cfg_message ( 3, ( const char * ) tr ( "Can't open database connection\n" ).utf8() ); + aLog::print ( aLog::Error,tr ( "aDatabase open connection to %1" ).arg ( dbname ) ); + return false; + } + else + { + aLog::print ( aLog::Info,tr ( "aDatabase open connection to %1" ).arg ( dbname ) ); + + } + return false; +} + + +/*! + * \~english + * Helper method. + * \~russian + * Вспомогательный метод. Обновляет структуру базы данных. + * \~ + * \see createdb() + */ +bool +aDatabase::update() +{ + return createdb ( true ); +} + + + +/*! + * Creates aDataTable object for browsing and editing sql table in current database. + * \param name (in) - sql table name. + * \return newly created object. + */ +aDataTable * +aDatabase::table ( const QString & name ) +{ + aDataTable *t = 0; + + if ( tableExists ( name ) ) + { + t = new aDataTable ( qds->tableName ( name ), this ); + } + else + { + t = new aDataTable ( QString::null, this ); + } + return t; +} + + +/*! + * \~english + * Helper metod. Returns sql table name for metadata object. + * \~russian + * Вспомогательный метод. Возвращает имя sql таблицы для объекта метаданных. + * \~ + * \see tableDbName( aCfg &md, aCfgItem context, long * tid ) + * \param md (in) - \~english metadata tree object. \~russian дерево метаданных. \~ + * \param context (in) - \~english node of metadata tree which represents metadata Class. \~russian объект метаданных \~ + * \return \~english sql table name. \~russian имя таблицы в базе данных \~ + */ +QString +aDatabase::tableDbName ( aCfg &md, aCfgItem context ) +{ + long dummy; + return tableDbName ( md,context,&dummy ); +} + + +/*! +* \~english +* Returns sql table name for metadata object. +* \~russian +* Возвращает имя sql таблицы для объекта метаданных. +* \~ +* \see tableDbName( aCfg &md, aCfgItem context, long * tid ) +* \param md (in) - \~english metadata tree object. \~russian дерево метаданных. \~ +* \param context (in) - \~english node of metadata tree which represents metadata Class. \~russian объект метаданных \~ +* \param tid (out) - \~english id of metadata Class. \~russian идентификатор объекта метаданных, которому принадлежит таблица \~ +* \return \~english sql table name. \~russian имя таблицы в базе данных \~ +*/ +QString +aDatabase::tableDbName ( aCfg &md, aCfgItem context, long * tid ) +{ + aCfgItem parent = context; + QString oclass, tname = ""; + long id, idp=0, temp=0; + if ( context.isNull() ) return ""; + oclass = md.objClass ( context ); + id = md.id ( context ); + while ( idp == 0 && ! parent.isNull() ) + { + parent = md.parent ( parent ); + idp = md.id ( parent ); + } + if ( oclass == md_element ) + { + tname = QString ( db_catalog_element ).arg ( idp ); + temp = idp; + } + if ( oclass == md_group ) + { + tname = QString ( db_catalog_group ).arg ( idp ); + temp = idp; + } + if ( oclass == md_header ) + { + tname = QString ( db_document_header ).arg ( idp ); + temp = idp; + } + if ( oclass == md_iregister ) + { + tname = QString ( db_iregister ).arg ( id ); + temp = id; + } + if ( oclass == md_aregister ) + { + tname = QString ( db_aregister ).arg ( id ); + temp = id; + } + if ( oclass == md_table ) + { + if ( md.objClass ( parent ) == md_document ) + { + tname = QString ( db_document_table ).arg ( idp ).arg ( id ); + temp = id; + } + } + if ( oclass == md_resources ) + { + if ( md.objClass ( parent ) == md_aregister ) + { + tname = QString ( db_areg_remainder ).arg ( idp ); + temp = idp; + } + } + if ( oclass == md_field ) + { + if ( md.objClass ( parent ) == md_aregister ) + { + tname = QString ( db_areg_dim ).arg ( idp ).arg ( id ); + temp = idp; + } + } + *tid = temp; +// printf("tname = %s\n",tname.ascii()); + return tname; +} + + + +/*! + * \~english + * Generates new unique id for system object. + * \~russian + * Генерирует новый уникальный номер. Эти номера являются невосполнимым ресурсом системы. + * \~ + * \param otype (in) - \~english object type (e.g. document, catalog, journal etc.) \~russian тип объекта \~ + * \return \~english newly generated unique id. \~russian новый сгенерированный номер \~ + */ +Q_ULLONG +aDatabase::uid ( int otype ) +{ + Q_ULLONG uid = 0; + QString query; + QString drv = driverName(); +// printf("driver name =%s\n",drv.ascii()); + query.sprintf ( "insert into uniques (otype) values (%d)", otype ); + QSqlQuery q = db()->exec ( query ); + if ( db()->lastError().type() !=QSqlError::None ) + { + reportError ( db()->lastError(),query ); + } + query = feature ( "autoincrement" ); + q = db()->exec ( query ); + if ( db()->lastError().type() !=QSqlError::None ) + { + reportError ( db()->lastError(),query ); + } + if ( q.first() ) + { + uid = q.value ( 0 ).toULongLong(); + } + else + { + aLog::print ( aLog::Error,tr ( "aDatabase generate new unique number for object type %1" ).arg ( otype ) ); + } +// printf("uid=%llu, otype=%d\n",uid,otype); + aLog::print ( aLog::Debug,tr ( "aDatabase generate new unique number %1 for objecttype %2" ).arg ( uid ).arg ( otype ) ); + return uid; +} + + + +/*! + * \~english + * Returns type of object identified by its uid. + * \~russian + * Возвращает тип объекта по его идентификатору. + * \~ + * \see uid( int otype ) + * \param uid (in) - \~english object's uid. \~russian уникальный идентификатор объекта \~ + * \return \~english object's type \~russian тип объекта \~ + */ +int +aDatabase::uidType ( Q_ULLONG uid ) +{ + QSqlQuery q = db()->exec ( QString ( "SELECT otype FROM uniques WHERE id=%1" ).arg ( uid ) ); + if ( q.first() ) + return q.value ( 0 ).toInt(); + else + aLog::print ( aLog::Error,tr ( "aDatabase get object type for unique id=%1" ).arg ( uid ) ); + return 0; +} + + + +/*! + * \~english + * Checks table existence. + * \~russian + * Проверяет, существует ли таблица в базе данных. + * \~ + * \param name (in) - \~english table name to check for. \~russian имя проверяемой таблицы \~ + * \return \~english true, if table exists in current database \~russian true, если таблица существует \~ + */ +bool +aDatabase::tableExists ( const QString & name ) +{ + return qds->tableExists ( qds->tableName ( name ) ); +} + + +/*! + * + */ +bool +aDatabase::createdb ( bool update ) +{ + bool rc = false; + + if ( qds ) + { + qds_dd ( cfg ); + qds->setDataDictionary ( dd ); + if ( qds->verifyStructure() ) + { + // need to update + printf ( "verify log:\n%s\n", ( const char * ) qds->verifyLog().join ( "\n" ) ); + printf ( "update structure query:\n%s\n", ( const char * ) qds->updateStructureQuery().join ( "\n" ) ); + if ( qds->updateStructure() !=0 ) + { + rc = false; + cfg_message ( 2, ( const char * ) tr ( "Data base update error\n" ) ); + } + else + { + rc = true; + cfg_message ( 0, ( const char * ) tr ( "Data base update successfull\n" ) ); + } + } + } + return rc; +} + + + +/*! + * \~english + * Sets delete flag to true in system table for \a uid. + * \~russian + * Устанавливает флаг удаления в true в системной таблице для заданного \a uid + * \~ + * \see deleteMarked() + * \param uid - \~english id for mark deleted \~russian id для пометки на удаление \~ + */ +void +aDatabase::markDeleted ( Q_ULLONG uid ) +{ + db()->exec ( QString ( "UPDATE uniques SET df='1' WHERE id=%1" ).arg ( uid ) ); +} + + +/*! + * \~english + * Delete all marked records. + * \~russian + * Удаляет все помеченные записи. + * \~ + * \see markDeleted(Q_ULLONG uid) + */ +void +aDatabase::deleteMarked() +{ + db()->exec ( "DELETE FROM uniques WHERE df='1'" ); +} + + +QStringList +aDatabase::supportedDriverList() +{ + QStringList l; + l<<"internal"; + l<<"mysql"; + l<<"postgresql"; + return l; +} + + +bool +aDatabase::exchangeDataSystables ( QDomDocument &xml, bool import ) +{ + bool res = false; + if ( import ) + { + qds->databaseImport ( "import.xml", false ); + res |= importTableData ( xml,"a_journ" ); + res |= importTableData ( xml,db_users ); + res |= importTableData ( xml,db_user_roles ); + res |= importTableData ( xml,db_roles ); + res |= importTableData ( xml,db_right_roles ); + res |= importTableData ( xml,db_indices ); + + } + else + { + qds->databaseExport ( "export.xml" ); + res |= exportTableData ( xml,"a_journ" ); + res |= exportTableData ( xml,db_users ); + res |= exportTableData ( xml,db_user_roles ); + res |= exportTableData ( xml,db_roles ); + res |= exportTableData ( xml,db_right_roles ); + res |= exportTableData ( xml,db_indices ); + } + return res; +} + +bool +aDatabase::exchangeDataUniques ( QDomDocument &xml, bool import ) +{ + bool res = false; + if ( import ) + { + res |= importTableData ( xml,"uniques" ); + } + else + { + res |= exportTableData ( xml,"uniques" ); + } + return res; +} + +bool +aDatabase::exchangeDataCatalogues ( QDomDocument &xml, bool import ) +{ + aCfgItem gcont, cont, item; + long id; + int n, i; + bool rc = false; + + gcont = cfg.find ( cfg.find ( mdc_metadata ), md_catalogues, 0 ); + n = cfg.count ( gcont, md_catalogue ); + for ( i = 0; iselect(); + QDomElement xml_root = xml.documentElement(); + if ( xml_root.isNull() ) + { + aLog::print ( aLog::Error,tr ( "aDatabase export table: invalid XML file" ) ); +// printf("xml has no root element"); + return true; + } + QDomElement table = xml.createElement ( "table" ); + table.setAttribute ( "name",tableName ); + QDomElement row; + QDomElement field; + xml_root.appendChild ( table ); + if ( !dataTable->first() ) return false; + do + { + uint countField = dataTable->count(); + QVariant val; + row = xml.createElement ( "row" ); + table.appendChild ( row ); + for ( uint i=0; ivalue ( i ); + if ( val.isValid() ) + { + field = xml.createElement ( "field" ); + field.setAttribute ( "name",dataTable->fieldName ( i ) ); + field.appendChild ( xml.createTextNode ( val.toString() ) ); + row.appendChild ( field ); + } + } + } + while ( dataTable->next() ); + return false; +} + + +bool +aDatabase::importTableData ( QDomDocument &xml, const QString &tableName ) +{ +// printf("import table data %s\n",tableName.ascii()); + QDomElement root = xml.documentElement(); + if ( root.nodeName() != "AnanasDump" ) + { + + aLog::print ( aLog::Error,tr ( "aDatabase import table: invalid XML file" ) ); + //printf("uncnown data format\n"); + return true; + } + QDomNodeList tables = root.childNodes(); + uint countTables = tables.count(); + for ( uint i=0; iexec ( query ); + } + for ( uint j=0; jexec ( query ); + + } + } + else + { + buffer = tbl->primeInsert(); + for ( uint k=0; ksetValue ( field.attribute ( "name" ),field.toElement().text() ); + } + } + tbl->insert(); + } + } + break; + } + } + return false; +} + +void +aDatabase::reportError ( QSqlError er, const QString &query ) +{ + aLog::print ( aLog::Error, QObject::tr ( "aDatabase query: %1" ).arg ( query ) ); + aLog::print ( aLog::Error, QObject::tr ( "aDatabase text: %1" ).arg ( er.text() ) ); + aLog::print ( aLog::Error, QObject::tr ( "aDatabase database text: %1" ).arg ( er.databaseText() ) ); + aLog::print ( aLog::Error, QObject::tr ( "aDatabase driver text: %1" ).arg ( er.driverText() ) ); +} + +//start transaction +bool aDatabase::transaction() +{ + if ( dataBase ) + return dataBase->transaction(); + return false; +} + +//commit transaction +bool aDatabase::commit() +{ + if ( dataBase ) + return dataBase->commit(); + return false; +} + +//rollback transaction +bool aDatabase::rollback() +{ + if ( dataBase ) + return dataBase->rollback(); + return false; +} + + +QStringList +aDatabase::users() +{ + QStringList l; + l << "user1"; + l << "user2"; + l << "user3"; + return l; +} + + +int +aDatabase::loginUsersCount() +{ + QSqlQuery q = db()->exec ( QString ( "SELECT users FROM netusers" ) ); + if ( q.first() ) return q.value ( 0 ).toInt(); + else aLog::print ( aLog::Error,tr ( "aDatabase get users count" ) ); + return 0; +} + + +bool +aDatabase::login ( const QString &username, const QString &password, int applicationId ) +{ + QSqlQuery q, q1; + int count = 0, role_id, md_id, perm, isActive = 0; + bool userOk = false; + + v_user_id = 0; + v_app_id = applicationId; + + if ( applicationId < 0 || applicationId > 3 ) applicationId = 0; + q = db()->exec ( QString ( "SELECT count(*) FROM %1" ).arg ( qds->tableName ( db_users ) ) ); + if ( q.first() ) count = q.value ( 0 ).toInt(); + if ( !count ) + { + userOk = true; + } + else + { + q = db()->exec ( QString ( "SELECT id,active%4 FROM %1 WHERE login='%2' AND password='%3'" ).arg ( qds->tableName ( db_users ) ).arg ( username ).arg ( password ).arg ( applicationId ) ); + if ( q.first() ) + { + v_user_id = q.value ( 0 ).toInt(); + isActive = q.value ( 1 ).toInt(); + userOk = true; + } + else aLog::print ( aLog::Error,tr ( "aDatabase get users count" ) ); + } + if ( userOk ) + { + if ( isActive !=0 && applicationId !=AApplication::Administrator ){ + QMessageBox::information ( 0, "Ananas",tr ( "User already logged in" ), 0, 0, 0 ); +// return false; + } + db()->exec ( QString ( "UPDATE %1 SET users=users+1" ).arg ( qds->tableName ( "netusers" ) ) ); + if ( count ) + { + db()->exec ( QString ( "UPDATE %1 SET active%2=1 WHERE id=%3" ).arg ( qds->tableName ( db_users ) ).arg ( applicationId ).arg ( v_user_id ) ); + } + printf ( "login user id = %i OK\n", v_user_id ); + +// Считаем набор прав пользователя + q = db()->exec ( QString ( "SELECT idr FROM %1 WHERE id=%2" ).arg ( qds->tableName ( db_user_roles ) ).arg ( v_user_id ) ); + while ( q.next() ) + { + role_id = q.value ( 0 ).toInt(); + q1 = db()->exec ( QString ( "SELECT object,permission FROM %1 WHERE id=%2" ).arg ( qds->tableName ( db_right_roles ) ).arg ( role_id ) ); + while ( q1.next() ) + { + md_id = q1.value ( 0 ).toInt(); + perm = q1.value ( 1 ).toInt(); + if ( accessRights.contains ( md_id ) ) + { + accessRights[ md_id ] |= perm; + } + else accessRights[ md_id ] = perm; + } + } + QMap::Iterator it; + for ( it = accessRights.begin(); it != accessRights.end(); ++it ) + { + printf ( "P %i:%04x\n", + it.key(), + it.data() ); + } + + return true; + } + return false; +} + + +void +aDatabase::logout() +{ + db()->exec ( QString ( "UPDATE %1 SET users=CASE WHEN users>0 THEN users-1 ELSE 0 END" ).arg ( qds->tableName ( "netusers" ) ) ); + objectUnlock ( 0 ); + db()->exec ( QString ( "UPDATE %1 SET active%2=0 WHERE id=%3" ).arg ( qds->tableName ( db_users ) ).arg ( v_app_id ).arg ( v_user_id ) ); + if ( !loginUsersCount() ) + { + db()->exec ( QString ( "DELETE FROM %1" ).arg ( qds->tableName ( "locks" ) ) ); + } +} + + +void +aDatabase::netupdate() +{ + printf ( "UPDATE++\n" ); + db()->exec ( QString ( "UPDATE %1 SET updates=updates+1" ).arg ( qds->tableName ( "netusers" ) ) ); + v_updatesCount++; +} + + + +bool +aDatabase::isObjectLocked ( Q_ULLONG id ) +{ + if ( !id ) return false; + QSqlQuery q = db()->exec ( QString ( "SELECT id FROM %1 WHERE userid=%2 AND id=%3" ).arg ( qds->tableName ( "locks" ) ).arg ( v_user_id ).arg ( id ) ); + if ( q.first() ) + { + QMessageBox::information ( 0, "Ananas",tr ( "Object locked by another user" ), 0, 0, 0 ); + return true; + } + return false; +} + + +bool +aDatabase::objectLock ( Q_ULLONG id ) +{ + if ( !id ) return true; +// printf("LOCK user=%i obj=%Lu\n", v_user_id, id); + db()->exec ( QString ( "INSERT INTO %1 (userid,id) VALUES (%2,%3)" ).arg ( qds->tableName ( "locks" ) ).arg ( v_user_id ).arg ( id ) ); + if ( db()->lastError().type() ==0 ) return true; + QMessageBox::information ( 0, "Ananas",tr ( "Object locked by another user" ), 0, 0, 0 ); + return false; +} + +void +aDatabase::objectUnlock ( Q_ULLONG id ) +{ +// printf("UNLOCK user=%i obj=%Lu\n", v_user_id, id); + QString query ( QString ( "DELETE FROM %1 WHERE userid=%2" ).arg ( qds->tableName ( "locks" ) ).arg ( v_user_id ) ); + if ( id ) query.append ( QString ( " AND id=%1" ).arg ( id ) ); + db()->exec ( QString ( query ) ); +} + + +aDatabase * +aDatabase::database() +{ + return &aDatabase_default; +} + + +int +aDatabase::updatesCount() +{ + QSqlQuery q = db()->exec ( QString ( "SELECT updates FROM %1" ).arg ( qds->tableName ( "netusers" ) ) ); + if ( q.first() ) return q.value ( 0 ).toInt(); + return 0; +} + + + +void +aDatabase::timerEvent ( QTimerEvent * ) +{ + int uc; + if ( !db()->isOpen() ) return; + uc = updatesCount(); + if ( uc > v_updatesCount ) + { + v_updatesCount = uc; + emit refresh(); +// printf( "EMIT refresh\n" ); + } +} + + + +bool +aDatabase::isAccessRights ( int md_type, Q_ULLONG obj_id, DBPermission req_operation ) +{ + bool res = false; + + if ( accessRights.contains ( md_type ) ) + { + res = ( accessRights[ md_type ] & req_operation ) != 0; + } + else res = true; + if ( ! res ) + { + QMessageBox::information ( 0, "Ananas",tr ( "No access rights" ), 0, 0, 0 ); + } + return res; +} + + +int +aDatabase::rolePermission ( int role_id, int md_id ) +{ + int perm = 0; + + QSqlQuery q = db()->exec ( QString ( "SELECT permission FROM %1 WHERE id=%2 AND object=%3" ).arg ( qds->tableName ( db_right_roles ) ).arg ( role_id ).arg ( md_id ) ); + if ( q.first() ) perm = q.value ( 0 ).toInt(); + else perm = DBP_All; + return perm; +} + + +void +aDatabase::setRolePermission ( int role_id, int md_id, int new_permission ) +{ + QString query; + + printf ( "SET PERMISSIONS role = %i, obj_id=%i perm=%08x\n", role_id, md_id, new_permission ); + + QSqlQuery q = db()->exec ( QString ( "SELECT permission FROM %1 WHERE id=%2 AND object=%3" ).arg ( qds->tableName ( db_right_roles ) ).arg ( role_id ).arg ( md_id ) ); + if ( q.first() ) query = QString ( "UPDATE %1 SET permission=%4 WHERE id=%2 AND object=%3" ).arg ( qds->tableName ( db_right_roles ) ).arg ( role_id ).arg ( md_id ).arg ( new_permission ); + else query = QString ( "INSERT INTO %1 (id,object,permission) VALUES (%2,%3,%4)" ).arg ( qds->tableName ( db_right_roles ) ).arg ( role_id ).arg ( md_id ).arg ( new_permission ); + q = db()->exec ( query ); + if ( db()->lastError().type() !=0 ) printf ( "error query %s\n", ( const char* ) query ); +} diff --git a/src/lib/sys/adatabase.h b/src/lib/sys/adatabase.h new file mode 100644 index 0000000..cece630 --- /dev/null +++ b/src/lib/sys/adatabase.h @@ -0,0 +1,208 @@ +/**************************************************************************** +** $Id: adatabase.h,v 1.2 2008/11/09 21:08:09 leader Exp $ +** +** Header file of the ananas database of Ananas +** Designer and Engine applications +** +** Created : 20031201 +** +** Copyright (C) 2003-2004 Leader InfoTech. All rights reserved. +** Copyright (C) 2003-2005 Grigory Panov , Yoshkar-Ola +** +** This file is part of the Library of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.leaderit.ru/page=ananas or email sales@leaderit.ru +** See http://www.leaderit.ru/gpl/ for GPL licensing information. +** +** Contact org@leaderit.ru if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#ifndef ADATABASE_H +#define ADATABASE_H +#include +#include +#include +#include +//Added by qt3to4: +#include +#include "acfg.h" +#include +#include +#include + + +/** + * Константы, используемые для формирования имен sql таблиц в зависимости от соответствия + * sql таблицы и бизнес объекта Ананаса + */ +#define db_document_header "dh%1" +#define db_document_table "dt%1_%2" +#define db_catalog_element "ce%1" +#define db_catalog_group "cg%1" +#define db_iregister "ri%1" +#define db_aregister "ra%1" +#define db_areg_remainder "ra%1_rem" +#define db_user_roles "usr_rl" +#define db_users "usr" +#define db_roles "rl" +#define db_right_roles "r_rl" +#define db_indices "idc" +#define db_areg_dim "ra%1_d%2" + +class aDatabase; +class aCfgRc; +class aDataTable; + +/*! + *\~english + * Database abstraction layer class. + * Used for working with SQL database on metadata context. + *\~russian + * \brief Класс для работы с СУБД. Ananas Data Abstraction Layer. + * Наследует QObject. + * + * Обеспечивает унифицированный программный интерфейс доступа к данным, независимый от используемой СУБД. + * Используется для работы с базой данных в контексте бизнес схемы. + *\~ + */ +class ANANAS_EXPORT aDatabase: public QObject +{ + Q_OBJECT + +public slots: + +public: + + enum DBPermission { + DBP_NoAccess = 0, + DBP_View = 1 << 0, + DBP_Update = 1 << 1, + DBP_Insert = 1 << 2, + DBP_Delete = 1 << 3, + DBP_Execute = 1 << 4, + DBP_TurnOn = 1 << 5, + DBP_TurnOff = 1 << 6, + DBP_All = 0xFFFF + }; + + /*! \~english type of database drivers \~russian перечисление типов баз данных \~ */ + enum dbServer + { + /*! \~english Unknown driver (not supported)\~russian Неизвестный драйвер (не поддерживается)\~ */ + unknown, + /*! \~english MySQL driver \~russian MySQl драйвер \~ */ + mysql, + /*! \~english PostgreSQL driver \~russian PostgreSQL драйвер \~ */ + postgresql, + /*! \~english ODBC driver (not supported)\~russian ODBC драйвер (не поддерживается) \~ */ + odbc, + /*! \~english Oracle driver (not supported)\~russian Oracle драйвер (не поддерживается) \~ */ + oracle, + /*! \~english MSSQL driver (not supported)\~russian MSSQL драйвер (не поддерживается) \~ */ + mssql, + /*! \~english Sybase driver (not supported)\~russian Sybase драйвер (не поддерживается) \~ */ + sybase }; + /*! \~english link to database \~russian ссылка на базу данных \~ */ + QSqlDatabase ddb; + /*! \~english metadata object \~russian метаданные \~ */ + aCfg cfg; + QDataSchema *qds; + + aDatabase(); + ~aDatabase(); + bool init( aCfgRc *rc, const QString &dbname = QString::null ); + bool init( const QString &rcname, const QString &dbname = QString::null ); + bool prepareDatabaseConnect( aCfgRc *rc ); + void done(); + QSqlDatabase *db(const QString &dbname = QString::null ); + bool checkStructure(); + bool create(); + bool drop( const QString &); + bool update(); + Q_ULLONG uid( int otype ); +// int otype( Q_ULLONG uid ); + int uidType ( Q_ULLONG uid ); + aDataTable *table( const QString & name = QString::null ); + bool tableExists( const QString & name ); + void markDeleted(qulonglong uid); + void deleteMarked(); + QString driverName(); + + bool isAccessRights( int md_type, Q_ULLONG obj_id, DBPermission req_operation ); + + static QStringList supportedDriverList(); + static QStringList getUniqueIndices(const QString & flddef); + static QString tableDbName( aCfg &md, aCfgItem context, long * tid); + static QString tableDbName( aCfg &md, aCfgItem context); + + bool exchangeDataSystables ( QDomDocument &xml, bool import ); + bool exchangeDataCatalogues ( QDomDocument &xml, bool import ); + bool exchangeDataDocuments ( QDomDocument &xml, bool import ); + bool exchangeDataJournals ( QDomDocument &xml, bool import ); + bool exchangeDataInfoRegisters ( QDomDocument &xml, bool import ); + bool exchangeDataAccumulationRegisters ( QDomDocument &xml, bool import ); + bool exchangeDataUniques ( QDomDocument &xml, bool import ); + + bool transaction(); + bool commit(); + bool rollback(); + + QStringList users(); + int loginUsersCount(); + bool login( const QString &username, const QString &password, int applicationId = 0 ); + void logout(); + void netupdate(); + + bool isObjectLocked( Q_ULLONG id ); + bool objectLock( Q_ULLONG id ); + void objectUnlock( Q_ULLONG id=0 ); +// QDataSchema *qds(); + + int rolePermission( int role_id, int md_id ); + void setRolePermission( int role_id, int md_id, int new_permission ); + + static aDatabase *database(); +signals: + void refresh(); +protected: + void timerEvent ( QTimerEvent * ); +private: + /** + * \en + * link to database + * \_en \ru + * \brief Ссылка на объект доступа к базе данных sql сервера. + * \_ru + */ + QSqlDatabase *dataBase; + int v_user_id, v_app_id; + int v_updatesCount; + int v_timerId; + + int updatesCount(); + bool exportTableData(QDomDocument& xml, const QString &tableName); + bool importTableData(QDomDocument& xml, const QString &tableName); + void reportError(QSqlError er, const QString &query); + + bool isExists(const QString fname, QStringList *f_lst, QString &match); + bool createdb( bool update ); + bool dumpTable( QDomDocument& xml, const QString &tableName); + void fillFeatures(); + QString feature(const QString& fetureName); + + QMap featuresMySQL, featuresSQLite, featuresPostgreSQL; + QMap accessRights; +}; + +#endif diff --git a/src/lib/sys/sys.pri b/src/lib/sys/sys.pri new file mode 100644 index 0000000..565fc56 --- /dev/null +++ b/src/lib/sys/sys.pri @@ -0,0 +1,7 @@ +HEADERS += \ + sys/adatabase.h \ + sys/aapplication.h + +SOURCES += \ + sys/adatabase.cpp \ + sys/aapplication.cpp diff --git a/src/lib/widgets/awidget.cpp b/src/lib/widgets/awidget.cpp new file mode 100644 index 0000000..6cbb20f --- /dev/null +++ b/src/lib/widgets/awidget.cpp @@ -0,0 +1,1108 @@ +/**************************************************************************** +** $Id: awidget.cpp,v 1.2 2008/11/08 20:16:36 leader Exp $ +** +** Code file of the Ananas visual bject of Ananas +** Designer and Engine applications +** +** Created : 20031201 +** +** Copyright (C) 2003-2004 Leader InfoTech. All rights reserved. +** Copyright (C) 2003-2006 Grigory Panov , Yoshkar-Ola. +** +** This file is part of the Library of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.leaderit.ru/page=ananas or email sales@leaderit.ru +** See http://www.leaderit.ru/gpl/ for GPL licensing information. +** +** Contact org@leaderit.ru if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#include +#include +#include +#include +#include +//Added by qt3to4: +#include +#include +#include +#include "adatabase.h" +#include "awidget.h" +#include "wfield.h" +#include "wdbfield.h" +#include "wdbtable.h" +#include "aform.h" +#include "alog.h" + + +/*! + *\en + * Abstract Ananas widget object. + *\_en + *\ru + * Конструктор, создающий абстрактный объект. Абстрактность в данном случае означает + * отстутствие привязки к базе данных. \n + * Вызывает конструктор базового класса QWidget. + * \param parent - указатель на родительский виджет. + * \param name - имя создаваемого объекта. + * \param fl - флаги используемые при создании виджета. Передаются в конструктор базового класса. + *\_ru + */ +aWidget::aWidget( QWidget *parent, const char *name, Qt::WFlags fl ) +:QWidget( parent, name, fl ) +{ + vId = 0; + db = 0; + dbobj = 0; + engine = 0; + vFormMode = 0; + vInited = false; +} + +/*! + * \ru + * Конструктор, использующий для создания объекта имя элемента метаданных.\n + * У класса есть также конструктор, использующий для создания объекта ссылку на объект с описанием элемента метаданных. + * \param itemname - имя элемента метаданных. + * \param adb - ссылка на объект доступа к базе данных. + * \param parent - указатель на родительский виджет (передается в конструктор базового класса). + * \param name - имя создаваемого объекта (передается в конструктор базового класса). + * \param fl - флаги, используемые конструктором базового класса. + * \_ru + */ +aWidget::aWidget( const QString &itemname, aDatabase *adb, QWidget *parent, const char *name, Qt::WFlags fl ) +:QWidget( parent, name, fl ) +{ + vId = 0; + dbobj = 0; + vInited = false; + engine = 0; + vFormMode = 0; + if ( adb ) { + obj = adb->cfg.find( itemname ); + init( adb ); + } +} + + +/*! + * \ru + * Конструктор, использующий для создания объекта ссылку на объект элемента метаданных.\n + * У класса есть также конструктор, использующий для создания объекта имя элемента метаданных. + * \param context - ссылка на объект элемента метаданных. + * \param adb - ссылка на объект доступа к базе данных. + * \param parent - указатель на родительский виджет (передается в конструктор базового класса). + * \param name - имя создаваемого объекта (передается в конструктор базового класса). + * \param fl - флаги, используемые конструктором базового класса. + * \_ru + */ +aWidget::aWidget( aCfgItem context, aDatabase *adb, QWidget *parent, const char *name, Qt::WFlags fl ) +:QWidget( parent, name, fl ) +{ + vId = 0; + dbobj = 0; + vInited = false; + engine = 0; + obj = context; + vFormMode = 0; + init( adb ); +} + +aWidget::~aWidget() +{ + delete dbobj; + dbobj = 0; +} + + + +/*! + *\en + * Create database object. + *\_en + *\ru + * Пока ничего не делает. Возвращает 0; + *\_ru + */ +aObject * +aWidget::createDBObject( aCfgItem , aDatabase * ) +{ + return 0; +} + + + + +/*! + *\en + * Create toolbar for QMainWindow owner object. + *\_en + *\ru + * Пока ничего не делает. Возвращает 0; + *\_ru + */ +Q3ToolBar* +aWidget::createToolBar( Q3MainWindow * ) +{ + return 0; +} + + +/*! + *\ru + * Если объект не был проинициализирован, вызывает initObject(adb). + *\_ru + */ + +void +aWidget::init( aDatabase *adb ) +{ + if ( isInited() ) return; +// aWidget *pc = parentContainer( this ); +// if ( pc ) if ( !pc->isInited() ) pc->init( adb ); + initObject( adb ); +} + + + +/*! + *\en + * Init object after create. + * Need setId( id ), where id - if of the metadata object of the adb->cfg loaded Configuration. + *\_en + *\ru + * Инизиализирует созданный объект. + * Необходимо выполнить setId(id), где id идентификатор обекта в конфигурации. + *\_ru + *\param adb - \en ananas database object. \_en \ru объект доступа к базе данных. \_ru + */ +void +aWidget::initObject( aDatabase *adb ) +{ + aCfgItem fg, f; + QString tname; + + aLog::print(aLog::Debug, tr("aWidget init widget %1 form mode %2").arg(name()).arg(formMode()) ); + // Init myself. + setInited( true ); + + //<для чего? + Q3SqlPropertyMap *pm = new Q3SqlPropertyMap(); + //> + + + db = adb; + md = 0; + if ( db ) + { + md = &db->cfg; + } + else + { + aLog::print(aLog::Error, tr("aWidget init: invalid database") ); + return; + } + + if ( obj.isNull() ) + { + obj = md->find( getId() ); + } + + + //<для чего? + form = new Q3SqlForm( this ); + pm->insert("wDBField","value"); + form->installPropertyMap( pm ); + //> + + + if ( obj.isNull() ) + { + aLog::print(aLog::Error, tr("aWidget init: invalid meta object") ); + return; + } + dbobj = createDBObject( obj, adb ); + QObjectList l = this->queryList( "QWidget" ); + QListIterator it( l ); + QObject *obj; + while ( it.hasNext() ) + { + obj = it.next(); + if ( parentContainer( ( QWidget *) obj ) != this ) continue; + + //debug_message("SCAN: Widget class name=%s\n", obj->className() ); + + if ( obj->className()==QString("wDBTable") ) + { + + aLog::print(aLog::Debug, tr("aWidget init: connect signals wDBTable") ); + connect( this, SIGNAL( changeObj(const QString &) ), + //(wDBTable*) + obj, SLOT( newFilter(const QString &) )); + connect( this, SIGNAL( changeObjId(const qulonglong) ), + //(wDBTable*) + obj, SLOT( newDataId(const qulonglong) )); + } + // if ( obj->className()==QString("wDBField") ) + // { +// connect( this, SIGNAL( changeObj(const QString &) ), +// //(wDBTable*) +// obj, SLOT( newFilter(const QString &) )); + // } + } + //--delete l; // delete the list, not the objects + //--l=0; +} + + + +/*! + *\~english + *\~russian + *\~ + */ + /* +void +aWidget::formInsert( QWidget *widget, const QString &field ) +{ + form->insert( widget, field ); +} +*/ + + +/*! + *\~english + *\~russian + *\~ + */ +/* +void +aWidget::formRemove( const QString &field ) +{ + form->remove( field ); +} +*/ + + +/*! + *\en + *\_en + *\ru + * Ничего не делает. Возвращает false. + *\_ru + */ +bool +aWidget::checkStructure() +{ + return false; +} + + + +/*! + *\en + *\_en + *\ru + * Возвращает значение свойства vName. + *\_ru + */ +/*QString +aWidget::getName() const { +// if (vName.isEmpty()) return name(); + return vName; +} +*/ + + +/*! + *\en + *\_en + *\ru + * Устанавливает значение свойства vName. + *\_ru + */ + /* +void +aWidget::setName(QString fn){ + vName = fn; +} +*/ + + +/*! + *\en + *\_en + *\ru + * Ничего не делает. Возвращает 0. + *\_ru + */ +QDialog* +aWidget::createEditor( QWidget * ) +{ + return 0; +} + + + +/*! + *\en + *\_en + *\ru + * Вызывает редактор свойств, если значение передаваемого параметра равно true. + * Редактор свойств предоставляет пользователю диалог задания значений свойств виджета. + * Например, для такого виджета как wDBField редактор свойств позволяет выбрать элемент метаданных + * описывающий поле базы данных, значение которого будет редактироваться с использованием виджета. + * То есть осуществить привязку данных (data bindings). + *\param fn - параметр, значение которого должно быть равно true, для того чтобы был вызван + * редактор свойств. + *\_ru + */ +void +aWidget::setOpenEditor( bool fn ) +{ + if(fn) widgetEditor(); +} + + + +/*! + *\en + * Emit signal setData( object, md ). + *\_en + *\ru + * Посылает сигнал setData( object, md ). + *\_ru + */ +void +aWidget::setObjectData( QWidget *object, aCfg *md ) +{ + emit( setData( object, md ) ); +} + + + +/*! + *\en + * Emit signal getData( object ). + *\_en + *\ru + * Посылает сигнал getData( object ). + *\_ru + */ +void +aWidget::getObjectData( QWidget *object ) +{ + emit( getData( object ) ); +} + + + +/*! + *\en + * Return toplevel metadata configuration. + *\_en + *\ru + * Возвращает объект конфигурации для виджета верхнего уровня. + *\_ru + */ +aCfg* +aWidget::getMd() +{ + aCfg *md = 0; + QWidget *mw = topLevelWidget(); + if (mw->name() == QString("ananas-designer_mainwindow") ) + { + connect( this, SIGNAL( getMd( aCfg ** ) ), mw, SLOT( getMd( aCfg ** ) )); + emit ( getMd( &md ) ); + } + return md; +} + + + +/*! + *\~english + * Get id from database. + * Get id for current database record or 0 if database object not created. + *\~russian + * Возвращает id объекта базы данных. + * Возвращает id текущей записи в базе данных или 0 если обект + * для работы с базой не создан. Id является уникальным и идентифицирует конкретный + * экземпляр обекта. + *\~ + *\return \~english current database record id\~russian id текущей записи в базе данных.\~ + */ +qulonglong +aWidget::uid() +{ + if ( dbobj ) + { + return dbobj->getUid(); + } + else + { + aLog::print(aLog::Error, tr("aWidget invalid data source object") ); + } + return 0; +} + + + +/*! + *\~english + *\~russian + *\~ + */ +void +aWidget::widgetEditor() +{ + aWidget::widgetEditor( this, createEditor( topLevelWidget() ) ); +} + + + +/*! + *\~english + *\~russian + *\~ + */ +void +aWidget::widgetEditor( QWidget *object, QDialog *editor ) +{ + aCfg *md = 0; + QWidget *mw = object->topLevelWidget(); + aWidget o( mw ); + if ( mw->name() == QString( "ananas-designer_mainwindow" ) ) + { + md = o.getMd(); + if ( !md ) + { + aLog::print(aLog::Error, tr("aWidget widgetEditor: invalid metadata object") ); + return; + } + if ( editor ) { + connect( &o, SIGNAL( setData( QWidget *, aCfg* ) ), editor, SLOT( setData( QWidget *, aCfg* ) ) ); + connect( &o, SIGNAL( getData( QWidget * ) ), editor, SLOT( getData( QWidget * ) ) ); + o.setObjectData( object, md ); + if ( editor->exec() == QDialog::Accepted ) + { + o.getObjectData( object ); + //o.updateProp(); + } + delete editor; + editor = 0; + } + } +} + + + +/*! + *\~english + *\~russian + *\~ + */ +aWidget * +aWidget::parentContainer( QWidget *w ) +{ + while ( w ) + { + w = w->parentWidget(); + if ( w ) + { + if ( w->inherits("aWidget") ) + { + if ( ( ( aWidget *) w )->isContainer()) break; + } + } + } + return ( aWidget *) w; +} + + + +/*! + *\~english + *\~russian + *\~ + */ +aForm * +aWidget::parentForm( QWidget *w ) +{ + while ( w ) + { + if ( w->inherits("aForm") ) break; + w = w->parentWidget(true); + } + return ( aForm *) w; +} + + + +/*! + *\~english + *\~russian + *\~ + */ +aCfgItem * +aWidget::getMDObject() +{ + return &obj; +} + + + +/*! + *\~english + *\~russian + *\~ + */ +void +aWidget::setMDObject( aCfgItem object ) +{ + obj = object; +} + + + +/*! + *\~english + *\~russian + *\~ + */ +aSQLTable * +aWidget::table( const QString &name ) +{ + if ( dbobj ) + { + return dbobj->table( name ); + } + aLog::print(aLog::Error, tr("aWidget table: invalid data source object") ); + return 0; +} + +/* +bool +aWidget::tableInsert( const QString &name ) +{ + if ( db ) { + aSQLTable *t = db->table( name ); + if ( !t ) return false; + dbtables.insert( name, t ); + return true; + } + return false; +} + + +bool +aWidget::tableRemove( const QString &name ) +{ + dbtables.remove( name ); + return true; +} +*/ + + + +/*! + *\~english + *\~russian + *\~ + */ +QString +aWidget::displayString() +{ + return ""; +} + + + + +/*! + *\~english + * Create new database record object. + * New object create with using wirtual function aObject::New() of aObject + * and it's childs. + *\~russian + * Создает новый объект для работы с записями базы данных. + * Объект создается испоьлзуя виртуальную функцию aObject::New() объекта aObject + * и его потомков. + *\~ + *\return \~engilsh error code. \~russian код ошибки.\~ + */ +ERR_Code +aWidget::New() +{ + if ( dbobj ) + { + return dbobj->New(); + } + aLog::print(aLog::Error, tr("aWidget new: invalid data source object") ); + return err_abstractobj; + +} + + + +/*! + *\~english + * Select object in database. + *\~russian + * Выбирает объект в базе данных. + *\~ + *\param id -\~english database record id.\~russian id объекта в базе данных.\~ + *\return \~english error code.\~russian код ошибки.\~ + */ +ERR_Code +aWidget::Select( qulonglong id ) +{ + int rc = 0; + if ( dbobj ) + { + bool res; + res = dbobj->select( id ); + if(res) rc = err_noerror; + else rc = err_selecterror; + //Refresh(); + return rc; + } + aLog::print(aLog::Error, tr("aWidget select: invalid data source object") ); + return err_abstractobj; +} + + + +/*! + *\~english Update data + *\~russian Обновляет данные по данному виджету в базе + *\~ + */ +ERR_Code +aWidget::Update() +{ + QString fname; + if ( dbobj ) + { + + QObjectList l = this->queryList( "wDBField" ); + QListIterator it( l ); + aWidget *obj; + while ( it.hasNext() ) + { + obj = qobject_cast(it.next()); + fname= obj->getFieldName(); + dbobj->SetValue( fname,( ( aWidget *) obj )->value() ); + } + //--delete l; // delete the list, not the objects + //--l=0; +/* + while ( (obj = (aWidget*) tit.current()) != 0 ){ + ++tit; + ((QDataTable*)obj)->refresh(); + } + delete tl; // delete the list, not the objects + + return err_noerror; +*/ + return dbobj->Update(); + } + aLog::print(aLog::Error, tr("aWidget update: invalid data source object") ); + return err_incorrecttype; +} + +/*! + *\~english + *\~russian + *\~ + */ +ERR_Code +aWidget::Refresh() +{ + QString fname; + QObjectList l = this->queryList( "wDBField" ); + QListIterator it( l ); + QObjectList tl = this->queryList( "wDBTable" ); + QListIterator tit( tl ); + aWidget *obj; + while ( it.hasNext() ){ + obj = qobject_cast(it.next()); + if ( parentContainer( obj ) != this ) continue; + fname= obj->getFieldName(); + obj->setValue(dbobj->Value(fname).toString()); + } + //--delete l; // delete the list, not the objects + //--l=0; + + Q3DataTable* obj2; + while ( tit.hasNext() ){ + obj2 = qobject_cast(tit.next()); + obj2->refresh(); + } + //--delete tl; // delete the list, not the objects + + return err_noerror; +} + + +/*! + *\~english + *\~russian + *\~ + */ +ERR_Code +aWidget::TurnOn() +{ + return err_incorrecttype; +} + + + +/*! + *\~english + * Get field value. + * get value for field with such name. + *\~russian + * Возвращает значение поля. + * Возвращает значение поля с именем name. + *\~ + *\param name - \~english field md name. \~russian имя поля в конфигурации.\~ + *\return \~english field value. \~russian значение поля.\~ + */ +QVariant +aWidget::value( const QString & nameWidget ) +{ + QObject *w; + QVariant res; +/* + aObject *o = 0; + if ( mainWidget ) o = mainWidget->dataObject(); + if ( o ) { + res = o->Value( name ); + } + if ( res.type() != QVariant::Invalid ) return res; + else printf("no field %s in data object\n", ( const char *) name ); +*/ + w = Widget( nameWidget ); + if ( w ) { + if (w->inherits("aWidget")){ + res=( (aWidget*)w )->textValue();//value(); +// } else if (w->inherits("wField")){ +// res=( (wField*)w )->text();//value(); + } else if (!strcmp(w->className(),"QPushButton")){ + res=((QPushButton *)w)->text(); + } else if (!strcmp(w->className(),"QLabel")){ + res=((QLabel*)w)->text(); + } else if (!strcmp(w->className(),"QLineEdit")){ + res=((QLineEdit*)w)->text(); + } else if (!strcmp(w->className(),"QCheckBox")){ + res=((QCheckBox*)w)->text(); + } else if (!strcmp(w->className(),"QDateEdit")){ + res=((Q3DateEdit*)w)->date().toString(Qt::ISODate); + } + } else { + // debug_message(tr("Error! Can't find widget by name==`%s`\n"),(const char*) name.local8Bit()); + + aLog::print(aLog::Error, tr("aWidget value not fount widget with name %1").arg(nameWidget) ); + } + return res; +// if ( dbobj ) return dbobj->Value(name); +//CHECK_POINT +// return QVariant(""); +} + + + +/*! + *\~english + * Setting form widgets value. + * Support type of widgets: wField, wDBField, QPushButton, QLabel, QLineEdit, QCheckBox. + *\~russian + * Установка значения виджетов формы. + * Поддерживаемые типы виджетов: wField, wDBField, QPushButton, QLabel, QLineEdit, QCheckBox. + *\~ + *\param nameWidget -\~english Widget name. + \~russian Имя виджета. + \~ + *\param value -\~english value. + \~russian Значение виджета. + \~ + */ +int +aWidget::setValue( const QString & nameWidget, const QVariant &value ) +{ + QObject *w; + int rc= err_noerror; + + w = Widget( nameWidget ); + if ( w ) { + if (w->inherits("wField")){ + ((aWidget*)w)->setValue(value.toString()); +// } else if (w->inherits("wField")){ +// ((wField*)w)->setValue(value.toString()); + } else if (!strcmp(w->className(),"QPushButton")){ + ((QPushButton *)w)->setText( value.toString() ); + } else if (!strcmp(w->className(),"QLabel")){ + ((QLabel*)w)->setText( value.toString() ); + } else if (!strcmp(w->className(),"QLineEdit")){ + ((QLineEdit*)w)->setText( value.toString() ); + } else if (!strcmp(w->className(),"QCheckBox")){ + ((QCheckBox*)w)->setText(value.toString() ); + } else if (!strcmp(w->className(),"QDateEdit")){ + ((Q3DateEdit*)w)->setDate( value.toDate() ); + } + } else { + //debug_message(tr("aForm::SetValue() Error! Can't find widget by name==`%s`\n"),(const char*) name.local8Bit()); + aLog::print(aLog::Error, tr("aWidget set value: not fount widget with name %1").arg(nameWidget) ); + rc = err_nowidgetfound; + } + return rc; +} + + + +/*! + *\~english + * Setting form widgets value. + * Must be implemented in inherited class. + *\~russian + * Функция установки значения виджетов формы. + * Должна быть реализована в наследующем классе. + *\~ + *\param value -\~english value. + \~russian Значение виджета. Имя у виджета уже есть в момент вызова этой функции. + \~ + */ +void +aWidget::setValue( const QString & value) +{ +} +/*! + *\~english + * Setting form widgets value of object type. + * Support type of widgets: wField, wDBField. + *\~russian + * Установка значения виджетов формы сложного типа. + * Поддерживаемые типы виджетов: wField, wDBField. + *\~ + *\param nameWidget -\~english Widget name. + \~russian Имя виджета. + \~ + *\param value -\~english value. + \~russian Значение виджета. + \~ + */ +int +aWidget::setObjValue( const QString & nameWidget, aObject *value ) +{ + QObject *w; + int rc= err_noerror; + w = Widget( nameWidget ); + if ( w ) { + if (w->inherits("wField") && value){ + ((aWidget*)w)->setValue(QString("%1").arg(value->getUid())); + } + } else { + //debug_message(tr("aForm::SetValue() Error! Can't find widget by name==`%s`\n"),(const char*) name.local8Bit()); + aLog::print(aLog::Error, tr("aWidget set value: not fount widget with name %1").arg(nameWidget) ); + rc = err_nowidgetfound; + } + return rc; +} + + +/*! + *\~english + *\~russian + *\~ + */ +bool +aWidget::isContainer() +{ + return false; +} + + + +/*! + *\~english + * Seting widget readonly flag. + * When widget readonly it's fields can't be edit, and make updatе action + *\~russian + * Устанавливает флаг толко чтение. + * Когда установлен этот флаг, запрещается редактирование полей виджета, + * и сохранение изменений в базу. + *\~ + *\param status - \~english New readonly flag.\~russian Новое значение флага только чтение.\~ + */ +void +aWidget::SetReadOnly ( bool status ) +{ +//CHECK_POINT + QObjectList l;// = this->queryList( "wField" ); + QObject *obj; + l = this->queryList( "aWidget" ); + QListIterator itl( l ); + while ( itl.hasNext() ) + { +// CHECK_POINT + obj = itl.next(); + (( aWidget *)obj)->SetReadOnly( status ); + } + //--delete l; // delete the list, not the objects + l = this->queryList( "QFrame" ); + QListIterator tl( l ); + while ( tl.hasNext() ) + { + //printf("QFrame classname '%s'\n", (const char*) obj->className() ); + obj = tl.next(); + if (obj->inherits("QTable")) (( Q3Table * )obj)->setReadOnly(true); + //else (( QFrame *)obj)->setDisabled( status ); + } + //--delete l; // delete the list, not the objects + //--l=0; +} + + +/*! + * + */ +qulonglong +aWidget::docId() +{ + if ( dbobj ) + { + return dbobj->docId(); + } + aLog::print(aLog::Error, tr("aWidget doc Id: invalid data source object") ); + return 0; +} + + + +QString +aWidget::widgetName(QWidget *obj) +{ + QString res=""; + if (obj) + { + if (obj->inherits("wDBField")) + { + res= ((aWidget*)obj)->getFieldName(); + } + else + { + res=obj->name(); + } + } + return res; +} + + + + +/*! + *\~english + * Return form widget pointer by name. + *\~russian + *\~ +*/ +QWidget* +aWidget::Widget( QWidget *owner, QString name ) +{ + QWidget *res = 0; + QWidget* obj; + QObjectList list = owner->queryList("QWidget"); + + QListIterator it(list); + while ( it.hasNext() ) { + obj = qobject_cast(it.next()); + if (!obj) continue; + if ( name == aWidget::widgetName( obj ) ) { + res = obj; + break; + } + } + return res; +} + + + +/*! + *\~english + * Return form widget pointer by name. + *\~russian + *\~ +*/ +QWidget * +aWidget::Widget( QString name, bool onlyMyWidgets ) +{ + QWidget *res = aWidget::Widget( this, name ); + if ( onlyMyWidgets && parentContainer( res ) != this ) res = 0; + return res; +} + + + +/*! + *\~english + * Return form widget pointer by name. + *\~russian + *\~ +*/ +aDataField* +aWidget::getAttribute( const QString & name ) +{ + aDataField *f = 0; + + return f; +} + + + +/*! + *\~english + * Return form widget pointer by name. + *\~russian + *\~ +*/ +int +aWidget::setAttribute( const QString & name, const aDataField *value ) +{ + return 0; +} + + +/*! + *\~english + * + *\~russian + * Обрабатывает события при нажатии кнопок клавиатуры. + *\~ + */ +void +aWidget::keyPressEvent ( QKeyEvent *e ) +{ +// switch ( e->key() ){ +// case Qt::Key_Escape: +// printf("ESC\n"); +// break; +// default: +// e->ignore(); +// break; +// } + + QWidget::keyPressEvent( e ); +} + diff --git a/src/lib/widgets/awidget.h b/src/lib/widgets/awidget.h new file mode 100644 index 0000000..e1fe08b --- /dev/null +++ b/src/lib/widgets/awidget.h @@ -0,0 +1,156 @@ +/**************************************************************************** +** $Id: awidget.h,v 1.1 2008/11/05 21:16:29 leader Exp $ +** +** Header file of the Ananas visual bject of Ananas +** Designer and Engine applications +** +** Created : 20031201 +** +** Copyright (C) 2003-2004 Leader InfoTech. All rights reserved. +** +** This file is part of the Library of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.leaderit.ru/page=ananas or email sales@leaderit.ru +** See http://www.leaderit.ru/gpl/ for GPL licensing information. +** +** Contact org@leaderit.ru if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#ifndef AWIDGET_H +#define AWIDGET_H +#include +#include +#include +//Added by qt3to4: +#include +#include "ananas.h" + +class QWidget; + + + +/*! + *\~english + * Base visual object. + *\~russian + * \brief Базовый класс для визуальных объектов. + * Наследует QWidget. + * + * От него наследуют свойства и методы такие визуальные объекты + * как контейнеры wDocument, wJournal, wCatalog, wDocument, wReport и виджеты wField, wDBField.\n + * + */ +class ANANAS_EXPORT aWidget : public QWidget +{ + Q_OBJECT +// Q_PROPERTY( QString Name READ getName WRITE setName STORED true DESIGNABLE false ) + Q_PROPERTY( int Id READ getId WRITE setId STORED true DESIGNABLE false ) + Q_PROPERTY( bool openEditor READ getOpenEditor WRITE setOpenEditor STORED false ) + Q_PROPERTY( int FormMode READ formMode WRITE setFormMode STORED true ) +public: + aDatabase* db; + aCfg* md; + aEngine* engine; + + aWidget( QWidget *parent = 0, const char *name = 0, Qt::WFlags fl = 0 ); + aWidget( const QString &oname, aDatabase *adb, QWidget *parent = 0, const char *name = 0, Qt::WFlags fl = 0 ); + aWidget( aCfgItem context, aDatabase *adb, QWidget *parent = 0, const char *name = 0, Qt::WFlags fl = 0 ); + virtual ~aWidget(); + + virtual bool checkStructure(); + virtual void initObject( aDatabase *adb ); + virtual void widgetEditor(); + static void widgetEditor( QWidget *object, QDialog *editor ); + virtual QDialog* createEditor( QWidget *parent ); + virtual Q3ToolBar* createToolBar( Q3MainWindow *parent ); + virtual aObject* createDBObject( aCfgItem obj, aDatabase * ); + virtual QString displayString(); + + void init( aDatabase *adb ); + bool getOpenEditor() const { return false; }; + void setOpenEditor( bool );// { widgetEditor(); }; + bool isInited() { return vInited; }; + virtual bool isContainer(); + void setInited( bool flag ){ vInited = flag; }; +// void formInsert( QWidget *widget, const QString &field ); +// void formRemove( const QString &field ); + static aWidget* parentContainer( QWidget *w ); + static aForm* parentForm( QWidget *w ); + aCfgItem* getMDObject(); + void setMDObject( aCfgItem object ); + aSQLTable* table( const QString &name = "" ); +// bool tableInsert( const QString &name ); +// bool tableRemove( const QString &name ); + void setObjectData( QWidget *object, aCfg *md ); + void getObjectData( QWidget *object ); + aCfg* getMd(); + virtual qulonglong uid(); + virtual ERR_Code New(); + virtual ERR_Code Update(); + virtual ERR_Code TurnOn(); + virtual ERR_Code Select( qulonglong id ); + aObject* dataObject(){ return dbobj; }; + + virtual qulonglong docId(); + int formMode() const { return vFormMode; }; + virtual void setFormMode( int mode ){ vFormMode = mode; }; + virtual QString getFieldName() const { return ""; }; + + static QString widgetName( QWidget *w ); + static QWidget* Widget( QWidget *owner, QString name ); + +// QString getName() const; +// void setName( QString fn ); + int getId() const { return vId ;}; + void setId( int fn ){ vId = fn; }; + +public slots: + virtual QVariant value( const QString & name ); + virtual QString value() const {return QString::null;}; + virtual QString textValue() {return QString::null;}; + virtual void setValue( const QString &); + virtual int setValue( const QString & name, const QVariant &value ); + virtual int setObjValue( const QString & nameWidget, aObject *value ); + virtual void SetReadOnly(bool); + virtual int Refresh(); + QWidget* Widget( QString name, bool onlyMyWidgets = true ); + + virtual aDataField* getAttribute( const QString & name ); + virtual int setAttribute( const QString & name, const aDataField *value ); + +signals: + void setData( QWidget *, aCfg * ); + void getData( QWidget * ); + void getMd( aCfg ** ); + void valueChanged( const QString &, const QVariant & ); + void valueChanged( const QString &, const QVariant &, const QString & ); + void changeObj(const QString &); + void changeObjId(const qulonglong); + void keyPressed(QKeyEvent *e); + +protected: + aObject *dbobj; + virtual void updateProp() {}; + virtual void keyPressEvent ( QKeyEvent * e ); +private: + bool vInited; + QString vName; + int vId, vFormMode; + aCfgItem obj; + Q3SqlForm* form; +// QDict dbtables; +}; + + +#endif diff --git a/src/lib/widgets/widgets.pri b/src/lib/widgets/widgets.pri new file mode 100644 index 0000000..bc23eaf --- /dev/null +++ b/src/lib/widgets/widgets.pri @@ -0,0 +1,5 @@ +HEADERS += \ + widgets/awidget.h + +SOURCES += \ + widgets/awidget.cpp diff --git a/src/plugins/README b/src/plugins/README new file mode 100644 index 0000000..d360b41 --- /dev/null +++ b/src/plugins/README @@ -0,0 +1,69 @@ +_Введение_ +В каждом каталоге находится код, реализующий ровно один плагин (plugin), предназначенный для +использования в QSA Designer. +С помощью этих плагинов реализуется связывание данных (data binding) +элементов настраиваемого пользовательского интерфейса Ананаса с базами, +хранящимися на SQL сервере, облегчающее +прикладному программисту-настройщику создание экранных форм-диалогов. + + +_Спецификация_ +Визуальные плагины ананас состоят из двух модулей: +- плагин, реализующий функциональность +- диалог конфигурации плагина в дизайнере Ананас + +Плагин реализует _только_ функциональность, необходимую для работы +в инициализированной форме диалога. Он не должен содержать функции, +необходимые для поддержки форм диалога. Плагин всегда вставляется в +объект-контейнер. Для получения дополнительной информации для +инициализации использовать функцию: +static aWidget *aWidget::parentContainer( QWidget *w ); + +Диалог конфигурации считывает и отображает свойства плагина, +позволяет редактировать их, используя статические функции +aWidget и aObject для получения указателей на метаданные, +контейнер плагина и дополнительной информации,сохраняет свойства +в плагине для записи в структуру формы. +Диалог должен считать всю необходимую информацию из метаданных +при установке параметров и в дальнейшем к метаданным не обращаться. +Функции для получения дополнительной информации: +static aWidget *aWidget::parentContainer( QWidget *w ); + +В режиме настройки плагин должен использовать _только_ метаданные +без обращения к базе данных, так как информация в БД не актуальна до +момента обновления структуры при сохранении метаданных. + +_Компилирование_ + +Makefile'ы генерируются командой qmake на основе содержимого *.pro файлов. +Для изменения процедуры компиляции следует вносить изменения в *.pro файлы. + +компилирование заключается в задании двух команд +qmake +make + +в каждом подкаталоге + + +_Установка_ + +После успешной компиляции необходимо скопировать получившиеся динамические библиотеки +в каталог /usr/lib, а лучше создать ссылку. +А также проверить появились ли они в каталоге +$(QTDIR)/plugins/designer + + +_Возможные проблеммы_ + +Если компиляция и копирование библиотек выполнено, а при запуске designer плагины +не отображаются в списке виджелов, попробуйте исправить содержимое файла *.pro, +убрав параметр +thread +в строке, начинающейся со слова CONFIG + +Удачи! + + + + + diff --git a/src/plugins/actionbutton/actionbutton.pri b/src/plugins/actionbutton/actionbutton.pri new file mode 100644 index 0000000..caf0592 --- /dev/null +++ b/src/plugins/actionbutton/actionbutton.pri @@ -0,0 +1,15 @@ +HEADERS += \ + actionbutton/eactionbutton.h \ + actionbutton/wactionbutton.h \ + actionbutton/wactionbutton_plugin.h \ + actionbutton/wactionbutton_taskmenu.h \ + +SOURCES += \ + actionbutton/eactionbutton.cpp \ + actionbutton/wactionbutton.cpp \ + actionbutton/wactionbutton_plugin.cpp \ + actionbutton/wactionbutton_taskmenu.cpp \ + +FORMS += \ + actionbutton/eactionbutton.ui + \ No newline at end of file diff --git a/src/plugins/actionbutton/eactionbutton.cpp b/src/plugins/actionbutton/eactionbutton.cpp new file mode 100644 index 0000000..76d9263 --- /dev/null +++ b/src/plugins/actionbutton/eactionbutton.cpp @@ -0,0 +1,138 @@ +#include "eactionbutton.h" + +#include +#include +#include + +#include +#include + +/* + * Constructs a eActionButton as a child of 'parent', with the + * name 'name' and widget flags set to 'f'. + * + * The dialog will by default be modeless, unless you set 'modal' to + * true to construct a modal dialog. + */ +eActionButton::eActionButton(QWidget* parent, const char* name, bool modal, Qt::WindowFlags fl) + : QDialog(parent, name, modal, fl) +{ + setupUi(this); + +} + +/* + * Destroys the object and frees any allocated resources + */ +eActionButton::~eActionButton() +{ + destroy(); + // no need to delete child widgets, Qt does it all for us +} + +/* + * Sets the strings of the subwidgets using the current + * language. + */ +void eActionButton::languageChange() +{ + retranslateUi(this); +} + +void eActionButton::Action_toggled( bool o ) +{ + Script->setChecked( !o ); + //else +} + + +void eActionButton::Script_toggled( bool o ) +{ + Action->setChecked( !o ); +} + +void eActionButton::setData( wActionButton *b ) +{ + if ( !b ) return; + if ( b->isAction() ) Action->setChecked( TRUE ); + if ( b->isActionUpdate() ) cbUpdate->setChecked( TRUE ); + if ( b->isActionTurnOn() ) cbTurnon->setChecked( TRUE ); + if ( b->isActionClose() ) cbClose->setChecked( TRUE ); + if ( b->isScript() ) Script->setChecked( TRUE ); +// cbAction->setCurrentItem(b->getAction()) + // eCode->setText( b->getScriptCode() ); +// button = b; + aWidget *wd = aWidget::parentContainer( b ); + if ( !strcmp(wd->name(),"Catalogue") ) + { + cbTurnon->setChecked( false ); + cbTurnon->setHidden( TRUE ); + +// b->setActionTurnOn( FALSE ); + } + aCfg *md = wd->getMd(); + QStringList l_name; + aCfgItem parent = md->find(mdc_actions); + l_id.clear(); + loadActions(&l_name, &l_id, parent, md); + cbAction->clear(); + cbAction->insertStringList(l_name); + cbAction->setCurrentItem( l_id.findIndex( QString("%1").arg(b->getActionId()) ) ); + +} + + +void eActionButton::getData( wActionButton *button) +{ + if ( !button ) return; + button->setAction( Action->isChecked() ); + button->setActionUpdate( cbUpdate->isChecked() ); + button->setActionTurnOn( cbTurnon->isChecked() ); + button->setActionClose( cbClose->isChecked() ); + button->setScript( Script->isChecked() ); + button->setActionUpdate( cbUpdate->isChecked() ); + if(cbAction->isEnabled()) + { + + button->setActionId ( atoi(l_id[cbAction->currentItem()].ascii())); + } + else + { + button->setActionId(0); + } +// button->setScriptCode( eCode->text() ); +} + +void eActionButton::destroy() +{ + //getData(); +} + + +void +eActionButton::loadActions( QStringList *lst, QStringList *id, aCfgItem p, aCfg *md ) +{ + aCfgItem cobj; + QString oclass; + if(p.isNull()) + { + p = md->find(mdc_actions); + // printf("parent were NULL, set parent to %s\n",md->objClass(p).ascii()); + } + + if(p.isNull()) return; + cobj = md->firstChild ( p ); + while ( !cobj.isNull() ) + { + oclass = md->objClass ( cobj ); + if ( oclass == md_actiongroup ) + loadActions ( lst, id, cobj, md ); + if ( oclass == md_action ) + { + lst->append(md->attr(cobj,mda_name)); + id->append(md->attr(cobj,mda_id)); + } + cobj = md->nextSibling ( cobj ); + } +} + diff --git a/src/plugins/actionbutton/eactionbutton.h b/src/plugins/actionbutton/eactionbutton.h new file mode 100644 index 0000000..592bdb9 --- /dev/null +++ b/src/plugins/actionbutton/eactionbutton.h @@ -0,0 +1,34 @@ +#ifndef EACTIONBUTTON_H +#define EACTIONBUTTON_H + +#include "ui_eactionbutton.h" + + +class eActionButton : public QDialog, public Ui::eActionButton +{ + Q_OBJECT + +public: + eActionButton(QWidget* parent = 0, const char* name = 0, bool modal = false, Qt::WindowFlags fl = 0); + ~eActionButton(); + +public slots: + virtual void Action_toggled( bool o ); + virtual void Script_toggled( bool o ); + virtual void setData( wActionButton *o ); + virtual void getData( wActionButton *o ); + +protected: + virtual void loadActions( QStringList *lst, QStringList *id, aCfgItem parent, aCfg *md); + +protected slots: + virtual void languageChange(); + +private: + QStringList l_id; + + void destroy(); + +}; + +#endif // EACTIONBUTTON_H diff --git a/src/plugins/actionbutton/eactionbutton.ui b/src/plugins/actionbutton/eactionbutton.ui new file mode 100644 index 0000000..e3d4541 --- /dev/null +++ b/src/plugins/actionbutton/eactionbutton.ui @@ -0,0 +1,206 @@ + + + + + eActionButton + + + + 0 + 0 + 484 + 228 + + + + Action button + + + + + + + 3 + 5 + 0 + 0 + + + + 0 + + + Simple action + + + true + + + false + + + false + + + false + + + + + + + + Update + + + + + + + Close + + + + + + + Turn on + + + + + + + + + + + + User action + + + true + + + false + + + false + + + false + + + + + + + + + 0 + 5 + 0 + 0 + + + + Execute + + + false + + + + + + + + + + + + + + + + + + 1 + 0 + 0 + 0 + + + + OK + + + + + + + + 1 + 0 + 0 + 0 + + + + Cancel + + + + + + + + 20 + 121 + + + + Expanding + + + Vertical + + + + + + + + + qPixmapFromMimeSource + + wactionbutton.h + awidget.h + + + + Action + toggled(bool) + eActionButton + Action_toggled(bool) + + + Script + toggled(bool) + eActionButton + Script_toggled(bool) + + + pushButton1 + clicked() + eActionButton + accept() + + + pushButton2 + clicked() + eActionButton + reject() + + + diff --git a/src/plugins/actionbutton/wactionbutton.cpp b/src/plugins/actionbutton/wactionbutton.cpp new file mode 100644 index 0000000..fb7bd7a --- /dev/null +++ b/src/plugins/actionbutton/wactionbutton.cpp @@ -0,0 +1,106 @@ +/**************************************************************************** +** $Id: wactionbutton.cpp,v 1.1 2008/11/05 21:16:29 leader Exp $ +** +** Header file of the table plugin of Ananas +** Designer and Engine applications +** +** Created : 20031201 +** +** Copyright (C) 2003-2004 Leader InfoTech. All rights reserved. +** +** This file is part of the Ananas Plugins of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.leaderit.ru/page=ananas or email sales@leaderit.ru +** See http://www.leaderit.ru/gpl/ for GPL licensing information. +** +** Contact org@leaderit.ru if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#include "wactionbutton.h" +#include "eactionbutton.h" +#include +#include +#include +#include "qobject.h" +#include "qobject.h" +//Added by qt3to4: +#include + +//--#include "command.h" +//--#include "formwindow.h" +//--#include "mainwindow.h" +//--#include "mainform.h" + +#include "adatabase.h" + +wActionButton::wActionButton( QWidget *parent, const char *name ) + : QPushButton( parent, "wActionButton") +{ + action = true; + actionId=0; + actionUpdate = actionTurnOn = actionClose = false; + connect( this, SIGNAL(clicked()), this, SLOT(onClick()) ); + +} + + +wActionButton::~wActionButton() +{ +} + + +void +wActionButton::openEditor() +{ + eActionButton *e = new eActionButton(this->topLevelWidget()); + aCfg *md; + e->setData(this); + if ( e->exec()==QDialog::Accepted ) + { + e->getData(this); + //updateProp(); + } + delete e; + e=0; +} + + + +void +wActionButton::onClick() +{ +//CHECK_POINT +} + +void +wActionButton::keyPressHandler ( QKeyEvent * e ) +{ + CHECK_POINT + switch(e->key()) + { + case Qt::Key_Return: + break; + case Qt::Key_Escape: + if(accel() == QKeySequence(Qt::Key_Escape)) + { + emit(clicked()); + e->accept(); + } + break; + + } + //printf("key pressed %c",e->ascii()); + //QWidget::keyPressEvent ( e ); + e->ignore(); +} diff --git a/src/plugins/actionbutton/wactionbutton.h b/src/plugins/actionbutton/wactionbutton.h new file mode 100644 index 0000000..d0d0823 --- /dev/null +++ b/src/plugins/actionbutton/wactionbutton.h @@ -0,0 +1,90 @@ +/**************************************************************************** +** $Id: wactionbutton.h,v 1.1 2008/11/05 21:16:29 leader Exp $ +** +** Header file of the table plugin of Ananas +** Designer and Engine applications +** +** Created : 20031201 +** +** Copyright (C) 2003-2004 Leader InfoTech. All rights reserved. +** +** This file is part of the Ananas Plugins of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.leaderit.ru/page=ananas or email sales@leaderit.ru +** See http://www.leaderit.ru/gpl/ for GPL licensing information. +** +** Contact org@leaderit.ru if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#ifndef WACTIONBUTTON_H +#define WACTIONBUTTON_H + +#include +#include +//Added by qt3to4: +#include +#include "acfg.h" + +class QWidget; + +class QT_WIDGET_PLUGIN_EXPORT wActionButton : public QPushButton +{ + Q_OBJECT + Q_PROPERTY( bool openEditor READ getOpenEditor WRITE setOpenEditor STORED false ) + Q_PROPERTY( bool action READ isAction WRITE setAction DESIGNABLE true ) + Q_PROPERTY( bool actionUpdate READ isActionUpdate WRITE setActionUpdate DESIGNABLE true ) + Q_PROPERTY( bool actionTurnOn READ isActionTurnOn WRITE setActionTurnOn DESIGNABLE true) + Q_PROPERTY( bool actionClose READ isActionClose WRITE setActionClose DESIGNABLE true) + Q_PROPERTY( int actionId READ getActionId WRITE setActionId DESIGNABLE true) + Q_PROPERTY( bool script READ isScript WRITE setScript DESIGNABLE true) +// Q_PROPERTY( QString scriptCode READ getScriptCode WRITE setScriptCode DESIGNABLE false) +public: + + wActionButton( QWidget *parent = 0, const char *name = 0 ); + virtual ~wActionButton(); + + void openEditor(); + + +public slots: + + void onClick(); + void keyPressHandler ( QKeyEvent * e ); + + bool getOpenEditor() const { return false; }; + void setOpenEditor( bool b ) { if( b ) openEditor(); }; + bool isAction() const { return action; }; + bool isActionUpdate() const { return actionUpdate; }; + bool isActionTurnOn() const { return actionTurnOn; }; + bool isActionClose() const { return actionClose; }; + int getActionId() const { return actionId; }; + bool isScript() const { return !action; }; + QString getScriptCode() const { return scriptCode; }; + + void setAction( bool a ) { action = a; }; + void setActionUpdate( bool a ) { actionUpdate = a; }; + void setActionTurnOn( bool a ) { actionTurnOn = a; }; + void setActionClose( bool a ) { actionClose = a; }; + void setActionId( int a ) { actionId = a; }; + void setScript( bool a ) { action = !a; }; + void setScriptCode( QString a ) { scriptCode = a; }; +private: + + bool action, actionUpdate, actionTurnOn, actionClose; + int actionId; + QString scriptCode; +}; + +#endif //WACTIONBUTTON_H + diff --git a/src/plugins/actionbutton/wactionbutton_plugin.cpp b/src/plugins/actionbutton/wactionbutton_plugin.cpp new file mode 100644 index 0000000..31026db --- /dev/null +++ b/src/plugins/actionbutton/wactionbutton_plugin.cpp @@ -0,0 +1,100 @@ +/**************************************************************************** +** +** Code file +** +** Copyright (C) 2006 Dmitriy Pavlyuk +** +** This file is part of the Ananas Plugins of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +**********************************************************************/ + +#include "wactionbutton_plugin.h" + +#include +#include +#include + +#include "wactionbutton_taskmenu.h" +#include "wactionbutton.h" + + +wActionButtonPlugin::wActionButtonPlugin(QObject *parent) + : QObject(parent), m_initialized(false) +{ + m_initialized = false; +} + +bool wActionButtonPlugin::isContainer() const +{ + return false; +} + +bool wActionButtonPlugin::isInitialized() const +{ + return m_initialized; +} + +void wActionButtonPlugin::initialize(QDesignerFormEditorInterface *core) +{ + if (m_initialized) + return; + Q_UNUSED(core); + + QExtensionManager *manager = core->extensionManager(); + Q_ASSERT(manager != 0); + manager->registerExtensions(new wActionButtonTaskMenuFactory(manager), + Q_TYPEID(QDesignerTaskMenuExtension)); + + m_initialized = true; +} + +QWidget *wActionButtonPlugin::createWidget(QWidget *parent) +{ + wActionButton *w = new wActionButton(parent); + return w; +} + +QString wActionButtonPlugin::name() const +{ + return QLatin1String("wActionButton"); +} + +QString wActionButtonPlugin::group() const +{ + return QLatin1String("Ananas"); +} + +QString wActionButtonPlugin::toolTip() const +{ + return QString("Ananas for QT Action button Widget"); +} + +QString wActionButtonPlugin::whatsThis() const +{ + return QString(); +} + +QString wActionButtonPlugin::includeFile() const +{ + return QLatin1String("wactionbutton.h"); +} + +QIcon wActionButtonPlugin::icon() const +{ + //return QIcon(); + return QIcon(":/images/wactionbutton.png"); +} + +QString wActionButtonPlugin::domXml() const +{ + return "\n\n"; +} diff --git a/src/plugins/actionbutton/wactionbutton_plugin.h b/src/plugins/actionbutton/wactionbutton_plugin.h new file mode 100644 index 0000000..9b03290 --- /dev/null +++ b/src/plugins/actionbutton/wactionbutton_plugin.h @@ -0,0 +1,53 @@ +/**************************************************************************** +** +** Header file +** +** Copyright (C) 2006 Dmitriy Pavlyuk +** +** This file is part of the Ananas Plugins of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +**********************************************************************/ + +#ifndef WACTIONBUTTON_PLUGIN_H +#define WACTIONBUTTON_PLUGIN_H + +#include + +#include "qwidgetplugin.h" + + +class QT_WIDGET_PLUGIN_EXPORT wActionButtonPlugin : public QObject, public QDesignerCustomWidgetInterface +{ + Q_OBJECT + Q_INTERFACES(QDesignerCustomWidgetInterface) + +public: + wActionButtonPlugin(QObject *parent=0); + + bool isContainer() const; + bool isInitialized() const; + void initialize(QDesignerFormEditorInterface *core); + QWidget *createWidget(QWidget *parent); + + QString name() const; + QString group() const; + QString toolTip() const; + QString whatsThis() const; + QString includeFile() const; + QIcon icon() const; + QString domXml() const; + +private: + bool m_initialized; +}; + +#endif // WACTIONBUTTON_PLUGIN_H diff --git a/src/plugins/actionbutton/wactionbutton_taskmenu.cpp b/src/plugins/actionbutton/wactionbutton_taskmenu.cpp new file mode 100644 index 0000000..3605c9e --- /dev/null +++ b/src/plugins/actionbutton/wactionbutton_taskmenu.cpp @@ -0,0 +1,75 @@ +/**************************************************************************** +** +** Copyright (C) 2006 Dmitriy Pavlyuk All rights reserved. +** +** This file is part of the widgets plugin of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +****************************************************************************/ + +#include + +#include + +#include "wactionbutton_taskmenu.h" +#include "wactionbutton.h" +#include "eactionbutton.h" + + +wActionButtonTaskMenu::wActionButtonTaskMenu(wActionButton *widget, QObject *parent) + : QObject(parent) +{ + m_widget = widget; + + m_editAction = new QAction(tr("Edit ..."), this); + connect(m_editAction, SIGNAL(triggered()), this, SLOT(edit())); +} + +void wActionButtonTaskMenu::edit() +{ + //eActionButton e(m_widget->topLevelWidget()); + /*eActionButton e; + + e.setData(m_widget); + if (e.exec() == QDialog::Accepted) + { + e.getData(m_widget); + }*/ + m_widget->openEditor(); +} + +QAction *wActionButtonTaskMenu::preferredEditAction() const +{ + return m_editAction; +} + +QList wActionButtonTaskMenu::taskActions() const +{ + QList list; + list.append(m_editAction); + return list; +} + +wActionButtonTaskMenuFactory::wActionButtonTaskMenuFactory(QExtensionManager *parent) + : QExtensionFactory(parent) +{ +} + +QObject *wActionButtonTaskMenuFactory::createExtension(QObject *object, const QString &iid, QObject *parent) const +{ + if (iid != Q_TYPEID(QDesignerTaskMenuExtension)) + return 0; + + if (wActionButton *ab = qobject_cast(object)) + return new wActionButtonTaskMenu(ab, parent); + + return 0; +} diff --git a/src/plugins/actionbutton/wactionbutton_taskmenu.h b/src/plugins/actionbutton/wactionbutton_taskmenu.h new file mode 100644 index 0000000..4d68b96 --- /dev/null +++ b/src/plugins/actionbutton/wactionbutton_taskmenu.h @@ -0,0 +1,57 @@ +/**************************************************************************** +** +** Copyright (C) 2006 Dmitriy Pavlyuk All rights reserved. +** +** This file is part of the widgets plugin of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +****************************************************************************/ + +#ifndef WACTIONBUTTON_TASKMENU_H +#define WACTIONBUTTON_TASKMENU_H + +#include +#include + + +class QExtensionManager; +class QAction; +class wActionButton; + +class wActionButtonTaskMenu: public QObject, public QDesignerTaskMenuExtension +{ + Q_OBJECT + Q_INTERFACES(QDesignerTaskMenuExtension) +public: + wActionButtonTaskMenu(wActionButton *widget, QObject *parent); + + QAction *preferredEditAction() const; + QList taskActions() const; + +private slots: + void edit(); + +private: + QAction *m_editAction; + wActionButton *m_widget; +}; + +class wActionButtonTaskMenuFactory: public QExtensionFactory +{ + Q_OBJECT +public: + wActionButtonTaskMenuFactory(QExtensionManager *parent = 0); + +protected: + QObject *createExtension(QObject *object, const QString &iid, QObject *parent) const; +}; + +#endif // WACTIONBUTTON_TASKMENU_H diff --git a/src/plugins/aform.cpp b/src/plugins/aform.cpp new file mode 100644 index 0000000..a108061 --- /dev/null +++ b/src/plugins/aform.cpp @@ -0,0 +1,1896 @@ +/**************************************************************************** +** $Id: aform.cpp,v 1.3 2008/12/10 21:04:56 leader Exp $ +** +** Code file of Ananas forms of Ananas +** Designer and Engine applications +** +** Created : 20031201 +** +** Copyright (C) 2003-2006 Leader InfoTech. All rights reserved. +** Copyright (C) Andrey Paskal , Yoshkar-Ola +** Copyright (C) Grigory Panov , Yoshkar-Ola +** +** This file is part of the Library of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.leaderit.ru/page=ananas or email sales@leaderit.ru +** See http://www.leaderit.ru/gpl/ for GPL licensing information. +** +** Contact org@leaderit.ru if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +//--#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +//--#include +#include +//--#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +//Added by qt3to4: +#include +#include +#include + +#include "aform.h" +#include "wcatalogue.h" +#include "wdocument.h" +#include "wjournal.h" +#include "wreport.h" +#include "wfield.h" +#include "wdbfield.h" +#include "wtable.h" +#include "wdbtable.h" +#include "wactionbutton.h" +#include "alog.h" +/*! +Base form object. +*/ +aForm::aForm( QWidget *parent, aEngine *eng ) +:QObject( eng, (QString("aForm%1").arg(eng->next_obj_id++)).ascii()) +{ + engine = eng; + db = eng->db; + md = &db->cfg; + parentWidget = parent; + form = 0; + closeAfterSelect = false; + RO=false; + callerWidget = NULL; + mode = 0; + db_uid=0; + objid=0; + init(); +} + + + +aForm::aForm( QWidget *parent, aEngine *eng, Q_ULONG form_mid, aWidget* caller ) +:QObject( eng, (QString("aForm%1").arg(eng->next_obj_id++)).ascii() ) +{ + aCfgItem obj; + + engine = eng; + db = eng->db; + md = engine->md; + parentWidget = parent; + form = 0; + closeAfterSelect = false; + mdObj = md->find( form_mid ); + objid = form_mid; + db_uid=0; + RO=false; + callerWidget = caller; + mode = 0; + init(); +} + +aForm::aForm( QWidget *parent, aEngine *eng, QString oftype, QObject *aobj ) +:QObject( eng, (QString("aForm%1").arg(eng->next_obj_id++)).ascii()) +{ + engine = eng; + db = eng->db; + md = &db->cfg; + parentWidget = parent; + db_uid=0; + objid=0; + form = 0; + closeAfterSelect = false; + RO=false; + mode = 0; + init(); + +} + + + +aForm::~aForm() +{ +} + +aWidget * +aForm::parentContainer( QWidget *w ) +{ + w = w->parentWidget(); + while ( w ) { + if ( w->inherits("aWidget") ) break; + w = w->parentWidget(); + } + return ( aWidget *) w; +} + + +/*! + *\~english + * Init container object, that not inherits from aWidget. + *\~russian + * Инициализирует объекты, которые не унаследованы от aWidget, но + * требуют инициализации, например wDBTable. + *\~ + */ +void +aForm::initWidget( QWidget *widget, aDatabase *adb ) +{ + QString oclass = widget->className(); + if (oclass == "wDBTable") ( ( wDBTable* ) widget )->init( adb, engine ); +} + + +/*! + *\~english + * Recursive init all form containers and widgets. + *\~russian + * Инициализирует все виджеты, унаследованные от aWidget + *\~ + */ +void +aForm::initContainer( aWidget *widget, aDatabase *adb ){ + + // Init subobjects. + if ( !widget->isContainer() ) return; + + widget->engine = engine; + widget->init( adb ); + QObjectList l = widget->queryList( "QWidget" ); + QListIterator it( l ); // iterate over all subwidgets + QObject *obj; + QString oclass; + aWidget *aw; +// QWidget *w; + // Init all container owned widgets + while ( it.hasNext() ) { + // for each found object... + obj = it.next(); + if ( !obj ) continue; + if ( parentContainer( ( QWidget *) obj ) != widget ) continue; + if ( obj->inherits("aWidget") ) { + aw = ( aWidget* ) obj; + aw->engine = engine; + if ( !aw->isContainer() ) + { + aw->init( adb ); + } + if ( form->inherits( "QMainWindow" ) ) aw->createToolBar( ( Q3MainWindow *) form ); + } else initWidget( ( QWidget *) obj, adb ); + } + it.toFront(); + // Init all container subcontainers + while ( it.hasNext() ) { + obj = it.next(); + if ( !obj ) continue; + if ( obj == widget ) continue; + if ( parentContainer( ( QWidget*) obj ) != widget ) continue; + if ( obj->inherits("aWidget") ) { + aw = ( aWidget* ) obj; + aw->engine = engine; + if ( aw->isContainer() ) initContainer( aw, adb ); + } + } + //delete l; +} + + +/*! + *\~english + * Init form, reparent central widget of form, if it needed. Evaluate script module. + *\~russian + * Инициализирует форму, меняет родителя у центрального виджера формы, если это необходимо. + * Обрабатывает также модуль скрипта, благодаря этому впоследствии можно вызывать + * функции, определенные в этом модуле. + *\~ + */ +void +aForm::init() +{ + QString ui, sModule; + aCfgItem obj; + static QMutex mutex; + mainWidget = 0; + if ( !mdObj.isNull() && md ) { + ui = md->sText( mdObj, md_formdesign ); + sModule = md->sText( mdObj, md_sourcecode ); + if ( !ui.isEmpty() ) { + //aLog::print(aLog::Debug, ui); + QByteArray buf = ui.toUtf8(); + QBuffer b(&buf); + //--b.open(QIODevice::WriteOnly); + + //--b.writeBlock( ( const char *) ui, strlen( ( const char *) ui) ); + //--b.close(); + b.open(QIODevice::ReadOnly ); + aLog::print(aLog::Info, tr("aForm creating form from ui")); + //--form = QWidgetFactory::create( &b ); + QFormBuilder fb; + fb.addPluginPath(QCoreApplication::applicationDirPath() /*"/plugins/designer"*/); + /*QList l = fb.customWidgets(); + int i; + for (i=0; iname()); + }*/ + form = fb.load(&b); + aLog::print(aLog::Info, tr("aForm form create from ui ok")); + b.close(); + } + } + if (form) { + Q3MainWindow *mw = new Q3MainWindow( parentWidget, "main form", Qt::WDestructiveClose ); + mw->statusBar()->hide(); + mw->setCaption( form->caption() ); + + printf("try find in windowslist %d, %llu\n ", objid, db_uid); + if ( engine->wl->find( objid, db_uid ) ) + { + printf("found, remove\n"); + engine->wl->remove( objid, db_uid ); + } + else + { + printf("not found\n"); + } + engine->wl->insert( objid, mw, db_uid ); + printf("insert new in wl ok\n"); + if ( form->inherits("QMainWindow" )){ + ((Q3MainWindow *) form)->statusBar()->hide(); + } + mainWidget = 0; + aCfgItem par = md->parent( md->parent( mdObj ) ); + if ( !form->inherits("aWidget")) + { + aLog::print(aLog::Error, tr("aForm do not inherits aWidget!")); + QMessageBox::critical( 0, tr("Error"), tr("Error while open dialog form. Init hasn't been completed.") ); + return; + } + // Create main widgets container. + if ( md->objClass( par ) == md_catalogue ) { + mainWidget = ( wCatalogue *) form; //new wCatalogue( mw ); + mw->setIcon( rcIcon("wcatalogue.png")); + } + if ( md->objClass( par ) == md_document ) { + mainWidget = ( wDocument *) form; //new wDocument( mw ); + mw->setIcon( rcIcon("wdocument.png")); + } + if ( md->objClass( par ) == md_journal ) { + mainWidget = ( wJournal *) form; //new wJournal( mw ); + mw->setIcon( rcIcon("wjournal.png")); + mw->statusBar()->show(); + mw->statusBar()->message(tr("New document - , Edit - , View - ")); + } + if ( md->objClass( par ) == md_report ) { + mainWidget = ( wReport *) form; + mw->setIcon( rcIcon("wreport.png")); + } + + if ( !mainWidget ) { + form->reparent( parentWidget, Qt::WDestructiveClose, QPoint(0, 0)); + delete mw; + } else { + form = mw; + mainWidget->setFormMode( md->attr( mdObj, mda_type ).toInt()); + mainWidget->createToolBar( mw ); + mw->resize( mainWidget->size() ); + mainWidget->reparent( mw, 0, QPoint(0, 0)); + mw->setCentralWidget( mainWidget ); + initContainer( mainWidget, db ); + mainWidget->show(); + form = mw; + mw->setFocusPolicy( Qt::NoFocus ); + } + //-- + ((QWorkspace*)engine->ws)->addWindow(form); + form->show(); + + connectSlots(); + if ( !sModule.isEmpty() ) + { + // engine->project.addObject(this); + engine->project.interpreter()->evaluate(sModule,this ); + aLog::print(aLog::Debug, tr("aForm load form module script")); + QStringList lst = engine->project.interpreter()->functions(this); + for(uint i=0; iattr( mdObj, mda_readonly ).toInt()) SetReadOnly(true); + } + else + { + aLog::print(aLog::Error, tr("aForm form not found")); + QMessageBox::critical( 0, tr("Error"), tr("Error open dialog form. Form not found.") ); + + } +} + +/*! + *\~english + * Return ananas contaner object for widget. + * Use for widget->init() function. + *\~russian + * Возвращает объект-контейнер для заданного виджета. + * \param widget - виджет, для которого необходимо найти объект-контейнер. + * \return объект контейнер. + *\~ +*/ +QWidget * +aForm::aParent( QWidget *widget ) +{ + QWidget *p = widget->parentWidget(); + QString pc; + while ( p ){ + pc = p->className(); + if ( pc == "wCatalogue") break; + if ( pc == "wDocument") break; + p = p->parentWidget(); + } + return p; +} + + +/*! + *\~english + * Show form. Move it in left top corner of workspace. + *\~russian + * \brief ScriptAPI. Показывает форму на экране. + * + * Перемещает ее в левый верхний угол рабочего пространства. Вызывает функцию on_formstart() скрипта модуля + * экранной формы, если функция определена в модуле. + * + * \see close + *\~ +*/ +void +aForm::Show() +{ + if ( form ) + { + if ( engine->project.interpreter()->functions( this ).findIndex("on_formstart")!=-1) + { + engine->project.interpreter()->call("on_formstart", QVariantList(), this); + } + form->show(); + ((QWidget*)form->parent())->move(0,0); + connect( form, SIGNAL(destroyed()), this, SLOT(close()) ); + } +} + +/** + * \brief Deprecated. See Show() + */ +void +aForm::show() { + aLog::print(aLog::Debug,tr("Deprecated method call: aForm::show()")); + this->Show(); +} + + +/*! + *\~english + * Close form. Delete this pointer after close. + *\~russian + * \brief ScriptAPI. Закрывает и уничтожает форму. + * + * Вызывает функцию on_formstop() + * скрипта модуля экранной формы, если функция определена в модуле. + * + * \see show + *\~ +*/ +void +aForm::Close() { + // don't call function name() in this place in Win32 - crash + emit(closeForm(selectedCatId())); + on_form_close(); //to run ananas-script + + if( form ) { + if( form->isShown() ) { + aLog::print(aLog::Debug,tr("aForm::Close() hides form")); + disconnect( form ); + form->hide(); + } + } + if( engine && engine->wl ) { + engine->wl->remove( objid, db_uid ); + } + deleteLater(); +} + +/** + * \brief Deprecated + */ +void +aForm::close() { + aLog::print(aLog::Debug,tr("Deprecated method call: aForm::close(). Use aForm::Close() instead")); + this->Close(); +} + +/** + * \brief Deprecated + */ +int +aForm::turn_on(){ + aLog::print(aLog::Debug,tr("Deprecated method call: aForm::turn_on()")); + return SignIn(); +} + +/*! + *\~english + * Turn on document. + *\~russian + * \brief ScriptAPI. Проводит (регистрирует) документ. + * + * Вызывает функцю on_conduct() кода Ананас.скрипта модуля экранной формы. + * В скрипте вы можете проверить условия проведения документа, + * и, если они не выполняются, вернуть в функции false. + * Если функция возвращает false, то отметка о проведении не ставится. + *\~ + */ +int +aForm::SignIn(){ + QVariant res; + if ( form && !mainWidget->dataObject()->IsConducted()) + { + if ( engine->project.interpreter()->functions( this ).findIndex("on_conduct")!=-1) + { + res = engine->project.interpreter()->call("on_conduct",QVariantList(), this); + } + } + //--if(res.type()==QSArgument::Variant) + { + // if return false + if(res.toBool()==false && res.type()!=QVariant::Invalid) + { + aLog::print(aLog::Info, tr("aForm conduct: function on_conduct() return false, document not conducted")); + return 0; + } + } + return mainWidget->TurnOn(); +} + +/** + * \brief Deprecated + */ +int +aForm::turn_off(){ + aLog::print(aLog::Debug,tr("Deprecated method call: aForm::turn_off()")); + return SignOut(); +} + +/*! + *\~english + * Turn off document. Do nothing. + *\~russian + * \brief ScriptAPI. Отменяет проведение (регистрацию) документа. + * + * На самом деле ничего не делает. Отмена проведения производится при открытии + * документа. + *\~ + */ +int +aForm::SignOut(){ + return 0; +} + +/** + * \brief Depticated + */ +ERR_Code +aForm::update(){ + aLog::print(aLog::Debug,tr("Deprecated method call: aForm::update()")); + return this->UpdateDB(); +} + +/*! + *\~english + * Update object. + *\~russian + * \brief ScriptAPI. Обновляет данные в базе. + *\~ + */ +ERR_Code +aForm::UpdateDB() +{ + ERR_Code rc = err_noerror; + aWidget* aw = NULL; + + if ( RO ) return err_readonly; + rc = mainWidget->Update(); + if (!rc && callerWidget!=NULL) + { + emit( changedData()); + emit( update( db_uid ) ); + } + return rc; +} + +/*! + *\~english + * do nothing. + *\~russian + * Ничего не делает. + *\~ +char* +aForm::formMetaObjectId(QString filename){ +// if (filename==""){ +// } +// return aot_doc; + return ""; +} + */ + + + +//QString +//aForm::widgetName(QObject *obj){ +// return aWidget::widgetName( ( QWidget *) obj ); +/* + QString res=""; + + if (obj) { +*/ +/* + if (!strcmp(obj->className(),"QAnanasField")) res=((QAnanasField *)obj)->getName(); + else + if (!strcmp(obj->className(),"QAnanasDBField")) res=((QAnanasDBField *)obj)->getName(); + else + if (!strcmp(obj->className(),"QAnanasTable")) res=((QAnanasTable *)obj)->getName(); + else +*/ +/* if (!strcmp(obj->className(),"wDBField")) { + res= ((wDBField*)obj)->getMdFieldName(); +// printf("wdbfield name=%s\n",(const char*)((wDBField*)obj)->getMdFieldName().local8Bit()); + } else { + res=obj->name(); + } + } + return res; +*/ +//} + + + +/*! + *\~english + * Return form widget pointer by name. + *\~russian + * \brief ScriptAPI. Возвращает указатель на виджет по его имени. + * + * Очень полезная функция для работы с QT виджетами, находящимися в экранной форме. Используя этот метод, + * можно получить доступ к методам любого виджета, лежащего в форме. + * ВАЖНО! Из Ананас скрипта вы сможете обратиться только к публичным слотам и свойствам виджета. Публичные методы + * виджета из Ананас скрипта недоступны. + * Документацию по свойствам и методам QT виджетов смотрите на сайте http://trolltech.com + * + * \code + * // допустим в экранной форме есть виджет myCheckBox, являющийся экземпляром класса QCheckBox + * + * var myBox = Widget("myCheckBox"); //возвращает указатель на объект + * if ( myBox.checked ) { // Проверяем значение свойства checked + * sys.Message(0, "Yes" ); + * } else { + * sys.Message(0, "No" ); + * } + * + * // К сожалению мы не имеем доступа к методам setChecked() и isChecked(), так как они не являются публичными слотами. + * + * \endcode + * \see aWidget::Widget() + *\~ +*/ +QWidget * +aForm::Widget( QString name ) +{ + return mainWidget->Widget( name ); +} + +//QObject * +//aForm::findWidget( QString name ){ + +// return mainWidget->Widget( name ); +/* + QObject *res=NULL; + QObject* obj; + QObjectList* list = form->queryList("QWidget"); + + QObjectListIt it(*list); + while ( ( obj = it.current() ) !=0 ) { + ++it; + if (!obj) continue; + if (name==widgetName(obj)) { + res=obj; + break; + } + } + delete list; + return res; +*/ +//} + + +/*! + *\~english + * Connecting widget slots to form. + *\~russian + * Коннектит некоторые слоты объектов формы. + * Обеспечивает работу функций ананас скрипта + * on_valuechanged(), on_button(), on_tabvaluechanged(), etc. + *\~ + */ +void +aForm::connectSlots() +{ + QObject* obj; + if ( !form ) return; + QObjectList list = form->queryList("QWidget"); + if ( mainWidget->inherits("aWidget") ) + connect( mainWidget, SIGNAL( valueChanged( const QString &, const QVariant & ) ),\ + this, SLOT( on_valueChanged( const QString &, const QVariant & ) ) ); + + QListIterator it(list); + while ( it.hasNext() ) { + obj = it.next(); + if (!obj) continue; + if ( obj->inherits("wActionButton" )){ + connect( obj, SIGNAL( clicked() ), this, SLOT( on_actionbutton() ) ); + connect( mainWidget, SIGNAL( keyPressed(QKeyEvent*) ), obj, SLOT( keyPressHandler(QKeyEvent*) ) ); + // continue; + } + if ( obj->inherits("QPushButton" )){ + connect( obj, SIGNAL( clicked() ), this, SLOT( on_button() ) ); + continue; + } + if ( obj->inherits("wDBTable" )){ + connect( obj, SIGNAL( currentChanged( QSqlRecord * ) ), this, SLOT( on_dbtablerow( QSqlRecord * ) ) ); + connect( obj, SIGNAL( deleteLine( QSqlRecord * ) ), this, SLOT( on_tabupdate( QSqlRecord * ) ) ); + + connect(obj, SIGNAL(updateCurr(int,int) ), + this, SLOT( on_tabvalueChanged(int, int) ) ); +// connect( obj, SIGNAL( primeUpdate( QSqlRecord * ) ), this, SLOT( on_tabupdate( QSqlRecord * ) ) ); + connect( obj, SIGNAL( selected( qulonglong ) ), this, SLOT( on_tabselected( qulonglong ) ) ); + connect( obj, SIGNAL( selectRecord( qulonglong ) ), this, SLOT( on_tablerow( qulonglong ) ) ); + continue; + } + } + //--delete list; +} + +void +aForm::on_tabupdate( QSqlRecord *rec ) +{ +} + +/*! + * \ru + * \brief ScriptAPI. Возвращает значение поля экранной формы. + * + * Например, значение поля шапки "Номер" приходной накладной. + * Слот предназначен для использования Ананас-Скриптом. + * \param name - имя поля, как оно определено в метаданных. Например, "Номер" или "Покупатель". + * \return значение поля. Необходимо понимать, что если поле имеет сложный тип данных, например + * его значение задается выбором элемента из справочника товаров, то будет возвращено текстовое + * представление товара (его название), а не ссылка на составной объект, хранящий все атрибуты товара. + * Для того что бы получить доступ к составному объекту, для обращения ко всем атрибутам товара + * необходимо воспользоваться функцией DBValue(); + *\see aForm::DBValue() + +Пример кода для размещения в модуле экранной формы. Экранная форма содержит одну кнопку с именем Button1 и +поле ввода LineEdit1. +После ввода значения, следует нажать на кнопку и в окно сообщений будет выведено только что введенное значение. + + +\code +function on_button(buttonName) // обработчик нажатия кнопки +{ + if(buttonName=="Button1") // Button1 - имя кнопки, данное ей в дизайнере + { + // Получаем значение поля LineEdit1 экранной формы + str = Value("LineEdit1"); + + // Выводим в окно сообщений, полученное значение + StatusMessage(str); + } +} +\endcode + * \_ru + */ +QVariant +aForm::Value(const QString &name) +{ + QVariant res= mainWidget->value( name ); //value(); + if(res.type()==QVariant::ULongLong || res.type()==QVariant::LongLong) + { + res = res.toString(); + } + //if(res.type()==QVariant::DateTime) + //{ + // res = res.toDateTime().toString(ISODate); + //} + return res; + +/* + aObject *o = 0; + if ( mainWidget ) o = mainWidget->dataObject(); + if ( o ) { + res = o->Value( name ); + } + if ( res.type() != QVariant::Invalid ) return res; + else printf("no field %s in data object\n", ( const char *) name ); +*/ +/* + w = findWidget( name ); + if ( w ) { + if (!strcmp(w->className(),"wDBField")){ + res=( (wDBField*)w )->text(); //value(); + } else if (w->inherits("wField")){ + res=( (wField*)w )->text(); //value(); + } else if (!strcmp(w->className(),"QPushButton")){ + res=((QPushButton *)w)->text(); + } else if (!strcmp(w->className(),"QLabel")){ + res=((QLabel*)w)->text(); + } else if (!strcmp(w->className(),"QLineEdit")){ + res=((QLineEdit*)w)->text(); + } else if (!strcmp(w->className(),"QDateEdit")){ + res=((QDateEdit*)w)->date().toString(Qt::ISODate); + } + } else { + debug_message(tr("Error! Can't find widget by name==`%s`\n"),(const char*) name.local8Bit()); + } + return res; +*/ +} + + +/*! + *\~english + * Getting widgets value, inherited aWidget. + *\~russian + * \brief ScriptAPI. Возвращает значение атрибута бизнес объекта Ананаса. + * + * Предназначен для использования в контексте экранной формы редактирования бизнес объекта. + * Или, говоря по другому, в модуле экранной формы. + * Тип возвращаемого значения такой же, как задан в метаданных у соответствующего атрибута бизнес объекта. + * Для поля типа Каталог или Документ функция вернет число (id). + * Функция необходима, если нужно заполнять поля сложных типов. + * Для остальных случаев можно использовать aForm::Value(), обеспечивающее доступ к значению виджета экранной формы, + * в контексте которой исполняется Скрипт. + *\~ + *\param name -\~english Widget name. For wDBField this parameter must be name field of metadata. + \~russian Имя атрибута бизнес объекта, как задано в метаданных. + \~ + +Пример кода для размещения в модуле экранной формы. Экранная форма содержит одну кнопку с именем Button1. +При нажатии на кнопку в окно сообщений будет выведено значение атрибута "Покупатель" редактируемого бизнес объекта. + + +\code +function on_button(buttonName) // обработчик нажатия кнопки +{ + if(buttonName=="Button1") // Button1 - имя кнопки, данное ей в дизайнере + { + // Получаем значение атрибута "Покупатель" редактируемого бизнес объекта + contragent = DBValue("Покупатель"); + + // Выводим в окно сообщений, полученное значение + StatusMessage(contragent); + } +} +\endcode +\~ + */ +QVariant +aForm::DBValue(const QString &name) +{ + QObject *w; + QVariant res; + w = Widget( name ); + if ( w ) + { + if (!strcmp(w->className(),"wDBField")) + { + res=( (wDBField*)w )->value(); //value(); + if(res.type()==QVariant::ULongLong || res.type()==QVariant::LongLong) + { + res = res.toString(); + } + //if(res.type()==QVariant::DateTime) + //{ + // res = res.toDateTime().toString(ISODate); + //} + } + else + { + if (w->inherits("wField")) + { + res=( (wField*)w )->value(); //value(); + } + if(res.type()==QVariant::ULongLong || res.type()==QVariant::LongLong) + { + res = res.toString(); + } + //if(res.type()==QVariant::DateTime) + //{ + // res = res.toDateTime().toString(ISODate); + //} + } + } + else + { + aLog::print(aLog::Error, tr("aForm not found widget with name %1").arg(name)); + } + return res; +} + + +/*! + *\~english + * Setting form widgets value of object type. + *\~russian + * \brief ScriptAPI. Устанавливает значения виджетов формы сложных типов (aDocument, aCatalogue) + * + * Обычно для установки значения используют SetValue(...) + *\~ + * \see SetValue(...) + *\param tname -\~english Widget name. + \~russian Имя виджета. + \~ + */ +int +aForm::SetObjValue(const QString &name, aObject *value) +{ + return mainWidget->setObjValue( name, value ); +} + +/*! + *\~english + * Setting form widgets value. + *\~russian + * \brief ScriptAPI. Устанавливает значения виджетов экранной формы. + *\~ + * \see aWidget::setValue() + *\param name -\~english Widget name. + \~russian Имя виджета. + \~ + *\param value -\~english Widget value. + \~russian Значение виджета. Для сложных типов (Документ,Каталог) должен использоваться идентификатор. + * Если идентификатор недоступен, используйте функция SetObjValue(), которая принимает в качестве + * параметра ссылку на объект. + \~ + */ +int +aForm::SetValue(const QString &name, QVariant value) +{ + return mainWidget->setValue( name, value ); +/* + QObject *w; + int rc= err_noerror; + + w = findWidget( name ); + if ( w ) { + if (!strcmp(w->className(),"wDBField")){ + ((wDBField*)w)->setValue(value.toString()); + } else if (w->inherits("wField")){ + ((wField*)w)->setValue(value.toString()); + } else if (!strcmp(w->className(),"QPushButton")){ + ((QPushButton *)w)->setText( value.toString() ); + } else if (!strcmp(w->className(),"QLabel")){ + ((QLabel*)w)->setText( value.toString() ); + } else if (!strcmp(w->className(),"QLineEdit")){ + ((QLineEdit*)w)->setText( value.toString() ); + } + } else { + debug_message(tr("aForm::SetValue() Error! Can't find widget by name==`%s`\n"),(const char*) name.local8Bit()); + rc = err_nowidgetfound; + } + return rc; +*/ +} + +/*! + *\~english + * Setting column readonly flag. + * When column readonly, user can't edit value of this column. + *\~russian + * \brief ScriptAPI. Устанавливает для столбца таблицы флаг только чтение. + * + * Когда установлен этот флаг, пользователь не может редактировать значения в этом столбце. + *\~ + *\param tname - \~english Table name.\~russian Имя таблицы.\~ + *\param numCol - \~english Column number.\~russian Номер столбца.\~ + *\param ro - \~english `Readonly' flag value.\~russian Значение флага `только чтение'.\~ + */ +void +aForm::SetColumnReadOnly(const QString &tname, int numCol, bool ro) +{ + QObject *w; + w = Widget( tname ); + if ( w ) + { + if (!strcmp(w->className(),"wDBTable")) + { + ((wDBTable*)w)->setColumnReadOnly(numCol,ro); + } + } + else + { + aLog::print(aLog::Error, tr("aForm not found widget with name %1").arg(tname)); + } + + return; +} + + +/*! + *\~english + * Count table row. + *\~russian + * \brief ScriptAPI. Возвращает количество строк в табличном виджете wDBTable. + * + * Если табличный виджет не является объектом класса wDBTable, + * метод запишет в лог сообщение об ошибке и вернет 0. + *\~ + *\param tname - \~english Table name.\~russian Имя таблицы.\~ + *\return - \~english Number rows of table.\~russian Количество строк в таблице.\~ + */ +int +aForm::TabCount(const QString &tname) +{ + int res=0; + QObject *w; + w = Widget( tname ); + if ( w ) + { + if (!strcmp(w->className(),"wDBTable")) + { + res=( (wDBTable*)w )->numRows() ; //value(); + } + else + { + aLog::print(aLog::Error, tr("Expected wDBTable widget but found %1").arg(w->className())); + } + } + else + { + aLog::print(aLog::Error, tr("aForm not found widget with name %1").arg(tname)); + } + + return res; + +} + +/** + * \ru + * \brief ScriptAPI. Добавляет новую строку в табличный виджет wDBTable. + * + * \param tname - имя виджета + * \_ru + */ +void +aForm::TabNewLine(const QString &tname) +{ + QObject *w; + + w = Widget( tname ); + if ( w && !strcmp(w->className(),"wDBTable")) + { + wDBTable *wdb = (wDBTable*)w; + Q3SqlCursor *cur = wdb->sqlCursor(); + QSqlRecord *buffer = cur->primeInsert(); + wdb->lineInsert(buffer); + cur->insert(); + } + else + { + aLog::print(aLog::Error, tr("aForm not found wDBTabe widget with name %1").arg(tname)); + } +} + +void +aForm::TabUpdate(const QString &tname) +{ + QObject *w; + + w = Widget( tname ); + if ( w && !strcmp(w->className(),"wDBTable")) + { + wDBTable *wdb = (wDBTable*)w; + Q3SqlCursor *cur = wdb->sqlCursor(); + //QSqlRecord *buffer = cur->primeInsert(); + // wdb->lineInsert(buffer); + cur->primeUpdate(); + cur->update(); + } + else + { + aLog::print(aLog::Error, tr("aForm not found wDBTabe widget with name %1").arg(tname)); + } +} +/** + * \ru + * \brief ScriptAPI. Возвращает значение ячейки табличного виджета wDBTable. + * + * + * Если табличный виджет не является объектом класса wDBTable, метод запишет сообщение + * об ошибке в лог и вернет строку "Unknown". + * То есть он предназначен только для работы с таблицами привязанными (binded) к + * табличным частям бизнес объектов Ананаса. Если в ячейке хранится сложный тип данных (Документ, Элемент справочника) + * будет возвращен уникальный идентификатор объекта, а не его текстовое представление, которое видит пользователь. + * Для получения текстового представления сложного объекта воспользуйтесь методом aForm::TabDBValue. + * + * \param tname - имя виджета + * \param row - индекс строки таблицы + * \param col - индекс столбца таблицы + * \return значение ячейки табличного виджета + * \see aForm::TabDBValue(...) + * \_ru + * + */ +QVariant +aForm::TabValue(const QString &tname, int row, int col) +{ + return tabValue(tname,row,col,true); +} + +/** + * \ru + * \brief ScriptAPI. Возвращает значение ячейки табличного виджета wDBTable для сложного типа данных. + * + * + * Если табличный виджет не является объектом класса wDBTable, метод запишет сообщение + * об ошибке в лог и вернет строку "Unknown". + * То есть он предназначен только для работы с таблицами привязанными (binded) к + * табличным частям бизнес объектов Ананаса. + * В отличие от aForm::TabValue, который вернет числовой идентификатор, в случае, если ячейка имеет сложный тип данных, + * aForm::TabDBValue вернет текстовое представление, которое видит в таблице пользователь. + * + * \param tname - имя виджета + * \param row - индекс строки таблицы + * \param col - индекс столбца таблицы + * \return значение ячейки табличного виджета + * \see aForm::TabValue(...) + * \_ru + * + */ +QVariant +aForm::TabDBValue(const QString &tname, int row, int col) +{ + return tabValue(tname,row,col,false); +} + + +QVariant +aForm::tabValue(const QString &tname, int row, int col, bool dbval) +{ + QVariant res=QString::QString("Unknown"); + QObject *w; + QStringList l; + w = Widget( tname ); + if ( w && !strcmp(w->className(),"wDBTable")) + { + wDBTable *wdb = (wDBTable*)w; + if(wdb->getDefIdList().count()>col && col>=0) + { + long f_oid = wdb->getDefIdList()[col].toLong(); + QString type = wdb->getFieldType(f_oid); + if(row==-1) + { + row = wdb->currentRow(); + } + if(type.left(1) == "O" && dbval) + { + res = ananas_objectstr(db, wdb->value(row,col).toULongLong(), type.section(' ',1,1).toInt()); + } + else + { + res = wdb->value(row,col); + //if( res.type() == QVariant::DateTime || res.type() == QVariant::Date ) + //{ + // res = QString("%1").arg(res.toDateTime().toString(Qt::ISODate)); + //} + } + } + else + { + aLog::print(aLog::Error, tr("aForm table value: column out of range")); + } + } + else + { + aLog::print(aLog::Error, tr("aForm not found widget with name %1").arg(tname)); + } + return res; +} + + +/*! + *\~english + * Return column index in table \param tname. + *\~russian + * \brief ScriptAPI. Возвращает индекс столбца таблицы tname по его имени в метаданных. + *\~ + * \param tname - \~english Table name.\~russian Имя таблицы.\~ + * \param colname - \~english Column name.\~russian Имя столбца.\~ + * \return \~english Column index.\~russian Индекс столбца.\~ + */ +int +aForm::ColIndex(const QString &tname, const QString &colname) +{ + int res; + QObject *w; + int col=-1; + w = Widget( tname ); + if ( w && !strcmp(w->className(),"wDBTable")) + { + wDBTable *wdb = ((wDBTable*)w ); + col= wdb->getDefFields().findIndex(colname); + } + else + { + aLog::print(aLog::Error, tr("aForm not found widget with name %1").arg(tname)); + } + return col; +} + + +/** + * \ru + * \brief ScriptAPI. Задает значение ячейки табличного виджета wDBTable. + * + * \param tname - имя таблицы + * \param colname - имя столбца + * \param row - номер строки + * \param value - значение + * \_ru + */ +void +aForm::SetTabValue(const QString &tname, const QString &colname, int row, QVariant value) +{ + QObject *w; + w = Widget( tname ); + if ( w && !strcmp(w->className(),"wDBTable")) + { + // printf(">>>>>>>>>>>>>>Set tab value %s, for %s, rov = %d, value = %s\n",(const char*)tname.local8Bit(), (const char *)colname.local8Bit(), row, (const char*)value.toString().local8Bit() ); + wDBTable *wdb = (wDBTable*)w; + aSQLTable *t = ( aSQLTable *) wdb->sqlCursor(); + t->select(QString("idd=%1").arg(mainWidget->uid())); + t->first(); + if(t->seek(row)) + { + t->setValue(colname,value); + t->Update(); + //t->update(); + } + wdb->refresh();//updateCurrent(); + // wdb->setValue(row, col, value); + //res = wdb->text(row,col); + } + else + { + aLog::print(aLog::Error, tr("aForm not found wDBTable widget with name %1").arg(tname)); + } + + return; + +} + + + +/** + * \brief Deprecated + */ +void +aForm::done( int rc ){ + aLog::print(aLog::Debug,tr("Deprecated method call: aForm::done(...)")); + rc=rc; +// if (form) form->done(rc); +} + +/** + * \brief Deprecated + */ +void +aForm::setfocus(QString fname){ + aLog::print(aLog::Debug,tr("Deprecated method call: aForm::setfocus()")); +// QWidget *w; +// w=(QWidget *) form->child(fname,"QWidget"); +// if (w) w->setFocus(); +} + +/** + * + */ +void +aForm::SetFocus(){ +// aLog::print(aLog::Debug,tr("Deprecated method call: aForm::setfocus()")); +// QWidget *w; +// w=(QWidget *) form->child(fname,"QWidget"); + if(form) form->setFocus(); +} + +void +aForm::on_button(){ + if ( engine->project.interpreter()->functions(this).findIndex("on_button")!=-1) + { + engine->project.interpreter()->call("on_button",QVariantList()<name(),this); +// engine->code->evaluate("on_button(\""+sender()->name()+"\")", this); + } +} + + + +/*! + *\~english + * Action button pressed. + *\~russian + *\~ + */ +void +aForm::on_actionbutton() +{ + wActionButton *b = ( wActionButton *) sender(); + if ( b ) { + if ( b->isAction() ) { + if ( b->isActionUpdate() ) update(); + if ( b->isActionTurnOn() ) turn_on(); + if ( b->isActionClose() ) + { + if(form) + if( form->isShown() ) + { +//#ifndef _Windows + form->disconnect(); + form->hide(); +//#endif + } + close(); + } + } else { + if(b->getActionId()) + { + aCfgItem item = md->find(b->getActionId()); + engine->execAction( item, this); + } + } + } +} + + + +void +aForm::on_return(){ +} + + +void +aForm::on_lostfocus(){ +} + + +void +aForm::on_form_close(){ + if(!engine) return; + if ( engine->project.interpreter()->functions(this).findIndex("on_formstop")!=-1) { + engine->project.interpreter()->call("on_formstop", QVariantList(),this); + } +} + + +void +aForm::on_valueChanged(const QString &s){ +// char buf[200]; +/* + const QObject *sobj=sender(); + QString objName=widgetName((QObject *) sobj); + cfg_message(0, "value changed %s (%s)\n", (const char *) objName.utf8(), (const char *) dbobject->className()); + cfg_message(0, "classname %s\n", (const char *) sobj->className()); + if (strcmp(sobj->className(),"QAnanasDBField")==0) { +// if (sobj->className()=="QAnanasDBField") { + cfg_message(0,"OK"); + if (dbobject->className()=="QAdoc"){ + ((QAdoc *)dbobject)->setfield(objName, s); + } + if (dbobject->className()=="QAcat"){ + cfg_message(0,"Поле справочника %s=%s\n",(const char *) objName.utf8(), (const char *) s.utf8()); + ((QAcat *)dbobject)->setfield(objName, s); + } + } +*/ +} + + + +/*! + *\~english + * Process field value changed. + * Connect on main widget signal, and work only with it fields. + * Call afta widget process change field value signal. + *\~russian + * Обрабатывает изменение значения поля + * Присоединяется на сигнал главнов виджета формы + * и обрабатывает только изменение его полей. + * Сигнал вызывается виджетом, после того, как он сам обработает новое значение. + *\~ + *\param name - \~english field metedata name \~russian имя поля в конфигурации.\~ + *\param value - \~english new field value \~russian новое значение поля. \~ + */ +void +aForm::on_valueChanged( const QString & name, const QVariant & val ) +{ + + if ( engine->project.interpreter()->functions(this).findIndex("on_valuechanged")!=-1) + { + Q3ValueList lst; + lst << name; + lst << val; +// if(!val.isNull() && !val.isValid()) v = val; + engine->project.interpreter()->call("on_valuechanged",QVariantList(lst), this); + // printf("aForm change value field %s to %s\n",(const char*)name.local8Bit(), val.toString().ascii()); + } +} + + +void +aForm::on_tabvalueChanged(int row, int col) +{ + + if ( engine->project.interpreter()->functions(this).findIndex("on_tabupdate")!=-1) + { + Q3ValueList lst; + lst << row; + lst << col; + lst << sender()->name(); + + engine->project.interpreter()->call("on_tabupdate",QVariantList(lst), this); + } +/* + const QObject *sobj=sender(); + QString objName=widgetName((QObject *) sobj); + cfg_message(0, "value changed %s (%s)\n", (const char *) objName.utf8(), (const char *) dbobject->className()); + cfg_message(0, "classname %s\n", (const char *) sobj->className()); + if (strcmp(sobj->className(),"QAnanasDBTable")==0) { +// if (sobj->className()=="QAnanasDBField") { +*/ +/* cfg_message(0,"OK"); + if (dbobject->className()=="QAdoc"){ + ((QAdoc *)dbobject)->setfield(objName, s); + } + if (dbobject->className()=="QAcat"){ + cfg_message(0,"Поле справочника %s=%s\n",(const char *) objName.utf8(), (const char *) s.utf8()); + ((QAcat *)dbobject)->setfield(objName, s); + } +*/ +// } +} + + +void +aForm::on_dbtablerow( QSqlRecord *r ) +{ + unsigned int i; + aObject *o = 0; + QVariant tv; + if ( mainWidget ) o = mainWidget->dataObject(); + if ( o ) + { + aSQLTable *t = o->table(); + id = t->value(0).toULongLong(); + } + if ( engine->project.interpreter()->functions(this).findIndex("on_tablerow")!=-1) { + engine->project.interpreter()->call("on_tablerow", QVariantList()<name(), this); + } +} + +void +aForm::on_event( const QString &source, const QString &data ) +{ + Q3ValueList lst; + lst << source; + lst << data; + if ( engine->project.interpreter()->functions(this).findIndex("on_event")!=-1) { + engine->project.interpreter()->call("on_event", QVariantList(lst), this); + } +} + + + +void +aForm::on_tabselected( qulonglong uid ) +{ + emit selected( uid ); + if ( closeAfterSelect ) { + aLog::print(aLog::Debug, QObject::tr("aForm::on_tabselected(...), closeAfterSelect is true")); + close(); + } else { + aLog::print(aLog::Debug, QObject::tr("aForm::on_tabselected(...), closeAfterSelect is false")); + } +} + +void +aForm::on_tablerow( qulonglong uid ) +{ + Q3ValueList lst; + lst << sender()->name(); + lst << QString("%1").arg(uid); + if ( engine->project.interpreter()->functions(this).findIndex("on_tabrowselected")!=-1) { + engine->project.interpreter()->call("on_tabrowselected", QVariantList(lst), this); + } +} + +int +aForm::New() +{ + if ( mainWidget ) { +// printf("try find in windowslist %d, %llu\n ", objid, db_uid); + if ( engine->wl->find( objid, db_uid ) ) + { +// printf("found, remove\n"); + engine->wl->remove( objid, db_uid ); + } + else + { +// printf("not found\n"); + } + mainWidget->New(); + db_uid = mainWidget->uid(); + printf(">>>>>db_uid = %llu\n",db_uid); + if(engine->wl->find( objid, db_uid )) + { + engine->wl->get(objid, db_uid )->setFocus(); + } + else + { + engine->wl->insert( objid, form , db_uid ); + } + } + return 0; +} + + +int +aForm::Select( qulonglong id ) +{ + if ( mainWidget ) { +// printf("try find in windowslist %d, %llu\n ", objid, db_uid); + if ( engine->wl->find( objid, db_uid ) ) + { +// printf("found, remove\n"); + engine->wl->remove( objid, db_uid ); + } + else + { +// printf("not found\n"); + } +// printf("insert new in wl ok\n"); +// printf("form->select()\n"); + mainWidget->Select( id ); + mainWidget->Refresh(); + db_uid = id; + if(engine->wl->find( objid, db_uid )) + { + engine->wl->get(objid, db_uid )->setFocus(); + } + else + { + engine->wl->insert( objid, form, db_uid ); + } + } + return 0; +} + + +int +aForm::SelectGroup( qulonglong id ) +{ + if ( mainWidget && !strcmp(mainWidget->className(),"wCatalogue")) + { + if ( engine->wl->find( objid, db_uid ) ) + { +// printf("found, remove\n"); + engine->wl->remove( objid, db_uid ); + } + ((wCatalogue*)mainWidget)->SelectGroup ( id ); + db_uid = id; + if(engine->wl->find( objid, db_uid )) + { + engine->wl->get(objid, db_uid )->setFocus(); + } + else + { + engine->wl->insert( objid, form, db_uid ); + } + } + return 0; +} + +/* +int +aForm::select( Q_ULLONG id ) +{ +CHECK_POINT +// Select( id ); + QObject *res=NULL; + QObject* obj; + QObjectList* list = form->queryList("wDBField"); + aCfgItem o; + QString fieldName; + QObjectListIt it(*list); + while ( ( obj = it.current() ) !=0 ) + { + ++it; + if (!obj) continue; + ((aWidget*)obj)->Select(id); + // if (name==widgetName(obj)) { + //o = md->find(((wDBField*)obj)->getId()); + //if(o.isNull()) continue; + fieldName = ((wDBField*)obj)->getMdFieldName(); + ((wDBField*)obj)->setValue(mainWidget->table()->value(fieldName).toString()); + + //debug_message("mainWidget class = %s\n", mainWidget->className() ); + // break; + // } + } + //return res; + + return 0; +} +*/ + + +/** + * \ru + * \brief ScriptAPI. Обновляет экранную форму. + * \_ru + */ +int +aForm::Update() +{ + if ( mainWidget ) { + mainWidget->Update(); + } + return err_noerror; +} + + + +/*! + *\~english + * Seting form readonly flag. + * When form readonly we can't edit database fields, and make updatе action + *\~russian + * \brief ScriptAPI. Устанавливает флаг "только чтение". + * + * Когда установлен этот флаг, запрещается редактирование полей формы, + * и сохранение изменений в базу. + *\~ + *\param status - \~english New readonly flag.\~russian Новое значение флага только чтение.\~ + */ +void +aForm::SetReadOnly ( bool status ) +{ + RO = status; + if ( mainWidget ) + { + if(status) + { + aLog::print(aLog::Info, tr("aForm set read only")); + } + else + { + aLog::print(aLog::Info, tr("aForm set read/write")); + } + mainWidget->SetReadOnly( status ); + } +/* QObjectList *l = mainWidget->queryList( "wDBField" ); + QObjectListIt it( *l ); + QObject *obj; + while ( (obj = it.current()) != 0 ) + { +CHECK_POINT + ++it; + (( wDBField *)obj)->setDisabled( status ); + } + delete l; // delete the list, not the objects*/ +} + + + +/*! + *\~english + * Geting form readonly flag. + *\~russian + * \brief ScriptAPI. Возвращает значение флага "только чтение". + *\~ + *\return \~english true if form open in read only mode. + * \~russian true если форма открыта в режиме только чтение.\~ + */ +bool +aForm::IsReadOnly() +{ + return RO; +} + +/*! + *\~english + * Convert number to russian language text format. + *\~russian + * \brief Конвертирует число в его текстовое представление c указанием единиц измерения. + * + * Параметры позволяют настроить вид результата. По умолчанию валюта - рубли, копейки выводятся. + * + * примеры использования: + * \li Propis("20301.34") = Двадцать тысяч триста один рубль 34 копейки + * \li Propis("20301.34", false) = Двадцать тысяч триста один рубль + * \li Propis("20301.34", false, false, "штук", "штука", "штуки") = Двадцать тысяч триста одна штука + * \li Propis("2", false, true, "слонёнков", "слонёнок", "слонёнка") = Два слонёнка + * \li Propis("5", false, false, "мартышек", "мартышка", "мартышки") = Пять мартышек + * \li Propis("38.5", false, true, "попугаев", "попугай", "попугая") = Тридцать восемь попугаев + * + * пример неправильного использования: + * \li Propis("38.5", true, true, "попугаев", "попугай", "попугая") = Тридцать восемь попугаев 50 копеек + * + *\~ + * \param val - \~english number to convert \~russian число для конвертирования\~ + * \param need_kopeyki - \~english wtite to output decimal part \~russian записывать в результат копейки (по умолчанию - да)\~ + * \param male - \~english male \~russian конвертируемая единица - мужского рода (по умолчанию - да)\~ + * \param end1 - \~english end1 \~russian окончание для нуля конвертируемых единиц (по умолчанию - `рублей')\~ + * \param end2 - \~english end2 \~russian окончание для одной конвертируемой единицы (по умолчанию - `рубль')\~ + * \param end3 - \~english end3 \~russian окончание для двуx конвертируемых единиц (по умолчанию - `рубля')\~ + * \return - \~english text representetion of number \~russian текстовое представление числа \~ + * \see Propis() + */ +QString +aForm::Propis( QString val, bool need_kopeyki, bool male, const QString &end1, const QString &end2, const QString &end3) +{ + return aService::number2money(QVariant(val).toDouble(),need_kopeyki,male, end1, end2, end3); +} + + +/** + * \ru + * \brief Конвертирует числовое представление денег в пропись с учетом указанной валюты. + * \param amount - сумма денег для преобразование в пропись. + * \param currency - строка с обозначением валюты. Допустимые значения: "RUR" - рубль, "USD" - доллар, "EUR" - евро. + * \returns значение суммы прописью. + * \_ru + */ +QString +aForm::MoneyToText( QString amount , QString currency ) { + return aService::number2money( currency, QVariant(amount).toDouble()); +} + + +/*! + * \ru + * \brief ScriptAPI. Используя идентификатор редактируемого виджетами формы документа, настраивает объект aDocument на доступ к + * документу с таким же идентификатором. + * + * То есть к тому же документу. Используется в Ананас.Скрипте для передачи + * ссылки на документ в другие объекты. Например в регистры. Для примера смотри код на Ананас.Cкрипте, + * отрабатываемый при проведении Приходной накладной в бизнес схеме Inventory. + * \param doc - документ, который необходимо настроить. + * \return void. + * \_ru + */ +void +aForm::SelectByCurrent(aObject *doc) +{ + if(mainWidget) + { + int res = doc->select(mainWidget->uid()); + aLog::print(aLog::Debug, QObject::tr("aForm SelectByCurrent %1 ended with %1").arg(mainWidget->uid()).arg(res)); + } +} + +/** + * \ru + * \brief Устаревшая. Смотри SelectByCurrent() + * \_ru + * \en + * \brief Deprecated. See SelectByCurrent() + * \_en + */ +void +aForm::SetCurrent( aObject *doc) { + SelectByCurrent( doc ); +} + +/*! + *\~english + * Return current data object of form. + *\~russian + * \brief ScriptAPI. Возвращает ссылку на бизнес объект, редактируемый данной экранной формой. + * + * По свему назначению метод аналогичен SelectByCurrent() + *\~ + * \return - \~english current data object \~russian текущий объект формы \~ + * \see SelectByCurrent() + */ +aObject* +aForm::Current() +{ + if(mainWidget) + { + return mainWidget->dataObject(); + } + else return 0; +} + +/*! + *\~english + * Get value of attribute + *\~russian + * \brief Возвращает значение атрибута формы. + *\~ + *\param name - \~english Name of attribute.\~russian Имя атрибута.\~ +aDataField* +aForm::getAttribute(const QString &name) +{ + QString oname, aname; + aWidget *w = mainWidget; + QVariant v; + aDataField *f = 0; + + oname = name.section(".",0,0); + aname = name.section(".",1); + if ( oname.isEmpty() ) aname = oname; + else { + } + v = w->value( aname ); +// f = new aDataField( this, aname ); + return f; +} + */ + + +/*! + *\~english + * Sets attribute value + *\~russian + * Устанавливает значение атрибута формы. + *\~ + * *Not implemented* + *\param name - \~english Name of attribute.\~russian Имя атрибута.\~ +int +aForm::setAttribute(const QString &name, aDataField *value) +{ + return 1; +} + */ + +/*! + *\~english + * Convert number to currensy format. + *\~russian + * \brief ScriptAPI. Конвертирует число в денежный формат (#0.00 :) ). Используется для вывода на печать. + * + * Для конвертирования числа в текстовое представление используйте Propis() + *\~ + * \param number - \~english number to convert \~russian число для конвертирования\~ + * \return - \~english rounded number \~russian округленное до 2-х цифр после запятой число \~ + * \see Propis() + */ +QString +aForm::ConvertNumber2MoneyFormat(double number) +{ + return aService::convertNumber2MoneyFormat(number); +} + +/*! + *\~english + * Convert date to local format. + *\~russian + * \brief ScriptAPI. Конвертирует дату в локальный формат. Используется для вывода на печать. + * + * Все функции работы с датой оперируют датой в ISO формате. (yyyy-MM-ddThh:mm:ss) + * Данная функция предназначена для конвертации такой даты в читаемый вид. + *\~ + * \param ISODate - \~english date in ISO format \~russian дата в ISO формате (yyyy-MM-ddThh:mm:ss)\~ + * \return - \~english date in local format \~russian дату в локальном формате \~ + */ +QString +aForm::ConvertDateFromIso(const QString &ISODate) +{ + return aService::Date2Print(ISODate); +} + + +/*! + *\~english + * Date of end day. + *\~russian + * \brief ScriptAPI. Возвращает дату-время на конец дня. + * \param ISODate - строка, содержащая дату в формате ISO (YYYY-MM-DD). + *\~ + * \return - \~english date \~russian дату вида yyyy-mm-ddT23:59:59 \~ + */ +QString +aForm::EndOfDay(const QString& ISODate) +{ + return QString("%1T%2").arg(ISODate.section('T',0,0)).arg("23:59:59"); +} + +/*! + *\~english + * Sets form mode. + *\~russian + * \brief ScriptAPI. Устанавливает режим формы. + * \param m - Допустим один из трех режимов открытия формы: 0 - новая, 1 - редактирование, 2- просмотр. + *\~ + * \see GetMode() + */ +void +aForm::setMode(int m) +{ + this->mode = m; +} + +/*! + *\~english + * Get form mode. 0 - new, 1- edit, 2- browse + *\~russian + * \brief ScriptAPI. Получение режима открытия формы. + * \return 0 - новая, 1 - редактирование, 2- просмотр. + *\~ + * \return - \~english mode \~russian режим открытия формы \~ + */ +int +aForm::GetMode() +{ + return this->mode; +} diff --git a/src/plugins/aform.h b/src/plugins/aform.h new file mode 100644 index 0000000..993ea6f --- /dev/null +++ b/src/plugins/aform.h @@ -0,0 +1,207 @@ +/**************************************************************************** +** $Id: aform.h,v 1.1 2008/11/05 21:16:29 leader Exp $ +** +** Header file of Ananas forms of Ananas +** Designer and Engine applications +** +** Created : 20031201 +** +** Copyright (C) 2003-2004 Leader InfoTech. All rights reserved. +** Copyright (C) 2003-2005 Grigory Panov , Yoshkar-Ola. +** +** This file is part of the Library of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.leaderit.ru/page=ananas or email sales@leaderit.ru +** See http://www.leaderit.ru/gpl/ for GPL licensing information. +** +** Contact org@leaderit.ru if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +/*! +*/ +#ifndef AFORM_H +#define AFORM_H + +#include "ananasglobal.h" + +#include +#include +#include +#include +//--#include +#include +//Added by qt3to4: +#include + +#include "engine.h" +#include "adatabase.h" +#include "adocument.h" +#include "acfg.h" + + +class QWidget; +class Q3SqlForm; +class aWidget; + + + +/*! + *\~english + * Ananas form. + *\~russian + * \brief Определяет программный интерфейс экранных форм Ананаса, предназначенный для использования + * Ананас.Скриптом модуля экранной формы Документа и других бизнес объектов Ананаса. + * + * Любая экранная форма, спроектированная в Ананас.Дизайнере имеет методы этого класса. + * Объект данного класса создается при создании формы. Программный код, написанный на Ананас.Скрипте и хранящийся + * в модуле экранной формы (вкладка "Модуль" в Дизайнере) может обращаться к методам этого объекта напрямую, + * без указания имени объекта. + * + * Кроме того, класс обеспечивает вызов некоторых функций на Ананас.Скрипте, определенных в модуле экранной формы, + * при наступлении определенных событий, например открытии или закрытии формы, изменения значения виджетов формы и т.п + * Полный список этих событий и функций можно посмотеть на сайте Ананаса в разделе руководства по Ананас.Дизайнеру. + *\~ + */ +class QT_WIDGET_PLUGIN_EXPORT aForm : public QObject +{ + Q_OBJECT +public: + aEngine* engine; + aDatabase* db; + aCfg* md; + aCfgItem mdObj; + QWidget* parentWidget; + bool closeAfterSelect; + + aForm(); + aForm( QWidget *parent, aEngine *eng ); + aForm( QWidget *parent, aEngine *eng, Q_ULONG form_mid = 0, aWidget* caller = NULL); + aForm( QWidget *parent, aEngine *eng, QString oftype, QObject *aobj = NULL); + ~aForm(); + QWidget *form; + void init(); + QWidget* aParent( QWidget *widget ); + int New(); + int Select( qulonglong id ); + int SelectGroup( qulonglong id ); + qulonglong selectedCatId(){ return db_uid;} // Return uid, selected in Catalogue + qulonglong selectedId(){ return id;} // Return uid, selected in main wDBTable +signals: + void selected( qulonglong uid ); + void closeForm( qulonglong ); + void changedData(); + void update( ANANAS_UID ); +public: + + QVariant tabValue(const QString &tname, int row, int col, bool dbval=false); + void setMode(int m); + +public slots: +// QObject * object(const QString &name); + void done( int rc ); + void Show(); + void Close(); + void show(); //depricated + void close(); //depricated + QVariant Value(const QString &name); + QVariant DBValue(const QString &name); + int SetValue(const QString &name, QVariant value); + int SetObjValue(const QString &name, aObject *value); + void SetColumnReadOnly(const QString &tname, int numCol, bool ro); + int ColIndex(const QString &tname, const QString &colname); + int TabCount(const QString &tname); +// QVariant TabValue(const QString &tname, const QString &colname, int row =-1 ); + QVariant TabValue(const QString &tname, int row, int col); + QVariant TabDBValue(const QString &tname, int row, int col); + void TabNewLine(const QString &tname); + void TabUpdate(const QString &tname); +// QVariant TabDBValue(const QString &tname, const QString &colname , int row =-1); +// void SetTabValue(const QString &tname, const QString &name, QVariant value); + void SetTabValue(const QString &tname, const QString &colname, int row, QVariant value); + void setfocus(QString fname); + void SetFocus(); + ERR_Code UpdateDB(); // Обновить в БД + ERR_Code update(); // Depricated + int turn_on(); // Depricated + int turn_off(); // Depricated + int SignIn(); // Провести документ + int SignOut(); // Отменить проведение документа +// void formClose(); + int Update(); + void SetReadOnly( bool status ); + bool IsReadOnly(); + int GetMode(); + + QString Propis( QString val , + bool need_kopeyki=true, + bool male=true, + const QString &end1="рублей", + const QString &end2="рубль", + const QString &end3="рубля"); + QString MoneyToText( QString amount , QString currency ); + QString ConvertNumber2MoneyFormat(double number); + QString ConvertDateFromIso(const QString &ISODate); + QString EndOfDay(const QString& ISODate); + + void SelectByCurrent(aObject *doc); + void SetCurrent(aObject *doc); + aObject* Current(); + + QWidget* Widget( QString name ); + +// after compleete will remove value() setValue() +// aDataField* getAttribute(const QString &name); +// int setAttribute(const QString &name, aDataField *value); + +/** + * Возвращает идентификатор объекта метаданных для которого создана форма. + * \input fn (in) - имя файла формы. + * \return один из предопределенных в cfg.h типов. + */ +// char* formMetaObjectId(QString fn); +private slots: + void on_dbtablerow( QSqlRecord *r ); + void on_tabupdate( QSqlRecord *r ); + void on_button();//int id); + void on_actionbutton(); + void on_form_close(); + void on_return(); + void on_lostfocus(); + void on_valueChanged(const QString &s); + void on_valueChanged( const QString & name, const QVariant & value ); + void on_tabvalueChanged(int row, int col); + void on_tabselected( qulonglong uid ); + void on_event( const QString &source, const QString &data ); + void on_tablerow( qulonglong uid ); +// QObject *findWidget(QString name); +// QString widgetName(QObject *w); +// void openForm( int oid, int fid = 0 , int defaultfor = 1, int mode = 0, bool readonly = false ); + void connectSlots(); +protected: + virtual void initWidget( QWidget *widget, aDatabase *adb ); + virtual void initContainer( aWidget *widget, aDatabase *adb ); + aWidget *parentContainer( QWidget *widget ); +private: + QObject* dbobject; + int tobj, objid; + int mode; + qulonglong id; + qulonglong db_uid; + bool RO; + aWidget* mainWidget; + aWidget* callerWidget; +}; + + +#endif // AFORM_H diff --git a/src/plugins/atoolbar.cpp b/src/plugins/atoolbar.cpp new file mode 100644 index 0000000..ce607f1 --- /dev/null +++ b/src/plugins/atoolbar.cpp @@ -0,0 +1,91 @@ +/**************************************************************************** +** $Id: atoolbar.cpp,v 1.1 2008/11/05 21:16:29 leader Exp $ +** +** Code file of the Ananas Tool bar of Ananas +** Designer and Engine applications +** +** Created : 20031201 +** +** Copyright (C) 2003-2004 Leader InfoTech. All rights reserved. +** +** This file is part of the Library of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.leaderit.ru/page=ananas or email sales@leaderit.ru +** See http://www.leaderit.ru/gpl/ for GPL licensing information. +** +** Contact org@leaderit.ru if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +/****************************************************************** + ******************************************************************/ + +//#include +#include "atoolbar.h" +//Added by qt3to4: +#include + +aToolBar::aToolBar( aCfg *cfg, aCfgItem &obj, aEngine *e, Q3MainWindow* parent , const char* name ) +: Q3ToolBar( parent, name ) +{ + md = cfg; + en = e; + ReadTool( obj ); +} + +aToolBar::~aToolBar(){ +} + +void +aToolBar::ReadTool( aCfgItem &obj ) +{ + aCfgItem aobj, apix; // action and pixmap XML data + QString aKey; // key sequence + long pid; // action id + + aobj = md->firstChild( obj ); //from first child action + while ( !aobj.isNull() ) { // foreach not null + aKey = md->sText ( aobj, md_key ); //key sequence + pid = md->id( aobj ); // action id + apix = md->findChild( + md->find( + md->text( md->findChild( aobj, md_comaction, 0 ) ).toLong() ), + md_active_picture, + 0 + ); // first action pixmap cfg object + QPixmap pix( md->binary( apix ) ); // pixmap + QAction *a = new QAction( + QIcon(pix), // pixmap + md->attr( aobj, mda_name), // name + aKey, // key sequence + this, // owner + md->attr( aobj, mda_name) // name + ); // create new action + actions.insert( pid, a ); // add action to dict + a->addTo( this ); // put action into toolbar + connect( a, SIGNAL(activated()), this, SLOT(on_Item()) ); // connect to slot + aobj = md->nextSibling( aobj ); // get next action + } +} + +void +aToolBar::on_Item() +{ + Q3IntDictIterator it( actions ); //dict iterator + for ( ; it.current(); ++it ) { // foreach action + if ( it.current() == sender() ) { // sender object + en->on_MenuBar( it.currentKey() ); // call slot + break; // break cycle + } + } +} diff --git a/src/plugins/atoolbar.h b/src/plugins/atoolbar.h new file mode 100644 index 0000000..5c7c129 --- /dev/null +++ b/src/plugins/atoolbar.h @@ -0,0 +1,61 @@ +/**************************************************************************** +** $Id: atoolbar.h,v 1.1 2008/11/05 21:16:29 leader Exp $ +** +** Header file of the Ananas Tool bar of Ananas +** Designer and Engine applications +** +** Created : 20031201 +** +** Copyright (C) 2003-2004 Leader InfoTech. All rights reserved. +** +** This file is part of the Library of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.leaderit.ru/page=ananas or email sales@leaderit.ru +** See http://www.leaderit.ru/gpl/ for GPL licensing information. +** +** Contact org@leaderit.ru if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +/**************************************************************************** +****************************************************************************/ + +#ifndef ATOOLBAR_H +#define ATOOLBAR_H + +#include +#include + +#include "acfg.h" +#include "ananas.h" + +class QT_WIDGET_PLUGIN_EXPORT aToolBar : public Q3ToolBar +{ + Q_OBJECT +private: + aCfg *md; + aEngine *en; + Q3IntDict actions; + +public: + aToolBar( aCfg *cfg, aCfgItem &obj, aEngine *e, Q3MainWindow* parent = 0, const char* name = 0 ); + ~aToolBar(); + + void ReadTool( aCfgItem &obj ); + +public slots: + void on_Item(); +}; + + +#endif // ATOOLBAR_H diff --git a/src/plugins/awidgets_plugin.cpp b/src/plugins/awidgets_plugin.cpp new file mode 100644 index 0000000..ca0a03a --- /dev/null +++ b/src/plugins/awidgets_plugin.cpp @@ -0,0 +1,58 @@ +/**************************************************************************** +** +** Code file +** +** Copyright (C) 2006 Dmitriy Pavlyuk +** +** This file is part of the Ananas Plugins of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +**********************************************************************/ + +#include "awidgets_plugin.h" + +#include + +#include "acombobox_plugin.h" +#include "wfield_plugin.h" +#include "wdbfield_plugin.h" +#include "wtable_plugin.h" +#include "wdbtable_plugin.h" +#include "wcatalogue_plugin.h" +#include "wdocument_plugin.h" +#include "wjournal_plugin.h" +#include "wgrouptree_plugin.h" +#include "wactionbutton_plugin.h" +#include "wreport_plugin.h" + + +aWidgetsCollection::aWidgetsCollection(QObject *parent) + : QObject(parent) +{ + widgets.append(new wActionButtonPlugin(this)); + widgets.append(new wFieldPlugin(this)); + widgets.append(new wDBFieldPlugin(this)); + widgets.append(new wTablePlugin(this)); + widgets.append(new wDBTablePlugin(this)); + widgets.append(new wGroupTreePlugin(this)); + widgets.append(new AComboBoxPlugin(this)); + widgets.append(new wCataloguePlugin(this)); + widgets.append(new wDocumentPlugin(this)); + widgets.append(new wJournalPlugin(this)); + widgets.append(new wReportPlugin(this)); +} + +QList aWidgetsCollection::customWidgets() const +{ + return widgets; +} + +Q_EXPORT_PLUGIN2(aWidgetsCollection, aWidgetsCollection) diff --git a/src/plugins/awidgets_plugin.h b/src/plugins/awidgets_plugin.h new file mode 100644 index 0000000..db17ddb --- /dev/null +++ b/src/plugins/awidgets_plugin.h @@ -0,0 +1,44 @@ +/**************************************************************************** +** +** Header file +** +** Copyright (C) 2006 Dmitriy Pavlyuk +** +** This file is part of the Ananas Plugins of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +**********************************************************************/ + +#ifndef AWIDGETS_PLUGIN_H +#define AWIDGETS_PLUGIN_H + +#include + +#include "qwidgetplugin.h" + + +typedef QList aListInterfaces; + +class QT_WIDGET_PLUGIN_EXPORT aWidgetsCollection: public QObject, public QDesignerCustomWidgetCollectionInterface +{ + Q_OBJECT + Q_INTERFACES(QDesignerCustomWidgetCollectionInterface) + +public: + aWidgetsCollection(QObject *parent=0); + + virtual aListInterfaces customWidgets() const; + +private: + aListInterfaces widgets; +}; + +#endif // AWIDGETS_PLUGIN_H diff --git a/src/plugins/catalogue/catalogform.cpp b/src/plugins/catalogue/catalogform.cpp new file mode 100644 index 0000000..cef8d59 --- /dev/null +++ b/src/plugins/catalogue/catalogform.cpp @@ -0,0 +1,986 @@ +#include "catalogform.h" + +#include +#include +#include "alog.h" +// TODO Remove!!! +#include "../ananas/mainform.h" +#include "aform.h" +#include "aservice.h" + +#include +#include +#include +#include +#include +#include +#include +/* + * Constructs a CatalogForm as a child of 'parent', with the + * name 'name' and widget flags set to 'f'. + * + */ +CatalogForm::CatalogForm(QWidget* parent, const char* name, Qt::WindowFlags fl) + : Q3MainWindow(parent, name, fl) +{ + setupUi(this); + + (void)statusBar(); + init(); +} + +/* + * Destroys the object and frees any allocated resources + */ +CatalogForm::~CatalogForm() +{ + destroy(); + // no need to delete child widgets, Qt does it all for us +} + +/* + * Sets the strings of the subwidgets using the current + * language. + */ +void CatalogForm::languageChange() +{ + retranslateUi(this); +} + +/*! + * \return id selected element + */ +qulonglong +CatalogForm::getId() +{ + return id; +} + +/*! + * Function set initial data. Adds one element in each group. + * \param catalog (in) - object catalog for edit or select. + * \param mg (in) - map of catalog groups. Key - group id. + * \param Fname (in) - list of field names of elements. + * \param FnameGroup (in) - list of field names of groups. + */ +void +CatalogForm::setData( aCatalogue* catalog, + QMap mg, + //QMap map_d, + const QStringList & Fname, + const QStringList & FnameGroup, + qulonglong idElForm, + qulonglong idGrForm, + const bool toSelect) +{ + ListView->setDestination(toSelect); + aLog::print(aLog::Debug, tr("CatalogForm:setData begin")); + Q3ListViewItem* item; + uint i; + QPixmap pixmap(getElementPixmap()); + QPixmap pixmap_mark_deleted(getMarkDeletedPixmap()); + idElementForm = idElForm; + idGroupForm = idGrForm; + cat = catalog; + fieldName= Fname[0]; + fieldList= Fname; + fieldListGroup = FnameGroup; + map_gr = mg; + ListView->setAllColumnsShowFocus ( true ); + QMap::Iterator it = map_gr.begin(); + cat->Select(); + // added one element in each group + while(it!=map_gr.end()) + { + cat->selectByGroup(it.key());// select elements in each group + if(cat->First()) // if group have elements + { + item = new Q3ListViewItem(map_gr[it.key()]); + aLog::print(aLog::Debug, tr("CatalogForm add first element in group")); + //printf("add first element in group\n"); + if(cat->isElementMarkDeleted()) + item->setPixmap(0,pixmap_mark_deleted); + else + item->setPixmap(0,pixmap); + for(i=0; isetText(i,cat->sysValue(fieldList[i]).toString()); + } + map_el.insert(cat->sysValue("id").toULongLong(),item); + } + ++it; + } + + cat->selectByGroup(0);// select elements without group + if(cat->First()) + { + + aLog::print(aLog::Debug, tr("CatalogForm add elements into root")); + do + { + item = new Q3ListViewItem(ListView); + if(cat->isElementMarkDeleted()) + item->setPixmap(0,pixmap_mark_deleted); + else + item->setPixmap(0,pixmap); + for(i=0; isetText(i,cat->sysValue(fieldList[i]).toString()); + } + map_el.insert(cat->sysValue("id").toULongLong(),item); + + }while(cat->Next()); + } + cat->Select(); + setGeometry(aService::loadSizeFromConfig(QString("%1_embedded editor").arg(cat->md->attr(cat->obj, mda_name)))); + ListView->setSelected(ListView->firstChild(),true); + aLog::print(aLog::Debug, tr("CatalogForm init")); +} + +/*! + * Function set id, returned getId(). + * \param idx (in) - id. + */ +void +CatalogForm::setId(qulonglong idx ) +{ + id = idx; +} + +/*! Function search string s in table of elements and show list founding lines. + * Searching for length s >= constant LENGTH_NO_FIND. + * Displaing <= VISIBLE_ROWS lines. + * \param s (in) - string for search. + */ +void +CatalogForm::find(const QString& s ) +{ + int count=0;//,rows=0; + bool ok; + int tmp = aService::readConfigVariable("LengthAboveFind",&ok).toInt(); + if(!ok) tmp = 3; + const int LENGTH_NO_FIND = tmp; + + tmp = aService::readConfigVariable("VisibleRows",&ok).toInt(); + if(!ok) tmp = 50; + + const int VISIBLE_ROWS = tmp; + + setId(0); + ListHint->clear(); + if(s.length()>=LENGTH_NO_FIND) // show list hint + { + if(!ListHint->isVisible()) + { + ListHint->show(LineEdit, StatusFrame); + StatusFrame->show(); + } + + cat->select(fieldName + " like '%"+s+"%'");// AND df<>'1'"); + if(cat->First()) + { + do + { + if(count++insertItem(cat->sysValue(fieldName).toString(), cat->sysValue("id").toInt()); + } + } while(cat->Next()); + } + if(!ListHint->count()) // don't show empty list + { + ListHint->hide(); + StatusFrame->hide(); + + } + else + { + StatusFrame->repaint(); + StatusFrame->drawText( 5, StatusFrame->size().height()-3, QString(tr("displaying %1 from %2")).arg(ListHint->count()).arg(count) ); + } + + } + else // length < LENGTH_NO_FIND, don't show list hint + { + if(ListHint->isVisible()) + { + ListHint->hide(); + StatusFrame->hide(); + } + } + +} + +/*! + * Handler signal press arrow for line edit + */ +void +CatalogForm::pressArrow() +{ + + if(ListHint->isVisible()) + { + ListHint->setFocus(); + ListHint->setSelected(ListHint->currentItem(),true); + + } + else + { + find(LineEdit->text()); + if(ListHint->isVisible()) + { + ListHint->setFocus(); + ListHint->setSelected(ListHint->currentItem(),true); + } + + } +} + + +void +CatalogForm::isPressArrow() +{ + +} + +/*! + * Function create visual objects and connect slots. + */ +void +CatalogForm::init() +{ + + ListView = new aListView(centralWidget(), "listView"); + ListView->setGeometry(30,30,400,300); + ListView->setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding); + LineEdit = new aLineEdit(centralWidget(), "lineEdit"); + ListHint = new aListBox(centralWidget(), "listBox"); + StatusFrame = new Q3Frame(centralWidget(), "statusFrame"); + + ListView->setRootIsDecorated( true ); + + StatusFrame->setGeometry( QRect( 0, 0, 50,5 ) ); + StatusFrame->setFrameShape( Q3Frame::StyledPanel ); + StatusFrame->setFrameShadow( Q3Frame::Raised ); + StatusFrame->hide(); + + GridLayout = new Q3GridLayout(centralWidget(), 1, 1, 11, 6, "GridLayout"); + GridLayout->addMultiCellWidget( ListView, 2,3, 0 , 0 ); + GridLayout->addWidget( LineEdit, 1, 0 ); + GridLayout->addWidget( bCancel, 3, 1 ); + QLabel *lb = new QLabel(tr("Search"),centralWidget()); + lb->setSizePolicy( QSizePolicy( (QSizePolicy::SizeType)5, (QSizePolicy::SizeType)0, 0, 0, lb->sizePolicy().hasHeightForWidth() ) ); + GridLayout->addWidget( lb ,0,0); + QSpacerItem* spacer = new QSpacerItem( 20, 390, QSizePolicy::Minimum, QSizePolicy::Expanding ); + GridLayout->addMultiCell( spacer, 0,2,1, 1); + + QPixmap pix= rcIcon("cat.png"); + if(pix.isNull()) + { + aLog::print(aLog::Info, tr("Catalog Form image cat.png not loaded")); + } + else + { + setIcon( pix ); + } + //setFocusPolicy(); + // connect(this, SIGNAL (destoyed()), +// this, SLOT (close()); + + connect(ListView, SIGNAL (newItemRequest(Q3ListViewItem*)), + this, SLOT (new_item(Q3ListViewItem*))); + + connect(ListView, SIGNAL (newGroupRequest(Q3ListViewItem*)), + this, SLOT (new_group(Q3ListViewItem*))); + + connect(ListView, SIGNAL (delItemRequest(Q3ListViewItem*)), + this, SLOT (del_item(Q3ListViewItem*))); + + connect(ListView, SIGNAL (markDeletedRequest(Q3ListViewItem*)), + this, SLOT (mark_deleted(Q3ListViewItem*))); + + connect(ListView, SIGNAL (undoMarkDeletedRequest(Q3ListViewItem*)), + this, SLOT (undo_mark_deleted(Q3ListViewItem*))); + + connect(ListView, SIGNAL (editRequest(Q3ListViewItem*, int)), + this, SLOT (edit(Q3ListViewItem*, int))); + + connect(ListView, SIGNAL (selectRequest(Q3ListViewItem*)), + this, SLOT (select(Q3ListViewItem*))); + + connect(LineEdit, SIGNAL (delayTextChanged(const QString&)), + this, SLOT (find(const QString&))); + + connect(LineEdit, SIGNAL (keyArrowPressed()), + this, SLOT (pressArrow())); + + connect(LineEdit, SIGNAL (keyEnterPressed()), + this, SLOT (go())); + + connect(ListView, SIGNAL (expanded ( Q3ListViewItem *)), + this, SLOT (onLoadElements( Q3ListViewItem *))); + + connect(ListHint, SIGNAL (lostFocus()), + LineEdit, SLOT (setFocus())); + + connect(ListHint, SIGNAL (lostFocus()), + StatusFrame, SLOT (hide())); + + connect(ListHint, SIGNAL (lostFocus()), + ListHint, SLOT (hide())); + + connect(ListHint, SIGNAL (keyArrowLRPressed()), + LineEdit, SLOT (setFocus())); + + connect(ListHint, SIGNAL (keyArrowLRPressed(const QString&)), + this, SLOT (setText(const QString&))); + + connect(ListHint, SIGNAL (keyEnterPressed()), + this, SLOT (go())); + + connect(ListHint, SIGNAL (sendMessage(const QString &)), + this->statusBar(), SLOT (message( const QString &))); + + connect(ListView, SIGNAL (sendMessage(const QString &)), + this->statusBar(), SLOT (message( const QString &))); + + connect(LineEdit, SIGNAL (sendMessage(const QString &)), + this->statusBar(), SLOT (message( const QString &))); + + LineEdit->setFocus(); +} + +/*! + * Function delete objects, which were created in function init() + */ +void +CatalogForm::destroy() +{ + aService::saveSize2Config(this->rect(),QString("%1_embedded editor").arg(cat->md->attr(cat->obj, mda_name))); + delete cat; + cat = 0; +} + +/*! + * Function set text for line edit. Don't emit signals. + */ +void +CatalogForm::setText( const QString & s ) +{ + LineEdit->blockSignals ( true ); + LineEdit->setText ( s ); + setId(ListHint->getId(ListHint->currentItem())); + LineEdit->blockSignals ( false ); +} + +/*! + * Handler bGo::onClick() event. + */ +void +CatalogForm::go() +{ + qulonglong ide=getId(), idg; + if(!getId()) + { + ide = findFirst(LineEdit->text()); + setId(ide); + } + idg = getIdg(ide); + loadElements(idg); + if(map_el.contains(getId())) + { + goToItem(map_el[getId()]); + } + +} +/*! + * Ensures that item is visible, scrolling the list view vertically if necessary and opening (expanding) any parent items if this is required to show the item. + */ +void +CatalogForm::goToItem( Q3ListViewItem *item) +{ + ListView->setSelected(item, true); + ListView->ensureItemVisible(item); + ListView->setFocus(); +} + +/*! + * Searching string s in table of elements. + * \param s (in) - stirng for search. + * \return id first founding line. + */ +long +CatalogForm::findFirst( const QString &s ) +{ + qulonglong res=0; + cat->select(fieldName + " like '%"+s+"%'");// AND df<>'1'"); + //Cat->Select(); + if(cat->First()) + { + res = cat->sysValue("id").toULongLong(); + + } + return res; +} + +/*! + * Loads elements in group, if then don't loaded. + * \param idGroup (in) - id group for load. + */ +void +CatalogForm::loadElements( qulonglong idGroup ) +{ + Q3ListViewItem * item; + Q3ListViewItem * p_item; + uint i; +// printf("load elements\n"); +// printf("sel by group id = %lu\n",idGroup); + QPixmap pixmap(getElementPixmap()); + QPixmap pixmap_mark_deleted(getMarkDeletedPixmap()); + cat->selectByGroup(idGroup); +// printf("_sel by group\n"); + if(cat->First()) + { + do + { + //count++; + if(map_gr.contains(idGroup) + && !map_el.contains(cat->sysValue("id").toULongLong())) + { + p_item = map_gr[idGroup]; + item = new Q3ListViewItem(p_item); + if(cat->isElementMarkDeleted()) + item->setPixmap(0,pixmap_mark_deleted); + else + item->setPixmap(0,pixmap); + for(i=0; isetText(i,cat->sysValue(fieldList[i]).toString()); + } + map_el.insert(cat->sysValue("id").toULongLong(),item); + } + }while(cat->Next()); + } +// printf("end load\n"); +} + +/*! + * Loads elemens in group, if then don't loaded. + * \param item (in) - group for load. + */ +void +CatalogForm::onLoadElements( Q3ListViewItem *item ) +{ + Q3ValueList lst = map_gr.values(); + int ind = lst.findIndex(item); + qulonglong key; + if(ind!=-1) + { + Q3ValueList listKey = map_gr.keys(); + key = listKey[ind]; + loadElements(key); + } +} + +/*! + * Gets id parent group for element. + * \param ide (in) - id of element. + * \return id of group or 0 if no group. + */ +qulonglong +CatalogForm::getIdg( qulonglong ide ) +{ + return cat->idGroupByElement(ide); +} + + +/*! + * Adds new element. + * \param parentItem (in) - parent group. If parent group == 0, element not added. + */ +void +CatalogForm::new_item( Q3ListViewItem * parentItem ) +{ + if(!parentItem) + { + //cat->groupSelect(0); + cat->newElement(0); + //printf("id = %llu\n",id); + Q3ListViewItem* item = new Q3ListViewItem(ListView); + QPixmap pixmap(getElementPixmap()); + item->setPixmap(0,pixmap); + map_el.insert(cat->sysValue("id").toULongLong(),item); + edit(item,true); + ListView->ensureItemVisible(item); + // cfg_message(0,tr("Can't added element")); + return; + } + qulonglong id = getGroupId(parentItem); + QPixmap pixmap(getElementPixmap()); + if(id) // parent item is group + { + cat->groupSelect(id); + if(!cat->isGroupMarkDeleted()) + { + cat->newElement(id); + Q3ListViewItem* item = new Q3ListViewItem(map_gr[id]); + item->setPixmap(0,pixmap); + map_el.insert(cat->sysValue("id").toULongLong(),item); + edit(item,true); + ListView->ensureItemVisible(item); + //ListView->setFocus(); + } + else cfg_message(0,tr("Can't added new element to mark deleted group")); + } + else + { + new_item(parentItem->parent()); + }//cfg_message(0,tr("Can't added element to element")); +} + +/*! + * Gets group id. + * \param item (in) - group item. + */ +long +CatalogForm::getGroupId( Q3ListViewItem * item ) +{ + Q3ValueList lst = map_gr.values(); + int ind = lst.findIndex(item); + qulonglong key=0; + if(ind!=-1) + { + Q3ValueList listKey = map_gr.keys(); + key = listKey[ind]; + } +return key; +} + +/*! + * Adds new group. + * \param parentItem (in) - parent group. If parent group == 0, group adds in root. + */ +void +CatalogForm::new_group( Q3ListViewItem * parentItem ) +{ + qulonglong id = getGroupId(parentItem); + Q3ListViewItem * item; + QPixmap pixmap(getGroupPixmap()); + //cat->groupSelect( id ); + if(!id) + { + id = getElementId(parentItem); + if(id) + { + cfg_message(0,tr("Can't added group to element")); + return; + } + else + { +// printf(">>>>id=0\n"); + cat->newGroup(id); + item = new Q3ListViewItem(ListView); + ListView->insertItem(item); + } + } + else + { + //cat->groupSelect(id); + if(cat->isGroupMarkDeleted()) + { + cfg_message(0,tr("Can't added group to mark deleted group")); + return; + } + cat->newGroup(id); + item = new Q3ListViewItem(map_gr[id]); + } + //item->setText(0,cat->GroupSysValue(fieldListGroup[0]).toString()); + item->setPixmap(0,pixmap); + map_gr.insert(cat->GroupSysValue("id").toULongLong(),item); + edit(item,true); + ListView->ensureItemVisible(item); + ListView->setCurrentItem(item); + ListView->setSelected(item,true); + //ListView->setFocus(); + +} + +/*! + * Gets pixmap for group. + * \return pixmap. + */ +QPixmap +CatalogForm::getGroupPixmap() +{ + QPixmap pixmap = rcIcon("group2.png"); +// pixmap.detach(); + if(pixmap.isNull()) + { + aLog::print(aLog::Info, tr("Catalog Form group pixmap not load")); + } +return pixmap; +} + + +/*! + * Gets pixmap for element. + * \return pixmap. + */ +QPixmap +CatalogForm::getElementPixmap() +{ + QPixmap pixmap= rcIcon("field2.png"); + if(pixmap.isNull()) + { + aLog::print(aLog::Info, tr("Catalog Form element pixmap not load")); + } +return pixmap; +} + +/*! + * Gets pixmap for mark deleted element or group. + * \return pixmap. + */ +QPixmap +CatalogForm::getMarkDeletedPixmap() +{ + QPixmap pixmap = rcIcon("editdelete2.png"); +// pixmap. + if(pixmap.isNull()) + { + aLog::print(aLog::Info, tr("Catalog Form mark deleted group pixmap not load")); + } +return pixmap; +} +/*! + * Delets current element or group (with subgroups). + * \param item (in) - deleted element or group item. + */ +void CatalogForm::del_item( Q3ListViewItem * item ) +{ + // cat->groupSelect(getGroupId(item)); + qulonglong id = getElementId(item); + if(id) + { + cat->select(id); + if(cat->First()) + { + cat->delElement(); + map_el.remove(id); + delete item; + item = 0; + } + } + else + { + id = getGroupId(item); + if(id) + { + Q3ValueList listDeletedId; + cat->delGroup(id, listDeletedId); + Q3ValueList::iterator it = listDeletedId.begin(); + while(it!= listDeletedId.end()) + { + if(map_el.contains(*it)) map_el.remove(*it); + else if(map_gr.contains(*it)) map_gr.remove(*it); + ++it; + } + delete item; // destructor delete all subitems + item = 0; + } + } +} + +/*! + * Marks deleted current element or group (with subgroups). + * While for mark deleted items sets ahother pixmap only. + * \param item (in) - marked deleted element or group item. + */ +void CatalogForm::mark_deleted( Q3ListViewItem * item ) +{ + qulonglong id = getElementId(item); + if(id) + { + cat->select(id); +// cat->setSelected(true); + if(cat->First()) + { + cat->setMarkDeletedElement(id,true); + item->setPixmap(0,getMarkDeletedPixmap()); + } + } + else + { + id = getGroupId(item); + if(id) + { + loadElements(id); // populate items in group + Q3ValueList listDeletedId; + cat->getMarkDeletedList(id,listDeletedId); + Q3ValueList::iterator it = listDeletedId.begin(); + while(it != listDeletedId.end()) //first delete elements in this group + { + if(map_el.contains(*it)) + { + map_el[*it]->setPixmap(0, getMarkDeletedPixmap()); + cat->setMarkDeletedElement(*it,true); + it = listDeletedId.remove(it); + } + else + { + ++it; + } + } + it = listDeletedId.begin(); + while(it != listDeletedId.end()) //second delete groups + { + if(map_gr.contains(*it)) + { + map_gr[*it]->setPixmap(0, getMarkDeletedPixmap()); + cat->setMarkDeletedGroup(*it,true); + it = listDeletedId.remove(it); + //map_el[*it]->invalidateHeight();// setHeight(10); + } + else + { + ++it; + } + } + } + } +} + +/*! + * Undo marks deleted current element or group (with subgroups). + * \param item (in) - marked deleted element or group item. + */ +void CatalogForm::undo_mark_deleted( Q3ListViewItem * item ) +{ + qulonglong id = getElementId(item); + if(id) + { + cat->select(id); + if(cat->First()) + { + cat->setMarkDeletedElement(id,false); + item->setPixmap(0,getElementPixmap()); + } + } + else + { + id = getGroupId(item); + if(id) + { + // cat->select(QString("id=%1").arg(id),md_group); + //if(cat->FirstInGroupTable()) + Q3ValueList listDeletedId; + // cat->setMarkDeletedGroup(id, listDeletedId,false); + cat->getMarkDeletedList(id, listDeletedId); + Q3ValueList::iterator it = listDeletedId.begin(); + while(it != listDeletedId.end()) //first delete elements in this group + { + if(map_el.contains(*it)) + { + map_el[*it]->setPixmap(0, getElementPixmap()); + cat->setMarkDeletedElement(*it,false); + it = listDeletedId.remove(it); + } + else + { + ++it; + } + } + it = listDeletedId.begin(); + while(it != listDeletedId.end()) //second delete groups + { + if(map_gr.contains(*it)) + { + map_gr[*it]->setPixmap(0, getGroupPixmap()); + cat->setMarkDeletedGroup(*it,false); + it = listDeletedId.remove(it); + //map_el[*it]->invalidateHeight();// setHeight(10); + } + else + { + ++it; + } + } + } + } +} + +void CatalogForm::edit( Q3ListViewItem * item, int) +{ + edit( item, false); +} + +void CatalogForm::edit( Q3ListViewItem * item, bool afterNew) +{ +// QWidget *wd = topLevelWidget(); + aLog::print(aLog::Debug, tr("Catalog Form edit element start")); + MainForm * mw = (MainForm*) topLevelWidget(); + if(mw) + { + qulonglong id = getElementId(item); + if(id) + { + aLog::print(aLog::Debug, tr("Catalog Form edit element with id=%1").arg(id)); + cat->select(id); + if(idElementForm) + { + if(!cat->isElementMarkDeleted()) + { + aForm *editForm = new aForm(mw->ws, &mw->engine, (long int) idElementForm); + if(editForm) + { + if(afterNew) editForm->setMode(0); + else editForm->setMode(1); + editForm->Select(id); + connect(editForm, SIGNAL(closeForm(qulonglong)), this, SLOT(Refresh(qulonglong))); + editForm->show(); + } + else + { + aLog::print(aLog::Error, tr("Catalog Form edit element form is null")); + } + } + else cfg_message(0, tr("Can't edit mark deleted element")); + } + else cfg_message(1,tr("Catalog haven't edit element form")); + } + else + { + id = getGroupId(item); + aLog::print(aLog::Debug, tr("Catalog Form edit group with id = %1").arg(id)); + if(id) + { + + cat->groupSelect(id); + if(idGroupForm) + { + if(!cat->isGroupMarkDeleted()) + { + aForm *editForm = new aForm(mw->ws, &mw->engine, (long int) idGroupForm); + if(editForm) + { + if(afterNew) editForm->setMode(0); + else editForm->setMode(1); + + editForm->SelectGroup(id); + connect(editForm, SIGNAL(closeForm(qulonglong)), this, SLOT(Refresh(qulonglong))); + editForm->show(); + } + else + { + aLog::print(aLog::Error, tr("Catalog Form edit group form is null")); + } + } + else cfg_message(0, tr("Can't edit mark deleted group")); + } + else cfg_message(1,tr("Catalog haven't edit group form")); + } + } + } + else + { + aLog::print(aLog::Error, tr("Catalog Form main widget is not 'MainForm'")); + } + +} + +/*! + * Selects current group or element. + * \param item (in) - selected element or group item + */ +void CatalogForm::select( Q3ListViewItem * item ) +{ + qulonglong res = getGroupId(item); + if(!res) + { + res = getElementId(item); + cat->select(res); + if(!cat->isElementMarkDeleted()) + { + setId(res); + doOk(); + } + } + else + { + cat->groupSelect(res); + if(!cat->isGroupMarkDeleted()) + { + setId(res); + doOk(); + } + } + emit(selected(res)); +// return res; +} + +/*! + * Gets element id. + * \param item (in) - element item. + */ +qulonglong CatalogForm::getElementId( Q3ListViewItem * item ) +{ + Q3ValueList lst = map_el.values(); + int ind = lst.findIndex(item); + qulonglong key=0; + if(ind!=-1) + { + Q3ValueList listKey = map_el.keys(); + key = listKey[ind]; + } +return key; +} + + +void CatalogForm::doOk() +{ + close(); +} + + + +void CatalogForm::keyPressEvent( QKeyEvent * e ) +{ + if ( e->key()==Qt::Key_Return) + { + } + if ( e->key()==Qt::Key_Escape) + { + close(); + } + e->ignore(); +} + + +void CatalogForm::Refresh( qulonglong id ) +{ + Q3ListViewItem * item; + if( map_el.contains( id )) + { + item = map_el[id]; + cat->select( id ); + for(uint i=0; isetText(i,cat->sysValue(fieldList[i]).toString()); + ListView->setFocus(); + } + } + else + { + if( map_gr.contains( id ) ) + { + item = map_gr[id]; + cat->groupSelect( id ); + item->setText(0,cat->GroupSysValue(fieldListGroup[0]).toString()); + ListView->setFocus(); + } + } +} + +//#include "catalogform.ui.h" diff --git a/src/plugins/catalogue/catalogform.h b/src/plugins/catalogue/catalogform.h new file mode 100644 index 0000000..891f884 --- /dev/null +++ b/src/plugins/catalogue/catalogform.h @@ -0,0 +1,84 @@ +#ifndef CATALOGFORM_H +#define CATALOGFORM_H + +#include "ui_catalogform.h" + +#include +#include + + +class CatalogForm : public Q3MainWindow, public Ui::CatalogForm +{ + Q_OBJECT + +public: + CatalogForm(QWidget* parent = 0, const char* name = 0, Qt::WindowFlags fl = Qt::WType_TopLevel); + ~CatalogForm(); + + aListView* ListView; + QString fieldName; + aLineEdit *LineEdit; + aListBox* ListHint; + Q3Frame* StatusFrame; + aCatalogue* cat; + bool FormToSelect; + + virtual Q_ULLONG getId(); + virtual void init(); + virtual void destroy(); + virtual long findFirst( const QString & s ); + virtual Q_ULLONG getIdg( Q_ULLONG ide ); + virtual QPixmap getGroupPixmap(); + virtual void edit( Q3ListViewItem * item, bool ); + virtual QPixmap getElementPixmap(); + virtual QPixmap getMarkDeletedPixmap(); + +public slots: + virtual void setData( aCatalogue * catalog, QMap mg, const QStringList & Fname, const QStringList & FnameGroup, Q_ULLONG idElForm, Q_ULLONG idGrForm, const bool toSelect ); + virtual void setId( Q_ULLONG idx ); + virtual void find( const QString & s ); + virtual void pressArrow(); + virtual void isPressArrow(); + virtual void setText( const QString & s ); + virtual void go(); + virtual void goToItem( Q3ListViewItem * item ); + virtual void loadElements( Q_ULLONG idGroup ); + virtual void onLoadElements( Q3ListViewItem * item ); + virtual void new_item( Q3ListViewItem * parentItem ); + virtual void new_group( Q3ListViewItem * parentItem ); + virtual void del_item( Q3ListViewItem * item ); + virtual void mark_deleted( Q3ListViewItem * item ); + virtual void undo_mark_deleted( Q3ListViewItem * item ); + virtual void edit( Q3ListViewItem * item, int ); + virtual void select( Q3ListViewItem * item ); + virtual void Refresh( Q_ULLONG id ); + +signals: + void selected(Q_ULLONG); + +protected: + Q3GridLayout* GridLayout; + Q3VBoxLayout* layout1; + Q_ULLONG id,idElementForm,idGroupForm; + QStringList fieldList, fieldListGroup; + + virtual long getGroupId( Q3ListViewItem * item ); + virtual Q_ULLONG getElementId( Q3ListViewItem * item ); + +protected slots: + virtual void languageChange(); + + virtual void keyPressEvent( QKeyEvent * e ); + + +private: + QMap map_gr; + QMap map_el; + QMap map_deleted; + +private slots: + virtual void doOk(); + +}; + +#endif // CATALOGFORM_H diff --git a/src/plugins/catalogue/catalogform.ui b/src/plugins/catalogue/catalogform.ui new file mode 100644 index 0000000..f5411d8 --- /dev/null +++ b/src/plugins/catalogue/catalogform.ui @@ -0,0 +1,50 @@ + + + + + CatalogForm + + + + 0 + 0 + 610 + 466 + + + + Catalogue + + + + + + 530 + 410 + 70 + 24 + + + + Cancel + + + + + + qPixmapFromMimeSource + + wfield.h + catalogformwidgets.h + qmap.h + qstatusbar.h + + + + bCancel + clicked() + CatalogForm + close() + + + diff --git a/src/plugins/catalogue/catalogformwidgets.cpp b/src/plugins/catalogue/catalogformwidgets.cpp new file mode 100644 index 0000000..2d067d0 --- /dev/null +++ b/src/plugins/catalogue/catalogformwidgets.cpp @@ -0,0 +1,435 @@ +/**************************************************************************** +** $Id: catalogformwidgets.cpp,v 1.1 2008/11/05 21:16:29 leader Exp $ +** +** Catalogue metadata object implementation file of +** Ananas application library +** +** Created : 20031201 +** +** Copyright (C) 2003-2004 Grigory Panov, Yoshkar-Ola. +** +** This file is part of the Designer application of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.leaderit.ru/page=ananas or email sales@leaderit.ru +** See http://www.leaderit.ru/gpl/ for GPL licensing information. +** +** Contact org@leaderit.ru if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#include +#include +#include +//Added by qt3to4: +#include +#include +#include + +#include "catalogformwidgets.h" +/*! + * Constructor + */ +aListBox::aListBox(QWidget* parent, const char * name, Qt::WFlags f):Q3ListBox(parent,name,f) +{ + + listPrivate = new Q3ListBox(parent); + listPrivate->hide(); + setFocusPolicy (Qt::StrongFocus); + connect(this, SIGNAL ( doubleClicked( Q3ListBoxItem * ) ), + this, SLOT ( doubleClickHandler( Q3ListBoxItem * ) )); +// layout1 = new QVBoxLayout(); +// statusBar = new QLabel(this,"statusBar"); +// statusBar-> +// layout1->addWidget(this,0); +// layout1->addWidget(statusBar,1); + +} +/*! + * Destructor + */ +aListBox::~aListBox() +{ +// delete statusBar; + delete listPrivate; +} +/*! + * Function move and resize frame and list box. + *\param wd (in) - widget for pattern geometry. + * \param fr (in, out) - status frame. + */ +void +aListBox::show(QWidget *wd, Q3Frame *fr)//, QLabel *lb) +{ + setGeometry(wd->x(), + wd->y()+wd->size().height()+1, + wd->size().width()+wd->x(), + wd->size().height()+wd->y()+100); + QWidget::show(); +// statusBar->setGeometry( size().higth(), +// size()+10 +// statusBar->setWidth(wd->size().width() ); +// fr->resize(size()); +// fr->setPos(pos()); + fr->setGeometry(x(), + size().height()+y(), + size().width(), + 20); + emit(sendMessage(tr("Press arrow down for go to drop down list"))); +// lb->move(fr->x()+2,fr->y()+2); +} +/*! + * Key press event handler. + * Emit signals keyArrowLRPressed if press arrow left or arrow rigth. + * \param e (in) - key press event. + */ +void +aListBox::keyPressEvent(QKeyEvent *e) +{ + if(e->key()==Qt::Key_Left || e->key()==Qt::Key_Right) + { + emit(keyArrowLRPressed()); + emit(keyArrowLRPressed(currentText())); + //printf("emit key pressed\n"); + } + if(e->key() == Qt::Key_Return) + { + //printf("enter !!!\n");// return; + emit(keyArrowLRPressed()); + emit(keyArrowLRPressed(currentText())); + emit(keyEnterPressed()); + //printf("enter !!!\n");// return; + } + if(e->key() == Qt::Key_Escape) + { + this->clearFocus(); + +// emit(lostFocus()); +// printf("Esc!\n"); + e->accept(); + return; + + } + e->accept(); + Q3ListBox::keyPressEvent(e); +} +/*! + * Inserts s in list and idx in list of id. + * \param s (in) - string for insert. + * \param idx (in) - id for insert. + * \param index (in) - position for insert. + */ +void +aListBox::insertItem(const QString &s, long idx, int index) +{ + listPrivate->insertItem(QString("%1").arg(idx),index); + Q3ListBox::insertItem(s,index); +} +/*! + * Clears list and list of id. + */ +void +aListBox::clear() +{ + listPrivate->clear(); + Q3ListBox::clear(); +} +/*! + * Focus out event handler. Emit signal lost focus. + * \param e - focus out event. + */ +void +aListBox::focusOutEvent ( QFocusEvent *e ) +{ + QWidget::focusOutEvent ( e ); +// printf("focus is out\n"); + emit(lostFocus()); +} + +void +aListBox::setFocus() +{ + Q3ListBox::setFocus(); + emit(sendMessage(tr("Use Enter for go to item and arrow for navigation"))); +} + +void +aListBox::doubleClickHandler(Q3ListBoxItem *i) +{ +// printf("double click handler!\n"); + emit(keyArrowLRPressed()); + emit(keyArrowLRPressed(i->text())); + emit(keyEnterPressed()); + +} +aLineEdit::aLineEdit ( QWidget* parent, const char* name) : QLineEdit(parent,name) +{ + timer = new QTimer(this); + setFocusPolicy(Qt::StrongFocus); + connect(timer, SIGNAL (timeout()), + this, SLOT (timerDone())); + connect(this, SIGNAL (textChanged ( const QString & )), + this, SLOT (timerRestart(const QString &))); + connect(this, SIGNAL (lostFocus()), + SLOT (stopTimer())); +} + +aLineEdit::~aLineEdit() +{ + if(timer) + { + delete timer; + timer=0; + } +} + +/*! Key press event handler. Emit signal keyArrowPressed(). + * \param e (in) - key press event. + */ +void +aLineEdit::keyPressEvent(QKeyEvent *e) +{ +// timer->start(500,TRUE); + if(e->key()==Qt::Key_Return)//Key_Enter) + { + e->accept(); + emit(keyEnterPressed()); + //e->ignore(); + } + if(e->key()==Qt::Key_Down) + { + emit(keyArrowPressed()); + } + e->ignore(); + QLineEdit::keyPressEvent(e); +} +void +aLineEdit::timerDone() +{ + emit(delayTextChanged(text())); + +} + +void +aLineEdit::timerRestart(const QString &) +{ + timer->start(500, false); +} + +void +aLineEdit::stopTimer() +{ + timer->stop(); +} + +void +aLineEdit::setFocus() +{ + QLineEdit::setFocus(); + emit(sendMessage(tr("Enter string for search"))); +} +/*! + <* Constructor create list view and popup menu. + */ +aListView::aListView(QWidget* parent, + const char* name, + Qt::WFlags f) : Q3ListView(parent,name,f) +{ + menu = 0; + toSelect = true; + + connect(this, SIGNAL( doubleClicked( Q3ListViewItem *, const QPoint&, int)), + this, SLOT( doubleClickHandler( Q3ListViewItem *, const QPoint&, int))); + + connect(this, SIGNAL( contextMenuRequested (Q3ListViewItem*, const QPoint&, int)), + this, SLOT( showMenu( Q3ListViewItem*, const QPoint&, int))); + +} + +aListView::~aListView() +{ + delete menu; + menu = 0; +} +/*! + * Shows popup menu. + * \param item (in) - current item. + * \param p (in) - mouse pointer position. + * \param col (in) - current column. + */ +void +aListView::showMenu( Q3ListViewItem* item, const QPoint& p, int col) +{ + delete menu; + menu = new Q3PopupMenu(); + if(toSelect) + { + menu->insertItem(tr("Select"), this, SLOT(select())); + menu->insertSeparator(); + } + menu->insertItem(tr("Edit"), this, SLOT(edit())); + menu->insertSeparator(); + menu->insertItem(tr("New element"), this, SLOT(newItem())); + menu->insertItem(tr("New group"), this, SLOT(newGroup())); + menu->insertSeparator(); + //menu->setItemEnabled(menu->idAt(3),false); + menu->insertItem(tr("Undo mark delete"), this, SLOT(undoMarkDeleted())); + menu->insertItem(tr("Delete (mark deleted)"),this, SLOT(markDeleted())); + menu->insertItem(tr("Delete (phisical)"), this, SLOT(delItem())); + parentItem = item; + if(col==-1) col = 0; + columnClicked = col; + menu->popup( p ); +} + +void +aListView::newItem() +{ + emit (newItemRequest(parentItem)); +} +void +aListView::newGroup() +{ + emit (newGroupRequest(parentItem)); +} +void +aListView::delItem() +{ + emit (delItemRequest(parentItem)); +} +void +aListView::markDeleted() +{ + emit (markDeletedRequest(parentItem)); +} +void +aListView::undoMarkDeleted() +{ + emit (undoMarkDeletedRequest(parentItem)); +} + +void +aListView::edit() +{ + emit (editRequest(parentItem,columnClicked)); +} +void +aListView::select() +{ + emit (selectRequest(parentItem)); +} +void +aListView::setDestination(const bool dest) +{ + toSelect = dest; +} +bool +aListView::getDestination() +{ + return toSelect; +} +/*! Key press event handler. Emit signal keyEnterPressed(). + * \param e (in) - key press event. + */ +void +aListView::keyPressEvent(QKeyEvent *e) +{ + + switch(e->key()) + { + case Qt::Key_Return: + e->accept(); + parentItem = selectedItem(); + columnClicked = 0; + if(toSelect) + { + select(); + } + else + { + edit(); + } + break; + case Qt::Key_Insert: + parentItem = selectedItem(); + columnClicked = 0; + switch(QMessageBox::question(this, + tr("Type of new item"), + tr("

Select type of new item

"), + tr("&Elemnt"), tr("&Group"))) + { + case 0: + newItem(); + break; + case 1: + newGroup(); + break; + default: + break; + } + break; + case Qt::Key_Delete: + parentItem = selectedItem(); + columnClicked = 0; + switch(QMessageBox::question(this, + tr("Delete item"), + tr("

Mark deleted or delete?

"), + tr("&Mark deleted"), tr("&Delete"))) + { + case 0: + markDeleted(); + break; + case 1: + delItem(); + break; + default: + break; + } + break; + default: + e->ignore(); + break; + } + Q3ListView::keyPressEvent(e); + +} + +void +aListView::setFocus() +{ + Q3ListView::setFocus(); + if(toSelect) + { + emit(sendMessage(tr(" - select, - add, - delete items"))); + } + else + { + emit(sendMessage(tr(" - edit, - add, - delete items"))); + } +} + + +void +aListView::doubleClickHandler( Q3ListViewItem *item, const QPoint& p, int col) +{ + parentItem = item; + columnClicked = col; + if(toSelect) + { + select(); + } + else + { + edit(); + } +} + diff --git a/src/plugins/catalogue/catalogformwidgets.h b/src/plugins/catalogue/catalogformwidgets.h new file mode 100644 index 0000000..f4b07a8 --- /dev/null +++ b/src/plugins/catalogue/catalogformwidgets.h @@ -0,0 +1,154 @@ +/**************************************************************************** +** $Id: catalogformwidgets.h,v 1.1 2008/11/05 21:16:29 leader Exp $ +** +** Catalogue metadata object implementation file of +** Ananas application library +** +** Created : 20031201 +** +** Copyright (C) 2003-2004 Grigory Panov, Yoshkar-Ola. +** +** This file is part of the Designer application of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.leaderit.ru/page=ananas or email sales@leaderit.ru +** See http://www.leaderit.ru/gpl/ for GPL licensing information. +** +** Contact org@leaderit.ru if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ +#ifndef CATALOGFORMWIDGET_H +#define CATALOGFORMWIDGET_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +//Added by qt3to4: +#include +#include +#include +//class QVBoxLayout; + +class aListBox:public Q3ListBox +{ + Q_OBJECT +public: + aListBox(QWidget *parent = 0, const char* name = 0, Qt::WFlags f = 0); + ~aListBox(); + void insertItem(const QString &s, long idx, int index = -1); + void show(QWidget *w, Q3Frame *fr);//, QLabel *lb); + + long getId(int ind) { return atol(listPrivate->text(ind).ascii()); }; + + void clear(); + //void setId(long idx) {id = idx;}; +public slots: + virtual void setFocus(); + +protected: + + virtual void keyPressEvent ( QKeyEvent *e ); + void focusOutEvent ( QFocusEvent *e ); +protected slots: + void doubleClickHandler(Q3ListBoxItem *i); + // QVBoxLayout* layout1; +// QLabel * statusBar; +signals: + void keyArrowLRPressed(); + void keyArrowLRPressed(const QString&); + void keyEnterPressed(); + void lostFocus(); + void sendMessage(const QString &); +private: + Q3ListBox* listPrivate; +}; + + +class aLineEdit:public QLineEdit +{ + Q_OBJECT +public: + aLineEdit( QWidget* parent, const char* name = 0 ); + ~aLineEdit(); + +protected: + virtual void keyPressEvent ( QKeyEvent *e ); + +private: + QTimer *timer; + +public slots: + void stopTimer(); + virtual void setFocus(); +protected slots: + void timerDone(); + void timerRestart(const QString & s); + +signals: + void keyArrowPressed(); + void delayTextChanged(const QString &); + void keyEnterPressed(); + void sendMessage(const QString &); +}; + +class aListView : public Q3ListView +{ + Q_OBJECT +public: + aListView(QWidget* parent = 0, const char* name = 0, Qt::WFlags f = 0); + ~aListView(); + + Q3PopupMenu *menu; + void setDestination(const bool dest); + bool getDestination(); +protected: + virtual void keyPressEvent ( QKeyEvent *e ); + +public slots: + + void showMenu( Q3ListViewItem* item, const QPoint& p, int); + void newItem(); + void newGroup(); + void delItem(); + void markDeleted(); + void undoMarkDeleted(); + void edit(); + void select(); + virtual void setFocus(); + +protected slots: + void doubleClickHandler( Q3ListViewItem *, const QPoint&, int col); + +signals: + + void sendMessage(const QString &); + void newItemRequest(Q3ListViewItem* parentItem); + void newGroupRequest(Q3ListViewItem* parentItem); + void delItemRequest(Q3ListViewItem* item); + void markDeletedRequest(Q3ListViewItem* item); + void undoMarkDeletedRequest(Q3ListViewItem* item); + void editRequest(Q3ListViewItem* item, int columnClicked); + void selectRequest(Q3ListViewItem* item); +private: + Q3ListViewItem* parentItem; + int columnClicked; + bool toSelect; +}; +#endif + diff --git a/src/plugins/catalogue/catalogue.pri b/src/plugins/catalogue/catalogue.pri new file mode 100644 index 0000000..85dbd8a --- /dev/null +++ b/src/plugins/catalogue/catalogue.pri @@ -0,0 +1,19 @@ +HEADERS += \ + catalogue/catalogform.h \ + catalogue/catalogformwidgets.h \ + catalogue/ecatalogue.h \ + catalogue/wcatalogue.h \ + catalogue/wcatalogue_plugin.h \ + catalogue/wcatalogue_taskmenu.h + +SOURCES += \ + catalogue/catalogform.cpp \ + catalogue/catalogformwidgets.cpp \ + catalogue/ecatalogue.cpp \ + catalogue/wcatalogue.cpp \ + catalogue/wcatalogue_plugin.cpp \ + catalogue/wcatalogue_taskmenu.cpp + +FORMS += \ + catalogue/catalogform.ui \ + catalogue/ecatalogue.ui diff --git a/src/plugins/catalogue/ecatalogue.cpp b/src/plugins/catalogue/ecatalogue.cpp new file mode 100644 index 0000000..2da761e --- /dev/null +++ b/src/plugins/catalogue/ecatalogue.cpp @@ -0,0 +1,203 @@ +#include "ecatalogue.h" + +#include +#include +#include + +/* + * Constructs a eCatalogue as a child of 'parent', with the + * name 'name' and widget flags set to 'f'. + * + * The dialog will by default be modeless, unless you set 'modal' to + * true to construct a modal dialog. + */ +eCatalogue::eCatalogue(QWidget* parent, const char* name, bool modal, Qt::WindowFlags fl) + : QDialog(parent, name, modal, fl) +{ + setupUi(this); + + init(); +} + +/* + * Destroys the object and frees any allocated resources + */ +eCatalogue::~eCatalogue() +{ + // no need to delete child widgets, Qt does it all for us +} + +/* + * Sets the strings of the subwidgets using the current + * language. + */ +void eCatalogue::languageChange() +{ + retranslateUi(this); +} + + +#include "acfg.h" + +void eCatalogue::init() +{ +/* + int oc, i, f, idx=0; + char *id, *name, *ot; + cfg_objptr o; + char otype[100]; + QString named; + + otypes.clear(); + eType->clear(); + otypes.append("D"); + eType->insertItem(trUtf8("Дата"), idx++); + otypes.append("T"); + eType->insertItem(trUtf8("Время"), idx++); + otypes.append("N %d %d"); + eType->insertItem(trUtf8("Число"), idx++); + otypes.append("C %d"); + eType->insertItem(trUtf8("Строка"), idx++); + + oc=cfgobj_count(NULL, NULL); + for (i=1;i<=oc;i++) { + id=cfgobj_idn(NULL, NULL, i, &o); + ot=(char *)o->name; + name=cfgobj_attr(o, "name"); + named=""; + f=0; + if (strcmp((char *)ot, aot_doc)==0) { + named=trUtf8("Документ."); + f=1; + } + if (strcmp((char *)ot, aot_cat)==0) { + named=trUtf8("Справочник."); + f=1; + } + if (f) { + named=named+trUtf8(name); + sprintf(otype, "O %s", id); + otypes.append(otype); + eType->insertItem(named, idx++); + } + } +*/ +} + + + +/*void eCatalogue::setData( aCatalogue *f, QWidget *mw ) +{ + aCfg *md = 0; + if ( !f ) return; +// printf("name = '%s'\n", (const char *) mw->name() ); + if (mw->name() == QString("ananas-designer_mainwindow") ) { +// printf("running under ananas designer\n"); + CfgForm *cf = ( ( MainForm *) mw )->cfgForm(); + if ( cf ) { + md = &cf->cfg; +// QString ts = f->getFieldType(); +// char t=' '; + int w=0, d=0, idx=0; + unsigned int i; + long oid , id; + + id = f->getId(); + + otypes.clear(); + eType->clear(); + + QStringList tlist = md->types( md_catalogue ); + otypes.clear(); + eType->clear(); + for ( QStringList::Iterator it = tlist.begin(); it != tlist.end(); ++it ) { + otypes.append( (*it).section( "\t", 0, 0 ) ); + eType->insertItem( (*it).section("\t", 1, 1 ), idx++ ); + } + for ( i = 0 ; i < otypes.count(); i++ ) { + oid = 0; + if( otypes[i][0] == 'O' ) { + sscanf( (const char *)otypes[ i ], "O %d", &oid ); + if ( oid == id ) { + eType->setCurrentItem( i ); + break; + } + } + } + } else reject(); + } + +} +*/ + +void +eCatalogue::setData( QWidget *o, aCfg *md ) +{ +// const QObject *o = sender(); + if ( o ) { + if ( o->className() != QString("wCatalogue") || !md ) { + reject(); + return; + } + } + else { + reject(); + return; + } + wCatalogue *f = ( wCatalogue*) o; + int w=0, d=0, idx=0; + unsigned int i; + long oid , id; + + id = f->getId(); + + QStringList tlist = md->types( md_catalogue ); + otypes.clear(); + eType->clear(); + for ( QStringList::Iterator it = tlist.begin(); it != tlist.end(); ++it ) { + otypes.append( (*it).section( "\t", 0, 0 ) ); + eType->insertItem( (*it).section("\t", 1, 1 ), idx++ ); + } + for ( i = 0 ; i < otypes.count(); i++ ) { + oid = 0; + if( otypes[i][0] == 'O' ) { + sscanf( (const char *)otypes[ i ], "O %d", &oid ); + if ( oid == id ) { + eType->setCurrentItem( i ); + break; + } + } + } +} + + +void eCatalogue::getData( QWidget * o ) +{ + +/* int idx=eType->currentItem(); + long oid = 0; + + if (f) { + if( otypes[idx][0] == 'O' ) { + sscanf( (const char *)otypes[ idx ], "O %d", &oid ); + f->setId( oid ); + } + } +*/ +// const QObject *o = sender(); + if ( !o ) return; + if ( o->className() != QString("wCatalogue") ) return; + wCatalogue *f = ( wCatalogue*) o; + + int idx=eType->currentItem(); + long oid = 0; + + if (f) { + if( otypes[idx][0] == 'O' ) { + sscanf( (const char *)otypes[ idx ], "O %d", &oid ); + f->setId( oid ); + } + } + +} + diff --git a/src/plugins/catalogue/ecatalogue.h b/src/plugins/catalogue/ecatalogue.h new file mode 100644 index 0000000..1fc2cbe --- /dev/null +++ b/src/plugins/catalogue/ecatalogue.h @@ -0,0 +1,27 @@ +#ifndef ECATALOGUE_H +#define ECATALOGUE_H + +#include "ui_ecatalogue.h" + + +class eCatalogue : public QDialog, public Ui::eCatalogue +{ + Q_OBJECT + +public: + eCatalogue(QWidget* parent = 0, const char* name = 0, bool modal = false, Qt::WindowFlags fl = 0); + ~eCatalogue(); + + QStringList otypes; + +public slots: + virtual void init(); + virtual void setData( QWidget * o, aCfg * md ); + virtual void getData( QWidget * o ); + +protected slots: + virtual void languageChange(); + +}; + +#endif // ECATALOGUE_H diff --git a/src/plugins/catalogue/ecatalogue.ui b/src/plugins/catalogue/ecatalogue.ui new file mode 100644 index 0000000..4f847bf --- /dev/null +++ b/src/plugins/catalogue/ecatalogue.ui @@ -0,0 +1,116 @@ + + + + + eCatalogue + + + + 0 + 0 + 348 + 106 + + + + Catalogue + + + + + + + + + + + + + 100 + 32767 + + + + Type + + + false + + + + + + + + 31 + 16 + + + + Expanding + + + Vertical + + + + + + + + + OK + + + true + + + + + + + Cancel + + + + + + + + + + 91 + 31 + + + + Expanding + + + Horizontal + + + + + + + qPixmapFromMimeSource + + ananas.h + wcatalogue.h + + + + bOK + clicked() + eCatalogue + accept() + + + bCancel + clicked() + eCatalogue + reject() + + + diff --git a/src/plugins/catalogue/wcatalogue.cpp b/src/plugins/catalogue/wcatalogue.cpp new file mode 100644 index 0000000..e6d42a2 --- /dev/null +++ b/src/plugins/catalogue/wcatalogue.cpp @@ -0,0 +1,443 @@ +/**************************************************************************** +** $Id: wcatalogue.cpp,v 1.2 2008/11/08 20:16:36 leader Exp $ +** +** Code file of the catlogue plugin of Ananas +** Designer and Engine applications +** +** Created : 20031201 +** +** Copyright (C) 2003-2004 Leader InfoTech. All rights reserved. +** Copyright (C) 2003-2004 Grigory Panov, Yoshkar-Ola. +** +** This file is part of the Ananas Plugins of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.leaderit.ru/page=ananas or email sales@leaderit.ru +** See http://www.leaderit.ru/gpl/ for GPL licensing information. +** +** Contact org@leaderit.ru if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#include +#include +#include +#include +#include +//--#include +#include "adatabase.h" +#include "wcatalogue.h" +#include "ecatalogue.h" +#include "wdbfield.h" +#include "wdbtable.h" +#include "wgrouptree.h" +#include "alog.h" + +//extern aCfg *plugins_aCfg; + + +/*!\en + *\_en \ru + *\_ru + */ +wCatalogue::wCatalogue( QWidget *parent, Qt::WFlags fl ) +:aWidget( parent, "wCatalogue", fl ) +{ + setInited( false ); + setFormMode( 0 ); +} + + +wCatalogue::~wCatalogue() +{ +} + + + +void +wCatalogue::initObject( aDatabase *adb ) +{ + aWidget::initObject( adb ); + QObject *obj; + QObjectList lb = this->queryList( "QWidget" ); + QListIterator itb( lb ); // iterate over all wDBFields + while ( itb.hasNext() ) + { + obj = itb.next(); + if(obj->inherits("wDBField")) + { +// if ( (wActionButtton*) obj )->isActionUpdate() ) + connect( (wDBField *)obj, SIGNAL(valueChanged( const QVariant & )), + this, SLOT(valueChanged( const QVariant & )) ); + } + if(obj->inherits("wGroupTree")) + { + ((wGroupTree*)obj)->setId(getId()); + connect( (wGroupTree *)obj, SIGNAL(selectionChanged( const qulonglong )), + this, SLOT(selectionChanged( const qulonglong )) ); + + } + if(obj->inherits("wDBTable")) + { + connect( this, SIGNAL(newSelectionFilter( const QString& )), + (wDBTable*)obj, SLOT(newFilter( const QString& )) ); + connect( this, SIGNAL(newSelectionGroupId( const qulonglong )), + (wDBTable*)obj, SLOT(newDataId( const qulonglong )) ); + + } + + } + //--delete lb; // delete the list, not the objects + //--focusData()->next()->setFocus(); + focusNextChild(); + +} + + + +/*! + *\~english + * Processed field value changed. + * Conected on signal valueChanged( const QVariant & ) for all + * wDBField insert in the widget. + * Decode field name and set new field value in database object. + * Emit signal value change with field name and value. + * Signal connectaed on aform slot, for future work. + *\~russian + * Обрабатывает изменение значения поля + * Присоединяется к сигналу valueChanged( const QVariant & ), + * всех полей типа wDBField, вставленных в виджет. + * Декодирует имя поля и сохраняет его новое значение в объекте для + * работы с базой. + * Посылает сигнал об изменении значения, который содержит имя поля + * и его новое значение. + * Сигнал присоединяется к слоту формы для последующей обработки. + *\~ + *\param value - \~english new field value. \~russian новое значение поля. \~ + */ +void +wCatalogue::valueChanged( const QVariant & value ) +{ + if ( sender()->className() != QString("wDBField") ) return; + wDBField * fld = ( wDBField * ) sender(); + aCfgItem o_field,o_parent; + QString parent_name; + QVariant val = value; + + o_field = md->find(fld->getId()); + o_parent = md->parent(o_field); + const QString fname = fld->getFieldName(); + + parent_name = md->objClass( o_parent ); + if( parent_name == QString(md_group) ) + { + + if (dbobj)// && dbobj->className() == QString("aCatalogue") ) + { + aLog::print(aLog::Debug, tr("wCatalogue group value changed to %1").arg(value.toString())); + ((aCatalogue*)dbobj)->GroupSetValue( fname, value ); + } + + + } + + else + { + + if (dbobj) + { + aLog::print(aLog::Debug, tr("wCatalogue element value changed to %1").arg(value.toString())); + dbobj->SetValue( fname, val ); + } + } + + emit aWidget::valueChanged( fname, value ); +} + + +bool +wCatalogue::checkStructure() +{ + + return false; +} + + +QVariant +wCatalogue::value( const QString &name ) +{ + + aLog::print(aLog::Error, tr("wCatalogue value for name %1 ").arg(name)); + return QVariant(""); +} + + +void +wCatalogue::setValue( const QString &name, QVariant &value ) +{ +// if ( formMode() == CATALOGUEFORMMODE_GROUP ) { +// ( aCatalogue *) dbobj->SetValue(name,value); +// } else { +// printf("wCatalogue::setValue(%s,%s)\n",name.ascii(),value.toString().ascii()); + aLog::print(aLog::Debug, tr("wCatalogue set value %1 for name %2 ").arg(value.toString()).arg(name)); + dbobj->SetValue(name,value); +// } + //dbobj->Update(); +// debug_message("wCatalogue value changed to %s\n",value.toString().ascii()); + +} + + +QDialog* +wCatalogue::createEditor( QWidget *parent ) +{ + return new eCatalogue( parent ); +} + + +int +wCatalogue::select( qulonglong )//id ) +{ + return 0; +} + + +qulonglong +wCatalogue::insert() +{ + return 0; +} + + +int +wCatalogue::update() +{ + if ( dbobj ) + { + aLog::print(aLog::Debug, tr("wCatalogue update")); +// printf("wCatalogue:;update()\n"); + return dbobj->Update(); + } + + aLog::print(aLog::Error, tr("wCatalogue have not data source object ")); + return err_abstractobj; +} + + +int +wCatalogue::markDelete() +{ + return 0; +} + + +QString +wCatalogue::displayString() +{ + return ""; +} + +/*! + * Create aDocument database object. + */ +aObject * +wCatalogue::createDBObject( aCfgItem obj, aDatabase *adb ) +{ +// printf("cat form mode = %i\n",formMode() ); +// if ( formMode() == CATALOGUEFORMMODE_GROUP ) return new aCatGroup( obj, adb ); + return new aCatalogue( obj, adb ); +} + + +ERR_Code +wCatalogue::Select( qulonglong id ) +{ + + //if ( formMode()==0 ) { + + QObject *obj; + QObjectList lb = this->queryList( "wDBTable" ); + QListIterator itb( lb ); // iterate over all wDBTable + while ( itb.hasNext() ) + { + obj = itb.next(); + ( (wDBTable *)obj )->setFocus(); + ( (wDBTable *)obj )->Select( id ); +// if ( (wActionButtton*) obj )->isActionUpdate() ) +// connect( (wDBTable *)obj, SIGNAL(valueChanged( const QVariant & )), +// this, SLOT(valueChanged( const QVariant & )) ); + } + //--delete lb; // delete the list, not the objects + //--lb=0; +// return 0; + + + +//} +// +// + blockSignals( true ); + ERR_Code err = aWidget::Select ( id ); //table()->select( id ); //aWidget::Select ( id ); + + blockSignals( true ); + NewValues(); + blockSignals( false ); + return err_noerror; +} + + + +ERR_Code +wCatalogue::SelectGroup( qulonglong id ) +{ + + ERR_Code err = ((aCatalogue*)dbobj)->groupSelect( id ); + if ( err ) + { + aLog::print(aLog::Error, tr("wCatalogue select group error = %1 ").arg(err)); + return err; + } + blockSignals( true ); + NewValues(); + blockSignals( false ); + //emit( changeObj(QString("idd=%1").arg(id))); + return err_noerror; +} + + +/*! + *\~english + * Set fields values from database. + * Used for insert values into fields when create or open catalogue. + *\~russian + * Устанавливает значения полей. + * Устанавливает значения полей из базы данных, + * используется при открытии формы или смене каталога. + *\~ + */ +void +wCatalogue::NewValues() +{ + aLog::print(aLog::Debug, tr("wCatalogue set new values for all fields")); + QString fname; + QObjectList l = this->queryList( "wDBField" ); + QListIterator it( l ); + QObject *obj; + //--obj = it.toFirst(); + aCfgItem o_field,o_parent; + QString parent_name; + while ( it.hasNext() ) + { + //++it; + //obj = it.current(); + obj= it.next(); + fname=((wDBField *)obj)->getFieldName(); + o_field = md->find(((wDBField *)obj)->getId()); + o_parent = md->parent(o_field); + //printf( "field name %s\n",(const char*)fname.local8Bit() ); + parent_name = md->objClass( o_parent ); + //printf("parent_name = %s\n", (const char*)parent_name ); + if( parent_name == QString(md_group) ) + { +// debug_message("group set value\n"); + if (dbobj)// && dbobj->className() == QString("aCatalogue") ) + { + + aLog::print(aLog::Debug, tr("wCatalogue set new values for group field %1").arg(fname)); + ((wDBField*)obj)->setValue(((aCatalogue*)dbobj)->GroupValue( fname ).toString()); + } + + } + else + { + aLog::print(aLog::Debug, tr("wCatalogue value for element field %1 ").arg(fname)); + ((wDBField*)obj)->setValue(dbobj->Value(fname).toString()); + } + } + //--delete l; // delete the list, not the objects + //--l=0; +} + + + +void +wCatalogue::setFormMode( int Mode ) +{ + aWidget::setFormMode( Mode ); +} + + +/*! + * Create toolbar for Catalogue. + */ +Q3ToolBar* +wCatalogue::createToolBar( Q3MainWindow * owner ) +{ + /* + QAction *a; + QToolBar *t = new QToolBar( owner, "CatalogueTools" ); + + a = new QAction( + QPixmap::fromMimeSource("doc_new.png"), + tr("New"), + QKeySequence(""),//Insert"), + t, + tr("New Element") + ); + a->setToolTip(tr("New element (Ins)")); + a->addTo( t ); + connect( a, SIGNAL( activated() ), this, SLOT( insert() ) ); + + a = new QAction( + QPixmap::fromMimeSource("doc_edit.png"), + tr("Edit"), + QKeySequence(""),//Return"), + t, + tr("Edit element") + ); + a->setToolTip(tr("Edit element (Enter)")); + a->addTo( t ); + connect( a, SIGNAL( activated() ), this, SLOT( update() ) ); +*/ +/* a = new QAction( + QPixmap::fromMimeSource("doc_view.png"), + tr("View"), + QKeySequence("Shifh+Return"), + t, + tr("View element") + ); + a->setToolTip(tr("View element (Shift+Enter)")); + a->addTo( t ); + connect( a, SIGNAL( activated() ), this, SLOT( view() ) ); +*/ +/* + a = new QAction( + QPixmap::fromMimeSource("doc_view.png"), + tr("Delete"), + QKeySequence(""),//Delete"), + t, + tr("Delete element") + ); + a->setToolTip(tr("Delete element (Shift+Enter)")); + a->addTo( t ); + connect( a, SIGNAL( activated() ), this, SLOT( markDelete() ) ); +*/ + return 0; +} + +void +wCatalogue::selectionChanged(const qulonglong groupId) +{ + aLog::print(aLog::Error, tr("wCatalogue selection changed to %1 ").arg(groupId)); + emit(newSelectionGroupId(groupId)); + emit(newSelectionFilter(QString("idg=%1").arg(groupId))); +} diff --git a/src/plugins/catalogue/wcatalogue.h b/src/plugins/catalogue/wcatalogue.h new file mode 100644 index 0000000..8348a67 --- /dev/null +++ b/src/plugins/catalogue/wcatalogue.h @@ -0,0 +1,79 @@ +/**************************************************************************** +** $Id: wcatalogue.h,v 1.1 2008/11/05 21:16:29 leader Exp $ +** +** Header file of the catlogue plugin of Ananas +** Designer and Engine applications +** +** Created : 20031201 +** +** Copyright (C) 2003-2004 Leader InfoTech. All rights reserved. +** +** This file is part of the Ananas Plugins of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.leaderit.ru/page=ananas or email sales@leaderit.ru +** See http://www.leaderit.ru/gpl/ for GPL licensing information. +** +** Contact org@leaderit.ru if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#ifndef WCATALOGUE_H +#define WCATALOGUE_H +#include +//#include "ananas.h" +#include "awidget.h" + +class QWidget; + +#define CATALOGUEFORMMODE_LIST 0 // Elements list +#define CATALOGUEFORMMODE_ELEMENT 1 // Element form +#define CATALOGUEFORMMODE_GROUP 2 // Group form + + +class QT_WIDGET_PLUGIN_EXPORT wCatalogue : public aWidget +{ + Q_OBJECT +public: + wCatalogue( QWidget *parent = 0, Qt::WFlags fl = 0 ); + virtual ~wCatalogue(); + bool checkStructure(); + virtual void initObject( aDatabase *adb ); + virtual QDialog* createEditor( QWidget *parent ); + virtual QString displayString(); + virtual bool isContainer() { return true; }; + virtual aObject* createDBObject( aCfgItem obj, aDatabase *adb ); + virtual Q3ToolBar* createToolBar( Q3MainWindow *parent ); + void setFormMode( int Mode ); +public slots: + virtual ERR_Code Select( qulonglong id ); + virtual ERR_Code SelectGroup( qulonglong id ); + void valueChanged( const QVariant & value ); + QVariant value( const QString &name ); + void setValue( const QString &name, QVariant &value ); + int select( qulonglong id ); + qulonglong insert(); + int update(); + int markDelete(); + void selectionChanged(const qulonglong); + +private: + + void NewValues(); +signals: + void newSelectionFilter(const QString &); + void newSelectionGroupId( const qulonglong ); + +}; + + +#endif // WCATALOGUE_H diff --git a/src/plugins/catalogue/wcatalogue_plugin.cpp b/src/plugins/catalogue/wcatalogue_plugin.cpp new file mode 100644 index 0000000..d6733a6 --- /dev/null +++ b/src/plugins/catalogue/wcatalogue_plugin.cpp @@ -0,0 +1,100 @@ +/**************************************************************************** +** +** Code file +** +** Copyright (C) 2006 Dmitriy Pavlyuk +** +** This file is part of the Ananas Plugins of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +**********************************************************************/ + +#include "wcatalogue_plugin.h" + +#include +#include +#include + +#include "wcatalogue_taskmenu.h" +#include "wcatalogue.h" + + +wCataloguePlugin::wCataloguePlugin(QObject *parent) + : QObject(parent), m_initialized(false) +{ + m_initialized = false; +} + +bool wCataloguePlugin::isContainer() const +{ + return true; +} + +bool wCataloguePlugin::isInitialized() const +{ + return m_initialized; +} + +void wCataloguePlugin::initialize(QDesignerFormEditorInterface *core) +{ + if (m_initialized) + return; + Q_UNUSED(core); + + QExtensionManager *manager = core->extensionManager(); + Q_ASSERT(manager != 0); + manager->registerExtensions(new wCatalogueTaskMenuFactory(manager), + Q_TYPEID(QDesignerTaskMenuExtension)); + + m_initialized = true; +} + +QWidget *wCataloguePlugin::createWidget(QWidget *parent) +{ + wCatalogue *w = new wCatalogue(parent, 0); + return w; +} + +QString wCataloguePlugin::name() const +{ + return QLatin1String("wCatalogue"); +} + +QString wCataloguePlugin::group() const +{ + return QLatin1String("Ananas"); +} + +QString wCataloguePlugin::toolTip() const +{ + return QString(); +} + +QString wCataloguePlugin::whatsThis() const +{ + return QString(); +} + +QString wCataloguePlugin::includeFile() const +{ + return QLatin1String("wcatalogue.h"); +} + +QIcon wCataloguePlugin::icon() const +{ + //return QIcon(); + return QIcon(":/images/wcatalogue.png"); +} + +QString wCataloguePlugin::domXml() const +{ + return "\n\n"; +} diff --git a/src/plugins/catalogue/wcatalogue_plugin.h b/src/plugins/catalogue/wcatalogue_plugin.h new file mode 100644 index 0000000..2eab2b0 --- /dev/null +++ b/src/plugins/catalogue/wcatalogue_plugin.h @@ -0,0 +1,53 @@ +/**************************************************************************** +** +** Header file +** +** Copyright (C) 2006 Dmitriy Pavlyuk +** +** This file is part of the Ananas Plugins of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +**********************************************************************/ + +#ifndef WCATALOGUE_PLUGIN_H +#define WCATALOGUE_PLUGIN_H + +#include + +#include "qwidgetplugin.h" + + +class QT_WIDGET_PLUGIN_EXPORT wCataloguePlugin : public QObject, public QDesignerCustomWidgetInterface +{ + Q_OBJECT + Q_INTERFACES(QDesignerCustomWidgetInterface) + +public: + wCataloguePlugin(QObject *parent=0); + + bool isContainer() const; + bool isInitialized() const; + void initialize(QDesignerFormEditorInterface *core); + QWidget *createWidget(QWidget *parent); + + QString name() const; + QString group() const; + QString toolTip() const; + QString whatsThis() const; + QString includeFile() const; + QIcon icon() const; + QString domXml() const; + +private: + bool m_initialized; +}; + +#endif // WCATALOGUE_PLUGIN_H diff --git a/src/plugins/catalogue/wcatalogue_taskmenu.cpp b/src/plugins/catalogue/wcatalogue_taskmenu.cpp new file mode 100644 index 0000000..3d3f1ba --- /dev/null +++ b/src/plugins/catalogue/wcatalogue_taskmenu.cpp @@ -0,0 +1,74 @@ +/**************************************************************************** +** +** Copyright (C) 2006 Dmitriy Pavlyuk All rights reserved. +** +** This file is part of the widgets plugin of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +****************************************************************************/ + +#include + +#include + +#include "wcatalogue_taskmenu.h" +#include "wcatalogue.h" +#include "ecatalogue.h" + + +wCatalogueTaskMenu::wCatalogueTaskMenu(wCatalogue *widget, QObject *parent) + : QObject(parent) +{ + m_widget = widget; + + m_editAction = new QAction(tr("Edit ..."), this); + connect(m_editAction, SIGNAL(triggered()), this, SLOT(edit())); +} + +void wCatalogueTaskMenu::edit() +{ + /*eCatalogue e; + + e.setData(m_widget); + if (e.exec() == QDialog::Accepted) + { + e.getData(m_widget); + }*/ + m_widget->widgetEditor(); +} + +QAction *wCatalogueTaskMenu::preferredEditAction() const +{ + return m_editAction; +} + +QList wCatalogueTaskMenu::taskActions() const +{ + QList list; + list.append(m_editAction); + return list; +} + +wCatalogueTaskMenuFactory::wCatalogueTaskMenuFactory(QExtensionManager *parent) + : QExtensionFactory(parent) +{ +} + +QObject *wCatalogueTaskMenuFactory::createExtension(QObject *object, const QString &iid, QObject *parent) const +{ + if (iid != Q_TYPEID(QDesignerTaskMenuExtension)) + return 0; + + if (wCatalogue *cat = qobject_cast(object)) + return new wCatalogueTaskMenu(cat, parent); + + return 0; +} diff --git a/src/plugins/catalogue/wcatalogue_taskmenu.h b/src/plugins/catalogue/wcatalogue_taskmenu.h new file mode 100644 index 0000000..5f0d4da --- /dev/null +++ b/src/plugins/catalogue/wcatalogue_taskmenu.h @@ -0,0 +1,57 @@ +/**************************************************************************** +** +** Copyright (C) 2006 Dmitriy Pavlyuk All rights reserved. +** +** This file is part of the widgets plugin of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +****************************************************************************/ + +#ifndef WCATALOGUE_TASKMENU_H +#define WCATALOGUE_TASKMENU_H + +#include +#include + + +class QExtensionManager; +class QAction; +class wCatalogue; + +class wCatalogueTaskMenu: public QObject, public QDesignerTaskMenuExtension +{ + Q_OBJECT + Q_INTERFACES(QDesignerTaskMenuExtension) +public: + wCatalogueTaskMenu(wCatalogue *widget, QObject *parent); + + QAction *preferredEditAction() const; + QList taskActions() const; + +private slots: + void edit(); + +private: + QAction *m_editAction; + wCatalogue *m_widget; +}; + +class wCatalogueTaskMenuFactory: public QExtensionFactory +{ + Q_OBJECT +public: + wCatalogueTaskMenuFactory(QExtensionManager *parent = 0); + +protected: + QObject *createExtension(QObject *object, const QString &iid, QObject *parent) const; +}; + +#endif // WCATALOGUE_TASKMENU_H diff --git a/src/plugins/combobox/acombobox.cpp b/src/plugins/combobox/acombobox.cpp new file mode 100644 index 0000000..044533c --- /dev/null +++ b/src/plugins/combobox/acombobox.cpp @@ -0,0 +1,272 @@ +/**************************************************************************** +** $Id: acombobox.cpp,v 1.1 2008/11/05 21:16:29 leader Exp $ +** +** Code file of the field plugin of Ananas +** Designer and Engine applications +** +** Copyright (C) 2006 Andrey Paskal. +** +** This file is part of the Ananas Plugins of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** +**********************************************************************/ + +#include "acombobox.h" +//Added by qt3to4: +#include +#include +#include + +AComboBox::AComboBox( QWidget* parent, const char* name ):QComboBox( parent, name ) { +} + +AComboBox::AComboBox( bool rw, QWidget* parent, const char* name ):QComboBox( rw, parent, name ) { +} + +AComboBox::~AComboBox(){ +} + +int +AComboBox::count() const { + return QComboBox::count(); +} + +void +AComboBox::insertStringList( const QStringList &list, int index ) { + QComboBox::insertStringList( list, index ); +}; + +/*--void +AComboBox::insertStrList( const Q3StrList &list, int index ){ + QComboBox::insertStrList( list, index ); +}; + +void +AComboBox::insertStrList( const Q3StrList *list, int index ){ + QComboBox::insertStrList( list, index ); +}; + +void +AComboBox::insertStrList( const char **str, int numStrings, int index){ + QComboBox::insertStrList( str, numStrings, index ); +};*/ + +void +AComboBox::insertItem( const QString &text, int index ){ + QComboBox::insertItem( text, index); +}; + +void +AComboBox::insertItem( const QPixmap &pixmap, int index ){ + QComboBox::insertItem( pixmap, index); +}; + +void +AComboBox::insertItem( const QPixmap &pixmap, const QString &text, int index ){ + QComboBox::insertItem(pixmap, text, index ); +}; + + +void +AComboBox::removeItem( int index ){ + QComboBox::removeItem( index ); +}; + + +int +AComboBox::currentItem() { + return QComboBox::currentItem(); +}; + +void +AComboBox::setCurrentItem( int index ){ + QComboBox::setCurrentItem( index ); +}; + + +QString +AComboBox::currentText() const { + return QComboBox::currentText(); +}; + +void +AComboBox::setCurrentText( const QString& string){ + QComboBox::setCurrentText( string ); +}; + + +QString +AComboBox::text( int index ) const { + return QComboBox::text( index ); +}; + +const QPixmap +AComboBox::pixmap( int index ) const { + return QComboBox::pixmap( index ); +}; + +void +AComboBox::changeItem( const QString &text, int index ){ + QComboBox::changeItem( text, index ); +}; + +void +AComboBox::changeItem( const QPixmap &pixmap, int index ){ + QComboBox::changeItem( pixmap, index ); +}; + +void +AComboBox::changeItem( const QPixmap &pixmap, const QString &text, int index ){ + QComboBox::changeItem( pixmap, text, index ); +}; + + +/*--bool +AComboBox::autoResize() const { + return QComboBox::autoResize(); +}; + +void +AComboBox::setAutoResize( bool val){ + QComboBox::setAutoResize( val ); +};*/ + +QSize +AComboBox::sizeHint() const { + return QComboBox::sizeHint(); +}; + +void +AComboBox::setPalette( const QPalette &pal ){ + QComboBox::setPalette( pal ); +}; + +void +AComboBox::setFont( const QFont & font) { + QComboBox::setFont( font ); +}; + +void +AComboBox::setEnabled( bool val){ + QComboBox::setEnabled( val); +}; + + +/*--void +AComboBox::setSizeLimit( int size ){ + QComboBox::setSizeLimit( size ); +}; + +int +AComboBox::sizeLimit() const { + return QComboBox::sizeLimit(); +};*/ + +void +AComboBox::setMaxCount( int cnt ){ + QComboBox::setMaxCount( cnt ); +} + +int +AComboBox::maxCount() const { + return QComboBox::maxCount(); +} + +void +AComboBox::setInsertionPolicy(QComboBox::Policy policy ){ + QComboBox::setInsertionPolicy(policy ); +} + +QComboBox::Policy +AComboBox::insertionPolicy() const{ + return QComboBox::insertionPolicy() ; +} + + +void +AComboBox::setValidator( const QValidator * v){ + QComboBox::setValidator( v ); +} + +const QValidator * +AComboBox::validator() const{ + return QComboBox::validator(); +} + +/*--void +AComboBox::setListBox( Q3ListBox * lb){ + QComboBox::setListBox( lb ); +} + +Q3ListBox * +AComboBox::listBox() const { + return QComboBox::listBox(); +}*/ + +void +AComboBox::setLineEdit( QLineEdit *edit ){ + QComboBox::setLineEdit( edit ); +} + +QLineEdit* +AComboBox::lineEdit() const{ + return QComboBox::lineEdit(); +} + + +void +AComboBox::setAutoCompletion( bool val ){ + QComboBox::setAutoCompletion( val ); +} + +bool +AComboBox::autoCompletion() const{ + return QComboBox::autoCompletion(); +} + +bool +AComboBox::eventFilter( QObject *object, QEvent *event ){ + return QComboBox::eventFilter( object, event ); +} + +void +AComboBox::setDuplicatesEnabled( bool enable ){ + QComboBox::setDuplicatesEnabled( enable ); +} + +bool +AComboBox::duplicatesEnabled() const{ + return QComboBox::duplicatesEnabled(); +} + +bool +AComboBox::editable() const{ + return QComboBox::editable(); +} + +void +AComboBox::setEditable( bool val ){ + QComboBox::setEditable( val ); +} + +void +AComboBox::popup(){ + QComboBox::popup(); +} + + +void +AComboBox::hide(){ + QComboBox::hide(); +} + + diff --git a/src/plugins/combobox/acombobox.h b/src/plugins/combobox/acombobox.h new file mode 100644 index 0000000..62c3860 --- /dev/null +++ b/src/plugins/combobox/acombobox.h @@ -0,0 +1,140 @@ +/**************************************************************************** +** $Id: acombobox.h,v 1.1 2008/11/05 21:16:29 leader Exp $ +** +** Header file of the field plugin of Ananas +** Designer and Engine applications +** +** Copyright (C) 2006 Andrey Paskal +** +** This file is part of the Ananas Plugins of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +**********************************************************************/ + +#ifndef ACOMBOBOX_H +#define ACOMBOBOX_H + + +#include +#include "qcombobox.h" +//Added by qt3to4: +#include +#include +#include +#include + + +/*! + * \en + * \brief QComboBox wrapper for AnanasScript access. + * \_en + * \ru + * \brief Плагин -- виджет обеспечивает доступ из Ананас.Скрипта ко всем публичным методам QComboBox, являясь врапером + * последнего. + * Наследует QComboBox. + * + * Смотрите документацию на QComboBox, поставляемую вместе с библиотекой QT компании TrollTech или на сайте + * http://trolltech.com + * + * Все публичные методы QComboBox доступны как публичные слоты AComboBox. + * + * \code + * var myBox=Widget("aComboBox1"); // Предполагается наличие в экранной форме комбобокса с именем aComboBox1 + * myBox.clear(); + * myBox.insertItem("Первый пункт"); + * myBox.insertItem("Второй пункт"); + * myBox.insertItem("Третий пункт"); + * myBox.setCurrentItem(1); // Порядковые номера наченаются с нуля, так что текущим делаем второй пункт. + * \endcode + * + * \_ru + */ +class QT_WIDGET_PLUGIN_EXPORT AComboBox : public QComboBox +{ + Q_OBJECT + public: + AComboBox( QWidget* parent=0, const char* name=0 ); + AComboBox( bool rw, QWidget* parent=0, const char* name=0 ); + ~AComboBox(); +public slots: + + int count() const; + + void insertStringList( const QStringList &, int index=-1 ); + //--void insertStrList( const Q3StrList &, int index=-1 ); + //--void insertStrList( const Q3StrList *, int index=-1 ); + //--void insertStrList( const char **, int numStrings=-1, int index=-1); + + void insertItem( const QString &text, int index=-1 ); + void insertItem( const QPixmap &pixmap, int index=-1 ); + void insertItem( const QPixmap &pixmap, const QString &text, int index=-1 ); + + void removeItem( int index ); + + int currentItem(); + virtual void setCurrentItem( int index ); + + QString currentText() const; + virtual void setCurrentText( const QString& ); + + QString text( int index ) const; + const QPixmap pixmap( int index ) const; + + void changeItem( const QString &text, int index ); + void changeItem( const QPixmap &pixmap, int index ); + void changeItem( const QPixmap &pixmap, const QString &text, int index ); + + //--bool autoResize() const; + //--virtual void setAutoResize( bool ); + QSize sizeHint() const; + + void setPalette( const QPalette & ); + void setFont( const QFont & ); + void setEnabled( bool ); + + //--virtual void setSizeLimit( int ); + //--int sizeLimit() const; + + + virtual void setMaxCount( int ); + int maxCount() const; + + virtual void setInsertionPolicy( Policy policy ); + QComboBox::Policy insertionPolicy() const; + + virtual void setValidator( const QValidator * ); + const QValidator * validator() const; + + //--virtual void setListBox( Q3ListBox * ); + //--Q3ListBox * listBox() const; + + virtual void setLineEdit( QLineEdit *edit ); + QLineEdit* lineEdit() const; + + virtual void setAutoCompletion( bool ); + bool autoCompletion() const; + + bool eventFilter( QObject *object, QEvent *event ); + + void setDuplicatesEnabled( bool enable ); + bool duplicatesEnabled() const; + + bool editable() const; + void setEditable( bool ); + + virtual void popup(); + + void hide(); + +}; + + +#endif diff --git a/src/plugins/combobox/acombobox_plugin.cpp b/src/plugins/combobox/acombobox_plugin.cpp new file mode 100644 index 0000000..4cec34d --- /dev/null +++ b/src/plugins/combobox/acombobox_plugin.cpp @@ -0,0 +1,91 @@ +/**************************************************************************** +** +** Code file +** +** Copyright (C) 2006 Dmitriy Pavlyuk +** +** This file is part of the Ananas Plugins of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +**********************************************************************/ + +#include "acombobox_plugin.h" + +#include + +#include "acombobox.h" + + +AComboBoxPlugin::AComboBoxPlugin(QObject *parent) + : QObject(parent), m_initialized(false) +{ + m_initialized = false; +} + +bool AComboBoxPlugin::isContainer() const +{ + return false; +} + +bool AComboBoxPlugin::isInitialized() const +{ + return m_initialized; +} + +void AComboBoxPlugin::initialize(QDesignerFormEditorInterface *core) +{ + if (m_initialized) + return; + Q_UNUSED(core); + m_initialized = true; +} + +QWidget *AComboBoxPlugin::createWidget(QWidget *parent) +{ + AComboBox *w = new AComboBox(parent, 0); + return w; +} + +QString AComboBoxPlugin::name() const +{ + return QLatin1String("AComboBox"); +} + +QString AComboBoxPlugin::group() const +{ + return QLatin1String("Ananas"); +} + +QString AComboBoxPlugin::toolTip() const +{ + return QString("Ananas for QT custom combobox"); +} + +QString AComboBoxPlugin::whatsThis() const +{ + return QString(""); +} + +QString AComboBoxPlugin::includeFile() const +{ + return QLatin1String("acombobox.h"); +} + +QIcon AComboBoxPlugin::icon() const +{ + //return QIcon(); + return QIcon(":/images/acombobox.png"); +} + +QString AComboBoxPlugin::domXml() const +{ + return "\n\n"; +} diff --git a/src/plugins/combobox/acombobox_plugin.h b/src/plugins/combobox/acombobox_plugin.h new file mode 100644 index 0000000..2f43ce1 --- /dev/null +++ b/src/plugins/combobox/acombobox_plugin.h @@ -0,0 +1,53 @@ +/**************************************************************************** +** +** Header file +** +** Copyright (C) 2006 Dmitriy Pavlyuk +** +** This file is part of the Ananas Plugins of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +**********************************************************************/ + +#ifndef ACOMBOBOX_PLUGIN_H +#define ACOMBOBOX_PLUGIN_H + +#include + +#include + + +class QT_WIDGET_PLUGIN_EXPORT AComboBoxPlugin : public QObject, public QDesignerCustomWidgetInterface +{ + Q_OBJECT + Q_INTERFACES(QDesignerCustomWidgetInterface) + +public: + AComboBoxPlugin(QObject *parent=0); + + bool isContainer() const; + bool isInitialized() const; + void initialize(QDesignerFormEditorInterface *core); + QWidget *createWidget(QWidget *parent); + + QString name() const; + QString group() const; + QString toolTip() const; + QString whatsThis() const; + QString includeFile() const; + QIcon icon() const; + QString domXml() const; + +private: + bool m_initialized; +}; + +#endif // ACOMBOBOX_PLUGIN_H diff --git a/src/plugins/combobox/combobox.pri b/src/plugins/combobox/combobox.pri new file mode 100644 index 0000000..3051470 --- /dev/null +++ b/src/plugins/combobox/combobox.pri @@ -0,0 +1,7 @@ +HEADERS += \ + combobox/acombobox.h \ + combobox/acombobox_plugin.h + +SOURCES += \ + combobox/acombobox.cpp \ + combobox/acombobox_plugin.cpp diff --git a/src/plugins/dbfield/dbfield.pri b/src/plugins/dbfield/dbfield.pri new file mode 100644 index 0000000..7599d16 --- /dev/null +++ b/src/plugins/dbfield/dbfield.pri @@ -0,0 +1,15 @@ +HEADERS += \ + dbfield/edbfield.h \ + dbfield/wdbfield.h \ + dbfield/wdbfield_plugin.h \ + dbfield/wdbfield_taskmenu.h + +SOURCES += \ + dbfield/edbfield.cpp \ + dbfield/wdbfield.cpp \ + dbfield/wdbfield_plugin.cpp \ + dbfield/wdbfield_taskmenu.cpp \ + +FORMS += \ + dbfield/edbfield.ui + \ No newline at end of file diff --git a/src/plugins/dbfield/edbfield.cpp b/src/plugins/dbfield/edbfield.cpp new file mode 100644 index 0000000..dd81233 --- /dev/null +++ b/src/plugins/dbfield/edbfield.cpp @@ -0,0 +1,137 @@ +#include "edbfield.h" + +#include +#include +#include + +#include "acfg.h" +#include "wdbfield.h" + +/* + * Constructs a eDBField as a child of 'parent', with the + * name 'name' and widget flags set to 'f'. + * + * The dialog will by default be modeless, unless you set 'modal' to + * true to construct a modal dialog. + */ +eDBField::eDBField(QWidget* parent, const char* name, bool modal, Qt::WindowFlags fl) + : QDialog(parent, name, modal, fl) +{ + setupUi(this); + + init(); +} + +/* + * Destroys the object and frees any allocated resources + */ +eDBField::~eDBField() +{ + // no need to delete child widgets, Qt does it all for us +} + +/* + * Sets the strings of the subwidgets using the current + * language. + */ +void eDBField::languageChange() +{ + retranslateUi(this); +} + + +void eDBField::init() +{ + eName->clear(); + onames.clear(); + oids.clear(); +} + + + +void eDBField::setData( QWidget *o, aCfg *md ) +{ +// const QObject *o = sender(); + if ( o ) { + if ( o->className() != QString("wDBField") || !md ) { + reject(); + return; + } + } + else { + reject(); + return; + } + int w=0, d=0, idx=0; + unsigned int i; + long oid, widgetId, fieldId; + QString pn; + aWidget *widget; + wDBField *field = (wDBField*)o; + QWidget *pWidget = field->parentWidget(); + + while ( pWidget ) { + pn = ""; + pn = pWidget->className(); + if ( pn == QString("wCatalogue") || pn == QString("wDocument") ) break; + pWidget = pWidget->parentWidget(); + } + if ( pn == QString("wCatalogue") ) widget = (wCatalogue*)pWidget; else + if ( pn == QString("wDocument") ) widget = (wDocument*)pWidget; else + return; + + widgetId = widget->getId(); + //fieldId = field->getId(); + if ( widgetId ) widget->setMDObject( md->find( widgetId ) ); + +// printf( "parent widget id = %i\n", widgetId ); +// printf( "field id = %i\n", fieldId ); +// printf( "metadata id = %i\n", md->id( *widget->getMDObject() ) ); + + QStringList tlist = md->types( md_field, widget->getMDObject() ); + otypes.clear(); + eType->clear(); + for ( QStringList::Iterator it = tlist.begin(); it != tlist.end(); ++it ) { + otypes.append( (*it).section( "\t", 0, 0 ) ); + eName->insertItem( (*it).section("\t", 1, 1 ), idx++ ); + } + for ( i = 0 ; i < otypes.count(); i++ ) { + oid = 0; + if( otypes[i][0] == 'O' ) { + sscanf( (const char *)otypes[ i ], "O %d", &oid ); + if ( oid == fieldId ) { + eName->setCurrentItem( i ); + break; + } + } + } +} + + +void eDBField::getData( QWidget *o ) +{ +// const QObject *o = sender(); + if ( !o ) return; + if ( o->className() != QString("wDBField") ) return; + wDBField *f = ( wDBField*) o; + + int idx=eName->currentItem(); + long oid = 0; + if (f) { + if( otypes[idx][0] == 'O' ) { + sscanf( (const char *)otypes[ idx ], "O %d", &oid ); + // f->setId( oid ); + } + } +} + + +void eDBField::namechanged( const QString &s ) +{ + int idx=eName->currentItem(); +// printf("new str=%s\n", (const char *) s.utf8()); + selotype=otypes[idx]; + seloid=oids[idx]; + eType->setText(onames[idx]); +} + diff --git a/src/plugins/dbfield/edbfield.h b/src/plugins/dbfield/edbfield.h new file mode 100644 index 0000000..6830c99 --- /dev/null +++ b/src/plugins/dbfield/edbfield.h @@ -0,0 +1,36 @@ +#ifndef EDBFIELD_H +#define EDBFIELD_H + +#include "ui_edbfield.h" + + +class eDBField : public QDialog, public Ui::eDBField +{ + Q_OBJECT + +public: + eDBField(QWidget* parent = 0, const char* name = 0, bool modal = false, Qt::WindowFlags fl = 0); + ~eDBField(); + + QStringList oids; + QString selotype; + QStringList otypes; + QString seloid; + +public slots: + virtual void setData( QWidget * o, aCfg * md ); + virtual void getData( QWidget * o ); + virtual void namechanged( const QString & s ); + +protected: + QStringList onames; + +protected slots: + virtual void languageChange(); + +private: + void init(); + +}; + +#endif // EDBFIELD_H diff --git a/src/plugins/dbfield/edbfield.ui b/src/plugins/dbfield/edbfield.ui new file mode 100644 index 0000000..18d158d --- /dev/null +++ b/src/plugins/dbfield/edbfield.ui @@ -0,0 +1,134 @@ + + + + + eDBField + + + + 0 + 0 + 356 + 161 + + + + Database field + + + + + + Field type + + + false + + + + + + + Field name + + + false + + + + + + + QFrame::Box + + + + + + false + + + + + + + + + + OK + + + true + + + + + + + + 101 + 31 + + + + Expanding + + + Horizontal + + + + + + + Cancel + + + + + + + + 21 + 21 + + + + Expanding + + + Vertical + + + + + + + qPixmapFromMimeSource + + ananas.h + wfield.h + wcatalogue.h + wdocument.h + + + + pushButton1 + clicked() + eDBField + accept() + + + pushButton2 + clicked() + eDBField + reject() + + + eName + activated(QString) + eDBField + namechanged(QString) + + + diff --git a/src/plugins/dbfield/wdbfield.cpp b/src/plugins/dbfield/wdbfield.cpp new file mode 100644 index 0000000..7fba231 --- /dev/null +++ b/src/plugins/dbfield/wdbfield.cpp @@ -0,0 +1,423 @@ +/**************************************************************************** +** $Id: wdbfield.cpp,v 1.1 2008/11/05 21:16:29 leader Exp $ +** +** Code file of the field plugin of Ananas +** Designer and Engine applications +** +** Created : 20031201 +** +** Copyright (C) 2003-2004 Leader InfoTech. All rights reserved. +** Copyright (C) 2003-2004 Grigory Panov, Yoshkar-Ola. +** +** This file is part of the Ananas Plugins of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.leaderit.ru/page=ananas or email sales@leaderit.ru +** See http://www.leaderit.ru/gpl/ for GPL licensing information. +** +** Contact org@leaderit.ru if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#include +#include +//Added by qt3to4: +#include + +#include "ananas.h" +#include "wfield.h" +#include "edbfield.h" +#include "wdbfield.h" +#include "addfdialog.h" +//--#include "mainform.h" + + + +/*! + * \en Constructor without name. \_en + * \ru Создает конструктор без указания имени виджета. \_ru + */ +wDBField::wDBField( QWidget *parent, Qt::WFlags fl ) + : wField( parent, "wDBField", fl) +{ + init(); +} + + + +/*! + * \en Constructor. \_en + * \ru Конструктор. \_ru + */ +wDBField::wDBField( QWidget *parent, const char *name, Qt::WFlags fl ) + : wField( parent, name, fl) +{ + init(); +} + + + +/*! + * \en Destructor. \_en + * \ru Деструктор. \_ru + */ +wDBField::~wDBField() +{ + +} + + +/*! + * \en Creates property editor dialog window. \_en + * \ru Создает окно диалога редактора свойств.\_ru + * \param parent - \en parent \_en \ru родитель \_ru + */ +QDialog* +wDBField::createEditor( QWidget *parent ) +{ + return new addfdialog( parent ); +} + + +/*! + * \en Opens property editor dialog form. \_en + * \ru Открывает окно диалога редактора свойств. \_ru + */ +void wDBField::openEditor() +{ +/* + QString s; + QValueList bindList = getBindList(); + addfdialog e(this->topLevelWidget()); + getFields(); + e.setData( defDisplayFields, defFields,defId); + e.ListBox->setCurrentItem(e.ListBox->findItem(getFieldName())); + if ( e.exec()==QDialog::Accepted ) + { + s = e.getData(true); + if(s.isEmpty()) return; + setFieldName(s); + s = e.getData(false); + if(s=="0") return; + // if select binding field + if(bindList.find(s.toULongLong()) != bindList.end()) + { + cfg_message(0, tr("field already binding, please select another field.")); + return; + } + setId(s.toInt()); + setEditorType(); + updateProp(); + } + */ +} + + + + + + + +/*! + * \en Sets property value `fieldName'. \_en + * \ru Устанавливает значение свойства `fieldName'. \_ru + */ +void +wDBField::setFieldName( QString n ) +{ + FieldName=n; +} + + +/*! + * \en Gets field name in metadata. \_en + * \ru Получение имени поля в метаданных, на которое настроен виджет. \_ru + * return - \en Field name. \_en \ru Имя поля в метаданных.\_ru + */ +/* +QString +wDBField::getMdFieldName() const +{ + aCfgItem o = md->find(getId()); + if(!o.isNull()) + { + return md->attr(o,mda_name); + } + else + { + return getFieldName(); + } +} +*/ +/*! + * \en Inits widget. Gets copy of metadata from designer window. \_en + * \ru Инициализирунт виджет. + * Получает метаданные из окна дизайнера. \_ru + */ +void +wDBField::init() +{ + qulonglong id; + id=0; + //get copy of metadata + md = getMd(); + if(md) + { + // get id of container object - catalogue or document + id = aWidget::parentContainer(this)->getId(); + head = md->find(id); + } +} + + + +/*! + * \en Gets list of fields and id for Document.Header or Catalogue.Element and + * Catalogue.Group \_en + * \ru Возвращает список полей, определенных в метаданных, для шапки документа + * или элемента и группы каталога. + * К имени уже забинденного поля добавляет впереди звездочку. + * Для групп и элементов каталога добавляет в конце (element) или (group) \_ru + * \return \en List of field name \_en \ru Список имен полей \_ru + */ +QStringList +wDBField::getFields() +{ + QStringList lst, dlst; + QString str; + int res,i; + Q3ValueList bindList = getBindList(); + aCfgItem o, o_head; + defId.clear(); + defFields.clear(); + defDisplayFields.clear(); + if(!head.isNull()) + { + if(md->objClass(head) == md_catalogue) + { +// printf("getting fields from metadata\n"); + o = md->findChild(head,md_element); //object element + res = md->countChild(o,md_field); +// printf("find elements\n"); + for( i = 0; i < res; i++ ) + { +// printf("find %d elem\n",i); + o_head = md->findChild(o,md_field,i); + if(md->attr(o_head,mda_type).at(0)!=' ') + { +// printf("mda_type = %s\n",md->attr(o_head,mda_type).ascii()); + lst << md->attr(o_head,mda_name); + dlst << md->attr(o_head,mda_name) + " (element)"; + defId << md->attr(o_head,mda_id); + } + else + { +// printf("calculated field not allowed here\n"); + } + } + o = md->findChild(head,md_group); // object group + res = md->countChild(o,md_field); +// printf("find groups\n"); + for( i = 0; i < res; i++ ) + { +// printf("find %d group\n",i); + o_head = md->findChild(o,md_field,i); + //--if(md->attr(o,mda_type).left(1)!=' ') + if(md->attr(o,mda_type).at(0)!=' ') + { + lst << md->attr(o_head,mda_name); + dlst << md->attr(o_head,mda_name) + " (group)"; + defId << md->attr(o_head,mda_id); + } + } + } + else + { + o = md->findChild(head,md_header); // object header + res = md->countChild(o,md_field); + for( i = 0; i < res; i++ ) + { + o_head = md->findChild(o,md_field,i); + dlst << md->attr(o_head,mda_name); + lst << md->attr(o_head,mda_name); + defId << md->attr(o_head,mda_id); + } + } + res = lst.count(); + for(int i=0; i>>>>>> 1.37.2.4 +return defFields; +} + + + +//<<<<<<< wdbfield.cpp +/* + * \en Updates object. \_en + * \ru Записывает значение объекта в базу. \_ru +*/ +/* +int +wDBField::Update() +{ + if(dbobj) + { + return dbobj->Update(); + } + else + { + return err_abstractobj; + } +} +*/ + + +/* + * \en Inits object. \_en + * \ru Инициализирует объект. \_ru +*/ +/* +aObject * +wDBField::createDBObject(aCfgItem o, aDatabase *adb ) +{ +// wField::initObject( adb ); + // aCfgItem o; + / o = md->find( getId() ); + aObject* obj = new aObject(o,adb); + aCfgItem g = md->parent( o );//, e = md->find( obj, md_element ); + obj->tableInsert( aDatabase::tableDbName( *md, g ), g ); + debug_message("table inserted\n"); + return obj; +} +*/ +void +wDBField::initObject(aDatabase *adb ) +{ + wField::initObject( adb ); + //aCfgItem o; + //o = md->find( getId() ); + //aObject* obj = new aObject(o,adb); + //tableInsert( aDatabase::tableDbName( *md, o ), o ); +// debug_message("init dbfield \n"); +} + +//======= +//>>>>>>> 1.37.2.4 +/*! + * \en Set widget type, use property `Id'. \_en + * \ru Устанавливает тип виджета, используя свойство `Id'. \_ru + */ +void +wDBField::setEditorType () +{ + aCfgItem o_head,o; + QString str, type; + int id; + if(!head.isNull()) + { + id = property("Id").toInt(); + o_head = md->find(id); + if(!o_head.isNull()) + { + type = md->attr(o_head,mda_type); + setFieldType(type); + str = type.section(' ',0,0); + // gets type of editor + if(str=="N") wField::setEditorType(Numberic); + if(str=="C") wField::setEditorType(String); + if(str=="D") wField::setEditorType(Date); + if(str=="B") wField::setEditorType(Boolean); + if(str=="O") + { + //editor type is Object . + //May be Catalog or Document. + qulonglong tid; + //gets object id. + str = type.section(' ',1,1); + tid = atol(str); + o = md->find(tid); + if(!o.isNull()) + { + //gets object class + str = md->objClass(o); + if(str == md_catalogue) + // and set editor + wField::setEditorType(Catalogue); + if(str == md_document) + wField::setEditorType(Document); + + } + + } + + } + + } + +} + + +/*! + * \en Gets list of binding fields id. \_en + * \ru Получает список id забинденых полей. Корректно работает с удаленными + * виджетами. \_ru + * \return \en List of binding fields id. \_en + * \ru Список id забинденых полей. \_ru + */ +Q3ValueList +wDBField::getBindList() +{ +aCfgItem obj; +QObjectList wList; +int id; +Q3ValueList listBindings; +wDBField* wfield; +QObject* wd = aWidget::parentContainer (this); + listBindings.clear(); + wList = wd->queryList( "wDBField" ); + QListIterator it( wList ); // iterate over the wDBTable + while ( it.hasNext() ) + { + wfield = qobject_cast( it.next() ); + + if(strcmp(wfield->name(),this->name())) // don't added current id + { + //don.t added deleted widgets + if(strncmp("qt_dead_widget_",wfield->name(),strlen("qt_dead_widget_"))) + { + id = wfield->property("Id").toULongLong(); + // if(id>=0) // don't added negativ id (table while not selected) + // { + listBindings << id; +// printf(">>>added id = `%d'\n",id); + // } + } + } + } + //--delete wList; +return listBindings; +} + diff --git a/src/plugins/dbfield/wdbfield.h b/src/plugins/dbfield/wdbfield.h new file mode 100644 index 0000000..2eea7a9 --- /dev/null +++ b/src/plugins/dbfield/wdbfield.h @@ -0,0 +1,98 @@ +/**************************************************************************** +** $Id: wdbfield.h,v 1.1 2008/11/05 21:16:29 leader Exp $ +** +** Header file of the field plugin of Ananas +** Designer and Engine applications +** +** Created : 20031201 +** +** Copyright (C) 2003-2004 Leader InfoTech. All rights reserved. +** Copyright (C) 2003-2004 Grigory Panov, Yoshkar-Ola. +** +** This file is part of the Ananas Plugins of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.leaderit.ru/page=ananas or email sales@leaderit.ru +** See http://www.leaderit.ru/gpl/ for GPL licensing information. +** +** Contact org@leaderit.ru if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#ifndef QADBFIELD_H +#define QADBFIELD_H + +#include +#include +#include +#include +#include +#include +#include +//Added by qt3to4: +#include +#include "adatabase.h" +#include "acfg.h" +#include "wfield.h" +//#include "addfdialog.h" + +/*! + * \en + * \brief Ananas DBField. widget. + * \_en + * \ru + * \brief Универсальный Плагин -- виджет, предназначен для редактирования атрибутов бизнес объектов Ананаса. + * Наследует wField. + * + * Основным полезным свойством этого визуального класса является возможность его привязки к атрибуту persistence бизнес объекта + * Ананаса. Как только привязка задана - логика заполнения объекта значением соответствующего атрибута бизнес объекта, логика + * сохранения заданного пользователем значения в соответствующем атрибуте бизнес объекта выполняется автоматически runtime + * подсистемой Ананаса. То есть мы используем прием, который имеет общепринятое название data bindings. + * + * \_ru + */ +class QT_WIDGET_PLUGIN_EXPORT wDBField : public wField +{ + Q_OBJECT + + Q_PROPERTY( bool openEditor READ getOpenEditor WRITE setOpenEditor STORED false) + Q_PROPERTY( QString FieldName READ getFieldName WRITE setFieldName ) + +friend class addfdialog; + + +public: + + wDBField( QWidget *parent, Qt::WFlags fl ); + wDBField( QWidget *parent, const char *name, Qt::WFlags fl ); + ~wDBField(); + + virtual QDialog* createEditor( QWidget *parent ); + virtual void initObject( aDatabase *adb ); + void openEditor(); + bool getOpenEditor() const { return false; }; + virtual QString getFieldName() const { return FieldName; }; + void setOpenEditor(bool b) { if(b) openEditor(); }; + void setFieldName(QString n); +protected: + QStringList getFields(); + void init(); + Q3ValueList getBindList(); + void setEditorType(void); + + QString FieldName; + QStringList defDisplayFields,defFields,defId; + +private: + aCfgItem head; +}; +#endif diff --git a/src/plugins/dbfield/wdbfield_plugin.cpp b/src/plugins/dbfield/wdbfield_plugin.cpp new file mode 100644 index 0000000..edba874 --- /dev/null +++ b/src/plugins/dbfield/wdbfield_plugin.cpp @@ -0,0 +1,104 @@ +/**************************************************************************** +** +** Code file +** +** Copyright (C) 2006 Dmitriy Pavlyuk +** +** This file is part of the Ananas Plugins of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +**********************************************************************/ + +#include "wdbfield_plugin.h" + +#include +#include +#include + +#include "wdbfield_taskmenu.h" +#include "wdbfield.h" + + +wDBFieldPlugin::wDBFieldPlugin(QObject *parent) + : QObject(parent), m_initialized(false) +{ + m_initialized = false; +} + +bool wDBFieldPlugin::isContainer() const +{ + return false; +} + +bool wDBFieldPlugin::isInitialized() const +{ + return m_initialized; +} + +void wDBFieldPlugin::initialize(QDesignerFormEditorInterface *core) +{ + if (m_initialized) + return; + Q_UNUSED(core); + + QExtensionManager *manager = core->extensionManager(); + Q_ASSERT(manager != 0); + manager->registerExtensions(new wDBFieldTaskMenuFactory(manager), + Q_TYPEID(QDesignerTaskMenuExtension)); + + m_initialized = true; + printf("dbfield inited\n"); +} + +QWidget *wDBFieldPlugin::createWidget(QWidget *parent) +{ + wDBField *w = new wDBField(parent, 0); + return w; +} + +QString wDBFieldPlugin::name() const +{ + return QLatin1String("wDBField"); +} + +QString wDBFieldPlugin::group() const +{ + return QLatin1String("Ananas"); +} + +QString wDBFieldPlugin::toolTip() const +{ + return QString("Ananas for QT Database Field Edit Widget"); +} + +QString wDBFieldPlugin::whatsThis() const +{ + return QString("Entry to modify field value of Ananas's object"); +} + +QString wDBFieldPlugin::includeFile() const +{ + return QLatin1String("wdbfield.h"); +} + +QIcon wDBFieldPlugin::icon() const +{ + //return QIcon(); +//QIcon i = QIcon(":/images/wdbfield.png"); +//if (i.isNull()) printf("FIELD ICON is NULL\n"); +//else printf("field icon OK\n"); + return QIcon(":/images/wdbfield.png"); +} + +QString wDBFieldPlugin::domXml() const +{ + return "\n\n"; +} diff --git a/src/plugins/dbfield/wdbfield_plugin.h b/src/plugins/dbfield/wdbfield_plugin.h new file mode 100644 index 0000000..7d91c11 --- /dev/null +++ b/src/plugins/dbfield/wdbfield_plugin.h @@ -0,0 +1,53 @@ +/**************************************************************************** +** +** Header file +** +** Copyright (C) 2006 Dmitriy Pavlyuk +** +** This file is part of the Ananas Plugins of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +**********************************************************************/ + +#ifndef WDBFIELD_PLUGIN_H +#define WDBFIELD_PLUGIN_H + +#include + +#include "qwidgetplugin.h" + + +class QT_WIDGET_PLUGIN_EXPORT wDBFieldPlugin : public QObject, public QDesignerCustomWidgetInterface +{ + Q_OBJECT + Q_INTERFACES(QDesignerCustomWidgetInterface) + +public: + wDBFieldPlugin(QObject *parent=0); + + bool isContainer() const; + bool isInitialized() const; + void initialize(QDesignerFormEditorInterface *core); + QWidget *createWidget(QWidget *parent); + + QString name() const; + QString group() const; + QString toolTip() const; + QString whatsThis() const; + QString includeFile() const; + QIcon icon() const; + QString domXml() const; + +private: + bool m_initialized; +}; + +#endif // WDBFIELD_PLUGIN_H diff --git a/src/plugins/dbfield/wdbfield_taskmenu.cpp b/src/plugins/dbfield/wdbfield_taskmenu.cpp new file mode 100644 index 0000000..aec82e0 --- /dev/null +++ b/src/plugins/dbfield/wdbfield_taskmenu.cpp @@ -0,0 +1,74 @@ +/**************************************************************************** +** +** Copyright (C) 2006 Dmitriy Pavlyuk All rights reserved. +** +** This file is part of the widgets plugin of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +****************************************************************************/ + +#include + +#include + +#include "wdbfield_taskmenu.h" +#include "wdbfield.h" +#include "addfdialog.h" + + +wDBFieldTaskMenu::wDBFieldTaskMenu(wDBField *widget, QObject *parent) + : QObject(parent) +{ + m_widget = widget; + + m_editAction = new QAction(tr("Edit ..."), this); + connect(m_editAction, SIGNAL(triggered()), this, SLOT(edit())); +} + +void wDBFieldTaskMenu::edit() +{ + /*addfdialog e; + + e.setData(m_widget); + if (e.exec() == QDialog::Accepted) + { + e.getData(m_widget); + }*/ + m_widget->widgetEditor(); +} + +QAction *wDBFieldTaskMenu::preferredEditAction() const +{ + return m_editAction; +} + +QList wDBFieldTaskMenu::taskActions() const +{ + QList list; + list.append(m_editAction); + return list; +} + +wDBFieldTaskMenuFactory::wDBFieldTaskMenuFactory(QExtensionManager *parent) + : QExtensionFactory(parent) +{ +} + +QObject *wDBFieldTaskMenuFactory::createExtension(QObject *object, const QString &iid, QObject *parent) const +{ + if (iid != Q_TYPEID(QDesignerTaskMenuExtension)) + return 0; + + if (wDBField *df = qobject_cast(object)) + return new wDBFieldTaskMenu(df, parent); + + return 0; +} diff --git a/src/plugins/dbfield/wdbfield_taskmenu.h b/src/plugins/dbfield/wdbfield_taskmenu.h new file mode 100644 index 0000000..9ae82dd --- /dev/null +++ b/src/plugins/dbfield/wdbfield_taskmenu.h @@ -0,0 +1,57 @@ +/**************************************************************************** +** +** Copyright (C) 2006 Dmitriy Pavlyuk All rights reserved. +** +** This file is part of the widgets plugin of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +****************************************************************************/ + +#ifndef WDBFIELD_TASKMENU_H +#define WDBFIELD_TASKMENU_H + +#include +#include + + +class QExtensionManager; +class QAction; +class wDBField; + +class wDBFieldTaskMenu: public QObject, public QDesignerTaskMenuExtension +{ + Q_OBJECT + Q_INTERFACES(QDesignerTaskMenuExtension) +public: + wDBFieldTaskMenu(wDBField *widget, QObject *parent); + + QAction *preferredEditAction() const; + QList taskActions() const; + +private slots: + void edit(); + +private: + QAction *m_editAction; + wDBField *m_widget; +}; + +class wDBFieldTaskMenuFactory: public QExtensionFactory +{ + Q_OBJECT +public: + wDBFieldTaskMenuFactory(QExtensionManager *parent = 0); + +protected: + QObject *createExtension(QObject *object, const QString &iid, QObject *parent) const; +}; + +#endif // WDBFIELD_TASKMENU_H diff --git a/src/plugins/dbtable/dbtable.pri b/src/plugins/dbtable/dbtable.pri new file mode 100644 index 0000000..5e2a3cb --- /dev/null +++ b/src/plugins/dbtable/dbtable.pri @@ -0,0 +1,15 @@ +HEADERS += \ + dbtable/edbtable.h \ + dbtable/wdbtable.h \ + dbtable/wdbtable_plugin.h \ + dbtable/wdbtable_taskmenu.h + +SOURCES += \ + dbtable/edbtable.cpp \ + dbtable/wdbtable.cpp \ + dbtable/wdbtable_plugin.cpp \ + dbtable/wdbtable_taskmenu.cpp + +FORMS += \ + dbtable/edbtable.ui + diff --git a/src/plugins/dbtable/edbtable.cpp b/src/plugins/dbtable/edbtable.cpp new file mode 100644 index 0000000..2477cda --- /dev/null +++ b/src/plugins/dbtable/edbtable.cpp @@ -0,0 +1,521 @@ +#include "edbtable.h" + +#include +#include +#include + +#include +#include "wdbtable.h" +//Added by qt3to4: +#include +#include + +/* + * Constructs a eDBTable as a child of 'parent', with the + * name 'name' and widget flags set to 'f'. + * + * The dialog will by default be modeless, unless you set 'modal' to + * true to construct a modal dialog. + */ +eDBTable::eDBTable(QWidget* parent, const char* name, bool modal, Qt::WindowFlags fl) + : QDialog(parent, name, modal, fl) +{ + setupUi(this); + + init(); +} + +/* + * Destroys the object and frees any allocated resources + */ +eDBTable::~eDBTable() +{ + destroy(); + // no need to delete child widgets, Qt does it all for us +} + +/* + * Sets the strings of the subwidgets using the current + * language. + */ +void eDBTable::languageChange() +{ + retranslateUi(this); +} + +void eDBTable::init() +{ +} + + +void +eDBTable::destroy() +{ +// tablerow_free( r ); +} + + +/* +void eDBTable::insertColumn(const char *Header, const char *Name, +int idxt, int cw, int tw, int td) +{ + +tablefield *f; +char s[30]; + +sprintf(s, "%s %i %i", (const char *)otypes[idxt], tw, td); + +f = tablefield_newsys(Name, s, ""); +tablefield_setheader(f, Header); +f->sizex = cw; +f->flen = tw; +f->decimals = td; +f->ftypeindex = idxt; +tablerow_insertcolumn(r, f, -1); + +// blockSignals( true ); +ListCol->insertItem(trUtf8(Header)); +// eColHeader->setText( trUtf8(Header)); +// eColName->setText(trUtf8(Name)); +// eColWidth->setValue(cw); +// eColTWidth->setValue(tw); +// eColTDec->setValue(td); +// blockSignals( false ); +if (ListCol->count()) ListCol->setCurrentItem(ListCol->count()-1); + +} +*/ + + + +void eDBTable::ColumnDel() +{ + +int idx; +QString str; +idx = ListCol->currentItem(); +if (idx != -1 && ListCol->count()>0) +{ + str = fname[idx]; + table->removeColumn(idx); + deletedFields.append(str); + deletedFieldsId.append(idlist[idx]); + idlist.remove(idlist.at(idx)); + fname.remove(fname.at(idx)); + cwidth.remove(cwidth.at(idx)); + ListCol->removeItem(idx); +// table->removeColumn(idx); +} +} + +void eDBTable::ColumnL() +{ + int idx; + QString str; + QStringList::Iterator it; + idx = ListCol->currentItem(); + if(idx>0) + { + str = fname[idx]; + //--it = fname.at(idx); + //--fname.remove(it); + fname.removeAt(idx); + //--it = fname.at(idx-1); + //--fname.insert(it,str); + fname.insert(idx-1,str); + + str = idlist[idx]; + //--it = idlist.at(idx); + //--idlist.remove(it); + idlist.removeAt(idx); + //--it = idlist.at(idx-1); + //--idlist.insert(it,str); + idlist.insert(idx-1,str); + + str = cwidth[idx]; + //--it = cwidth.at(idx); + //--cwidth.remove(it); + cwidth.removeAt(idx); + //--it = cwidth.at(idx-1); + //--cwidth.insert(it,str); + cwidth.insert(idx-1,str); + + str = ListCol->currentText(); + ListCol->removeItem(idx); + ListCol->insertItem(str,idx-1); + ListCol->setSelected(idx-1,true); + } +} + + +void eDBTable::ColumnR() +{ + uint idx; + QString str; + QStringList::Iterator it; + idx = ListCol->currentItem(); + if(idxcount()-1) + { + str = fname[idx]; + //--it = fname.at(idx); + //--fname.remove(it); + fname.removeAt(idx); + //--it = fname.at(idx+1); + //--fname.insert(it,str); + fname.insert(idx+1,str); + + str = idlist[idx]; + //--it = idlist.at(idx); + //--idlist.remove(it); + idlist.removeAt(idx); + //--it = idlist.at(idx+1); + //--idlist.insert(it,str); + idlist.insert(idx+1,str); + + str = cwidth[idx]; + //--it = cwidth.at(idx); + //--cwidth.remove(it); + cwidth.removeAt(idx); + //--it = cwidth.at(idx+1); + //--cwidth.insert(it,str); + cwidth.insert(idx+1,str); + + str = ListCol->currentText(); + ListCol->removeItem(idx); + ListCol->insertItem(str,idx+1); + ListCol->setSelected(idx+1,true); + } + +} +void eDBTable::ColumnSel(int col) +{ +QString str,s; +int ind = 0; +QStringList lst; + eColHeader->blockSignals(true); + eColWidth->blockSignals(true); + eType->clear(); + eColTWidth->setValue(0); + eColTDec->setValue(0); + eColHeader->setText(""); + eColWidth->setValue(0); + eColName->setText(""); +// str = table->getFieldType((const char*) ComboBoxTable->currentText().utf8(),(const char*)ListCol->currentText().utf8()); + //if(eColHeader->text="") +// ListCol->blockSignals( TRUE ); + //ListCol->changeItem(s, ListCol->currentItem()); + +// printf(">>>read property DefHeaders in %s\n", table->name()); +// lst = table->property("DefHeaders").toStringList(); +// printf(">>>ok!\n"); +// ListCol->clear(); +// printf(">>>insert str list\n"); +// ListCol->insertStringList(lst); +// ListCol->setCurrentItem(col); +// ListCol->blockSignals( FALSE ); + if(col==-1 || ListCol->count()==0) return; +// printf(">>>set text in eColHeader\n"); + eColHeader->setText(ListCol->currentText()); + eColHeader->blockSignals(false); + ind = ListCol->currentItem(); + str = cwidth[ind]; + eColWidth->setValue(atoi(str)); + eColWidth->blockSignals(false); + str = fname[ind]; + eColName->setText(str); +// eType->clear(); +// printf(">>>get fields type\n"); +// str = eColName->text(); + + str = table->getFieldType(idlist[ind].toInt()); +// parse string with type, num, numdec + if(!str.isEmpty()) + { + eType->setText(str.left(1)); + str.remove(0,2); + if(!str.isEmpty()) + { +// printf(">>>%s\n",str.ascii()); + eColTWidth->setValue(atoi(str)); + } + ind = str.find(" "); + if(ind)// poisk decimal chasti + { + s = str.remove(0,str.find(" ")); + } + else + { + str="0"; + } +// printf(">>>%s\n",str.ascii()); + eColTDec->setValue(atoi(str)); + } + else + { +// printf(">>>unknown field\n"); + } + /* + tablefield *f; + + if (col >= 0 && col < tablerow_columns( r )) { + f = tablerow_column( r, col ); + blockSignals( true ); + eColHeader->setText(trUtf8(tablefield_header( f ))); + eColWidth->setValue(f->sizex); + eType->setCurrentItem(f->ftypeindex); + eColName->setText(trUtf8(f->name)); + eColTWidth->setValue(f->flen); + eColTDec->setValue(f->decimals); + blockSignals( false ); + } +*/ +} + + +void eDBTable::ColumnUpd() +{ +QStringList lst; +int id; +Q3ValueList listTableId; + id = table->getTableId(ComboBoxTable->currentItem()-1); + listTableId = table->getBindList(); + if(listTableId.find(id)!=listTableId.end()) + { + cfg_message(0,tr("table in use, please select another table")); + // ComboBoxTable->setCurrentItem(table->getTableInd(table->property("TableInd").toInt())); + ListCol->clear(); + ListCol->insertItem("table in use!"); + ListCol->setEnabled(false); + bOK->setEnabled(false); + ColumnSel(-1); // clear all line edit and labels + return; + } + if(!ListCol->isEnabled()) ListCol->setEnabled(true); + if(!bOK->isEnabled()) bOK->setEnabled(true); + lst = table->getFields(id); + ListCol->clear(); + fname = lst; + idlist = table->getFields(id,true); + ListCol->insertStringList(lst,0); + cwidth.clear(); + for(uint i=0; iproperty("DefaultColWidth").toString(); + } + //fname = table->fname; + findDeletedFields(id,idlist); + +} + + +void eDBTable::getData( wDBTable *t ) +{ +QStringList lst; +QString str, str2; +int i; +const Q3SqlFieldInfo *f; + if(ComboBoxTable->count()) + { + // t->setProperty("TableInd", tables[ComboBoxTable->currentItem()].section("\t",0,0).toInt()) + t->setProperty("TableInd",t->getTableId(ComboBoxTable->currentItem()-1)); + i=0; + while(inumCols()) + { + t->removeColumn(0); + ++i; + } + t->cur->clear(); + for(uint j=0; jcount(); j++) + { + ListCol->setCurrentItem(j); + str = ListCol->currentText(); + lst << str; + f = new Q3SqlFieldInfo(fname[j]); + t->cur->append(*f); + t->setSqlCursor(t->cur); + t->addColumn(f->name(),str,atoi(cwidth[j].ascii())); + t->refresh(Q3DataTable::RefreshColumns); + } + t->setProperty("DefHeaders",lst); + t->setProperty("DefFields",fname); + t->setProperty("DefIdList",idlist); + t->setProperty("ColWidth", cwidth); + } + else + { + t->setProperty("TableInd",-1); + } +} + + +void eDBTable::setData( wDBTable * t, aCfg *md ) + +{ +QStringList sl; +QString ft,h,n; +int idTable; +bool ok; +QStringList lst,lst_full; +aCfgItem own; +aWidget *wo; + table = t; +// md->print(); +// own = + // wo = aWidget::parentContainer( t ); + // if ( !wo ) return; + // tables = md->objTables( wo->getId() ); + // QString wotype = wo->className(); +// if ( wotype == "wDocument" ) tables.remove( tables[0] ); +// if ( wotype == "wCatalogue" ) tables.remove( tables[1] ); +// printf("tables=\n%s\n", ( const char *) tables.join("\n") ); +// for ( unsigned int i=0; i < tables.count(); i++ ) { +// ComboBoxTable->insertItem( tables[ i ].section("\t", 1 ) ); +// } +// ComboBoxTable->insertItem("None"); + ComboBoxTable->insertStringList(table->list_available_tables, 1); + idTable = table->property("TableInd").toInt(&ok); + // printf("table ind = %i, id table =%i\n", t->getTableInd(idTable), idTable ); + + ComboBoxTable->setCurrentItem(1+t->getTableInd(idTable)); + if(ok && idTable>-1) + { + // v = new QVariant(lst); + // } + // else + // { + // table->setFields(t->getTableId(0)); + // v = new QVariant(lst); + //table->setProperty("DefFields",*v); + // } + // v = new QVariant(lst); +// table->setProperty("DefHeaders",*v); + // table->setProperty("ColWidth",*v); + //ComboBoxTable->setFocus(); +// tmp_table = *t; + lst = table->property("DefHeaders").toStringList(); + ListCol->insertStringList(lst,0); + cwidth = table->property("ColWidth").toStringList(); + fname = table->property("DefFields").toStringList(); + idlist = table->property("DefIdList").toStringList(); + findDeletedFields(idTable,idlist); + } + else + { + ColumnUpd(); + } + ListCol->setFocus(); + /* if(!ListCol->isEmpty()) + { + ColumnSel(0); + } + */ + /* + if (!t->getDefineCols().isEmpty()) { + sl = QStringList::split("\n",t->getDefineCols()); + for (i = 0; i < sl.count(); i++) { + sscanf((const char *)sl[i].section("|",3,3),"%s %d %d", st, &l, &d); + if (st[0]=='O') ft.sprintf("O %d",l); + else ft=st; + w = sl[i].section("|",2,2).toInt(); + h = sl[i].section("|",5,5); + n = sl[i].section("|",4,4); + for (idxt = otypes.count()-1; idxt>0; idxt--) { + if (ft[0]=='O' && otypes[idxt]==ft) break; + else if (otypes[idxt][0]==ft[0]) break; + } + printf("set data %i = %s %s %i %i %i\n", i, + (const char *)h, (const char *)n, idxt, w, l); + insertColumn(h,n,idxt,w,l,d); + } + } + */ + + +} + + +void eDBTable::ColumnTextUpd( const QString &s ) +{ +CHECK_POINT + + int idx; + idx = ListCol->currentItem(); + if (idx == -1) return; + ListCol->blockSignals( TRUE ); + ListCol->changeItem(s, ListCol->currentItem()); + ListCol->blockSignals( FALSE ); + +} + + +void eDBTable::doOK() +{ + getData(table); + accept(); +} + + +void eDBTable::ColumnAdd() +{ +QString s; +QString idx; +QStringList::Iterator it; + addfdialog e( this->topLevelWidget()); + e.setData(deletedFields,deletedFields,deletedFieldsId); + if ( e.exec()==QDialog::Accepted ) + { + idx = e.getData(false); +// printf(">>>idx = %s\n",idx.ascii()); + if(idx=="0") return; + s = table->getFieldName(idx.toInt()); + idlist << idx; +// printf(">>> add field = '%s'\n",s.ascii()); + ListCol->insertItem(s,ListCol->count()); + fname << s; + cwidth << table->property("DefaultColWidth").toString(); + it = deletedFields.find(s); + deletedFields.remove(it); + it = deletedFieldsId.find(idx); + deletedFieldsId.remove(it); +// table->addColumn(s,s,100); + } +} + + +void eDBTable::ColWidthChange( int value ) +{ + int ind; + QString num; + ind = ListCol->currentItem(); + if(ind!=-1) + { + cwidth[ind] = num.setNum(value); + } + +} + + +QStringList +eDBTable::findDeletedFields( int t_num ,QStringList idls) +{ + QStringList lst_full; + deletedFields.clear(); + //formiruem list udalennix poley + lst_full = table->getFields(t_num,true); + for(unsigned int i=0;i>>field '%s'\n",lst_full[i].ascii()); + if(idls.find(lst_full[i])==idls.end()) + { + deletedFieldsId << lst_full[i]; + deletedFields << table->getFieldName(lst_full[i].toInt()); + } + } +return deletedFields; +} + + +void eDBTable::doCancel() +{ +} + diff --git a/src/plugins/dbtable/edbtable.h b/src/plugins/dbtable/edbtable.h new file mode 100644 index 0000000..3e59031 --- /dev/null +++ b/src/plugins/dbtable/edbtable.h @@ -0,0 +1,48 @@ +#ifndef EDBTABLE_H +#define EDBTABLE_H + +#include "ui_edbtable.h" + + +class eDBTable : public QDialog, public Ui::eDBTable +{ + Q_OBJECT + +public: + eDBTable(QWidget* parent = 0, const char* name = 0, bool modal = false, Qt::WindowFlags fl = 0); + ~eDBTable(); + + QStringList deletedFields, deletedFieldsId; + wDBTable *table; + + virtual QStringList findDeletedFields( int t_num, QStringList idls ); + +public slots: + virtual void ColumnDel(); + virtual void ColumnL(); + virtual void ColumnR(); + virtual void ColumnSel( int col ); + virtual void ColumnUpd(); + virtual void getData( wDBTable * t ); + virtual void setData( wDBTable * t, aCfg * md ); + virtual void ColumnTextUpd( const QString & s ); + virtual void doOK(); + virtual void ColumnAdd(); + virtual void ColWidthChange( int value ); + virtual void doCancel(); + +signals: + void closeEvent(); + +protected slots: + virtual void languageChange(); + +private: + QStringList otypes, fname, cwidth,idlist, tables; + + virtual void init(); + virtual void destroy(); + +}; + +#endif // EDBTABLE_H diff --git a/src/plugins/dbtable/edbtable.ui b/src/plugins/dbtable/edbtable.ui new file mode 100644 index 0000000..760b73b --- /dev/null +++ b/src/plugins/dbtable/edbtable.ui @@ -0,0 +1,448 @@ + + + + + eDBTable + + + + 0 + 0 + 479 + 348 + + + + aDBTable + + + + + + + + true + + + + 0 + 0 + 0 + 0 + + + + QFrame::NoFrame + + + QFrame::Plain + + + Table name + + + false + + + + + + + + + + + + + + + + + + + + OK + + + true + + + + + + + Cancel + + + + + + + + 301 + 21 + + + + Expanding + + + Horizontal + + + + + + + + + Column list + + + + + + 1 + + + 0 + + + 1 + + + + + + + + + + Column + + + + + + + + + 0 + 5 + 0 + 0 + + + + + 120 + 0 + + + + Header + + + false + + + + + + + 100 + + + + + + + + + + + + 0 + 5 + 0 + 0 + + + + + 120 + 0 + + + + Column width + + + false + + + + + + + 9999 + + + + + + + + + + + Width + + + false + + + + + + + false + + + 255 + + + + + + + + + + + Delete + + + + + + + Up + + + + + + + Down + + + + + + + Add + + + + + + + + + + + + 0 + 5 + 0 + 0 + + + + + 120 + 0 + + + + Field name + + + false + + + + + + + 300 + + + true + + + + + + + + + + + + 0 + 0 + 0 + 0 + + + + + 120 + 0 + + + + Field type + + + false + + + + + + + + + + false + + + + + + + + + + + decimal + + + false + + + + + + + false + + + 9 + + + + + + + + + + + + qPixmapFromMimeSource + + wdbtable.h + ananas.h + addfdialog.h + + + + bOK + clicked() + eDBTable + accept() + + + bCancel + clicked() + eDBTable + reject() + + + bColAdd + clicked() + eDBTable + ColumnAdd() + + + bColDel + clicked() + eDBTable + ColumnDel() + + + bColL + clicked() + eDBTable + ColumnL() + + + bColR + clicked() + eDBTable + ColumnR() + + + ListCol + highlighted(int) + eDBTable + ColumnSel(int) + + + ComboBoxTable + activated(QString) + eDBTable + ColumnUpd() + + + eColHeader + textChanged(QString) + eDBTable + ColumnTextUpd(QString) + + + eColWidth + valueChanged(int) + eDBTable + ColWidthChange(int) + + + ComboBoxTable + activated(QString) + ListCol + setFocus() + + + bCancel + clicked() + eDBTable + doCancel() + + + eDBTable + closeEvent() + eDBTable + doCancel() + + + bColAdd + clicked() + ListCol + setFocus() + + + diff --git a/src/plugins/dbtable/wdbtable.cpp b/src/plugins/dbtable/wdbtable.cpp new file mode 100644 index 0000000..26195b4 --- /dev/null +++ b/src/plugins/dbtable/wdbtable.cpp @@ -0,0 +1,1901 @@ +/**************************************************************************** +** $Id: wdbtable.cpp,v 1.2 2008/11/08 20:16:36 leader Exp $ +** +** Code file of the database table plugin of Ananas +** Designer and Engine applications +** +** Created : 20031201 +** +** Copyright (C) 2003-2004 Leader InfoTech. All rights reserved. +** Copyright (C) 2003-2006 Grigory Panov, , Yoshkar-Ola. +** Copyright (C) 2003-2004 Andrey Paskal , Yoshkar-Ola. +** +** This file is part of the Ananas Plugins of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.leaderit.ru/page=ananas or email sales@leaderit.ru +** See http://www.leaderit.ru/gpl/ for GPL licensing information. +** +** Contact org@leaderit.ru if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +//--#include +#include +#include +#include +//Added by qt3to4: +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +//--#include "propertyeditor.h" +//--#include "command.h" +//--#include "formwindow.h" +//--#include "mainwindow.h" +//--#include "mainform.h" +#include "adocjournal.h" +#include "alog.h" + +#include "wdbtable.h" +#include "edbtable.h" + + +/*! + * \en Constructor. \_en + * \ru Конструктор. + * Задает значение ширины по умолчанию для столбца = 100. \_ru + */ +wDBTable::wDBTable( QString objtype, QWidget *parent, const char *name ) + : Q3DataTable( parent, name ) +{ +// vId = 0; +// verticalHeader()->hide(); + setLeftMargin(0); + setNullText(""); + objtype = ""; + defColWidth = 100; //default column width + tableInd = -1; + inEditMode = false; + searchWidget = 0; + searchMode = false; + searchString = ""; + connect( this, SIGNAL(cursorChanged ( QSql::Op ) ), this, SLOT(lineUpdate( QSql::Op ) ) ); + connect( this, SIGNAL(currentChanged ( int, int ) ), this, SLOT(lineChange( int, int ) ) ); + connect( this, SIGNAL(beforeInsert ( QSqlRecord* ) ), this, SLOT(lineInsert( QSqlRecord* ) ) ); + connect( this, SIGNAL(valueChanged ( int, int ) ), this, SLOT(updateTableCellHandler(int, int ) ) ); + connect( this, SIGNAL(doubleClicked ( int, int, int, const QPoint&) ), this, SLOT(doubleClickEventHandler(int,int,int, const QPoint&))); + init(); + + + aLog::print(aLog::Debug, tr("wDBTable init ok")); +// printf("ok init wdbtable\n"); + +} + + + +/*! + * \en Opens property editor. \_en + * \ru Открывает окно редактора свойсв, если fn == true \_ru + */ +void +wDBTable::setOpenEditor( bool fn ) +{ + if(fn) OpenEditor(); +} + + +/*! + * \~english + * Gets list of defined fields. + * \~russian + * Получение списка заданных полей. + * \~ + */ +QStringList +wDBTable::getDefFields() const +{ + return fname; +} + + +/*! + * \~english + * Gets list of defined headers. + * \~russian + * Получение списка заданных заголовков. + * \~ + */ +QStringList +wDBTable::getDefHeaders() const +{ + return hname; +} + + +/*! + * \~english + * Gets list of defined column width. + * \~russian + * Получение списка заданных размеров столбцов. + * \~ + */ +QStringList +wDBTable::getColWidth() const +{ + return colWidth; +} + + +/*! + * \~english + * Gets list of defined column id. + * \~russian + * Получение списка заданных идентификаторов столбцов. + * \~ + */ +QStringList +wDBTable::getDefIdList() const +{ + return idList; +} + +/*! + * \~english + * Gets metadata document id. + * \~russian + * Получение идентификатора документа метаданных, которому принадлежит виджет. + * \~ + */ +qulonglong +wDBTable::getId() const +{ + return doc_id; +} + +/*! + * \~english + * Gets current table id. + * \~russian + * Получение идентификатора текущей таблицы. + * \~ + */ +int +wDBTable::getTblInd() const +{ + return tableInd; +} + +/*! + * \~english + * Olways return false. + * \~russian + * Всегда возвращает false. + * \~ + * \return false + */ +bool +wDBTable::getOpenEditor() const +{ + return false; +} + +/*! + * \~english + * Gets default column width. + * \~russian + * Получение размера столбца по умолчанию. + * \~ + */ +int +wDBTable::getDefColWidth() const +{ + return defColWidth; +} + +/*! + * \~english + * Sets list of field names. + * \~russian + * Установка списка имен полей. + * \~ + */ +void +wDBTable::setDefFields(QStringList lst) +{ + fname = lst; +} + +/*! + * \~english + * Sets list of field headers. + * \~russian + * Установка списка заголовков полей. + * \~ + */ +void +wDBTable::setDefHeaders(QStringList lst) +{ + hname = lst; +} + +/*! + * \~english + * Sets list of columns width. + * \~russian + * Установка списка размеров столбцов. + * \~ + */ +void +wDBTable::setColWidth(QStringList lst) +{ + colWidth = lst; +} + +/*! + * \~english + * Gets list of column id. + * \~russian + * Установка списка идентификаторов столбцов. + * \~ + */ +void +wDBTable::setDefIdList(QStringList lst) +{ + idList = lst; +} + +/*! + * \~english + * Sets metadata document id. + * \~russian + * Установка идентификатора документа метаданных, которому принадлежит виджет. + * \~ + */ +void +wDBTable::setId( qulonglong fn ) +{ + doc_id = fn; +} + + +/*! + * \~english + * Gets current table id. + * \~russian + * Установка идентификатора текущей таблицы. + * \~ + */ +void +wDBTable::setTblInd( int ind ) +{ + tableInd = ind; +} + + +/*! + * \~english + * Sets default columns width. + * \~russian + * Установка размера столбцов по умолчанию. + * \~ + */ +void +wDBTable::setDefColWidth( int fn ) +{ + defColWidth = fn; +} + + + +/*! + * \en Creates property editor dialog window. \_en + * \ru Создает диалоговое окно редактора свойств. \_ru + */ +void +wDBTable::OpenEditor() +{ + //getBindList(); + setAvailableTables(); + eDBTable e( this->topLevelWidget()); + checkFields(); + e.setData(this,md); + if ( e.exec()==QDialog::Accepted ) + { + e.getData(this); + //updateProp(); + } +} + + + +/*! + * \~endlish + * Destructor. + * \~russian + * Деструктор. + * \~ + */ +wDBTable::~wDBTable() +{ + delete cur; + cur=0; +} + + + +/*! + * \~english + * Function init. Sets metadata object and tables object. + * \~russian + * Функция инициализации. Устанавливает объект метаданных и объект таблицы, + * к которому идет обращение для поиска полей или (в случае документа) таблиц + * \~ + */ +void +wDBTable::init()// aDatabase *adb ) +{ + int id=0; + aCfgItem o, o_table; + aCfgItem mditem, docitem; + + // set up pixmap for calculated fields + + cur = new Q3SqlCursor("cur",false); + md = aWidget::parentContainer(this)->getMd(); + if ( md ) + { + id = aWidget::parentContainer(this)->getId(); + o = md->find(id); + QString objClass = md->objClass(o); + if(objClass==md_document) + { + o = md->findChild(o,md_tables); // object tables + tables = o; + } + if(objClass==md_journal){ + o = md->findChild(o, md_columns); + tables = o; + } + if(objClass==md_catalogue) + { +// verticalHeader()->hide(); + o = md->findChild(o,md_element); + tables = o; + } + } + else + { +// verticalHeader()->hide(); +// printf("name engin\n"); + } + +} + + + +/*! + * \en Sets available tables, using object tables. \_en + * \ru Заполняет внутренний список доступных таблиц, используя в качестве + * источника информации объект tables. + * Добавляет к имени уже забинденой таблицы звездочку(*). \_ru + */ +void +wDBTable::setAvailableTables() +{ +aCfgItem o_table, o = tables; +QString str; +QStringList listIdTable; +int res; +Q3ValueList vList = getBindList(); + + if(o.isNull()) return; + QString objClass = md->objClass(o); + //printf("obj class `%s'\n",objClass.ascii()); + list_available_tables.clear(); + if(objClass==md_tables) + { + res = md->countChild(o,md_table); // ind kol_vo tables in obj tables + for(int i=0; ifindChild(o,md_table,i); + listIdTable << QString("%1").arg(md->id(o_table)); + //printf("id = %li\n", md->id(o_table)); + } + } + if(objClass==md_columns) + { + // listIdTable << QString("%1").arg(md->id(o)); + list_available_tables << tr("Available columns"); + } + if(objClass==md_element) + { + list_available_tables << md_element; + + // listIdTable << QString("%1").arg(md->id(o)); + } + + //res = md->countChild(o,md_table); // ind kol_vo tables in obj tables + res = listIdTable.count(); + for(int i=0; ifindChild(o,md_table,i); + + if(vList.find(listIdTable[i].toInt())!=vList.end()) + str ="* "; + else + str =""; + list_available_tables << str + md->attr(md->find(listIdTable[i].toInt()),mda_name); // add tables name in combo box + } +} + + + + +/*! + * \en Handler line current change signal. \_en + * \ru Обработчик сигнала изменения строки. Генерирует сигналы + * deleteLine и saveLine. \_ru + */ +void +wDBTable::lineUpdate( QSql::Op mode) +{ +QSqlRecord *rec = sqlCursor()->editBuffer();//currentRecord(); + switch(mode) + { + case QSql::Update: + // rec = currentRecord(); + break; + case QSql::Insert: + break; + case QSql::Delete: + //printf("emit del line\n"); + emit(deleteLine(rec)); + return; + default: + break; + } + //if(!rec) return; + //printf(" emit saveLine\n"); + emit(saveLine(rec)); +} + + + +/*! + * \~english + * Function paint field in table. + * \~russian + * Переопределенная функция рисования поля таблицы. + * В типе DateTime не отображает время. + * Поддерживает вычисляемые поля. + * \~ + */ +void +wDBTable::paintField ( QPainter * p, const QSqlField * field, const QRect & cr, bool selected ) +{ + if(field->name().left(5)=="text_") return; + if ( sqlCursor()->isCalculated( field->name() ) ){ + if ( field->name()=="system_icon" ) + p->drawPixmap( QRect( 0, 0, cr.width(), cr.height() ), systemIcon() ); + return; + } + if ( sqlCursor()->contains( "text_"+field->name() ) ) { + QSqlField f(*field); + f.setValue(((aDataTable*)sqlCursor())->sysValue("text_"+f.name())); + Q3DataTable::paintField( p, &f, cr, selected ); + return; + // f = * sqlCursor()->field( "text_"+f.name() ); + } + if(field->type() == QVariant::DateTime) + { + QSqlField f(*field); + f.setValue(field->value().toDate());// don't show time + Q3DataTable::paintField( p, &f, cr, selected ); + return; + } + Q3DataTable::paintField( p, field, cr, selected ); +} + + + +/*! + * \~english + * Return system icon for display object record state. + * \russian + * Возвращает иконку для отображения состояния строки. + * \~ + */ +QPixmap +wDBTable::systemIcon() +{ + aWidget *container = aWidget::parentContainer( this ); + QString ctype=""; + QPixmap pm; + Q3SqlCursor *r = sqlCursor(); + int df=0, cf=0, mf=0; + + if ( container ) ctype = container->className(); + if ( r ) + { + if ( r->contains("df") ) df = r->field("df").value().toInt(); + if ( r->contains("cf") ) cf = r->field("cf").value().toInt(); + else + { + if(ctype=="wJournal") + { + + aDocJournal* sysObj = new aDocJournal(db); + if(sysObj) + { +//for(int i=0; icount(); i++) +// printf("f[%d]=%s, %s\n",i, r->fieldName(i).ascii(), r->field(i)->value().toString().ascii()); + if(sysObj->findDocument(r->field("id").value().toULongLong())) + { + aDocument *doc = sysObj->CurrentDocument(); + cf = doc->IsConducted(); + delete doc; + } + else + { + printf(">>doc select failed!\n"); + } + //doc = 0; + //cf = sysObj->sysValue("cf").toInt(); + } + + delete sysObj; + + + } +//>>>>>>> 1.71.2.13 + } + if ( r->contains("mf") ) mf = r->field("mf").value().toInt(); + if(ctype=="wJournal") + { + pm = t_doc; + if ( df ) pm = t_doc_d; + if ( cf && !df ) pm = t_doc_t; + if ( mf && !df ) pm = t_doc_m; + if ( cf && mf && !df ) pm = t_doc_tm; + } + else + if(ctype=="wCatalogue") + { + pm = t_cat_e; + if ( df ) pm = t_cat_ed; + } + else + if(ctype=="wCatGroupe") + { + pm = t_cat_g; + if ( df ) pm = t_cat_gd; + } + } + return pm; +} + + + +/*! + * \~english + * Sets property `DefFields', `DefHeaders', `ColWidth', `DefIdList' to + * values from metadata. + * \~russian + * Устанавливает свойства `DefFields', `DefHeaders', `ColWidth', `DefIdList' + * в значения, определенные в метаданных. Старые значения не сохраняются. + * Для документа используется idTable. + * \~ + * \param idTable (in) - \~english table id + * \~russian id таблицы документа. Не используется для каталогов и журналов. + * \~ + */ +void +wDBTable::setFields(int idTable) +{ +CHECK_POINT + int field_count,j; + int i; //,tableCount; + //QSqlCursor *cur; + const Q3SqlFieldInfo *field; + QString str; + QStringList Cwidth, list_fields,list_id; + aCfgItem o, o_table, o_field; + QString mdtag=QString(md_field); + + list_fields.clear(); + o = tables; // object tables + QString objClass = md->objClass(o); + //printf("table parent obj class '%s'\n", (const char*)objClass); + if(objClass==md_tables) + { + o_table = md->find(idTable); + } + else + if(objClass==md_columns) + { + o_table = o; + mdtag=QString(md_column); + } + else + if(objClass==md_element) + { + o_table = o; + } + colWidth.clear(); + i=0; + while(iclear(); + if(!o_table.isNull()) + { + field_count = md->countChild(o_table,mdtag); + //printf("table name '%s'\n",(const char*)md->attr(o_table,mda_name)); + //printf("table id '%s'\n",(const char*)md->attr(o_table,mda_id)); + for (j=0; jfindChild(o_table,mdtag,j); + //printf("field %i name '%s'\n",j,(const char*)md->attr(o_field,mda_name)); + //printf("field %i id '%s'\n",j,(const char*)md->attr ( o_field, mda_id )); + list_fields << md->attr(o_field,mda_name); + list_id << md->attr(o_field,mda_id); + str.setNum(j); + field = new Q3SqlFieldInfo(md->attr(o_field,"name")); + cur->append(*field); + setSqlCursor(cur); + addColumn(field->name(),field->name(),property("DefaultColWidth").toInt()); + refresh(RefreshColumns); + Cwidth << property("DefaultColWidth").toString(); + } + } + setProperty("DefFields",list_fields); + setProperty("DefHeaders",list_fields); + setProperty("ColWidth",Cwidth); + setProperty("DefIdList",list_id); +} + + + +/*! + * \en Gets table id at position table. \_en + * \ru Получение id таблицы по ее позиции в метаданных. + * Эта позиция совпадает с индексом таблицы в комбобоксе редактора свойств + * таблицы. \_ru + * \param numTable (in) - \en Position table in metadata \_en + * \ru Положение таблицы в метаданных. + * Не используется в каталоге и журнале. \_ru + * \return \en table id \_en \ru id таблицы \_ru + */ +int +wDBTable::getTableId(int numTable) +{ + int res = -1; + aCfgItem o, o_table; + if ( numTable == -1 ) return res; + o = tables; // object tables + QString objClass = md->objClass(o); + if(objClass==md_tables) + { + o_table = md->findChild(o,md_table,numTable); + res = md->id(o_table); + } + if(objClass==md_columns) + { + res = md->id(o); + //printf("parent name %s\n", (const char*)md->attr(md->parent(o),mda_name)); + } + if(objClass==md_element) + { + res = md->id(o); + } + //printf("get table id=%i\n", res); + return res; +} + + + +/*! + * \en Gets table position at id table. \_en + * \ru Получение позиции таблицы в метаданных по ее id. + * Эта позиция совпадает с индексом таблицы в комбобоксе редактора свойств + * таблицы. \_ru + * \param id (in) - \en Id table \_en + * \ru id таблицы. + * Не используется в каталоге и журнале. \_ru + * \return \en table position for documet or 0 for catalogue and journal\_en + * \ru Для документа возвращает позицию таблицы, для каталога и + * журнала документов возвращает 0 \_ru + */ +int +wDBTable::getTableInd(int id) +{ +int j,tableCount; +aCfgItem o, o_table; + o = tables; // object tables + QString objClass = md->objClass(o); + if(objClass==md_columns || objClass==md_element) + { + //printf("TableInd=%i\n",tableInd); + return tableInd; + } + tableCount = md->count(o,md_table); + for(j=tableCount-1; j>=0; j--) + { + o_table = md->findChild(o,md_table,j); + if(md->id(o_table)==id) break; + } +return j; +} + + + +/*! + * \en Gets list of id fields or list of name fields. \_en + * \ru Получение списка id или имен полей таблицы. + * Возвращаемое значение зависит от параметра GetId. \_ru + * \param idTable (in) - \en id of table \_en + * \ru id таблицы документа. Для каталога и журнала + * не используется. \_ru + * \param GetId (ib) - \en if GetId == true returns list of id, else + * returns list of names. \_en + * \ru если параметр равен true, возвращается + * список id полей таблицы, иначе возвращается + * список имен полей таблицы. \_ru + * \return \en list of id fields or list of name fields. \_en + * \ru Список id или имен полей таблицы. \_ru + */ +QStringList +wDBTable::getFields(int idTable, bool GetId) +{ + QStringList lst; + if (idTable==-1) { + return lst; + } + + int items_count,j;//,tableCount; + aCfgItem o, o_table, o_item; + QString mdtag=md_field; + + +//aWidget *wo = aWidget::parentContainer( this ); +// if ( !wo ) return lst; +// o_table = md->objTable( wo->getId(), idTable ); + + o = tables; // object tables + QString objClass = md->objClass(o); + if(objClass==md_tables) + { + o_table = md->find(idTable); + } + else + if(objClass==md_columns) + { + o_table = o; + mdtag = md_column; + } + else + if(objClass==md_element) + { + o_table = o; + } + if(!o_table.isNull()) + { + items_count = md->countChild(o_table,mdtag); + for (j=0; jfindChild(o_table,mdtag,j); + if(GetId) + lst << md->attr(o_item,mda_id); + else + lst << md->attr(o_item,mda_name); + } + } + else { + debug_message("Table not found!\n"); + } +return lst; +} + + + +/*! + * \~english + * Gets field type. + * \~russian + * Получение типа поля. + * \~ + * \param id - \~english field id \~russian идентификатор поля \~ + * \return \~english field type \~russian тип поля \~ + */ +QString +wDBTable::getFieldType(long id) +{ + aCfgItem o; + QString str=""; + + QString objClass = md->objClass(tables); + if(objClass==md_columns) { + id= journalFieldId(id); + } + o = md->find(id); + if(!o.isNull()) + { + str = md->attr(o,mda_type); + } +return str; +} + + + +/*! + * \~english + * Gets field name. + * \~russian + * Получение имени поля. + * \~ + * \param id - \~english field id \~russian идентификатор поля \~ + * \return \~english field name \~russian имя поля \~ + */ +QString +wDBTable::getFieldName(long id) +{ + aCfgItem o; + QString str=""; + o = md->find(id); + if(!o.isNull()) + { + str = md->attr(o,mda_name); + } +return str; +} + + + +/*! + *\~english + * function check property name, id, header and width. + * If have incorrect field name or id, then print message and all. + * If have less or more items in DefHeaders or ColWidth, then set them normal. + *\~russian + * Функция проверяет свойства name, id, DefHeaders и ColWidth. + * Если находит ошибки в свойствах name или id, она выводит сообщение об этом, но не исправляет ошибки. + * Если находит ошибки в свойствах DefHeaders или ColWidth, то исправляет. + *\~ + */ +void +wDBTable::checkFields() +{ + QStringList fl,hl,cl,il; + unsigned int i; + QString str; + + //t = getFields(property("tableInd").toInt(),true); //get list fields id + fl = property("DefFields").toStringList(); + il = property("DefIdList").toStringList(); + cl = property("ColWidth").toStringList(); + hl = property("DefHeaders").toStringList(); +// proverka na nalichie field in metadata + for(i=0; i=hl.count()) hl << str; + if(i>=cl.count()) cl << property("DefaultColWidth").toString(); + } + while(icfg; + tid = property("TableInd").toInt(); + container = aWidget::parentContainer( this ); + if ( !container ) + { + aLog::print(aLog::Error, tr("wDBTable not in Ananas object container ")); + return; //printf("!no wDBTable parent container\n"); + } + else + { + o = md->objTable( container->getId(), tid ); + if ( o.isNull() ) + { + //debug_message("Table not found\n"); + aLog::print(aLog::Error, tr("wDBTable init meta object not found ")); + } + ctype = container->className(); + aLog::print(aLog::Info, tr("wDBTable container type is %1 ").arg(ctype)); + + setContainerType(ctype); + } + + //o = md->find(property("TableInd").toInt()); + if ( o.isNull() ) + { + aLog::print(aLog::Error, tr("wDBTable init meta object not found ")); + return; + } + countField = numCols(); + for(i=0; iuid()); + aLog::print(aLog::Info, tr("wDBTable filter is %1 ").arg(flt)); + setFilter(flt); + //TODO: fix memory leak + tbl = new aSQLTable( o, adb ); +// printf("new table ok\n"); + // tbl->first(); + + } + if ( containerType() == "wCatalogue" ) { + tbl = container->table(); //new aSQLTable( o, adb ); + setFilter(QString("idg=0")); + newDataId(0); + tbl->append( Q3SqlFieldInfo("system_icon") ); +// tbl->setGenerated( "system_icon", false ); + tbl->setCalculated("system_icon", true ); + } + if ( containerType() == "wJournal" ) { + tbl = container->table(); //new aSQLTable( o, adb ); + tbl->setMode( 0 ); + tbl->append( Q3SqlFieldInfo( "system_icon" ) ); +// tbl->setGenerated( "system_icon", false ); + tbl->setCalculated( "system_icon", true ); +// tbl->append( QSqlFieldInfo( "t1" ) ); +// tbl->setGenerated( "t1", false ); +// tbl->setCalculated("t1", true ); + } + refresh(); + cur->clear(); + setSqlCursor(tbl,true); + refresh(RefreshColumns); + countField = numCols(); + lst = property("DefIdList").toStringList(); + lstHead = property("DefHeaders").toStringList(); + lstWidth = property("ColWidth").toStringList(); + for ( i = 0; i < countField; i++ ) + { + //remove all columns in wDBTable, not in sql cursor + removeColumn( 0 ); + QString s = sqlCursor()->fieldName(i); +// printf(">>>>s = %s\n",s.ascii()); +// if(sqlCursor()->isCalculated(s)) +// { +// if((s.left(7)=="text_uf" && lst.findIndex(s.mid(7))!=-1) || s == "system_icon") +// { +// continue; +// } + // not calculate field, if is not contents in wDBTable +// sqlCursor()->setCalculated(sqlCursor()->fieldName(i),false); +// } + } + if ( containerType() == "wJournal" ) { + addColumn( "system_icon", "", 20 ); + setColumnReadOnly( 0, true ); + if (md->objClass(*(container->getMDObject()))==md_journal && !((aDocJournal*) container->dataObject())->type() ) { + // we have common journal + // Insert journal system columns. + addColumn( "ddate", tr("Date"), 100 ); + addColumn( "pnum", tr("Prefix"), 200 ); + addColumn( "num", tr("Number"), 100 ); + } + } + if ( containerType() == "wCatalogue" ) { + addColumn( "system_icon", "", 20 ); + // printf("set column ro\n"); + setColumnReadOnly( 0, true ); + } + + if ( containerType() == "wDocument" || containerType() == "wCatalogue" ) { + + // Задаем сортировку по индентификатору в обратном порядке для + // табличной части документа + // чтобы при добавлении новых позиций в список строки не скакали + QSqlIndex pk = sqlCursor()->primaryIndex(); + pk.setDescending( 0, false); + setSort( pk ); + sqlCursor()->select(); + sqlCursor()->first(); + refresh(); + } + + + //refresh(RefreshColumns); + if (md->objClass(*(container->getMDObject()))!=md_journal || ((aDocJournal*) container->dataObject())->type() ) { + // we have not common journal + for(i=0; i>>>>>ss=%s\n",str.ascii()); + } + else + { + str = "uf"+lst[i]; + } + // add defined fields + addColumn(str,lstHead[i],lstWidth[i].toInt()); + } + } + refresh(RefreshAll); + setWFieldEditor(); + aLog::print(aLog::Debug, tr("wDBTable init in engine ok")); +} + + + +/*! + * + */ +/*! + * \~english + * Set custom field editor (wField) used property `value'. + * \~russian + * Устанавливает свой редактор ячейки таблицы (wField). + * \~ + */ +void +wDBTable::setWFieldEditor() +{ + aEditorFactory * f = new aEditorFactory(this,""); + f->setMd(md); + Q3SqlPropertyMap * m = new Q3SqlPropertyMap(); + m->insert("wField", "value"); + installPropertyMap(m); + installEditorFactory(f); +} + + + +/*! + * \~english + * Construct cell editor. Creates new wField object and inited it. + * \~russian + * Конструктор редактора ячейки. Создает новый экземпляр объекта wField и инициализирует его. + * \~ + */ +QWidget* +aEditorFactory::createEditor(QWidget * parent, const QSqlField * field) +{ +//--WFlags fl=0; +wField * tmp; +wDBTable *t=0; +QString str,stmp; +wField::tEditorType type = wField::Unknown; + if(md) + { + t = (wDBTable*)parent->parent()->parent(); + + tmp = new wField((QWidget*)(parent->parent()),""/*--,fl*/); + if(t) + { + str = field->name(); + str = str.remove(0,2); + tmp->setFieldType(t->getFieldType(str.toInt())); + str = t->getFieldType(str.toInt()); + stmp = str.section(' ',0,0); +// printf("type is %s\n",stmp.ascii()); + if(stmp=="C") type = wField::String; + if(stmp=="N") type = wField::Numberic; + if(stmp=="D") type = wField::Date; + if(stmp=="B") type = wField::Boolean; + if(stmp=="O") + { + int tid; + //gets object id. + //stmp = str.section(' ',1,1); + tid = atoi(str.section(' ',1,1).ascii()); +// printf("tid =%d\n",tid); + aCfgItem o = md->find(tid); + if(!o.isNull()) + { + //gets object class + str = md->objClass(o); +// printf("otupe = %s\n",str.ascii()); + if(str == md_catalogue) + // and set editor + type = wField::Catalogue; + if(str == md_document) + type = wField::Document; + + } + else + { + aLog::print(aLog::Error,tr("aEditorFactory field metaobject not found")); + } + } + tmp->setEditorType(type); + tmp->initObject( t->db ); + tmp->engine = t->engine; + } + } + else + { + aLog::print(aLog::Error,tr("aEditorFactory metadata in null")); + } + if(parent && parent->parent() && parent->parent()->parent()) // setted right tabOrder + // parent->parent()->parent() - pointer to wDBTable; + QWidget::setTabOrder((QWidget*)parent->parent()->parent(),tmp); + return tmp; + +} +void +aEditorFactory::setMd(aCfg * cfg) +{ + md = cfg; +} + + +/*! + * \~english + * Gets list of id binding table. + * \~russian + * Получение списка уже присутствующих в форме таблиц. Необходимо для того, чтобы одну таблицу не добавили два раза. + * \~ + * \return \~english list of id binding table. \~russian список таблиц \~ + */ +Q3ValueList +wDBTable::getBindList() +{ +aCfgItem obj; +QObjectList wList; +int id; +wDBTable* wtable; +QObject* wd = aWidget::parentContainer( this ); + listBindings.clear(); + wList = wd->queryList( "wDBTable" ); + QListIterator it( wList ); // iterate over the wDBTable + while ( it.hasNext() ) + { + wtable = qobject_cast( it.next() ); + + if(strcmp(wtable->name(),this->name())) // don't added current id + { + //don.t added deleted widgets + if(strncmp("qt_dead_widget_",wtable->name(),strlen("qt_dead_widget_"))) + { + id = wtable->property("TableInd").toInt(); + if(id>=0) // don't added negativ id (table while not selected) + { + listBindings << id; + } + } + } + } + //--delete wList; +return listBindings; +} + + + +/*! + * \~english + * Get field value slot. Don't implemented. + * \~russian + * Получение значения поля. Не реализовано. + * \~ + */ +QVariant +wDBTable::Value( const QString &colname ) +{ + aLog::print(aLog::Error, tr("wDBTable: function Value() call")); + return QVariant(""); +} + + + +/*! + *\~english + * Emit signal on select record. + * Signal give information about selected record database id. + *\~russian + * Выдает сигнал при выборе записи. + * Сигнал содержит информацию об id, выбранного объекта в базе данных. + *\param -\~english Not use, only for signal compatibility.\~russian + * Не используются, заданы только для совместимости с сигналом таблицы.\~ + *\~ + */ +void +wDBTable::lineChange(int, int) +{ + QSqlRecord * rec = currentRecord(); + if ( !rec ) return; + qulonglong id = 0; + if(rec->contains("id")) id = rec->value("id").toLongLong(); + //if (containerType() == "wJournal") + //{ + //if(rec->contains("idd")) id = rec->value("idd").toLongLong(); + //} + aLog::print(aLog::Info, tr("wDBTable: select document %1").arg(id)); + emit( selectRecord( id ) ); +} + + +/*! + *\ru + * Устанавливает значение системного поля idd во вновь добавляемую запись табличной части документа. + *\_ru + */ +void +wDBTable::lineInsert(QSqlRecord* rec){ + + if (containerType() == "wDocument") + { + if(rec->contains("idd")) rec->setValue("idd",QVariant(doc_id)); + if(rec->contains("ln")) rec->setValue("ln",numRows()-1); + } + if(containerType() == "wCatalogue") + { + if(rec->contains("idg")) rec->setValue("idg",QVariant(cat_group_id)); + } +} + + +/*! + * \~english + * Delete line function + * \~russian + * Функция удаления строки. + * \~ + * \return \~english true, if no error \~russian true, если ошибок не было \~ + */ +bool +wDBTable::deleteCurrent() +{ + bool res; + res = Q3DataTable::deleteCurrent(); + emit(updateCurr(currentRow(),currentColumn())); + return res; + +} + + +/*! + * \~english + * Key press handler. + * \~russian + * Обрабатывает события при нажатии кнопок клавиатуры. + * \~ + */ +void +wDBTable::keyPressEvent ( QKeyEvent *e ) +{ + qulonglong id; + + aWidget *container = NULL; + if ( searchMode == FALSE && e->text().at( 0 ).isPrint() ) + { + searchOpen( e->text() ); + } + else + { + searchClose(); + } + + if(containerType() =="wJournal") + { + e->ignore(); + } + if(containerType() =="wCatalogue") + { + switch ( e->key() ) + { + case Qt::Key_Escape: + e->ignore(); + break; + case Qt::Key_Return: + if(currentRecord()) + { + id = currentRecord()->value(0).toLongLong(); + if ( e->state() == Qt::ShiftModifier ) + { + //printf("Shift+Return pressed %Ld\n", id); + EditElement(); + } else + { + //printf("Return pressed %Ld\n", id ); + emit( selected( id ) ); + } + e->accept(); + } + else + { + aLog::print(aLog::Info, tr("wDBTable: current record not setted")); + } + break; + default: + e->ignore(); + break; + } + } + Q3DataTable::keyPressEvent( e ); +} + + + +/*! + *\ru + * Слот обрабатывает ситуацию смены/установки идентификатора документа, устанавливая новый фильтр. + * Кроме переустановки фильта следует вызывать слот newDataId, для смены/установки + * значения идентификатора документа. Для журнала этого можно не делать. + * \param flt - строка вида "idd=999", задающая условия отбора записей в таблицу по значению поля idd. + *\_ru + */ +void +wDBTable::newFilter(const QString & flt) +{ + setFilter(flt); + refresh(); +} + +/*! + *\ru + * Слот обрабатывает ситуацию смены/установки идентификатора документа, запоминая новое значение. + * Для смены фильта следует вызывать слот newFilter. + * \param id - идентификатор документа, который следует запомнить. + *\_ru + */ +void +wDBTable::newDataId(const qulonglong id) +{ + if(containerType() == "wDocument") + { + setId(id); + } + if(containerType() == "wCatalogue") + { + cat_group_id = id; + } +} + + +/*! + * \~english + * Opens form for edit catalogue element. + * \~russian + * Открывает форму по умолчанию для объекта контейнера и настраивает ее на работу с текущей строкой таблицы. Используется только в настраиваемом редакторе каталога. + * \~ + */ +void +wDBTable::EditElement() +{ + + ANANAS_UID id = 0; +// wGroupTreeItem * item = ( wGroupTreeItem * ) tree->currentItem(); + aForm * f = 0; + +//CHECK_POINT + id = currentRecord()->value(0).toLongLong(); + if ( id ) { + if ( engine ) { + f = engine->openForm( aWidget::parentContainer( this )->getId(), 0, md_action_edit, md_form_elem, id, ( aWidget *) this ); + if ( f ) { + connect(f, SIGNAL( update( ANANAS_UID )), this, SLOT(updateItem( ANANAS_UID ))); +// connect(f, SIGNAL(selected( Q_ULLONG )), this, SLOT(on_selected( Q_ULLONG ))); +// f->closeAfterSelect = true; + } + } + } +} + + +long +wDBTable::journalFieldId(long columnId){ + aCfgItem item; + + item= md->find(md->find(columnId),md_fieldid); + return md->text(item).toLong(); + +} + +QString +wDBTable::journalFieldName(long columnId) +{ + aCfgItem item; + item= md->find(md->find(columnId),md_fieldid); + item = md->find(md->text(item).toLong()); + if(!item.isNull()) + { + QString s = md->attr(item,mda_type); + QChar ch = s[0]; + if(ch.upper()=='O') + { + return QString("text_uf%1").arg(md->attr(item,mda_id)); + } + else + { + return QString("uf%1").arg(md->attr(item,mda_id)); + } + } + return "uf0"; + +} + +/*! + * \~english + * Hanler table cell end edit. + * \~russian + * Обрабатывает окончание редактирования ячейки таблицы. + * \~ + */ +//bool +void +wDBTable::updateTableCellHandler(int r, int c) +{ +// printf(">>>>update curr row %d col %d!\n",r,c); + lastEditedRow= r; + lastEditedCol= c; +} + +/*! + * \~english + * Reimplemented QDataTable function. + * \~russian + * Переопределяет функцию QDataTable. Испускает сигнал updateCurr(). + * \~ + */ +bool +wDBTable::updateCurrent() +{ + bool res = Q3DataTable::updateCurrent(); + if(res) + { +// printf(">>>>real update curr row %d col %d!\n",lastEditedRow, lastEditedCol); + emit(updateCurr(lastEditedRow,lastEditedCol)); + } +return res; +} + + +/*! + * \~english + * Reimplemented QDataTable function. + * \~russian + * Переопределяет функцию QDataTable. Отрабатывет после нажатия Enter в редактируемой ячейке. + * Перемещает фокус ввода на следующую ячейку. + * \~ + */ +void +wDBTable::activateNextCell() +{ + //int r = currentRow(), c = currentColumn(); + //if(r<0) r=0; + //if(c<0) c=0; + //tCurrentCell(r,c+1); +} + + + + +/*! + * \~english + * Reimplemented QDataTable function. + * \~russian + * Переопределяет функцию QDataTable. Выделяет текст в ячейке. + * \~ + */ +//>>>>>>> 1.71.2.13 +QWidget * +wDBTable::beginUpdate ( int row, int col, bool replace ) +{ + wField *wd; + wd = (wField*)Q3DataTable::beginUpdate(row,col,replace); + if(wd) + { + //inEditMode = true; + wd->selectAll(); + } + return wd; +} + + +void +wDBTable::doubleClickEventHandler(int /*rol*/, int /*col*/, int /*button*/, const QPoint &/*mousePos*/) +{ + if(containerType() =="wCatalogue" || containerType() == "wJournal") + { + if(currentRecord()) + { + qulonglong id = currentRecord()->value(0).toLongLong(); + emit( selected( id ) ); + } + } + +} + +/** + * \ru + * \brief Переопределяем метод базового класса, вызывающий диалог подтверждения. + * Переопределен только диалог подтверждения удаления. + * \_ru + */ + +QSql::Confirm +wDBTable::confirmEdit( QSql::Op m ) { + if ( m == QSql::Delete ) { + if ( 0 == QMessageBox::question( + this, + tr("Remove record?"), + tr("You are going to remove record
" + "Are you sure?"), + tr("&Yes, remove"), tr("&No"), + QString::null, 0, 1 ) ) { + return QSql::Yes; + } else { + return QSql::No; + } + } else { + return Q3DataTable::confirmEdit( m ); + } +} + +/** + * \ru + * \brief Переопределяем метод базового класса, осуществляющий вставку новой строки в таблицу. + * Наш метод будет всегда помещать новую строку в начале таблицы. + * \_ru + */ + +bool +wDBTable::beginInsert() { + if ( !sqlCursor() || isReadOnly() || !numCols() ) + return FALSE; + if ( !sqlCursor()->canInsert() ) + return FALSE; + + bool result = Q3DataTable::beginInsert(); + endEdit( currentRow(), currentColumn(), false, false); + setCurrentCell( numRows(), 0 ); + return result; + +} + + +/*! + * \~english + * Reimplemented QDataTable function. + * \~russian + * Переопределяет функцию QDataTable. Если контейнер wJournal, может испускаеть сигналы insertRequest(), updateRequest(), deleteRequest(), viewRequest() + * \~ + */ +void +wDBTable::contentsContextMenuEvent ( QContextMenuEvent * e ) +{ + Q3Table::contentsContextMenuEvent( e ); + QString str, ctype; + + if ( containerType() == "wDocument" || containerType() == "wCatalogue" ) { + // Переопределяем всплывающее по правой кнопке мыши меню для табличной части документа + // Во-первых, для его локализации + // Во-вторых, чтобы добавляемая в табличную часть строка всегда вставлялась самой последней. + enum { + IdInsert=0, + IdUpdate, + IdDelete, + }; + + QPointer popupForDoc = new Q3PopupMenu( this ); + int id[ 3 ]; + id[ IdInsert ] = popupForDoc->insertItem( tr( "New" ) ); + id[ IdUpdate ] = popupForDoc->insertItem( tr( "Edit" ) ); + id[ IdDelete ] = popupForDoc->insertItem( tr( "Delete" ) ); + + if ( !sqlCursor() || isReadOnly() || !numCols() ) { + popupForDoc->setItemEnabled(id[ IdInsert ], false ); + popupForDoc->setItemEnabled(id[ IdUpdate ], false ); + popupForDoc->setItemEnabled(id[ IdDelete ], false ); + } + + int r = popupForDoc->exec( e->globalPos() ); + delete (Q3PopupMenu*) popupForDoc; + if(r==id[IdInsert]) { + beginInsert(); + } else if(r==id[IdUpdate]) { + keyPressEvent( new QKeyEvent( QEvent::KeyPress, Qt::Key_F2, 0, Qt::NoButton)); + } else if(r==id[IdDelete]) { + Q3DataTable::deleteCurrent(); + } + } + + + if ( containerType() == "wJournal" ) + { + //id = currentRecord()->value(0).toLongLong(); + enum { + IdInsert=0, + IdUpdate, + IdDelete, + IdView, + IdRefresh }; + QPointer popup = new Q3PopupMenu( this ); + int id[ 5 ]; + id[ IdInsert ] = popup->insertItem( tr( "New" ) ); + id[ IdUpdate ] = popup->insertItem( tr( "Edit" ) ); + id[ IdDelete ] = popup->insertItem( tr( "Delete" ) ); + id[ IdView ] = popup->insertItem( tr( "View" ) ); + id[ IdRefresh ] = popup->insertItem( tr( "Refresh" ) ); + int r = popup->exec( e->globalPos() ); + delete (Q3PopupMenu*) popup; + if(r==id[IdInsert]) + emit(insertRequest()); + else + if(r==id[IdUpdate]) + emit(updateRequest()); + else + if(r==id[IdDelete]) + emit(deleteRequest()); + else + if(r==id[IdView]) + emit(viewRequest()); + if(r==id[IdRefresh]) + { + //recalculate(); + refresh(); + } + } + e->accept(); + +} + + +void +wDBTable::updateItem( ANANAS_UID db_uid ) +{ + refresh(); + emit currentChanged( currentRecord() ); +} + + +int +wDBTable::Select( ANANAS_UID db_uid ) +{ + aSQLTable *t = ( aSQLTable *) sqlCursor(); + +// printf("id = %Li\n",db_uid); + ANANAS_UID cur_id = 0; + uint curr = currentRow(), curc=currentColumn(), row = 0; + bool found = FALSE; + + while ( t->seek( row ) ){ + cur_id = t->sysValue( "id" ).toULongLong(); + if ( cur_id == db_uid ) { + found = TRUE; + break; + } + row++; + } + if ( found ) { + setCurrentCell( row, curc ); + } else setCurrentCell( curr, curc ); + return 0; +} + + +bool +wDBTable::searchColumn( const QString & text, bool FromCurrent, bool Forward ) +{ + + QString s; + uint curr = currentRow(), curc=currentColumn(), row = 0, idx; + bool found = FALSE; + aSQLTable *t = ( aSQLTable *) sqlCursor(); + + if ( FromCurrent ) row = curr; + if ( Forward ) row++; else row--; + idx = indexOf( curc ); + + while ( t->seek( row ) ){ + s = t->value( idx ).toString(); + if ( s.left( text.length() ) == text ) { + found = TRUE; + break; + } + if ( Forward ) row++; else row--; + } + if ( found ) { + setCurrentCell( row, curc ); + }; + return found; +} + + + +void +wDBTable::searchOpen( const QString & text ) +{ + searchWidget = new aSearchWidget( aWidget::parentContainer( this ), this ); + searchMode = TRUE; + searchWidget->setFocus(); + searchWidget->search( text ); +} + + +void +wDBTable::searchClose() +{ + if ( searchWidget ) { + setFocus(); + searchWidget->deleteLater(); + searchMode = FALSE; + searchWidget = 0; + } +} + + +/*! + *\~english + * + * + *\~russian + * Осуществляет интерактивный поиск по первым буквам + * текстового значения текущего столбца таблицы. + * Пока не реализован поиск для столбцов типа "Объект". + * Up - предыдущее значение. + * Down - следующее значение. + * ESC,Enter - конец поиска. + *\~ + */ +aSearchWidget::aSearchWidget( QWidget *parent, wDBTable *table ) +: Q3Frame( parent ) +{ + t = table; + ftext = ""; + setFrameStyle( Q3Frame::PopupPanel | Q3Frame::Raised ); + setFocusPolicy( Qt::StrongFocus ); + new Q3HBoxLayout( this, 0, 0 ); + l = new QLineEdit( this ); + l->installEventFilter( this ); + setFocusProxy( l ); + layout()->add( l ); +// move (0,0); + move( 3+t->x()+t->columnPos( t->currentColumn()), t->y()+1/*+t->height()*/); + resize( t->columnWidth( t->currentColumn() )-2, 25 ); + connect( l, SIGNAL( textChanged( const QString & ) ), this, SLOT( setText( const QString & ) ) ); +} + + +aSearchWidget::~aSearchWidget() +{ +} + + +void +aSearchWidget::search( const QString &t ) +{ + show(); + l->setText( t ); +} + + +void +aSearchWidget::setText( const QString &text ) +{ + if ( t->searchColumn( text ) ) ftext = text; + else l->setText( ftext ); +} + + +bool +aSearchWidget::eventFilter( QObject *obj, QEvent *ev ) +{ + if ( obj == l ) { + if ( ev->type() == QEvent::FocusOut ) { + t->searchClose(); + return TRUE; + } + if ( ev->type() == QEvent::KeyPress ) { + QKeyEvent *e = ( QKeyEvent *) ev; + switch ( e->key() ){ + case Qt::Key_Return: + case Qt::Key_Escape: + //printf("OK\n"); + t->searchClose(); + break; + case Qt::Key_Up: + t->searchColumn( ftext, TRUE, FALSE ); + break; + case Qt::Key_Down: + t->searchColumn( ftext, TRUE, TRUE ); + break; + default: + return FALSE; + break; + } + return TRUE; + } else { + return FALSE; + } + } else { + // pass the event on to the parent class + return Q3Frame::eventFilter( obj, ev ); + } +} diff --git a/src/plugins/dbtable/wdbtable.h b/src/plugins/dbtable/wdbtable.h new file mode 100644 index 0000000..2041a98 --- /dev/null +++ b/src/plugins/dbtable/wdbtable.h @@ -0,0 +1,323 @@ +/**************************************************************************** +** $Id: wdbtable.h,v 1.1 2008/11/05 21:16:30 leader Exp $ +** +** Header file of the database table plugin of Ananas +** Designer and Engine applications +** +** Created : 20031201 +** +** Copyright (C) 2003-2004 Leader InfoTech. All rights reserved. +** Copyright (C) 2003-2004 Grigory Panov, Yoshkar-Ola. +** +** This file is part of the Ananas Plugins of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.leaderit.ru/page=ananas or email sales@leaderit.ru +** See http://www.leaderit.ru/gpl/ for GPL licensing information. +** +** Contact org@leaderit.ru if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#ifndef WDBTABLE_H +#define WDBTABLE_H + +#include +#include +//Added by qt3to4: +#include +#include +#include +#include +#include +#include +#include +#include +#include "acfg.h" +#include "aobject.h" +#include "awidget.h" +#include "wfield.h" + +class aDatabase; +class wDBTable; +class Q3DataTable; + +class aSearchWidget : public Q3Frame +{ +Q_OBJECT +public: + aSearchWidget( QWidget *parent, wDBTable *table ); + ~aSearchWidget(); + void search( const QString &t =""); +public slots: + void setText( const QString &t ); +protected: +// virtual void keyPressEvent ( QKeyEvent *e ); + bool eventFilter( QObject *obj, QEvent *ev ); +private: + QString ftext; + QLineEdit *l; + wDBTable *t; +}; + + + +/*! + * \en Class for editing documents tables. \_en + * \ru + * \brief Визуальный класс для редактирования табличных частей документа. + * Наследует QDataTable. + * + * Поддерживает редактирование журнала документов + * и таблицы элементов каталога. + * \_ru + * + */ +class QT_WIDGET_PLUGIN_EXPORT wDBTable : public Q3DataTable +{ + friend class aForm; + + Q_OBJECT + Q_PROPERTY( qulonglong Id READ getId WRITE setId DESIGNABLE true ) + Q_PROPERTY( int DefaultColWidth READ getDefColWidth WRITE setDefColWidth DESIGNABLE true ) + Q_PROPERTY( int TableInd READ getTblInd WRITE setTblInd DESIGNABLE true ) + Q_PROPERTY( QStringList DefFields READ getDefFields WRITE setDefFields DESIGNABLE true ) + Q_PROPERTY( QStringList DefHeaders READ getDefHeaders WRITE setDefHeaders DESIGNABLE true ) + Q_PROPERTY( QStringList ColWidth READ getColWidth WRITE setColWidth DESIGNABLE true ) + Q_PROPERTY( QStringList DefIdList READ getDefIdList WRITE setDefIdList DESIGNABLE true ) +// Q_PROPERTY( bool openEditor READ getOpenEditor WRITE setOpenEditor STORED true ) + Q_PROPERTY( QString editFormName READ getEditFormName WRITE setEditFormName DESIGNABLE true ) +public: + aCfg* md; + aDatabase* db; + aEngine* engine; + //char vLoaded; + QStringList list_available_tables; + QStringList fname, hname, colWidth,idList; + int defColWidth; + int tableInd; + aCfgItem tables; + Q3SqlCursor* cur; + bool searchMode; + QString searchString; + aSearchWidget *searchWidget; + + wDBTable( QString objtype, QWidget *parent = 0, const char *name = 0); + virtual ~wDBTable(); + void checkFields(); + void setFields(int numTable); //set propertis default value for table with num=numTable + QStringList getFields(int numTable, bool GetId=false); // return list field names or id's, defined in metadata + QString getFieldName(long idField); // return attribute `name' value + QString getFieldType(long idField); // return attribute `type' value + int getTableInd(int id); + int getTableId(int ind); + + // void init( aDatabase *adb ); + void init(); + void init(aDatabase *adb, aEngine *e = 0 ); // call in ananas engine + void OpenEditor(); + //QWidget* createEditor(); + + //int getDefaultWidth() const {return defColWidth;}; + + QStringList getDefFields() const; + QStringList getDefHeaders() const; + QStringList getColWidth() const; + QStringList getDefIdList() const; + qulonglong getId() const; + int getTblInd() const; + bool getOpenEditor() const; + int getDefColWidth() const; + + void setDefFields(QStringList lst); + void setDefHeaders(QStringList lst); + void setColWidth(QStringList lst); + void setDefIdList(QStringList lst); + void setId( qulonglong fn ); + void setTblInd( int ind ); + void setOpenEditor( bool fn ); + void setDefColWidth( int fn ); + + QString getEditFormName() const { return vEditFormName;}; + void setEditFormName( QString name) { vEditFormName = name; }; + + QString containerType() const { return container_type;}; + void setContainerType( QString name) { container_type = name; }; + QPixmap systemIcon(); + virtual int Select( ANANAS_UID db_uid ); +public slots: + Q3ValueList getBindList(); + void setWFieldEditor(); + void setAvailableTables(); + void lineUpdate(QSql::Op mode); + void newFilter(const QString & ); + void newDataId(const qulonglong ); + QVariant Value( const QString &colname ); + + bool searchColumn( const QString &text, bool FromCurrent = FALSE, bool Forward = TRUE ); + void searchOpen( const QString &text = "" ); + void searchClose(); + +protected slots: + void doubleClickEventHandler(int , int , int, const QPoint& ); //parametrs not used + virtual void updateTableCellHandler(int, int); +signals: + +/*! + * \~english + * Signal emitted after table line update. + * \~russian + * Сигнал испускается после обновлении строки таблицы. + * \~ + */ + void saveLine(QSqlRecord *rec); + +/*! + * \~english + * Signal emitted after table line delete. + * \~russian + * Сигнал испускается после удаления строки таблицы. + * \~ + */ + void deleteLine(QSqlRecord *rec); +/*! + * \~english + * Signal emitted after select another document. + * \~russian + * Сигнал испускается после выбора документа. + * \~ + */ + void selected( qulonglong uid ); +/*! + * \~english + * Signal emitted after change line. + * \~russian + * Сигнал испускается после изменения строки. + * \~ + */ + void selectRecord ( qulonglong ); +/*! + * \~english + * Signal emitted after update cell. + * \~russian + * Сигнал испускается после обновления ячейки с номером \a row, \a col. + * \~ + */ + void updateCurr(int row, int col); +//<<<<<<< wdbtable.h + + //signals from context menu for connecting to wJournal + //if container has another type, then do QDataTable context menu + //and this signal no emitted +//======= + +/*! + * \~english + * signals from context menu for connecting to wJournal + * if container has another type, then do QDataTable context menu + * and this signal no emitted + * \~russian + * Сигналы от контекстного меню для присоединения к wJournal + * Если контейнер другого типа, то вызывается стандартное меню, + * и эти сигналы не испускаются. + * \~ + * \see updateRequest(); deleteRequest(); viewRequest(); + * +*/ +//>>>>>>> 1.45.2.4 + void insertRequest(); +/*! + * \see insertRequest(); +*/ + void updateRequest(); +/*! + * \see insertRequest(); +*/ + void deleteRequest(); +/*! + * \see insertRequest(); +*/ + void viewRequest(); + // end + +private slots: + //void select( Q_ULLONG group ); + void lineChange(int, int); + void lineInsert(QSqlRecord*); + void updateItem( ANANAS_UID db_uid ); + +protected: + virtual void paintField ( QPainter * p, const QSqlField * field, const QRect & cr, bool selected ); + QWidget * beginUpdate ( int row, int col, bool replace ); + virtual bool updateCurrent(); + void contentsContextMenuEvent ( QContextMenuEvent * e ); +// void propertyUpdate(const QString &propName); + virtual bool deleteCurrent(); + //virtual QSql::Confirm confirmEdit ( QSql::Op m ); + virtual void keyPressEvent ( QKeyEvent *e ); + void EditElement(); + virtual void activateNextCell(); + virtual bool beginInsert (); + virtual QSql::Confirm confirmEdit( QSql::Op m ); + +private: + + QPixmap t_doc; + QPixmap t_doc_d; + QPixmap t_doc_t; + QPixmap t_doc_m; + QPixmap t_doc_tm; + QPixmap t_cat_e; + QPixmap t_cat_ed; + QPixmap t_cat_g; + QPixmap t_cat_gd; + + int lastEditedRow; + int lastEditedCol; + + QString container_type; + qulonglong doc_id; + qulonglong cat_group_id; + long journalFieldId(long); + QString journalFieldName(long); + bool inEditMode; + //aDBTablePrivate impl; +// void updateProp(void); + Q3ValueList listBindings; + aCfgItem obj; + QString vName, vEditFormName; + QString vDefineCols; + qulonglong oid; +}; + + +/*! + * \en Class for support custom editor in wDBTable. \_en + * \ru + * \brief Класс для поддержки собственного редактора поля в wDBTable. + * Наследует QSqlEditorFactory. + * \_ru + */ +class aEditorFactory: public Q3SqlEditorFactory +{ +public: +/*! + * \~english Constructor + * \~russian Конструктор \~ + */ + aEditorFactory(QObject * parent = 0, const char * name = 0):Q3SqlEditorFactory(parent/*--,name*/) {}; + QWidget * createEditor (QWidget * parent, const QSqlField * field); + void setMd(aCfg *md); +private: + aCfg * md; +}; +#endif diff --git a/src/plugins/dbtable/wdbtable_plugin.cpp b/src/plugins/dbtable/wdbtable_plugin.cpp new file mode 100644 index 0000000..b13124e --- /dev/null +++ b/src/plugins/dbtable/wdbtable_plugin.cpp @@ -0,0 +1,100 @@ +/**************************************************************************** +** +** Code file +** +** Copyright (C) 2006 Dmitriy Pavlyuk +** +** This file is part of the Ananas Plugins of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +**********************************************************************/ + +#include "wdbtable_plugin.h" + +#include +#include +#include + +#include "wdbtable_taskmenu.h" +#include "wdbtable.h" + + +wDBTablePlugin::wDBTablePlugin(QObject *parent) + : QObject(parent), m_initialized(false) +{ + m_initialized = false; +} + +bool wDBTablePlugin::isContainer() const +{ + return false; +} + +bool wDBTablePlugin::isInitialized() const +{ + return m_initialized; +} + +void wDBTablePlugin::initialize(QDesignerFormEditorInterface *core) +{ + if (m_initialized) + return; + Q_UNUSED(core); + + QExtensionManager *manager = core->extensionManager(); + Q_ASSERT(manager != 0); + manager->registerExtensions(new wDBTableTaskMenuFactory(manager), + Q_TYPEID(QDesignerTaskMenuExtension)); + + m_initialized = true; +} + +QWidget *wDBTablePlugin::createWidget(QWidget *parent) +{ + wDBTable *w = new wDBTable("", parent, 0); + return w; +} + +QString wDBTablePlugin::name() const +{ + return QLatin1String("wDBTable"); +} + +QString wDBTablePlugin::group() const +{ + return QLatin1String("Ananas"); +} + +QString wDBTablePlugin::toolTip() const +{ + return QString("Ananas for QT database Table Widget"); +} + +QString wDBTablePlugin::whatsThis() const +{ + return QString("Entry to modify database tables values of Ananas's object"); +} + +QString wDBTablePlugin::includeFile() const +{ + return QLatin1String("wdbtable.h"); +} + +QIcon wDBTablePlugin::icon() const +{ + //return QIcon(); + return QIcon(":/images/wdbtable.png"); +} + +QString wDBTablePlugin::domXml() const +{ + return "\n\n"; +} diff --git a/src/plugins/dbtable/wdbtable_plugin.h b/src/plugins/dbtable/wdbtable_plugin.h new file mode 100644 index 0000000..1610911 --- /dev/null +++ b/src/plugins/dbtable/wdbtable_plugin.h @@ -0,0 +1,53 @@ +/**************************************************************************** +** +** Header file +** +** Copyright (C) 2006 Dmitriy Pavlyuk +** +** This file is part of the Ananas Plugins of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +**********************************************************************/ + +#ifndef WDBTABLE_PLUGIN_H +#define WDBTABLE_PLUGIN_H + +#include + +#include "qwidgetplugin.h" + + +class QT_WIDGET_PLUGIN_EXPORT wDBTablePlugin : public QObject, public QDesignerCustomWidgetInterface +{ + Q_OBJECT + Q_INTERFACES(QDesignerCustomWidgetInterface) + +public: + wDBTablePlugin(QObject *parent=0); + + bool isContainer() const; + bool isInitialized() const; + void initialize(QDesignerFormEditorInterface *core); + QWidget *createWidget(QWidget *parent); + + QString name() const; + QString group() const; + QString toolTip() const; + QString whatsThis() const; + QString includeFile() const; + QIcon icon() const; + QString domXml() const; + +private: + bool m_initialized; +}; + +#endif // WDBTABLE_PLUGIN_H diff --git a/src/plugins/dbtable/wdbtable_taskmenu.cpp b/src/plugins/dbtable/wdbtable_taskmenu.cpp new file mode 100644 index 0000000..599047a --- /dev/null +++ b/src/plugins/dbtable/wdbtable_taskmenu.cpp @@ -0,0 +1,76 @@ +/**************************************************************************** +** +** Copyright (C) 2006 Dmitriy Pavlyuk All rights reserved. +** +** This file is part of the widgets plugin of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +****************************************************************************/ + +#include + +#include + +#include "wdbtable_taskmenu.h" +#include "wdbtable.h" +#include "edbtable.h" + + +wDBTableTaskMenu::wDBTableTaskMenu(wDBTable *widget, QObject *parent) + : QObject(parent) +{ + m_widget = widget; + + m_editAction = new QAction(tr("Edit ..."), this); + connect(m_editAction, SIGNAL(triggered()), this, SLOT(edit())); +} + +void wDBTableTaskMenu::edit() +{ + /*eDBTable e; + + m_widget->setAvailableTables(); + m_widget->checkFields(); + e.setData(m_widget); + if (e.exec() == QDialog::Accepted) + { + e.getData(m_widget); + }*/ + m_widget->OpenEditor(); +} + +QAction *wDBTableTaskMenu::preferredEditAction() const +{ + return m_editAction; +} + +QList wDBTableTaskMenu::taskActions() const +{ + QList list; + list.append(m_editAction); + return list; +} + +wDBTableTaskMenuFactory::wDBTableTaskMenuFactory(QExtensionManager *parent) + : QExtensionFactory(parent) +{ +} + +QObject *wDBTableTaskMenuFactory::createExtension(QObject *object, const QString &iid, QObject *parent) const +{ + if (iid != Q_TYPEID(QDesignerTaskMenuExtension)) + return 0; + + if (wDBTable *dt = qobject_cast(object)) + return new wDBTableTaskMenu(dt, parent); + + return 0; +} diff --git a/src/plugins/dbtable/wdbtable_taskmenu.h b/src/plugins/dbtable/wdbtable_taskmenu.h new file mode 100644 index 0000000..a08fed9 --- /dev/null +++ b/src/plugins/dbtable/wdbtable_taskmenu.h @@ -0,0 +1,57 @@ +/**************************************************************************** +** +** Copyright (C) 2006 Dmitriy Pavlyuk All rights reserved. +** +** This file is part of the widgets plugin of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +****************************************************************************/ + +#ifndef WDBTABLE_TASKMENU_H +#define WDBTABLE_TASKMENU_H + +#include +#include + + +class QExtensionManager; +class QAction; +class wDBTable; + +class wDBTableTaskMenu: public QObject, public QDesignerTaskMenuExtension +{ + Q_OBJECT + Q_INTERFACES(QDesignerTaskMenuExtension) +public: + wDBTableTaskMenu(wDBTable *widget, QObject *parent); + + QAction *preferredEditAction() const; + QList taskActions() const; + +private slots: + void edit(); + +private: + QAction *m_editAction; + wDBTable *m_widget; +}; + +class wDBTableTaskMenuFactory: public QExtensionFactory +{ + Q_OBJECT +public: + wDBTableTaskMenuFactory(QExtensionManager *parent = 0); + +protected: + QObject *createExtension(QObject *object, const QString &iid, QObject *parent) const; +}; + +#endif // WDBTABLE_TASKMENU_H diff --git a/src/plugins/document/document.pri b/src/plugins/document/document.pri new file mode 100644 index 0000000..3bf42d3 --- /dev/null +++ b/src/plugins/document/document.pri @@ -0,0 +1,19 @@ +HEADERS += \ + document/edocument.h \ + document/eselectdoctype.h \ + document/wdocument.h \ + document/wdocument_plugin.h \ + document/wdocument_taskmenu.h + +SOURCES += \ + document/edocument.cpp \ + document/eselectdoctype.cpp \ + document/wdocument.cpp \ + document/wdocument_plugin.cpp \ + document/wdocument_taskmenu.cpp + +FORMS += \ + document/edocument.ui \ + document/eselectdoctype.ui + + \ No newline at end of file diff --git a/src/plugins/document/edocument.cpp b/src/plugins/document/edocument.cpp new file mode 100644 index 0000000..8092766 --- /dev/null +++ b/src/plugins/document/edocument.cpp @@ -0,0 +1,153 @@ +#include "edocument.h" + +#include +#include +#include + +#include "acfg.h" + +/* + * Constructs a eDocument as a child of 'parent', with the + * name 'name' and widget flags set to 'f'. + * + * The dialog will by default be modeless, unless you set 'modal' to + * true to construct a modal dialog. + */ +eDocument::eDocument(QWidget* parent, const char* name, bool modal, Qt::WindowFlags fl) + : QDialog(parent, name, modal, fl) +{ + setupUi(this); + + init(); +} + +/* + * Destroys the object and frees any allocated resources + */ +eDocument::~eDocument() +{ + // no need to delete child widgets, Qt does it all for us +} + +/* + * Sets the strings of the subwidgets using the current + * language. + */ +void eDocument::languageChange() +{ + retranslateUi(this); +} + +void eDocument::init() +{ +/* + int oc, i, f, idx=0; + char *id, *name, *ot; + cfg_objptr o; + char otype[100]; + QString named; + + otypes.clear(); + eType->clear(); + otypes.append("D"); + eType->insertItem(trUtf8("Дата"), idx++); + otypes.append("T"); + eType->insertItem(trUtf8("Время"), idx++); + otypes.append("N %d %d"); + eType->insertItem(trUtf8("Число"), idx++); + otypes.append("C %d"); + eType->insertItem(trUtf8("Строка"), idx++); + + oc=cfgobj_count(NULL, NULL); + for (i=1;i<=oc;i++) { + id=cfgobj_idn(NULL, NULL, i, &o); + ot=(char *)o->name; + name=cfgobj_attr(o, "name"); + named=""; + f=0; + if (strcmp((char *)ot, aot_doc)==0) { + named=trUtf8("Документ."); + f=1; + } + if (strcmp((char *)ot, aot_cat)==0) { + named=trUtf8("Справочник."); + f=1; + } + if (f) { + named=named+trUtf8(name); + sprintf(otype, "O %s", id); + otypes.append(otype); + eType->insertItem(named, idx++); + } + } +*/ +} + + + +void eDocument::setData( QWidget *o, aCfg *md ) +{ +// const QObject *o = sender(); + if ( o ) { + if ( o->className() != QString("wDocument") || !md ) { + reject(); + return; + } + } + else { + reject(); + return; + } + wDocument *f = ( wDocument*) o; + int w=0, d=0, idx=0; + unsigned int i; + long oid , id; + + id = f->getId(); + + otypes.clear(); + eType->clear(); + + QStringList tlist = md->types( md_document ); + otypes.clear(); + eType->clear(); + for ( QStringList::Iterator it = tlist.begin(); it != tlist.end(); ++it ) { + otypes.append( (*it).section( "\t", 0, 0 ) ); + eType->insertItem( (*it).section("\t", 1, 1 ), idx++ ); + } + for ( i = 0 ; i < otypes.count(); i++ ) { + oid = 0; + if( otypes[i][0] == 'O' ) { + sscanf( (const char *)otypes[ i ], "O %d", &oid ); + if ( oid == id ) { + eType->setCurrentItem( i ); + break; + } + } + } +} + + +void eDocument::getData( QWidget *o ) +//aDocument *f ) +{ + QVariant v; +// const QObject *o = sender(); + if ( !o ) return; + if ( o->className() != QString("wDocument") ) return; + wDocument *f = ( wDocument*) o; + + int idx=eType->currentItem(); + int oid = 0; + + if (f) { + if( otypes[idx][0] == 'O' ) { + sscanf( (const char *)otypes[ idx ], "O %d", &oid ); +// v = oid; + f->setProperty("Id", QVariant( oid ) ); +// f->setId( oid ); + } + } + +} + diff --git a/src/plugins/document/edocument.h b/src/plugins/document/edocument.h new file mode 100644 index 0000000..e60042a --- /dev/null +++ b/src/plugins/document/edocument.h @@ -0,0 +1,27 @@ +#ifndef EDOCUMENT_H +#define EDOCUMENT_H + +#include "ui_edocument.h" + + +class eDocument : public QDialog, public Ui::eDocument +{ + Q_OBJECT + +public: + eDocument(QWidget* parent = 0, const char* name = 0, bool modal = false, Qt::WindowFlags fl = 0); + ~eDocument(); + + QStringList otypes; + +public slots: + virtual void init(); + virtual void setData( QWidget * o, aCfg * md ); + virtual void getData( QWidget * o ); + +protected slots: + virtual void languageChange(); + +}; + +#endif // EDOCUMENT_H diff --git a/src/plugins/document/edocument.ui b/src/plugins/document/edocument.ui new file mode 100644 index 0000000..c3becf3 --- /dev/null +++ b/src/plugins/document/edocument.ui @@ -0,0 +1,116 @@ + + + + + eDocument + + + + 0 + 0 + 348 + 110 + + + + Document + + + + + + + + + + + + + 100 + 32767 + + + + Type + + + false + + + + + + + + 31 + 16 + + + + Expanding + + + Vertical + + + + + + + + + OK + + + true + + + + + + + Cancel + + + + + + + + + + 91 + 31 + + + + Expanding + + + Horizontal + + + + + + + qPixmapFromMimeSource + + ananas.h + wdocument.h + + + + bOK + clicked() + eDocument + accept() + + + bCancel + clicked() + eDocument + reject() + + + diff --git a/src/plugins/document/eselectdoctype.cpp b/src/plugins/document/eselectdoctype.cpp new file mode 100644 index 0000000..82f16eb --- /dev/null +++ b/src/plugins/document/eselectdoctype.cpp @@ -0,0 +1,77 @@ +#include "eselectdoctype.h" + +#include +#include +#include + +/* + * Constructs a eSelectDocType as a child of 'parent', with the + * name 'name' and widget flags set to 'f'. + * + * The dialog will by default be modeless, unless you set 'modal' to + * true to construct a modal dialog. + */ +eSelectDocType::eSelectDocType(QWidget* parent, const char* name, bool modal, Qt::WindowFlags fl) + : QDialog(parent, name, modal, fl) +{ + setupUi(this); + + init(); +} + +/* + * Destroys the object and frees any allocated resources + */ +eSelectDocType::~eSelectDocType() +{ + // no need to delete child widgets, Qt does it all for us +} + +/* + * Sets the strings of the subwidgets using the current + * language. + */ +void eSelectDocType::languageChange() +{ + retranslateUi(this); +} + +void eSelectDocType::init() +{ + listDocs->header()->hide(); + listDocs->setColumnWidth( 0, 1000 ); + listDocs->setFocus(); +} + + +void eSelectDocType::setJournal( aCfg *md, int id ) +{ + aCfgItem obj, dobj; + int i, cnt, t, did; + QString name; + + listDocs->clear(); + dlist.clear(); + obj = md->find( id ); + if ( !obj.isNull() ) { + dlist = md->getJournalDocuments( obj ); +// printf("docs=%s\n", ( const char *) dlist.join("\n") ); + for (i=0;i< dlist.count();i++) { + did = dlist[i].toInt(); + dobj = md->find( did ); + if ( !dobj.isNull() ) { + name = md->attr( dobj, mda_name ); + new Q3ListViewItem( listDocs, name, dlist[i] ); + } + } + listDocs->setSelected( listDocs->firstChild(), true ); + } +} + + +void eSelectDocType::accepted() +{ + docId = listDocs->selectedItem()->text(1).toInt(); + // printf("docId=%i\n", docId ); + accept(); +} diff --git a/src/plugins/document/eselectdoctype.h b/src/plugins/document/eselectdoctype.h new file mode 100644 index 0000000..936ab86 --- /dev/null +++ b/src/plugins/document/eselectdoctype.h @@ -0,0 +1,28 @@ +#ifndef ESELECTDOCTYPE_H +#define ESELECTDOCTYPE_H + +#include "ui_eselectdoctype.h" + + +class eSelectDocType : public QDialog, public Ui::eSelectDocType +{ + Q_OBJECT + +public: + eSelectDocType(QWidget* parent = 0, const char* name = 0, bool modal = false, Qt::WindowFlags fl = 0); + ~eSelectDocType(); + + QStringList dlist; + int docId; + +public slots: + virtual void init(); + virtual void setJournal( aCfg * md, int id ); + virtual void accepted(); + +protected slots: + virtual void languageChange(); + +}; + +#endif // ESELECTDOCTYPE_H diff --git a/src/plugins/document/eselectdoctype.ui b/src/plugins/document/eselectdoctype.ui new file mode 100644 index 0000000..662f149 --- /dev/null +++ b/src/plugins/document/eselectdoctype.ui @@ -0,0 +1,102 @@ + + + + + eSelectDocType + + + + 0 + 0 + 304 + 272 + + + + Select document type + + + + + + Cancel + + + + + + + OK + + + true + + + + + + + Q3ScrollView::AlwaysOff + + + + Document type + + + true + + + true + + + + + ID + + + true + + + true + + + + + + + + + 21 + 171 + + + + Expanding + + + Vertical + + + + + + + qPixmapFromMimeSource + + ananas.h + + + + bOK + clicked() + eSelectDocType + accepted() + + + bCancel + clicked() + eSelectDocType + reject() + + + diff --git a/src/plugins/document/wdocument.cpp b/src/plugins/document/wdocument.cpp new file mode 100644 index 0000000..a3f82c9 --- /dev/null +++ b/src/plugins/document/wdocument.cpp @@ -0,0 +1,420 @@ +/**************************************************************************** +** $Id: wdocument.cpp,v 1.2 2008/11/08 20:16:36 leader Exp $ +** +** Code file of the document plugin of Ananas +** Designer and Engine applications +** +** Created : 20031201 +** +** Copyright (C) 2003-2004 Leader InfoTech. All rights reserved. +** +** This file is part of the Ananas Plugins of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.leaderit.ru/page=ananas or email sales@leaderit.ru +** See http://www.leaderit.ru/gpl/ for GPL licensing information. +** +** Contact org@leaderit.ru if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#include +//--#include +#include "adatabase.h" +#include "adocument.h" +#include "asqltable.h" +#include "wdocument.h" +#include "edocument.h" +#include "wdbfield.h" +#include "wdbtable.h" +#include "wactionbutton.h" +#include "alog.h" + + +/*! + *\~english + * Create wDocument object. + *\~russian + * Создает объект wDocument. + *\~ + *\param - \~english \~russian \~ + *\param - \~english \~russian \~ + */ +wDocument::wDocument( QWidget *parent, Qt::WFlags fl ) +:aWidget( parent, "wDocument", fl ) +{ + setInited( false ); +} + + + +/*! + *\~english + * Destructor for object. + *\~russian + * Деструктор. + *\~ + */ +wDocument::~wDocument() +{ + +} + + + +/*! + *\~english + * Create aDocument database object. + *\~russian + * Создает объект aDocument для работы с базой. + *\~ + *\param - \~english \~russian \~ + *\param - \~english \~russian \~ + *\return \~english \~russian \~ + */ +aObject * +wDocument::createDBObject( aCfgItem obj, aDatabase *adb ) +{ + return new aDocument( obj, adb ); +} + + + +/*! + *\~english + *\~russian + *\~ + *\param - \~english \~russian \~ + */ +void +wDocument::initObject( aDatabase *adb ) +{ + aWidget::initObject( adb ); + QObject *obj; + QObjectList lb = this->queryList( "wDBField" ); + QListIterator itb( lb ); // iterate over the buttons + while ( itb.hasNext() ) + { + obj = itb.next(); +// if ( (wActionButtton*) obj )->isActionUpdate() ) + connect( (wDBField *)obj, SIGNAL(valueChanged( const QVariant & )), + this, SLOT(valueChanged( const QVariant & )) ); + } + //--delete lb; // delete the list, not the objects + lb = this->queryList( "wDBTable" ); + QListIterator itb1( lb ); // iterate over the buttons + while ( itb1.hasNext() ) + { + obj = itb1.next(); +// if ( (wActionButtton*) obj )->isActionUpdate() ) + connect( this, SIGNAL(changeObj(const QString &)), + (wDBTable *)obj, SLOT(newFilter(const QString &))); + connect( this, SIGNAL(changeObjId(const qulonglong)), + (wDBTable *)obj, SLOT(newDataId(const qulonglong))); + } + //--delete lb; // delete the list, not the objects + //--focusData()->next()->setFocus(); + focusNextChild(); +} + + + +/*! + *\~english + *\~russian + *\~ + *\return \~english \~russian \~ + */ +bool +wDocument::checkStructure() +{ + return false; +} + + + +/*! + *\~english + *\~russian + *\~ + *\param - \~english \~russian \~ + *\return \~english \~russian \~ + */ +QDialog* +wDocument::createEditor( QWidget *parent ) +{ + return new eDocument( parent ); +} + + + +/*! + *\~english + *\~russian + *\~ + *\param - \~english \~russian \~ + *\return \~english \~russian \~ + */ +int +wDocument::select( qulonglong id ) +{ + id=id; + return 0; +} + + + +/*! + *\~english + * Select object in database. + *\~russian + * Выбирает объект в базе данных. + *\~ + *\param id -\~english database record id.\~russian id объекта в базе данных.\~ + *\return id -\~english error code.\~russian код ошибки.\~ + */ +ERR_Code +wDocument::Select( qulonglong id ) +{ + ERR_Code err = aWidget::Select ( id ); +/* if ( err ) + { + printf( "select document error %i\n", err ); + return err; + } +*/ NewValues(); + emit( changeObj(QString("idd=%1").arg(id))); + emit( changeObjId(id)); + return err_noerror; +} + + +/*! + *\~english + *\~russian + *\~ + *\param - \~english \~russian \~ + *\return \~english \~russian \~ + */ +qulonglong +wDocument::Insert() +{ + return 0; +} + + + +/*! + *\~english + * Update values in database. + * Udate values in current document header. + *\~russian + * Обновляет значения в базе данных. + * Обновляет значения в текущей шапке документа. + *\~ + *\return \~english error code.\~russian код ошибки.\~ + */ +int +wDocument::Update() +{ + if ( dbobj ) { + return dbobj->Update(); + NewValues(); + } + else return err_abstractobj; +} + + + +/*! + *\~english + *\~russian + *\~ + *\param - \~english \~russian \~ + *\return \~english \~russian \~ + */ +int +wDocument::MarkDelete() +{ + return 0; +} + + + +/*! + *\~english + *\~russian + *\~ + *\return \~english \~russian \~ + */ +QString +wDocument::displayString() +{ + return""; +} + + + +/*! + *\~english + *\~russian + *\~ + *\return \~english \~russian \~ + */ +bool +wDocument::isContainer() +{ + return true; +} + + + +/*! + *\~english + *\~russian + *\~ + *\return \~english \~russian \~ + */ +int +wDocument::New() +{ + ERR_Code err = aWidget::New(); + qulonglong idd; + if ( err ) return err; + NewValues(); + idd = uid(); +// printf("<<<<<<<<<<<<<<Conduct(); +} +/*! + *\~english + * UnConduct current docment. + *\~russian + * Распроводит текущий документ. + *\~ + *\return \~english error code.\~russian код ошибки.\~ + */ +int +wDocument::TurnOff() +{ + if (!dbobj) return err_abstractobj; + else return dbobj->UnConduct(); +} + + + +/*! + *\~english + * Set fields values from database. + * Used for insert values into fields when create or open document. + *\~russian + * Устанавливает значения виджетов (кроме таблиц). + * Устанавливает значения виджетов (полей экранной формы таких как поля шапки документа) + * равными значениям из базы данных. + * Используется для при открытии формы, смене документа, обновлении значений виджетов документа. + *\~ + */ +void +wDocument::NewValues() +{ + QString fname; + QObjectList l = this->queryList( "wDBField" ); + QListIterator it( l ); + QObject *obj; + while ( it.hasNext() ) + { + obj = it.next(); + fname=((wDBField *)obj)->getFieldName(); + ((wDBField *)obj)->setValue(dbobj->Value(fname).toString()); + aLog::print(aLog::Debug, tr("wDocument set new value %1 for field %2 ").arg(dbobj->Value(fname).toString()).arg(fname)); + } + //--delete l; // delete the list, not the objects +} + + + +/*! + *\~english + * Processed field value changed. + * Conected on signal valueChanged( const QVariant & ) for all + * wDBField insert in the widget. + * Decode field name and set new field value in database object. + * Emit signal value change with field name and value. + * Signal connectaed on aform slot, for future work. + *\~russian + * Обрабатывает изменение значения поля + * Присоединяется к сигналу valueChanged( const QVariant & ), + * всех полей типа wDBField, вставленных в виджет. + * Декодирует имя поля и сохраняет его новое значение в объекте для + * работы с базой. + * Посылает сигнал об изменении значения, который содержит имя поля + * и его новое значение. + * Сигнал присоединяется к слоту формы для последующей обработки. + *\~ + *\param value - \~english new field value. \~russian новое значение поля. \~ + */ +void +wDocument::valueChanged( const QVariant & value ) +{ + if ( sender()->className() != QString("wDBField") ) return; + wDBField * fld = ( wDBField * ) sender(); + QString fname=fld->getFieldName(); +// printf( "field name %s\n",(const char*)fname ); + if ( dbobj ) dbobj->SetValue( fname, value ); + emit aWidget::valueChanged( fname, value ); +} + +/*void +wDocument::on_abuttonclick() +{ + wActionButton *b = ( wActionButton *) sender(); + if ( !b ) return; + if ( !b->isAction() ) return; + if ( b->isActionUpdate() ) + { + QString fname; + QObjectList *l = this->queryList( "wDBField" ); + QObjectListIt it( *l ); + QObject *obj; + uint i = 0; + while ( (obj = it.current()) != 0 ) + { + ++it; + fname=((wDBField *)obj)->getFieldName(); + dbobj->SetValue(fname,((wDBField *)obj)->value()); + } + update(); + } + if ( b->isActionTurnOn() ) Conduct(); +}*/ + diff --git a/src/plugins/document/wdocument.h b/src/plugins/document/wdocument.h new file mode 100644 index 0000000..06920e9 --- /dev/null +++ b/src/plugins/document/wdocument.h @@ -0,0 +1,83 @@ +/**************************************************************************** +** $Id: wdocument.h,v 1.1 2008/11/05 21:16:30 leader Exp $ +** +** Header file of the document plugin of Ananas +** Designer and Engine applications +** +** Created : 20031201 +** +** Copyright (C) 2003-2004 Leader InfoTech. All rights reserved. +** +** This file is part of the Ananas Plugins of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.leaderit.ru/page=ananas or email sales@leaderit.ru +** See http://www.leaderit.ru/gpl/ for GPL licensing information. +** +** Contact org@leaderit.ru if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#ifndef WDOCUMENT_H +#define WDOCUMENT_H +#include +#include +#include "awidget.h" + +class aDatabase; + + + +/*! + *\~english + * Visual object for work with documents. + *\~russian + * \brief Визуальный объект - контейнер для работы с документами. + * Наследует aWidget. + */ +class QT_WIDGET_PLUGIN_EXPORT wDocument : public aWidget +{ + Q_OBJECT +public: + wDocument( QWidget *parent = 0, Qt::WFlags fl = 0 ); + virtual ~wDocument(); + bool checkStructure(); + virtual void initObject( aDatabase *adb ); + virtual QDialog* createEditor( QWidget *parent ); + virtual QString displayString(); + virtual bool isContainer(); + virtual aObject *createDBObject( aCfgItem obj, aDatabase *adb ); + + virtual ERR_Code New(); + virtual ERR_Code Select( qulonglong id ); + +public slots: + int select( qulonglong id ); + qulonglong Insert(); + virtual int Update(); + virtual int TurnOn(); + virtual int TurnOff(); + int MarkDelete(); +// void on_abuttonclick(); + +//signals: +// void valueChanged( const QString &, const QVariant & ); + +private slots: + virtual void valueChanged( const QVariant & ); + +private: + void NewValues(); +}; + + +#endif // WDOCUMENT_H diff --git a/src/plugins/document/wdocument_plugin.cpp b/src/plugins/document/wdocument_plugin.cpp new file mode 100644 index 0000000..ecec7e4 --- /dev/null +++ b/src/plugins/document/wdocument_plugin.cpp @@ -0,0 +1,100 @@ +/**************************************************************************** +** +** Code file +** +** Copyright (C) 2006 Dmitriy Pavlyuk +** +** This file is part of the Ananas Plugins of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +**********************************************************************/ + +#include "wdocument_plugin.h" + +#include +#include +#include + +#include "wdocument_taskmenu.h" +#include "wdocument.h" + + +wDocumentPlugin::wDocumentPlugin(QObject *parent) + : QObject(parent), m_initialized(false) +{ + m_initialized = false; +} + +bool wDocumentPlugin::isContainer() const +{ + return true; +} + +bool wDocumentPlugin::isInitialized() const +{ + return m_initialized; +} + +void wDocumentPlugin::initialize(QDesignerFormEditorInterface *core) +{ + if (m_initialized) + return; + Q_UNUSED(core); + + QExtensionManager *manager = core->extensionManager(); + Q_ASSERT(manager != 0); + manager->registerExtensions(new wDocumentTaskMenuFactory(manager), + Q_TYPEID(QDesignerTaskMenuExtension)); + + m_initialized = true; +} + +QWidget *wDocumentPlugin::createWidget(QWidget *parent) +{ + wDocument *w = new wDocument(parent, 0); + return w; +} + +QString wDocumentPlugin::name() const +{ + return QLatin1String("wDocument"); +} + +QString wDocumentPlugin::group() const +{ + return QLatin1String("Ananas"); +} + +QString wDocumentPlugin::toolTip() const +{ + return QString(); +} + +QString wDocumentPlugin::whatsThis() const +{ + return QString(); +} + +QString wDocumentPlugin::includeFile() const +{ + return QLatin1String("wdocument.h"); +} + +QIcon wDocumentPlugin::icon() const +{ + //return QIcon(); + return QIcon(":/images/wdocument.png"); +} + +QString wDocumentPlugin::domXml() const +{ + return "\n\n"; +} diff --git a/src/plugins/document/wdocument_plugin.h b/src/plugins/document/wdocument_plugin.h new file mode 100644 index 0000000..2028630 --- /dev/null +++ b/src/plugins/document/wdocument_plugin.h @@ -0,0 +1,53 @@ +/**************************************************************************** +** +** Header file +** +** Copyright (C) 2006 Dmitriy Pavlyuk +** +** This file is part of the Ananas Plugins of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +**********************************************************************/ + +#ifndef WDOCUMENT_PLUGIN_H +#define WDOCUMENT_PLUGIN_H + +#include + +#include "qwidgetplugin.h" + + +class QT_WIDGET_PLUGIN_EXPORT wDocumentPlugin : public QObject, public QDesignerCustomWidgetInterface +{ + Q_OBJECT + Q_INTERFACES(QDesignerCustomWidgetInterface) + +public: + wDocumentPlugin(QObject *parent=0); + + bool isContainer() const; + bool isInitialized() const; + void initialize(QDesignerFormEditorInterface *core); + QWidget *createWidget(QWidget *parent); + + QString name() const; + QString group() const; + QString toolTip() const; + QString whatsThis() const; + QString includeFile() const; + QIcon icon() const; + QString domXml() const; + +private: + bool m_initialized; +}; + +#endif // WDOCUMENT_PLUGIN_H diff --git a/src/plugins/document/wdocument_taskmenu.cpp b/src/plugins/document/wdocument_taskmenu.cpp new file mode 100644 index 0000000..6856cef --- /dev/null +++ b/src/plugins/document/wdocument_taskmenu.cpp @@ -0,0 +1,74 @@ +/**************************************************************************** +** +** Copyright (C) 2006 Dmitriy Pavlyuk All rights reserved. +** +** This file is part of the widgets plugin of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +****************************************************************************/ + +#include + +#include + +#include "wdocument_taskmenu.h" +#include "wdocument.h" +#include "edocument.h" + + +wDocumentTaskMenu::wDocumentTaskMenu(wDocument *widget, QObject *parent) + : QObject(parent) +{ + m_widget = widget; + + m_editAction = new QAction(tr("Edit ..."), this); + connect(m_editAction, SIGNAL(triggered()), this, SLOT(edit())); +} + +void wDocumentTaskMenu::edit() +{ + /*eDocument e; + + e.setData(m_widget); + if (e.exec() == QDialog::Accepted) + { + e.getData(m_widget); + }*/ + m_widget->widgetEditor(); +} + +QAction *wDocumentTaskMenu::preferredEditAction() const +{ + return m_editAction; +} + +QList wDocumentTaskMenu::taskActions() const +{ + QList list; + list.append(m_editAction); + return list; +} + +wDocumentTaskMenuFactory::wDocumentTaskMenuFactory(QExtensionManager *parent) + : QExtensionFactory(parent) +{ +} + +QObject *wDocumentTaskMenuFactory::createExtension(QObject *object, const QString &iid, QObject *parent) const +{ + if (iid != Q_TYPEID(QDesignerTaskMenuExtension)) + return 0; + + if (wDocument *dt = qobject_cast(object)) + return new wDocumentTaskMenu(dt, parent); + + return 0; +} diff --git a/src/plugins/document/wdocument_taskmenu.h b/src/plugins/document/wdocument_taskmenu.h new file mode 100644 index 0000000..44c190c --- /dev/null +++ b/src/plugins/document/wdocument_taskmenu.h @@ -0,0 +1,57 @@ +/**************************************************************************** +** +** Copyright (C) 2006 Dmitriy Pavlyuk All rights reserved. +** +** This file is part of the widgets plugin of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +****************************************************************************/ + +#ifndef WDOCUMENT_TASKMENU_H +#define WDOCUMENT_TASKMENU_H + +#include +#include + + +class QExtensionManager; +class QAction; +class wDocument; + +class wDocumentTaskMenu: public QObject, public QDesignerTaskMenuExtension +{ + Q_OBJECT + Q_INTERFACES(QDesignerTaskMenuExtension) +public: + wDocumentTaskMenu(wDocument *widget, QObject *parent); + + QAction *preferredEditAction() const; + QList taskActions() const; + +private slots: + void edit(); + +private: + QAction *m_editAction; + wDocument *m_widget; +}; + +class wDocumentTaskMenuFactory: public QExtensionFactory +{ + Q_OBJECT +public: + wDocumentTaskMenuFactory(QExtensionManager *parent = 0); + +protected: + QObject *createExtension(QObject *object, const QString &iid, QObject *parent) const; +}; + +#endif // WDOCUMENT_TASKMENU_H diff --git a/src/plugins/eaddobj.cpp b/src/plugins/eaddobj.cpp new file mode 100644 index 0000000..76f7a9d --- /dev/null +++ b/src/plugins/eaddobj.cpp @@ -0,0 +1,48 @@ +#include "eaddobj.h" + +#include +#include +#include + +/* + * Constructs a eAddObj as a child of 'parent', with the + * name 'name' and widget flags set to 'f'. + * + */ +eAddObj::eAddObj(QWidget* parent, const char* name, Qt::WindowFlags fl) + : Q3MainWindow(parent, name, fl) +{ + setupUi(this); + + (void)statusBar(); + init(); +} + +/* + * Destroys the object and frees any allocated resources + */ +eAddObj::~eAddObj() +{ + destroy(); + // no need to delete child widgets, Qt does it all for us +} + +/* + * Sets the strings of the subwidgets using the current + * language. + */ +void eAddObj::languageChange() +{ + retranslateUi(this); +} + +void +eAddObj::init() +{ +} + +void +eAddObj::destroy() +{ +} + diff --git a/src/plugins/eaddobj.h b/src/plugins/eaddobj.h new file mode 100644 index 0000000..b38556e --- /dev/null +++ b/src/plugins/eaddobj.h @@ -0,0 +1,24 @@ +#ifndef EADDOBJ_H +#define EADDOBJ_H + +#include "ui_eaddobj.h" + + +class eAddObj : public Q3MainWindow, public Ui::eAddObj +{ + Q_OBJECT + +public: + eAddObj(QWidget* parent = 0, const char* name = 0, Qt::WindowFlags fl = Qt::WType_TopLevel); + ~eAddObj(); + +protected slots: + virtual void languageChange(); + +private: + void init(); + void destroy(); + +}; + +#endif // EADDOBJ_H diff --git a/src/plugins/eaddobj.ui b/src/plugins/eaddobj.ui new file mode 100644 index 0000000..22e890a --- /dev/null +++ b/src/plugins/eaddobj.ui @@ -0,0 +1,39 @@ + + + + + eAddObj + + + + 0 + 0 + 417 + 297 + + + + Form1 + + + + + + + 0 + + + 0 + + + + + + + + qPixmapFromMimeSource + + adocument.h + acatalogue.h + + diff --git a/src/plugins/engine.cpp b/src/plugins/engine.cpp new file mode 100644 index 0000000..2c163f9 --- /dev/null +++ b/src/plugins/engine.cpp @@ -0,0 +1,874 @@ +/**************************************************************************** +** $Id: engine.cpp,v 1.4 2008/12/10 21:04:56 leader Exp $ +** +** Code file of the Ananas Engine of Ananas +** Engine applications +** +** Created : 20031201 +** +** Copyright (C) 2003-2004 Leader InfoTech. All rights reserved. +** Copyright (C) 2003-2004 Grigory Panov, Yoshkar-Ola. +** +** This file is part of the Library of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.leaderit.ru/page=ananas or email sales@leaderit.ru +** See http://www.leaderit.ru/gpl/ for GPL licensing information. +** +** Contact org@leaderit.ru if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +//--#include +#include +#include +#include +#include +//Added by qt3to4: +#include +#include + +#include "ananas.h" +#include "wcatalogeditor.h" +#include "adatafield.h" +#include "alog.h" +#include "acombobox.h" + +/*! + * \~english + * Constructor + * \~russian + * Конструктор. Регистрирует следующие типу объектов для использования их в Ананас.Скрипте + * \arg \c PopupMenu всплывающее меню + * \arg \c Document документ + * \arg \c Catalogue каталог + * \arg \c CatalogueEditor редактор каталога + * \arg \c Report отчет + * \arg \c ARegister накопительный регистр + * \arg \c DataField поле (не работает) + * \arg \c Journal журнал + * \arg \c ATime объект для работы со временем + * \~ + */ +aObjectsFactory::aObjectsFactory( aEngine *e ) +{ + engine = e; + if ( ! engine ) return; + db = e->db; + if ( ! db ) return; + + + registerClass("MetaObject",&AMetaObject::staticMetaObject); + registerClass("MetaObjectGroup",&AMetaObjectGroup::staticMetaObject); + registerClass("DocumentsGroup",&ADocumentsGroup::staticMetaObject); + registerClass("CataloguesGroup",&ACataloguesGroup::staticMetaObject); + registerClass("MetaDataInfo",&AMetaDataInfo::staticMetaObject); + registerClass("MetaDataGlobal",&AMetaDataGlobal::staticMetaObject); + + + registerClass("PopupMenu",&Q3PopupMenu::staticMetaObject); +// registerClass("PopupMenu","QApopupmenu"); + registerClass("Document",&aDocument::staticMetaObject); + registerClass("Catalogue",&aCatalogue::staticMetaObject); + registerClass("CatalogEditor",&wCatalogEditor::staticMetaObject); + registerClass("Report",&aReport::staticMetaObject); + registerClass("ARegister",&aARegister::staticMetaObject); + registerClass("IRegister",&aIRegister::staticMetaObject); + registerClass("ATime",&aTime::staticMetaObject); + registerClass("DataField",&aDataField::staticMetaObject); +// registerClass("reg","QAreg"); + registerClass("Journal",&aDocJournal::staticMetaObject); + registerClass("ComboBox",&AComboBox::staticMetaObject); +//registerClass("djournalview","QAjournview"); +// registerClass("djournalview","QAdocjournal"); +// registerClass("form","AForms"); +// registerClass("report","QAreport"); +// registerClass("table","QAnanasTable"); + +//Register extensions classes + QStringList extlist = AExtensionFactory::keys(); + for ( int i=0; i0) { + res = new aDocument(arguments[0].toString(), db ); + } + }else if (className=="Catalogue") { + if (arguments.size()>0) { + res = new aCatalogue( arguments[0].toString(), db ); + } + }else if ( className=="Report" ) { + if ( arguments.size()>0 ) + { + if(arguments.size()==2) { + res = new aReport( arguments[0].toString(),(aReport::RT_type)arguments[1].toInt(), engine ); + }else{ + res = new aReport( arguments[0].toString(),aReport::RT_text, engine ); + } + } + }else if (className =="CatalogEditor") { + if (arguments.size()>0) { + aCfgItem it; + it = db->cfg.find(QString("Catalogue.%1").arg(arguments[0].toString())); + if(!it.isNull()) { + wCatalogEditor * w = new wCatalogEditor(engine->ws,db->cfg.id(it)); + w->initCat(db); + res = w; + } + } + }else if (className == "ARegister") { + if (arguments.size() > 0) { + res = new aARegister(arguments[0].toString(), db); + } + + }else if (className == "IRegister") { + if (arguments.size() > 0) { + res = new aIRegister(arguments[0].toString(), db); + } + + } else if (className == "Journal") { + if (arguments.size() > 0) { + res = new aDocJournal(arguments[0].toString(), db); + } + + } else if (className == "ATime") { + res = new aTime(); + } else if (className == "DataField") { + res = new aDataField(); + } else if ( AExtensionFactory::keys().contains( className )) { +// printf("create extension object %s\n",(const char*) className); + AExtension *obj = AExtensionFactory::create( className ); + // Insert check existence signal in future!!!! + QObject::connect( obj, SIGNAL(event(const QString&)), + engine, SLOT( on_event(const QString&))); + obj->init(db); + res = obj; + } else if ( className == "ComboBox" ) { + if (arguments.size() == 1) { + res = new AComboBox( 0, arguments[0].toString()); + } else { + res = new AComboBox(); + } + } + if(!res) aLog::print(aLog::Error,QObject::tr("Unknown classname '%1' or metaobject '%2'").arg(className).arg(arguments[0].toString())); + return res; +} + + + +/*! + *\en + * Constructor. + *\_en + *\ru + * Конструктор. Создает новый объект с именем "sys". Доступ к функциям этого объекта из Ананас.Скрипта возможен примерно так: + * \code + * sys.Date(); // текущая дата + * sys.OpenForm("DocJournal.Системный журнал.Form.Список документов"); // открывает форму "Список Документов" журнала "Системный журнал" + * \endcode + *\_ru + */ +aEngine::aEngine():QObject(0,"sys") +{ + md = 0; + next_obj_id = 1; + db = aDatabase::database(); +} + + + +/*! + *\en + * Destructor + *\_en \ru + * Деструктор. + *\_ru + */ +aEngine::~aEngine() +{ + values.clear(); +// delete project; +} + + + +/*! + * \~english + * Init engine. + * Init script subsystem, load global module. + * \~russian + * Инициализирует объект. Инициализирует скриптовую систему, добавляет несколько глобальных функций. + * \~ + */ +bool +aEngine::init( const QString &rcfile ) +{ +// QString mGlobal; + aCfgItem gobj, obj, obj0; + QString sysf = +// "function Message( t, msg ){ sys.Message( t, msg );}" +// "function StatusMessage( msg ){ sys.StatusMessage( msg );}" +// "function Date(){ return sys.Date();}" +// "function Time(){ return sys.Time();}" +// "function Exit(){ return sys.Exit();}" + ""; + + bool ok = false; + if ( db->init( rcfile ) ) { + md = &db->cfg; + code = project.interpreter(); +// code->setErrorMode(QSInterpreter::Notify); + code->setErrorMode(QSInterpreter::Nothing); + connect(code, SIGNAL( error ( const QString &, QObject *, const QString &, int )), + this, SLOT ( error ( const QString &, QObject *, const QString &, int ))); + code->addObjectFactory( new QSInputDialogFactory ); + code->addObjectFactory( new aObjectsFactory( this ) ); + code->addObjectFactory( new QSUtilFactory ); + project.addObject( this ); + project.addObject( md ); + project.addObject( AMetaData::metadata() ); + mGlobal = md->sText( md->find( md->find( mdc_metadata ), md_globals, 0 ), md_sourcecode ); + if ( ! mGlobal.isEmpty() ) { +// project.createScript("global", mGlobal); +// project.createScript(this, mGlobal ); +// project.createScript( "globalmodule", sysf ); +// project.createScript( this, sourcePreprocessor(mGlobal)); + project.createScript( "globalmodule", sysf+sourcePreprocessor(mGlobal)); +// code->evaluate(sourcePreprocessor(mGlobal)); + } else { +// printf("Global module is empty\n"); + } + } else return false; + return true; +} + + + +/*! + *\en + *\_en \ru + * Заглушка. + *\_ru + */ +void +aEngine::done() +{ + +} + + + +/*! + *\en + * Called on system start. + *\_en \ru + * Автоматически вызывается при старте системы. Если в глобальном модуле определа функция on_systemstart() + * то она будет автоматически вызвана. + * Это можно использовать для открытия документов или журналов при старте системы, или каких-либо других действий. + * \see on_systemstop() + *\_ru + */ +int +aEngine::on_systemstart(){ + + if (project.interpreter()->functions().findIndex("on_systemstart")!=-1) { + project.interpreter()->call("on_systemstart",QVariantList()); + } + return 0; +} + + +void +aEngine::on_event( const QString &data ) +{ + Q3ValueList lst; + lst << sender()->name(); + lst << data; + if (project.interpreter()->functions().findIndex("on_event")!=-1) { + project.interpreter()->call("on_event", QVariantList(lst)); + } + emit event( sender()->name(), data ); +} + + + +/*! + *\en + * Called on system stop. + *\_en \ru + * Автоматически вызывается при остановке системы. + * Если в глобальном модуле определа функция on_systemstop() + * то она будет автоматически вызвана. + * \see on_systemstart() + *\_ru + */ +int +aEngine::on_systemstop(){ + if (project.interpreter()->functions().findIndex("on_systemstop")!=-1) { + project.interpreter()->call("on_systemstop",QVariantList()); + } + return 0; +} + + + +/*! + *\en + * Stub. + *\_en \ru + * Заглушка. + *\_ru + */ +void +aEngine::timerEvent(QTimerEvent *e) +{ + e=e; // +// project->interpreter()->evaluate(pr_timer, this); +} + + + +/*! + *\en + * Stub. + *\_en \ru + * Заглушка. Возвращает всегда строку "???" + * В будущем возможно будет возвращать имя конфигурации. + *\_ru + */ +QString +aEngine::cfgname() { + return "???"; //cfg_info("name"); +} + + + +/*! + *\en + *\_en \ru + * Возвращает строковое представление текущего времени в формате "hh:mm:ss" + *\_ru + */ +QString +aEngine::Time() { + return QTime::currentTime().toString("hh:mm:ss"); +} + + + +/*! + *\en + *\_en \ru + * Возвращает строковое представление текущей даты в формате "dd.MM.yy" + *\_ru + */ +QString +aEngine::Date() { + return QDate::currentDate().toString("dd.MM.yy"); +} + + +void +aEngine::Exit() { + qApp->quit(); +} + +/*! + * \~english + * Outputs messages. + * \~russian + * Вывод сообщений. + * \param n - тип сообщения. 0 - уведомление, 1 - предупреждение, 2 - ошибка. + * \param msg - текст сообщения. + * \~ + * \see cfg_message(int msgtype, const char *msgfmt,...) + */ +void +aEngine::Message(int n, const QString &msg) +{ + cfg_message(n, (const char *) msg.utf8()); +} + + + +/*! + *\en + * Outputs status messages. + *\_en \ru + * Вывод сообщений в строке состояния. + * \param msg - текст сообщения. + *\_ru + */ +void +aEngine::StatusMessage( const QString &msg ) +{ + emit statusMessage( msg ); +} + + + +/*! + *\en + *\_en \ru + *\_ru + */ +void +aEngine::settimer(int sec, QString proc){ + // TODO Need id timer - get from startTimer + //--killTimers(); + if (sec) { + pr_timer=proc; + startTimer(sec*1000); + } else { + pr_timer=""; + } +} + + + +/*! + *\en + *\_en \ru + * Запускает действие + * \param id - идентификатор действия в метаданных. + *\_ru + */ +void +aEngine::on_MenuBar( int id ) +{ + aCfgItem obj, act; + int actions, i; + +// printf("menu %i selected\n", id); + if ( id>0 ) { + obj = md->find( id ); + if ( !obj.isNull() ) { + actions = md->count( obj, md_comaction ); +// printf("obj found %i actions\n", actions); + for ( i=0; ifindChild( obj, md_comaction, i ); + act = md->find( md->text( act ).toLong() ); + execAction( act ); + } + } + } +} + + + +/*! + *\en + *\_en \ru + * Вспомогательный метод. + * Запускает действие в указанном контексте. Правильная работа не гарантируется (где-то там ошибки есть). + * \param act - ссылка на объект метаданных, описывающий действие + * \param context - контекст выполнения действия. + *\_ru + */ +void aEngine::execAction( aCfgItem &act, QObject *context ) +{ + QString aModule, arg; + int atype, satype; + long oid, foid; + //aForm *form; + aCfgItem gobj, obj; + + if ( ! act.isNull() ) { + atype = md->attr( act, mda_type ).toInt(); +// printf("atype=%i\n",atype); + switch ( atype ){ + case 0: + satype = md->sText( act, md_actiontype ).toInt(); + oid = md->sText( act, md_objectid ).toLong(); + foid = md->sText( act, md_formid ).toLong(); + arg = md->sText( act, md_argument ); +// printf("satype=%d, oid=%d,foid=%d,arg=%s",satype,oid,foid,arg.ascii()); + gobj = md->find( oid ); + if ( foid == 0 ) + { + foid = md->getDefaultFormId( gobj, satype ); + break; + } + if ( foid == 1 ) + { + openEmbedCatalogueEditor(oid, NULL, false); //open to edit + break; + } + + openForm(oid, foid, satype, 0, 0, 0 ); + break; +/* if ( !arg.isEmpty() ) { + obj = md->findName( md->find( gobj, md_forms ), md_form, arg ); + foid = md->id( obj ); +// if ( !obj.isNull() ) printf("form found\n"); +// else printf("! not found %s\n", (const char *) arg ); + }*/ + /* + if ( wl->find( foid ) ) + { + printf("form already exist,set focus \n"); + wl->get( foid )->setFocus(); + } + else + { + printf("execute action\n"); + if ( oid ) + switch ( satype ) + { + case md_action_new://create new + printf("create new\n"); + form = new aForm( ws, this, foid ); +// form->init(); + form->New(); + form->show(); + break; + case md_action_view://view + printf("view\n"); + form = new aForm( ws, this, foid ); + //form->init(); + form->show(); + break; + } + } + break; + */ + case 1: + aModule = md->sText( act, md_sourcecode ); + if ( !aModule.isEmpty() ) { + code->evaluate( sourcePreprocessor(aModule), context, md->attr( act, mda_name ) ); + } + break; + case 2: + break; + } +// printf("executed %s\n", ( const char *) md->attr( act, mda_name ).local8Bit() ); + } +} + + + +/*! + *\~english + * Create and open new form. + *\~russian + * Создает и открывает новую форму. + * Форма создается с учетом её id в конфигураци и действия, + * режима работы (просмотр, редактирование, создание нового объекта). + * Форма должна поддерживать тот режим, для которого она открывается. + * Если форма открыта для просмотра она открывается в режиме отлько чтение. + * Если id формы равно 0, делается попытка найти первую форму с + * требуемым режимом. + *\~ + *\param oid - \~english form owner md id,\~russian id владельца формы в конфигурации,\~ + *\param fid - \~english form md id, \~russian id формы в конфигурации\~ + *\param mode - \~english form use mode, \~russian режим работы формы\~ + *\param ido - \~english database id of opening object\~russian идентификатор объекта в базе данных, для которого открывается форма.\~ + *\return \~english link on new form or 0 if form not created. + \~russian ссылку на новую форму или 0, если форма не создана.\~ + */ +aForm* +aEngine::OpenForm(QString fname, int mode, aObject* selecter)//Q_ULLONG ido) +{ + aCfgItem object, form; + + form = md->find(fname); + if(!form.isNull()) + { + object = md->parent(md->parent(form)); + if(object.isNull()) return 0; + qulonglong ido =0; + if(selecter) ido = selecter->sysValue("id").toULongLong(); + return openForm(atoi(md->attr(object,mda_id)), atoi(md->attr(form,mda_id)), mode, mode, ido); + } + else + { + return 0; + } +} + + + +/*! + *\~english + * Create and open new form. + *\~russian + * Создает и открывает новую форму. + * Форма создается с учетом её id в конфигураци и действия, + * режима работы (просмотр, редактирование, создание нового объекта). + * Форма должна поддерживать тот режим, для которого она открывается. + * Если форма открыта для просмотра она открывается в режиме отлько чтение. + * Если id формы равно 0, делается попытка найти первую форму с + * требуемым режимом. + * При необходимости поля формы заполняются в соответствии с параметром \a id + *\~ + *\param oid - \~english form owner md id,\~russian id владельца формы в конфигурации,\~ + *\param fid - \~english form md id, \~russian id формы в конфигурации,\~ + *\param defaultfor - \~english form use mode, \~russian режим работы формы,\~ + *\param mode - \~english not use yet\~russian пока не используется,\~ + *\param id - \~english database id of opening object\~russian идентификатор объекта в базе данных, для которого открывается форма. Используется только в режиме просмотра или редактирования.\~ + *\param caller - \~english caller widget\~russian Вызывающий данную функцию объект. Он будет обновлен автоматически при закрытии формы. \~ + *\return \~english link on new form or 0 if form not created. + \~russian ссылку на новую форму или 0, если форма не создана.\~ + */ +aForm * +aEngine::openForm(int oid, int fid, int defaultfor, int mode, ANANAS_UID id, aWidget* caller ) +{ + aForm *form = 0; + if ( fid == 0 ) + { + fid = md->getDefaultFormId( md->find( oid ), defaultfor, mode ); + } + //printf("engine:try found %d %llu in wl\n", fid, id); + if ( wl->find( fid, id ) ) + { + //printf("foubd!, set focus\n"); + wl->get( fid, id )->setFocus(); + } + else { + //printf("not found!\n"); + aLog::print(aLog::Info,tr("aEngine open form %1 in mode %2, select %3").arg(fid).arg(mode).arg(id)); + if ( oid ) { + switch ( defaultfor ) { + case md_action_new://create new + form = new aForm( ws, this, fid, caller ); + if(form) + { + form->setMode(0); + form->New(); + } + else + { + aLog::print(aLog::Error,tr("aEngine form create error")); + } + //printf("open new form\n"); + break; + case md_action_view://view + form = new aForm( ws, this, fid, caller ); + if(form) + { + form->setMode(1); + form->SetReadOnly(true); + form->Select( id ); + } + else + { + aLog::print(aLog::Error,tr("aEngine form create error")); + } + //printf(" open form for view %llu\n",id); + break; + case md_action_edit: + form = new aForm( ws, this, fid, caller ); + if(form) + { + form->setMode(2); + form->Select( id ); + } + else + { + aLog::print(aLog::Error,tr("aEngine form create error")); + } + //printf("open form for edit %llu\n ",id); + break; + default: + aLog::print(aLog::Error, tr("aEngine open form mode %1 not supported").arg(defaultfor)); + } + connect( this, SIGNAL( event(const QString &, const QString&)), + form, SLOT( on_event(const QString &, const QString&))); + } + } + if(form && caller) + { + connect(form,SIGNAL(changedData()),caller,SLOT(Refresh())); + } +// printf("before clear\n"); +// this->project.interpreter()->clear(); + if ( form ) form->show(); +// printf("end open form\n"); + return form; +} + + + +/*! + *\~english + * Create and open new embedded catalog editor form. + *\~russian + * Создает и открывает новую форму встроенного редактора каталога. + *\~ + *\param oid - \~english catalogue md id,\~russian id каталога конфигурации,\~ + *\param parent - \~english parent wField object, \~russian родительский объект wField\~ + *\param toSelect - \~english Mode. true - for select, false - for edit\~russian Режим. true - выбор, false - редактирование\~ + */ +void +aEngine::openEmbedCatalogueEditor(int oid, QWidget* parent,const bool toSelect) +{ + wCatalogEditor * w = new wCatalogEditor(ws,oid); + if( parent ) + { + connect(w, SIGNAL(selected( qulonglong )), + (wField*)parent,SLOT(on_selected( qulonglong ))); + connect(w, SIGNAL(destroyed_form()), + (wField*)parent,SLOT(setFocus())); + } + + w->initCat(db); + if(toSelect) + { + w->select(); + } + else + { + w->edit(); + } +} + + + +/*! + *\en + *\_en \ru + * Печатает сообщение об ощибке. + *\_ru + */ +void +aEngine::error ( const QString & message, QObject * context, const QString & scriptName, int lineNumber ) +{ + Message( 2, tr("Line:%1 Message:%2 Stack:(%3)").arg(lineNumber).arg(message).arg(code->stackTraceString()) ); +} + + + +/*! + *\en + *\_en \ru + * Функция препроцессора исходного текста скрипта. + * Для разработчиков: + * В первую очередь может быть использована для замены коротких + * имен из локального контекста на квалифицированные имена + * глобальных функций и объектов, например Message() в контексте + * формы может заменяться на global.Message() перед выполнением скрипта + * и выполняться корректно из любого места. + * В противном случае приходится дублировать глобальные + * встроенные функции во всех контекстах. + *\_ru + */ +QString +aEngine::sourcePreprocessor( const QString &src ) +{ + QString psrc = src; + // Global functions preprocessing +// psrc.replace( "Message(", "global.Message("); +// psrc.replace( "Statusglobal.Message(", "global.StatusMessage("); +// psrc.replace( "Date(", "global.Date("); +// psrc.replace( "Time(", "global.Time("); + // Russian key words +// psrc.replace( QString::fromUtf8("функция"), "function"); +// psrc.replace( QString::fromUtf8("если"), "if"); +// psrc.replace( QString::fromUtf8("то"), "then"); +// psrc.replace( QString::fromUtf8("иначе"), "else"); +// psrc.replace( QString::fromUtf8("начало"), "{"); +// psrc.replace( QString::fromUtf8("конец"), "}"); + return psrc; +} + + + +/*! + *\en + *\_en \ru + * Получение значения глобальной переменной. + *\_ru + */ +QVariant +aEngine::value( const QString &name ) +{ + QVariant v, *pv; + pv = values.find( name ); + if ( pv ) return *pv; + return v; +} + + + +/*! + *\en + *\_en \ru + * Установка значения глобальной переменной. + *\_ru + */ +void +aEngine::setValue( const QString &name, QVariant value ) +{ + values.remove( name ); + if ( !value.isValid() ) values.insert( name, new QVariant( value ) ); +} + + + +/*! + *\en + *\_en \ru + * Установка значения глобальной переменной. + *\_ru + */ +aDataField* +aEngine::enterValue( const QString &FieldType, const QString &title ) +{ + aDataField *f = new aDataField( "", FieldType ); + QDialog *d = new QDialog( ws, title, true ); + wField *wf = new wField( d, "" ); + QPushButton *b_ok = new QPushButton( d, tr("OK") ); + QPushButton *b_cancel =new QPushButton( d, tr("Cancel") ); + connect( b_ok, SIGNAL( pressed() ), d, SLOT( accept() ) ); + connect( b_cancel, SIGNAL( pressed() ), d, SLOT( reject() ) ); + if ( d->exec() == QDialog::Accepted ) { +// printf("accepted\n"); + } + delete d; + return f; +} + diff --git a/src/plugins/engine.h b/src/plugins/engine.h new file mode 100644 index 0000000..2e0e46d --- /dev/null +++ b/src/plugins/engine.h @@ -0,0 +1,198 @@ +/**************************************************************************** +** $Id: engine.h,v 1.2 2008/12/10 21:04:56 leader Exp $ +** +** Header file of the Ananas Engine of Ananas +** Engine applications +** +** Created : 20031201 +** +** Copyright (C) 2003-2004 Leader InfoTech. All rights reserved. +** +** This file is part of the Library of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.leaderit.ru/page=ananas or email sales@leaderit.ru +** See http://www.leaderit.ru/gpl/ for GPL licensing information. +** +** Contact org@leaderit.ru if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +/**************************************************************************** +****************************************************************************/ +#ifndef ENGINE_H +#define ENGINE_H +#include +#include +#include +#include +#include +//Added by qt3to4: +#include +#include + +#include "adatabase.h" +#include "acfg.h" +#include "awindowslist.h" +#include +#include "adatafield.h" +#include "aobject.h" + + + +class aEngine; +class aWidget; +class QSInterpreter; + +/*! + * \~english + * Register Ananas-engine objects into script engine. + * \~russian + * \brief Метод aObjectsFactory::create регистрирует С++ классы Ананаса в интерпретаторе скриптов, + * делая доступным работу с объектами зарегистрированного класса из Ананас.Скрипта. + * Наследует QSObjectFactory. + * \~ + */ +class QT_WIDGET_PLUGIN_EXPORT aObjectsFactory : public QSObjectFactory +{ +public: + aEngine *engine; + aDatabase *db; + aObjectsFactory( aEngine *e ); + QObject *create( const QString &className, + const QVariantList &arguments, + QObject *context ); +}; + + +class aForm; + +/*! + * \~english + * Ananas-engine object. + * \~russian + * \brief Определяет программный интерфейс Runtime системы, который используется Ананас скриптом. + * Наследует QObject. + * + * Класс, реализующий обработку и выполнение скриптов, открытие экранных форм, + * предварительную обработку скрипта перед выполнением (для последующего использования русских управляющих инструкций), + * системные функции получения даты и времени, печати сообщений об ошибках и т.д + * \~ + */ +class QT_WIDGET_PLUGIN_EXPORT aEngine : public QObject +{ + Q_OBJECT +public: +/*! + * \~english + * database connection. + * \~russian + * Соединение с базой данных. + * \~ +*/ + aDatabase *db; +/*! + * \~english + * link to metadata. + * \~russian + * ссылка на метаданные. + * \~ +*/ + aCfg* md; +/*! + * \~english + * link to workspace. + * \~russian + * ссылка на рабочее пространство. + * \~ +*/ + QWidget* ws; +/*! + * \~english + * link to windowlist. + * \~russian + * ссылка на список окон. + * \~ +*/ + aWindowsList* wl; +/*! + * \~english + * link to script interpreter. + * \~russian + * ссылка на интерпретатор скрипта. + * \~ +*/ + QSInterpreter* code; +/*! + * \~english + * link to script project. + * \~russian + * ссылка на проект. + * \~ +*/ + QSProject project; +/*! + * \~english + * number to form + * \~russian + * номер для обеспечения уникальных имен при открытии форм. + * \~ +*/ + int next_obj_id; + + aEngine(); + virtual ~aEngine(); + virtual bool init( const QString &rcfile ); + virtual void done(); + void openEmbedCatalogueEditor(int oid, QWidget *parent=NULL, const bool toSelect=true); + + QString sourcePreprocessor( const QString &src ); + + void timerEvent(QTimerEvent *e); + int on_systemstart(); + int on_systemstop(); + aForm *openForm( int oid, int fid = 0 , int defaultfor = 1, + int mode = 0, ANANAS_UID id = 0, aWidget* caller = 0 ); + +public slots: + QString cfgname(); + QString Time(); + QString Date(); + void Exit(); + void Message(int n, const QString &msg ); + void StatusMessage( const QString &msg ); + void settimer(int sec, QString proc); + aForm * OpenForm(QString fname, int mode=0, aObject * selecter=0);//Q_ULLONG ido=0); + QVariant value( const QString &name ); + void setValue( const QString &name, QVariant value = QVariant::Invalid ); + + void on_MenuBar( int id ); + void execAction( aCfgItem &act, QObject *context = 0 ); + + aDataField *enterValue( const QString &FieldType, const QString &title = "" ); + +private slots: + void error ( const QString & message, QObject * context, + const QString & scriptName, int lineNumber ); + void on_event( const QString &data ); +signals: + void statusMessage( const QString &msg ); + void event( const QString &source, const QString &data ); + +private: + QString pr_timer; + QString mGlobal; + Q3Dict values; + +}; + +#endif // ENGINE_H diff --git a/src/plugins/field/addfdialog.cpp b/src/plugins/field/addfdialog.cpp new file mode 100644 index 0000000..c4dc979 --- /dev/null +++ b/src/plugins/field/addfdialog.cpp @@ -0,0 +1,126 @@ +#include "addfdialog.h" + +#include +#include "wdbfield.h" + +#include +/* + * Constructs a addfdialog as a child of 'parent', with the + * name 'name' and widget flags set to 'f'. + * + * The dialog will by default be modeless, unless you set 'modal' to + * true to construct a modal dialog. + */ +addfdialog::addfdialog(QWidget* parent, const char* name, bool modal, Qt::WindowFlags fl) + : QDialog(parent, name, modal, fl) +{ + setupUi(this); + + init(); +} + +/* + * Destroys the object and frees any allocated resources + */ +addfdialog::~addfdialog() +{ + destroy(); + // no need to delete child widgets, Qt does it all for us +} + +/* + * Sets the strings of the subwidgets using the current + * language. + */ +void addfdialog::languageChange() +{ + retranslateUi(this); +} + +/*! + * Sets current field name and field id for return with function getData() + */ + +void addfdialog::doOk() +{ + int idx; + idx = ListBox->currentItem(); + if(idx>=0) + { + id = idlist[idx]; + field = list[idx]; + } + else id="0"; + accept(); +} + + +void addfdialog::init() +{ + id="0"; + field=""; +} + + +void addfdialog::destroy() +{ + +} + + +/*! + * Function return field name (if param name == true) or field id otherwise + * \return field name or field id + */ +const QString addfdialog::getData(bool name) +{ + if(name) return field; + else return id; +} + +/*! + * Sets list of field name and list of field id. + * \param flst (in) - list of field name + * \param ilst (in) - list of field id + */ +void addfdialog::setData( QStringList displst, QStringList flst, QStringList ilds) +{ + list = flst; + ListBox->insertStringList(displst); + idlist = ilds; +} + + + + +void addfdialog::setData( QWidget *o, aCfg *md ) +{ + + wDBField *w = (wDBField *)o; + w->getFields(); + setData( w->defDisplayFields, w->defFields,w->defId); + ListBox->setCurrentItem(ListBox->findItem(w->getFieldName())); +} + + +void addfdialog::getData( QWidget *o ) +{ + QString s; + wDBField *w = (wDBField *)o; + Q3ValueList bindList = w->getBindList(); + s = getData(true); + if(s.isEmpty()) return; + w->setFieldName(s); + s = getData(false); + if(s=="0") return; + // if select binding field + if(bindList.find(s.toULongLong()) != bindList.end()) + { + cfg_message(0, tr("field already binding, please select another field.")); + return; + } + w->setId(s.toInt()); + w->setEditorType(); + //w->updateProp(); + +} diff --git a/src/plugins/field/addfdialog.h b/src/plugins/field/addfdialog.h new file mode 100644 index 0000000..2aeb81b --- /dev/null +++ b/src/plugins/field/addfdialog.h @@ -0,0 +1,36 @@ +#ifndef ADDFDIALOG_H +#define ADDFDIALOG_H + +#include "ui_addfdialog.h" + + +class addfdialog : public QDialog, public Ui::addfdialog +{ + Q_OBJECT + +public: + addfdialog(QWidget* parent = 0, const char* name = 0, bool modal = false, Qt::WindowFlags fl = 0); + ~addfdialog(); + + QStringList list,idlist; + + virtual void init(); + virtual void destroy(); + virtual const QString getData( bool name ); + +public slots: + virtual void doOk(); + virtual void setData( QStringList displst, QStringList flst, QStringList ilds ); + virtual void setData(QWidget *o, aCfg *md); + virtual void getData(QWidget *o); + +protected slots: + virtual void languageChange(); + +private: + QString field; + QString id; + +}; + +#endif // ADDFDIALOG_H diff --git a/src/plugins/field/addfdialog.ui b/src/plugins/field/addfdialog.ui new file mode 100644 index 0000000..bda881c --- /dev/null +++ b/src/plugins/field/addfdialog.ui @@ -0,0 +1,83 @@ + + + + + addfdialog + + + + 0 + 0 + 363 + 224 + + + + select field + + + + + + + + OK + + + + + + + Cancel + + + + + + + + 20 + 120 + + + + Expanding + + + Vertical + + + + + + + + + + + + qPixmapFromMimeSource + + wdbtable.h + + + + OkButton + clicked() + addfdialog + doOk() + + + CButton + clicked() + addfdialog + reject() + + + ListBox + doubleClicked(Q3ListBoxItem*) + addfdialog + doOk() + + + diff --git a/src/plugins/field/efield.cpp b/src/plugins/field/efield.cpp new file mode 100644 index 0000000..acf687f --- /dev/null +++ b/src/plugins/field/efield.cpp @@ -0,0 +1,168 @@ +#include "efield.h" + +#include +#include +#include + +#include "acfg.h" +#include + +/* + * Constructs a eField as a child of 'parent', with the + * name 'name' and widget flags set to 'f'. + * + * The dialog will by default be modeless, unless you set 'modal' to + * true to construct a modal dialog. + */ +eField::eField(QWidget* parent, const char* name, bool modal, Qt::WindowFlags fl) + : QDialog(parent, name, modal, fl) +{ + setupUi(this); + + init(); +} + +/* + * Destroys the object and frees any allocated resources + */ +eField::~eField() +{ + // no need to delete child widgets, Qt does it all for us +} + +/* + * Sets the strings of the subwidgets using the current + * language. + */ +void eField::languageChange() +{ + retranslateUi(this); +} + +void eField::init() +{ + + + +} + + + +void eField::setData( QWidget *o, aCfg *cfg ) +{ + md = cfg; + if(!o) + { + reject(); + return; + } + if ( o->className() != QString("wField") || !md ) { + reject(); + return; + } + wField *f = ( wField*) o; + QString ts = f->getFieldType(); +// printf(">>> fieldType = %s;\n", ts.ascii() ); + char t=' '; + int w=0, d=0, oid, idx=0; + unsigned int i; + +// eName->setText(f->getName()); + otypes.clear(); + eType->clear(); + + QStringList tlist = md->types(); + otypes.clear(); + eType->clear(); + for ( QStringList::Iterator it = tlist.begin(); it != tlist.end(); ++it ) { + otypes.append( (*it).section( "\t", 0, 0 ) ); + eType->insertItem( (*it).section("\t", 1, 1 ), idx++ ); + } + if ( !ts.isEmpty() ) { + sscanf( ts, "%c %d %d", &t, &w, &d ); + } else { + t = 'N'; + w = 10; + } + if ( t=='O' ) { + for( i = 0 ; i < otypes.count(); i++ ) { + if( otypes[i][0] == 'O' ) { + sscanf( (const char *)otypes[ i ], "O %d", &oid ); + if ( oid == w ) { + eType->setCurrentItem( i ); + break; + } + } + } + } else { + eWidth->setValue( w ); + eDec->setValue( d ); + if ( t == ' ' ) eType->setCurrentItem( 0 ); + if ( t == 'N' ) eType->setCurrentItem( 1 ); + if ( t == 'C' ) eType->setCurrentItem( 2 ); + if ( t == 'D' ) eType->setCurrentItem( 3 ); + if ( t == 'B' ) eType->setCurrentItem( 4 ); + } + typeSelect( eType->currentItem() ); +} + + +void eField::getData( QWidget *o ) +{ +// const QObject *o = sender(); + if ( !o ) return; + if ( o->className() != QString("wField") ) return; + wField *f = ( wField*) o; + wField::tEditorType type; + char ntype[40]=""; + int idx=eType->currentItem(); + + if (f) { + //f->setName(eName->text()); + sprintf(ntype, (const char *) otypes[idx], eWidth->value(), eDec->value()); + f->setFieldType(ntype); + if(otypes[idx][0]==' ') type = wField::Unknown; + if(otypes[idx][0]=='N') type = wField::Numberic; + if(otypes[idx][0]=='C') type = wField::String; + if(otypes[idx][0]=='D') type = wField::Date; + if(otypes[idx][0]=='B') type = wField::Boolean; + if(otypes[idx][0]=='O') + { + QString tmp = otypes[idx].section(' ',1,1); + long tid = atol(tmp); + aCfgItem item = md->find(tid); + if(!item.isNull()) + { + //gets object class + tmp = md->objClass(item); + if(tmp == md_catalogue) + type = wField::Catalogue; + if(tmp == md_document) + type = wField::Document; + } + } + f->setEditorType(type); + } +} + +void eField::typechanged(const QString &s ) +{ +} + +void eField::typeSelect( int idx ) +{ + bool w = false, d = false; + if ( otypes[ idx ][0] == 'N' ){ + w = true; + d = true; + + } else + if ( otypes[ idx ][0] == 'C' ){ + w = true; + + } + eWidth->setShown( w ); + tWidth->setShown( w ); + eDec->setShown( d ); + tDec->setShown( d ); +} diff --git a/src/plugins/field/efield.h b/src/plugins/field/efield.h new file mode 100644 index 0000000..e4cc313 --- /dev/null +++ b/src/plugins/field/efield.h @@ -0,0 +1,32 @@ +#ifndef EFIELD_H +#define EFIELD_H + +#include "ui_efield.h" + + +class eField : public QDialog, public Ui::eField +{ + Q_OBJECT + +public: + eField(QWidget* parent = 0, const char* name = 0, bool modal = false, Qt::WindowFlags fl = 0); + ~eField(); + + QStringList otypes; + +public slots: + virtual void init(); + virtual void setData( QWidget * o, aCfg * cfg ); + virtual void getData( QWidget * o ); + virtual void typechanged( const QString & s ); + virtual void typeSelect( int idx ); + +protected: + aCfg * md; + +protected slots: + virtual void languageChange(); + +}; + +#endif // EFIELD_H diff --git a/src/plugins/field/efield.ui b/src/plugins/field/efield.ui new file mode 100644 index 0000000..a08baa7 --- /dev/null +++ b/src/plugins/field/efield.ui @@ -0,0 +1,212 @@ + + + + + eField + + + + 0 + 0 + 313 + 186 + + + + Input field + + + + + + + + Positive + + + + + + + Required + + + + + + + + + + + + + 100 + 32767 + + + + Type + + + false + + + + + + + + + + + 100 + 32767 + + + + Name + + + false + + + + + + + + 31 + 16 + + + + Expanding + + + Vertical + + + + + + + + + OK + + + true + + + + + + + Cancel + + + + + + + + + + 91 + 31 + + + + Expanding + + + Horizontal + + + + + + + + 100 + 32767 + + + + Width + + + false + + + + + + + 254 + + + 1 + + + + + + + + 100 + 32767 + + + + Decimals + + + false + + + + + + + 9 + + + + + + + qPixmapFromMimeSource + + ananas.h + acfg.h + wfield.h + + + + pushButton1 + clicked() + eField + accept() + + + pushButton2 + clicked() + eField + reject() + + + eType + activated(QString) + eField + typechanged(QString) + + + eType + activated(int) + eField + typeSelect(int) + + + diff --git a/src/plugins/field/field.pri b/src/plugins/field/field.pri new file mode 100644 index 0000000..efef031 --- /dev/null +++ b/src/plugins/field/field.pri @@ -0,0 +1,22 @@ +HEADERS += \ + field/efield.h \ + field/addfdialog.h \ + field/wfield.h \ + field/wdateedit.h \ + field/wcatalogeditor.h \ + field/wfield_plugin.h \ + field/wfield_taskmenu.h + +SOURCES += \ + field/efield.cpp \ + field/addfdialog.cpp \ + field/wfield.cpp \ + field/wdateedit.cpp \ + field/wcatalogeditor.cpp \ + field/wfield_plugin.cpp \ + field/wfield_taskmenu.cpp + +FORMS += \ + field/efield.ui \ + field/addfdialog.ui + \ No newline at end of file diff --git a/src/plugins/field/wcatalogeditor.cpp b/src/plugins/field/wcatalogeditor.cpp new file mode 100644 index 0000000..6fa468b --- /dev/null +++ b/src/plugins/field/wcatalogeditor.cpp @@ -0,0 +1,411 @@ +/**************************************************************************** +** $Id: wcatalogeditor.cpp,v 1.2 2008/11/08 20:16:36 leader Exp $ +** +** Code file of the field plugin of Ananas +** Designer and Engine applications +** +** Created : 20031201 +** +** Copyright (C) 2003-2004 Leader InfoTech. All rights reserved. +** Copyright (C) 2003-2004 Grigory Panov, Yoshkar-Ola. +** +** This file is part of the Ananas Plugins of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.leaderit.ru/page=ananas or email sales@leaderit.ru +** See http://www.leaderit.ru/gpl/ for GPL licensing information. +** +** Contact org@leaderit.ru if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#include +#include +#include +#include +#include +#include +//Added by qt3to4: +#include +#include +#include "ananas.h" +#include "wcatalogeditor.h" +#include "wfield.h" +#include "wdbtable.h" +#include "catalogform.h" +#include "alog.h" +#include "../ananas/mainform.h" + + +/*! + * \en Creates catalog editor widget. \_en + * \ru Создает виджет для редактирования каталога. + * В принципе он не предусмотрен использоваться ни как иначе, кроме как часть + * объекта wField, т.е его родительский объект должен быть wField + * или его наследник для обеспечения корректной инициализации. + * При создании объекта runtime не предусмотрено, за исключением случая, + * когда виджет используется в составе wField в объекте wDBTable. + * \param parent - \en parent object. \_en \ru родительский объект. \_ru + * \param name - \en name \_en \ru имя \_ru + * \param catname \en not used \_en \ru не используется \_ru + */ +wCatalogEditor::wCatalogEditor( wField *parent, + const char *name, + const char *catname) : QWidget(parent, name) +{ + QWidget* w =0; + md = NULL; + QString str; + label = new QLabel(parent, name); + label->setFrameShape(Q3Frame::Box); + w =(QWidget*) parent->parent()->parent(); + str = parent->getFieldType(); + catId = atoi(str.remove(0,2));// gets catalog id. + if(w) + { + if(strcmp(w->className(),"wDBTable")==0) // wField is element wDBTable + { + initCat(((wDBTable*)w)->db); + } + } +} + +wCatalogEditor::wCatalogEditor(QWidget* parent,int cat) : QWidget() +{ + catId = cat; + label = 0; + ws = parent; +} + + +/*! + * \en Destructor catalog editor. \_en + */ +wCatalogEditor::~wCatalogEditor() +{ + delete label; + label = 0; +} + + + +/*! + * \en Initialisation catalog editor. \_en + * \ru Инициализация редактора каталога. + * Инициализирует внутренние объекты метаданных и базы банных. \_ru + */ +void +wCatalogEditor::initCat(aDatabase * adb) +{ + md = &adb->cfg; + db = adb; +} + + +/*! + * \en Handler signal click(). + * Creates and shows form for select catalog. \_en + * \ru Обработчик события нажатия кнопки, + * которая является второй составной частью виджета. + * Сигнал коннектится в объекте wField. + * Создает и отображет в рабочем пространстве енжина форму для + * редактирования каталога или выбора из каталога. + * Производит заполнение дерева групп и элементов группами и формирует + * данные для передачи в форму редактирования каталога. + * Создает и отображет в рабочем пространстве енжина эту форму.\_ru + */ +void +wCatalogEditor::select() +{ + openForm(true); +} +/*! + * \en Creates and shows form for edit catalog. \_en + * \ru Обработчик события нажатия кнопки, + * которая является второй составной частью виджета. + * редактирования каталога. + * Производит заполнение дерева групп и элементов группами и формирует + * данные для передачи в форму редактирования каталога. + * Создает и отображет в рабочем пространстве енжина эту форму.\_ru + */ +void +wCatalogEditor::edit() +{ + openForm(false); +} + +void +wCatalogEditor::openForm(const bool toSelect) +{ + + + aLog::print(aLog::Debug, tr("wCatalog Editor open form for select=%1 ").arg((int)toSelect)); + MainForm *mainform; + if(parent()) + { + mainform = (MainForm*) topLevelWidget(); + ws = mainform->ws; + } +// aWindowsList *wl = mainform->wl; + int objid = catId; +/* if ( wl->find( objid ) ) + { +// wl->remove(objid); + wl->get( objid )->setFocus(); + return; + } + else + { + CatalogForm* newform = new CatalogForm(ws,0, WDestructiveClose); + wl->insert( objid, newform ); + }*/ + CatalogForm* newform = new CatalogForm(ws,0, Qt::WDestructiveClose); + + connect( newform, SIGNAL(selected(qulonglong)), + this, SLOT(on_selected( qulonglong ))); + connect( newform, SIGNAL(destroyed()), + this, SLOT(on_destroyed_form())); + + aCatalogue *cat = new aCatalogue(md->find(catId),db); + int count=0; + bool est=true; + QMap map, map_el; + aCfgItem tmp, tmp_f,tmp_el,tmp_group, o; + Q3ListViewItem * item; + Q3ListViewItem * p_item; + qulonglong idGrForm=0, idElForm=0; + QStringList listPos, listPosGroup; + newform->ListHint->hide(); + QPixmap pixmap(newform->getGroupPixmap()); + QPixmap pixmap_mark_deleted(newform->getMarkDeletedPixmap()); + tmp = md->find(catId); + newform->setCaption(md->attr(tmp,mda_name)); + o = md->findChild(tmp, md_forms); // get obj forms + if(!o.isNull()) + { + count = md->count(o,md_form); + for(int i=0; ifindChild(o,md_form,i); + if(!tmp_f.isNull() + && atoi(md->attr(tmp_f,mda_type).ascii())==md_form_elem) + { + aLog::print(aLog::Debug, tr("wCatalog Editor found element forms")); + idElForm = md->id(tmp_f); +// continue; + } + if(!tmp_f.isNull() + && atoi(md->attr(tmp_f,mda_type).ascii())==md_form_group) + { + aLog::print(aLog::Debug, tr("wCatalog Editor found group forms")); + idGrForm = md->id(tmp_f); + } + } + } + else + { + aLog::print(aLog::Error, tr("wCatalog Editor meta object forms not found")); + } + tmp_el = md->findChild(tmp, md_element); + tmp_group = md->findChild(tmp,md_group); + tmp = md->findChild(tmp_el, md_field); + int count_fields = md->count(tmp_el,md_field); + listPosGroup = cat->getGroupUserFields(); + int i,level = 0; + cat->Select(); + while(est) // add group in tree on levels + { + est = false; + ++level; + cat->selectByLevel(level-1); + + if(!cat->FirstInGroupTable()) break; + do + { + if(cat->GroupSysValue("level").toInt()==level-1) //all groups, having this level + { + est = true; + QString displayString; + displayString= cat->GroupSysValue(listPosGroup[0]).toString(); + if(map.contains(cat->GroupSysValue("idp").toULongLong())) + { + p_item = map[(cat->GroupSysValue("idp").toULongLong())]; + item = new Q3ListViewItem(p_item); + } + else + { + item = new Q3ListViewItem(newform->ListView); + newform->ListView->insertItem(item); + } + item->setText(0, displayString); + if(cat->isGroupMarkDeleted()) + item->setPixmap(0,pixmap_mark_deleted); + else + item->setPixmap(0,pixmap); + + map.insert(cat->GroupSysValue("id").toULongLong(),item); + //printf("%lu\n",cat->GroupSysValue("id").toULongLong()); + + } + + + }while(cat->NextInGroupTable()); + + } + listPos = cat->getUserFields(); + checkUserFields(listPos); + int fid; + //sets column name + for(uint i=0; ifind(fid); + } + if(fid) + { + tmp = md->find(fid); + newform->ListView->addColumn(md->attr(tmp,mda_name)); + } + } + + listPos.clear(); + listPos = cat->getUserFields(); + checkUserFields(listPos); + //Q_ULLONG res = 0; + // cat deleted in function catalogform::destroy(); + + newform->setData( cat, + map, + listPos, + cat->getGroupUserFields(), + idElForm, + idGrForm, + toSelect); + + newform->setId(value().toULongLong()); + //-- + if (ws) + ((QWorkspace*)ws)->addWindow(newform); + newform->show(); + ((QWidget*)newform->parent())->move(0,0); +} +void +wCatalogEditor::checkUserFields( QStringList &lst) +{ + aCfgItem item = md->find(catId); + int fid; + if(item.isNull()) return; + item = md->findChild(item,md_element); + for(int i=0; i< md->count(item,md_field); i++) + { + aCfgItem mdi = md->findChild(item,md_field,i); + int ind = lst.findIndex(QString("uf%1").arg(md->attr(mdi,mda_id))); + if(ind!=-1) + { + //--lst.insert(lst.at(i),lst[ind]); + lst.insert(i,lst[ind]); + lst.remove(lst.at(ind+1)); + + } + else + { + ind = lst.findIndex(QString("text_uf%1").arg(md->attr(mdi,mda_id))); + if(ind!=-1) + { + //--lst.insert(lst.at(i),lst[ind]); + lst.insert(i,lst[ind]); + lst.remove(lst.at(ind+1)); + + } + } + } + +} + +void +wCatalogEditor::on_selected( qulonglong uid ) +{ + emit( selected(uid) ); +} + +void +wCatalogEditor::on_destroyed_form( ) +{ + emit( destroyed_form() ); +} + + +/*! + * \en Gets catalog editor value. \_en + * \ru Получение значения редактора каталога. + * Т.е. то, что было выбрано или утановлено функцией setValue(). + * Сейчас возвращает стринг с id, но может быть + * Для получения осмысленного значения используй функцию displayValue() \_ru + */ +QString +wCatalogEditor::value() const +{ + return vValue; +} + + +/*! + * \en Gets value for displaying. \_en + * \ru Получение осмысленного представления id. + * Строка является представлением уникального id для элемента + * или группы каталога. \_ru + * \param id_element (in) -\en unique id element or group \_en + * \ru уникальный идентификатор элемента или группы \_ru + */ +QString +wCatalogEditor::displayValue(qulonglong id_element) const +{ +const QString no_select = " "; + if(md) + { + /* aCfgItem tmp,field; + QString res; + tmp = md->find(catId); + tmp = md->findChild(tmp, md_element); + field = md->findChild(tmp,md_field); + aSQLTable* te = new aSQLTable(tmp,db); + te->select(QString("id=%1").arg(id_element)); + if(te->first()) + { + res = te->sysValue(QString("uf%1").arg(md->id(field))).toString(); + } + else res = no_select; + delete te;*/ + return QString("%1").arg(id_element); + } + else return no_select; +} + + +/*! + * \en Sets id for displaying. \_en + * \ru Установка id для показа. + * Хранится в стринге для совмесимости с wField. \_ru + */ +void +wCatalogEditor::setValue(QString newvalue) +{ + if(vValue==newvalue) return; + vValue = newvalue; + if(label) label->setText(displayValue(newvalue.toULongLong())); + emit valueChanged(value()); +} + diff --git a/src/plugins/field/wcatalogeditor.h b/src/plugins/field/wcatalogeditor.h new file mode 100644 index 0000000..a67c906 --- /dev/null +++ b/src/plugins/field/wcatalogeditor.h @@ -0,0 +1,93 @@ +/**************************************************************************** +** $Id: wcatalogeditor.h,v 1.1 2008/11/05 21:16:30 leader Exp $ +** +** Header file of the field plugin of Ananas +** Designer and Engine applications +** +** Created : 20031201 +** +** Copyright (C) 2003-2004 Leader InfoTech. All rights reserved. +** Copyright (C) 2003-2004 Grigory Panov, Yoshkar-Ola. +** +** This file is part of the Ananas Plugins of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.leaderit.ru/page=ananas or email sales@leaderit.ru +** See http://www.leaderit.ru/gpl/ for GPL licensing information. +** +** Contact org@leaderit.ru if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#ifndef WCATALOGEDITOR_H +#define WCATALOGEDITOR_H + +#include "ananasglobal.h" + +#include +#include +#include +#include +//#include +//#include +//#include +//#include +//#include +#include "wfield.h" +#include "adatabase.h" +#include "ananas.h" + +/*! + * \en + * \brief Ananas catalogue type field editor. + * \_en + * \ru + * \brief Класс предоставляет доступ к методам встроенного редактора справочников (каталогов) + * Наследует QWidget. + * \_ru + */ +class QT_WIDGET_PLUGIN_EXPORT wCatalogEditor : public QWidget +{ + Q_OBJECT + Q_PROPERTY( QString value READ value WRITE setValue) +public: + QLabel* label; + wCatalogEditor( wField* parent = 0, const char *name = 0, const char* catname=0); + wCatalogEditor( QWidget* w, int cat); + ~wCatalogEditor(); + QString value() const; + void setValue(QString newvalue); + void initCat(aDatabase *adb); + QString displayValue(qulonglong id_element) const; +private slots: + void on_selected( qulonglong ); + void on_destroyed_form(); + +protected slots: + void openForm(const bool toSelect); +public slots: + void checkUserFields( QStringList &lst); + void select(); + void edit(); + +signals: + void valueChanged(const QString &); + void selected( qulonglong ); + void destroyed_form(); +private: + QString vValue; + aCfg* md; + int catId; + QWidget *ws; + aDatabase* db; +}; +#endif diff --git a/src/plugins/field/wdateedit.cpp b/src/plugins/field/wdateedit.cpp new file mode 100644 index 0000000..419eb33 --- /dev/null +++ b/src/plugins/field/wdateedit.cpp @@ -0,0 +1,77 @@ +/**************************************************************************** +** $Id: wdateedit.cpp,v 1.1 2008/11/05 21:16:30 leader Exp $ +** +** Code file of the field plugin of Ananas +** Designer and Engine applications +** +** Created : 20031201 +** +** Copyright (C) 2003-2004 Grigory Panov, Yoshkar-Ola. +** +** This file is part of the Ananas Plugins of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.leaderit.ru/page=ananas or email sales@leaderit.ru +** See http://www.leaderit.ru/gpl/ for GPL licensing information. +** +** Contact org@leaderit.ru if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#include +//Added by qt3to4: +#include +#include "wdateedit.h" + + + +/*! + * \en Constructor. \_en + * \ru Конструктор. \_ru + */ +wDateEdit::wDateEdit(QWidget* parent, const char* name ):Q3DateEdit(parent,name) +{} + + +/*! + * \en Constructor with setting date. \_en + * \ru Конструктор с инициированием даты. \_ru + * \param date - \en date for set \_en \ru Дата для установки \_ru + */ +wDateEdit::wDateEdit(const QDate &date, + QWidget* parent, + const char* name) : Q3DateEdit(date,parent,name) +{} + + + +/*! + * \en Destructor \_en + */ +wDateEdit::~wDateEdit() +{ + //QDateEdit::~QDateEdit(); +} + + +/*! + * \en Focus out event handler. Emit signal lostFocus. \_en + * \ru Обработчик сигнала выхода из фокуса. Испускает сигнал lostFocus. \_ru + */ +void +wDateEdit::focusOutEvent ( QFocusEvent * e) +{ + emit(lostFocus()); + QWidget::focusOutEvent(e); +} + + diff --git a/src/plugins/field/wdateedit.h b/src/plugins/field/wdateedit.h new file mode 100644 index 0000000..b4b8570 --- /dev/null +++ b/src/plugins/field/wdateedit.h @@ -0,0 +1,78 @@ +/**************************************************************************** +** $Id: wdateedit.h,v 1.1 2008/11/05 21:16:30 leader Exp $ +** +** Header file of the field plugin of Ananas +** Designer and Engine applications +** +** Created : 20031201 +** +** Copyright (C) 2003-2004 Grigory Panov, Yoshkar-Ola. +** +** This file is part of the Ananas Plugins of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.leaderit.ru/page=ananas or email sales@leaderit.ru +** See http://www.leaderit.ru/gpl/ for GPL licensing information. +** +** Contact org@leaderit.ru if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#ifndef WDATEEDIT_H +#define WDATEEDIT_H + +#include +#include +//Added by qt3to4: +#include + +/*! + * \en Unknown field editor. \_en + * \ru + * \brief Плагин-виджет для отображения в экранной форме поля типа Unknown. + * Наследует QLabel. + * \_ru + */ +class wUnknownField : public QLabel +{ + Q_OBJECT +public: + wUnknownField( QWidget *parent = 0, const char *name = 0):QLabel(parent, name){}; + +}; + + +/*! + * \en DateEdit field editor. \_en + * \ru + * \brief Плагин -- виджет используется в экранных формах в качестве поля ввода/редактирования + * атрибута типа Дата бизнес объекта Ананаса. + * Наследует QDateEdit. + * + * \_ru + */ +class wDateEdit : public Q3DateEdit +{ + Q_OBJECT +public: + wDateEdit(QWidget* parent = 0, const char* name = 0); + wDateEdit(const QDate &date, + QWidget* parent = 0, + const char* name = 0 ); + ~wDateEdit(); +protected: + void focusOutEvent ( QFocusEvent * ); +signals: + void lostFocus(); +}; + +#endif diff --git a/src/plugins/field/wfield.cpp b/src/plugins/field/wfield.cpp new file mode 100644 index 0000000..1f18d09 --- /dev/null +++ b/src/plugins/field/wfield.cpp @@ -0,0 +1,720 @@ +/**************************************************************************** +** $Id: wfield.cpp,v 1.1 2008/11/05 21:16:30 leader Exp $ +** +** Code file of the field plugin of Ananas +** Designer and Engine applications +** +** Created : 20031201 +** +** Copyright (C) 2003-2004 Leader InfoTech. All rights reserved. +** Copyright (C) 2003-2004 Grigory Panov, Yoshkar-Ola. +** +** This file is part of the Ananas Plugins of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.leaderit.ru/page=ananas or email sales@leaderit.ru +** See http://www.leaderit.ru/gpl/ for GPL licensing information. +** +** Contact org@leaderit.ru if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +//Added by qt3to4: +#include +#include +#include + +//--#include "command.h" +//--#include "mainwindow.h" +//--#include "formwindow.h" + +#include "ananas.h" +#include "wfield.h" +#include "wdateedit.h" +#include "wcatalogeditor.h" +#include "efield.h" + + + +/*! + * \en Constructs object with parent=parent, name=name and flags=fl \_en + * \ru Создает объект с родителем parent, именем name и флагом fl. \_ru + */ +wField::wField( QWidget *parent, const char *name, Qt::WFlags fl ) + : aWidget( parent, name, fl ) +{ + loaded = 0; + md_oid = 0; + md_fid = 0; + setSizePolicy( QSizePolicy( QSizePolicy::Preferred, QSizePolicy::Fixed ) ); + setFocusPolicy(Qt::StrongFocus); + new Q3HBoxLayout( this, 0, 0 ); + lineEdit = new QLineEdit(this); + lineEdit->hide(); + dateEdit = new wDateEdit(this); + dateEdit->hide(); + objButton = new wCatButton("...",this); + objButton->hide(); + objLabel = new QLabel(this); + objLabel->setSizePolicy( QSizePolicy( QSizePolicy::Ignored, QSizePolicy::Preferred )); + objLabel->setFrameShape(Q3Frame::Box); + objLabel->setText("UnknownField"); + objLabel->show(); + checkBox = new wCheckBox(this); + checkBox->hide(); + vEditorType = Unknown; +} +/* +wField::wField( QWidget *parent, const char *name, WFlags fl, bool dbf ) + : aWidget( parent, name, fl ) +{ + setSizePolicy( QSizePolicy( QSizePolicy::Preferred, QSizePolicy::Fixed ) ); + //vValue = ""; + //vFieldType=""; + new QHBoxLayout( this, 0, 0 ); + loaded = 0; + fieldEditor = NULL; + fieldSelector = NULL; + cfgobj_name = NULL; + cfgobj_type = NULL; + vEditorType = Unknown; + setMode( Mode0 ); + if ( dbf ) widgetInit(); +} +*/ + + +/*! + * \en Destructor. \_en + */ +wField::~wField() +{ +} + + +/*! + * \en Sets widget visual type, depend of property fieldType. + * This property must be set above call this function. \_en + * \ru Устанавливает визуальный тип виджета в зависимости от свойства + * `fieldType'. Это свойсто должно быть установлено до вызова этой функции, + * иначе тип виджета будет установлен в Unknown. \_ru + */ +void +wField::widgetInit() +{ + QString str; + char s1[20]; + int n1=0, n2=0; + lineEdit->hide(); + disconnect( lineEdit, SIGNAL( textChanged( const QString & ) ), + this, SLOT( setValue( const QString & ) ) ); + disconnect( lineEdit, SIGNAL( lostFocus() ), this, SLOT( focusOutEvent()) ); + // lineEdit->disconnect(); + lineEdit->setReadOnly(false); + layout()->remove(lineEdit); + dateEdit->hide();// = new QDateEdit(this); + disconnect(dateEdit, SIGNAL( valueChanged ( const QDate&) ), + this, SLOT( setValue( const QDate & ) ) ); + disconnect(dateEdit, SIGNAL( lostFocus() ), + this, SLOT( focusOutEvent() ) ); + layout()->remove(dateEdit); + objLabel->hide();// = new QLabel(this); + objLabel->disconnect(); + layout()->remove(objLabel); + objButton->hide();// = new wCatButton("...",this); + disconnect( objButton, SIGNAL( clicked() ), + this, SLOT( fieldSelect() ) ); +// objButton->disconnect(); + layout()->remove(objButton); + checkBox->hide(); + disconnect( checkBox, SIGNAL( valueChanged ( const QString & ) ), + this, SLOT( setValue( const QString & ) ) ); + + disconnect( checkBox, SIGNAL( toggled (bool) ), checkBox, SLOT( on_toggled() ) ); +// checkBox->disconnect(); + layout()->remove(checkBox); + //TODO: need rewrite + if (!vFieldType.isEmpty()) sscanf((const char *)vFieldType,"%s %i %i", s1, &n1, &n2); + + switch (vEditorType) + { + case Numberic: + lineEdit->setText(vValue); + if(vFieldType.isEmpty()) + { + // set validator for numeric type + QString str = tr("^\\-{0,1}\\d{0,%1}\\.{1}\\d{0,%2}$").arg(3).arg(3); + QRegExp rexp( str ); + lineEdit->setValidator(new QRegExpValidator(rexp,lineEdit)); + } + else + { + if(n2==0) + { + // set default validator for integer type + QString str = tr("^\\-{0,1}\\d{0,%1}$").arg(n1); + QRegExp rexp( str ); + lineEdit->setValidator(new QRegExpValidator(rexp,lineEdit)); + } + else + { + // set default validator for float type + QString str = tr("^\\-{0,1}\\d{0,%1}\\.{1}\\d{0,%2}$").arg(n1).arg(n2); + QRegExp rexp( str ); + lineEdit->setValidator(new QRegExpValidator(rexp,lineEdit)); + } + } + connect( lineEdit, SIGNAL( textChanged( const QString & ) ), + this, SLOT( setValue( const QString & ) ) ); + connect( lineEdit, SIGNAL( lostFocus() ), this, SLOT( focusOutEvent()) ); + + setFocusProxy(lineEdit); + layout()->add( lineEdit ); + lineEdit->show(); + break; + + case String: + if(vFieldType.isEmpty()) + { + // set default validator for string + lineEdit->setMaxLength(20); + } + else + { + // set validator for string + lineEdit->setMaxLength(n1); + } + connect( lineEdit, SIGNAL( textChanged( const QString & ) ), + this, SLOT( setValue( const QString & ) ) ); + connect( lineEdit, SIGNAL( lostFocus() ), this, SLOT( focusOutEvent()) ); + + setFocusProxy(lineEdit); + layout()->add( lineEdit ); + lineEdit->show(); + break; + + case Date: + case DateTime: + // used object wDateTime, inherits QDateTime + dateEdit->setSeparator("."); + dateEdit->setOrder( Q3DateEdit::DMY ); + connect(dateEdit, SIGNAL( valueChanged ( const QDate&) ), + this, SLOT( setValue( const QDate & ) ) ); + connect(dateEdit, SIGNAL( lostFocus() ), + this, SLOT( focusOutEvent() ) ); + + setFocusProxy( dateEdit ); + layout()->add( dateEdit ); + dateEdit->show(); + break; + + case Catalogue: + md_oid = n1; + objLabel->setFrameShape( Q3Frame::Box ); + objLabel->setLineWidth( 1 ); + objLabel->setFocusPolicy(Qt::NoFocus); + objButton->setMaximumWidth(25); + objButton->setFocusPolicy(Qt::StrongFocus); + connect( objButton, SIGNAL( clicked() ), + this, SLOT( fieldSelect() ) ); + + setFocusProxy(objButton); + layout()->add( objLabel ); + layout()->add( objButton ); + objLabel->show(); + objButton->show(); + break; + + case Document: +//>>>>>>> 1.49.2.4 + // Field type = Document + md_oid = n1; + objLabel->setFrameStyle( Q3Frame::Panel | Q3Frame::Sunken ); + objLabel->setLineWidth( 1 ); + objLabel->setFocusPolicy(Qt::NoFocus); + objButton->setMaximumWidth(25); + objButton->setFocusPolicy(Qt::StrongFocus); + connect( objButton, SIGNAL( clicked() ), + this, SLOT( fieldSelect() ) ); + + setFocusProxy(objButton); + layout()->add( objLabel ); + layout()->add( objButton ); + objLabel->show(); + objButton->show(); + break; + + case Boolean: +// connect( checkBox, SIGNAL( lostFocus() ), this, SLOT( focusOutEvent()) ); + connect( checkBox, SIGNAL( valueChanged ( const QString & ) ), + this, SLOT( setValue( const QString & ) ) ); + + connect( checkBox, SIGNAL( toggled (bool) ), checkBox, SLOT( on_toggled() ) ); + setFocusProxy(checkBox); + layout()->add(checkBox); + checkBox->show(); + break; + + default: + objLabel->setText("UnknownField"); + objLabel->setFrameShape(Q3Frame::Box); + setFocusPolicy(Qt::NoFocus); + layout()->add( objLabel ); + objLabel->show(); + break; + } + setValue(vValue); +} + + + +/*! + * \en Sets property fieldType. \_en + * \ru Устанавливает значение свойства `fieldType'.\_ru + */ +void +wField::setFieldType( QString n ) +{ + vFieldType=n; + if (!loaded) + { + loaded = true; + } + //widgetInit(); +} + + +/*! + * \en Sets property editorType. \_en + * \ru Устанавливает значение свойства `editorType'.\_ru + */ +void +wField::setEditorType( tEditorType n ) +{ + vEditorType=n; + widgetInit(); +} + + + +//<<<<<<< wfield.cpp + +/* +void +wField::load() +{ +} + +*/ + +/*! + * \en Creates property editor dialog window. \_en + * \ru Создает окно диалога редактора свойств.\_ru + * \param parent - \en parent \_en \ru родитель \_ru + */ +QDialog* +wField::createEditor( QWidget *parent ) +{ + return new eField( parent ); +} + + +/*! + * \en Sets value type DateTime. \_en + * \ru Устанавливает значения типа DateTime. + * Так как в базе хранится тип DateTime, значение дополняется + * нулевым временем для корректной конвертации и хранении в базе. + * Формат даты в базе данных должен быть ISO. \_ru + * \param newDate (in) - \en date for set \_en \ru Дата для установки \_ru + */ +void +wField::setValue(const QDate& newDate) +{ +//CHECK_POINT + vValue = newDate.toString(Qt::ISODate); + vValue+="T00:00:00"; //for correct converting to date-time + emit valueChanged(vValue); + emit valueChanged(QVariant(vValue)); +} + + + +/*! + * \en Sets value. \_en + * \ru Устанавливает значение виджета. \_ru + * \param newvalue (in) - \en value for set \_en \ru значение для установки \_ru + */ +void +wField::setValue(const QString &newvalue) +{ + int pos; + QString str; + QDateTime dt; +//<<<<<<< wfield.cpp +// if (!fieldEditor) return; +// emit valueChanged(newvalue); +// emit valueChanged(QVariant(newvalue)); +///======= +//>>>>>>> 1.49.2.4 + switch (vEditorType) + { + case Unknown: + break; + case Numberic: + case String: + vValue = newvalue; + pos = lineEdit->cursorPosition(); + lineEdit->setText(vValue); + lineEdit->setCursorPosition(pos); + break; + case Date: + case DateTime: + // conventering date-time to date, and if new value is NULL set up current locale date. + // date must be stored in server in format ISO + str = newvalue; + if(newvalue.isEmpty()) + { + str= QDateTime::currentDateTime(Qt::LocalTime).toString(Qt::ISODate); + } + dt = QDateTime::fromString(str,Qt::ISODate); + vValue = dt.toString(Qt::ISODate); + dateEdit->setDate(dt.date()); + break; + case Catalogue: + case Document: + vValue = newvalue; + objLabel->setText( ananas_objectstr( db, vValue.toULongLong(), md_oid ) ); + break; + case Boolean: + vValue = newvalue; + if(newvalue == "1") + { + checkBox->setChecked(true); + } + else + { + checkBox->setChecked(false); + } + break; + //emit valueChanged(QVariant(vValue)); + + } + emit valueChanged(vValue); + emit valueChanged(QVariant(vValue)); +} + + + +/*! + * \en Gets value. \_en + * \ru Возвращает значение виджета. \_ru + * \return \en value \_en \ru значение виджета \_ru + */ +QString +wField::value() const +{ + QString str = vValue; + return str; //str.setUnicode(vValue.unicode(),vValue.length()); +} + + + +/*! + * \en Gets text value. \_en + * \ru Возвращает текстовое значение виджета. \_ru + * \return \en value \_en \ru значение виджета \_ru + */ +QString +wField::text() const +{ + QString str; + switch (vEditorType) + { + case Date: + case DateTime: + str = dateEdit->date().toString(Qt::ISODate); + break; + case String: + case Numberic: + str = lineEdit->text(); + break; + case Catalogue: + case Document: + str = objLabel->text(); + break; + case Boolean: + str = checkBox->isChecked()?"1":"0"; + break; + default: + str = ""; + break; + } + return str; //str.setUnicode(vValue.unicode(),vValue.length()); +} + +/*! + * \en Calls handler onClick event for Catalogue or Document object. \_en + * \ru Вызывает обработчик события onClick для объектов Каталог или Документ. \_ru + */ +void +wField::fieldSelect() +{ + aForm * f = 0; +// if (!fieldEditor) return; + switch (vEditorType) + { + case Catalogue: + //printf("select catalogue\n"); + if ( engine ) + { + int fid = md->getDefaultFormId( md->find( md_oid ), md_action_view); + if ( !fid ) + { + engine->openEmbedCatalogueEditor(md_oid,this,true); + return; + } + f = engine->openForm( md_oid, 0, md_action_view, 0, false ); + if ( f ) + { + connect(f, SIGNAL(selected( qulonglong )), this, SLOT(on_selected( qulonglong ))); + f->closeAfterSelect = true; + } + } + else printf("No Engine\n"); + break; + case Document: + if( engine ) + { + aCfgItem journ = md->findJournal(1, md->find( md_oid )); + if( journ.isNull() ) + { + printf("special journal not found, find system journal\n"); + journ = md->findJournal(0, md->find( md_oid )); + } + else + { + printf("found special journal %s with class %s\n", (const char*) md->attr(journ,mda_name).local8Bit(),md->objClass(journ).ascii()); + } + f = engine->openForm( md->id(journ), 0, md_action_view, 0, false ); + if( f ) + { + connect(f, SIGNAL(selected( qulonglong )), this, SLOT(on_selected( qulonglong ))); + f->closeAfterSelect = true; + } + + } + else printf("No engine\n"); +// printf("select document!\n"); + break; + default: + break; + } +} + + + + +/*! + * \en Handler signal lostFocus. \_en + * \ru Обработчик сигнала lostFocus. \ru + */ +void +wField::focusInEvent() +{ + switch (vEditorType) { + case Catalogue: + objLabel->setLineWidth( 2 ); + break; + case Document: + break; + default: + break; + } +//emit(lostFocus()); +} + + +/*! + * \en Handler signal lostFocus. \_en + * \ru Обработчик сигнала lostFocus. \ru + */ +void +wField::focusOutEvent() +{ + switch (vEditorType) { + case Catalogue: + objLabel->setLineWidth( 1 ); + break; + case Document: + break; + default: + break; + } +//emit(lostFocus()); +} + + +void +wField::on_selected( qulonglong uid ) +{ + setValue( QString::number( uid ) ); + setFocus(); +} + +void +wField::selectAll() +{ + switch (vEditorType) { + case Numberic: + case String: +// ((QLineEdit *) fieldEditor)->home( false ); + lineEdit->selectAll(); + break; + default: + break; + } +} + +void +wField::SetReadOnly(bool fl) +{ + switch (vEditorType) { + case Numberic: + case String: + lineEdit->setReadOnly(fl); + break; + case Date: + case DateTime: + dateEdit->setDisabled(fl); + break; + case Catalogue: + objButton->setDisabled( fl ); + break; + case Document: + objButton->setDisabled( fl ); + break; + case Boolean: + checkBox->setDisabled( fl ); + break; + default: + break; + } + +} + +/*<<<<<<< wfield.cpp +void +wField::SetReadOnly(bool fl) +{ + switch (vEditorType) { + case Numberic: + case String: +// ((QLineEdit *) fieldEditor)->home( false ); + ((QLineEdit *) fieldEditor)->setReadOnly(fl); + break; + case Date: + ((QDateEdit*)fieldEditor)->setDisabled(fl); + break; + case DateTime: + ((QDateTimeEdit*)fieldEditor)->setDisabled(fl); + break; + case Catalogue: +// ((QLabel *) fieldEditor)->setFrameShape( QFrame::NoFrame ); + ((wCatButton *) fieldSelector)->setDisabled( fl ); + break; + case Document: + break; + default: + break; + } + +} + +======= + +>>>>>>> 1.49.2.4 +*/ +/*! + *\~english + * Proces value changed. + * Proces value changed in fields diferent types. + *\~russian + * Обрабатывает изменение значения. + * Обрабатывает изменение значения в поле, вне зависимости от типа поля. + *\~ + */ + +wCatButton::wCatButton(const char * caption, QWidget *parent):QPushButton(caption,parent) +{ +} + +wCatButton::~wCatButton() +{ +} + +void +wCatButton::keyPressEvent ( QKeyEvent * e ) +{ + switch(e->key()) + { + case Qt::Key_Left: + case Qt::Key_Up: + case Qt::Key_Right: + case Qt::Key_Down: + e->accept(); + break; + case Qt::Key_Space: + e->accept(); + emit( clicked() ); + break; + case Qt::Key_Tab: +// printf("press tab\n"); + e->accept(); +//<<<<<<< wfield.cpp + //new QKeyEvent( QEvent::KeyPress, Qt::Key_Return, 10, 0); + //new QKeyEvent( QEvent::KeyRelease, Qt::Key_Return, 10, 0); +//======= +//>>>>>>> 1.49.2.4 + break; + default: + e->ignore(); + break; + + } +} + +wCheckBox::wCheckBox(QWidget * parent, const char * name):QCheckBox(parent,name) +{ +} + +wCheckBox::~wCheckBox() +{ +} + +void +wCheckBox::on_toggled() +{ +// printf("wCheckBox state is %d\n",this->state()); + if(this->isChecked()) emit(valueChanged("1")); + else emit(valueChanged("0")); +} diff --git a/src/plugins/field/wfield.h b/src/plugins/field/wfield.h new file mode 100644 index 0000000..3f8cc87 --- /dev/null +++ b/src/plugins/field/wfield.h @@ -0,0 +1,149 @@ +/**************************************************************************** +** $Id: wfield.h,v 1.1 2008/11/05 21:16:30 leader Exp $ +** +** Header file of the field plugin of Ananas +** Designer and Engine applications +** +** Created : 20031201 +** +** Copyright (C) 2003-2004 Leader InfoTech. All rights reserved. +** Copyright (C) 2003-2004 Grigory Panov, Yoshkar-Ola. +** +** This file is part of the Ananas Plugins of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.leaderit.ru/page=ananas or email sales@leaderit.ru +** See http://www.leaderit.ru/gpl/ for GPL licensing information. +** +** Contact org@leaderit.ru if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#ifndef QAFIELD_H +#define QAFIELD_H + +#include +#include +#include +#include +#include +#include +#include "qlineedit.h" +//Added by qt3to4: +#include +#include "wdateedit.h" +#include "adatabase.h" +#include "ananas.h" + +class wCatButton; +class wCheckBox; + +/*! + * \en + * \brief Ananas Field widget. + * \_en + * \ru + * \brief Плагин -- виджет предназначенный для редактирования значений любых типов, определенных в бизнес схеме. + * Наследует aWidget. + * + * В отличие от wDBField класс wField не биндится к атрибутам persistent бизнес объектов. То есть время жизни + * хранимых в нем значений равно времени жизни родительской экранной формы. Прикладной программист сам должен + * решить вопрос обработки и хранения значений задаваемых пользователем. + * \_ru + */ +#include + +//class QT_WIDGET_PLUGIN_EXPORT wField : public aWidget +class QDESIGNER_WIDGET_EXPORT wField : public aWidget +{ + Q_OBJECT + + Q_PROPERTY( QString value READ value WRITE setValue) + Q_PROPERTY( QString FieldType READ getFieldType WRITE setFieldType ) + Q_PROPERTY( tEditorType EditorType READ getEditorType WRITE setEditorType ) + Q_ENUMS(tEditorType) + Q_ENUMS(FieldMode) +public: + enum tEditorType { Unknown, Numberic, String, Date, DateTime, Boolean, Catalogue=101, Document}; + + wField( QWidget *parent, const char *name, Qt::WFlags fl = 0 ); +// wField( QWidget *parent, const char *name, WFlags fl, bool dbf = TRUE ); + virtual ~wField(); + + virtual QDialog* createEditor( QWidget *parent ); + +signals: + void valueChanged( const QString & ); + void valueChanged( const QVariant & ); + void lostFocus(); + +public slots: + bool getOpt() const { return false; }; + void setOpt( bool fn ) { if(fn) widgetEditor(); }; + virtual QString value() const; + QString text() const; + virtual void setValue( const QString &fn ); + void setValue( const QDate& d); + virtual QString textValue() {return text();}; + void setFieldType( QString n ); + QString getFieldType() const {return vFieldType;}; + void setEditorType( tEditorType n ); + tEditorType getEditorType() const { return vEditorType; }; + void fieldSelect(); +// void propertyUpdate(QString propName); + virtual void focusInEvent(); + virtual void focusOutEvent(); + void selectAll(); + virtual void SetReadOnly(bool); + +private slots: + void on_selected( qulonglong uid ); + +protected: + QLineEdit *lineEdit; + wDateEdit *dateEdit; + QLabel *objLabel; + wCatButton *objButton; + wCheckBox *checkBox; + tEditorType vEditorType; + QString vFieldType; + QString vValue; +// virtual void updateProp(); + void widgetInit(); +private: + int loaded; + int md_oid, md_fid; +}; + +class wCatButton: public QPushButton +{ + Q_OBJECT + public: + wCatButton(const char * caption, QWidget *parent); + virtual ~wCatButton(); + protected: + void keyPressEvent ( QKeyEvent * e ); +}; +class wCheckBox: public QCheckBox +{ + Q_OBJECT + public: + wCheckBox(QWidget *parent, const char * name =0); + virtual ~wCheckBox(); + + public slots: + void on_toggled(); + signals: + void valueChanged(const QString &); +}; + +#endif diff --git a/src/plugins/field/wfield_plugin.cpp b/src/plugins/field/wfield_plugin.cpp new file mode 100644 index 0000000..4114396 --- /dev/null +++ b/src/plugins/field/wfield_plugin.cpp @@ -0,0 +1,101 @@ +/**************************************************************************** +** +** Code file +** +** Copyright (C) 2006 Dmitriy Pavlyuk +** +** This file is part of the Ananas Plugins of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +**********************************************************************/ + +#include "wfield_plugin.h" + +#include +#include +#include + +#include "wfield_taskmenu.h" +#include "wfield.h" + + +wFieldPlugin::wFieldPlugin(QObject *parent) + : QObject(parent), m_initialized(false) +{ + m_initialized = false; +} + +bool wFieldPlugin::isContainer() const +{ + return false; +} + +bool wFieldPlugin::isInitialized() const +{ + return m_initialized; +} + +void wFieldPlugin::initialize(QDesignerFormEditorInterface *core) +{ + if (m_initialized) + return; + Q_UNUSED(core); + + QExtensionManager *manager = core->extensionManager(); + Q_ASSERT(manager != 0); + manager->registerExtensions(new wFieldTaskMenuFactory(manager), + Q_TYPEID(QDesignerTaskMenuExtension)); + + m_initialized = true; +} + +QWidget *wFieldPlugin::createWidget(QWidget *parent) +{ + wField *w = new wField(parent, 0); + return w; +} + +QString wFieldPlugin::name() const +{ + return QLatin1String("wField"); +} + +QString wFieldPlugin::group() const +{ + return QLatin1String("Ananas"); +} + +QString wFieldPlugin::toolTip() const +{ + return QString("Ananas for QT Field Edit Widget"); +} + +QString wFieldPlugin::whatsThis() const +{ + return QString("Entry to modify field value of Ananas's object"); +} + +QString wFieldPlugin::includeFile() const +{ + return QLatin1String("wfield.h"); +} + +QIcon wFieldPlugin::icon() const +{ +// return QIcon(); + return QIcon( ":/images/wfield.png" ); +} + +QString wFieldPlugin::domXml() const +{ + return "\n\n"; +} + diff --git a/src/plugins/field/wfield_plugin.h b/src/plugins/field/wfield_plugin.h new file mode 100644 index 0000000..ddb61a0 --- /dev/null +++ b/src/plugins/field/wfield_plugin.h @@ -0,0 +1,53 @@ +/**************************************************************************** +** +** Header file +** +** Copyright (C) 2006 Dmitriy Pavlyuk +** +** This file is part of the Ananas Plugins of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +**********************************************************************/ + +#ifndef WFIELD_PLUGIN_H +#define WFIELD_PLUGIN_H + +#include + +#include "qwidgetplugin.h" + + +class QT_WIDGET_PLUGIN_EXPORT wFieldPlugin : public QObject, public QDesignerCustomWidgetInterface +{ + Q_OBJECT + Q_INTERFACES(QDesignerCustomWidgetInterface) + +public: + wFieldPlugin(QObject *parent=0); + + bool isContainer() const; + bool isInitialized() const; + void initialize(QDesignerFormEditorInterface *core); + QWidget *createWidget(QWidget *parent); + + QString name() const; + QString group() const; + QString toolTip() const; + QString whatsThis() const; + QString includeFile() const; + QIcon icon() const; + QString domXml() const; + +private: + bool m_initialized; +}; + +#endif // WFIELD_PLUGIN_H diff --git a/src/plugins/field/wfield_taskmenu.cpp b/src/plugins/field/wfield_taskmenu.cpp new file mode 100644 index 0000000..f526022 --- /dev/null +++ b/src/plugins/field/wfield_taskmenu.cpp @@ -0,0 +1,74 @@ +/**************************************************************************** +** +** Copyright (C) 2006 Dmitriy Pavlyuk All rights reserved. +** +** This file is part of the widgets plugin of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +****************************************************************************/ + +#include + +#include + +#include "wfield_taskmenu.h" +#include "wfield.h" +#include "efield.h" + + +wFieldTaskMenu::wFieldTaskMenu(wField *widget, QObject *parent) + : QObject(parent) +{ + m_widget = widget; + + m_editAction = new QAction(tr("Edit ..."), this); + connect(m_editAction, SIGNAL(triggered()), this, SLOT(edit())); +} + +void wFieldTaskMenu::edit() +{ + /*eField e; + + e.setData(m_widget); + if (e.exec() == QDialog::Accepted) + { + e.getData(m_widget); + }*/ + m_widget->widgetEditor(); +} + +QAction *wFieldTaskMenu::preferredEditAction() const +{ + return m_editAction; +} + +QList wFieldTaskMenu::taskActions() const +{ + QList list; + list.append(m_editAction); + return list; +} + +wFieldTaskMenuFactory::wFieldTaskMenuFactory(QExtensionManager *parent) + : QExtensionFactory(parent) +{ +} + +QObject *wFieldTaskMenuFactory::createExtension(QObject *object, const QString &iid, QObject *parent) const +{ + if (iid != Q_TYPEID(QDesignerTaskMenuExtension)) + return 0; + + if (wField *ob = qobject_cast(object)) + return new wFieldTaskMenu(ob, parent); + + return 0; +} diff --git a/src/plugins/field/wfield_taskmenu.h b/src/plugins/field/wfield_taskmenu.h new file mode 100644 index 0000000..7ce4e45 --- /dev/null +++ b/src/plugins/field/wfield_taskmenu.h @@ -0,0 +1,57 @@ +/**************************************************************************** +** +** Copyright (C) 2006 Dmitriy Pavlyuk All rights reserved. +** +** This file is part of the widgets plugin of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +****************************************************************************/ + +#ifndef WFIELD_TASKMENU_H +#define WFIELD_TASKMENU_H + +#include +#include + + +class QExtensionManager; +class QAction; +class wField; + +class wFieldTaskMenu: public QObject, public QDesignerTaskMenuExtension +{ + Q_OBJECT + Q_INTERFACES(QDesignerTaskMenuExtension) +public: + wFieldTaskMenu(wField *widget, QObject *parent); + + QAction *preferredEditAction() const; + QList taskActions() const; + +private slots: + void edit(); + +private: + QAction *m_editAction; + wField *m_widget; +}; + +class wFieldTaskMenuFactory: public QExtensionFactory +{ + Q_OBJECT +public: + wFieldTaskMenuFactory(QExtensionManager *parent = 0); + +protected: + QObject *createExtension(QObject *object, const QString &iid, QObject *parent) const; +}; + +#endif // WFIELD_TASKMENU_H diff --git a/src/plugins/grouptree/grouptree.pri b/src/plugins/grouptree/grouptree.pri new file mode 100644 index 0000000..dde3799 --- /dev/null +++ b/src/plugins/grouptree/grouptree.pri @@ -0,0 +1,7 @@ +HEADERS += \ + grouptree/wgrouptree.h \ + grouptree/wgrouptree_plugin.h + +SOURCES += \ + grouptree/wgrouptree.cpp \ + grouptree/wgrouptree_plugin.cpp diff --git a/src/plugins/grouptree/wgrouptree.cpp b/src/plugins/grouptree/wgrouptree.cpp new file mode 100644 index 0000000..637c1f2 --- /dev/null +++ b/src/plugins/grouptree/wgrouptree.cpp @@ -0,0 +1,416 @@ +/**************************************************************************** +** $Id: wgrouptree.cpp,v 1.1 2008/11/05 21:16:30 leader Exp $ +** +** Header file of the document plugin of Ananas +** Designer and Engine applications +** +** Created : 20031201 +** +** Copyright (C) 2003-2004 Leader InfoTech. All rights reserved. +** +** This file is part of the Ananas Plugins of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.leaderit.ru/page=ananas or email sales@leaderit.ru +** See http://www.leaderit.ru/gpl/ for GPL licensing information. +** +** Contact org@leaderit.ru if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#include +#include +#include +//Added by qt3to4: +#include +#include +#include +#include "wgrouptree.h" +#include "awidget.h" + +wGroupTreeItem::wGroupTreeItem( Q3ListView *parent, const QString &name ) + : Q3ListViewItem( parent, name ) +{ + level = -1; + parent = 0; + id = 0; +} + + +wGroupTreeItem::wGroupTreeItem( wGroupTreeItem *parent, wGroupTreeItem *after, const QString &name, int newlevel, ANANAS_UID newid ) + : Q3ListViewItem( parent, after, name ) +{ + level = newlevel; + id = newid; +} + + +wGroupTreeItem::wGroupTreeItem( wGroupTreeItem *parent, wGroupTreeItem *after, aCatGroup *g ) + : Q3ListViewItem( parent, after ) +{ + level = g->Value( "Level" ).toInt(); + id = g->getUid(); +// setText( 0, g->Value("Name").toString()+" "+QString::number( level )+" ("+QString::number( id )+")" ); + setText( 0, g->displayString() ); +} + + +wGroupTreeItem::~wGroupTreeItem() +{ +} + + + +wGroupTreeItem * +wGroupTreeItem::parentItem() +{ + return ( wGroupTreeItem *) parent(); +} + + +wGroupTree::wGroupTree( QWidget *parent, Qt::WFlags fl ) + : aWidget( parent, "wGroupTree", fl ) +{ + tree = new Q3ListView( this ); + tree->addColumn( "" ); + tree->header()->hide(); + tree->setSorting( 0 ); + tree->setSelectionMode( Q3ListView::Single ); + root = new wGroupTreeItem( tree, "ROOT" ); + root->setOpen( true ); + root->setPixmap(0, rcIcon("wcatalogue.png")); + + Q3GridLayout *l = new Q3GridLayout( this ); + l->addWidget( tree, 0, 0 ); + connect(tree, SIGNAL(selectionChanged(Q3ListViewItem*)), + this, SLOT( on_selectionChanged(Q3ListViewItem*))); +} + + +wGroupTree::~wGroupTree() +{ +} + + +void +wGroupTree::initObject( aDatabase *adb ) +{ + aWidget::initObject( adb ); + findGroupTree(); + //connectSlots(); +} + + +QDialog* +wGroupTree::createEditor( QWidget * )//parent ) +{ + return 0; //new eCatalogue( parent ); +} + + + +/*! + * Create aDocument database object. + */ +aObject * +wGroupTree::createDBObject( aCfgItem obj, aDatabase *adb ) +{ + return new aCatGroup( obj, adb ); +} + + +void +wGroupTree::buildGroupTree( aCfgItem obj, aCatGroup * cg1, wGroupTreeItem * wG ) +{ + aCatGroup cg2 (obj, db); + QString t; + int err = 0; + wGroupTreeItem *item; + CHECK_POINT + + err = cg2.SelectChild( cg1 ); + if ( !err ) + { +// CHECK_POINT +// QListViewItem * parent1 = new QListViewItem ( wG ); +// wG = new wGroupTreeItem ( tree, parent1 ); + do + { +// CHECK_POINT + t = cg2.Value("Name").toString(); +// CHECK_POINT + item = new wGroupTreeItem ( wG, 0, &cg2 ); //cg2.Value("Level").toInt(), cg2.getUid() ); + item->setPixmap( 0, rcIcon( "t_cat_g.png" )); +// buildGroupTree( obj, &cg2, wG ); +// CHECK_POINT + buildGroupTree( obj, &cg2, item ); +// CHECK_POINT + } + while ( cg2.Next() ); + } else { +// CHECK_POINT + printf("table %s err = %d\n", ( const char *)cg2.table()->name(), err); + } +} + + + +void +wGroupTree::findGroupTree() +{ + int oid = 0; + aCfgItem tab, cat; + if ( !db || !md ) return; + CHECK_POINT + aWidget *pc = parentContainer( this ); + if ( !pc ) return; + CHECK_POINT + printf("inserted in %s\n", pc->className()); + if ( pc->className() == QString("wCatalogue") ) { + cat = md->find( pc->getId() ); // md->find(mdc_metadata), md_catalogues, 0 ), md_catalogue, 0 ); + root->setText( 0, md->attr( cat, mda_name ) ); +// CHECK_POINT +// wGroupTreeItem *wG = new wGroupTreeItem ( tree, root, "root" ); +// aCatGroup cg ( cat, db ); + +// CHECK_POINT + buildGroupTree( cat, 0, root ); + CHECK_POINT + } +} + + +/*! + *\~english + * + *\~russian + * ������ ������������� �����. + *\~ + */ +void +wGroupTree::keyPressEvent ( QKeyEvent *e ) +{ + ANANAS_UID id = 0; + wGroupTreeItem * item = ( wGroupTreeItem * ) tree->currentItem(); + printf("key=%04x\n",e->key()); + switch ( e->key() ){ + case Qt::Key_Return: + id = item->id; + if ( e->state() == Qt::ShiftModifier ) { + printf("Shift+Return pressed %Li\n", id); + if ( id ) EditGroup(); + } else { + printf("Return pressed %Li\n", id ); + emit( selected( id ) ); + } + e->accept(); + break; + case Qt::Key_Escape: + break; + case Qt::Key_Delete: + id = item->id; + if ( id ) DeleteGroup(); + break; + case Qt::Key_Insert: + NewGroup(); + item = ( wGroupTreeItem * ) tree->currentItem(); + id = item->id; + if ( id ) EditGroup(); + break; + + default: + e->ignore(); + break; + } + aWidget::keyPressEvent( e ); +} + + + +void +wGroupTree::NewGroup() +{ + wGroupTreeItem *item, *cur; + QString t = "Element"; + int level; + + cur = ( wGroupTreeItem *) tree->currentItem(); + if ( !cur ) cur = root; + level = cur->level + 1; + ( ( aCatGroup *) dbobj )->New(); + dbobj->SetValue("Name", t); + dbobj->setSysValue("level", level ); + dbobj->setSysValue("idp", cur->id ); + dbobj->Update(); + item = new wGroupTreeItem ( cur, 0, ( aCatGroup *) dbobj ); //level, dbobj->getUid() ); + item->id = dbobj->getUid(); + cur->setOpen( true ); + tree->setCurrentItem( item ); + +} + + +void +wGroupTree::DeleteGroup() +{ +CHECK_POINT + aCatGroup g( *getMDObject(), db); + wGroupTreeItem * item = ( wGroupTreeItem * ) tree->currentItem(); + if(item!=root) + { + g.select( item->id ); + g.Delete(); + item->id=0; + item->setText(0,"X"); + } +} + + +void +wGroupTree::EditGroup() +{ + ANANAS_UID id = 0; + wGroupTreeItem * item = ( wGroupTreeItem * ) tree->currentItem(); + if(item!=root) + { + aForm * f = 0; + if ( item ) id = item->id; +CHECK_POINT + if ( id ) { + if ( engine ) { + f = engine->openForm( parentContainer( this )->getId(), 0, md_action_edit, md_form_group, id, this ); + if ( f ) { + f->SelectGroup(id); + connect(f, SIGNAL( update( ANANAS_UID )), this, SLOT(updateItem( ANANAS_UID ))); +// connect(f, SIGNAL(selected( Q_ULLONG )), this, SLOT(on_selected( Q_ULLONG ))); +// f->closeAfterSelect = true; + } + } else printf("No Engine\n"); + + } + } +} + + +//void +//wGroupTree::UpdateItem( aCatGroup *g ) +//{ +//} + + +/*! + * Show appropriated group after catalogue item selected. + */ +void +wGroupTree::on_selected( ANANAS_UID element ) +{ + +} + + +/*! + * Update item after edit. + */ +void +wGroupTree::updateItem( ANANAS_UID element ) +{ + wGroupTreeItem *i = 0; + aCatGroup g( *getMDObject(), db); + + printf("Need update text %Li\n", element); + i = findItem( element ); + if ( i ) { + g.select( element ); + printf("founded text %Li %s\n", element, (const char *) i->text(0)); + i->setText( 0, g.displayString() ); + + } +} + + +wGroupTreeItem * +wGroupTree::findItem( ANANAS_UID id ) +{ + wGroupTreeItem *i = 0; + + Q3ListViewItemIterator it( tree ); + while ( i = ( wGroupTreeItem *) it.current() ) { + if ( i->id == id ) break; + ++it; + } + return i; +} + + +/*! + * Create toolbar for Journal. + */ +Q3ToolBar* +wGroupTree::createToolBar( Q3MainWindow * owner ) +{ + QAction *a; + Q3ToolBar *t = new Q3ToolBar( owner, "GroupTreeTools" ); + + a = new QAction( + rcIcon("doc_new.png"), + tr("New"), + QKeySequence(""),//Insert"), + t, + tr("New group") + ); + a->setToolTip(tr("New group (Ins)")); + a->addTo( t ); + connect( a, SIGNAL( activated() ), this, SLOT( NewGroup() ) ); + + a = new QAction( + rcIcon("doc_edit.png"), + tr("Edit"), + QKeySequence(""),//Return"), + t, + tr("Edit group") + ); + a->setToolTip(tr("Edit group (Enter)")); + a->addTo( t ); + connect( a, SIGNAL( activated() ), this, SLOT( EditGroup() ) ); + +/* a = new QAction( + QPixmap::fromMimeSource("doc_view.png"), + tr("View"), + QKeySequence("Shifh+Return"), + t, + tr("View element") + ); + a->setToolTip(tr("View element (Shift+Enter)")); + a->addTo( t ); + connect( a, SIGNAL( activated() ), this, SLOT( view() ) ); +*/ + a = new QAction( + rcIcon("doc_delete.png"), + tr("Delete group"), + QKeySequence(""),//Delete"), + t, + tr("Delete group") + ); + a->setToolTip(tr("Delete group (Delete)")); + a->addTo( t ); + connect( a, SIGNAL( activated() ), this, SLOT( DeleteGroup() ) ); + + + return 0; +} + +void +wGroupTree::on_selectionChanged( Q3ListViewItem * item) +{ + printf("wGroupTree id =%llu\n",((wGroupTreeItem*) item)->id); + emit(selectionChanged( ((wGroupTreeItem*) item)->id) ); +} diff --git a/src/plugins/grouptree/wgrouptree.h b/src/plugins/grouptree/wgrouptree.h new file mode 100644 index 0000000..296cc68 --- /dev/null +++ b/src/plugins/grouptree/wgrouptree.h @@ -0,0 +1,95 @@ +/**************************************************************************** +** $Id: wgrouptree.h,v 1.1 2008/11/05 21:16:30 leader Exp $ +** +** Header file of the document plugin of Ananas +** Designer and Engine applications +** +** Created : 20031201 +** +** Copyright (C) 2003-2004 Leader InfoTech. All rights reserved. +** +** This file is part of the Ananas Plugins of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.leaderit.ru/page=ananas or email sales@leaderit.ru +** See http://www.leaderit.ru/gpl/ for GPL licensing information. +** +** Contact org@leaderit.ru if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#ifndef WGROUPTREE_H +#define WGROUPTREE_H + +#include +#include +#include +//Added by qt3to4: +#include +#include "awidget.h" + +class wGroupTreeItem; + +class QT_WIDGET_PLUGIN_EXPORT wGroupTree : public aWidget +{ + Q_OBJECT +public: + Q3ListView *tree; + wGroupTreeItem *root; + + wGroupTree( QWidget *parent = 0, Qt::WFlags fl = 0 ); + virtual ~wGroupTree(); + + virtual void initObject( aDatabase *adb ); + virtual QDialog* createEditor( QWidget *parent ); + virtual Q3ToolBar* createToolBar( Q3MainWindow *parent ); + virtual aObject *createDBObject( aCfgItem obj, aDatabase *adb ); + void buildGroupTree( aCfgItem obj, aCatGroup * cg1, wGroupTreeItem * wG ); + void findGroupTree(); + wGroupTreeItem *findItem( ANANAS_UID id ); +public slots: + void NewGroup(); + void DeleteGroup(); + void EditGroup(); +// void UpdateItem( aCatGroup *g ); +private slots: + void on_selected( ANANAS_UID element ); +// void updateItem( ANANAS_UID element ); + void updateItem( ANANAS_UID element ); + void on_selectionChanged( Q3ListViewItem *); +signals: + virtual void selected( ANANAS_UID group ); + virtual void selectionChanged( const qulonglong ); +protected: + virtual void keyPressEvent ( QKeyEvent *e ); +private: +}; + + + +class wGroupTreeItem : public Q3ListViewItem +{ +public: + ANANAS_UID id; + int level; + wGroupTreeItem( Q3ListView *parent, const QString &name = QString::null ); + wGroupTreeItem( wGroupTreeItem *parent, wGroupTreeItem *after, const QString &name = QString::null, int newlevel = 0, ANANAS_UID newid = 0 ); + wGroupTreeItem( wGroupTreeItem *parent, wGroupTreeItem *after, aCatGroup *g = 0 ); + virtual ~wGroupTreeItem(); + wGroupTreeItem *parentItem(); +private: +}; + + + +#endif // WGROUPTREE_H + diff --git a/src/plugins/grouptree/wgrouptree_plugin.cpp b/src/plugins/grouptree/wgrouptree_plugin.cpp new file mode 100644 index 0000000..67be9bf --- /dev/null +++ b/src/plugins/grouptree/wgrouptree_plugin.cpp @@ -0,0 +1,91 @@ +/**************************************************************************** +** +** Code file +** +** Copyright (C) 2006 Dmitriy Pavlyuk +** +** This file is part of the Ananas Plugins of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +**********************************************************************/ + +#include "wgrouptree_plugin.h" + +#include + +#include "wgrouptree.h" + + +wGroupTreePlugin::wGroupTreePlugin(QObject *parent) + : QObject(parent), m_initialized(false) +{ + m_initialized = false; +} + +bool wGroupTreePlugin::isContainer() const +{ + return false; +} + +bool wGroupTreePlugin::isInitialized() const +{ + return m_initialized; +} + +void wGroupTreePlugin::initialize(QDesignerFormEditorInterface *core) +{ + if (m_initialized) + return; + Q_UNUSED(core); + m_initialized = true; +} + +QWidget *wGroupTreePlugin::createWidget(QWidget *parent) +{ + wGroupTree *w = new wGroupTree(parent); + return w; +} + +QString wGroupTreePlugin::name() const +{ + return QLatin1String("wGroupTree"); +} + +QString wGroupTreePlugin::group() const +{ + return QLatin1String("Ananas"); +} + +QString wGroupTreePlugin::toolTip() const +{ + return QString("Ananas for QT Group Tree Widget"); +} + +QString wGroupTreePlugin::whatsThis() const +{ + return QString("Entry to select group of Ananas's object"); +} + +QString wGroupTreePlugin::includeFile() const +{ + return QLatin1String("wgrouptree.h"); +} + +QIcon wGroupTreePlugin::icon() const +{ + //return QIcon(); + return QIcon(":/images/wgrouptree.png"); +} + +QString wGroupTreePlugin::domXml() const +{ + return "\n\n"; +} diff --git a/src/plugins/grouptree/wgrouptree_plugin.h b/src/plugins/grouptree/wgrouptree_plugin.h new file mode 100644 index 0000000..d900af1 --- /dev/null +++ b/src/plugins/grouptree/wgrouptree_plugin.h @@ -0,0 +1,53 @@ +/**************************************************************************** +** +** Header file +** +** Copyright (C) 2006 Dmitriy Pavlyuk +** +** This file is part of the Ananas Plugins of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +**********************************************************************/ + +#ifndef WGROUPTREE_PLUGIN_H +#define WGROUPTREE_PLUGIN_H + +#include + +#include "qwidgetplugin.h" + + +class QT_WIDGET_PLUGIN_EXPORT wGroupTreePlugin : public QObject, public QDesignerCustomWidgetInterface +{ + Q_OBJECT + Q_INTERFACES(QDesignerCustomWidgetInterface) + +public: + wGroupTreePlugin(QObject *parent=0); + + bool isContainer() const; + bool isInitialized() const; + void initialize(QDesignerFormEditorInterface *core); + QWidget *createWidget(QWidget *parent); + + QString name() const; + QString group() const; + QString toolTip() const; + QString whatsThis() const; + QString includeFile() const; + QIcon icon() const; + QString domXml() const; + +private: + bool m_initialized; +}; + +#endif // WGROUPTREE_PLUGIN_H diff --git a/src/plugins/images/acombobox.png b/src/plugins/images/acombobox.png new file mode 100644 index 0000000000000000000000000000000000000000..7d4890a7ff9cfad18c271c0524ea8a053afa827c GIT binary patch literal 549 zcmV+=0^0qFP)osEah%awY_22_dv6%?)C^lR}GwD2SlT4T9j};-a1&qL6|} zbb=u`xQK3UU+;T)*QrnG?i_x+fA@ax@x6E7BZQDA$|nW(fI@kpoKT2VtJPq!Sp17* zGP!jOJ=FI>IY%)}r&Eo5KEJabkH=Zb+p(_yl8Hy75hIt&ZPeGxSS+Ts^-^_w+4eGV zzu(tLrBXZVkw|2v59jN@TZ(T`+)Ss_Aj>jHk_6Ri6)Kg=RzjiBN;?{jYV|}SfzmI^ zEm@x8x6kJTkH-UoAehE(x2rp5V!Rp`D4oyeFq_RxqdPo5iVrDgxFQbNu594CbAkKO zZJ1uKr-~m?e1N+~@nkY#(!g5)g6~1YbUGbXd`|$dB*!QokH>6f{3tAj4byJ7|6;5c z4~Ih-3o;D7ZS2Cphtj2GNWjLYRRU)=3>EycK0D)GgwRtxI& zx@n5VB46BSG%Up!Gay%t|GSkKi=xOEWALrSIGfFGiZOu{3I)hyGN!@TWnFxS#K;~oGBKlw zg(m>1122G>c?LFwgoF_4%)&(4g{ne;73?PQ-_s$!RtQcp>L(pp_Pzf3`;M=DMO7)1 zhzL*xtn64Rn5IAq#6Y5|i5ak%uj=yhauftX;oxvMlm8L0!!GOVF zz~kd1p64+djR=B(IGz|gI5^<^{QPsL)A+9_8?NP7S>G%7z z+ieaH5Al7UUav=|)A@aIanT0uUmbgGZB4JPuJrWuG`}`eOTZ`d@~Qw)6csw2j=j0L zNs=UNZ*Oyae9Xea0+mVy*LCT3y8!QjdjqZ*K+*C`lF2G+G#c#h@6+q`P*rw!cX1pC z+qSvAy*1O{05xkCkf!Ne#~T|P`L&~?Beu4-CUL9P>9kcqo`9n$%H2(?)oO8ec9x%; z*skkh+cwQ+lQ0aQ+*1ndI1Y~E#a5!W<9utP)v-eX9JSzhU!!U=McFhIPPAHOz z9mg?I6cGf$%dMEVr$)L5RsQ1&-<*4TCuaUQ#3pRVr$k(nI2Eg z`3Br%WuPuF%E6xJ;rl)h4-cgsXTU!2(>ybS`{wV~1bkkvF7RUtoC3*oD-z&KRv&fqwtTQ@amF@pb?J0000+}kNAkY{;53lGOz=e3<2YlT~aG{ZvHGQM`jQzOnvRzkNY6G1s z;63LL)Y#8jTkNLF3LAL75rg(y=guB#-MfeKZv!;v=JGRY*7TXC4+sIF&cJd1rK)}G z7#^k})6IuSq-@l(UH}uzL1_sB`~{wDT-_m378U@wS5yR+6?`%g3EVz*)O%`Y3HsA# zv}vNWrh4l(K1S!f$r^YIJf6mbQi4)w+eT{5k(?Z=ON!kM<-5>ddXT1xRElZK;`+!a zQLWp7+2x>=1OWg&cPcCVr?azBS|hba#g|TZAr}|XS~DXAEkDBa$6`U?QL+XAPhU?= zH0HZpd8O_Qq*6$wkxC&f3l+b4>rj~f*wUKtzZrn@Rm1OVs>zGR90S{SEVSnCLmhcT)!Uw$ENPq!^I%=x?Ckygf z7#KvvmK?Zt;LcuCo9X746#nl*dVx19L0b|81lx9(`2%^m%nuB*G&hfsl4)V_){G*Q za+Z_`rMT+#uswCl6`UtcDj-m8c$f-j;@K%*!q@@itc|CTE z;jxQdE*ofB-Uqtt-RX8ymfNmMciF&$wLt5AQv(R#Xg_52GzB;T_;KdbyJT;_S^u{F Y02P^50h#1@X#fBK07*qoM6N<$f|_(yT>t<8 literal 0 HcmV?d00001 diff --git a/src/plugins/images/doc_edit.png b/src/plugins/images/doc_edit.png new file mode 100644 index 0000000000000000000000000000000000000000..9e70eacfc236df137c765cbde0e6efd84018f935 GIT binary patch literal 939 zcmV;c162HpP);iVRXxH)I z$GZW3Jjuy9&-0%1{GaD{&U=9W$4r0E@&7t;190m(?Lp;e`qjEA!PjRu3E+Gexm4rNENuNE5{8)JTco`(ZJ z;=I1f?O&2)G73_0B|-=!Ny-g1KR=fB$H&L9SS*wuIm+DiRl-fr6NgxV0I+K!HSxK* zIgE!NN2}GMJANF)*|S{O*Z}A&D;5w!u)e;I-|sJBT~Sd%dwV;{WRiu2gFDS{2!X@l;DL%QG75Zq`754j z$j~=(DV9v8%mAv0?uDm#JvcbXdvCr(P1CC!e(DHgpD*!iJar1V0Z`I`5F*=R0UDFZ z#M06d8-K9{V0Lzv#~#V>2%cB*Oxp;qtRG^ z%VM!`>C6f4%WQDs=}lh$aD}Z@+D+acta{1CiPhE<6BC%9twSq*CcSkBmp95!w@cEg zBMOB=c)i|SytTCzzu%w3Q(Ifh>5o2O@_jQqzXjM#r5X9u!#nQ|)6>&aSa816*4C!j z?e+pOwGOOSDbpkGX4GiC3sX3Ns@#t%XmDVf{hxDhUVsGMn^|ERHH##-$bPB0JB%zM7JNrY&P#M zkQLGE_2~8b5<~zkEiE{|{)Av?jm<5Ea~EZXhsV+D^?MgkOPrnEZa3fEjA5VmbLE;B z?CfM`XNQ@YnY|%eSy^Fud0Dlh#l=O+%ggCMeVL)5A-cM{@cDcM0s-7^H$ZGp zh#DIkRRz-NG#-x!tJO+(cQ-DVi+DUvB9X{;@P+C@0F%k2?8hRJh%!ArtxQc#DZRbD z3h@0s5$(sq;V=$|16h`_*=#tS&Z|J@Zs%?R%05OExBzth(?b8X{Rzd7d+nenmlFU0 N002ovPDHLkV1lPQxE25a literal 0 HcmV?d00001 diff --git a/src/plugins/images/doc_new.png b/src/plugins/images/doc_new.png new file mode 100644 index 0000000000000000000000000000000000000000..6c8b94d16b1f0181075a35b2378e31630d01299b GIT binary patch literal 950 zcmV;n14;aeP)7qz`o z5xb#yF`d|XA&7{zQb7d2Rz)geN0E8qAY&03MOZqJg;HptY=nx`;zgrS(_%x~e4NLN zq%m!C=3w>@@6Gcb{vXeC&U3&4BJ_)J&FTKGA%ZDFMg;3_cr>RArC0|p1LtbWCh$oe zGyNij?o`wQh5%E9kO-MdJp{}FvWtAElJt%R05bOlGy&#@h7drG9?|5-5mPDxVw%Xr z1hTY*ghEv7l@r@0QVs&K@82^A8XwfScx4j=-g?c;p$0|wsYVis1g059DcIQf0q~=g zsve)uSLHSw1TO!ykRSN;1s{(-?m|j}(iQo&a(6UMqfmH`eEyXk#7gb;t3)t?6E(Hp zlwz&rUTrOP<1m^_p)?SIQdW5Sr8TnB#mLAA;c%E_GD$X@1)!y+g@n5%*EE9g4O_<3#15zzlCq!Jj8cbXE}T36d!){C6P$vwkhh(pr_*@BXQ|{6R%Pj zUQh-|2@J1784$m^#rUNhH*OXf8ylm!xfuYD*&# z96hX)OW7zLzM9+Q%G5DBJ3Hy?>!YWq2fyFHCxKxYjspEP^EmfL=K=qbCXInJ4R}$U zd^yMT^%%MyXJO$90GgVbNT<^Pw6?a=-rkO`>rUPIw@t@QUA~U^UChqDx?`w5pO0uXx?OWjaJs9}sJfq;nv$8B8L=#@#__LW+oss| zUs4bMm0;h74=`@p*lK>a$JvaQ6<*IdW0d*bMVr6AT;_~vz3zoWVsJ`phFeAhwo7-T5_x&BvJl%v(U-xpZygZq8O YKVZkg?+Mhp2><{907*qoM6N<$g09@dEC2ui literal 0 HcmV?d00001 diff --git a/src/plugins/images/doc_view.png b/src/plugins/images/doc_view.png new file mode 100644 index 0000000000000000000000000000000000000000..9b175183a0b291cdc654838cfb9e5deb3baf13e2 GIT binary patch literal 1043 zcmV+u1nm2XP)yUr1Y59LGQR=GKd=ORh^>4K+rcTT7T$+**rTSJ;LF-ROod zLb_Vk$(S(+gE=g-dl~Fu;6#}CFz{jE!_XDxgo20#jW zgH6^Y!E|FU`@-RH{``KQ^ZT9OIq-j%@USyKy?5nE}ZWsH%#? z;Xslk-tX)prj)XmbrMOEkPUF<{Hwfm{T)8)`heWr+@k@4AS5D)M=>xkKqwUAYHJ5; zN)>teCpc|7jwHZ-RAV`~%fa4pKIWq_tVhOfIqj2^W`Pnc)64t zmn>Xgfu8x90OwxfyFtd@sZd z1|lL@p3TD(P&s?rmiZ1uQN(JsQdn4+NRuQ#fwAxuQ@aL433j6}wF9DX_=p5SpulE^ zpO0k*B$p>ZuB@>Qtnb6un}-HjB4i1N5D_SRN=C~zWKNMNig>+V78Vu&C@3hvpoOvR zED$tRCJZFuuo(a?{DAT&b-uiJ@9`qA*=&i2)6&wy#KZ)xrKK3xJ@}O(VmS&DAZi-Y zuF8dz5{sU@jE;_`1&GOjN6Xdaa^ZHn2?m2amuKRl=HvP8AF143rbY;G$$Y@Bf0eDR zEo4~+r~qyqnWELzRp#gC6C2vw+v)7=q^YTi=H_OikqG{+6}-_Xo12>`io!*0otko) zAA;G+=f56&d?%z80oUQL-}J@0y1L2n@$r%| zE-o@WJdDTVnFOwcfKNAKEx-5# zV{8BPvb#va7+cQ3pqbs#r=NCLqX6hkCX+|4_0KHJ9*UyiQp@w4G)-D@>$C@=RZi2mH zDJ5lD0+1vL+wImD_4|FFH)~w(u1CSurD!gT%abGlV6)lOYECMy9GO~N%~z`x0K?(X z$H#;m-8>-#qtVD02_gJkvqlJUT5(yHwRKu77F6flShL3EXDM!DC&A5~z2+R(!0+@) zd$7s#{OBP+*Y^88l|HTk69Fbo)2G>Nb|1%aEBJ1=V?Lh)tN;lpfDgbA+oa7E{ulTK zd=0N}e002ovPDHLkV1jU&@b3Ts literal 0 HcmV?d00001 diff --git a/src/plugins/images/wcatalogue.png b/src/plugins/images/wcatalogue.png new file mode 100644 index 0000000000000000000000000000000000000000..9b26a30416cc42cb3e07058b950bab265bcd9784 GIT binary patch literal 570 zcmV-A0>%A_P)US5 zpf_;aU8T}pi3hOTZh8PoK;A5zI7wb39svX$A$y}CRb5a6_O+|#_~MJZns0*!f{=YBZMFu9t0rUk*@uI56)|2 zjIjuu^FOep(NG)?2V_}>rDBYMb52qMPmZtGijpK5b(CfGBsfhYTrRwKY=^;)o&Dh} zsY!zXBqiXvuB5K>o$IwCJrPx9PBygyeL|I+Ar#v!o2-N}uyUHF5#qQ;QAC3=BYDT; z(fD}1{v4g8EMb6bZ8jTxEXjIV_Lr{HssAmC2yq+_<1fLF$Kwe)T@k7A?D@Wrw#8Ej z*6Y_W5n z@YHOV3wP%B3e_+EH-`z8QkvzqTK&xG%}w)VY#tq|x|^rFB>JB0xwdSmv8DCSv{W|K zI7Ntv&gU}$SbQ~2L$-tvB!nP`h-l8TZRsw@&bCS&q+qXqEU0<|fm2zN<_{^1+ zlb+V3o|~u=^jvYX>gTe~DWM4fB>RS( literal 0 HcmV?d00001 diff --git a/src/plugins/images/wdbtable.png b/src/plugins/images/wdbtable.png new file mode 100644 index 0000000000000000000000000000000000000000..233b0760ed9f0b4b5ad737b7bd67156fbb26917e GIT binary patch literal 691 zcmV;k0!;mhP)DICY}ZQuX^0zgSb zK~#90&6L4v8c`U9Kdm@}0SB@WB)D;xLLQ)-fS_*0O~FkzcHOt=Bea`r3SGF8L0pwQ zKoz8MTtsK%CKyO$MiPVEI|}LQ-pn{-p_D?;>YsD&J@fx(=H67>6fbW-eMSg@=Xppe z*>1P|3D)a1j^prd{!?=q03igeR*O=pq=jm=ie*`JyWN9^wr$gFHUSt627Il(YH0w^ z^CG63%?8V|I6FK0ZKpyAU7MyE(J}zf&(Cx^orqu<2FJ(8F+K~=c}g#xFirvS|7b8c^MBO5cB47=Sf!sYwl;!&uNRV)^f zQeqee`FtLLa=FaO$w{oMecbdzFIL6n<)t1Cpx5gGP^nZ78ufZTo$>YcH8&wmXB-3p z+wE2#j_GvD)6h(H82wd0YM~F|8fc?!$C-TtRi1B*8 zj^vh5$d`I0G!X~MYy$NB7);MI2;bhvTR(7;}}8+1HK4;FW`{m zcs!yg3fyitNGZql=ksYW*tGLFXH*o00ai*u2!TA$A%sBJbz{ObO>w{9@zt?X%D8ew z1mE`&h9QC=nB9@p84ovL8m{YNzu$jop6A(tyRKUVFB!3Rtd!aY{1?a5daM?26UUo@ yhqvM1!EM_jNfK*tRaJJK_v?4`-g#`R&-4YJRw>f(%Yp$r}K8pU>SSet{xZ{Tzi$Z!w*P@7SR~AJU zjir;8s9fCkcFO8iPHYT{EG2W9GB21sP7_XTGEUn0UGCm*&Gg3(*~}A#qGo3ro~!;+ zyI*8~71O7>2(Ftp6HedmoU(eSO5v-wWk(H{IL7X;kC^xTe3Z?tw;U>#`nR&onFO-m rDt;6@x3gci{*(dF@;`>+_9u87{=1o^zP^4O=nDo%A_P)US5 zpf_;aU8T}pi3hOTZh8PoK;A5zI7wb39svX$A$y}CRb5a6_O+|#_~MJZns0*!f{=YBZMFu9t0rUk*@uI56)|2 zjIjuu^FOep(NG)?2V_}>rDBYMb52qMPmZtGijpK5b(CfGBsfhYTrRwKY=^;)o&Dh} zsY!zXBqiXvuB5K>o$IwCJrPx9PBygyeL|I+Ar#v!o2-N}uyUHF5#qQ;QAC3=BYDT; z(fD}1{v4g8EMb6bZ8jTxEXjIV_Lr{HssAmC2yq+_<1fLF$Kwe)T@k7A?D@Wrw#8Ej z*6Y_W5n z@YHOV3wP%B3e_+EH-`z8QkvzqTK&xG%}w)VY#tq|x|^rFB>JB0xwdSmv8DCSv{W|K zI7Ntv&gU}$SbQ~2L$-tvB!nP`h-l8TZRsw@&b!lvI6;RN#5=* z4F5rJ!QSPQfg+p*9+AZi4BSE>%y{W;-5;PJdx@v7EBh4|VIe8DExVg;FfcF*c)B=- zRNUG+b#HHrfk5kgeia_m02a{zW=77d3RMf(nS`VioT3C39!@ahh!AF|zBsS!d)oPA zS?h_py>|P5Za(_8>ahA7Zh52cUlll73|ln1PJBL{D)N16g|DkX$88he8{2x9pd7f@cC>|F&Cycgd8n z#9-%7%O6!A^=IC_uG_@-=7B_sA6>G?6Z}%Ip5xvG3%JrG?kO*e@Wl?(fKNE>eg&va4~qg`njxgN@xNAx}l=_ literal 0 HcmV?d00001 diff --git a/src/plugins/images/wreport.png b/src/plugins/images/wreport.png new file mode 100644 index 0000000000000000000000000000000000000000..0c4bb0c066fce2757147c499a69c38e4b65803ba GIT binary patch literal 636 zcmV-?0)zdDP)g3vw)0+dpeN+l|l z3Z|J-Ns-5bl~N(_lU}daaa}hN9toCGhQLxvq?7=x*K2CES|U6WY~J04v=iXFQYfWZ zuh#%ntJPR|Ixa_TAwt?2kiEWUI2>wC2!Z1`A$aPrK}<8H=JPrEUXQjAe13e?Q4R(J z8jS|acVh0pi7`jmw7Z-Yccm%{o{AE7ZK0fsG$^HFak^dV`=twPTuJMXpEQDRH~uki0000DGb_2eS`o20zgSb zK~#90&6L4v8c`U9Kdm@}0SB@WB)D;xLLQ)-fS_*0O~FkzcHOt=Bea`r3SGF8L0pwQ zKoz8MTtsK%CKyO$MiPVEI|}LQ-pn{-p_D?;>YsD&J@fx(=H67>6fbW-eMSg@=Xppe z*>1P|3D)a1j^prd{!?=q03igeR*O=pq=jm=ie*`JyWN9^wr$gFHUSt627Il(YH0w^ z^CG63%?8V|I6FK0ZKpyAU7MyE(J}zf&(Cx^orqu<2FJ(8F+K~=c}g#xFirvS|7b8c^MBO5cB47=Sf!sYwl;!&uNRV)^f zQeqee`FtLLa=FaO$w{oMecbdzFIL6n<)t1Cpx5gGP^nZ78ufZTo$>YcH8&wmXB-3p z+wE2#j_GvD)6h(H82wd0YM~F|8fc?!$C-TtRi1B*8 zj^vh +#include +#include + +#include "acfg.h" + +/* + * Constructs a eJournal as a child of 'parent', with the + * name 'name' and widget flags set to 'f'. + * + * The dialog will by default be modeless, unless you set 'modal' to + * true to construct a modal dialog. + */ +eJournal::eJournal(QWidget* parent, const char* name, bool modal, Qt::WindowFlags fl) + : QDialog(parent, name, modal, fl) +{ + setupUi(this); + + init(); +} + +/* + * Destroys the object and frees any allocated resources + */ +eJournal::~eJournal() +{ + // no need to delete child widgets, Qt does it all for us +} + +/* + * Sets the strings of the subwidgets using the current + * language. + */ +void eJournal::languageChange() +{ + retranslateUi(this); +} + +void eJournal::init() +{ +/* + int oc, i, f, idx=0; + char *id, *name, *ot; + cfg_objptr o; + char otype[100]; + QString named; + + otypes.clear(); + eType->clear(); + otypes.append("D"); + eType->insertItem(trUtf8("Дата"), idx++); + otypes.append("T"); + eType->insertItem(trUtf8("Время"), idx++); + otypes.append("N %d %d"); + eType->insertItem(trUtf8("Число"), idx++); + otypes.append("C %d"); + eType->insertItem(trUtf8("Строка"), idx++); + + oc=cfgobj_count(NULL, NULL); + for (i=1;i<=oc;i++) { + id=cfgobj_idn(NULL, NULL, i, &o); + ot=(char *)o->name; + name=cfgobj_attr(o, "name"); + named=""; + f=0; + if (strcmp((char *)ot, aot_doc)==0) { + named=trUtf8("Документ."); + f=1; + } + if (strcmp((char *)ot, aot_cat)==0) { + named=trUtf8("Справочник."); + f=1; + } + if (f) { + named=named+trUtf8(name); + sprintf(otype, "O %s", id); + otypes.append(otype); + eType->insertItem(named, idx++); + } + } +*/ +} + + + +/*void eJournal::setData( aCatalogue *f, QWidget *mw ) +{ + aCfg *md = 0; + if ( !f ) return; +// printf("name = '%s'\n", (const char *) mw->name() ); + if (mw->name() == QString("ananas-designer_mainwindow") ) { +// printf("running under ananas designer\n"); + CfgForm *cf = ( ( MainForm *) mw )->cfgForm(); + if ( cf ) { + md = &cf->cfg; +// QString ts = f->getFieldType(); +// char t=' '; + int w=0, d=0, idx=0; + unsigned int i; + long oid , id; + + id = f->getId(); + + otypes.clear(); + eType->clear(); + + QStringList tlist = md->types( md_catalogue ); + otypes.clear(); + eType->clear(); + for ( QStringList::Iterator it = tlist.begin(); it != tlist.end(); ++it ) { + otypes.append( (*it).section( "\t", 0, 0 ) ); + eType->insertItem( (*it).section("\t", 1, 1 ), idx++ ); + } + for ( i = 0 ; i < otypes.count(); i++ ) { + oid = 0; + if( otypes[i][0] == 'O' ) { + sscanf( (const char *)otypes[ i ], "O %d", &oid ); + if ( oid == id ) { + eType->setCurrentItem( i ); + break; + } + } + } + } else reject(); + } + +} +*/ + +void +eJournal::setData( QWidget *o, aCfg *md ) +{ +// const QObject *o = sender(); + if ( o ) { + if ( o->className() != QString("wJournal") || !md ) { + reject(); + return; + } + } + else { + reject(); + return; + } + wJournal *f = ( wJournal*) o; + int w=0, d=0, idx=0; + unsigned int i; + long oid , id; + + id = f->getId(); + + QStringList tlist = md->types( md_journal ); + otypes.clear(); + eType->clear(); + for ( QStringList::Iterator it = tlist.begin(); it != tlist.end(); ++it ) { + otypes.append( (*it).section( "\t", 0, 0 ) ); + eType->insertItem( (*it).section("\t", 1, 1 ), idx++ ); + } + for ( i = 0 ; i < otypes.count(); i++ ) { + oid = 0; + if( otypes[i][0] == 'O' ) { + sscanf( (const char *)otypes[ i ], "O %d", &oid ); + if ( oid == id ) { + eType->setCurrentItem( i ); + break; + } + } + } +} + + +void eJournal::getData( QWidget * o ) +{ + +/* int idx=eType->currentItem(); + long oid = 0; + + if (f) { + if( otypes[idx][0] == 'O' ) { + sscanf( (const char *)otypes[ idx ], "O %d", &oid ); + f->setId( oid ); + } + } +*/ +// const QObject *o = sender(); + if ( !o ) return; + if ( o->className() != QString("wJournal") ) return; + wJournal *f = ( wJournal*) o; + + int idx=eType->currentItem(); + long oid = 0; + + if (f) { + if( otypes[idx][0] == 'O' ) { + sscanf( (const char *)otypes[ idx ], "O %d", &oid ); + f->setId( oid ); + } + } + +} diff --git a/src/plugins/journal/ejournal.h b/src/plugins/journal/ejournal.h new file mode 100644 index 0000000..fdeeccb --- /dev/null +++ b/src/plugins/journal/ejournal.h @@ -0,0 +1,27 @@ +#ifndef EJOURNAL_H +#define EJOURNAL_H + +#include "ui_ejournal.h" + + +class eJournal : public QDialog, public Ui::eJournal +{ + Q_OBJECT + +public: + eJournal(QWidget* parent = 0, const char* name = 0, bool modal = false, Qt::WindowFlags fl = 0); + ~eJournal(); + + QStringList otypes; + +public slots: + virtual void init(); + virtual void setData( QWidget * o, aCfg * md ); + virtual void getData( QWidget * o ); + +protected slots: + virtual void languageChange(); + +}; + +#endif // EJOURNAL_H diff --git a/src/plugins/journal/ejournal.ui b/src/plugins/journal/ejournal.ui new file mode 100644 index 0000000..d96107a --- /dev/null +++ b/src/plugins/journal/ejournal.ui @@ -0,0 +1,116 @@ + + + + + eJournal + + + + 0 + 0 + 348 + 109 + + + + Journal + + + + + + + + + + + + + 100 + 32767 + + + + Type + + + false + + + + + + + + 31 + 16 + + + + Expanding + + + Vertical + + + + + + + + + OK + + + true + + + + + + + Cancel + + + + + + + + + + 91 + 31 + + + + Expanding + + + Horizontal + + + + + + + qPixmapFromMimeSource + + ananas.h + wjournal.h + + + + bOK + clicked() + eJournal + accept() + + + bCancel + clicked() + eJournal + reject() + + + diff --git a/src/plugins/journal/journal.pri b/src/plugins/journal/journal.pri new file mode 100644 index 0000000..61ed3fb --- /dev/null +++ b/src/plugins/journal/journal.pri @@ -0,0 +1,15 @@ +HEADERS += \ + journal/ejournal.h \ + journal/wjournal.h \ + journal/wjournal_plugin.h \ + journal/wjournal_taskmenu.h + +SOURCES += \ + journal/ejournal.cpp \ + journal/wjournal.cpp \ + journal/wjournal_plugin.cpp \ + journal/wjournal_taskmenu.cpp + +FORMS += \ + journal/ejournal.ui + \ No newline at end of file diff --git a/src/plugins/journal/wjournal.cpp b/src/plugins/journal/wjournal.cpp new file mode 100644 index 0000000..5d51361 --- /dev/null +++ b/src/plugins/journal/wjournal.cpp @@ -0,0 +1,351 @@ +/**************************************************************************** +** $Id: wjournal.cpp,v 1.2 2008/11/08 20:16:36 leader Exp $ +** +** Code file of the journal plugin of Ananas +** Designer and Engine applications +** +** Created : 20031201 +** +** Copyright (C) 2003-2004 Leader InfoTech. All rights reserved. +** +** This file is part of the Ananas Plugins of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.leaderit.ru/page=ananas or email sales@leaderit.ru +** See http://www.leaderit.ru/gpl/ for GPL licensing information. +** +** Contact org@leaderit.ru if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#include +#include +#include +#include +#include +#include +//Added by qt3to4: +#include +#include "adatabase.h" +#include "wjournal.h" +#include "ejournal.h" +#include "eselectdoctype.h" +#include "adocjournal.h" +#include "eselectdoctype.h" +#include "wdbtable.h" +#include "alog.h" + + + +wJournal::wJournal( QWidget *parent, Qt::WFlags fl ) +:aWidget( parent, "wJournal", fl ) +{ + dSelectType = new eSelectDocType(); + setInited( false ); +} + + +wJournal::~wJournal() +{ + delete dSelectType; + dSelectType = 0; +} + + + +void +wJournal::initObject( aDatabase *adb ) +{ + eSelectDocType *d = ( eSelectDocType *)dSelectType; + aWidget::initObject( adb ); + d->setJournal( &adb->cfg, getId() ); + + + if(((aDocJournal*)dbobj)->type()==0 && toolbar) + { + date_from = new Q3DateEdit(toolbar); + date_to = new Q3DateEdit(toolbar); + QDate current = QDate::currentDate(); + date_to->setMinimumWidth(100); + date_from->setMinimumWidth(100); + date_to->setDate(current); + date_from->setDate(current.addMonths(-1)); + connect(date_from, SIGNAL(valueChanged(const QDate &)), this, SLOT(setFilterByDate())); + connect(date_to, SIGNAL(valueChanged(const QDate &)), this, SLOT(setFilterByDate())); + } + else + { + date_from = date_to = 0; + } + setFilterByDate(); + QObject *obj; + uint i = 0; + QObjectList lb = this->queryList( "wDBTable", 0, false, false ); + QListIterator itb( lb ); // iterate over the buttons + i = 0; + while ( itb.hasNext() ) + { + obj = itb.next(); + //printf("wDBTable #%u found\n",++i); + aLog::print(aLog::Info, tr("wDBTable #%1 found ").arg(++i)); + connect( (wDBTable *)obj, SIGNAL(selectRecord( qulonglong )), + this, SLOT(select( qulonglong )) ); + connect( (wDBTable *)obj, SIGNAL( insertRequest()), + this, SLOT(insert()) ); + connect( (wDBTable *)obj, SIGNAL(updateRequest()), + this, SLOT(update()) ); + connect( (wDBTable *)obj, SIGNAL(viewRequest()), + this, SLOT(view()) ); + connect( (wDBTable *)obj, SIGNAL(deleteRequest()), + this, SLOT(markDelete()) ); +//<<<<<<< wjournal.cpp +// ((QWidget *)obj)->setFocus(); // set focus to wDBTable + +//======= + //((QWidget *)obj)->setFocus(); // set focus to wDBTable + +//>>>>>>> 1.15.2.6 + } + //--delete lb; // delete the list, not the objects + //--lb=0; + +} + + +bool +wJournal::checkStructure() +{ + + return false; +} + + +/*! + * Create toolbar for Journal. + */ +Q3ToolBar* +wJournal::createToolBar( Q3MainWindow * owner ) +{ + QAction *a,*b,*c,*d, *e; + toolbar = new Q3ToolBar( owner, "JournalTools" ); + a = new QAction( + rcIcon("doc_new.png"), + tr("New"), + QKeySequence(QString("Insert")), + toolbar, + tr("New document") + ); + a->setToolTip(tr("New document ")); + a->addTo( toolbar ); + connect( a, SIGNAL( activated() ), this, SLOT( insert() ) ); + b = new QAction( + rcIcon("doc_edit.png"), + tr("Edit"), + QKeySequence(Qt::Key_Return), + toolbar, + tr("Edit document") + ); + b->setToolTip(tr("Edit document ")); + b->addTo( toolbar ); + connect( b, SIGNAL( activated() ), this, SLOT( update() ) ); + c = new QAction( + rcIcon("doc_view.png"), + tr("View"), + QKeySequence(Qt::SHIFT + Qt::Key_Return), + toolbar, + tr("View document") + ); + c->setToolTip(tr("View document ")); + c->addTo( toolbar ); + connect( c, SIGNAL( activated() ), this, SLOT( view() ) ); + d = new QAction( + rcIcon("doc_delete.png"), + tr("Delete"), + QKeySequence(QString("Del")), + toolbar, + tr("Delete document") + ); + d->setToolTip(tr("Delete document ")); + d->addTo( toolbar ); + connect( d, SIGNAL( activated() ), this, SLOT( markDelete() ) ); + + e = new QAction( + rcIcon("doc_copy.png"), + tr("Copy"), + QKeySequence(Qt::CTRL+Qt::Key_D), + toolbar, + tr("Copy document") + ); + e->setToolTip(tr("Duplicate document ")); + e->addTo( toolbar ); + connect( e, SIGNAL( activated() ), this, SLOT( copy() ) ); + + return toolbar; +} + + + +QDialog* +wJournal::createEditor( QWidget *parent ) +{ + return new eJournal( parent ); +} + + +int +wJournal::select( qulonglong id ) +{ + if ( !dbobj ) return err_abstractobj; + docUid = dbobj->docId(); +// docUid = 0; + docId = db->uidType(docUid); +// printf("selected record uid = %llu, doc uid = %llu doc md id %i\n", id, docUid, docId ); + return 0; +} + + + +qulonglong +wJournal::insert() +{ + aForm * f = 0; + int md_id = 0; + eSelectDocType *d = ( eSelectDocType *)dSelectType; + + if ( dSelectType->exec() == QDialog::Accepted ) { + md_id = d->docId; + if ( md_id > 0 ){ + if ( engine ) { + f = engine->openForm( md_id, 0, md_action_new, 0, 0, (aWidget*)this ); + if ( f ) { +// connect(f, SIGNAL(selected( Q_ULLONG )), this, SLOT(on_selected( Q_ULLONG ))); +// f->closeAfterSelect = true; + } + } else printf("engine = NULL\n"); + + } + } + return 0; +} + + +int +wJournal::update() +{ + if ( !dbobj ) return err_abstractobj; + aDocument *doc = ((aDocJournal*)dbobj)->CurrentDocument(); + //doc->select(docUid); + int res=0; + if(doc->IsConducted()) + { + res = QMessageBox::question(this, + tr("Can not edit document"), + tr("To edit document you have to unconduct it. Or you can view it. Unconduct?"), + tr("&Unconduct"), tr("&View"), + QString::null, 0, 1 ); + } + else + { + delete doc; + engine->openForm( docId, 0, md_action_edit, 0, docUid, (aWidget*)this ); + return 0; + } + if(res==0) + { + doc->UnConduct(); + engine->openForm( docId, 0, md_action_edit, 0, docUid, (aWidget*)this ); + } + else + { + view(); + } + delete doc; + return 0; +} + +int +wJournal::copy() +{ + aDocument *doc = ((aDocJournal*)dbobj)->CurrentDocument(); + if(doc) + { + int res = doc->Copy(); + Refresh(); + return res; + } + return err_copyerror; +} +int +wJournal::view() +{ +//CHECK_POINT + engine->openForm( docId, 0, md_action_view, 0, docUid, (aWidget*)this ); + return 0; +} + + + +int +wJournal::markDelete() +{ + if ( !dbobj ) return err_abstractobj; + int res = QMessageBox::question(this, + tr("Confirm"), + tr("Do you really want to delete document?"), + tr("&Yes"), tr("&No"), + QString::null, 0, 1 ); + if(res) return res; + aDocument *doc = ((aDocJournal*)dbobj)->CurrentDocument(); + if(doc->IsConducted()) doc->UnConduct(); + res = doc->Delete(); + //invalidate selection + docId = docUid = 0; + Refresh(); + delete doc; + doc = 0; + return res; +} + + +QString +wJournal::displayString() +{ + return "***"; +} + + +/*! + * Create aDocJournal database object. + */ +aObject * +wJournal::createDBObject( aCfgItem obj, aDatabase *adb ) +{ + return new aDocJournal( obj, adb ); +} + +void +wJournal::setFilterByDate() +{ + if(date_from && date_to) + { + QObject *obj; + QObjectList lb = this->queryList( "wDBTable" ); + QListIterator itb( lb ); // iterate over the buttons + while ( itb.hasNext() ) + { + obj = itb.next(); + ((wDBTable *)obj)->setFilter(QString("ddate>='%1T00:00:00' AND ddate<='%2T23:59:59'").arg(date_from->date().toString(Qt::ISODate)).arg(date_to->date().toString(Qt::ISODate))); + } + //--delete lb; // delete the list, not the objects + } + Refresh(); +} diff --git a/src/plugins/journal/wjournal.h b/src/plugins/journal/wjournal.h new file mode 100644 index 0000000..6c26952 --- /dev/null +++ b/src/plugins/journal/wjournal.h @@ -0,0 +1,92 @@ +/**************************************************************************** +** $Id: wjournal.h,v 1.1 2008/11/05 21:16:30 leader Exp $ +** +** Header file of the catlogue plugin of Ananas +** Designer and Engine applications +** +** Created : 20031201 +** +** Copyright (C) 2003-2004 Leader InfoTech. All rights reserved. +** +** This file is part of the Ananas Plugins of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.leaderit.ru/page=ananas or email sales@leaderit.ru +** See http://www.leaderit.ru/gpl/ for GPL licensing information. +** +** Contact org@leaderit.ru if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#ifndef WJOURNAL_H +#define WJOURNAL_H +#include +#include +#include "awidget.h" + +class QWidget; +/*! + *\en + * Visual object for work with Journals of Documents. + *\_en + *\ru + * \brief Визуальный объект - контейнер для работы с Журналами документов. + * Наследует aWidget. + * + * При создании диалогов - экранных форм журналов все элементы диалога + * (в том числе wDBField, wDBTable) располагаются в этом контейнере. + * В свойстве aObject *dbobj, унаследованном от aWidget, этого класса хранится объект доступа к данным + * журнала в sql таблице базы данных, используемый элементами диалога для выборки и записи данных в базу данных. + * Смотрите метод wJournal::dataObject(). + * В свойстве aCfgItem obj, унаследованном от aWidget, этого класса хранится элемент конфигурации (метаданные), + * описывающий структуру объекта данных (как правило таблицу). + * Смотрите метод wJournal::getMDObject(). + *\_ru + */ + +class QT_WIDGET_PLUGIN_EXPORT wJournal : public aWidget +{ + Q_OBJECT +public: + wJournal( QWidget *parent = 0, Qt::WFlags fl = 0 ); + virtual ~wJournal(); + bool checkStructure(); + virtual void initObject( aDatabase *adb ); + virtual Q3ToolBar* createToolBar( Q3MainWindow *parent ); + virtual QDialog* createEditor( QWidget *parent ); + virtual QString displayString(); + virtual bool isContainer() { return true; }; + virtual aObject* createDBObject( aCfgItem obj, aDatabase *adb ); +// virtual ERR_Code Select( Q_ULLONG id ); + + +public slots: + int select( qulonglong id ); + qulonglong insert(); + int update(); + int view(); + int markDelete(); + int copy(); + +protected slots: + void setFilterByDate(); + +private: + QDialog *dSelectType; + Q3ToolBar *toolbar; + Q3DateEdit *date_from, *date_to; + qulonglong docUid; + int docId; +}; + + +#endif // WJOURNAL_H diff --git a/src/plugins/journal/wjournal_plugin.cpp b/src/plugins/journal/wjournal_plugin.cpp new file mode 100644 index 0000000..e965f72 --- /dev/null +++ b/src/plugins/journal/wjournal_plugin.cpp @@ -0,0 +1,100 @@ +/**************************************************************************** +** +** Code file +** +** Copyright (C) 2006 Dmitriy Pavlyuk +** +** This file is part of the Ananas Plugins of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +**********************************************************************/ + +#include "wjournal_plugin.h" + +#include +#include +#include + +#include "wjournal_taskmenu.h" +#include "wjournal.h" + + +wJournalPlugin::wJournalPlugin(QObject *parent) + : QObject(parent), m_initialized(false) +{ + m_initialized = false; +} + +bool wJournalPlugin::isContainer() const +{ + return true; +} + +bool wJournalPlugin::isInitialized() const +{ + return m_initialized; +} + +void wJournalPlugin::initialize(QDesignerFormEditorInterface *core) +{ + if (m_initialized) + return; + Q_UNUSED(core); + + QExtensionManager *manager = core->extensionManager(); + Q_ASSERT(manager != 0); + manager->registerExtensions(new wJournalTaskMenuFactory(manager), + Q_TYPEID(QDesignerTaskMenuExtension)); + + m_initialized = true; +} + +QWidget *wJournalPlugin::createWidget(QWidget *parent) +{ + wJournal *w = new wJournal(parent, 0); + return w; +} + +QString wJournalPlugin::name() const +{ + return QLatin1String("wJournal"); +} + +QString wJournalPlugin::group() const +{ + return QLatin1String("Ananas"); +} + +QString wJournalPlugin::toolTip() const +{ + return QString(); +} + +QString wJournalPlugin::whatsThis() const +{ + return QString(); +} + +QString wJournalPlugin::includeFile() const +{ + return QLatin1String("wjournal.h"); +} + +QIcon wJournalPlugin::icon() const +{ + //return QIcon(); + return QIcon(":/images/wjournal.png"); +} + +QString wJournalPlugin::domXml() const +{ + return "\n\n"; +} diff --git a/src/plugins/journal/wjournal_plugin.h b/src/plugins/journal/wjournal_plugin.h new file mode 100644 index 0000000..38adaed --- /dev/null +++ b/src/plugins/journal/wjournal_plugin.h @@ -0,0 +1,53 @@ +/**************************************************************************** +** +** Header file +** +** Copyright (C) 2006 Dmitriy Pavlyuk +** +** This file is part of the Ananas Plugins of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +**********************************************************************/ + +#ifndef WJOURNAL_PLUGIN_H +#define WJOURNAL_PLUGIN_H + +#include + +#include "qwidgetplugin.h" + + +class QT_WIDGET_PLUGIN_EXPORT wJournalPlugin : public QObject, public QDesignerCustomWidgetInterface +{ + Q_OBJECT + Q_INTERFACES(QDesignerCustomWidgetInterface) + +public: + wJournalPlugin(QObject *parent=0); + + bool isContainer() const; + bool isInitialized() const; + void initialize(QDesignerFormEditorInterface *core); + QWidget *createWidget(QWidget *parent); + + QString name() const; + QString group() const; + QString toolTip() const; + QString whatsThis() const; + QString includeFile() const; + QIcon icon() const; + QString domXml() const; + +private: + bool m_initialized; +}; + +#endif // WJOURNAL_PLUGIN_H diff --git a/src/plugins/journal/wjournal_taskmenu.cpp b/src/plugins/journal/wjournal_taskmenu.cpp new file mode 100644 index 0000000..e30713f --- /dev/null +++ b/src/plugins/journal/wjournal_taskmenu.cpp @@ -0,0 +1,74 @@ +/**************************************************************************** +** +** Copyright (C) 2006 Dmitriy Pavlyuk All rights reserved. +** +** This file is part of the widgets plugin of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +****************************************************************************/ + +#include + +#include + +#include "wjournal_taskmenu.h" +#include "wjournal.h" +#include "ejournal.h" + + +wJournalTaskMenu::wJournalTaskMenu(wJournal *widget, QObject *parent) + : QObject(parent) +{ + m_widget = widget; + + m_editAction = new QAction(tr("Edit ..."), this); + connect(m_editAction, SIGNAL(triggered()), this, SLOT(edit())); +} + +void wJournalTaskMenu::edit() +{ + /*eJournal e; + + e.setData(m_widget); + if (e.exec() == QDialog::Accepted) + { + e.getData(m_widget); + }*/ + m_widget->widgetEditor(); +} + +QAction *wJournalTaskMenu::preferredEditAction() const +{ + return m_editAction; +} + +QList wJournalTaskMenu::taskActions() const +{ + QList list; + list.append(m_editAction); + return list; +} + +wJournalTaskMenuFactory::wJournalTaskMenuFactory(QExtensionManager *parent) + : QExtensionFactory(parent) +{ +} + +QObject *wJournalTaskMenuFactory::createExtension(QObject *object, const QString &iid, QObject *parent) const +{ + if (iid != Q_TYPEID(QDesignerTaskMenuExtension)) + return 0; + + if (wJournal *ob = qobject_cast(object)) + return new wJournalTaskMenu(ob, parent); + + return 0; +} diff --git a/src/plugins/journal/wjournal_taskmenu.h b/src/plugins/journal/wjournal_taskmenu.h new file mode 100644 index 0000000..5d28257 --- /dev/null +++ b/src/plugins/journal/wjournal_taskmenu.h @@ -0,0 +1,57 @@ +/**************************************************************************** +** +** Copyright (C) 2006 Dmitriy Pavlyuk All rights reserved. +** +** This file is part of the widgets plugin of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +****************************************************************************/ + +#ifndef WJOURNAL_TASKMENU_H +#define WJOURNAL_TASKMENU_H + +#include +#include + + +class QExtensionManager; +class QAction; +class wJournal; + +class wJournalTaskMenu: public QObject, public QDesignerTaskMenuExtension +{ + Q_OBJECT + Q_INTERFACES(QDesignerTaskMenuExtension) +public: + wJournalTaskMenu(wJournal *widget, QObject *parent); + + QAction *preferredEditAction() const; + QList taskActions() const; + +private slots: + void edit(); + +private: + QAction *m_editAction; + wJournal *m_widget; +}; + +class wJournalTaskMenuFactory: public QExtensionFactory +{ + Q_OBJECT +public: + wJournalTaskMenuFactory(QExtensionManager *parent = 0); + +protected: + QObject *createExtension(QObject *object, const QString &iid, QObject *parent) const; +}; + +#endif // WJOURNAL_TASKMENU_H diff --git a/src/plugins/plugins.pri b/src/plugins/plugins.pri new file mode 100644 index 0000000..086eaf5 --- /dev/null +++ b/src/plugins/plugins.pri @@ -0,0 +1,12 @@ +INCLUDEPATH += \ + ../plugins/actionbutton \ + ../plugins/catalogue \ + ../plugins/combobox \ + ../plugins/dbfield \ + ../plugins/dbtable \ + ../plugins/document \ + ../plugins/field \ + ../plugins/grouptree \ + ../plugins/journal \ + ../plugins/report \ + ../plugins/table diff --git a/src/plugins/plugins.pro b/src/plugins/plugins.pro new file mode 100644 index 0000000..16b9581 --- /dev/null +++ b/src/plugins/plugins.pro @@ -0,0 +1,84 @@ +#!define TARGET first for correct temporray paths definitions +TARGET = ananasplugin4 + +include( plugins.pri ) +include( ../lib/lib.pri ) +include ( ../ananas.pri ) +load(qsa) + +TEMPLATE = lib +shared:CONFIG += dll plugin + +DESTDIR = ../../lib/designer +DLLDESTDIR = ../../bin + +INCLUDEPATH += ../plugins ../lib +LIBS += -L../../lib -lananas4 + +shared { + win32:DEFINES+= QT_PLUGIN # ANANAS_DLL +} else { + win32:DEFINES += ANANAS_NO_DLL +} + +unix { + LIBS += -L/usr/X11R6/lib/ +} + +HEADERS = \ + aform.h \ + atoolbar.h \ + awidgets_plugin.h \ + eaddobj.h \ + engine.h \ + qwidgetplugin.h + +SOURCES = \ + aform.cpp \ + atoolbar.cpp \ + awidgets_plugin.cpp \ + engine.cpp \ + eaddobj.cpp + +FORMS = \ + eaddobj.ui + +RESOURCES += \ + plugins.qrc + +TRANSLATIONS = \ + ../../translations/ananas-plugins-en.ts \ + ../../translations/ananas-plugins-ru.ts + +#SLASH = / +unix { + lplugin.path = $(QTDIR)/plugins/designer + lplugin.files = libananasplugin4.so + lplugin.extra = cp -f libananasplugin4.so $(INSTALL_ROOT)$(LIBDIR) || true + lpluginheader.path = $(INCLUDEDIR) + lpluginheader.files = $$HEADERS +} + +win32 { + target.path = $(QTDIR)\plugins\designer + lplugin.path = $(QTDIR)\plugins\designer + lplugin.files = ananasplugin4.* + lplugin.extra = copy ananasplugin4.* $(QTDIR)\lib +} + +#INSTALLS += lplugin +unix{ +# INSTALLS += lpluginheader +} + +include ( actionbutton/actionbutton.pri ) +include ( catalogue/catalogue.pri ) +include ( combobox/combobox.pri ) +include ( dbfield/dbfield.pri ) +include ( dbtable/dbtable.pri ) +include ( document/document.pri ) +include ( field/field.pri ) +include ( grouptree/grouptree.pri ) +include ( journal/journal.pri ) +include ( report/report.pri ) +include ( table/table.pri ) diff --git a/src/plugins/plugins.qrc b/src/plugins/plugins.qrc new file mode 100644 index 0000000..3d31bd5 --- /dev/null +++ b/src/plugins/plugins.qrc @@ -0,0 +1,20 @@ + + + images/acombobox.png + images/doc_copy.png + images/doc_delete.png + images/doc_edit.png + images/doc_new.png + images/doc_view.png + images/wactionbutton.png + images/wcatalogue.png + images/wdbfield.png + images/wdbtable.png + images/wdocument.png + images/wfield.png + images/wgrouptree.png + images/wjournal.png + images/wreport.png + images/wtable.png + + diff --git a/src/plugins/qwidgetplugin.h b/src/plugins/qwidgetplugin.h new file mode 100644 index 0000000..32204a3 --- /dev/null +++ b/src/plugins/qwidgetplugin.h @@ -0,0 +1,54 @@ +/**************************************************************************** +** $Id: qwidgetplugin.h,v 1.2 2008/11/27 20:20:55 leader Exp $ +** +** Definition of QWidgetPlugin class +** +** Created : 010920 +** +** Copyright (C) 2001-2005 Trolltech AS. All rights reserved. +** +** This file is part of the widgets module of the Qt GUI Toolkit. +** +** This file may be distributed under the terms of the Q Public License +** as defined by Trolltech AS of Norway and appearing in the file +** LICENSE.QPL included in the packaging of this file. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition +** licenses may use this file in accordance with the Qt Commercial License +** Agreement provided with the Software. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for +** information about Qt Commercial License Agreements. +** See http://www.trolltech.com/qpl/ for QPL licensing information. +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#ifndef QWIDGETPLUGIN_H +#define QWIDGETPLUGIN_H + +#ifndef QT_NO_WIDGETPLUGIN + +#ifdef Q_WS_WIN +#ifdef QT_PLUGIN +#define QT_WIDGET_PLUGIN_EXPORT __declspec(dllexport) +#else +#define QT_WIDGET_PLUGIN_EXPORT __declspec(dllimport) +#endif +#else +#define QT_WIDGET_PLUGIN_EXPORT +#endif + +#endif // QT_NO_WIDGETPLUGIN +#endif // QWIDGETPLUGIN_H diff --git a/src/plugins/report/ereport.cpp b/src/plugins/report/ereport.cpp new file mode 100644 index 0000000..a400818 --- /dev/null +++ b/src/plugins/report/ereport.cpp @@ -0,0 +1,201 @@ +#include "ereport.h" + +#include +#include +#include + +#include "acfg.h" + +/* + * Constructs a eReport as a child of 'parent', with the + * name 'name' and widget flags set to 'f'. + * + * The dialog will by default be modeless, unless you set 'modal' to + * true to construct a modal dialog. + */ +eReport::eReport(QWidget* parent, const char* name, bool modal, Qt::WindowFlags fl) + : QDialog(parent, name, modal, fl) +{ + setupUi(this); + + init(); +} + +/* + * Destroys the object and frees any allocated resources + */ +eReport::~eReport() +{ + // no need to delete child widgets, Qt does it all for us +} + +/* + * Sets the strings of the subwidgets using the current + * language. + */ +void eReport::languageChange() +{ + retranslateUi(this); +} + +void eReport::init() +{ +/* + int oc, i, f, idx=0; + char *id, *name, *ot; + cfg_objptr o; + char otype[100]; + QString named; + + otypes.clear(); + eType->clear(); + otypes.append("D"); + eType->insertItem(trUtf8("Дата"), idx++); + otypes.append("T"); + eType->insertItem(trUtf8("Время"), idx++); + otypes.append("N %d %d"); + eType->insertItem(trUtf8("Число"), idx++); + otypes.append("C %d"); + eType->insertItem(trUtf8("Строка"), idx++); + + oc=cfgobj_count(NULL, NULL); + for (i=1;i<=oc;i++) { + id=cfgobj_idn(NULL, NULL, i, &o); + ot=(char *)o->name; + name=cfgobj_attr(o, "name"); + named=""; + f=0; + if (strcmp((char *)ot, aot_doc)==0) { + named=trUtf8("Документ."); + f=1; + } + if (strcmp((char *)ot, aot_cat)==0) { + named=trUtf8("Справочник."); + f=1; + } + if (f) { + named=named+trUtf8(name); + sprintf(otype, "O %s", id); + otypes.append(otype); + eType->insertItem(named, idx++); + } + } +*/ +} + + + +/*void eReport::setData( aCatalogue *f, QWidget *mw ) +{ + aCfg *md = 0; + if ( !f ) return; +// printf("name = '%s'\n", (const char *) mw->name() ); + if (mw->name() == QString("ananas-designer_mainwindow") ) { +// printf("running under ananas designer\n"); + CfgForm *cf = ( ( MainForm *) mw )->cfgForm(); + if ( cf ) { + md = &cf->cfg; +// QString ts = f->getFieldType(); +// char t=' '; + int w=0, d=0, idx=0; + unsigned int i; + long oid , id; + + id = f->getId(); + + otypes.clear(); + eType->clear(); + + QStringList tlist = md->types( md_catalogue ); + otypes.clear(); + eType->clear(); + for ( QStringList::Iterator it = tlist.begin(); it != tlist.end(); ++it ) { + otypes.append( (*it).section( "\t", 0, 0 ) ); + eType->insertItem( (*it).section("\t", 1, 1 ), idx++ ); + } + for ( i = 0 ; i < otypes.count(); i++ ) { + oid = 0; + if( otypes[i][0] == 'O' ) { + sscanf( (const char *)otypes[ i ], "O %d", &oid ); + if ( oid == id ) { + eType->setCurrentItem( i ); + break; + } + } + } + } else reject(); + } + +} +*/ + +void +eReport::setData( QWidget *o, aCfg *md ) +{ +// const QObject *o = sender(); + if ( o ) { + if ( o->className() != QString("wReport") || !md ) { + reject(); + return; + } + } + else { + reject(); + return; + } + wReport *f = ( wReport*) o; + int w=0, d=0, idx=0; + unsigned int i; + long oid , id; + + id = f->getId(); + + QStringList tlist = md->types( md_journal ); + otypes.clear(); + eType->clear(); + for ( QStringList::Iterator it = tlist.begin(); it != tlist.end(); ++it ) { + otypes.append( (*it).section( "\t", 0, 0 ) ); + eType->insertItem( (*it).section("\t", 1, 1 ), idx++ ); + } + for ( i = 0 ; i < otypes.count(); i++ ) { + oid = 0; + if( otypes[i][0] == 'O' ) { + sscanf( (const char *)otypes[ i ], "O %d", &oid ); + if ( oid == id ) { + eType->setCurrentItem( i ); + break; + } + } + } +} + + +void eReport::getData( QWidget * o ) +{ + +/* int idx=eType->currentItem(); + long oid = 0; + + if (f) { + if( otypes[idx][0] == 'O' ) { + sscanf( (const char *)otypes[ idx ], "O %d", &oid ); + f->setId( oid ); + } + } +*/ +// const QObject *o = sender(); + if ( !o ) return; + if ( o->className() != QString("wReport") ) return; + wReport *f = ( wReport*) o; + + int idx=eType->currentItem(); + long oid = 0; + + if (f) { + if( otypes[idx][0] == 'O' ) { + sscanf( (const char *)otypes[ idx ], "O %d", &oid ); + f->setId( oid ); + } + } + +} diff --git a/src/plugins/report/ereport.h b/src/plugins/report/ereport.h new file mode 100644 index 0000000..00b7505 --- /dev/null +++ b/src/plugins/report/ereport.h @@ -0,0 +1,27 @@ +#ifndef EREPORT_H +#define EREPORT_H + +#include "ui_ereport.h" + + +class eReport : public QDialog, public Ui::eReport +{ + Q_OBJECT + +public: + eReport(QWidget* parent = 0, const char* name = 0, bool modal = false, Qt::WindowFlags fl = 0); + ~eReport(); + + QStringList otypes; + +public slots: + virtual void init(); + virtual void setData( QWidget * o, aCfg * md ); + virtual void getData( QWidget * o ); + +protected slots: + virtual void languageChange(); + +}; + +#endif // EREPORT_H diff --git a/src/plugins/report/ereport.ui b/src/plugins/report/ereport.ui new file mode 100644 index 0000000..0983f4b --- /dev/null +++ b/src/plugins/report/ereport.ui @@ -0,0 +1,116 @@ + + + + + eReport + + + + 0 + 0 + 348 + 106 + + + + Catalogue + + + + + + + + + + + + + 100 + 32767 + + + + Type + + + false + + + + + + + + 31 + 16 + + + + Expanding + + + Vertical + + + + + + + + + OK + + + true + + + + + + + Cancel + + + + + + + + + + 91 + 31 + + + + Expanding + + + Horizontal + + + + + + + qPixmapFromMimeSource + + ananas.h + wreport.h + + + + bOK + clicked() + eReport + accept() + + + bCancel + clicked() + eReport + reject() + + + diff --git a/src/plugins/report/report.pri b/src/plugins/report/report.pri new file mode 100644 index 0000000..d64c02d --- /dev/null +++ b/src/plugins/report/report.pri @@ -0,0 +1,14 @@ +HEADERS += \ + report/ereport.h \ + report/wreport.h \ + report/wreport_plugin.h \ + report/wreport_taskmenu.h + +SOURCES += \ + report/ereport.cpp \ + report/wreport.cpp \ + report/wreport_plugin.cpp \ + report/wreport_taskmenu.cpp \ + +FORMS += \ + report/ereport.ui diff --git a/src/plugins/report/wreport.cpp b/src/plugins/report/wreport.cpp new file mode 100644 index 0000000..324677c --- /dev/null +++ b/src/plugins/report/wreport.cpp @@ -0,0 +1,145 @@ +/**************************************************************************** +** $Id: wreport.cpp,v 1.1 2008/11/05 21:16:30 leader Exp $ +** +** Code file of the report plugin of Ananas +** Designer and Engine applications +** +** Created : 20031201 +** +** Copyright (C) 2003-2004 Leader InfoTech. All rights reserved. +** +** This file is part of the Ananas Plugins of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.leaderit.ru/page=ananas or email sales@leaderit.ru +** See http://www.leaderit.ru/gpl/ for GPL licensing information. +** +** Contact org@leaderit.ru if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#include +#include +#include +//--#include +#include +#include "adatabase.h" +#include "wreport.h" +#include "ereport.h" + +//extern aCfg *plugins_aCfg; + + +wReport::wReport( QWidget *parent, Qt::WFlags fl ) +:aWidget( parent, "wReport", fl ) +{ + setInited( false ); +} + + +wReport::~wReport() +{ +} + + + +void +wReport::initObject( aDatabase *adb ) +{ + aWidget::initObject( adb ); +// focusData()->next()->setFocus(); + +//CHECK_POINT +} + + +bool +wReport::checkStructure() +{ + + return false; +} + + + +QDialog* +wReport::createEditor( QWidget *parent ) +{ + return new eReport( parent ); +} + + +int +wReport::select( qulonglong id ) +{ + return 0; +} + + +qulonglong +wReport::insert() +{ + return 0; +} + + +int +wReport::update() +{ + return 0; +} + + +int +wReport::markDelete() +{ + return 0; +} + +ERR_Code +wReport::New() +{ + return err_abstractobj; +} + + +ERR_Code +wReport::Update() +{ + return err_abstractobj; +} + + +ERR_Code +wReport::TurnOn() +{ + return err_abstractobj; +} + + +ERR_Code +wReport::Select( qulonglong id ) +{ + return err_abstractobj; +} + +QString +wReport::displayString() +{ + return QString(""); +} + +qulonglong +wReport::uid() +{ + return 0; +} diff --git a/src/plugins/report/wreport.h b/src/plugins/report/wreport.h new file mode 100644 index 0000000..3bfe09f --- /dev/null +++ b/src/plugins/report/wreport.h @@ -0,0 +1,68 @@ +/**************************************************************************** +** $Id: wreport.h,v 1.1 2008/11/05 21:16:30 leader Exp $ +** +** Header file of the report plugin of Ananas +** Designer and Engine applications +** +** Created : 20031201 +** +** Copyright (C) 2003-2004 Leader InfoTech. All rights reserved. +** +** This file is part of the Ananas Plugins of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.leaderit.ru/page=ananas or email sales@leaderit.ru +** See http://www.leaderit.ru/gpl/ for GPL licensing information. +** +** Contact org@leaderit.ru if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#ifndef WREPORT_H +#define WREPORT_H +#include +#include "awidget.h" + +class QWidget; + +class QT_WIDGET_PLUGIN_EXPORT wReport : public aWidget +{ + Q_OBJECT +public: + wReport( QWidget *parent = 0, Qt::WFlags fl = 0 ); + virtual ~wReport(); + bool checkStructure(); + virtual void initObject( aDatabase *adb ); + virtual QDialog* createEditor( QWidget *parent ); + virtual QString displayString(); + virtual bool isContainer() { return true; }; + + virtual qulonglong uid(); + virtual ERR_Code New(); + virtual ERR_Code Update(); + virtual ERR_Code TurnOn(); + virtual ERR_Code Select( qulonglong id ); + +public slots: +// QVariant value( const QString &name ); +// void setValue( const QString &name, QVariant &value ); + int select( qulonglong id ); + qulonglong insert(); + int update(); + int markDelete(); + +private: + +}; + + +#endif // WREPORT_H diff --git a/src/plugins/report/wreport_plugin.cpp b/src/plugins/report/wreport_plugin.cpp new file mode 100644 index 0000000..a459eb7 --- /dev/null +++ b/src/plugins/report/wreport_plugin.cpp @@ -0,0 +1,100 @@ +/**************************************************************************** +** +** Code file +** +** Copyright (C) 2006 Dmitriy Pavlyuk +** +** This file is part of the Ananas Plugins of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +**********************************************************************/ + +#include "wreport_plugin.h" + +#include +#include +#include + +#include "wreport_taskmenu.h" +#include "wreport.h" + + +wReportPlugin::wReportPlugin(QObject *parent) + : QObject(parent), m_initialized(false) +{ + m_initialized = false; +} + +bool wReportPlugin::isContainer() const +{ + return true; +} + +bool wReportPlugin::isInitialized() const +{ + return m_initialized; +} + +void wReportPlugin::initialize(QDesignerFormEditorInterface *core) +{ + if (m_initialized) + return; + Q_UNUSED(core); + + QExtensionManager *manager = core->extensionManager(); + Q_ASSERT(manager != 0); + manager->registerExtensions(new wReportTaskMenuFactory(manager), + Q_TYPEID(QDesignerTaskMenuExtension)); + + m_initialized = true; +} + +QWidget *wReportPlugin::createWidget(QWidget *parent) +{ + wReport *w = new wReport(parent, 0); + return w; +} + +QString wReportPlugin::name() const +{ + return QLatin1String("wReport"); +} + +QString wReportPlugin::group() const +{ + return QLatin1String("Ananas"); +} + +QString wReportPlugin::toolTip() const +{ + return QString(); +} + +QString wReportPlugin::whatsThis() const +{ + return QString(); +} + +QString wReportPlugin::includeFile() const +{ + return QLatin1String("wreport.h"); +} + +QIcon wReportPlugin::icon() const +{ + //return QIcon(); + return QIcon(":/images/wreport.png"); +} + +QString wReportPlugin::domXml() const +{ + return "\n\n"; +} diff --git a/src/plugins/report/wreport_plugin.h b/src/plugins/report/wreport_plugin.h new file mode 100644 index 0000000..dec2604 --- /dev/null +++ b/src/plugins/report/wreport_plugin.h @@ -0,0 +1,53 @@ +/**************************************************************************** +** +** Header file +** +** Copyright (C) 2006 Dmitriy Pavlyuk +** +** This file is part of the Ananas Plugins of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +**********************************************************************/ + +#ifndef WREPORT_PLUGIN_H +#define WREPORT_PLUGIN_H + +#include + +#include "qwidgetplugin.h" + + +class QT_WIDGET_PLUGIN_EXPORT wReportPlugin : public QObject, public QDesignerCustomWidgetInterface +{ + Q_OBJECT + Q_INTERFACES(QDesignerCustomWidgetInterface) + +public: + wReportPlugin(QObject *parent=0); + + bool isContainer() const; + bool isInitialized() const; + void initialize(QDesignerFormEditorInterface *core); + QWidget *createWidget(QWidget *parent); + + QString name() const; + QString group() const; + QString toolTip() const; + QString whatsThis() const; + QString includeFile() const; + QIcon icon() const; + QString domXml() const; + +private: + bool m_initialized; +}; + +#endif // WREPORT_PLUGIN_H diff --git a/src/plugins/report/wreport_taskmenu.cpp b/src/plugins/report/wreport_taskmenu.cpp new file mode 100644 index 0000000..eda89d4 --- /dev/null +++ b/src/plugins/report/wreport_taskmenu.cpp @@ -0,0 +1,74 @@ +/**************************************************************************** +** +** Copyright (C) 2006 Dmitriy Pavlyuk All rights reserved. +** +** This file is part of the widgets plugin of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +****************************************************************************/ + +#include + +#include + +#include "wreport_taskmenu.h" +#include "wreport.h" +#include "ereport.h" + + +wReportTaskMenu::wReportTaskMenu(wReport *widget, QObject *parent) + : QObject(parent) +{ + m_widget = widget; + + m_editAction = new QAction(tr("Edit ..."), this); + connect(m_editAction, SIGNAL(triggered()), this, SLOT(edit())); +} + +void wReportTaskMenu::edit() +{ + /*eReport e; + + e.setData(m_widget); + if (e.exec() == QDialog::Accepted) + { + e.getData(m_widget); + }*/ + m_widget->widgetEditor(); +} + +QAction *wReportTaskMenu::preferredEditAction() const +{ + return m_editAction; +} + +QList wReportTaskMenu::taskActions() const +{ + QList list; + list.append(m_editAction); + return list; +} + +wReportTaskMenuFactory::wReportTaskMenuFactory(QExtensionManager *parent) + : QExtensionFactory(parent) +{ +} + +QObject *wReportTaskMenuFactory::createExtension(QObject *object, const QString &iid, QObject *parent) const +{ + if (iid != Q_TYPEID(QDesignerTaskMenuExtension)) + return 0; + + if (wReport *ob = qobject_cast(object)) + return new wReportTaskMenu(ob, parent); + + return 0; +} diff --git a/src/plugins/report/wreport_taskmenu.h b/src/plugins/report/wreport_taskmenu.h new file mode 100644 index 0000000..6f7f61d --- /dev/null +++ b/src/plugins/report/wreport_taskmenu.h @@ -0,0 +1,57 @@ +/**************************************************************************** +** +** Copyright (C) 2006 Dmitriy Pavlyuk All rights reserved. +** +** This file is part of the widgets plugin of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +****************************************************************************/ + +#ifndef WREPORT_TASKMENU_H +#define WREPORT_TASKMENU_H + +#include +#include + + +class QExtensionManager; +class QAction; +class wReport; + +class wReportTaskMenu: public QObject, public QDesignerTaskMenuExtension +{ + Q_OBJECT + Q_INTERFACES(QDesignerTaskMenuExtension) +public: + wReportTaskMenu(wReport *widget, QObject *parent); + + QAction *preferredEditAction() const; + QList taskActions() const; + +private slots: + void edit(); + +private: + QAction *m_editAction; + wReport *m_widget; +}; + +class wReportTaskMenuFactory: public QExtensionFactory +{ + Q_OBJECT +public: + wReportTaskMenuFactory(QExtensionManager *parent = 0); + +protected: + QObject *createExtension(QObject *object, const QString &iid, QObject *parent) const; +}; + +#endif // WREPORT_TASKMENU_H diff --git a/src/plugins/table/etable.cpp b/src/plugins/table/etable.cpp new file mode 100644 index 0000000..630aef7 --- /dev/null +++ b/src/plugins/table/etable.cpp @@ -0,0 +1,288 @@ +#include "etable.h" + +#include +#include +#include + +#include "ananas.h" +#include "wtable.h" + +/* + * Constructs a eTable as a child of 'parent', with the + * name 'name' and widget flags set to 'f'. + * + * The dialog will by default be modeless, unless you set 'modal' to + * true to construct a modal dialog. + */ +eTable::eTable(QWidget* parent, const char* name, bool modal, Qt::WindowFlags fl) + : QDialog(parent, name, modal, fl) +{ + setupUi(this); + + init(); +} + +/* + * Destroys the object and frees any allocated resources + */ +eTable::~eTable() +{ + destroy(); + // no need to delete child widgets, Qt does it all for us +} + +/* + * Sets the strings of the subwidgets using the current + * language. + */ +void eTable::languageChange() +{ + retranslateUi(this); +} + +void eTable::init() +{ +/* + int oc, i, f, idx=0; + char *id, *name, *ot; + cfg_objptr o; + char otype[100]; + QString named; + + CHECK_POINT + r = tablerow_new(0); + + otypes.clear(); + eType->clear(); + otypes.append("U"); + eType->insertItem(trUtf8("Текстовая метка"), idx++); + otypes.append("D"); + eType->insertItem(trUtf8("Дата"), idx++); + otypes.append("T"); + eType->insertItem(trUtf8("Время"), idx++); + otypes.append("N %d %d"); + eType->insertItem(trUtf8("Число"), idx++); + otypes.append("C %d"); + eType->insertItem(trUtf8("Строка"), idx++); + + oc=cfgobj_count(NULL, NULL); + for (i=1;i<=oc;i++) { + id=cfgobj_idn(NULL, NULL, i, &o); + ot=(char *)o->name; + name=cfgobj_attr(o, "name"); + named=""; + f=0; + if (strcmp((char *)ot, aot_doc)==0) { + named=trUtf8("Документ."); + f=1; + } + if (strcmp((char *)ot, aot_cat)==0) { + named=trUtf8("Справочник."); + f=1; + } + if (f) { + named=named+trUtf8(name); + sprintf(otype, "O %s", id); + otypes.append(otype); + eType->insertItem(named, idx++); + } + } + CHECK_POINT +*/ +} + + +void +eTable::destroy() +{ +// tablerow_free( r ); +} + + + +void eTable::insertColumn(const char *Header, const char *Name, +int idxt, int cw, int tw, int td) +{ +/* + tablefield *f; + char s[30]; + + sprintf(s, "%s %i %i", (const char *)otypes[idxt], tw, td); + + f = tablefield_newsys(Name, s, ""); + tablefield_setheader(f, Header); + f->sizex = cw; + f->flen = tw; + f->decimals = td; + f->ftypeindex = idxt; + tablerow_insertcolumn(r, f, -1); + +// blockSignals( true ); + ListCol->insertItem(trUtf8(Header)); +// eColHeader->setText( trUtf8(Header)); +// eColName->setText(trUtf8(Name)); +// eColWidth->setValue(cw); +// eColTWidth->setValue(tw); +// eColTDec->setValue(td); +// blockSignals( false ); + if (ListCol->count()) ListCol->setCurrentItem(ListCol->count()-1); +*/ +} + + + +void eTable::ColumnAdd() +{ +// insertColumn("Новый", "Новый", 0, 0, 0, 0); +} + + +void eTable::ColumnDel() +{ +/* + int idx; + idx = ListCol->currentItem(); + if (ListCol->count() && idx != -1) { + tablerow_removecolumn( r, idx ); + ListCol->removeItem(idx); + } +*/ +} + + +void eTable::ColumnL() +{ + +} + + +void eTable::ColumnR() +{ + +} + + +void eTable::ColumnSel(int col) +{ +/* + tablefield *f; + + if (col >= 0 && col < tablerow_columns( r )) { + f = tablerow_column( r, col ); + blockSignals( true ); + eColHeader->setText(trUtf8(tablefield_header( f ))); + eColWidth->setValue(f->sizex); + eType->setCurrentItem(f->ftypeindex); + eColName->setText(trUtf8(f->name)); + eColTWidth->setValue(f->flen); + eColTDec->setValue(f->decimals); + blockSignals( false ); + } +*/ +} + + +void eTable::ColumnUpd() +{ +/* + tablefield *f; + + if (signalsBlocked()) return; + int idx = ListCol->currentItem(); + + if ( idx >= 0 && idx < tablerow_columns( r )) { + f = tablerow_column( r, idx ); + if (f->name) free(f->name); + f->name=strdup((const char *) eColName->text().utf8()); + tablefield_setheader( f, (const char *) eColHeader->text().utf8()); + f->sizex = eColWidth->value(); + f->flen = eColTWidth->value(); + f->decimals = eColTDec->value(); + f->ftypeindex = eType->currentItem(); + + printf("set w=%i l=%i d=%i ti=%i\n", f->sizex, f->flen, + f->decimals, f->ftypeindex); + ListCol->blockSignals( TRUE ); + ListCol->changeItem(eColHeader->text(), idx); + ListCol->blockSignals( FALSE ); + } + CHECK_POINT +*/ +} + + +void eTable::setData( QWidget *o, aCfg *md ) +{ + + QStringList sl; + unsigned int i; + QString ft,h,n; + int w=0, l=0, d=0, idxt=0; + char st[20]; + + wTable *t = (wTable *) o; + //--eTabName->setText(t->getName()); + eTabName->setText(t->objectName()); +/* + if (!t->getDefineCols().isEmpty()) { + sl = QStringList::split("\n",t->getDefineCols()); + for (i = 0; i < sl.count(); i++) { + sscanf((const char *)sl[i].section("|",3,3),"%s %d %d", st, &l, &d); + if (st[0]=='O') ft.sprintf("O %d",l); + else ft=st; + w = sl[i].section("|",2,2).toInt(); + h = sl[i].section("|",5,5); + n = sl[i].section("|",4,4); + for (idxt = otypes.count()-1; idxt>0; idxt--) { + if (ft[0]=='O' && otypes[idxt]==ft) break; + else if (otypes[idxt][0]==ft[0]) break; + } + printf("set data %i = %s %s %i %i %i\n", i, + (const char *)h, (const char *)n, idxt, w, l); + insertColumn(h,n,idxt,w,l,d); + } + } +*/ +} + + +void eTable::getData( QWidget *o ) +{ + wTable *t = (wTable *) o; +/* + int i; + QStringList sl; + QString cdef, ft, s; + tablefield *f; + + t->vTable->setNumCols(ListCol->count()); + for (i=0;iftypeindex],f->flen,f->decimals); + cdef.sprintf("%i|%i|%i|%s|%s|%s",i,0, f->sizex, + (const char *) ft, f->name, + tablefield_header( f )); + s = s + cdef +"\n"; + } +// t->vTable->setColumnLabels(sl); + t->setName(eTabName->text()); + CHECK_POINT + printf("getData defs = %s\n",(const char *)s.utf8()); + t->setDefineCols(s); +*/ + t->setName(eTabName->text()); +} + + +void eTable::ColumnTextUpd( const QString &s ) +{ +/* + int idx; + idx = ListCol->currentItem(); + if (idx == -1) return; + ListCol->blockSignals( TRUE ); + ListCol->changeItem(s, ListCol->currentItem()); + ListCol->blockSignals( FALSE ); + CHECK_POINT +*/ +} diff --git a/src/plugins/table/etable.h b/src/plugins/table/etable.h new file mode 100644 index 0000000..497046b --- /dev/null +++ b/src/plugins/table/etable.h @@ -0,0 +1,38 @@ +#ifndef ETABLE_H +#define ETABLE_H + +#include "ui_etable.h" + + +class eTable : public QDialog, public Ui::eTable +{ + Q_OBJECT + +public: + eTable(QWidget* parent = 0, const char* name = 0, bool modal = false, Qt::WindowFlags fl = 0); + ~eTable(); + +public slots: + virtual void insertColumn( const char * Header, const char * Name, int idxt, int cw, int tw, int td ); + virtual void ColumnAdd(); + virtual void ColumnDel(); + virtual void ColumnL(); + virtual void ColumnR(); + virtual void ColumnSel( int col ); + virtual void ColumnUpd(); + virtual void setData( QWidget * o, aCfg * md ); + virtual void getData( QWidget * o ); + virtual void ColumnTextUpd( const QString & s ); + +protected slots: + virtual void languageChange(); + +private: + QStringList otypes, ftype, fname, cwidth; + + virtual void init(); + virtual void destroy(); + +}; + +#endif // ETABLE_H diff --git a/src/plugins/table/etable.ui b/src/plugins/table/etable.ui new file mode 100644 index 0000000..fa779c4 --- /dev/null +++ b/src/plugins/table/etable.ui @@ -0,0 +1,297 @@ + + + + + eTable + + + + 0 + 0 + 510 + 318 + + + + Form table + + + + + + List of columns + + + + + + 1 + + + 0 + + + 1 + + + + + + + + + + Table name + + + false + + + + + + + OK + + + true + + + + + + + 30 + + + + + + + Table column + + + + + + Header + + + false + + + + + + + Width + + + false + + + + + + + Field type + + + false + + + + + + + Field name + + + false + + + + + + + View width + + + false + + + + + + + decimals + + + false + + + + + + + Add + + + + + + + Up + + + + + + + Down + + + + + + + Remove + + + + + + + 9999 + + + + + + + 255 + + + + + + + 9 + + + + + + + 100 + + + + + + + 300 + + + + + + + + + + + + + Cancel + + + + + + + qPixmapFromMimeSource + + ananas.h + + + + bOK + clicked() + eTable + accept() + + + bCancel + clicked() + eTable + reject() + + + bColAdd + clicked() + eTable + ColumnAdd() + + + bColDel + clicked() + eTable + ColumnDel() + + + bColL + clicked() + eTable + ColumnL() + + + bColR + clicked() + eTable + ColumnR() + + + ListCol + highlighted(int) + eTable + ColumnSel(int) + + + eColHeader + textChanged(QString) + eTable + ColumnUpd() + + + eType + activated(int) + eTable + ColumnUpd() + + + eColName + textChanged(QString) + eTable + ColumnUpd() + + + eColWidth + valueChanged(QString) + eTable + ColumnUpd() + + + eColTWidth + valueChanged(QString) + eTable + ColumnUpd() + + + eColTDec + valueChanged(QString) + eTable + ColumnUpd() + + + diff --git a/src/plugins/table/table.pri b/src/plugins/table/table.pri new file mode 100644 index 0000000..ffedd6e --- /dev/null +++ b/src/plugins/table/table.pri @@ -0,0 +1,13 @@ +HEADERS += \ + table/etable.h \ + table/wtable.h \ + table/wtable_plugin.h + +SOURCES += \ + table/etable.cpp \ + table/wtable.cpp \ + table/wtable_plugin.cpp + +FORMS += \ + table/etable.ui + \ No newline at end of file diff --git a/src/plugins/table/wtable.cpp b/src/plugins/table/wtable.cpp new file mode 100644 index 0000000..6f52b42 --- /dev/null +++ b/src/plugins/table/wtable.cpp @@ -0,0 +1,216 @@ +/**************************************************************************** +** $Id: wtable.cpp,v 1.1 2008/11/05 21:16:30 leader Exp $ +** +** Code file of the table plugin of Ananas +** Designer and Engine applications +** +** Created : 20031201 +** +** Copyright (C) 2003-2004 Leader InfoTech. All rights reserved. +** Copyright (C) 2006 Grigory Panov , Yoshkar-Ola. +** +** This file is part of the Ananas Plugins of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.leaderit.ru/page=ananas or email sales@leaderit.ru +** See http://www.leaderit.ru/gpl/ for GPL licensing information. +** +** Contact org@leaderit.ru if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#include +#include +#include +#include +#include +#include +#include + +#include "acfg.h" +#include "aobject.h" +#include "awidget.h" +#include "wtable.h" + + + +wTable::wTable(QWidget *parent, const char * name):Q3Table(parent, name) +{ + +} + +wTable::~wTable() +{ +} + + +void +wTable::setDocument(int row, aObject *object) +{ +} + +void +wTable::setText(int row, int col, const QString& text) +{ + return Q3Table::setText(row, col,text); +} + + +QString +wTable::text(int col, int row) +{ + return Q3Table::text(col,row); +} + +void +wTable::setHeaderText(int col, const QString& text) +{ + Q3Table::horizontalHeader()->setLabel( col, text ); +} + + +QString +wTable::textHeader(int col) +{ + return Q3Table::horizontalHeader()->label(col); +} + +void +wTable::sortColumn ( int col, bool ascending, bool wholeRows ) +{ + printf("do sort column\n"); + Q3Table::sortColumn( col, ascending, true ); +} + + +void +wTable::setColumnWidth(int col, int width) +{ + Q3Table::setColumnWidth(col,width); +} + + +int +wTable::columnWidth(int col) +{ + return Q3Table::columnWidth(col); +} + +void +wTable::setNumCols ( int r ) +{ + Q3Table::setNumCols(r); +} + +int +wTable::numCols () const +{ + int res = Q3Table::numCols();// - 1; + return res; +} +void +wTable::hideColumn ( int col ) +{ + Q3Table::hideColumn ( col ); +} + +void +wTable::showColumn ( int col ) +{ + Q3Table::showColumn ( col ); +} +/* +bool +wTable::isColumnHidden ( int col ) const +{ +// int i = -2; +// if(col>=0) i=col; + return QTable::isColumnHidden ( col ); +} +*/ +void +wTable::adjustColumn ( int col ) +{ + return Q3Table::adjustColumn ( col ); +} + +void +wTable::setColumnStretchable ( int col, bool stretch ) +{ + return Q3Table::setColumnStretchable ( col, stretch ); +} + +bool +wTable::isColumnStretchable ( int col ) const +{ + return Q3Table::isColumnStretchable ( col ); +} + + +void +wTable::swapColumns ( int col1, int col2, bool swapHeader ) +{ + Q3Table::swapColumns( col1, col2, swapHeader ); + +} + +void +wTable::swapCells ( int row1, int col1, int row2, int col2 ) +{ + Q3Table::swapCells( row1, col1, row2, col2 ); +} + +void +wTable::setCurrentCell ( int row, int col ) +{ + Q3Table::setCurrentCell( row, col ); +} + +void +wTable::setColumnReadOnly ( int col, bool ro ) +{ + Q3Table::setColumnReadOnly( col, ro ); +} + +void +wTable::insertColumns ( int col, int count ) +{ + Q3Table::insertColumns( col, count ); +} + +void +wTable::removeColumn ( int col ) +{ + Q3Table::removeColumn( col ); +} + +void +wTable::editCell ( int row, int col, bool replace ) +{ + Q3Table::editCell( row, col, replace ); +} + +void +wTable::columnClicked ( int col ) +{ +// int i = -2; +// if(col>=0) i=col; + Q3Table::columnClicked ( col );//i-1 ); +} +void +wTable::swapRows ( int row1, int row2, bool swapHeader ) +{ + Q3Table::swapRows ( row1, row2,swapHeader ); +} + + + diff --git a/src/plugins/table/wtable.h b/src/plugins/table/wtable.h new file mode 100644 index 0000000..a550587 --- /dev/null +++ b/src/plugins/table/wtable.h @@ -0,0 +1,115 @@ +/**************************************************************************** +** $Id: wtable.h,v 1.1 2008/11/05 21:16:30 leader Exp $ +** +** Header file of the table plugin of Ananas +** Designer and Engine applications +** +** Created : 20031201 +** +** Copyright (C) 2003-2004 Leader InfoTech. All rights reserved. +** Copyright (C) 2006 Grigory Panov , Yoshkar-Ola. +** +** This file is part of the Ananas Plugins of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.leaderit.ru/page=ananas or email sales@leaderit.ru +** See http://www.leaderit.ru/gpl/ for GPL licensing information. +** +** Contact org@leaderit.ru if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#ifndef WTABLE_H +#define WTABLE_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include "acfg.h" +#include "aobject.h" +#include "awidget.h" + +/*! + * \en + * \brief Object for view and edit tabel in aTable object. + * \_en + * \ru + * \brief Плагин - виджет для редактирования табличных данных, не хранящихся в бизнес объектах Ананаса. + * Наследует QTable. + * + * В отличие от wDBTable wTable не сохряняет редактируемые в нем данные автоматически + * в persistent бизнес объектах Ананаса. Программист самостоятельно + * должен закодировать на Ананас.Скрипте логику заполнения виджета данными и использования данных, вводимых + * пользователем. + * + * \_ru + */ + + +class QT_WIDGET_PLUGIN_EXPORT wTable : public Q3Table +{ + Q_OBJECT + +public: + + wTable(QWidget* parent, const char * name); + virtual ~wTable(); +public slots: + virtual void setDocument(int row, aObject *object); + void setText(int row, int col, const QString& text); + QString text(int col, int row); + void setHeaderText(int col, const QString& text); + QString textHeader(int col); + virtual void sortColumn ( int col, bool ascending = TRUE, bool wholeRows = TRUE ); + virtual void setColumnWidth(int col, int width); + virtual int columnWidth(int col); + virtual void setNumCols ( int r ); + virtual int numCols () const ; + virtual void hideColumn ( int col ); + virtual void showColumn ( int col ); +// bool isColumnHidden ( int col ) const; + virtual void adjustColumn ( int col ); + virtual void setColumnStretchable ( int col, bool stretch ); + bool isColumnStretchable ( int col ) const; + virtual void swapColumns ( int col1, int col2, bool swapHeader = FALSE ); + virtual void swapCells ( int row1, int col1, int row2, int col2 ); + virtual void setCurrentCell ( int row, int col ); + virtual void setColumnReadOnly ( int col, bool ro ); + virtual void insertColumns ( int col, int count = 1 ); + virtual void removeColumn ( int col ); + virtual void editCell ( int row, int col, bool replace = FALSE ); + virtual void swapRows ( int row1, int row2, bool swapHeader = FALSE ); +signals: +// void pressed ( int row, int col, int button, const QPoint & mousePos ); +// void currentChanged ( int row, int col ); +// void clicked ( int row, int col, int button, const QPoint & mousePos ); +// void valueChanged ( int row, int col ); + +protected slots: + virtual void columnClicked ( int col ); + +private slots: +// void on_pressed ( int row, int col, int button, const QPoint & mousePos ); +// void on_currentChanged ( int row, int col ); +// void on_clicked ( int row, int col, int button, const QPoint & mousePos ); +// void on_valueChanged ( int row, int col ); +protected: + virtual void activateNextCell () {} ; + +}; + +#endif diff --git a/src/plugins/table/wtable_plugin.cpp b/src/plugins/table/wtable_plugin.cpp new file mode 100644 index 0000000..cbc53bc --- /dev/null +++ b/src/plugins/table/wtable_plugin.cpp @@ -0,0 +1,91 @@ +/**************************************************************************** +** +** Code file +** +** Copyright (C) 2006 Dmitriy Pavlyuk +** +** This file is part of the Ananas Plugins of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +**********************************************************************/ + +#include "wtable_plugin.h" + +#include + +#include "wtable.h" + + +wTablePlugin::wTablePlugin(QObject *parent) + : QObject(parent), m_initialized(false) +{ + m_initialized = false; +} + +bool wTablePlugin::isContainer() const +{ + return false; +} + +bool wTablePlugin::isInitialized() const +{ + return m_initialized; +} + +void wTablePlugin::initialize(QDesignerFormEditorInterface *core) +{ + if (m_initialized) + return; + Q_UNUSED(core); + m_initialized = true; +} + +QWidget *wTablePlugin::createWidget(QWidget *parent) +{ + wTable *w = new wTable(parent, 0); + return w; +} + +QString wTablePlugin::name() const +{ + return QLatin1String("wTable"); +} + +QString wTablePlugin::group() const +{ + return QLatin1String("Ananas"); +} + +QString wTablePlugin::toolTip() const +{ + return QString("Ananas for QT Table Widget"); +} + +QString wTablePlugin::whatsThis() const +{ + return QString("Entry to modify tables values of Ananas's object"); +} + +QString wTablePlugin::includeFile() const +{ + return QLatin1String("wtable.h"); +} + +QIcon wTablePlugin::icon() const +{ + //return QIcon(); + return QIcon(":/images/wtable.png"); +} + +QString wTablePlugin::domXml() const +{ + return "\n\n"; +} diff --git a/src/plugins/table/wtable_plugin.h b/src/plugins/table/wtable_plugin.h new file mode 100644 index 0000000..b18a8c9 --- /dev/null +++ b/src/plugins/table/wtable_plugin.h @@ -0,0 +1,53 @@ +/**************************************************************************** +** +** Header file +** +** Copyright (C) 2006 Dmitriy Pavlyuk +** +** This file is part of the Ananas Plugins of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +**********************************************************************/ + +#ifndef WTABLE_PLUGIN_H +#define WTABLE_PLUGIN_H + +#include + +#include + + +class QT_WIDGET_PLUGIN_EXPORT wTablePlugin : public QObject, public QDesignerCustomWidgetInterface +{ + Q_OBJECT + Q_INTERFACES(QDesignerCustomWidgetInterface) + +public: + wTablePlugin(QObject *parent=0); + + bool isContainer() const; + bool isInitialized() const; + void initialize(QDesignerFormEditorInterface *core); + QWidget *createWidget(QWidget *parent); + + QString name() const; + QString group() const; + QString toolTip() const; + QString whatsThis() const; + QString includeFile() const; + QIcon icon() const; + QString domXml() const; + +private: + bool m_initialized; +}; + +#endif // WTABLE_PLUGIN_H diff --git a/src/src.pro b/src/src.pro new file mode 100644 index 0000000..e32d287 --- /dev/null +++ b/src/src.pro @@ -0,0 +1,8 @@ +TEMPLATE = subdirs +SUBDIRS += lib plugins +SUBDIRS += designer ananas admin +SUBDIRS += extensions + +#TRANSLATIONS = \ +# ../translations/ananas-en.ts \ +# ../translations/ananas-ru.ts diff --git a/src/test/main.cpp b/src/test/main.cpp new file mode 100644 index 0000000..24b0b78 --- /dev/null +++ b/src/test/main.cpp @@ -0,0 +1,47 @@ +/**************************************************************************** +** $Id: main.cpp,v 1.3 2008/12/06 22:16:55 leader Exp $ +** +** Tool for automatic running Ananas tests +** +** Created : 20051024 +** +** Copyright (C) 2008. Valery Grazhdankin , Moscow +** +** This file is part of the Designer application of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.leaderit.ru/page=ananas or email sales@leaderit.ru +** See http://www.leaderit.ru/gpl/ for GPL licensing information. +** +** Contact org@leaderit.ru if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#include "ananas.h" +#include +#include + +#include "testametadata.h" + +int main(int argc, char *argv[]) +{ + QApplication app(argc, argv); + int rc = 0; + +// TestQString test1; + TestAMetaData test2; + +// rc += QTest::qExec(&test1, argc, argv); + rc += QTest::qExec(&test2, argc, argv); + printf("\nTotal fails: %i\n",rc); + return rc; +} diff --git a/src/test/test.h b/src/test/test.h new file mode 100644 index 0000000..952cbfa --- /dev/null +++ b/src/test/test.h @@ -0,0 +1,45 @@ +/**************************************************************************** +** $Id: test.h,v 1.1 2008/11/19 20:20:16 leader Exp $ +** +** Tool for automatic running Ananas tests +** +** Created : 20081119 +** +** Copyright (C) 2008. Valery Grazhdankin , Moscow +** +** This file is part of the Designer application of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.leaderit.ru/page=ananas or email sales@leaderit.ru +** See http://www.leaderit.ru/gpl/ for GPL licensing information. +** +** Contact org@leaderit.ru if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#include +#include + +double rnd(double m=1); + + +double rnd(double m) +{ + double res; +#ifdef _Windows + res = rand()*m; +#else + res = random()*m; +#endif + return res; + +} diff --git a/src/test/test.pro b/src/test/test.pro new file mode 100644 index 0000000..fefd2e3 --- /dev/null +++ b/src/test/test.pro @@ -0,0 +1,20 @@ +TARGET = ananas4-test +include(../lib/lib.pri) +include(../plugins/plugins.pri) +include(../ananas.pri ) + +SOURCES += \ + main.cpp \ + testametadata.cpp + +HEADERS += \ + test.h \ + testametadata.h +TRANSLATES = + +CONFIG +=qtestlib +FORMS = +TEMPLATE =app +INCLUDEPATH += ../lib ../plugins +LIBS += -L$(QTDIR)/lib -lqsa -L../../lib -lananas4 +LIBS += -L../../lib/designer -lananasplugin4 -lqt4-qdataschema diff --git a/src/test/testametadata.cpp b/src/test/testametadata.cpp new file mode 100644 index 0000000..29ee89c --- /dev/null +++ b/src/test/testametadata.cpp @@ -0,0 +1,176 @@ +/**************************************************************************** +** $Id: testametadata.cpp,v 1.5 2008/12/15 22:22:48 leader Exp $ +** +** Tool for automatic running Ananas tests +** +** Created : 20081119 +** +** Copyright (C) 2008. Valery Grazhdankin , Moscow +** +** This file is part of the Designer application of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.leaderit.ru/page=ananas or email sales@leaderit.ru +** See http://www.leaderit.ru/gpl/ for GPL licensing information. +** +** Contact org@leaderit.ru if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#include "testametadata.h" +#include "ametadataioxml.h" +#include "ametafield.h" +#include "ananas.h" +#include + + +void TestAMetaData::initTestCase() +{ +// qDebug("TEST INIT"); +// md = new AMetaData(QString("КлассОбъекта"), fromUtf8("ИмяОбъекта"),); +// mdo = new AMetaObject(); +} + + + +void TestAMetaData::cleanupTestCase() +{ +// qDebug("TEST DONE"); +// delete md; +// delete mdo; +} + +/* +void TestAMetaData::toUpper_data() +{ + QTest::addColumn("string"); + QTest::addColumn("result"); + + QTest::newRow("all lower") << "hello" << "HELLO"; + QTest::newRow("mixed") << "Hello" << "HELLO"; + QTest::newRow("all upper") << "HELLO" << "HELLO"; +} + +void TestAMetaData::toUpper() +{ + QFETCH(QString, string); + QFETCH(QString, result); + + QCOMPARE(string.toUpper(), result); +} +*/ + +void TestAMetaData::testAMetaObject() +{ + QByteArray ba("1234567890АБВГД"); + QString ts = QString::fromUtf8("Проверочный текст UTF8"); + + AMetaObject *o = new AMetaObject(QString::fromUtf8("КлассОбъекта"), + QString::fromUtf8("ИмяОбъекта"), 0 ); + + o->setDescription( ts ); + QCOMPARE( o->description(), ts ); + + QCOMPARE( o->className(), QString::fromUtf8("КлассОбъекта")); + QCOMPARE( o->name(), QString::fromUtf8("ИмяОбъекта")); + + o->setId(123456); + QVERIFY( o->id()==123456); + + o->setAttr("String","String"); + o->setAttr("Int", 123456 ); + o->setText("Text", QString::fromUtf8("Проверочный текст")); + o->setRawdata("RAW1", ba ); + o->setRawdata("RAW2", ba ); + +// Test attr functions + QVERIFY( o->attrCount() == 2 ); + QVERIFY( o->attrExists("String") ); + QVERIFY( o->attrExists("Int") ); + QVERIFY( o->attrExists("IntX") == false ); + QVERIFY( o->attr("String") == "String" ); + QVERIFY( o->attr("Int") == 123456 ); + QVERIFY( o->attr( 0 ) == "String" ); + QVERIFY( o->attr( 1 ) == 123456 ); + QVERIFY( o->attr( -1 ) == QVariant() ); + QVERIFY( o->attr( 10 ) == QVariant() ); +// Test text functions + QVERIFY( o->textCount() == 1+1 ); + QVERIFY( o->textExists("Text") ); + QVERIFY( o->textExists("Text0") == false ); + QVERIFY( o->text("Text") == QString::fromUtf8("Проверочный текст") ); + QVERIFY( o->text( 1 ) == QString::fromUtf8("Проверочный текст") ); + QVERIFY( o->text( -1 ) == QString::null ); + QVERIFY( o->text( 10 ) == QString::null ); +// Test rawdata functions + QVERIFY( o->rawdataCount() == 2 ); + QVERIFY( o->rawdataExists("RAW1") ); + QVERIFY( o->rawdataExists("RAW2") ); + QVERIFY( o->rawdataExists("RAW3") == false ); + QVERIFY( o->rawdata("RAW1") == QString( ba.data() ) ); + QVERIFY( o->rawdata("RAW2") == QString( ba.data() ) ); + QVERIFY( o->rawdata( 0 ) == QString( ba.data() ) ); + QVERIFY( o->rawdata( 1 ) == QString( ba.data() ) ); + QVERIFY( o->rawdata( -1 ) == QByteArray() ); + QVERIFY( o->rawdata( 10 ) == QByteArray() ); + delete o; +} + + + +void TestAMetaData::testAMetaObjectGroup() +{ + AMetaObjectGroup *o = new AMetaObjectGroup( QString::fromUtf8("ИмяОбъекта") ); + + QCOMPARE( o->name(), QString::fromUtf8("ИмяОбъекта")); + delete o; +} + + + +void TestAMetaData::testAMetaData() +{ + AMetaData *o = new AMetaData(); + QCOMPARE( o->name(), QString("MetaData") ); + delete o; +} + + +void TestAMetaData::testAMetaField() +{ + AMetaField *o = new AMetaField(); + QCOMPARE( o->className(), QString("MetaField") ); + QCOMPARE( o->description(), QString("") ); + QCOMPARE( o->fieldType(), 0 ); + QCOMPARE( o->fieldSubType(), 0 ); + QCOMPARE( o->width(), 0 ); + QCOMPARE( o->notNull(), false ); + QCOMPARE( o->notNegative(), false ); + QCOMPARE( o->calcSumm(), false ); + delete o; +} + + +void TestAMetaData::testAMetaDataIOXML() +{ + AMetaDataIOXML *o = new AMetaDataIOXML(); + QString xml; + + QCOMPARE( o->write("test.cfg"), 0 ); + QCOMPARE( o->read("test1.cfg"), 0 ); + xml = o->text(); + QCOMPARE( o->write("test2.cfg"), 0 ); + QCOMPARE( o->read("test2.cfg"), 0 ); + QCOMPARE( xml, o->text() ); + //QCOMPARE( o->name(), QString("ROOT") ); + delete o; +} diff --git a/src/test/testametadata.h b/src/test/testametadata.h new file mode 100644 index 0000000..939ca8e --- /dev/null +++ b/src/test/testametadata.h @@ -0,0 +1,56 @@ +/**************************************************************************** +** $Id: testametadata.h,v 1.5 2008/12/15 22:22:48 leader Exp $ +** +** Tool for automatic running Ananas tests +** +** Created : 20081119 +** +** Copyright (C) 2008. Valery Grazhdankin , Moscow +** +** This file is part of the Designer application of the Ananas +** automation accounting system. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.leaderit.ru/page=ananas or email sales@leaderit.ru +** See http://www.leaderit.ru/gpl/ for GPL licensing information. +** +** Contact org@leaderit.ru if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#ifndef TESTAMETADATA_H +#define TESTAMETADATA_H +#include "ametadata.h" +#include + +class TestAMetaData: public QObject +{ + Q_OBJECT + +private slots: + void initTestCase(); + void cleanupTestCase(); + +// void toUpper_data(); +// void toUpper(); + + void testAMetaObject(); + void testAMetaObjectGroup(); + void testAMetaData(); + void testAMetaField(); + void testAMetaDataIOXML(); + +private: + AMetaObject *mdo; + AMetaData *md; +}; + +#endif diff --git a/translations/ananas-designer-en.ts b/translations/ananas-designer-en.ts new file mode 100644 index 0000000..8833822 --- /dev/null +++ b/translations/ananas-designer-en.ts @@ -0,0 +1,2061 @@ + + + CfgForm + + CfgForm + + + + Metadata + + + + Actions + + + + Interface + + + + Rights + + + + Languages + + + + Tag + + + + Name + + + + Translation file + + + + Add + + + + Remove + + + + Edit + + + + Clear dead aliases + + + + Image collection + + + + New + + + + &New + + + + Ctrl+N + + + + Open + + + + &Open... + + + + Ctrl+O + + + + Save + + + + &Save + + + + Ctrl+S + + + + Save As + + + + Save &As... + + + + Print + + + + &Print... + + + + Ctrl+P + + + + Exit + + + + E&xit + + + + ActionGroup + + + + Action + + + + Open image dialog + + + + New language + + + + Deleting row + + + + Delete '%1'? + + + + Yes + + + + No + + + + OK + + + + Saving changes + + + + Save changes %1? + + + + Cancel + + + + messageswindow + + + + Clearing dead aliases + + + + %1 dead aliases killed. + + + + Role name + + + + Description + + + + Clear dead roles + + + + New role + + + + Clearing dead roles + + + + %1 dead roles killed. + + + + Unable to write rc file. + + + + CfgForm readrc error + + + + Business scheme: + + + + CfgForm metadata root is null + + + + CfgForm metadata lang is null + + + + lang = %1 + + + + CfgForm %1 metadata lang is null + + + + + InterfaceTreeView + + &New Submenu + + + + New &Command + + + + New &Separator + + + + + MainForm + + Ananas: Designer + + + + &File + + + + &Edit + + + + Configuration + + + + Object + + + + &New + + + + Ctrl+N + + + + &Open... + + + + Ctrl+O + + + + &Save + + + + actFileSave + + + + Ctrl+S + + + + Save &as... + + + + &Print + + + + Ctrl+P + + + + E&xit + + + + Undo + + + + Ctrl+Z + + + + Redo + + + + Ctrl+Y + + + + Cut + + + + Ctrl+X + + + + Copy + + + + Ctrl+C + + + + Paste + + + + Ctrl+V + + + + Find + + + + Ctrl+F + + + + New + + + + Save + + + + ActionGroup + + + + New form + + + + Delete + + + + New field + + + + Rename + + + + Edit + + + + New table + + + + New in group + + + + Move Up + + + + Move Down + + + + New Group + + + + Action + + + + New Submenu + + + + New Command + + + + New Separator + + + + Clear dead aliases + + + + Add + + + + new item + + + + Image Collection + + + + &Help + + + + &About + + + + &Cascade + + + + &Tile + + + + Tile &horizontal + + + + Create new configuration + + + + Open configuration + + + + Tabs + + + + Вырезать + + + + Копировать + + + + Вставить + + + + Содержание + + + + &Содержание... + + + + Индекс + + + + &Индекс... + + + + О программе + + + + &О программе + + + + Конфигурация + + + + Save configuration + + + + Создать/обновить БД + + + + Новая кнопка + + + + Новый атрибут + + + + Новое поле + + + + Add new role + + + + Clear dead roles + + + + Edit role + + + + &Open + + + + &Windows + + + + About Ananas.Designer + + + + <h4>Ananas.Designer %1</h4> is a programm<br>for adjusting accounting automation system<br><br>Copyright 2003-2006 Leader Infotech, Valery Grazdankin <br>Copyright 2003-2006 Project Ananas, Andrey Paskal, Grigory Panov, Andrey Strelnikov<br>License: GPL<br><br>technical support:<br>lider-infotech@narod.ru<br>app@linux.ru.net<br>Web sites:<br><a href="http://ananas.lrn.ru">http://ananas.lrn.ru</a><br><a href="http://www.leaderit.ru">http://www.leaderit.ru</a><br><br>Avalable extensions:<br>%2 + + + + + PixmapPreview + + This is not a pixmap + + + + + QObject + + default + + + + Documents + + + + Init application + + + + Init forms designer + + + + Dialog forms designer + + + + Catalogues + + + + Reports + + + + Journals + + + + Information registers + + + + Accumulation registers + + + + Header + + + + Tables + + + + Forms + + + + Web forms + + + + Columns + + + + Resources + + + + Dimensions + + + + Information + + + + Element + + + + Group + + + + New field + + + + New document + + + + New catalogue + + + + New journal + + + + New information register + + + + New accumulation register + + + + New report + + + + New form + + + + New web form + + + + New Table + + + + ------------------- + + + + New Command + + + + New Popup menu + + + + New tool bar + + + + New Submenu + + + + Toolbars + + + + Main menu + + + + Popup menus + + + + New Action Group + + + + New Action + + + + Actions + + + + header + + + + New Column + + + + Elements list dialog + + + + Element dialog + + + + Group dialog + + + + embedded editor + + + + Unknown + + + + Numberic + + + + Ananas List View Item %1 is null + + + + Ananas List View Item swaping + + + + any files (*) + + + + New &Group + + + + New &Action + + + + + aAliasEditor + + Name + + + + + aMetadataTreeView + + &New + + + + + aRoleEditor + + Read + + + + Write + + + + Delete + + + + Turn On + + + + Turn Off + + + + + ananasTreeView + + <font color=darkblue><u><b>Context Menu</b></u></font> + + + + &Rename + + + + &Edit + + + + &Delete + + + + &MoveUp + + + + &MoveDown + + + + &SaveItem + + + + &LoadItem + + + + + dEditAReg + + Accumulating register + + + + Common + + + + Name: + + + + Description: + + + + Aliases + + + + Lang + + + + Name + + + + Accumulation register: + + + + + dEditAction + + Action + + + + Common + + + + Description: + + + + Name + + + + Type + + + + standart command + + + + user script + + + + Enabled icon + + + + ... + + + + X + + + + Disabled icon + + + + Execute + + + + Object + + + + Form + + + + new + + + + edit + + + + view + + + + execute + + + + Params + + + + Aliases + + + + Lang + + + + Action_2 + + + + Action: + + + + Open image dialog + + + + Choose an image + + + + external script + + + + File name + + + + + dEditCat + + Catalogue + + + + Common + + + + Name: + + + + Description: + + + + Aliases + + + + Lang + + + + Name + + + + Catalogue: + + + + Element string view + + + + Group string view + + + + Access + + + + Read + + + + Write + + + + + dEditCfg + + Common + + + + Name + + + + Author + + + + Date + + + + Description + + + + User + + + + Data base server user + + + + Data base password + + + + Data base type + + + + Unknown + + + + mysql + + + + postgres + + + + Data base server address + + + + Data base name + + + + Work directory + + + + Configuration file name + + + + Data base server port + + + + Global module + + + + MySQL + + + + Postgres + + + + Data base header + + + + Business scheme parameters + + + + Business scheme parameters: + + + + + dEditColumns + + Columns + + + + Name: + + + + Action + + + + Column: + + + + + dEditCommand + + Command + + + + Common + + + + Description: + + + + Hot Key: + + + + Ctrl + + + + Alt + + + + Shift + + + + 1 + + + + 2 + + + + 3 + + + + 4 + + + + 5 + + + + 6 + + + + 7 + + + + 8 + + + + 9 + + + + 0 + + + + A + + + + B + + + + C + + + + D + + + + E + + + + F + + + + G + + + + H + + + + I + + + + J + + + + K + + + + L + + + + M + + + + N + + + + O + + + + P + + + + Q + + + + R + + + + S + + + + T + + + + U + + + + V + + + + W + + + + X + + + + Y + + + + Z + + + + Type: + + + + Menu text + + + + Name: + + + + Actions + + + + Aliases + + + + Lang + + + + Name + + + + Command: + + + + + dEditDialog + + Form + + + + Common + + + + Description: + + + + Form file + + + + Module file + + + + Name + + + + Design + + + + View + + + + Module + + + + Aliases + + + + Lang + + + + Form: + + + + Form mode: + + + + Use for: + + + + Dialog + + + + New + + + + Edit + + + + Selection + + + + Read only + + + + Designer + + + + Preview + + + + dEditDialog edit form + + + + dEditDialog form file does not exists + + + + dEditDialog create form file from metadata + + + + dEditDialog create new form file from template + + + + dEditDialog open file %1 for write + + + + dEditDialog open file %1 for read from templates directory %2 + + + + dEditDialog file %1 not exists + + + + dEditDialog show formdesigner + + + + + dEditDoc + + Document + + + + Common + + + + Name + + + + Description: + + + + Module + + + + Aliases + + + + Document: + + + + String view + + + + Access + + + + Read + + + + Write + + + + + dEditField + + Field + + + + Common + + + + Name + + + + Description + + + + Aliases + + + + Lang + + + + Unknown + + + + Field: + + + + Sum + + + + Width + + + + Decimals + + + + Type + + + + Flags + + + + Sort + + + + Positive + + + + Not null + + + + Saldo source + + + + + dEditIReg + + Information register + + + + Common + + + + Name: + + + + Description: + + + + Aliases + + + + Lang + + + + Name + + + + Information register: + + + + Don't delete record in unconduct + + + + + dEditJournal + + Journal + + + + Common + + + + Name: + + + + Type: + + + + Special + + + + Othes + + + + Description: + + + + Aliases + + + + Documents + + + + Action + + + + Action_2 + + + + Journal: + + + + Access + + + + Read + + + + Write + + + + + dEditLang + + Language + + + + Common + + + + Tag: + + + + Name: + + + + Translation file: + + + + Language: + + + + + dEditReport + + Report + + + + Common + + + + Name: + + + + Description: + + + + Module + + + + Aliases + + + + Lang + + + + Name + + + + Report: + + + + + dEditRole + + Role + + + + Common + + + + Description: + + + + Name: + + + + Role: + + + + + dEditToolbar + + Form1 + + + + Common + + + + Description: + + + + Hot Key: + + + + Ctrl + + + + Alt + + + + Shift + + + + 1 + + + + 2 + + + + 3 + + + + 4 + + + + 5 + + + + 6 + + + + 7 + + + + 8 + + + + 9 + + + + 0 + + + + A + + + + B + + + + C + + + + D + + + + E + + + + F + + + + G + + + + H + + + + I + + + + J + + + + K + + + + L + + + + M + + + + N + + + + O + + + + P + + + + Q + + + + R + + + + S + + + + T + + + + U + + + + V + + + + W + + + + X + + + + Y + + + + Z + + + + Type: + + + + Name: + + + + Actions + + + + Aliases + + + + Lang + + + + Name + + + + Command: + + + + + dEditWebForm + + Web Form + + + + Common + + + + Description + + + + Name: + + + + Form editor + + + + Client module + + + + Server module + + + + Aliases + + + + Web form: + + + + diff --git a/translations/ananas-designer-ru.ts b/translations/ananas-designer-ru.ts new file mode 100644 index 0000000..05a03d3 --- /dev/null +++ b/translations/ananas-designer-ru.ts @@ -0,0 +1,2224 @@ + + + CfgForm + + CfgForm + + + + New + Новый + + + &New + &Новый + + + Ctrl+N + + + + Open + Открыть + + + &Open... + &Открыть... + + + Ctrl+O + + + + Save + Сохранить + + + &Save + &Сохранить + + + Ctrl+S + + + + Save As + Сохранить как + + + Save &As... + Сохранить &как ... + + + Print + Печать + + + &Print... + &Печать ... + + + Ctrl+P + + + + Exit + Выход + + + E&xit + В&ыход + + + ActionGroup + + + + Action + Действие + + + Configuration: + Бизнес схема: + + + Element + Элемент + + + Group + Группа + + + Saving changes + Сохранение изменений + + + Save changes %1? + Сохранить изменения в "%1"? + + + Yes + Да + + + No + Нет + + + Cancel + Отмена + + + Configuration + Конфигурация + + + Name + Имя + + + Object type + Тип объекта + + + Interface + Интерфейс + + + Command + Команда + + + Metadata + Метаданные + + + Actions + Действия + + + Rights + Права + + + Tag + Метка + + + Translation file + Файл перевода + + + Add + Добавить + + + Remove + Удалить + + + Edit + Редактировать + + + Clear dead aliases + Очистить лишние алиасы + + + Image collection + Коллекция картинок + + + Open image dialog + Выбрать каринку + + + New language + Новый язык + + + Deleting row + Удаление строки + + + Delete '%1'? + Удалить %1'? + + + OK + + + + messageswindow + + + + Languages + Языки + + + Clearing dead aliases + Очистка неиспользуемых псевдонимов + + + %1 dead aliases killed. + %1 псевдоним удален. + + + Role name + Название роли + + + Description + Описание + + + Clear dead roles + Убрать неиспользуемые роли + + + New role + Новая роль + + + Clearing dead roles + Удаление неиспользуемых ролей + + + %1 dead roles killed. + %1 убрано. + + + Unable to write rc file. + Невозможно записать rc файл. + + + CfgForm readrc error + CfgForm - Ошибка readrc + + + Business scheme: + Бизнес схема: + + + CfgForm metadata root is null + CfgForm - пустой корень метаданных + + + CfgForm metadata lang is null + CfgForm - lang в метаданных равен null + + + lang = %1 + lang = %1 + + + CfgForm %1 metadata lang is null + CfgForm - %1 lang в метаданных равен null + + + + InterfaceTreeView + + &New Submenu + Новое &подменю + + + New &Command + Новая &команда + + + New &Separator + Новый &разделитель + + + + MainForm + + Ctrl+N + + + + Ctrl+O + + + + actFileSave + + + + Ctrl+S + + + + Ctrl+P + + + + Ctrl+Z + + + + Ctrl+Y + + + + Ctrl+X + + + + Ctrl+C + + + + Ctrl+V + + + + Ctrl+F + + + + ActionGroup + + + + new item + новый элемент + + + Ananas: Configurator + Ананас: Конфигуратор + + + Configuration + Бизнес схема + + + Object + Объект + + + New + Новый + + + Open + Открыть + + + Save + Сохранить + + + Delete + Удалить + + + Rename + Переименовать + + + Edit + Редактировать + + + About Ananas configuration program + О программе настройки Ананаса + + + Ananas: Designer + Ананас.Дизайнер + + + &File + &Файл + + + &Edit + &Редактировать + + + &New + &Новый + + + &Open... + &Открыть... + + + &Save + &Сохранить + + + Save &as... + Сохранить &как ... + + + &Print + &Печать + + + E&xit + В&ыход + + + Undo + Отменить + + + Redo + Повторить + + + Cut + Вырезать + + + Copy + Скопировать + + + Paste + Вставить + + + Find + Найти + + + New form + Новая форма + + + New field + Новое поле + + + New table + Новая таблица + + + New in group + Новый в группе + + + Image Collection + Набор значков + + + &Windows + &Окна + + + &Help + &Помощь + + + &About + &О программе + + + &Cascade + &Каскадировать + + + &Tile + В &ряд + + + Tile &horizontal + В ряд &горизонтально + + + Move Up + Поднять + + + Move Down + Опустить + + + New Group + Новая Группа + + + Action + Действие + + + New Submenu + Новое подменю + + + New Command + Новая команда + + + New Separator + Новый разделитель + + + Clear dead aliases + Очистить лишние алиасы + + + Add + Добавить + + + <h4>Ananas configurator</h4> is a programm<br>for adjusting accounting automation system<br><br>Copyright 2003-2004 Leader Infotech,<br>Valery Grazdankin, Andrey Paskal.<br>License: GPL<br><br>technical support:<br>lider-infotech@narod.ru<br>app@linux.ru.net<br>Web sites:<br><a href="http://ananas.linux.ru.net">http://ananas.linux.ru.net</a><br><a href="http://www.leaderit.ru">http://www.leaderit.ru</a><br> + <h4>Ананас.Дизайнер</h4> программа<br>для настройки бизнес схем учетной системы<br><br>Copyright 2003-2005 Leader Infotech,<br>Валерий Гражданкин<br>Copyright 2003-2005, Проект Ананас, Андрей Паскаль.<br>Лицензия: GPL<br><br>тех.поддержка:<br>lider-infotech@narod.ru<br>app@linux.ru.net<br>Веб сайт:<br><a href="http://ananas.linux.ru.net">http://ananas.linux.ru.net</a><br><a href="http://www.leaderit.ru">http://www.leaderit.ru</a><br> + + + Index + Индекс + + + About + О программе + + + Create new configuration + Создать новую схему + + + Open configuration + Открыть схему + + + Save configuration changes + Сохранить изменения + + + Contents + Содержание + + + &Contents... + &Содержание... + + + &Index... + &Индекс... + + + Cteate/Update DB + Создать/обновить БД + + + New button + Новая кнопка + + + New attribute + Новый атрибут + + + New Field + Новое поле + + + Tabs + Закладки + + + Вырезать + + + + Копировать + + + + Вставить + + + + Содержание + + + + &Содержание... + &Содержание... + + + Индекс + + + + &Индекс... + &Индекс... + + + О программе + + + + &О программе + &О программе + + + Конфигурация + Бизнес схема + + + Save configuration + Сохранить схему + + + Создать/обновить БД + + + + Новая кнопка + + + + Новый атрибут + + + + Новое поле + + + + Add new role + Добавить новую роль + + + Clear dead roles + Убрать неиспользуемые роли + + + Edit role + Изменить роль + + + &Window + &Окно + + + Windows + Окна + + + Goto + Переход + + + &Open + &Открыть + + + <h4>Ananas configurator</h4> is a programm<br>for adjusting accounting automation system<br><br>Copyright 2003-2004 Leader Infotech,<br>Valery Grazdankin, Andrey Paskal.<br>License: GPL<br><br>technical support:<br>lider-infotech@narod.ru<br>app@linux.ru.net<br>Web sites:<br><a href="http://ananas.lrn.ru">http://ananas.lrn.ru</a><br><a href="http://www.leaderit.ru">http://www.leaderit.ru</a><br> + <h4>Ананас.Дизайнер</h4> это программа <br>для настройки бизнес схем.<br><br>Copyright 2003-2004 Leader Infotech,<br>Валерий Гражданкин, Андрей Паскаль.<br>Лицензия: GPL<br><br>техническая поддержка:<br>lider-infotech@narod.ru<br>app@linux.ru.net<br>Веб сайты:<br><a href="http://ananas.lrn.ru">http://ananas.lrn.ru</a><br><a href="http://www.leaderit.ru">http://www.leaderit.ru</a><br> + + + <h4>Ananas configurator %1</h4> is a programm<br>for adjusting accounting automation system<br><br>Copyright 2003-2004 Leader Infotech,<br>Valery Grazdankin, Andrey Paskal.<br>License: GPL<br><br>technical support:<br>lider-infotech@narod.ru<br>app@linux.ru.net<br>Web sites:<br><a href="http://ananas.lrn.ru">http://ananas.lrn.ru</a><br><a href="http://www.leaderit.ru">http://www.leaderit.ru</a><br> + <h4>Ананас.Дизайнер %1</h4> это программа <br>для настройки бизнес схем.<br><br>Copyright 2003-2006 Leader Infotech,<br>Валерий Гражданкин, Андрей Паскаль.<br>Лицензия: GPL<br><br>техническая поддержка:<br>lider-infotech@narod.ru<br>app@linux.ru.net<br>Веб сайты:<br><a href="http://ananas.lrn.ru">http://ananas.lrn.ru</a><br><a href="http://www.leaderit.ru">http://www.leaderit.ru</a><br> + + + About Ananas.Designer + О программе Ананас.Дизайнер + + + <h4>Ananas.Designer %1</h4> is a programm<br>for adjusting accounting automation system<br><br>Copyright 2003-2006 Leader Infotech, Valery Grazdankin, Copyright 2003-2006 Project Ananas, Andrey Paskal, Grigory Panov, Andrey Strelnikov<br>License: GPL<br><br>technical support:<br>lider-infotech@narod.ru<br>app@linux.ru.net<br>Web sites:<br><a href="http://ananas.lrn.ru">http://ananas.lrn.ru</a><br><a href="http://www.leaderit.ru">http://www.leaderit.ru</a><br> + <h4>Ананас.Дизайнер %1</h4> <br> +Ананас.Дизайнер - программа <br> +для настройки бизнес схем.<br> +Лицензия: GPL<br> +Copyright 2003-2006 Лидер Инфотех, Валерий Гражданкин<br> +Copyright 2003-2006 Проект Ананас, Андрей Паскаль, Григорий Панов, Андрей Стрельников<br> +<br> +<a href="http://ananas.lrn.ru">http://ananas.lrn.ru</a><br><a href="http://www.leaderit.ru">http://www.leaderit.ru</a><br> +<br>Доступные расширения:<br>%2 + + + <h4>Ananas.Designer %1</h4> is a programm<br>for adjusting accounting automation system<br><br>Copyright 2003-2006 Leader Infotech, Valery Grazdankin <br>Copyright 2003-2006 Project Ananas, Andrey Paskal, Grigory Panov, Andrey Strelnikov<br>License: GPL<br><br>technical support:<br>lider-infotech@narod.ru<br>app@linux.ru.net<br>Web sites:<br><a href="http://ananas.lrn.ru">http://ananas.lrn.ru</a><br><a href="http://www.leaderit.ru">http://www.leaderit.ru</a><br><br>Avalable extensions:<br>%2 + <h4>Ананас.Дизайнер %1</h4> <br> +Ананас.Дизайнер - программа для настройки бизнес схем.<br> +<br> +Лицензия: GPL<br> +Copyright 2003-2006 Лидер Инфотех, Валерий Гражданкин<br> +Copyright 2003-2006 Проект Ананас, Андрей Паскаль, Григорий Панов, Андрей Стрельников<br> +<br> +Техподдержка:<br> +lider-infotech@narod.ru<br> +app@linux.ru.net<br> +Сайты:<br> +<a href="http://ananas.lrn.ru">http://ananas.lrn.ru</a><br> +<a href="http://www.leaderit.ru">http://www.leaderit.ru</a><br> +<br> +Доступные расширения:<br> +%2 + + + + PixmapPreview + + This is not a pixmap + Это не картинка + + + + QObject + + Dialog forms designer + Редактор форм диалога + + + Catalogues + Справочники + + + Documents + Документы + + + Reports + Отчеты + + + Journals + Журналы + + + Information registers + Информационные регистры + + + Accumulation registers + Накопительные регистры + + + Header + Шапка + + + Tables + таблицы + + + Forms + Формы + + + Web forms + Веб-формы + + + Columns + Столбцы + + + Resources + Ресурсы + + + Dimensions + Измерения + + + Information + Информация + + + Element + Элемент + + + Group + Группа + + + New field + Новое поле + + + New document + Новый документ + + + New catalogue + Новый справочник + + + New journal + Новый журнал + + + New information register + Новый информационный регистр + + + New accumulation register + Новый накопительный регистр + + + New report + Новый отчет + + + New form + Новая форма + + + New web form + Новая веб-форма + + + New Table + Новая таблица + + + New Command + Новая команда + + + New Submenu + Новое подменю + + + Interface + Интерфейс + + + New Action Group + Новая группа действий + + + New Action + Новое действие + + + Actions + Действия + + + selection + выбор + + + default + предопределенный + + + Init application + Инициализация приложения + + + Init forms designer + Инициализация редактора форм + + + ------------------- + + + + New Popup menu + Новое всплывающее меню + + + New tool bar + Новая панель инструментов + + + Toolbars + Панели инструментов + + + Main menu + Главное меню + + + Popup menus + Всплывающие меню + + + header + заголовок + + + New Column + Новый столбец + + + Elements list dialog + Диалог списка элементов + + + Element dialog + Диалог элемента + + + Group dialog + Диалог Группы + + + embedded editor + Встроенный редактор + + + &Windows + &Окна + + + Unknown + Неизвестно + + + Numberic + Числовой + + + Ananas List View Item %1 is null + Элемент %1 списка равен null + + + Ananas List View Item swaping + Обмен пунктов списка + + + any files (*) + все файлы (*) + + + New &Group + Новая &Группа + + + New &Action + Новое &действие + + + + aAliasEditor + + Name + Имя + + + + aMetadataTreeView + + &New + &Новый + + + + aRoleEditor + + Read + Прочитать + + + Write + Записать + + + Delete + Удалить + + + Turn On + Включить + + + Turn Off + Выключить + + + + ananasTreeView + + <font color=darkblue><u><b>Context Menu</b></u></font> + <font color=darkblue><u><b>Контекстное меню</b></u></font> + + + &Rename + Пере&именовать + + + &Edit + &Редактировать + + + &Delete + &Удалить + + + &MoveUp + &Поднять + + + &MoveDown + &Опустить + + + &SaveItem + &Сохранить элемент в файл + + + &LoadItem + &Загрузить элемент из файла + + + + dEditAReg + + Accumulating register + Накопительный регистр + + + Common + Общий + + + Name: + Имя: + + + Description: + Описание: + + + Aliases + Псевдонимы + + + Lang + Язык + + + Name + Имя + + + Accumulation register: + Накопительный регистр: + + + + dEditAction + + Action + Действие + + + Common + Общий + + + Description: + Описание: + + + Name + Имя + + + Type + Тип + + + standart command + стандартная команда + + + user script + скрипт + + + Enabled icon + Значек при доступности + + + ... + ... + + + X + + + + Disabled icon + Значек при недоступности + + + Execute + Выполнить + + + Object + Объект + + + Params + Параметры + + + new + новый + + + edit + редактировать + + + execute + выполнить + + + Aliases + Псевдонимы + + + Lang + Язык + + + Action: + Действие: + + + Open image dialog + Выбрать картинку + + + Form + Форма + + + view + просмотр + + + Action_2 + + + + Choose an image + Выбрать изображение + + + external script + внешний скрипт + + + File name + Имя файла + + + + dEditCat + + Catalogue + Справочник + + + Common + Общий + + + Name: + Имя: + + + Description: + Описание: + + + Aliases + Псевдонимы + + + Lang + Язык + + + Name + Имя + + + Catalogue: + Справочник: + + + Element string view + Текстовое представление элемента + + + Group string view + Текстовое представление группы + + + Access + Доступ + + + Read + Читать + + + Write + Изменять + + + + dEditCfg + + mysql + + + + postgres + + + + MySQL + + + + Postgres + + + + Configuration parameters + Параметры схемы + + + Common + Общий + + + Name + Имя + + + Author + Автор + + + Date + Дата + + + Description + Описание + + + User + Пользователь + + + Data base server user + Пользователь сервера баз данных + + + Data base password + Пароль сервера баз данных + + + Data base type + Тип базы данных + + + Unknown + Неизвестно + + + Data base server address + Адрес сервера баз данных + + + Data base name + Имя базы данных + + + Work directory + Рабочий каталог + + + Configuration file name + Имя файла метаданных + + + Data base server port + Порт сервера баз данных + + + Global module + Глобальный модуль + + + Data base header + Заголовок базы данных + + + Configuration parameters: + Параметры схемы: + + + Business scheme parameters + Параметры бизнес схемы + + + Business scheme parameters: + Параметры бизнес схемы: + + + + dEditColumns + + Columns + Столбцы + + + Name: + Имя: + + + Action + Действие + + + Column: + Столбец: + + + + dEditCommand + + Command + Команда + + + Common + Общий + + + Description: + Описание: + + + Hot Key: + Клавиатурная комбинация: + + + Ctrl + + + + Alt + + + + Shift + + + + 1 + + + + 2 + + + + 3 + + + + 4 + + + + 5 + + + + 6 + + + + 7 + + + + 8 + + + + 9 + + + + 0 + + + + A + + + + B + + + + C + + + + D + + + + E + + + + F + + + + G + + + + H + + + + I + + + + J + + + + K + + + + L + + + + M + + + + N + + + + O + + + + P + + + + Q + + + + R + + + + S + + + + T + + + + U + + + + V + + + + W + + + + X + + + + Y + + + + Z + + + + Type: + Тип: + + + Name: + Имя: + + + Actions + Действия + + + Aliases + Псевдонимы + + + Lang + Язык + + + Name + Имя + + + Command: + Команда: + + + Menu text + Текст меню + + + + dEditDialog + + Form + Форма + + + Common + Общий + + + Name + Имя + + + Module file + Файл модуля + + + Form file + Файл формы + + + Description: + Описание: + + + Design + Дизайн + + + View + Просмотр + + + Module + Модуль + + + Aliases + Псевдонимы + + + Lang + Язык + + + Form: + Форма: + + + Default use for: + По умолчанию используется для: + + + no use + не использовать + + + create new + создать новый + + + view + просмотр + + + Form mode: + Режим формы: + + + Use for: + Использовать для: + + + Dialog + Диалог + + + New + Новый + + + Edit + Редактировать + + + Selection + Выбор + + + Read only + Только чтение + + + Designer + Редактор диалогов + + + Preview + Просмотр + + + dEditDialog edit form + Форма редактирования dEditDialog + + + dEditDialog form file does not exists + Не найден файл dEditDialog + + + dEditDialog create form file from metadata + dEditDialog - файл формы из метаданных + + + dEditDialog create new form file from template + dEditDialog - файл формы из шаблона + + + dEditDialog open file %1 for write + dEditDialog - редактируем файл %1 + + + dEditDialog open file %1 for read from templates directory %2 + dEditDialog - Открываем для чтения файл %1 из каталога шаблонов + + + dEditDialog file %1 not exists + dEditDialog - Файл %1 не найден + + + dEditDialog show formdesigner + dEditDialog - Открываем редактор диалогов + + + + dEditDoc + + Document + Документ + + + Common + Общий + + + Name + Имя + + + Description: + Описание: + + + Module + Модуль + + + Aliases + Псевдонимы + + + Document: + Документ: + + + String view + Текстовое представление + + + Access + Доступ + + + Read + Читать + + + Write + Изменять + + + + dEditField + + Field + Поле + + + Common + Общий + + + Name + Имя + + + Description + Описание + + + Aliases + Псевдонимы + + + Lang + Язык + + + Unknown + Неизвестно + + + Field: + Поле: + + + Sum + Сумма + + + Width + Ширина + + + Decimals + Десятичные + + + Type + Тип + + + Flags + Флаг + + + Sort + Сорт + + + Positive + Положительное + + + Not null + Не нулевое + + + Saldo source + Источник остатков + + + + dEditIReg + + Information register + Информационный регистр + + + Common + Общий + + + Name: + Имя: + + + Description: + Описание: + + + Aliases + Псевдонимы + + + Lang + Язык + + + Name + Имя + + + Information register: + Информационный регистр: + + + Don't delete record in unconduct + Не удалять записи при отмене проведения документа + + + + dEditJournal + + Journal + Журнал + + + Common + Общий + + + Name: + Имя: + + + Description: + Описание: + + + Aliases + Псевдонимы + + + Journal: + Журнал: + + + Type: + Тип: + + + Special + Специальный + + + Othes + Другой + + + Documents + Документы + + + Action + Действие + + + Action_2 + + + + Access + Доступ + + + Read + Читать + + + Write + Изменять + + + + dEditLang + + Language + Язык + + + Common + Общий + + + Tag: + Метка: + + + Name: + Имя: + + + Translation file: + Файл перевода: + + + Language: + Язык: + + + + dEditReport + + Report + Отчет + + + Common + Общий + + + Name: + Имя: + + + Description: + Описание: + + + Module + Модуль + + + Aliases + Псевдонимы + + + Lang + Язык + + + Name + Имя + + + Report: + Отчет: + + + + dEditRole + + Role + Роль + + + Common + Общий + + + Description: + Описание: + + + Name: + Имя: + + + Role: + Роль: + + + + dEditToolbar + + Form1 + + + + Common + Общий + + + Description: + Описание: + + + Hot Key: + Клавиатурная комбинация: + + + Ctrl + + + + Alt + + + + Shift + + + + 1 + + + + 2 + + + + 3 + + + + 4 + + + + 5 + + + + 6 + + + + 7 + + + + 8 + + + + 9 + + + + 0 + + + + A + + + + B + + + + C + + + + D + + + + E + + + + F + + + + G + + + + H + + + + I + + + + J + + + + K + + + + L + + + + M + + + + N + + + + O + + + + P + + + + Q + + + + R + + + + S + + + + T + + + + U + + + + V + + + + W + + + + X + + + + Y + + + + Z + + + + Type: + Тип: + + + Name: + Имя: + + + Actions + ДействияДействия + + + Aliases + Псевдонимы + + + Lang + Язык + + + Name + Имя + + + Command: + Команда: + + + + dEditWebForm + + Web Form + Веб-форма + + + Common + Общий + + + Description + Описание + + + Name: + Имя: + + + Form editor + Редактор форм + + + Client module + Модуль веб клиента + + + Server module + Модуль веб сервера + + + Aliases + Псевдонимы + + + Web form: + Веб-форма: + + + diff --git a/translations/ananas-engine-en.ts b/translations/ananas-engine-en.ts new file mode 100644 index 0000000..d7df61d --- /dev/null +++ b/translations/ananas-engine-en.ts @@ -0,0 +1,48 @@ + + + MainForm + + About + + + + &Help + + + + Ananas + + + + &Windows + + + + &Cascade + + + + &Tile + + + + Tile &horizontal + + + + About Ananas.Engine program + + + + <h4>Ananas.Engin %1</h4> is a programm<br>for executing application of accounting automation system<br><br>Copyright 2003-2006 Leader Infotech, Valery Grazdankin, Copyright 2003-2006 Project Ananas, Andrey Paskal, Grigory Panov, Andrey Strelnikov<br>License: GPL<br><br>technical support:<br>lider-infotech@narod.ru<br>app@linux.ru.net<br>Web sites:<br><a href="http://ananas.lrn.ru">http://ananas.lrn.ru</a><br><a href="http://www.leaderit.ru">http://www.leaderit.ru</a><br><br>Avalable extensions:<br>%2 + + + + + QObject + + Init application + + + + diff --git a/translations/ananas-engine-ru.ts b/translations/ananas-engine-ru.ts new file mode 100644 index 0000000..df55bf9 --- /dev/null +++ b/translations/ananas-engine-ru.ts @@ -0,0 +1,105 @@ + + + MainForm + + About + О программе + + + &Help + &Помощь + + + About Ananas engine program + О программе Ананас + + + <h4>Ananas engine</h4> is a programm<br>for executing application of accounting automation system<br><br>Copyright 2003-2004 Leader Infotech,<br>Valery Grazdankin, Andrey Pascal.<br>License: GPL<br><br>technical support:<br>lider-infotech@narod.ru<br>app@altlinux.ru<br>Web sites:<br><a href="http://ananas.linux.ru.net">http://ananas.linux.ru.net</a><br><a href="http://www.leaderit.ru">http://www.leaderit.ru</a><br> + <h4>Оболочка АНАНАС</h4> это программа<br>для выполнения приложений системы автоматизации учета<br><br>Права 2003-2004 Лидер ИнфоТех,<br>Валерий Гражданкин, Андрей Паскаль.<br>Лицензия: GPL<br><br>техническая поддержка:<br>lider-infotech@narod.ru<br>app@altlinux.ru<br>Веб сайты:<br><a href="http://ananas.linux.ru.net">http://ananas.linux.ru.net</a><br><a href="http://www.leaderit.ru">http://www.leaderit.ru</a><br> + + + Ananas + Ананас + + + <h4>Ananas engine</h4> is a programm<br>for executing application of accounting automation system<br><br>Copyright 2003-2004 Leader Infotech,<br>Valery Grazdankin, Andrey Paskal.<br>License: GPL<br><br>technical support:<br>lider-infotech@narod.ru<br>app@linux.ru.net<br>Web sites:<br><a href="http://ananas.linux.ru.net">http://ananas.linux.ru.net</a><br><a href="http://www.leaderit.ru">http://www.leaderit.ru</a><br> + <h4>Ананас</h4> +Ананас - платформа автоматизации учета.<br> +Лицензия: GPL<br> +Copyright 2003-2005 Лидер Инфотех, Валерий Гражданкин<br> +Copyright 2003-2005 Проект Ананас, Андрей Паскаль, Григорий Панов, Андрей Стрельников....<br> +<br> +<a href="http://ananas.lrn.ru">http://ananas.lrn.ru</a><br><a href="http://www.leaderit.ru">http://www.leaderit.ru</a><br> + + + Ananas + Ананас + + + &Windows + &Окна + + + <h4>Ananas engine</h4> is a programm<br>for executing application of accounting automation system<br><br>Copyright 2003-2004 Leader Infotech,<br>Valery Grazdankin, Andrey Paskal.<br>License: GPL<br><br>technical support:<br>lider-infotech@narod.ru<br>app@linux.ru.net<br>Web sites:<br><a href="http://ananas.lrn.ru">http://ananas.lrn.ru</a><br><a href="http://www.leaderit.ru">http://www.leaderit.ru</a><br> + <h4>Ананас</h4> +Ананас - платформа автоматизации учета.<br> +Лицензия: GPL<br> +Copyright 2003-2005 Лидер Инфотех, Валерий Гражданкин<br> +Copyright 2003-2005 Проект Ананас, Андрей Паскаль, Григорий Панов, Андрей Стрельников....<br> +<br> +<a href="http://ananas.lrn.ru">http://ananas.lrn.ru</a><br><a href="http://www.leaderit.ru">http://www.leaderit.ru</a><br> + + + &Cascade + &Каскадом + + + &Tile + &Черепицей + + + Tile &horizontal + Черепицей &горизонтально + + + <h4>Ananas engine %1</h4> is a programm<br>for executing application of accounting automation system<br><br>Copyright 2003-2004 Leader Infotech,<br>Valery Grazdankin, Andrey Paskal.<br>License: GPL<br><br>technical support:<br>lider-infotech@narod.ru<br>app@linux.ru.net<br>Web sites:<br><a href="http://ananas.lrn.ru">http://ananas.lrn.ru</a><br><a href="http://www.leaderit.ru">http://www.leaderit.ru</a><br><br>Avalable extensions:<br>%2 + <h4>Ананас %1</h4> +Ананас - платформа автоматизации учета.<br> +Лицензия: GPL<br> +Copyright 2003-2006 Лидер Инфотех, Валерий Гражданкин<br> +Copyright 2003-2006 Проект Ананас, Андрей Паскаль, Григорий Панов, Андрей Стрельников....<br> +<br> +<a href="http://ananas.lrn.ru">http://ananas.lrn.ru</a><br><a href="http://www.leaderit.ru">http://www.leaderit.ru</a><br> + + + About Ananas.Engine program + О программе Ананас + + + <h4>Ananas.Engin %1</h4> is a programm<br>for executing application of accounting automation system<br><br>Copyright 2003-2006 Leader Infotech, Valery Grazdankin, Copyright 2003-2006 Project Ananas, Andrey Paskal, Grigory Panov, Andrey Strelnikov<br>License: GPL<br><br>technical support:<br>lider-infotech@narod.ru<br>app@linux.ru.net<br>Web sites:<br><a href="http://ananas.lrn.ru">http://ananas.lrn.ru</a><br><a href="http://www.leaderit.ru">http://www.leaderit.ru</a><br><br>Avalable extensions:<br>%2 + <h4>Ананас %1</h4> +Ананас - платформа автоматизации учета.<br> +<br> +Лицензия: GPL<br> +Copyright 2003-2006 Лидер Инфотех, Валерий Гражданкин<br> +Copyright 2003-2006 Проект Ананас, Андрей Паскаль, Григорий Панов, Андрей Стрельников<br> +<br> +Техподдержка:<br> +lider-infotech@narod.ru<br> +app@linux.ru.net<br> +Сайты:<br> +<a href="http://ananas.lrn.ru">http://ananas.lrn.ru</a><br> +<a href="http://www.leaderit.ru">http://www.leaderit.ru</a><br> +<br> +Доступные расширения:<br> +%2 + + + + QObject + + Init application + Инициализация приложения + + + diff --git a/translations/ananas-lib-en.ts b/translations/ananas-lib-en.ts new file mode 100644 index 0000000..1eeaa55 --- /dev/null +++ b/translations/ananas-lib-en.ts @@ -0,0 +1,1518 @@ + + + HelpCfgForm + + Create busines shema + + + + Close + + + + Make group, item, set item paramert and press Ok button. See http://ananas.lrn.ru/index.php?title=Manual:Disigner for details + + + + + MessagesWindow + + Messages window + + + + + QObject + + Unknown + + + + Numberic + + + + Char + + + + Date + + + + Catalogue + + + + Document + + + + Journal + + + + Information Register + + + + Accumuliation Register + + + + Report + + + + Field + + + + Documents + + + + Element + + + + Group + + + + Header + + + + Boolean + + + + aDatabase drop field(s) %1 + + + + aDatabase add field(s) %1 + + + + aDatabase update field(s) %1 + + + + aDatabase query: %1 + + + + aDatabase text: %1 + + + + aDatabase database text: %1 + + + + aDatabase driver text: %1 + + + + aDataTable try set mdobject to null + + + + aDataTable get value of unknown field `%1' + + + + aDataTable get document prefix to `%1' + + + + aService copy: source file %1 not exist + + + + aService copy: replace destination file %1 + + + + aService copy: source file %1 open for read error + + + + aService copy: destination file %1 open for write error + + + + aService copy file %1 to %2 ok + + + + aTests file %1 not exists + + + + aTests file %1 not open for read + + + + Error read configuration line:%1 col:%2 %3 + + + + aDataTable clear filter + + + + aDataTable set filter %1='%2' + + + + aDataTable set filter %1='%2', %3 not exist + + + + + aARegister + + RecordDate + + + + Accumulation Register init + + + + Accumulation Register create main table + + + + Accumulation Register create saldo table + + + + Accumulation Register update + + + + Accumulation register convert datetime from string %1 + + + + Accumulation register not found table %1 + + + + Accumulation register set filter + + + + Accumulation register not found main table + + + + + aBackup + + Can't create temporary directory + + + + Can't connect to database + + + + Can't copy .cfg file + + + + Database import without errors + + + + Can't create directory %s + + + + Invalid resource file + + + + Can't write resource file + + + + Can't write file META-INF/manifest.xml + + + + Can't copy template file + + + + Data export done without errors + + + + Can't start zip + + + + Zip ended anormal + + + + Zip ended with code %1 + + + + Unable to start zip + + + + Zip ended with error + + + + Can't write content.xml + + + + aBackup create temporary directory %1 + + + + aBackup import data: unzip + + + + aBackup unzip + + + + aBackup filename = %1 + + + + aBackup workdir=%1 + + + + aBackup copy unzipped business schema file + + + + aBackup copy business schema file + + + + aBackup import data ok + + + + aBackup create temporary directory + + + + aBackup invalid *.rc file + + + + aBackup valid *.rc file + + + + aBackup template %1 %2 + + + + aBackup write %1 file + + + + aBackup dump base error + + + + aBackup bump base + + + + aBackup write manifest.xml + + + + aBackup zip archive + + + + aBackup export data ok + + + + aBackup start unzip + + + + aBackup unzip dead + + + + aBackup unzip normal + + + + aBackup zip start error + + + + aBackup zip dead + + + + aBackup dump tables ok + + + + aBackup init rc file %1 + + + + aBackup write content.xml + + + + aBackup dump base to xml compleet + + + + aBackup save xml %1 + + + + aBackup create manifest.xml + + + + aBackup delete file %1 + + + + aBackup delete directory %1 + + + + aBackup cleanup temporary files + + + + aBackup template dir `%1' not exists, try create + + + + aBackup create template dir `%1' fail + + + + aBackup create template dir `%1' + + + + aBackup template dir `%1' exists + + + + + aCManifest + + aCManifest save xml %1 + + + + aCManifest read file `%1' + + + + aCManifest read line: %1 column: %2 + + + + aCManifest invalid manifest + + + + + aCatGroup + + aCatGroup new group + + + + aCatGroup new group ok + + + + aCatGroup new group error %1 + + + + + aCatalogue + + aCatalogue delete ido=%1 + + + + aCatalogue update + + + + aCatalogue update groups error %1 + + + + aCatalogue update groups + + + + aCatalogue update elements error %1 + + + + aCatalogue select group id=%1 + + + + aCatalogue new group with id=%1 + + + + aCatalogue delete element with id=%1 + + + + aCatalogue delete group with id=%1 + + + + aCatalogue delete without selection + + + + aCatalogue update group + + + + + aCfg + + Bad configuration + + + + aCfg swap: first element is null + + + + aCfg swap: second element is null + + + + aCfg swap element himself + + + + aCfg swap: first parent null + + + + aCfg swap: second parent null + + + + aCfg swap elements with differernt parents + + + + Document + + + + Catalogue + + + + DocJournal + + + + Report + + + + InfoRegister + + + + AccumulationRegister + + + + Form + + + + aCfg saveOneObject: context save to file `%1' + + + + aCfg saveOneObject: context is null + + + + aCfg loadOneObject: invalid cfg file `%1' + + + + aCfg loadOneObject: invalid file name or not permission to file `%1' + + + + aLog setup new id for %1 + + + + aLog next id is %1 + + + + + aContainer + + aContainer unzip + + + + Can't create temporary directory + + + + aContainer create temporary directory %1 + + + + No manifest found! + + + + aContainer error copy file + + + + aContainer manifest is null + + + + Can't start unzip + + + + aContainer start unzip + + + + Unzip ended anormal + + + + aContainer unzip dead + + + + aContainer unzip normal + + + + Unzip ended with code %1 + + + + Unable to start zip + + + + aContainer zip start error + + + + Zip ended with error + + + + aContainer zip dead + + + + Zip ended with code %1 + + + + aContainer delete file %1 + + + + aContainer delete directory %1 + + + + + aDatabase + + Uniques table updated + + + + + Documents journal updated + + + + + Catalogue %s updated + + + + + Document %s updated + + + + + Can't open database connection + + + + + Users updated + + + + + Users roles updated + + + + + Roles updated + + + + + Rigths updated + + + + + Information registers %s updated + + + + + Accumulation registers %s updated + + + + + aDatabase open connection to %1 + + + + aDatabase drop database %1 + + + + aDatabase generate new unique number for object type %1 + + + + aDatabase generate new unique number %1 for objecttype %2 + + + + aDatabase get object type for unique id=%1 + + + + aDatabase check indices for %1 + + + + aDatabase search index %1 + + + + Catalogue %s processed + + + + + aDatabase catalogue %1 import + + + + aDatabase catalogue %1 export + + + + Document %s processed + + + + + aDatabase document %1 import + + + + aDatabase document %1 export + + + + Information registers %s processed + + + + + aDatabase information register %1 import + + + + aDatabase information register %1 export + + + + Accumulation registers %s processed + + + + + aDatabase accumulation register %1 import + + + + aDatabase accumulation register %1 export + + + + aDatabase export table: invalid XML file + + + + aDatabase import table: invalid XML file + + + + aDatabase import table: table %1 not exists + + + + aDatabase prepared for open connection to %1 + + + + aDatabase open connection failed, try create %1 + + + + aDatabase system database is open + + + + Can't create database + + + + + aDatabase create database %1 + + + + aDatabase open connection to %1 ok + + + + aDatabase import table: get table %1 + + + + + aDocJournal + + aDocJournal md object not exists + + + + aDocJournal columns not defined + + + + aDocJournal column defined + + + + aDocJournal invalid column define + + + + aDocJournal delete document with idd=%1 + + + + aDocJournal new document with idd=%1 + + + + aDocJournal generated next number for %1 is %2 + + + + aDocJournal document not found with idd=%1 + + + + aDocJournal document not found with number=%1 and type=%2 + + + + aDocJournal select document with number=%1 and md name=%2 + + + + + aDocument + + aDocument have no sysjournal + + + + aDocument new document + + + + aDocument select new table line number + + + + aDocument new table line number=%1 + + + + aDocument insert new table line + + + + aDocument delete from sysjournal + + + + aDocument delete from unicues + + + + aDocument delete table %1 + + + + aDocument delete table of conducted document + + + + aDocument deleted table not exist + + + + aDocument deleted table not selected + + + + aDocument delete table from info register + + + + aDocument delete table + + + + aDocument not selected + + + + aDocument table name is empty + + + + aDocument update error=%1 + + + + aDocument conducted table update + + + + aDocument conduct + + + + aDocument delete from accumulation register + + + + aDocument aObject::New() ended with error code = %1 + + + + aDocument metaobject is null=%1 + + + + aDocument new type = %1 + + + + aDocument New() error while added record in sysJournal =%1 + + + + Deprecated method call. aDocument::Conduct(...) + + + + Deprecated method call. aDocument::UnConduct() + + + + Deprecated method call. aDocument::IsConducted() + + + + aDocument::GetDocumentValue(...): Can't find aDocument + + + + + aIRegister + + aIRegister metaobject is null + + + + aIRegister deleted document have invalid idd + + + + aIRegister select period from %1 to %2 + + + + + aOOTemplate + + aOOTemplate temporary directory is %1 + + + + aOOTemplate create temporary directory %1 + + + + aOOTemplate start unzip + + + + aOOTemplate unzip dead + + + + aOOTemplate unzip normal + + + + aOOTemplate open + + + + aOOTemplate value for field %1 not setted + + + + aOOTemplate save %1 open for write + + + + aOOTemplate save working dir =%1 + + + + aOOTemplate start zip + + + + aOOTemplate zip dead + + + + aOOTemplate zip normal to %1 + + + + + aObject + + Table `%s' not found. + + + + + aObject have no database! + + + + aObject md object not found + + + + aObject table with name %1 not found + + + + aObject have no system field %1 + + + + aObject update error. Driver message: %1 + + + + aObject decode doc number %1 + + + + aObject decode doc number ok, pref=%1 num=%2 + + + + aObject table update: no table found with name %1 + + + + aObject display string context is null + + + + + aObjectList + + aObjectList have no database! + + + + aObjectList md object not found + + + + aObjectList have no system field %1 + + + + aObjectList display string context is null + + + + + aReport + + Warning + + + + aReport OpenOfficeExecutable not found in registery + + + + aReport OpenOfficeExecutable found %1 + + + + aReport OpenOfficeExecutable not found in ~/.ananas/configrc + + + + Unable to start OpenOffice (%1) + + + + aReport OpenOfficeExecutable set to %1 + + + + aReport working dir = %1 + + + + aReport name for template = %1 + + + + + aReportBrowser + + Print + + + + Print report + + + + + aTemplate + + aTemplate save file %1 + + + + + aWidget + + aWidget init widget %1 form mode %2 + + + + aWidget init: invalid database + + + + aWidget init: invalid meta object + + + + aWidget init: connect signals wDBTable + + + + aWidget invalid data source object + + + + aWidget widgetEditor: invalid metadata object + + + + aWidget table: invalid data source object + + + + aWidget new: invalid data source object + + + + aWidget select: invalid data source object + + + + aWidget update: invalid data source object + + + + aWidget value not fount widget with name %1 + + + + aWidget set value: not fount widget with name %1 + + + + aWidget doc Id: invalid data source object + + + + + dEditRC + + Resource file + + + + Data base header + + + + Data base name + + + + Data base server type + + + + Unknown + + + + mysql + + + + postgres + + + + Data base server address + + + + Data base server port + + + + Data base server user + + + + Data base server password + + + + Work directory + + + + Resource file name + + + + ... + + + + Configuration file name + + + + OK + + + + Cancel + + + + internal + + + + ananas config resource (*.rc) + + + + ananas config file (*.cfg) + + + + + dImportDB + + Resource file + + + + archive file + + + + Import + + + + any files (*) + + + + ananas business schema archiff file (*.bsa) + + + + + dLogin + + Ananas: Login + + + + Login name + + + + Password + + + + &Cancel + + + + Alt+C + + + + O&K + + + + Alt+K + + + + + dSelectDB + + Information base + + + + Select data base + + + + Name + + + + Resource file + + + + &OK + + + + &Delete + + + + &Cancel + + + + Alt+C + + + + &Help + + + + Alt+H + + + + New group + + + + save + + + + Delete item? + + + + confirm delete + + + + E&xit + + + + New &group + + + + Edi&t + + + + &Import + + + + &Export + + + + Backup + + + + Select item + + + + Please, select item for export + + + + Program + + + + Actions + + + + Service + + + + dSelectDB local settings not found + + + + dSelectDB read settings for group with name %1 + + + + dSelectDB save settings + + + + save settings local? + + + + dSelectDB business schema import + + + + dSelectDB restore: %1 + + + + dSelectDB backup ok + + + + dSelectDB backup: %1 + + + + New shema + + + + &New shema + + + + diff --git a/translations/ananas-lib-ru.ts b/translations/ananas-lib-ru.ts new file mode 100644 index 0000000..07a9771 --- /dev/null +++ b/translations/ananas-lib-ru.ts @@ -0,0 +1,1608 @@ + + + HelpCfgForm + + Create busines shema + Создание бизнес схемы + + + Close + Закрыть + + + Make group, item, set item paramert and press Ok button. See http://ananas.lrn.ru/index.php?title=Manual:Disigner for details + Создайте группу, элемент. Задайте параметры элемента, нажмите Ок. Смотрите описание на http://ananas.lrn.ru/index.php?title=Manual:Disigner + + + + MessagesWindow + + Messages window + Окно сообщений + + + + QObject + + Error read configuration line:%d col:%s %s + Ошибка чтения файла метаданных в строке:%d позиция:%s %s + + + Unknown + Неизвестный + + + Numberic + Число + + + Char + Символ + + + Date + Дата + + + Catalogue + Каталог + + + Document + Документ + + + Field + Поле + + + Journal + Журнал + + + Information Register + Информационный регистр + + + Accumuliation Register + Накопительный регистр + + + Report + Отчет + + + Documents + Документы + + + Element + Элементы + + + Group + Группа + + + Header + Заголовок + + + Boolean + Логический + + + aDatabase drop field(s) %1 + Удалены поля БД: %1 + + + aDatabase add field(s) %1 + Добавлены поля БД: %1 + + + aDatabase update field(s) %1 + Обновлены поля БД: %1 + + + aDatabase query: %1 + Запрос к БД: %1 + + + aDatabase text: %1 + Текст сообщения об ошибке при работе с БД: %1 + + + aDatabase database text: %1 + Текст сообщения об ошибке Сервера БД при работе с БД: %1 + + + aDatabase driver text: %1 + Текст сообщения об ошибке Драйвера при работе с БД: %1 + + + aDataTable try set mdobject to null + aDataTable Попытка установить значение mdobject в null + + + aDataTable get value of unknown field `%1' + aDataTable Попытка получения значения неизвестного поля `%1' + + + aDataTable get document prefix to `%1' + aDataTable Установка префикса документа : `%1' + + + aService copy: source file %1 not exist + aService copy: Исходный файл %1 не обнаружен + + + aService copy: replace destination file %1 + aService copy: Замена целевого файла при копировании: %1 + + + aService copy: source file %1 open for read error + aService copy: Ошибка открытия исходного файла %1 для чтения при копировании + + + aService copy: destination file %1 open for write error + aService copy: Ошибка открытия целевого файла %1 для записи + + + aService copy file %1 to %2 ok + aService: Файл %1 успешно скопирован в файл %2 + + + aTests file %1 not exists + aTests: Файл %1 не существует + + + aTests file %1 not open for read + aTests: Файл %1 невозможно открыть для чтения + + + Error read configuration line:%1 col:%2 %3 + Ошибка чтения конфигурации. Строка: %1, позиция: %2 %3 + + + aDataTable clear filter + aDataTable: Очистка фильтра + + + aDataTable set filter %1='%2' + aDataTable: Установка фильтра %1='%2' + + + aDataTable set filter %1='%2', %3 not exist + aDataTable: Установка фильтра %1='%2', %3 не существует + + + + aARegister + + Record Date + Дата записи + + + RecordDate + Дата записи + + + Accumulation Register init + Инициализация накопительного регистра + + + Accumulation Register create main table + Создание главной таблицы накопительного регистра + + + Accumulation Register create saldo table + Создание таблицы остатков накопительного регистра + + + Accumulation Register update + Обновление накопительного регистра + + + Accumulation register convert datetime from string %1 + Накопительный регистр: Конвертирование в тип ДатаВремя из строки %1 + + + Accumulation register not found table %1 + Накопительный регистр: Не найдена таблица %1 + + + Accumulation register set filter + Накопительный регистр: Установка фильтра + + + Accumulation register not found main table + Накопительный регистр: Не найдена главная таблица + + + + aBackup + + Can't create temporary directory + Не могу создать временную директорию + + + Can't connect to database + Не могу присоединиться к базе данных + + + Can't copy .cfg file + Не могу скопировать cfg файл + + + Database import without errors + Восстановление из резервной копии завершено без ошибок + + + Can't create directory %s + Не могу создать каталог %1 + + + Invalid resource file + Неправильный файл ресурса + + + Can't write resource file + Не могу записать файл ресурса + + + Can't write file META-INF/manifest.xml + Не могу записать файл META-INF/manifest.xml + + + Can't copy template file + Не могу записать файл шаблона + + + Data export done without errors + Резервная копия создана успешно + + + Can't start zip + Не могу запустить zip + + + Zip ended anormal + Запаковка завершилась с ошибкой + + + Zip ended with code %1 + Zip завершился с кодом %1 + + + Unable to start zip + Не могу запустить zip + + + Zip ended with error + Запаковка завершилась с ошибкой + + + Can't write content.xml + Не могу записать файл content.xml + + + aBackup create temporary directory %1 + aBackup: Создание временной папки %1 в файловой системе + + + aBackup import data: unzip + aBackup: Импорт данных: unzip + + + aBackup unzip + aBackup: Распаковка unzip + + + aBackup filename = %1 + aBackup: Имя файла = %1 + + + aBackup workdir=%1 + aBackup: Рабочая папка файловой системы =%1 + + + aBackup copy unzipped business schema file + aBackup: Копирование распакованного файла бизнес схемы + + + aBackup copy business schema file + aBackup: Копирование файла бизнес схемы + + + aBackup import data ok + aBackup: Успешно импортированы данные резервной копии + + + aBackup create temporary directory + aBackup: Создание временной папки в файловой системе + + + aBackup invalid *.rc file + aBackup: Ошибка в *.rc файле + + + aBackup valid *.rc file + aBackup: Нет ошибок в *.rc файле + + + aBackup template %1 %2 + aBackup: шаблон %1 %2 + + + aBackup write %1 file + aBackup: Запись файла %1 + + + aBackup dump base error + aBackup: Ошибка создания дампа БД + + + aBackup bump base + aBackup: Создание дампа БД + + + aBackup write manifest.xml + aBackup: Запись файла manifest.xml + + + aBackup zip archive + aBackup: zip архив + + + aBackup export data ok + aBackup: Успешно выполнен экспорт данных + + + aBackup start unzip + aBackup: Запуск распаковки unzip + + + aBackup unzip dead + aBackup: Ненормальное завершение распаковки zip + + + aBackup unzip normal + aBackup: Нормальное завершение распаковки zip + + + aBackup zip start error + aBackup: Ошибка запуска zip + + + aBackup zip dead + aBackup: Ненормальное завершение упаковки zip + + + aBackup dump tables ok + aBackup: Успешно создан дамп таблиц БД + + + aBackup init rc file %1 + aBackup: Файд инициализации (rc) %1 + + + aBackup write content.xml + aBackup: Запись файла content.xml + + + aBackup dump base to xml compleet + aBackup: Перенос дампа БД в xml файл завершен + + + aBackup save xml %1 + aBackup: Запись xml файла %1 + + + aBackup create manifest.xml + aBackup: Создание файла manifest.xml + + + aBackup delete file %1 + aBackup: Удаление файла %1 + + + aBackup delete directory %1 + aBackup: Удаление папки файловой системы %1 + + + aBackup cleanup temporary files + aBackup: Удаление временных файлов + + + aBackup template dir `%1' not exists, try create + aBackup: Папка `%1' не существует, пробуем создать + + + aBackup create template dir `%1' fail + aBackup: Не удалось создать временную папку `%1' в файловой системе + + + aBackup create template dir `%1' + aBackup: Создание временной папки `%1' в файловой системе + + + aBackup template dir `%1' exists + aBackup: Папка `%1' в файловой системе уже существует + + + + aCManifest + + aCManifest save xml %1 + aCManifest: Запись xml файла %1 + + + aCManifest read file `%1' + aCManifest: Чтение файла `%1 + + + aCManifest read line: %1 column: %2 + aCManifest: Чтение строки: %1 позиции: %2 + + + aCManifest invalid manifest + aCManifest: Ошибки в manifest файле + + + + aCatGroup + + aCatGroup new group + aCatGroup: Новая группа + + + aCatGroup new group ok + aCatGroup: Новая группа успешно создана + + + aCatGroup new group error %1 + aCatGroup: Ошибка при создании новой группы %1 + + + + aCatalogue + + aCatalogue delete ido=%1 + aCatalogue: Удаление ido=%1 + + + aCatalogue update + aCatalogue: Обновление + + + aCatalogue update groups error %1 + aCatalogue: Ошибка обновления групп: %1 + + + aCatalogue update groups + aCatalogue: Обновление групп + + + aCatalogue update elements error %1 + aCatalogue: Ошибка обновления элементов: %1 + + + aCatalogue select group id=%1 + aCatalogue: Выбор группы с идентификатором id=%1 + + + aCatalogue new group with id=%1 + aCatalogue: Новая группа с идентификатором id=%1 + + + aCatalogue delete element with id=%1 + aCatalogue: Удаление элемента с идентификатором id=%1 + + + aCatalogue delete group with id=%1 + aCatalogue: Удаление группы с идентификатором id=%1 + + + aCatalogue delete without selection + aCatalogue: Удаление без выбора + + + aCatalogue update group + aCatalogue: Обновление группы + + + + aCfg + + Bad configuration + Ошибка в файле бизнес схемы + + + aCfg swap: first element is null + aCfg swap: Первый элемент равен null + + + aCfg swap: second element is null + aCfg swap: Второй элемент равен null + + + aCfg swap element himself + aCfg: Замена элемента самим собой + + + aCfg swap: first parent null + aCfg swap: Первый родитель равен null + + + aCfg swap: second parent null + aCfg swap: Второй родитель равен null + + + aCfg swap elements with differernt parents + aCfg: Обмен элементов, имеющих разных родителей + + + Document + Документ + + + Catalogue + Каталог + + + DocJournal + Журнал документов + + + Report + Отчет + + + InfoRegister + Информационный регистр + + + AccumulationRegister + Накопительный регистр + + + Form + Форма + + + aCfg saveOneObject: context save to file `%1' + aCfg saveOneObject: Запись содержимого в файл `%1' + + + aCfg saveOneObject: context is null + aCfg saveOneObject: Содержимое равно null + + + aCfg loadOneObject: invalid cfg file `%1' + aCfg loadOneObject: Ошибка в cfg файле `%1' + + + aCfg loadOneObject: invalid file name or not permission to file `%1' + aCfg loadOneObject: Ошибка в имени файла, либо недостаточно прав для доступа к файлу `%1' + + + aLog setup new id for %1 + aLog setup: Новый идентификатор id для %1 + + + aLog next id is %1 + aLog: Следующий идентификатор равен %1 + + + + aContainer + + aContainer unzip + aContainer: Распаковка unzip + + + Can't create temporary directory + Не могу создать временную папку в файловой системе + + + aContainer create temporary directory %1 + aContainer: Не могу создать временную папку в файловой системе %1 + + + No manifest found! + Не найден файл manifest! + + + aContainer error copy file + aContainer: Ошибка копирования файла + + + aContainer manifest is null + aContainer: Файл manifest равен null + + + Can't start unzip + Не могу запустить unzip + + + aContainer start unzip + aContainer: Запуск unzip + + + Unzip ended anormal + Неудачное завершение распаковки unzip + + + aContainer unzip dead + aContainer: Ненормальное завершение распаковки unzip + + + aContainer unzip normal + aContainer: Нормальное завершение распаковки unzip + + + Unzip ended with code %1 + Unzip вернул код %1 + + + Unable to start zip + Не могу запустить zip + + + aContainer zip start error + aContainer: Ошибка запуска zip + + + Zip ended with error + Запаковка завершилась с ошибкой + + + aContainer zip dead + aContainer: Ненормальное завершение запаковки zip + + + Zip ended with code %1 + Zip завершился с кодом %1 + + + aContainer delete file %1 + aContainer: Удаление файла %1 + + + aContainer delete directory %1 + aContainer: Удаление папки %1 файловой системы + + + + aDatabase + + Can't open database connection + + Не могу установить соединение с сервером баз данных + + + Uniques table updated + + Обновлена таблица уникальных идентификаторов + + + Documents journal updated + + Обновлен журнал документов + + + Users updated + + Обновлена информация о пользователях + + + Users roles updated + + Обновлена информация о ролях + + + Roles updated + + Обновлены роли + + + Rigths updated + + Обновлена информация о правах + + + Catalogue %s updated + + Каталог %s обновлен + + + Document %s updated + + Документ %s обновлен + + + Information registers %s updated + + Информационный регистр %s обновлен + + + Accumulation registers %s updated + + Накопительный регистр %s обновлен + + + Can't open database connection with ananas_system + + Не могу установить соединение с базой данных ananas_system + + + Catalogue %s dump + + Каталог %s данные\n + + + aDatabase open connection to %1 + aDatabase: Открытие соединения с %1 + + + aDatabase drop database %1 + aDatabase: Удаление БД %1 + + + aDatabase generate new unique number for object type %1 + aDatabase: Создание нового уникального номера для объекта типа %1 + + + aDatabase generate new unique number %1 for objecttype %2 + aDatabase: Создание нового уникального номера %1 для объекта типа %2 + + + aDatabase get object type for unique id=%1 + aDatabase: Получение типа объекта по его уникальному идентификатору id=%1 + + + aDatabase check indices for %1 + aDatabase: Проверка индексов для %1 + + + aDatabase search index %1 + aDatabase: Поиск индекса %1 + + + Catalogue %s processed + + Каталог %s обработан + + + + aDatabase catalogue %1 import + aDatabase: Импорт каталога %1 + + + aDatabase catalogue %1 export + aDatabase: Экспорт каталога %1 + + + Document %s processed + + Документ %s обработан + + + aDatabase document %1 import + aDatabase: Импорт Документа %1 + + + aDatabase document %1 export + aDatabase: Экспорт документа %1 + + + Information registers %s processed + + Информационный регистр %s обработан + + + aDatabase information register %1 import + aDatabase: Импорт информационного регистра %1 + + + aDatabase information register %1 export + aDatabase: Экспорт информационного регистра %1 + + + Accumulation registers %s processed + + Накопительный регистр %s обработан + + + aDatabase accumulation register %1 import + aDatabase: Импорт накопительного регистра %1 + + + aDatabase accumulation register %1 export + aDatabase: Экспорт накопительного регистра %1 + + + aDatabase export table: invalid XML file + aDatabase: Эеспорт таблицы БД: Ошибки в XML файле + + + aDatabase import table: invalid XML file + aDatabase: Импорт таблицы БД: Ошибки в XML файле + + + aDatabase import table: table %1 not exists + aDatabase: Импорт таблицы БД: Таблица %1 не существует + + + aDatabase prepared for open connection to %1 + aDatabase: Готов к открытию соединения с % + + + aDatabase open connection failed, try create %1 + aDatabase: Ошибка открытия соединения, пытаюсь создать %1 + + + aDatabase system database is open + aDatabase: Системная БД открыта + + + Can't create database + + Не могу создать БД + + + aDatabase create database %1 + aDatabase: Создание БД %1 + + + aDatabase open connection to %1 ok + aDatabase: Успешное установление соединения с %1 + + + aDatabase import table: get table %1 + aDatabase: Импорт таблицы БД: Таблица %1 + + + + aDocJournal + + aDocJournal md object not exists + aDocJournal: Объект метаданных не существует + + + aDocJournal columns not defined + aDocJournal: Столбцы не определены + + + aDocJournal column defined + aDocJournal: Столбец определен + + + aDocJournal invalid column define + aDocJournal: Неверное определение столбца + + + aDocJournal delete document with idd=%1 + aDocJournal: Удаление документа с идентификатором idd=%1 + + + aDocJournal new document with idd=%1 + aDocJournal: Новый документ с идентификатором idd=%1 + + + aDocJournal generated next number for %1 is %2 + aDocJournal: Создан новый номер %2 для %1 + + + aDocJournal document not found with idd=%1 + aDocJournal: Документ с идентификатором idd=%1 не найден + + + aDocJournal document not found with number=%1 and type=%2 + aDocJournal: Документ с номером=%1 и типом=%2 не найден + + + aDocJournal select document with number=%1 and md name=%2 + aDocJournal: Выбор документа с номером=%1 и с заданным в метаданных именем=%2 + + + + aDocument + + aDocument have no sysjournal + aDocument: Нет системного журнала + + + aDocument new document + aDocument: Новый документ + + + aDocument select new table line number + aDocument Выбор новой строки таблицы + + + aDocument new table line number=%1 + aDocument: Номер новой строки таблицы=%1 + + + aDocument insert new table line + aDocument: Вставка новой строки таблицы + + + aDocument delete from sysjournal + aDocument: Удаление из системного журнала + + + aDocument delete from unicues + aDocument: Удаление из индекса уникальных идентификаторов + + + aDocument delete table %1 + aDocument: Удаление табличной части %1 + + + aDocument delete table of conducted document + aDocument: Удаление табличной части проведенного документа + + + aDocument deleted table not exist + aDocument: Нет табличных частей для удаления + + + aDocument deleted table not selected + aDocument: Удаляемая таблица не существует + + + aDocument delete table from info register + aDocument: Удаление связанных с табличной частью записей из информационного регистра + + + aDocument delete table + aDocument: Удаление табличной части документа + + + aDocument not selected + aDocument: Сначала выберите документ + + + aDocument table name is empty + aDocument: Пустое имя таблицы. Для удаления табличной части документа необходимо указать ее имя + + + aDocument update error=%1 + aDocument: Ошибка обновления документа=%1 + + + aDocument conducted table update + aDocument: Невозможно обновить табличную часть проведенного документа + + + aDocument conduct + aDocument: Проведение документа + + + aDocument delete from accumulation register + aDocument: Удаление из накопительного регистра + + + aDocument aObject::New() ended with error code = %1 + aDocument: aObject::New() вернул ошибку с кодом = %1 + + + aDocument metaobject is null=%1 + aDocument: Объект метаданных пуст =%1 + + + aDocument new type = %1 + aDocument: Тип нового документа = %1 + + + aDocument New() error while added record in sysJournal =%1 + aDocument: New() ошибка при добавлении в системный журнал =%1 + + + Deprecated method call. aDocument::Conduct(...) + Вызов устаревшего метода aDocument::Conduct(...) + + + Deprecated method call. aDocument::UnConduct() + Вызов устаревшего метода aDocument::UnConduct(...) + + + Deprecated method call. aDocument::IsConducted() + Вызов устаревшего метода aDocument::IsConduct(...) + + + aDocument::GetDocumentValue(...): Can't find aDocument + aDocument::GetDocumentValue(...): Невозможно найти документ + + + + aIRegister + + aIRegister metaobject is null + aIRegister: Объект метаданных = null + + + aIRegister deleted document have invalid idd + aIRegister: Неверный идентификатор (idd) удаляемого документа + + + aIRegister select period from %1 to %2 + aIRegister: Задание периода с %1 по %2 + + + + aOOTemplate + + aOOTemplate temporary directory is %1 + aOOTemplate: Временная папка файловой системы: %1 + + + aOOTemplate create temporary directory %1 + aOOTemplate: Создать временную папку файловой системы: %1 + + + aOOTemplate start unzip + aOOTemplate: Запуск unzip + + + aOOTemplate unzip dead + aOOTemplate: Ненормальное завершение распаковки unzip + + + aOOTemplate unzip normal + aOOTemplate: Нормальное завершение распаковки unzip + + + aOOTemplate open + aOOTemplate: Открываем + + + aOOTemplate value for field %1 not setted + aOOTemplate: Значение поля %1 не задано + + + aOOTemplate save %1 open for write + aOOTemplate: Ошибка записи %1 + + + aOOTemplate save working dir =%1 + aOOTemplate: Запись шаблона в рабочей папке %1 + + + aOOTemplate start zip + aOOTemplate: Запуск zip + + + aOOTemplate zip dead + aOOTemplate: Ненормальное завершение упаковки zip + + + aOOTemplate zip normal to %1 + aOOTemplate: Упаковка zip успешно завершена: %1 + + + + aObject + + Table `%s' not found. + + Таблица `%s' не найдена. + + + Table name is empty. + + Пустое имя таблицы. + + + aObject have no database! + aObject: Нет базы данных! + + + aObject md object not found + aObject: Объект метаданных не найден + + + aObject table with name %1 not found + aObject: Не найдена таблица %1 + + + aObject have no system field %1 + aObject: Не найдено системное поле %1 + + + aObject update error. Driver message: %1 + aObject: Ошибка обновления. Сообщение драйвера: %1 + + + aObject decode doc number %1 + aObject: Декодирование номера документа %1 + + + aObject decode doc number ok, pref=%1 num=%2 + aObject: Успешное декодирование номера документа, pref=%1 num=%2 + + + aObject table update: no table found with name %1 + aObject: Обновление таблицы: Таблица с именем %1 не найдена + + + aObject display string context is null + aObject: Содержимое строки для отображения равно null + + + + aObjectList + + aObjectList have no database! + aObjectList: Нет базы данных! + + + aObjectList md object not found + aObjectList: Объект метаданных не найден + + + aObjectList have no system field %1 + aObjectList: Не найдено системное поле %1 + + + aObjectList display string context is null + aObjectList: Содержимое строки для отображения равно null + + + + aReport + + Choose a OpenOffice executable file + Выберите исполняемый файл OpenOffice + + + Warning + Предупреждение + + + Unable to start OpenOffice + Невозможно запустить OpenOffice + + + aReport OpenOfficeExecutable not found in registery + aReport: Исполняемый файл OpenOffice в регистри не найден + + + aReport OpenOfficeExecutable found %1 + aReport: Исполняемый файл OpenOffice не найден: %1 + + + aReport OpenOfficeExecutable not found in ~/.ananas/configrc + aReport: Исполняемый файл OpenOffice не найден в ~/.ananas/configrc + + + Unable to start OpenOffice (%1) + Не могу запустит OpenOffice (%1) + + + aReport OpenOfficeExecutable set to %1 + aReport: Исполняемый файл OpenOffice определен как %1 + + + aReport working dir = %1 + aReport: Рабочая папка файловой системы = %1 + + + aReport name for template = %1 + aReport: Имя шаблона = %1 + + + + aReportBrowser + + Print + Печать + + + Print report + Печать отчета + + + + aTemplate + + aTemplate save file %1 + aTemplate: Запись файла %1 + + + + aWidget + + Error! Can't find widget by name==`%s` + + Ошибка! Не найден виджет с именем `%s' + + + aForm::SetValue() Error! Can't find widget by name==`%s` + + aForm::SetValue() Ошибка! Невозможно найти виджет с именем `%s` + + + aWidget init widget %1 form mode %2 + aWidget: Инициализация виджета %1: режим формы %2 + + + aWidget init: invalid database + aWidget: Инициализация: Не верно задана или недоступна БД + + + aWidget init: invalid meta object + aWidget: Инициализация: Неправильный объект метаданных + + + aWidget init: connect signals wDBTable + aWidget: Инициализация: Соединяем сигналы wDBTable + + + aWidget invalid data source object + aWidget: Неверный объект источника данных + + + aWidget widgetEditor: invalid metadata object + aWidget: widgetEditor: Неправильный объект метаданных + + + aWidget table: invalid data source object + aWidget: table: Неверный объект источника данных + + + aWidget new: invalid data source object + aWidget: new: Неверный объект источника данных + + + aWidget select: invalid data source object + aWidget: select: Неверный объект источника данных + + + aWidget update: invalid data source object + aWidget: update: Неверный объект источника данных + + + aWidget value not fount widget with name %1 + aWidget: Не найдено значения виджета с именем %1 + + + aWidget set value: not fount widget with name %1 + aWidget: Установка значения: Не найден виджет с именем %1 + + + aWidget doc Id: invalid data source object + aWidget: Идентификатор документа Id: Неверный объект источника данных + + + + dEditRC + + Resource file + Файл ресурса + + + Data base header + Заголовок базы данных + + + Data base name + Имя базы данных + + + Data base server type + Тип сервера базы данных + + + Unknown + Неизвестный + + + mysql + mysql + + + postgres + postgres + + + Data base server address + Адрес сервера баз данных + + + Data base server port + Порт сервера база данных + + + Data base server user + Пользователь сервера баз данных + + + Data base server password + Пароль сервера баз данных + + + Work directory + Рабочий каталог + + + Resource file name + Файл ресурса + + + ... + ... + + + Configuration file name + Имя файла метаданных + + + OK + Ок + + + Cancel + Отмена + + + internal + встроенный + + + ananas config resource (*.rc) + Файл ресурсов Ананаса (*.rc) + + + ananas config file (*.cfg) + Файл бизнес схемы Ананаса (*.cfg) + + + + dImportDB + + Resource file + Файл ресурса + + + archive file + Файл резервной копии + + + Import + Ок + + + any files (*) + Все файлы (*) + + + ananas business schema archiff file (*.bsa) + Файлы архивов бизнес схем Ананаса (*.bsa) + + + + dLogin + + Ananas: Login + Ананас: Авторизация + + + Login name + Регистрационное имя + + + Password + Пароль + + + &Cancel + &Отмена + + + Alt+C + Alt+C + + + O&K + O&K + + + Alt+K + Alt+K + + + + dSelectDB + + Information base + Список бизнес схем + + + Select data base + Выбрать бизнес схему + + + Name + Имя + + + Resource file + Файл ресурса + + + &OK + &OK + + + &New + &Новый + + + Alt+N + Alt+N + + + &Group + &Группа + + + Alt+G + Alt+G + + + &Delete + &Удалить + + + Alt+D + Alt+D + + + &Edit + &Изменить + + + Alt+E + Alt+E + + + &Cancel + &Отмена + + + Alt+C + Alt+C + + + &Help + &Помощь + + + Alt+H + Alt+H + + + New group + Новая группа + + + New item + Новая схема + + + save + Сохранить + + + Delete item? + Удалить элемент? + + + confirm delete + Подтверждение удаления + + + E&xit + В&ыход + + + New &group + Новая &группа + + + &New item + &Новая бизнес схема + + + Edi&t + &Редактировать + + + &Import + Восстановить &из резервной копии + + + &Export + С&оздать резервную копию + + + Backup + Резервная копия + + + Select item + Выберите элемент + + + Please, select item for export + Выберите элемент для создания резервной копии + + + &File + &Программа + + + &Actions + &Сервис + + + Program + Программа + + + Actions + Действия + + + Service + Сервис + + + dSelectDB local settings not found + dSelectDB: Пользовательские (локальные) настройки не найдены + + + dSelectDB read settings for group with name %1 + dSelectDB: Чтение настроек для группы с именем %1 + + + dSelectDB save settings + dSelectDB: Сохранение настроек + + + save settings local? + Сохранить настройки локально? + + + dSelectDB business schema import + dSelectDB Импорт бизнес схемы + + + dSelectDB restore: %1 + dSelectDB: Восстанавливаем: %1 + + + Any files (*) + Все файлы (*) + + + dSelectDB backup ok + dSelectDB: Успешно создана резервная копия + + + dSelectDB backup: %1 + dSelectDB Резервная копия: %1 + + + New shema + Новая бизнес схема + + + &New shema + Новая бизнес &схема + + + diff --git a/translations/ananas-plugins-en.ts b/translations/ananas-plugins-en.ts new file mode 100644 index 0000000..1b1ab30 --- /dev/null +++ b/translations/ananas-plugins-en.ts @@ -0,0 +1,964 @@ + + + CatalogForm + + Catalogue + + + + Cancel + + + + displaying %1 from %2 + + + + Can't added new element to mark deleted group + + + + Can't added group to element + + + + Can't added group to mark deleted group + + + + Can't edit mark deleted element + + + + Catalog haven't edit element form + + + + Can't edit mark deleted group + + + + Catalog haven't edit group form + + + + Search + + + + CatalogForm:setData begin + + + + CatalogForm add first element in group + + + + CatalogForm add elements into root + + + + CatalogForm init + + + + Catalog Form image cat.png not loaded + + + + Catalog Form group pixmap not load + + + + Catalog Form element pixmap not load + + + + Catalog Form mark deleted group pixmap not load + + + + Catalog Form edit element form is null + + + + Catalog Form edit group form is null + + + + Catalog Form edit element start + + + + Catalog Form edit element with id=%1 + + + + Catalog Form edit group with id = %1 + + + + Catalog Form main widget is not 'MainForm' + + + + + QObject + + aForm SelectByCurrent %1 ended with %1 + + + + Unknown classname '%1' or metaobject '%2' + + + + + aEditorFactory + + aEditorFactory field metaobject not found + + + + aEditorFactory metadata in null + + + + + aEngine + + OK + + + + Cancel + + + + aEngine open form %1 in mode %2, select %3 + + + + aEngine form create error + + + + aEngine open form mode %1 not supported + + + + Line:%1 Message:%2 Stack:(%3) + + + + + aForm + + Error + + + + Error while open dialog form. Init hasn't been completed. + + + + Error open dialog form. Form not found. + + + + New document - <Ins>, Edit - <Enter>, View - <Shift+Enter> + + + + aForm creating form from ui + + + + aForm form create from ui ok + + + + aForm do not inherits aWidget! + + + + aForm load form module script + + + + aForm defined function %1 + + + + aForm form module script is empty + + + + aForm form not found + + + + aForm not found widget with name %1 + + + + aForm table value: column out of range + + + + aForm set read only + + + + aForm set read/write + + + + Deprecated method call: aForm::show() + + + + Deprecated method call: aForm::close() + + + + Deprecated method call: aForm::turn_on() + + + + aForm conduct: function on_conduct() return false, document not conducted + + + + Deprecated method call: aForm::turn_off() + + + + Deprecated method call: aForm::update() + + + + Expected wDBTable widget but found %1 + + + + aForm not found wDBTabe widget with name %1 + + + + aForm not found wDBTable widget with name %1 + + + + Deprecated method call: aForm::done(...) + + + + Deprecated method call: aForm::setfocus() + + + + + aLineEdit + + Enter string for search + + + + + aListBox + + Press arrow down for go to drop down list + + + + Use Enter for go to item and arrow for navigation + + + + + aListView + + Select + + + + Edit + + + + New element + + + + New group + + + + Undo mark delete + + + + Delete (mark deleted) + + + + Delete (phisical) + + + + Type of new item + + + + <p align="center">Select type of new item</p> + + + + &Elemnt + + + + &Group + + + + Delete item + + + + <p align="center">Mark deleted or delete?</p> + + + + &Mark deleted + + + + &Delete + + + + <Enter> - select, <Ins> - add, <Del> - delete items + + + + <Enter> - edit, <Ins> - add, <Del> - delete items + + + + + addfdialog + + select field + + + + OK + + + + Cancel + + + + field already binding, please select another field. + + + + + eActionButton + + Action button + + + + Update + + + + Close + + + + Simple action + + + + User action + + + + Execute + + + + Turn on + + + + OK + + + + Cancel + + + + + eAddObj + + Form1 + + + + + eCatalogue + + Catalogue + + + + Type + + + + OK + + + + Cancel + + + + + eDBField + + Database field + + + + Field type + + + + Field name + + + + OK + + + + Cancel + + + + + eDBTable + + Cancel + + + + OK + + + + Width + + + + aDBTable + + + + Table name + + + + Column list + + + + Column + + + + Header + + + + Field type + + + + Field name + + + + Column width + + + + decimal + + + + Add + + + + Up + + + + Down + + + + Delete + + + + table in use, please select another table + + + + + eDocument + + Document + + + + Type + + + + OK + + + + Cancel + + + + + eField + + Input field + + + + Positive + + + + Required + + + + Type + + + + Name + + + + OK + + + + Cancel + + + + Width + + + + Decimals + + + + + eJournal + + Journal + + + + Type + + + + OK + + + + Cancel + + + + + eReport + + Catalogue + + + + Type + + + + OK + + + + Cancel + + + + + eSelectDocType + + Select document type + + + + Cancel + + + + OK + + + + Document type + + + + ID + + + + + wCatalogEditor + + wCatalog Editor open form for select=%1 + + + + wCatalog Editor found element forms + + + + wCatalog Editor found group forms + + + + wCatalog Editor meta object forms not found + + + + + wCatalogue + + wCatalogue group value changed to %1 + + + + wCatalogue element value changed to %1 + + + + wCatalogue value for name %1 + + + + wCatalogue set value %1 for name %2 + + + + wCatalogue update + + + + wCatalogue have not data source object + + + + wCatalogue select group error = %1 + + + + wCatalogue set new values for all fields + + + + wCatalogue set new values for group field %1 + + + + wCatalogue value for element field %1 + + + + wCatalogue selection changed to %1 + + + + + wDBTable + + Available columns + + + + Date + + + + Prefix + + + + Number + + + + New + + + + Edit + + + + Delete + + + + View + + + + Refresh + + + + wDBTable init ok + + + + wDBTable init in engine + + + + wDBTable not in Ananas object container + + + + wDBTable init meta object not found + + + + wDBTable container type is %1 + + + + wDBTable filter is %1 + + + + wDBTable init in engine ok + + + + wDBTable: current record not setted + + + + wDBTable: function Value() call + + + + wDBTable: select document %1 + + + + You are going to remove record <br>Are you sure? + + + + &No + + + + Remove record? + + + + &Yes, remove + + + + + wDocument + + wDocument new ok + + + + wDocument set new value %1 for field %2 + + + + + wField + + ^\-{0,1}\d{0,%1}\.{1}\d{0,%2}$ + + + + ^\-{0,1}\d{0,%1}$ + + + + + wGroupTree + + New + + + + New group + + + + New group (Ins) + + + + Edit + + + + Edit group + + + + Edit group (Enter) + + + + Delete group + + + + Delete group (Delete) + + + + + wJournal + + New + + + + New document + + + + Edit + + + + Edit document + + + + View + + + + View document + + + + New document <Ins> + + + + Edit document <Enter> + + + + View document <Shift+Enter> + + + + Delete + + + + Delete document + + + + Delete document <Delete> + + + + Can not edit document + + + + To edit document you have to unconduct it. Or you can view it. Unconduct? + + + + &Unconduct + + + + &View + + + + Confirm + + + + Do you really want to delete document? + + + + &Yes + + + + &No + + + + wDBTable #%1 found + + + + Copy + + + + Copy document + + + + Duplicate document <Ctrl+D> + + + + diff --git a/translations/ananas-plugins-ru.ts b/translations/ananas-plugins-ru.ts new file mode 100644 index 0000000..3282106 --- /dev/null +++ b/translations/ananas-plugins-ru.ts @@ -0,0 +1,1153 @@ + + + CatalogForm + + Catalogue + Справочник + + + Go + Перейти + + + OK + Ок + + + Cancel + Отмена + + + displaying %1 from %2 + показано %1 из %2 + + + Can't added new element to mark deleted group + Невозможно добавить новый элемент в удаленную группу + + + Can't added element to element + Невозможно добавить элемент в элемент + + + Can't added group to element + Невозможно добавить группу в элемент + + + Can't added group to mark deleted group + Невозможно добавить группу в удаленную группу + + + Can't edit mark deleted element + Невозможно редактировать удаленный элемент + + + Catalog haven't edit element form + Не задана форма редактирования элемента + + + Can't edit mark deleted group + Невозможно редактировать удаленную группу + + + Catalog haven't edit group form + Не задана форма редактирования группы + + + Can't added element + Невозможно добавить элемент + + + Search + Поиск + + + CatalogForm:setData begin + + + + CatalogForm add first element in group + CatalogForm: Добавление первого элемента в группу + + + CatalogForm add elements into root + CatalogForm: Добавление элементов в корень + + + CatalogForm init + CatalogForm: Инициализа + + + Catalog Form image cat.png not loaded + CatalogForm: Изображение cat.png не загружено + + + Catalog Form group pixmap not load + CatalogForm: Значек изображения для групп не загружен + + + Catalog Form element pixmap not load + CatalogForm: Значек изображения элемента не загружен + + + Catalog Form mark deleted group pixmap not load + CatalogForm: Значек изображения для удаленной группы не загружен + + + Catalog Form edit element form is null + CatalogForm: Форма редактирования элемента = null + + + Catalog Form edit group form is null + CataloForm: Форма редактирования группы = null + + + Catalog Form edit element start + CatalogForm: Начинаем открывать форму редактирования элемента + + + Catalog Form edit element with id=%1 + CatalogForm: Редактирование элемента с идентификатором id=%1 + + + Catalog Form edit group with id = %1 + CatalogForm: Редактирование группы с идентификатором id = %1 + + + Catalog Form main widget is not 'MainForm' + CatalogForm: Главный виджет не является 'MainForm' + + + + QObject + + report + + отчет + + + text report + + текстовый отчет + + + invalid arguments + + неверный аргумент + + + aForm SelectByCurrent %1 ended with %1 + aForm: Результат выполнения SelectByCurrent по идентификатору %1 равен %1 + + + Unknown classname '%1' or metaobject '%2' + Неизвестное имя класса '%1' или неопределен объект метаданных '%2' + + + + aEditorFactory + + aEditorFactory field metaobject not found + aEditorFactory: Поле в метаданных не найдено + + + aEditorFactory metadata in null + aEditorFactory: Объект метаданных = null + + + + aEngine + + Line:%1 %2 (%3) + Строка:%1 %2 (%3) + + + OK + Ок + + + Cancel + Отмена + + + aEngine open form %1 in mode %2, select %3 + aEngine: Открытие формы %1 в режиме %2, UID = %3 + + + aEngine form create error + aEngine: Ошибка создания формы + + + aEngine open form mode %1 not supported + aEngine: Открытие формы в режиме %1 не поддерживается + + + Line:%1 Message:%2 Stack:(%3) + Строка:%1 Сообщение:%2 Стэк:(%3) + + + + aForm + + Invalid widget class. Widget class have to inherits aWidget. + + Неверно задан класс. Виджет должен быть унаследован от класса aWidget. + + + Error + Ошибка + + + Error while open dialog form. Init hasn't been completed. + Ошибка открытия диалога. Инициализация не завершена. + + + Error open dialog form. Form not found. + Ошибка открытия формы диалога. Форма не найдена. + + + on_formstart() + on_formstart() + + + Error! Can't find widget by name==`%s` + + Ошибка, Не могу найти виджет по имени `%s` + + + Error! Can't find wDBTable `%s` + + Ошибка! Не могу найти wDBTable `%s` + + + on_button(" + on_button(" + + + ") + ") + + + on_conduct() + on_conduct() + + + New document - <Ins>, Edit - <Enter>, View - <Shift+Enter> + Новый документ - <Ins>, Изменить - <Enter>, Просмотр - <Shift+Enter> + + + Error! Can't find widget wDBTable by name==`%s` + + Ошибка! Невозможно найти виджет wDBTable с именем `%s' + + + aForm creating form from ui + aForm: Создание формы из ui файла + + + aForm form create from ui ok + aForm: Форма успешно создана из ui файла + + + aForm do not inherits aWidget! + aForm: Не является наследником aWidget! + + + aForm load form module script + aForm: Загрузка скрипта модуля формы + + + aForm defined function %1 + aForm: Определена функция %1 + + + aForm form module script is empty + aForm: Скрипт модуля формы пуст + + + aForm form not found + aForm: Форма не найдена + + + aForm not found widget with name %1 + aForm: Не найден виджет по имени %1 + + + aForm table value: column out of range + + + + aForm set read only + + + + aForm set read/write + aForm: Установка режима чтение/запись для формы + + + Deprecated method call: aForm::show() + Вызов устаревшего метода: aForm::show() + + + Deprecated method call: aForm::close() + Вызов устаревшего метода: aForm::close() + + + Deprecated method call: aForm::turn_on() + Вызов устаревшего метода: aForm::turn_on() + + + aForm conduct: function on_conduct() return false, document not conducted + aForm: Проведение документа: Функция on_conduct() вернула false. Документ не проведен + + + Deprecated method call: aForm::turn_off() + Вызов устаревшего метода: aForm::turn_off() + + + Deprecated method call: aForm::update() + Вызов устаревшего метода: aForm::update() + + + Expected wDBTable widget but found %1 + Ожидался wDBTable виджет, но обнаружен %1 + + + aForm not found wDBTabe widget with name %1 + aForm: Виджет wDBTabe с именем %1 не обнаружен + + + aForm not found wDBTable widget with name %1 + aForm: Виджет wDBTable с именем %1 не обнаружен + + + Deprecated method call: aForm::done(...) + Вызов устаревшего метода: aForm::done(...) + + + Deprecated method call: aForm::setfocus() + Вызов устаревшего метода: aForm::setfocus() + + + + aLineEdit + + Enter string for search + Задайте строку поиска + + + + aListBox + + Press arrow down for go to drop down list + Нажмите стрелку вниз для перемещения в выпадающий список + + + Use Enter for go to item and arrow for navigation + Используйте стрелки. Для перехода нажмите Enter + + + + aListView + + Select + Выбрать + + + Edit + Изменить + + + New element + Новый элемент + + + New group + Новая группа + + + Undo mark delete + Отменить удаление + + + Delete (mark deleted) + Удалить (логически) + + + Delete (phisical) + Удалить (физически) + + + Type of new item + Тип нового элемента + + + <p align="center">Select type of new item</p> + <p align="center">Выберите тип нового элемента</p> + + + &Elemnt + &Элемент + + + &Group + &Группа + + + Delete item + Удалить элемент + + + <p align="center">Mark deleted or delete?</p> + <p align="center">Пометить удаленным или удалить совсем?</p> + + + &Mark deleted + &Пометить удаленным + + + &Delete + &Удалить + + + <Enter> - select, <Ins> - add, <Del> - delete items + <Enter> - Выбрать, <Ins> - Новый, <Del> - Удалить + + + <Enter> - edit, <Ins> - add, <Del> - delete items + <Enter> - Изменить, <Ins> - Новый, <Del> - Удалить + + + + addfdialog + + select field + выбрать поле + + + OK + Ок + + + Cancel + Отмена + + + field already binding, please select another field. + поле уже используется, выберите другое поле. + + + + eActionButton + + Action button + Действие + + + Script + Скрипт + + + Action + Действие + + + Update + Обновить + + + Close + Закрыть + + + Turn on + Включить + + + Print + Печать + + + Simple action + Простое действие + + + User action + Пользовательское действие + + + Execute + Выполнить + + + Conduct + Провести + + + OK + Ок + + + Cancel + Отмена + + + + eAddObj + + Form1 + + + + + eCatalogue + + Catalogue + Справочник + + + Type + Тип + + + OK + Ок + + + Cancel + Отмена + + + + eDBField + + Database field + Поле базы данных + + + Field type + Тип поля + + + Field name + Имя поля + + + OK + Ок + + + Cancel + Отмена + + + + eDBTable + + Database table + Таблица базы данных + + + Cancel + Отмена + + + OK + Ок + + + Field + Поле + + + Width + Ширина + + + Table + Таблица + + + aDBTable + + + + Table name + Имя таблицы + + + Column list + Список столбцов + + + Column + Столбец + + + Header + Заголовок + + + Field type + Тип поля + + + Field name + Имя поля + + + Column width + Ширина столбца + + + decimal + десятичный + + + Add + Добавить + + + Up + Вверх + + + Down + Вниз + + + Delete + Удалить + + + table in use, please select another table + Таблица занята, выберите другую таблицу + + + + eDocument + + Document + Документ + + + Type + Тип + + + OK + Ок + + + Cancel + Отмена + + + + eField + + Input field + Поле ввода + + + Positive + Положительное + + + Required + Обязательное + + + Type + Тип + + + Name + Имя + + + OK + Ок + + + Cancel + Отмена + + + Width + Ширина + + + Decimals + Десятичное + + + + eJournal + + Journal + Журнал + + + Type + Тип + + + OK + Ок + + + Cancel + Отмена + + + + eReport + + Catalogue + Справочник + + + Type + Тип + + + OK + Ок + + + Cancel + Отмена + + + + eSelectDocType + + Select document type + Выберите тип документа + + + Cancel + Отмена + + + OK + Ок + + + Document type + Тип документа + + + ID + + + + + eTable + + Form table + Таблица формы + + + List of columns + Список столбцов + + + Table name + Имя таблицы + + + Table column + Столбец таблицы + + + Header + Заголовок + + + Width + Ширина + + + Field type + Тип поля + + + Field name + Имя поля + + + View width + Ширина просмотра + + + decimals + десятичные + + + Add + Добавить + + + Up + Вверх + + + Down + Вниз + + + Remove + Удалить + + + Cancel + Отмена + + + + wCatalogEditor + + wCatalog Editor open form for select=%1 + wCatalog: Открытие формы редактора для выбора %1 + + + wCatalog Editor found element forms + wCatalog: Редактор нашел форму для редактирования элемента + + + wCatalog Editor found group forms + wCatalog: Редактор нашел форму для редактирования группы + + + wCatalog Editor meta object forms not found + wCatalog: Не найдены формы в метаданных + + + + wCatalogue + + wCatalogue group value changed to %1 + wCatalogue: Значение группы изменено на %1 + + + wCatalogue element value changed to %1 + wCatalogue: Значение элемента изменено на %1 + + + wCatalogue value for name %1 + wCatalogue: Значение для имени %1 + + + wCatalogue set value %1 for name %2 + wCatalogue: Задаем значение %1 для имени %2 + + + wCatalogue update + wCatalogue: Обновление + + + wCatalogue have not data source object + wCatalogue: Нет объекта источника данных + + + wCatalogue select group error = %1 + wCatalogue: Ошибка выбора группы: %1 + + + wCatalogue set new values for all fields + wCatalogue: Установка новых значений для всех полей + + + wCatalogue set new values for group field %1 + wCatalogue: Установка значения для поля %1 группы + + + wCatalogue value for element field %1 + wCatalogue: Установка значения для поля %1 элемента + + + wCatalogue selection changed to %1 + wCatalogue: Выбор изменен на %1 + + + + wDBField + + field already binding, please select another field. + поле уже используется, выберите другое поле. + + + + wDBTable + + Available columns + Доступные столбцы + + + Date + Дата + + + Prefix + Префикс + + + Number + Номер + + + New + Новый + + + Edit + Изменить + + + Delete + Удалить + + + View + Просмотр + + + Refresh + Обновить + + + wDBTable init ok + wDBTable: Инициализация прошла успешно + + + wDBTable init in engine + wDBTable: Инициализация engine + + + wDBTable not in Ananas object container + wDBTable: Не является контейнером объектов Ananas + + + wDBTable init meta object not found + wDBTable: Объект мета данных не найден + + + wDBTable container type is %1 + wDBTable: Контейнер имеет тип %1 + + + wDBTable filter is %1 + wDBTable: Текущий фильтр: %1 + + + wDBTable init in engine ok + wDBTable: Успешное завершение инициализации в engine + + + wDBTable: current record not setted + wDBTable: Текущая запись не задана + + + wDBTable: function Value() call + wDBTable: Вызов функции Value() + + + wDBTable: select document %1 + wDBTable: Выбор документа %1 + + + Remove record? -- Ananas + Удалить запись? -- Ананас + + + You are going to remove record <br>Are you sure? + Вы собрались удалить запись <br> Действительно удалить? + + + &Yes + &Да + + + &No + &Нет + + + Remove record? + Удалить запись? + + + &Yes, remove + &Да, удалить + + + + wDocument + + wDocument new ok + wDocument: Новый wDocument успешно создан + + + wDocument set new value %1 for field %2 + wDocument: Задаем новое значение %1 полю %2 + + + + wField + + ^\-{0,1}\d{0,%1}\.{1}\d{0,%2}$ + + + + ^\-{0,1}\d{0,%1}$ + + + + + wGroupTree + + New + Новый + + + New group + Новая группа + + + New group (Ins) + Новая группа (Ins) + + + Edit + Изменить + + + Edit group + Изменить группу + + + Edit group (Enter) + Изменить группу (Enter) + + + Delete group + Удалить группу + + + Delete group (Delete) + Удалить группу (Delete) + + + + wJournal + + New + Новый + + + New document + Новый документ + + + New document (Ins) + Новый документ (Ins) + + + Edit + Изменить + + + Edit document + Изменить документ + + + Edit document (Enter) + Изменить документ (Enter) + + + View + Просмотр + + + View document + Просмотр документа + + + View document (Shift+Enter) + Просмотр документа (Shift+Enter) + + + Can not edit document + Не могу редактировать документ + + + To edit document you have to unconduct it. Or you can view it. Unconduct? + Для редактирования документа Вы должны отменить его проведение. Или Вы можете просмотреть его. Отменить проведение? + + + &Unconduct + &Отменить проведение + + + &View + &Просмотр + + + New document <Ins> + Новый документ - <Ins> + + + Edit document <Enter> + Изменить документ - <Enter> + + + View document <Shift+Enter> + Просмотр документа - <Shift+Enter> + + + Delete + Удалить + + + Delete document + Удалить документ + + + Delete document <Delete> + Удалить документ - <Delete> + + + Confirm + Подтвердить + + + Do you really want to delete document? + Вы действительно хотите удалить документ? + + + &Yes + &Да + + + &No + &Нет + + + wDBTable #%1 found + wDBTable: Не удалось обнаружить #%1 + + + Copy + Копировать + + + Copy document + Копировать документ + + + Duplicate document <Ctrl+D> + Создать копию документа <Ctrl+D> + + + -- 1.7.1